1. 数据不匹配问题
吴恩达深度学习课程中有几个小节谈到了训练数据集和测试数据集分布不匹配的问题,这种不匹配可能经常发生,因为对于特定问题领域我们可能无法获得充足的数据,而在深度学习中我们又总是尽量去收集更多的数据来训练网络,即使这些数据与目标分布不同,由此导致的结果是训练出的模型在实际应用中也许不能很好的工作。
吴恩达的课里讲到,这种问题没有什么系统性的解决办法。一般就是通过人工分析来找出数据不匹配的地方,然后想办法收集或者生成能弥补这种差距的数据。
2. 人脸性别分类器面对的数据不匹配挑战
最近为了做人脸属性转换,训练了一个人脸性别识别的分类器,就碰到了这种数据不匹配的问题。
因为人脸转换使用CelebA作为数据集,所以分类器当然也在CelebA上进行训练,使用的是剪裁对齐后的图片。一开始只使用随机左右翻转的数据增强,训练以及降低方差都没什么难度。但当我使用CelebA之外的人脸图片测试时则表现很差,比如下面图片中前5张,男女的判别全是反的:
我首先注意到小李和凯特的人脸有一定的倾斜,把图片旋正后,认出小李是男人了,可凯特还是汉子。实话说凯特的照片除了肤色有点红以外,我一开始实在看不出有什么特别之处。下面是几张CelebA的图片,看上去和凯特的图差不多。
当然,蒙娜丽莎确实和CelebA的不同,第一张图片的饱和度和色调可能和CelebA的也有点区别,并且是一个长相普通的中国女性,和CelebA不太一样,但我确实想象不出范冰冰和凯特有什么问题,尤其是凯特!于是我找了另一张凯特的图片就是上面图片中的最后一张,还好这张图分类器认出是女人了。
在看不出明显问题的情况下,我只能猜测某些方面存在着人类感知不到的区别。于是为了解决数据分布不匹配的问题,我一方面在模型中加入了正则化,参见gender_classifier.py,另一方面增加了数据增强,加入了随机旋转,剪裁,亮度,对比度,色度,饱和度的随机变化等等,参见dataset.py的augmentate函数(不过github上的这个程序版本并没有使用这些数据增强,后面会提到原因),希望分类器对未知的数据分布能有一定的泛化能力。
通过上述手段,分类器在CelebA开发集上的错误率进一步降低了,对CelebA之外的图片表现也有所提高,但凯特,蒙娜丽莎以及第一张女性照片仍旧识别不出来。
必须要说清楚的是,这里的情况和吴恩达深度学习课程中谈到的并不一样:
- 一是,这不是一个商业应用,没有明确的目标数据集,因而开发集和测试集也都是CelebA的一部分,只是希望训练后得到的系统在广泛随机的图片上也表现良好。因为CelebA的数据均从Internet上收集得到,从人类的角度看,样本非常多样化,所以一开始我以为这是一个合理的期望。
- 二是,收集和处理数据的成本对个人开发者而言非常高,所以这里只是随机从互联网上手工收集一点图片进行评估测试。由于实际上这个项目没有明确的目标和范围,所以就把这些个位数量的图片作为目标。
3. 迁移学习
上述数据不匹配的问题始终得不到解决,最后,使用了迁移学习。facenet_gender_classifier.py在Facenet网络的末段输出后面接两个Dense,在CelebA上只使用随机左右翻转数据增强,训练10轮,不但在CelebA上可以取得接近百分之百的准确率,在测试图片上的表现也非常完美。
使用Facenet做迁移学习是一个非常合理的选择,但这里有一个和普通迁移学习完全不同的地方是:普通的迁移学习是使用已训练的模型和已习得的特征提取能力在一个新的数据集上进行拟合,目标是拟合这个新数据集的分布;而在这个例子中,使用已训练模型的输出特征作为输入,训练一个小网络拟合一个数据集,最终这个小网络不但拟合了这个数据集,而且在不同分布的数据上也能够很好的拟合!这只能说明一点:那就是不同分布的数据输入Facenet,到最后输出时,那些和人脸特征无关的分布特性已经不存在了!对于那个小网络来说,无论输入数据分布是否相同,Facenet输出给它的都是同一个分布,所以无论什么照片它都能很好的识别。
为什么Facenet能处理不同分布的数据呢?我曾有不少猜想:比如数据,网络,任务。。。也进行了一些验证,不过在我找到数据哪里不匹配后,真相水落石出了。
4a. 数据不匹配的真相
前面说过,我使用的是剪裁对齐的图片,当我快速的一张一张过这些图片时,发现CelebA的人脸照片里,双眼都在同一个位置,甚至嘴的位置也大致相同,不管人脸的姿态和大小怎么变化。稍微想一下就明白了,CelebA数据集是自动化处理得到的,所以一定是使用人脸检测软件识别出人脸,然后校正到图像中央(所以即使左右翻转双眼和嘴位置也不变)。而我手工下载的照片则没有注意这一点!
把我自己收集的照片也做相同的位置校正后,之前训练的网络认出凯特和蒙娜丽莎是女人了!第一张人脸确实比较难识别,所以分类器仍旧认成是男人,但也更接近正确了。
那么Facenet为什么能处理位置分布的不同也就明朗了,阅读它的文档和代码后发现:它使用CASIA数据集训练时,用MTCNN做人脸检测对齐,然后做随机剪裁,这就相当于把位置变化了;而使用VGGFace2数据集时除了翻转不需要做数据增强,因为VGGFace2数据集中的图片是这样的:
所以归根结底,还在于训练数据。
等等,卷积的平移不变性(translation invariant)呢?
到这可能就有读者有疑问了,不是说好的卷积具有平移不变性吗?!为啥你这眼睛的位置一变,人脸就识别不出来了呢?!
为此,我重新查阅了《深度学习》第九章 卷积网络 9.2 动机,这一节写道:
对于卷积,参数共享的特殊形式使得神经网络层具有对平移等变(equivariance)的性质。如果一个函数满足输入改变,输出也以同样的方式改变这一性质,我们就说它是等变(equivariant)的。
就是说输入数据的位置变了,输出数值不变但是输出相应的也会做相同的位移。
9.3 池化,写道:
当输入作出少量平移时,池化能够帮助输入的表示近似不变(invariant)。对于平移的不变性是指当我们对输入进行少量平移时,经过池化函数后的大多数输出并不会发生改变。
“等变”!“少量”!“近似”!“大多数”!可见教科书说的就是严谨!不知道谁那么缺德脑补成“平移不变性”,把我都带歪了。。。。
澄清卷积“平移不变性”的误解,已经有人做研究了:《Why do deep convolutional networks generalize so poorly to small image transformations?》。《证伪:CNN中的图片平移不变性》和《既然cnn对图像具有平移不变性,那么利用 图像平移(shift)进行数据增强来训练cnn会有效果吗?》的首位回答对这个问题也都说得非常清楚,他俩都提到了前述论文。不过即使这样,在他们文章的评论里和别人的回答里还有不少不同声音,比如有人猜测全卷积网络/全局池化就能平移不变了,读者们不要被误导。
作为结论,大致上是这样:卷积和池化有能力允许网络具有某些不变性,但需要用变化的数据来训练网络,使之学到期望的不变性。
4b. 数据不匹配的真相
正是由于对CNN的“平移不变”理解不透,导致我之前分析数据不匹配时一直存在盲区,没往人脸位置那方面考虑。但是我一开始也使用了随机剪裁的数据增强呀,为什么不起作用呢?
仔细看一下代码会发现,每个样本只有十分之一的概率会随机剪裁,因为当初做数据增强时并不知道哪里不匹配,就只是打散弹枪式的做各种增强,样本中十分之一的随机剪裁不足以影响网络最终的参数。输入网络的图片都是从178x218剪裁到160x160,凯特那张照片这么处理后眼睛偏离中心确实就很多了。。。Facenet训练时是每个样本都做随机剪裁的,所以它能够应付这种位置变化。
因此,在性别分类器这个例子里,每张图片都做随机剪裁就可以解决数据不匹配的问题。不过对于这个应用,端到端的解决方案并不是必需的,人脸检测+人脸识别组成pipeline是这类应用的普遍解决方式,Facenet之所以要训练变化的位置可能也只是为了提高模型的性能和鲁棒性。
另外,
Understanding Black-box Predictions via Influence Functions提到使用影响函数来帮助解决数据不匹配问题,但两年过去也没听到进一步的成果,所以我猜测可能在实际中并没有取得太大的成效。