岐山凤鸣

Ecohnoch~Student~Software Engineering

更深入理解StyleGAN,究竟什么在控制人脸生成,我该如何控制?

Dec 9, 2019


原创:岐山凤鸣,转载请注明本站域名

理解可能有偏差,有错误请指出~

参考:

[1] Image2StyleGAN: How to Embed Images Into the StyleGAN Latent Space?

[2] A Style-Based Generator Architecture for Generative Adversarial Networks

前言:这篇StyleGAN的follow文章很有点意思,也是19年ICCV的Oral论文,是对StyleGAN进行的更多的理解和分析,而正是这些理解和分析,让StyleGAN有了超越仅仅生成高清图像的领域,进而对GAN有了更多的理解也有了更多的操作空间。什么是对GAN的理解?GAN本质是根据一个空间的分布(如512d向量空间),得到另一个空间的分布(如1024x1024x3的人脸空间),如果对这个有更多理解后,对原空间进行一些操作,从而让目标空间根据你想要的结果发生变化,这是非常awesome的。

理解StyleGAN

先放一张用烂的神图:

这图直接表明了StyleGAN的网络结构,很直观有两部分组成,一部分是左边的mapping网络和右边的Synthesis网络。

先明确输入,输入是一段随机分布latent,记为zz,首先zz经过Norm后,直接由多个串联的FC进行映射,映射到latent space \omegaω,关于这个的中文说法,有的说是"潜空间"或者"隐空间",总之我认为这个就是一个编码空间,每段编码经过仿射变换意味着一个 style,之后将style进行合成就能形成人脸。

那么原始输入latent映射到了latent space之后,假如原始latent的shape是[512],那当前映射后的shape还是是[ 512],再经过一些变换,得到n个[512]输入上图的A即仿射变换后得到n个style,其中每个style的编码是(2)的向量,即为(y_{s,i}, y_{b,i})(ys,i,yb,i),i表示第几层。这里在代码实现的时候,直接将向量经过多个个FC后,broadcast到n个layer后经过updating moving average + style mixing regularization + truncation trick后即可,可直接输入(n,512)的编码dlatent。

这里知道了A的输出是什么之后,再看最右边,是n个高斯噪音输入,这个是直接对特征图作用的,关于GAN中加噪音的原因可以参考别的资料,这里基本就是引入随机的细节。接下来是右边网络的细节部分,看下两图:

这是一个自顶向下的结构,最顶上的输入是一个const的比如4x4x512的矩阵,层层会进行传递,每层都包括style的输入和噪音的输入,输出是一个[res, res, channel]的矩阵,跨层的时候需要降采样,层内传递需要一个AdaIN模块和3x3的conv,最底层输出的是[1024,1024,3]的生成图像。AdaIN的模块公式上面给了,意思很简单,对特征图进行标准化后,和两个style值进行平移和缩放,然后一起经过conv。这个操作很像BN,但不同的是两个style值是根据编码来的,而不是特征图,这里对理解来说很重要,理解了BN也就能理解这个AdaIN模块的重要性。

简略的说,从代码层面考虑,整个过程很简单,就这样:

  1. 输入一个随机向量z,shape=(512,1)
  2. 多个FC对随机向量直接进行变换,得到z_{latent}zlatent,shape=(512,1)
  3. 复制n层z_{latent}zlatent,n表示右边结构的层数,shape=(n,512),经过uodating moving average + style mixing regularization + truncation后,得到dlatent,shape=(n,512)
  4. 先得到一个初始const图,往下进行输入
  5. 进行每层结构的计算,结构开始需要一个降采样,比如(4,4,512)降采样到(8,8,512),给feature_map加点高斯噪音,然后标准化。对输入的512的latent进行放射变换得到两个y,根据两个y对标准化的feature_map进行放缩和平移,之后输入conv进行channel变化
  6. 将n个结构都跑完,前几个结构都是4x4,8x8这种小的,主要是学的轮廓啊,头发在哪啊这些玩意,中间的几个结构比如32x32,64x64这种大一点的,主要是学的更多的人脸表情啊,眼睛啊什么的,最后几个更大的比如256x256,512x512,1024x1024学的就是超细节的比如毛发啊,颜色啊什么的。
  7. 输出最后的1024x1024x3

