龙空技术网

数字人算法知多少?Wav2Lip和SadTalker技术原理详解

极市平台 620

前言:

此时兄弟们对“sample算子”大约比较注意,大家都想要知道一些“sample算子”的相关内容。那么小编同时在网上网罗了一些有关“sample算子””的相关内容,希望你们能喜欢,同学们一起来学习一下吧!

作者丨wwdok

编辑丨极市平台

最近两年,数字人受到越来越多人的关注。数字人可分为3D和2D。3D的话比较出名的是虚幻引擎的meta human,背后的技术涉及到blendshape等等。而本文将介绍两个比较知名的2D数字人算法,分别是SadTalker和Wav2Lip。另外,最近泰勒斯威夫特说中文的视频很火,据说背后用到的算法之一是GeneFace++,不过限于篇幅和它的前提知识比较多,本文暂时不讲。

2D数字人根据输入类型的不同,还可以进一步分为视频+音频,wav2lip和geneface属于这一类,这一类算法只生成新的口型,另一类的输入是图片+音频,sadtalker属于这一类,这一类不仅生成新的口型,还生成头部运动,复杂度较高。

Wav2Lip技术原理论文:《A Lip Sync Expert Is All You Need for Speech to Lip Generation In the Wild》官方代码:

wav2lip采用的是GAN的训练范式,但它一共有1个生成器(下图左边大框,Generator)和2个判别器(下图右边两个小框,分别是pre-trained lip-sync expert和visual quality discriminator)。

为什么要两个判别器呢?因为作者认为之前的唇音同步效果不佳,是因为损失函数设计上有问题,比如对全脸应用L1的重建损失,因为嘴唇区域只占图片4%的面积,导致模型训练前期是在学习重建姿态、身份、背景等信息,后半阶段才会开始对嘴唇变形,因此作者认为需要一个额外的判别器来判断唇音同步。而现有的像LipGAN里的唇音同步判别器太弱,在LRS2测试集上只有56%的准确率,而本文使用的lip-sync expert能达到91%。作者认为LipGAN效果不佳的原因是,第一,只使用了单帧画面,没有使用时序上的上下文信息,第二,判别器聚焦在了生成图像上的伪影(artifacts)而不是唇音同步。基于这两个发现,作者提出了一个预训练好的唇音同步判别器,正如名字所强调的,训练好后就不再微调,否则会像LipGAN那样,模型权重被污染。这个唇音同步判别器基于SyncNet改造而来,SyncNet输入帧画面和形状的音频频谱图。SyncNet内有图像编码器和音频编码器(两者主要都是堆叠了一些Conv2d),分别对图像音频编码后得到face_embedding和audio_embedding,训练时,会随机选取跟一段音频匹配的画面和不匹配的画面,来作为正样本和负样本。损失函数的计算方法就是对face_embedding和audio_embedding计算余弦相似度,得到[0,1]之间的数值,然后根据正样本或负样本做BCE。

讲完唇音同步判别器,剩下的一个生成器和一个判别器就跟常规的GAN差不多了。

生成器由三部分组成:(i) Identity Encoder, (ii) Speech Encoder, (iii) Face Decoder,如上图中的蓝色、绿色、红色所示。它们内部主要都是由2D卷积组成,人脸解码器的上采样使用的是转置卷积。身份编码器的输入比较特殊,包括随机选取的参考帧(上图的粉红框)和被遮掉下半部分的、要重新合成嘴型的视频帧(上图的橙色框),每张图片3个通道,所以它的输入是6通道,而音频编码器只有一张单通道的梅尔频谱图。训练时,等生成器生成连续的帧后,再一起送给唇音判别器计算损失函数。 还有个细节是,音频和图像这两种模态在生成器里怎么融合的。简单来说,首先音频编码器把音频从输入形状[B, 1, 80, 16]编码为形状[B, 512, 1, 1]的张量,图片编码器把图片从输入形状[B, 6, 96, 96]编码到[B, 32, 48, 48][B, 64, 24, 24]、...、[B, 512, 3, 3][B, 512, 1, 1]等不同尺度的形状,然后获取[B, 512, 1, 1]的音频特征和[B, 512, 1, 1]的图像特征,在channel维度拼接在一起,输入给第一层解码器,解码器输出的张量再跟下一个尺度的图像特征拼接到一起,输入给第二层编码器,以此类推。

