利用神经网络为大头照生成卡通表情包(Memoji)

在今年发布的 iOS 12 系统中,苹果推出了一个有趣的新功能——Memoji,这是一种新型的 Animoji,可以用手机的前置摄像头制作自己的专属动画头像。这个功能刚推出的时候,网上就掀起一波晒 Memoji 的热潮。


在玩 Memoji 的时候,有没有想过仅从一张照片上就能生成一个 Memoji?本文就分享一下机器学习专家 Pat Niemeyer 的成果,使用神经网络为真实的人物照片生成相应的 Memoji。具体来说,他测试了 VGG16Face 模型,这是一个训练用于人脸识别的网络,看看将真实照片和“看起来”像多种对象的 Memoji 比较时,它的效果怎样。然后用它来指导选择特征,为新对象创建 Memoji。


代码地址见文末。

图:为特朗普大头照生成的Memoji(娘化了?
图:为奥巴马大头照生成的Memoji


剧透

上面这两张图展示的就是神经网络的生成结果。虽然还有很多不足之处,但我(作者 Pat Niemeyer——译者注)觉得还是很有意思的,而且这种方法不仅简单,还很有效。我个人觉得神经网络可能并没有把这些 Memoji 当成人脸,而且还有多个不利因素,容我一一道来:


  • 卡通图像

首先,第一个问题就是人们以卡通形式表现出来时,“看着”会是什么样子?卡通图像会夸大人物的最明显特征,但有些特征比如发型并不是固有不变的,在不同的照片里都变化很大,甚至每天都不是一个样。由于这个原因,似乎训练能够识别个体的神经网络,才能以考虑到这种变异情况的抽象方式捕捉发型信息。相反地,这意味着它可能不适合从随机图像中生成发型。


  • 肤色和头发颜色

在随机光照条件下拍摄的照片中很难推断肤色,我做了一个简单测试,效果非常糟糕,很好地印证了这一点。在测试中,神经网络通常会选择较亮的肤色,而且总是不能很好地区分现实和不现实选项(未展示)。另外,虽然测试在区分浅色头发和深色头发方面表现良好,但是在呈现色彩鲜艳的头发时多多少少都存在失误。



  • 没有 API

我在做生成 Memoji 这个实验时,面临的一个限制就是目前没有能批量化生成它们的 API(没有直接的方式能在 iOS 上自动化生成它们)。这就限制了我们很难高效地找到可能的 Memoji域作为生成过程的一部分。理想情况下,我们希望使用遗传算法大幅优化特征组合,而非依靠它们的可分离性,但在这个案例中并不可行。


  • 照片选择

选择哪张照片作为生成 Memoji 的素材对最终结果也有很大影响。有些照片生成的结果就比其它的好很多,我也不清楚原因在哪。总的来说,我尽量找那些由代表性的、剪裁得当以及正脸朝前的照片。


神经网络&设置

这项实验的实际代码其实很少,我挨个说一说,源代码链接放在文末。


  • VGG

VGG 是一个非常流行的用于图像识别的神经网络架构。VGG Face 则是实现了专门用于人脸识别的模型,而且整个训练后的网络(包括网络层信息和学习权重)都可以公开下载和使用。所以使用这种预训练模型是最好的选择之一,从头开始训练一个这样的模型需要花费大量的时间。


图:VGG Face图像模型架构


  • Torch

我使用的是 Torch 科学计算框架,它提供了运行 VGG 模型所需的环境,内有基于 Lua 的编程环境、供使用张量进行数学计算所需的程序库,以及搭建神经网络所需的构建模块。我选择 Torch 是因为我之前经常用它。


Torch 可以为我们加载提供好的 VGG Face 模型,只需几行代码就能在上面运行一张图像。基本流程为:


-- 加载神经网络
net = torch.load('./torch_model/VGG_FACE.t7')
net:evaluate()

-- 应用图像
img = load_image(my_file)
output = net:forward(img)
复制代码


还有几步涉及到加载图像和图像标准化,在源代码里可以找到。


  • 使用网络层

如上图所示,VGG 包含不同类型的网络层。首先是包含了 RGB 图像数据的张量,它应用了一系列的卷积、池化、加权以及其它类型的转换。数据的“形状”和维度发生了变化,因为每个网络层会不断学习更多的抽象特征。最终,神经网络的最终层生成一个一维的 2622 个元素的预测向量。该向量表示和训练网络所用的特定人物的匹配概率。


在我们的案例中,我们并不关心这些预测结果,而是想用神经网络比较我们自己的任意人脸数据集。要想实现这一点,我们可以利用预测层下面一层的输出。这一层提供了一个有 4096 个元素的向量,描述了人脸的特征。

output = net.modules[selectedLayer].output:clone()
复制代码


VGG16 有 16 个网络层,用 Torch 的实际实现结果生成了一个 40 层的“模型”设置,其中第 38 层生成了我们所需的结果。


  • 相似性

我们要做的事情基本上就是在神经网络中运行成对的图像,并用相似度指标比较各自的输出结果。比较两个超大型数字向量的一个方法就是使用点积:

torch.dot(output1, output2)
复制代码


这会生成一个标量值,可以把它当成表示向量和高维空间“一致”的比率。


在这个测试中,我们想将预期 Memoji 和多个引用图像进行比较,并合并它们。所以我需要将每对值标准化,进行平均取值以得到一个“分数”。


sum = 0
for i = 1, #refs do
  local ref  = refs[i]
  local dotself = torch.dot(ref , ref) 
  sum = sum + torch.dot(ref, target) / dotself
end
...
return sum / #refs
复制代码


标准化意味着将图像和它自己比较的得分会是 1.0,所以后面越高的“分数”值以为着更高的相似度。


我们还需要用到很多其它类型的指标,两个最明显的指标就是输出结果之间的欧几里得距离和均方误差。我简单用这两个试了一下,但是似乎点积能产生更好的结果,这里我有点摸不着头脑。


第一个测试:一组头像

我首先想验证的是这个人脸网络能不能处理卡通风格的 Memoji。我首先抓取了由 63 个、从谷歌搜索来的人脸 Memoji(大部分来自苹果的 demo)。



然后我选择了一个,让神经网络对所有 Memoji 排序,为我展示基于单张引用图像的前三个匹配结果。


结果很不错。神经网络不仅找出了同一 Memoji(排序第一,分数为 1.0),但第二个和第三个结果可信度不高。


真实图像

现在到了“真实”图像的测试:当和这些 Memoji 比较时,神经网络对真实生活中的图像会做出怎样的结果?我抓取了一些名人的照片,结果如下:

结果还是很有意思的。注意,神经网络只能在数量有限的 Memoji 中选择,而且它在这些图像中看到的主要特征可能并不符合我们的预期。此外,注意这些比较中的分数(置信度)大幅低于和其它 Memoji 相比时的分数。


生成过程

接着,我想把这个过程反过来,使用神经网络选择特征来创建一个 Memoji。这就有点棘手了。我前面提过,并没有明显的方法可以在 iOS 上自动创建 Memoji。虽然在越狱设备上或者黑进某些艺术网络或许能做到,但我还是想试试神经网络这种简单的方法。

在测试时,我用 QuickTime Player 的视频录制功能将我的手机和笔记本相连,然后将其放在角落,刚好让脚本能抓取录屏用于处理。每种特征我都尝试了各种可能性,选择每一种选项,按回车键来抓取和排列输出。



很明显这并不理想,有几个原因:首先,过程很痛苦(有 93 对选择,试着运行了十几次)。更重要的是,它只能让我们每次评估一个特征差异。理论上,我们可以对其迭代,重复尝试直到神经网络不再建议我们改动,但这也并不完美,因此可能存在“局部最小值”(如果一个特征会影响另一个特征的感知,那么评估的顺序就很重要)。


另外,还有个恼人的事情就是摄像头一直跟着我,很小的动作也会影响得分。


结果

开头的时候我剧透了几张结果,但是还可以再精心打磨一番。

不过神经网络在选择脸部特征时似乎很不稳定,也就是在某些情况下,模型选择的前 3 张图像非常相近,但有时又不这样。例如,下面是神经网络为特朗普的发型选择的前三种 Memoji:

有些特征倒也符合我的预期,比如奥巴马据说长有一对“招风耳”,然后神经网络确实按照匹配度从大到小列出了三个结果:

图:为奥巴马Memoji选择的耳朵

但眼睛的变化就比较大了:


图:为奥巴马Memoji选择的眼睛

相反,为特朗普选择的眼睛就变化不大:

图:为特朗普Memoji选择的眼睛


刚开始的时候,奥巴马的下巴我看着实在是太方了,但是过了一会儿我又觉得看着正好(所以说,在这方面如果主观性太强是不太妙的)。


头发颜色

我前面说过,肤色很难区分,选择头发颜色同样是个问题。特朗普和奥巴马两人的头发颜色看起来还说得过去,但是后面我用亮红色头发测试时,神经网络却老是想选灰色:



虽说排名前三的生成结果中有红色头发,但结果并不理想。我尝试了很多照片,想看看有哪些影响因素,比如调整图像的预处理方式。然而,即便我大幅修改了输入图像,神经网络依然锲而不舍的生成灰色头发的 Memoji。


在另一项实验中,我查看了其它网络层的生成结果。回想一下,我们之前选的是第 38 个网络层,因为它是表示脸部特征的最高层。然而我们可以和更低的网络层做个比较,看看有何区别。在使用第 32 个网络层时,结果确实有所不同,头发的颜色得到了更多关注。这一层对应的是 VGG16 模型中最后一个“池化”层,就在第一个“全连接层”之前,所以可能因此它保留了更多的空间和颜色信息。这一层和其它更低的网络层在为亮红色头发生成 Memoji 时,生成的结果更好。


此外,我还尝试了多种方法将颜色头发平均化(按照前三个选择和新网络层)。虽然这样生成了更为合理的结果,但最终也没有得到理想的亮红色头发。


本项目的 Torch 脚本代码见我的 GitHub 项目:

github.com/patniemeyer…


参考资料:
https://patniemeyer.github.io/2018/10/29/generating-memoji-from-photos.html


猜你喜欢

转载自juejin.im/post/5be15f0fe51d452ae43e5921