所以可以看到这个过程并不难,有兴趣的同学可以去读源码,读源码的话,一个完整的链是这样的:

  1. 302行的G_style是完整的生成器流程
  2. 334行定义synthesis网络,即440行的G_synthesis,同时了解总层数这些信息,dlatent的shape即是(n_layers,512)这种
  3. 338行定义mapping网络,即384行的G_mapping
  4. 根据随机的latent生成dlatent,四个步骤嘛,分别是345行的mapping,然后是348行的update,然后是356行的style mixing,然后是369行的truncation,最后得到dlatent
  5. 378行直接将dlatent输入syntheis网络即可,噪音均在中间生成。

只有上述过程全部了解,才能开始下面的内容,所以要理解如何进行嵌入和编辑,必须对StyleGAN有很完整的理解。

到底什么东西在控制人脸生成?

一句话,dlatent,其shape=(n_layers, 512)。

这到底是什么东西?

刚刚已经说了,它的前面几层在做什么?前面几层是4x4,8x8这种小图,前面几层的风格即是脑袋轮廓,头发位置这些显而易见的宏观风格。

所以它的中间几层,不断的一点点放大,去学的细节就会越来越多,n_layers越多,给的细节就越丰富,细节程度是自顶向下的那种,最顶部的细节是粗糙的,最底部的细节是最精细的。

每一个结构里,输入的dlatent 512编码,都仿射变换到了两个数y,然后带噪声的特征图通过标准化后用这两个y进行平移和放缩(AdaIN),所以实际控制风格的只有y,y来自于dlatent,这即表示输入当前层的dlatent即包含风格。

举个很简单的例子,比如你最后要输出256x256x3的清晰图像。那么整个res的变化是:

(4,4) -> (8,8) -> (16,16) -> (32,32) -> (64,64) -> (128,128) -> (256,256)

这一共是7个要变化的res,也就是需要7个结构,每个结构是包含两层的(一层欠采样,一层正常变换),所以一共14层,那么原始的z编码后是得到(14, 512)的编码,分别输入这14层。

第一层之前首先先init了一个(4,4,512)的东西,这时候还不是图像,然后加个噪音后标准化,将dlatent的第一个(512)提出来放射变换到y1,y2后对标准化后的图进行控制平移和放缩,然后一层层的输入。

所以就是这么简单,(14,512)的编码,一层层逐级的在控制人脸的生成。如果你改变(14,512)的前两三层,可能这个人的脑袋就变了,如果改了最后两三层,可能这个人的肤色什么的,毛孔什么的会发生变化。

如何控制人脸的特征生成?

既然了解了什么在控制人脸生成后,我们要进行控制,就变得很简单,只需要控制这个dlatent即可了。

那么到底如何控制?比如我现在有一张照片I,里面描述的是一个人严肃的表情,我想让他笑起来怎么办?

那么首先,先预训练上述的StyleGAN,得到了G,其中输入(14,512)的编码,会通过G得到一张256,256的图,这时候需要做一个类似AE结构的训练,训练什么?

我们得训练一个编码器,输入I后,得到人脸识别的emb前一层的feature_map,然后用这个feature_map经过一个编码结构,得到(14,512)的编码,然后输入参数冻结的G,得到了假图I',再通过一个预训练的人脸识别网络N(I, I')增加一个损失L给整个编码器,训练编码器。

这到底在干嘛?很简单,我们希望能够得到I这张照片的编码而已,也就是希望控制预训练且参数冻结的G生成出I这张照片。这样我们才能得到I的dlatent,得到dlatent后,通过控制dlatent才能编辑I这个人脸的特征,比如发色什么的。

到这步,我们手上得到了两个东西,生成器G,编码器E,要让I笑起来,怎么办?

这时候需要得到一组人脸数据对(I_1, I_2)(I1,I2),满足一个条件,前者是严肃不笑的照片,后者是笑的照片,都进入E后得到一组两个编码(E_1,E_2)(E1,E2),根据之前的理论,很明显啊,这一组从E_1 -> E_2E1>E2的方向向量,即是控制人脸笑起来的关键因素,当然这个方向向量也是(14,512)的shape。所以现在唯一要做的,就是求解出这个方向向量,然后作用到E(I)上,那么G(E(I) + \vec{w})G(E(I)+w)就是让I笑起来的图了。