SadTalker技术原理论文:《SadTalker: Learning Realistic 3D Motion Coefficients for Stylized Audio-Driven Single Image Talking Face Animation》官方代码:我用modelscope封装的sadtalker:

展开细讲,SadTalker利用3DMM技术对图片中的人脸进行3D重建,得到表情系数和头部姿态系数,作为后续合成视频每一帧的参考系数。

后续每一帧的表情系数和头部姿态系数分别是由ExpNet、PoseVAE这两个模型输出。为什么不把表情系数和头部姿态系数用一个模型输出就好?因为作者发现,表情运动是局部的,头部运动是全局的,且表情跟声音的关系比较强,头部姿态跟声音的关系比较弱,将这两个系数解耦开可以减少人脸扭曲。

ExpNet的测试时和训练时的工作流程如下图所示:

这里讲一下上面提到的3DMM技术和3D人脸重建。3DMM是3D人脸重建中的一种技术或思想。3DMM(3D Morphable Models)的思想是用以下等式建模一个3D人脸:

PoseVAE的训练时和测试时的工作流程如下图所示:

目前我们已经得到了每一帧的表情系数和头部姿态系数,接下来我们要使用3D-aware Face Render将这些系数转换为一帧帧图片,那怎么转换呢?作者从 face-vid2vid中获得了灵感,face vid2vid能实现输入一张图片和一段视频,输出受视频中的人脸驱动的图片中的人脸的视频。不过,在face-vid2vid中,它拥有一个驱动的视频作为驱动信号,(实际做法是从视频中提取人脸3D关键点作为驱动信号),而我们这里只能通过 3DMM 运动系数(表情系数和头部姿势系数)来驱动。如下图所示,作者使用 mappingNet 来将 3DMM 运动系数映射成3D关键点

(代码中实际上mappingNet只生成

这些系数,然后再用这些系数对canonical keypoint做变换得到15个3D关键点)。mappingNet主要是通过几个一维卷积层构建的。与 PIRenderer一样,为了人脸动作更平滑,作者使用整个滑动时间窗口中(体现在代码中就是def transform_semantic_1def transform_semantic_target里的参数semantic_radius)的系数来合成一帧画面。

有了源图片、源3D关键点、驱动3D关键点,将它们送给Image Generator,就能合成每一帧画面了。 Face vid2vid和3D-aware Face Render的工作流程如下图所示:

至于mappingNet的训练,包含两个步骤:首先,按照原论文中的方法训练 face-vid2vid。第二步,冻结appearance encoder, canonical keypoints estimator 和 image generator的所有参数,重构pipeline后在真实视频的 3DMM 系数上训练mappingNet。最终生成视频按照face-vid2vid的原始实现方式进行。

这一部分论文中讲得比较少,因为大部分内容都是借鉴自face-vid2vid的论文《One-shot free-view neural talking-head synthesis for video conferencing》,项目主页: 。

Image Generator代码中对应的是class OcclusionAwareSPADEGenerator。要想看懂里面的代码,需要对3D版的卷积算子和3D版的grid_sample算子比较熟悉,已经写了很多字了,这里我就偷懒跳过不展开讲了。

如果你想体验SadTalker,除了跑官方代码仓库外,也可以试试我用modelscope封装的sadtalker库( ),它的优点是把模型权重也打包进去了,国内下载速度很快,几行代码就可以调用sadtalker的能力。

标签: #sample算子