分享

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

 swordinhand 2023-11-08 发布于美国
图片
作者丨wwdok
编辑丨极市平台

极市导读

 

详解经典2D数字人算法SadTalker和Wav2Lip技术原理。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

最近两年,数字人受到越来越多人的关注。数字人可分为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》

http://cdn./cdn/cvit./images/Projects/Speech-to-Lip/paper.pdf

官方代码:https://github.com/Rudrabha/Wav2Lip

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》

https:///pdf/2211.12194.pdf

官方代码:https://github.com/OpenTalker/SadTalker

我用modelscope封装的sadtalker:https://github.com/wwdok/sadtalker_modelscope

简单来说,SadTalker将音频编码成了中间表示:表情系数和头部姿态系数,n代表合成视频中的帧数,然后再将这些中间表示经由渲染器渲染出每一帧,整体流程如下图所示:

图片

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

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

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

图片

测试时(即推理时),Audio Encoder(代码位于SimpleWrapperV2内)会将每一时间步、形状为的音频梅尔频谱图编码成形状的向量,然后再连同拼接起来,输入给Mapping网络,Mapping网络本质上是全连接层,把每一时间步的512+64+1维的张量映射到64维的。其中是随机生成的一个长度为t的序列,序列里的值代表眨眼的概率或者说力度。用式子表示就是:

经过ExpNet的推理,输出形状(BS, n, 64)的张量,也就是说视频每一帧都有一个64维的表情系数。训练时,把音频和图片输入给wav2lip得到对应口型的视频帧,再把视频的每一帧输入给3D人脸重建模型,模型会输出257个系数,拿取其中的表情系数跟Mapping输出的系数做蒸馏学习(用wav2lip生成的结果做标签来训练,这一点似乎注定了sadtalker在唇形同步上难以超越wav2lip)。其他系数会用来构建lip-reading loss 、facial landmark loss ,这部分内容详见论文附录B.3。

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

,其中, 是平均人脸,是形状系数,是形状基, 是表情系数, 是表情基,平均人脸、形状基、表情基都是3维的。我们只要计算出形状系数和表情系数,我们就能重建一个三维人脸。一种计算这些系数的方法就是是用神经网络模型。

SadTalker里的三维人脸重建模型(代码中的class ReconNetWrapper)本质上一个以resnet50为backbone,去掉最后的全连接层,再接上多头的全连接层,每个头分别预测这些系数,共计257维。不过我们这里只用到这几个系数,共计64+3+3=70维。这70个系数只对第一帧图片提取,作为参考系数,后续帧是用ExpNet、PoseVAE这两个模型分别生成64、6个系数,也是总共70个系数。

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

图片

PoseVAE本质上是一个Conditional VAE,而这个condition就是头部姿态风格是一个形状(46,64)的embedding,也就是说模型能自主学习到46种头部姿态。图中只绘制了Conditional VAE,但从代码来看,还有个AudioEncoder,跟ExpNet里的AudioEncoder模型结构一模一样,也是负责把每一时间步、形状为的音频梅尔谱图编码成形状的向量,但两者不共享权重。

从图中还可以看出,PoseVAE的损失有三部分组成。另外,由符号可知,PoseVAE实际生成的是相对于参考头部姿态系数的偏移量。

经过PoseVAE的推理,输出形状(BS, n, 6)的张量,也就是说视频每一帧都有一个6维的头部姿态系数。

目前我们已经得到了每一帧的表情系数和头部姿态系数,接下来我们要使用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》,项目主页:https://nvlabs./face-vid2vid/

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

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多