其他的例如表情迁移(哭->笑)、特征迁移(白发->黑发)这些都用类似的操作就可以很容易的实现。关于求解这个向量,这个问题下节进行详述。


 
 542305306@qq.com ·  Github · RSS · 某只Ecohnoch · © 2015 Gaohaoyang · Designed by HyG
 

 
岐山凤鸣

Ecohnoch~Student~Software Engineering

[闲谈]论被StyleGAN摧残的一天

Dec 9, 2019


原创:岐山凤鸣,转载请注明本站域名

这段时间做了很多GAN相关的研究,因为希望将之前投稿CVPR的文章结合GAN一起,做一点更强的工作,甚至是开创性的工作。

所以我兴冲冲的从DCGAN开始,复现了一个当前国内还没有的仅靠一段声纹生成人脸的应用,具体可以从Demo这里看到。当然,这个是从DCGAN出来的,人脸呢,很模糊,细节基本都不清晰,分辨率更是只有可怜的64x64,还不能改。

于是从DCGAN转战到17年传言巨强的WGAN,根据WGAN-GP的各种原理,对我的网络进行了从网络结构,到loss层面的大修改,这时候我还不能充分的理解WGAN带来的巨大的变革,只能从它论文中对DCGAN错误的推导,和大家纷纷惊叹的评论中知道,这个解决了很多原生GAN的问题,让调参变得更简单。

这篇知乎文章中,了解到它的改进主要基于四点:

  1. D去掉了sigmoid
  2. D和G的loss,不再用以前的sigmoid交叉熵形式,而是直接对向量编码的输出取sum
  3. D的参数截断
  4. 采用不基于动量的优化算法

相比于具体的技术细节,我这里更想分享一下我个人的经历和感受。到这里为止,两年来所有的深度学习模型,机器学习模型,我都尽量的从头到尾,自己按照论文和相关的代码进行复现,自己调出一套最好的参数,从来不会直接把别人的代码弄下来,简单复现一下就再也不去探讨细了。而遇到WGAN的时候,出现了第一个问题,那就是明明计算图、输出均是按照正确的形式搭的,在进行了从DCGAN形式到WGAN形式的转变后,G竟然无法生成正常的图像,它的输出变成了一团糟的乱码。

我尝试把loss再改回去,发现就没有问题了。这仿佛在说DCGAN比WGAN的效果要好,于是回头进行了各种检查,发现了两个问题:

  1. 我的框架里除了D做判别外,还有一个分类器C做人脸的类别分类
  2. GAN的调参之路是比图像识别更难的,我还需要进一步的调整参数

所以就陷入了问题,上述两个总结一点便是经验不足,所以这里我陷入了迷茫,究竟要怎么改?要严格改为和已有代码仓库中一样的参数么?另外一条线里,我在研究GANimation的损失,这里同样遇到了问题,讲究太多了。这才深深明白深度学习被称为炼丹的原因,在之前图像识别的境界里没有遇到这么多和理论复杂的参数。

之后放弃了WGAN的调参,一边进行动画的分析,一边继续寻找更好的人脸GAN,直到我遇到了StyleGAN,这下可把我震撼到了,高分辨率的生成,举个刚出炉的生成的栗子:

很难相信这是用算法生成出的假脸,因为细节实在是太丰富了,用我自己的眼睛去看,我甚至相信这确实就是一张正常的照片,但可惜世界上不存在这样的人。有好事者之后做了一个很火的网站,https://thispersondoesnotexist.com/,每一次刷新都能得到一张不存在的人脸图,这非常的神奇,不得不说NVIDIA大法好。

于是我对着StyleGAN源码,准备进行重现和学习,先按照Guideline进行了test的尝试,这时候我还没意识到什么,只是感叹这个跨平台的性能做的太好了,直接下完代码后,就能够跑起来得到测试结果。直到看了看细节,再看了看train,我惊呆了,同样是TensorFlow,为什么他这么秀?TensorFlow的代码居然可以写成这样。

