Deepfake就是前一阵很火的换脸App,从技术的角度而言,这是深度图像生成模型的一次非常成功的应用,这两年虽然涌现出了很多图像生成模型方面的论文,但大都是能算是Demo,没有多少的实用价值,除非在特定领域(比如医学上),哪怕是英伟达的神作:渐进生成高清人脸PGGAN好像也是学术意义大于实用价值。其实人们一直都在最求更通用的生成技术,我想Deepfake算是一例,就让我们由此出发,看看能否从中获取些灵感。
我们先看看Deepfake到底是个何方神圣,其原理一句话可以概括:用监督学习训练一个神经网络将张三的扭曲处理过的脸还原成原始脸,并且期望这个网络具备将任意人脸还原成张三的脸的能力。
说了半天这好像是一个自编码模型嘛~,没错,原始版本的deepfake就是这样的,公式如下:
这里的XW是经过扭曲处理过的图片,用过Deepfake的童鞋可能会有人提出质疑,“要让代码跑起来好像必须要有两个人的人脸数据吧”。没错,之所以要同时用两个人的数据并不是说算法只能将A与B互换,而是为提高稳定性,因为Encoder网络是共享的,Deocder网络是分开的,上公式:
为了方便理解我照搬项目二(加了Gan的版本)上的说明图片:
版本二我不打算讨论,仅介绍一下,简而言之就是增加了Adversarial Loss和Perceptual Loss,后者是用训练好的VGGFace网络(该网络不做训练)的参数做一个语义的比对。
Deepfake的整个流程包括三步,一是提取数据,二是训练,三是转换。其中第一和第三步都需要用到数据预处理,另外第三步还用到了图片融合技术。所以我在技术上主要分三个方面来剖析:图像预处理、网络模型、图像融合。
1. 图像预处理
从大图(或视频)中识别,并抠出人脸图像,原版用的是dlib中的人脸识别库(这个识别模块可替换),这个库不仅能定位人脸,而且还可以给出人脸的36个关键点坐标,根据这些坐标能计算人脸的角度,最终抠出来的人脸是摆正后的人脸。
2. 网络模型Encoder: 64x64x3->8x8x512x = input_x = conv(128)(x)x = conv(256)(x)x = conv(512)(x)x = conv(1024)(x)x = Dense(ENCODER_DIM)(Flatten()(x))x = Dense(4 * 4 * 1024)(x)x = Reshape((4, 4, 1024))(x)x = upscale(512)(x)Decoder:8x8x512->64x64x3x = input_x = upscale(256)(x)x = upscale(128)(x)x = upscale(64)(x)x = Conv2D(3, kernel_size=5, padding='same', activation='sigmoid')(x)
整个网络并不复杂,无非就是卷积加全连接,编码->解码,但是仔细研究后发现作者其实是匠心独运的,为什么我不急着说,我们先看看con和upscale的内部实现:def conv(filters): def block(x): x = Conv2D(filters, kernel_size=5, strides=2, padding='same')(x) x = LeakyReLU(0.1)(x) return x return blockdef upscale(filters): def block(x): x = Conv2D(filters * 4, kernel_size=3, padding='same')(x) x = LeakyReLU(0.1)(x) x = PixelShuffler()(x) return x return block
conv是中规中矩的卷积加lrelu激活函数,upscale中有个函数叫PixelShuffler,这个函数很有意思,其功能是将filter的大小变为原来的1/4,让后让高h、宽w各变为原来的两倍,这也就是为什么前面的卷积层的filtere要乘以4的原因。
经过测试对比,比如拿掉upscale换成步长为2的反卷机,或者简单resize为原来的两倍,实验的效果都大打折扣,结果是网络只能自编码,而得不到需要的人脸。虽然作者没有说这样设计是引用那篇论文的思想,笔者也未读到过直接讨论这个问题的论文,但是有一篇论文可以佐证:Deep Image Prior,包括Encoder中的全连接层都是人为打乱图像的空间依赖性,增加学习的难度,从而使网络能够更加充分地理解图像。所以Encoder中的全连接层和PixelShuffler都是必不可少的。经笔者测试,在不加Gan的情况下,去掉这两个要素,网络必定失败。
3. 图像融合
图像融合放在技术难点分析中讨论。
1. 清晰度问题
原版的人脸像素是64*64,显然偏低,但要提高人脸清晰度,并不能仅靠提高图片的分辨率,还应该在训练方法和损失函数上下功夫。众所周知,简单的L1Loss是有数学上的均值性的,会导致模糊。解决方案个人比较倾向在L1Loss的基础上加入GAN,因为强监督下的GAN具有区分更细微区别的能力,很多论文都提到这一点,比如较早的一篇超分辨率的文章。但是GAN也有很多问题,这个后面讨论。还有一个思路就是用PixelCNN来改善细节的,但经实践,这种方法不仅生成速度慢(虽然速度可以通过加入缓存机制,一定程度上优化),而且在质量上也不如GAN。
2. 人脸识别问题
由于第一个环节是对人脸做预处理,算法必须首先能识别出人脸,然后才能处理它,而dlib中的人脸检测算法,必须是“全脸”,如果脸的角度比较偏就无法识别,也就无法“换脸”。所以项目二就用了MTCNN作为识别引擎。
3. 人脸转换效果问题
原版的算法人脸转换的效果,笔者认为还不够好,比如由A->B的转换,B的质量和原图A是有一定关联的,这很容易理解,因为算法本身的原因,由XW->X,中不管X如何扭曲总会有一个限度。所以导致由美女A生成美女B的效果要远远优于由丑男A生成美女B。这个问题的解决笔者认为最容易想到的还是Gan,类似Cycle-Gan这样框架可以进行无监督的语义转换。另外原版的算法仅截取了人脸的中间部分,下巴还有额头都没有在训练图片之内,因此还有较大的提高空间。
4. 图片融合问题
由于生成出来的是一个正方形,如何与原图融合就是一个问题了,原始项目有很多种融合方法,包括直接覆盖,遮罩覆盖,还有就是泊松克隆“Seamless cloning”,从效果上而言,遮罩覆盖的效果与泊松克隆最好,二者各有千秋,遮罩覆盖边缘比较生硬,泊松克隆很柔和,其的单图效果要优于遮罩覆盖,但是由于泊松克隆会使图片发生些许位移,因此在视频合成中会产生一定的抖动。图片融合问题的改进的思路,笔者认为还是要从生成图片本身着手,项目二引入了遮罩,是一个非常不错的思路,也是一个比较容易想到的思路,就是最终生成的是一个RAGB的带通明度的图片。笔者还尝试过很多方法,其中效果比较好的是,在引入Gan的同时加入非常小的自我还原的L1Loss,让图片“和而不同”。经测试,这种方法能够使图片的边缘和原图基本融合,但是这种方法也有弊端,那就是像脸型不一样这样的比较大的改动,网络就不愿意去尝试了,网络更趋向于小修小补,仅改变五官的特征。
5. 视频抖动问题
视频抖动是一个很关键的问题。主要源自两点,第一点是人脸识别中断的问题,比如1秒钟视频的连续30帧的图片中间突然有几帧由于角度或是清晰度的问题而无法识别产生了中断。第二点是算法本身精确度问题会导致人脸的大小发生变化。这是由算法本身带来的,因为总是让XW->X,而XW是被扭曲过的,当XW是被拉大时,算法要由大还原小,当XW被缩小时,要由小还原大。也就是说同一张人脸图片,让他合成大于自己的或小于自己的脸都是有道理的,另外当人脸角度变化较大时,这种抖动就会更明显。视频抖动目前尚未有很好的解决方案,唯有不断提高算法的精确度,同时提高人脸识别和人脸转换的精确度。
在原始版本上加入Gan,项目二是这么做的,笔者也进行过较深入的研究。
Gan的优点是能比较快进行风格转换,相同参数下Gan训练2w次就生成比较清晰目标人脸,而原始算法大概需要5w以上,Gan生成的人脸较清晰,而且能减少对原图的依赖等,同时加入Gan之后,可以减少对特定网络模型的依赖,完全可以去掉原网络中的FC和Shuffer。
Gan的缺点也很突出,其训练难以把控,这是众所周知的。Gan会带来许多不可控的因子。比如一个人的肤色偏白,则生成的人脸也会变白,而忘记要与原图的肤色保持一致,比如有的人有流海,训练数据中大部分都是有刘海的图片,则Gan也会认为这个人必须是有刘海的,而不考虑原图是否有刘海。即使加入了Condition,Gan这种“主观臆断”和“自以为是”的特点也无法得到根除,总而言之,加入Gan以后经常会“过训练”。 这种情况在笔者之前做的字体生成项目中也出现过,比如在由黑体字合成宋体字时,Gan经常会自以为是地为“忄”的那一长竖加上一钩(像“刂”一样的钩)。另外Gan有一个最大的弊端就是他会过分趋近训练集的样本,而不考虑表情因素,比如原图的人是在大笑,但是训练集中很少有这类图片,因此生成的图片也许只是在微笑。我不禁联想到了Nvidia的那篇论文,没有条件的Gan虽然可以生成高清的图片,但是没法人为控制随机因子z,无法指定具体要生成生成什么样的脸,而有条件的Gan样本又过于昂贵。Gan的这一大缺点会使生成的视频中人物表情很刻板,而且画面抖动的情况也更剧烈,即使加入了强监督的L1Loss,GAN还是会有上述弊端。总之在原版的基础上加入Gan还需要进一步地研究,2017年Gan的论文很多,但没有多少令人眼前一亮的东西,Google甚者发了一篇论文说,这么多改进的版本与原版的差别并不显著,经测试,笔者得到的结论是Gan困最难的地方是抖动较大,合成视频时效果不太好,也许是Gan力量太强的原故。
单纯从技术的层面上来看,Deepfake是一个很不错的应用,笔者更期望它能用在正途上,能在电影制作,录制回忆篇,纪录片中发挥作用,真实地还原历史人物的原貌,这可能是无法仅由演员和化妆师做到的。笔者也期望在2018年,基于图像的生成模型能涌现出更多可以落地的应用。
免责声明:转载自网络,不用于商业宣传
网络上的两个程序通过一个双向的通信链实现数据的交换,这个链接的一端就成为Socket,它是进程通信的一种,即调用这个网络库的api函数实现分布在不同主机相关进程之间的数据交换
Kubernetes系统上Pod网络的实现依赖于第三方插件,而Flannel是由CoreOS主推的目前比较主流的容器网络解决方案,CNI插件有两种功能:网络配置和网络策略,由于flannel比较简单,并不支持网络策略
通过js加载一张1x1的极小图片,测试出图片加载的所用的时长。如果换一个几百KB的图片,则可心用来计算下载网速 ,第一次加载图像时,它将比后续加载花费更长的时间,即使我们确保图像没有被缓存。
2019年已经是互联网发展的成熟期了,随着网络的不断发展,以及手机应用的普及,几乎人人都已经会使用网络工具。但是又有多少人知道网络赚钱这个小众的赚钱方式呢?
在Angular网络请求是一个最常见的应用之一,下列我将以 ng-alain 项目为基础描述 Angular 网络请求。注:示例中代码都以简化的形式出现。
大多数情况下,在前端发起一个网络请求我们只需关注下面几点:传入基本参数(url,请求方式),请求参数、请求参数类型,设置请求获取响应的方式
为何在百度搜索之后,一些网站总能够推荐我刚刚搜索过的东西?百度会记录你的搜索信息,同时会在你本地保存一个标识本地的cookie,而当你打开第三方网站时,第三方网站嵌入了百度广告的JS代码
SDN的概念主要体现的是技术架构视角,强调的是实现网络设备的软件硬件解耦、网络系统的控制面与转发面解耦,以及整体全面的可编程性。SDN的优势在于它是基于系统全局信息进行网络转发等的策略决策的
为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值
最近在做大屏数据可视化项目得时候,在思考项目交付和运行情况得时候,考虑到了需要在公司大屏显示器上面展示,突然想到了项目可能面临断网及其网速慢得情况下得一下展示问题,因此作为专栏进行这两个问题得讲解
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!