笔者前言
《FSGAN: Subject Agnostic Face Swapping and Reenactment》是ICCV19的一篇文章,主要工作是面部身份变换和表情迁移,去年文章出来的时候我读过一遍,有些地方看的不是很懂。最近这篇文章的代码开源了,想复现一下,看看能不能用到最近比较火热的视频会议中去,便把这篇文章拿出来重新过了一遍,发现还是有新的收获的,话不多说,让我们直入正题。
What
这篇论文的亮点之一就是同时cover了人脸生成领域常见的两个任务,面部身份变换和表情迁移。给定源人脸和目标人脸,面部身份变换将源人脸贴合到目标人脸上,生成的人脸图像的背景、表情都是目标人脸的,但是身份是源人脸的。表情迁移生成的人脸图像的表情信息是目标人脸的,但是其他信息都是源人脸的。(不过在面对表情迁移任务时,关于源人脸和目标人脸的定义可能会反过来,比如FaceForensics++中的定义与FSGAN的定义就相反)
说了这么多,让我们用图来直观的感受面部身份变换和表情迁移。
上为面部重演,下为面部身份变换
此外,FSGAN还做到了subject agnostic,就是可以应对训练时没有见过的人脸,这也是FSGAN的亮点之一。此外,由于在模型结构中引入了分割模型,所以FSGAN在应对侧脸的时候效果较好。
Why
总的来说,为了降低对数据的依赖和提高模型在不同人物之间的泛化性。
可以看到,在人脸生成领域,除了要提高生成图像的质量,最近的趋势趋向于降低数据依赖。直观上很好理解,我希望我的模型在应对不同的人物,不同的角度都表现的很好,或者说不会太差。因为有时候,我们很难弄到源人物或者目标人物的大量人脸图像数据。
How
从整体的流程图上可以看到,整个模型大体分为三部分、四个生成器。
是源人脸,
是目标人脸,
是重演模块,将源人脸重演成目标人脸的形状,得到
;
是分割模块,对目标人脸进行分割,提取出面部、头发、背景区域,得到分割图
;
是修复模块,将
根据
修复,补充缺少区域;然后通过
的融合模块,将人脸贴合到目标图像中,得到最后的生成图像
。
在描述每个模块的操作原理和训练方法之前,先表一下下面会用到的损失函数。图像重建损失包括了两部分:感知损失,利用预训练好的VGG-19提取图像特征,特征的差异即损失函数。不同于以往的直接使用imagenet预训练好的vgg模型,FSGAN作者使用VGGface2和CelebA训练了模型用于这项损失,如下图:
重建损失的另一部分是逐像素的L1损失:
整体重建损失如下:
对抗损失方面,采用了与pix2pixHD相同的hinge loss以及不同尺度的判别器,具体如下:
面部重演和面部分割
重演模块的实现实际上是一个迭代的过程,作者通过源人脸和目标人脸得到对应的欧拉角以及对应的人脸关键点,然后在两个欧拉角和关键点中插值,进而得到中间状态的关键点
,通过迭代地生成对应中间关键点的面部图像来达到最终的面部重演的效果,公式如下:
可以看到,
以当前图像I和目标关键点的热力图H作为输入,输出生成的目标图像以及图像所对应的分割图。迭代到最后,就可以得到源图像根据目标图像重演之后的生成人脸。
这里的插值很有意思,也很有想法,具体实现细节应该再探究一下,这种逐步迭代的方法解决了pose差异过大所带来的负面效果。
训练阶段,源图像和目标图像都是从同一个视频里选取的,本质上是个重建过程。重演模块的损失包含了四项:1.对抗损失。2.目标人脸的分割结果
,
得到的生成人脸的分割图
,这两个分割结果做逐像素损失。3.模型生成的图像和真值的重建损失,只针对脸部的区域。4.此外,作者还提到了stepwise consistency损失,不过我在代码里没有找到,就是迭代过程中生成的图像和目标图像真值的重建损失。具体如下:
面部分割方面,训练数据集有真实标签,采用了图像分割的交叉熵损失和图像逐像素L1损失,如下所示:
在重演的推断阶段,非常有意思的是,FSGAN利用了源人脸视频的整个序列的信息,他将源人脸的每一帧的欧拉角信息,舍弃roll,保留pitch和yaw,投影到二维平面上,每个点对应一个姿态,连成三角形。在推断阶段,有目标pose作为参考时,找到包含该pose的三角形,然后用三个顶点对应的源人脸的图像,结合目标人脸关键点信息过
,将结果加权得到重演后得到的图像
.
面部修复
面部修复image inpainting模型的训练过程是一个有监督的训练过程,真值是没有了背景的目标图像
。在得到
输出的图像
和分割图
之后,对
进行增广,添加一些遮挡,然后对
使用增广后的分割图除去背景,然后再将除去背景的图像过
得到模型输出值
. 有了真值和输出值,损失函数如下:
面部融合
在面部融合阶段应用了泊松融合,公式如下:
然后训练了融合模型
去输出我们想要的融合后的图像,损失如下,包括重建损失和对抗损失:
不过,为什么不直接用泊松融合做最后阶段,而是训练一个模型要拟合这种输出呢?个人猜测是要利用GAN模型的强学习能力。
数据集选了IJB-C、VGGFace2、CelebA、LFW、FaceForensics++等,分别训练各个模型。评价指标选取了SSIM、欧拉角差异、人脸关键点差异,还使用了dlib提取id信息,进行人脸验证。(这里我没弄明白怎么用dlib做face verification,不过我觉得既然是提取id信息,可以使用预训练好的FaceNet之类的face verification网络或者使用face_recognition包。)
展示如下:
定量比较
表情重演定性比较
面部身份变换定性比较
笔者后记
FSGAN是一个大工程,不同于传统的端到端模型,FSGAN包括了很多需要单独训练的模型,也很好地解决了侧脸的问题。不过,当面对较大的pose时,成像质量会显著下降。并且,FSGAN没办法像三维模型一样很好地捕捉面部细节。
人脸生成方面开源的代码不多,既然这个代码最近已经开源,预训练模型也已提供,是时候跑一波看看效果了,希望可以最终应用到项目上。