这里必须要原谅我的无知,在我早期进行图像识别时,一般是先参考TF官方的源代码的示例,进行搭建,从给出的各个经典模型里进行代码写法的归纳总结,但torch的代码看多了以后,我一度认为Python里torch的代码写的比TF优雅多了,而且更加的pythonic。我在使用TF进行计算图搭建,数据处理的时候,往往都写成流处理的模式,和写sh脚本一样,达到效果即可,很难实现其的封装性。

原本的TF流程大致是这样:

  1. 原始数据的索引构建
  2. 数据输入、预处理的离线或Tensor行为
  3. 计算图的搭建,从Placeholder到opt.minize
  4. 训练流程与测试流程的搭建

而这四步,都是顺序的,流处理形式的,通过这样的方法,我基本都能够很容易的进行他人代码的复现,并且能找到对应的bug,了解更多的细节,我一度认为我自己写代码的瓶颈,在于代码的优雅度,而不在其他方面。现在StyleGAN的源码给了我更多的思路,原来的方法虽然能实现功能,但并不高效,部署效果不好,提示信息不够,高层的逻辑难搞。NVIDIA给出的方案是:

  1. 预先定义好一套深度学习的内核系统,可以随便复制到其他的项目下进行使用。
  2. 训练的时候,采用字典驱动的方法,直接链接对象,无论是数据,方法等。
  3. 测试/部署的时候,无论计算图和预训练和参数,直接加载预训练好的二进制项目。

纸上得来终觉浅,看上去很简单,各位看官可以自行去研究上述的Style源码,会发现非常的头疼,封装性高到很难在里面进行一些修改,但即便如此,可读性又维护在一个很高的层次,这是非常的厉害,正符合去突破我当前存在的瓶颈:代码质量不高、工程化不足。今天被StyleGAN摧残了一整天,但我也成功跑起来了我自己收集的Chinese数据集和修改后的版本,看着训练数的跳动,从4x4到8x8到16x16最终回到1024x1024的过程也是非常的令人兴奋。之后会进一步的修改Demo中提供的展示,希望有一天自己做的东西,不管是功能、技术还是优雅的层面,也能得到如此的认可。


 
 
 542305306@qq.com ·  Github · RSS · 某只Ecohnoch · © 2015 Gaohaoyang · Designed by HyG
 
 

 
 
 
Loading [MathJax]/extensions/MathMenu.js
岐山凤鸣

Ecohnoch~Student~Software Engineering

文章

【置顶】这个博客

Dec 30, 2099

【置顶】新功能【速查本】上新,有兴趣的伙伴可以一起维护

Dec 9, 2099

更深入理解StyleGAN,究竟什么在控制人脸生成,我该如何控制?

Dec 9, 2019

[闲谈]论被StyleGAN摧残的一天

Dec 9, 2019

动态GAN复现(一) GANimation概览、结构、原理与细节

Dec 5, 2019

CentOS内网匿名建站,采用内网穿透,隐藏IP,绕开备案

Nov 22, 2019

从Overleaf到Arxiv中遇到的一些坑

Nov 17, 2019

CVPR2020投稿感想

Nov 17, 2019

深度度量学习(四)正则学习、MMC算法

Jul 9, 2019

深度度量学习(三)正则变换学习、相关例子介绍、爱因斯坦求和约定

Jul 2, 2019

深度度量学习(二)协方差、Mahalanobis距离与Euclidean距离

Jun 24, 2019

深度度量学习(一)向量、距离与变换

Jun 22, 2019

深度学习入门(二十二)天河二号 极端情况下配置所有GPU环境

Jun 12, 2019

深度学习入门(二十)阶段性总结4,调参总结

May 16, 2019

深度学习入门(十九)阶段性总结3,精简式人脸识别

Apr 26, 2019

深度学习入门(十八)阶段性总结2,NetVLAD

Apr 21, 2019

深度学习入门(十七)阶段性总结1,数据读取相关、ResNet精简式写法

Apr 2, 2019

深度学习入门(十六)一周精读论文与代码复刻 Test与Evaluation相关 (Day 6)

Dec 19, 2018

深度学习入门(十五)一周精读论文与代码复刻 各种特殊功能的Layer (Day 5)

Dec 19, 2018

深度学习入门(十四)一周精读论文与代码复刻 MTCNN+ArcFace全流程代码1.0 (Day 4)

