Face alignment 优化记录
一, 任务明细:
基于下面的pipline 过程做优化
二, 目标:
使我们的目前 pipline 结果的错误值 小于 face alignment at 3000fps的结果错误值。
前提:使用同样的训练集,测试集, 相同的误差计算方法。
目前 face alignment at 3000fps 在处理好的数据集上误差值为 1.089.
误差计算公式
三,准备过程
1. 数据准备
第一阶段数据准备:
A. 图片数据准备
图片人脸获取:使用 cunpd库获得人脸的rect位置。
注意点:
(1)一张图片可能有多个人脸,不能检测到一个人脸就剪裁出来,因为一张图片只有一个 landmark标注,所以要把这个 landmark对应的人脸找到。目前我采用的方法是 判断 landmark关键点 是否在 rect 区域内,如果存在说明该 rect 的人脸 和landmark 是对应的。
(2)rect截取的人脸可能不完整,因为lanmark是人脸一个比较大的区域,但是不同的人脸检测库,检测到的区域选择大小不一,所以 需要将检测到的人脸区域进行扩大,保证 整个人脸都在 rect 区域内。
例如:红色框为实际检测的rect ,蓝色框为扩展后的区域。
(3)剪裁后的区域 resize 成 需要的大小,目前使用的是 96*96 .
B. 坐标数据准备
坐标数据读取:根据对应文件名称 读取landmark的pts文件,同时根据目前人脸剪裁的区域和resize的大小 对坐标值做相应的变换。共有68个坐标点,即136个标量,我们将图片名称和 标量 存到 txt 文件里面 用于后面的训练。
C. 数据分配
数据集:300W, afw, helen, ibug, lfpw, ZJUFace
训练集:9000张
测试集:773张
验证集:暂未加入验证集。
第二阶段数据准备:
A. 图片数据准备
四个部位区域剪裁:基于第一阶段的预测结果准备第二阶段的输入数据。
第一阶段可预测33个点,即下图中的蓝色圈圈。边缘的作为第一阶段的预测结果,其他的用于第二阶段的数据剪裁。
眼睛的剪裁大小为 :48*48
鼻子的剪裁大小为:48*24
嘴巴的剪裁大小为:48*36
注意:剪裁时做适当扩展,以免剪裁的区域不完整。
B. 坐标数据准备
对剪裁后的四个部分坐标 分别做变换,两个眼睛使用两个网络,每个网络预测 11个坐标,22个标量。一个鼻子使用一个网络,预测9个坐标,18个标量。一个嘴巴预测20个坐标,40个标量。
四,优化过程
1. 初始架构
Stage one:
Stage one 要预测 33个坐标,即回归出 66个标量。
Layer |
BottomLayer |
Type |
kernersize |
Stride/pad |
outputsize |
Input |
- |
Data |
- |
- |
48*48*3 |
Conv1 &Relu1 |
Input |
Conv&ReLU |
3 |
1/1 |
48*48*32 |
Pool1 |
Relu1 |
MAX/Pooling |
2 |
2/0 |
24*24*32 |
Conv2 &Relu2 |
Pool1 |
Conv&ReLU |
3 |
1/1 |
24*24*64 |
Conv2_1 &Relu2_1 |
Relu2 |
Conv&ReLU |
3 |
1/1 |
24*24*64 |
Pool2 |
Relu2_1 |
MAX/Pooling |
2 |
2/0 |
12*12*64 |
Conv3 &Relu3 |
Pool2 |
Conv&ReLU |
3 |
1/1 |
12*12*128 |
Conv3_1 &Relu3_1 |
Relu3 |
Conv&ReLU |
3 |
1/1 |
12*12*128 |
Pool3 |
Relu3_1 |
MAX/Pooling |
2 |
2/0 |
6*6*128 |
Conv4 &Relu4 |
Pool3 |
Conv&ReLU |
3 |
1/1 |
6*6*256 |
Conv4_1 &Relu4_1 |
Relu4 |
Conv&ReLU |
3 |
1/0 |
4*4*256 |
Pool4 |
Relu4_1 |
AVE/Pooling |
4 |
2/0 |
1*1*256 |
FC |
Pool4 |
InnerProduct |
- |
- |
66 |
Stage two
初始架构的 stage two是把 第一阶段的的四个部分剪切成相同的大小为 48*48。并把四张图片按深度连接到一起 变成一个48*48*12的输入数据,跟据这个输入数据搭建一个网络预测 剩余的 51个坐标,即102个标量值。
Layer |
BottomLayer |
Type |
kernersize |
Stride/pad |
outputsize |
Input |
- |
Data |
- |
- |
48*48*12 |
Conv1 &Relu1 |
Input |
Conv&ReLU |
3 |
1/1 |
48*48*64 |
Pool1 |
Relu1 |
MAX/Pooling |
2 |
2/0 |
24*24*64 |
Conv2 &Relu2 |
Pool1 |
Conv&ReLU |
3 |
1/1 |
24*24*128 |
Conv2_1 &Relu2_1 |
Relu2 |
Conv&ReLU |
3 |
1/1 |
24*24*128 |
Pool2 |
Relu2_1 |
MAX/Pooling |
2 |
2/0 |
12*12*128 |
Conv3 &Relu3 |
Pool2 |
Conv&ReLU |
3 |
1/1 |
12*12*256 |
Conv3_1 &Relu3_1 |
Relu3 |
Conv&ReLU |
3 |
1/1 |
12*12*256 |
Pool3 |
Relu3_1 |
MAX/Pooling |
2 |
2/0 |
6*6*256 |
Conv4 &Relu4 |
Pool3 |
Conv&ReLU |
3 |
1/1 |
6*6*512 |
Conv4_1 &Relu4_1 |
Relu4 |
Conv&ReLU |
3 |
1/0 |
4*4*512 |
Pool4 |
Relu4_1 |
AVE/Pooling |
4 |
2/0 |
1*1*512 |
FC |
Pool4 |
InnerProduct |
- |
- |
102 |
使用该结构误差值在 25左右,与 face alignment at 3000fps 的 1.089还相差甚远。
2. 优化1
对于 stage one 直接使用 AVE的结果做坐标的回归,效果一直不是很好,在优化过程中发现,在回归之前 再引入一个全连接,误差值会降低很多。
思考:之前很多优秀的网络架构例如GoogleNet 都是使用 AVEPooling来代替全连接来减少参数,减少过拟合问题。为何此处需要多引入一个全连接。
个人见解:由于之前的经典架构主要是做分类(ImageNet 1000),而回归值相对于分类需要更加精细的结果而不是一个泛化的分类结果,所以需要更强的非线性变换。
3. 优化2
图片大小改变:第二阶段的四个区域 跟据其实际大小剪裁成不同的大小。
眼睛:48*48 鼻子:24*48 嘴巴:48*36
网络改变:第二阶段使用四个小网络 分别做 眼睛(2个),鼻子,嘴巴 的landmark位置回归。
眼睛预测网络的结构为 眼睛landmark点为11个,即 回归22个标量。
Layer |
BottomLayer |
Type |
kernersize |
Stride/pad |
outputsize |
Input |
- |
Data |
- |
- |
48*48*3 |
Conv1 &Relu1 |
Input |
Conv&ReLU |
3 |
1/1 |
48*48*32 |
Pool1 |
Relu1 |
MAX/Pooling |
2 |
2/0 |
24*24*32 |
Conv2 &Relu2 |
Pool1 |
Conv&ReLU |
3 |
1/1 |
24*24*64 |
Pool2 |
Relu2_1 |
MAX/Pooling |
2 |
2/0 |
12*12*64 |
Conv3 &Relu3 |
Pool2 |
Conv&ReLU |
3 |
1/1 |
12*12*128 |
Pool3 |
Relu3_1 |
MAX/Pooling |
3 |
2/0 |
4*4*128 |
FC1 |
Pool3 |
InnerProduct |
- |
- |
256 |
FC2 |
FC1 |
InnerProduct |
- |
- |
22 |
其他三个网络架构与其相似,这里不一一给出了。
使用这种优化后误差值变为 8.5左右,此时与 face alignment at 3000fps 还有一段距离。
4. 优化3
观察第二次的优化结果发现,两个眼睛的误差错误值占了整个错误值的大部分,所以两个眼睛块儿的预测可能需要改变方法。
考虑重新对眼睛这块儿处理,受DCNN的启发,把眼睛这块儿的眉毛和眼睛分开单独预测,之前是眼睛眉毛crop到一起的。所以新的截取方式如下图。
不变:此时鼻子与嘴巴的截取方式与之前一样,网络架构也不变。
变:把眼睛这块儿的眉毛和眼睛分开。考虑每块儿采用一个小网络的话 第二阶段网络会太多,所以对于左眉毛和右眉毛使用同一个网络,左眼睛和右眼睛采用同一个网络,实验中发现这种方式与眉毛和眼睛都单独使用两个网络进行预测的误差值相似。
此时的错误值在 1.12左右,跟face alignment at 3000fps 1.089的结果已经相似了,但是我们的目标是超过它,所以还需进一步优化。
5. 优化4
在之前的几次优化中已经对人脸的五官部分做了优化,但是对于 人脸边缘17个点还没有优化的方法,而且当前的误差值中,边缘的17个关键点误差相对占了整个误差的大部分,所以该部分肯定需要优化。
基于stage two的一些优化方法,何不把人脸的边缘部分也剪裁出来,虽然剪裁出的区域较大,但还是减少了很多对边缘预测没用的部分呢。于是考虑在 stage two 再加一个剪裁块儿。剪裁如下图所示。
其中红色区域为原图 96*96 绿色区域为剪裁后的图 大小为64*64
经过剪裁后 再搭建一个人脸边缘点预测的网络检测点为17个,即回归34个标量。此时边缘点的错误值相对于之前的值减少了一半左右。
优化后整体的错误值为1.028 已经超过了face alignment at 3000fps 的1.089 .
五,目前性能
目前模型运行时间:cpu+gpu = 3.7+0.9 大概在 5ms
总共有 6个模型
总模型大小为:21M (stageone : 5.56M brow:1.66M eye:2.17M nose:2.17M mouth:5.20M face-edge:4.69M)
六,总结
1.优化目标与baseline 很重要,有了baseline和优化目标以后才会对整个优化方向,与优化过程更加清晰。
2.目前只是第一个版本的结果,后续可以 再基于输入图片大小,网络结构做优化,应该会有更好的效果。