概述
目的:
- 为什么libfacedetetiong可以脱离pytorch/caffe等环境的依赖
- 关于模型的一些训练细节,如:数据,模型,如何脱离pytorch的依赖,只用c++就行,推理的速度等
- 如何在现有的基础上进行拓展,让其支持更多的模型。
训练细节
1. 模型
先上关键代码,无关紧要的就删了:
self.model1 = Conv_2layers(3, 32, 16, 2)
self.model2 = Conv_2layers(16, 32, 32, 1)
self.model3 = Conv_3layers(32, 64, 32, 64, 1)
self.model4 = Conv_3layers(64, 128, 64, 128, 1)
self.model5 = Conv_3layers(128, 256, 128, 256, 1)
self.model6 = Conv_3layers(256, 256, 256, 256, 1)
self.loc, self.conf = self.multibox(self.num_classes)
def multibox(self, num_classes):
loc_layers = []
conf_layers = []
loc_layers += [nn.Conv2d(self.model3.out_channels, 3 * 14, kernel_size=3, padding=1, bias=True)]
conf_layers += [nn.Conv2d(self.model3.out_channels, 3 * num_classes, kernel_size=3, padding=1, bias=True)]
loc_layers += [nn.Conv2d(self.model4.out_channels, 2 * 14, kernel_size=3, padding=1, bias=True)]
conf_layers += [nn.Conv2d(self.model4.out_channels, 2 * num_classes, kernel_size=3, padding=1, bias=True)]
loc_layers += [nn.Conv2d(self.model5.out_channels, 2 * 14, kernel_size=3, padding=1, bias=True)]
conf_layers += [nn.Conv2d(self.model5.out_channels, 2 * num_classes, kernel_size=3, padding=1, bias=True)]
loc_layers += [nn.Conv2d(self.model6.out_channels, 3 * 14, kernel_size=3, padding=1, bias=True)]
conf_layers += [nn.Conv2d(self.model6.out_channels, 3 * num_classes, kernel_size=3, padding=1, bias=True)]
return nn.Sequential(*loc_layers), nn.Sequential(*conf_layers)
模型基本上是SSD的方案。
- 基础模型是conv,batchnorm,relu的堆叠
- 从3,4,5,6模块进行输出,并回归loss
- 位置回归分支输出的最后维度为啥是:3 *14,2 *14,还不一样呢。3和2表示每个点的anchor数量。这个对应config.py文件中的
'min_sizes': [[10, 16, 24], [32, 48], [64, 96], [128, 192, 256]],
说明:1. 这里前面的数字小,后面的数字大,表示用前面的特征图检测小目标,用后面的特征图检测大目标。 2. 这里每个list的个数表示每个点的anchor数量,比如第三层的[10,16,24],表示第三层输出特征,每个点的anchor宽度为10,16,24,所有是3 3. 这里的10是人脸的原始尺寸,并不是相对于下采样的特征图的尺寸,所以最小的anchor是10 - 位置输出分支的14:人脸bbox(4个值)+ 人脸关键点(10个值)= 14
2. 数据
数据采用的是widerface数据集。数据增强部分基本应该和常用的人脸检测项目一样。
我认为一些可以注意的地方:
- 项目本身采用320的尺寸进行训练,但是会以0.8的概率生成[0.3,1] scale的图片,在以图像短边为基准进行随机crop。
- 随机的亮度,对比度,色度等
- 将图片resize,填充到固定尺寸(320)
关键点对应的代码:
# 1. 更多的小尺寸图片
if random.uniform(0, 1) <= 0.2: # 0.2的概率采用同样尺寸
scale = 1
else:
scale = random.uniform(0.3, 1.) # 采用更多的小人脸,0.8的概率
short_side = min(width, height) # 短边
3. 损失函数
损失函数采用的是SSD的MultiBoxLoss,应该都是差不多的,没有对比。
损失函数计算三个:
- 人脸bbox的损失
中心点的偏差/(0.1*anchor的宽度/高度)
高度和宽度损失:log(偏差)/0.2 - 人脸关键点的损失
人脸关键点是相对于anchor左上角的偏差/(0.1*anchor的高度/宽度),这和人脸bbox中心点的计算过程一样 - 分类交叉熵损失
采用softmax为损失,但是会筛选样本,正负样本为1:3
前两个损失anchor与正样本对应时才计算
损失函数code
loss_l = F.smooth_l1_loss(loc_p[:, 0:4], loc_t[:, 0:4], reduction='sum') # 人脸bbox的loss
loss_lm = F.smooth_l1_loss(loc_p[:, 4:14], loc_t[:, 4:14], reduction='sum') # 人脸关键点的loss
loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='sum') # 交叉熵损失
# 人脸bbox和关键的损失
# dist b/t match center and prior's center
g_cxcy = (matched[:, 0:2] + matched[:, 2:4])/2 - priors[:, 0:2] # 中心点的偏差
# encode variance
g_cxcy /= (variances[0] * priors[:, 2:4]) # 中心点的偏差/高度或宽度
# match wh / prior wh
g_wh = (matched[:, 2:4] - matched[:, 0:2]) / priors[:, 2:4] # 高度和宽度的偏差
g_wh = torch.log(g_wh) / variances[1]
# landmarks
g_xy1 = (matched[:, 4:6] - priors[:, 0:2]) / (variances[0] * priors[:, 2:4]) # 关键点的偏差,相较于人脸bbox左上角的偏差
g_xy2 = (matched[:, 6:8] - priors[:, 0:2]) / (variances[0] * priors[:, 2:4])
g_xy3 = (matched[:, 8:10] - priors[:, 0:2]) / (variances[0] * priors[:, 2:4])
g_xy4 = (matched[:, 10:12] - priors[:, 0:2]) / (variances[0] * priors[:, 2:4])
g_xy5 = (matched[:, 12:14] - priors[:, 0:2]) / (variances[0] * priors[:, 2:4])
总结
- 项目可读性很强。一个晚上就搞定了
- 代码很美,基本一看就知道大概
明天继续模型转换等阅读
reference
- https://github.com/ShiqiYu/libfacedetection.train
最后
以上就是温婉裙子为你收集整理的【人脸检测】libfacedetection.train项目解读记录的全部内容,希望文章能够帮你解决【人脸检测】libfacedetection.train项目解读记录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复