Dec 18, 2018

深度学习入门(十三)一周精读论文与代码复刻 ArcFace网络结构与源码分析 (Day 3)

Dec 17, 2018

深度学习入门(十二)一周精读论文与代码复刻 ArcFace (Day 2)

Dec 16, 2018

深度学习入门(十一)一周精读论文与代码复刻 ArcFace (Day 1)

Dec 15, 2018

深度学习入门(十)复习,bp的基本公式原理,深度学习基本概念细节与相关面试题

May 3, 2018

深度学习入门(九)进阶卷积神经网络,参数保存+其他说明

May 2, 2018

深度学习入门(八)进阶卷积神经网络,网络构建+训练

May 2, 2018

深度学习入门(七)简单卷积神经网络

Apr 25, 2018

深度学习入门(六)自编码器Auto Encoder

Apr 7, 2018

深度学习入门(五)多层感知机与bp算法

Apr 4, 2018

深度学习入门(四)loss function与optimizer

Apr 3, 2018

深度学习入门(三)深度学习总览

Apr 2, 2018

数模美赛赛后总结+感想(吐槽)

Feb 18, 2018

网络综合实验总复习

Jan 2, 2018

项目介绍(七)JAVA分布式文件系统项目

Jan 1, 2018

项目介绍(六)背单词软件项目

Jan 1, 2018

项目介绍(五)界面代码自动生成项目

Jan 1, 2018

项目介绍(四)魔塔编辑器项目

Jan 1, 2018

项目介绍(三)Markdown->HTML解释器

Jan 1, 2018

项目介绍(二)个人博客项目介绍

Jan 1, 2018

项目介绍(一)Micro C编译器项目介绍

Jan 1, 2018

深度学习入门(二)TensorFlow系统学习第二篇,手写数字识别

Nov 30, 2017

深度学习入门(一)TensorFlow系统学习第一篇

Nov 2, 2017

密码学与网络安全(九)网络信息安全总复习

Nov 2, 2017

密码学与网络安全(八)EIGamal+Hash+数字签名

Nov 1, 2017

密码学与网络安全(七)公钥密码学+RSA算法+Diffie-Hellman算法及c++代码实现

Oct 26, 2017

密码学与网络安全(六)数论三大定理概念与证明

Oct 24, 2017

密码学与网络安全(五)离散复习与模运算

Oct 16, 2017

密码学与网络安全(四)DES加密过程与C++全独立实现

Oct 9, 2017

密码学与网络安全(三)C++加密/解密第三方库Crypto++初探

Oct 7, 2017

数据库第二次上机各种问题记录

Sep 29, 2017

Web前端(Week1)

Sep 21, 2017

密码学与网络安全(二)对称密码

Sep 20, 2017

密码学与网络安全(一)网络安全框架

Aug 7, 2017

Json解析器全独立cpp版本实现(一)

Aug 7, 2017

Python3重构Markdown解释器并模块化

Jul 26, 2017

独立开发Micro C编译器项目结题

Jul 10, 2017

独立开发Micro C编译器

Jul 10, 2017

独立开发Micro C编译器

Jun 20, 2017

Python全独立开发Markdown解释器

Jun 8, 2017

Python写Lisp解释器(五、原文全翻译)

May 16, 2017

Python写Lisp解释器(四、解释器1.0版本)

May 16, 2017

Python写Lisp解释器(三、eval部分)

May 16, 2017

Python写Lisp解释器(二、标准环境)

May 16, 2017

Python写Lisp解释器(一、parse部分)

May 16, 2017

计算机网络Computer Networking(十一、继续一些典型的题目讲解)

Apr 22, 2017

计算机网络Computer Networking(十、一些典型的题目讲解)

Apr 21, 2017

计算机网络Computer Networking(九、网络层,上)

Apr 17, 2017

TOFEL 2 学校教育

Apr 17, 2017

计算机网络Computer Networking(八、传输层复习(第二部分))

Apr 17, 2017

(搬运+翻译)LAMOST天文望远镜官网数据首页

Apr 16, 2017

TOFEL 1 音乐语言

Apr 14, 2017

(搬运+翻译)天文Python包

Apr 14, 2017

