数据集通过网址 http://shuoyang1213.me/WIDERFACE/ 下载 。
模型Pnet,Rnet 训练、测试选择使用的数据 WIDER FACE 。
WIDER FACE简介:数据标签只有bbox,没有landmark。注释:bbox [x1,y1,width,height]
模型Onet训练采用的数据通过网址http://mmlab.ie.cuhk.edu.hk/archive/CNN_FacePoint.htm 下载
CNN_FacePoint简介 :数据标签有bbox,以及landmark。注释:bbox[x1,x2,y1,y2]
landmark [x1,y1,x2,y2,x3,y3,x4,y4,x5,y5]
坑1:注意标签每个坐标含义。
工程需要做一个人脸识别的东东,所以准备把人脸识别的每块内容都认真的走一遍,步骤大概是:人脸检测 - 人脸矫正 - 活体检测 - 质量评估 - 人脸识别 ,为了快速搞定,利用别人的代码就是最便捷的方法,自己选择pytorch的一个版本。网址为:https://github.com/Sierkinhane/mtcnn-pytorch。
这里大概介绍一下mtcnn的工作原理
mtcnn网络结构如图1所示:

图1
他是一种多任务级联的网络,每一个网络都包含人脸分类任务,边界框回归任务、人脸关键点回归任务。P-Net 主要用来产生候选框可能的位置,R-Net 再过滤掉一部分候选框,O-Net 产生最终的候选框和landmark位置。
注意:PNet 输出的是map格式,而Rnet和ONet的输出的是条状的,原因是因为实际测试时,PNet输入图片大小是不固定的,所以维度是不固定的不能接入全连接层。
测试时,一张图片先通过PNet,按照一个比例系数进行resize 得到图片金字塔,分别在每张图片上面进行边界框预测输出,预测的方法是根据class_map上大于阈值的保留下来,作为边界框的左上角坐标,坐标通过resize 相应的系数映射回原图,右下角的坐标=(坐上角的坐标*stirde+12)/scale。对应红色的部分。stride =2 猜测比如输入一张256大小的图片,最后输出类别、位置信息时图像大小变为123 ,原图是特征图的二倍关系。
boundingbox = np.vstack([np.round((stride * t_index[1]) / scale), # x1 of prediction box in original image
np.round((stride * t_index[0]) / scale), # y1 of prediction box in original image
np.round((stride * t_index[1] + cellsize) / scale), # x2 of prediction box in original image
np.round((stride * t_index[0] + cellsize) / scale), # y2 of prediction box in original image #reconstruct the box in original image
score,
reg])
reg 是网络输出框的相对偏移的位置信息,最终的坐标输出以x1为例,为x1 = np.round((stride * t_index[1]) / scale)+ (np.round((stride * t_index[1] + cellsize) / scale)-np.round((stride * t_index[1]) / scale))*reg[:,0]
RNet输入是Pnet的输出,RNet主要会相对于Pnet输出位置进行调整。ONet同Rnet。landmark 输出的是相对位置,是相对boundingbox的相对位置坐标。
回到模型训练上,PNet,RNet,ONet模型的输入分别是12*12,24*24,48*48。输出的类别共包含0-负样本,1-正样本,-1-part样本就是部分含有正样本的数据,-2-landmark 样本。
需要注意的是模型训练的数据种类标签是否正确,否则训练的时候会出现某一个 loss 的梯度爆炸,原文作者代码的iou 计算输入有些问题,导致在训练ONet正负样本不均衡。
目前训练的PNet,RNet,ONet,比例大致是4:7:15 。
目前模型训练结果出现的问题:
1、框回归的不稳,抖动情况非常严重。这个问题目前没有解决。不知道该怎样优化。可能数据量还是不够。
2、关于参数 初始化 的问题,发现参数初始化不对loss降不太下去,现在每次训练都是在自己某一次实验结果上开始训练的。
自己写了个测试程序,分别统计检出率和准确率。目前iou=0.65,检出和准确率在0.7以上。可以通过这个小程序进行模型筛选。代码如下:
import cv2import torchfrom mtcnn.core.detect import create_mtcnn_net, MtcnnDetectorimport numpy as npimport osimport mtcnn.core.utils as utils testfiles = "anno_train.txt"testdata = "face_landmark/CNN_FacePoint"label = [] showlabel = True with open(testfiles, "r") as f: read = f.readlines()print("test Data num is :", len(read))pnet, rnet, onet = create_mtcnn_net(p_model_path="pnet_epoch.pt", r_model_path="rnet_epoch.pt", o_model_path="onet_epoch.pt", use_cuda = False)mtcnn_detector = MtcnnDetector(pnet=pnet, rnet=rnet, onet=onet, min_face_size=12) pos = 0numsdetect = 0for file in read: #print("file is :", file) file = file.strip().split(" ") img = cv2.imread(os.path.join(testdata, file[0].replace("\\", "/"))) print(os.path.join(testdata, file[0].replace("\\", "/"))) print("img.shape is :", img.shape) #print(file[0]) boxes_align_r, bboxs, landmarks = mtcnn_detector.detect_face(img) gtbox = list(map(float, file[1:5])) print("gtbox is :", gtbox) gtlandmarks = list(map(float, file[5:])) numdetect = len(bboxs) numsdetect = numsdetect + numdetect gtbox = np.array(gtbox, dtype=np.float32).reshape(-1, 4) for box in bboxs: if showlabel: cv2.rectangle(img, (int(box[0]), int(box[1])), (int(box[2]), int(box[3])), (0, 0, 255), 2, 1) #cv2.rectangle(img, (int(gtbox[0][0]), int(gtbox[0][2])), (int(gtbox[0][1]), int(gtbox[0][3])), (255, 0, 0), 2, 1) p1 = int(gtbox[0][0])+int(gtbox[0][2]) p2 = int(gtbox[0][1])+int(gtbox[0][3]) print("p1", int(gtbox[0][0]), int(gtbox[0][1]),p1,p2) cv2.rectangle(img, (int(gtbox[0][0]), int(gtbox[0][1])), (p1, p2), (255, 0, 0), 2, 1) iou = utils.IoU1(box, gtbox) print("iou is :", iou) if iou > 0.65: pos = pos + 1 if showlabel: cv2.imshow("img", img) cv2.waitKey(1000)print("recall is : %s accuracy is : %s "%(pos/len(read),pos/numsdetect))
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删