计算机网络Computer Networking(七、传输层复习(第一部分))

Apr 14, 2017

计算机网络Computer Networking(六、应用层复习)

Mar 28, 2017

计算机网络Computer Networking(五、第一章计算机网络与因特网复习)

Mar 21, 2017

《白梦》

Mar 20, 2017

计算机网络Computer Networking(四、传输层)

Mar 9, 2017

计算机网络Computer Networking(三、五层协议体系结构与应用层初探)

Mar 9, 2017

数学之美读书笔记三(分词模型)及自己在NLP这条路上的探索

Mar 7, 2017

计算机网络Computer Networking(二、网络核心及因特网)

Mar 7, 2017

计算机网络Computer Networking(一、网络边缘)

Mar 3, 2017

统计语言模型的实现(Qt实现)

Feb 25, 2017

数学之美读书笔记二(隐含马尔可夫模型)

Feb 8, 2017

TensorFlow学习记录三(会话Session)

Jan 22, 2017

数学之美读书笔记一(自然语言处理模型)

Jan 22, 2017

TensorFlow 学习记录二(第一段代码例子)

Jan 21, 2017

TensorFlow 学习记录一(macOS下的安装和初探)

Jan 20, 2017

《花笺》

Jan 9, 2017

macbook pro到手~

Jan 6, 2017

《凤岐》(三)

Jan 2, 2017

12-28 嗨呀

Dec 28, 2016

Discrete Math复习稀有名词索引 12-26Update

Dec 26, 2016

《凤岐》(二)

Dec 25, 2016

12-25 tyvj水题记录(1023-1024)

Dec 25, 2016

12-24 刷夜中

Dec 24, 2016

12-24 刷夜中

Dec 24, 2016

12-24 tyvj水题记录(1019-1022)

Dec 24, 2016

12-23 tyvj水题记录(1015-1018)

Dec 23, 2016

12-22 tyvj水题记录(1014)

Dec 22, 2016

《白衣》

Dec 21, 2016

12-21 设个记录点, 复活用..

Dec 21, 2016

12-21 tyvj水题记录(1013)(多维背包优化详解

Dec 21, 2016

12-20 tyvj水题记录(1010-1012)

Dec 20, 2016

12-19 tyvj水题记录(1005-1008)

Dec 19, 2016

12-18 tyvj水题记录(1001-1004)

Dec 18, 2016

<算法>tarjan强连通分量算法详解

Dec 15, 2016

<图论>用一款游戏来理解图论

Dec 13, 2016

<代数>格与布尔代数

Dec 13, 2016

《风岐》(一)

Dec 12, 2016

《方鼎》

Dec 9, 2016

《春日麦芽》

Dec 9, 2016

《人间道》

Dec 9, 2016

《雪中-年末有感》

Dec 9, 2016

《西江月-高考送行》

Dec 9, 2016

《小汇总》

Dec 9, 2016

Dispersed Math (离散数学)

Dec 9, 2016

《负重前行》(湄公河行动

Dec 9, 2016

《路过的爱情》(从你的全世界路过

Dec 9, 2016

《路过的爱情》(从你的全世界路过

Dec 9, 2016

《从十三岁到二十七岁》(七月与安生

Dec 9, 2016

《娜塔莎》

Dec 9, 2016

《火尖》

Dec 9, 2016

《易碎》

Dec 9, 2016

《山的衰落》

Dec 9, 2016

《典雅的城市-香港》

Dec 9, 2016

<代数>对左陪集关系的理解

Dec 9, 2016

《传说》(一)

Dec 9, 2016

《蜂灵》

Dec 9, 2016

《缘智》

Dec 9, 2016

《三国有谷堆》

Dec 9, 2016

《北斗增一》

Dec 9, 2016

《骊村》

Dec 9, 2016

《无尽画》

Dec 9, 2016

《英殿》

Dec 9, 2016

《错位》(依据别人剧本写作

Dec 9, 2016

《传说》(三)

Dec 9, 2016

《传说》(二)

Dec 9, 2016

《勇士》读书有感

Dec 9, 2016
分类目录

我的球

 542305306@qq.com ·  Github · RSS · 某只Ecohnoch · © 2015 Gaohaoyang · Designed by HyG
 
12-17 01:31