具体的对BEGAN
的原理和特点的讲解,就不展开了,具体可以参考这两篇文章
深度学习【43】BEGAN
BEGAN解读
但是其对BEGAN
损失函数的解释,我觉得有点太理论化,不太好理解,以下是对这个对抗生成网络的损失函数的理解
GAN的损失函数
首先看一下CGAN
的判别器和生成器的损失函数
在CGAN
中,生成器是通过一些条件,来生成需要的图像,而判别器是通过输入真假图片和条件,来输出判断的结果
gen_label = generator(image=train_picture, gf_dim=64, reuse=False, name='generator') # 得到生成器的输出
dis_real = discriminator(image=train_picture, targets=train_label, df_dim=64, reuse=False, name="discriminator") # 判别器返回的对真实标签的判别结果
dis_fake = discriminator(image=train_picture, targets=gen_label, df_dim=64, reuse=True, name="discriminator") # 判别器返回的对生成(虚假的)标签判别结果
gen_loss = tf.reduce_mean(-tf.log(dis_fake)) # 计算生成器的loss
dis_loss = tf.reduce_mean(-(tf.log(dis_real) + tf.log(1 - dis_fake))) # 计算判别器的loss
可以看到,判别器的目的是为了让真的图片的判别结果尽量靠近1,让生成的假的图像的判别结果尽量靠近0
而生成器的目的是为了让假的图像尽量像真的,也就是让假的图片的判别结果尽量靠近1
BEGAN的结构
在BEGAN
中,判别器并不是直观的输出判别的结果,而是一个自编码器,用图表示的话,如下图
自编码器也就是把一个图片压缩成一个小的向量,再把这个小的向量重新解压成一张图片。
那为什么要进行这个过程呢,因为在不断训练的这个过程中,这个自编码器就相当于变成了一个特征提取器。
形象的说,在这个过程中训练了一个压缩和解压的方法。这个自编码器(特征提取器)会根据图片的特征进行压缩和解压
假如输入了一张人脸的图片,那在压缩时,会保存一些重要的特征,比如五官和发型。将这些特征抽象出来保存到一个小的向量中,再进行解压。解压的过程也是一样,把这些抽象的人脸特征再表达出来
但是假如输入了一张乱七八糟的非人脸图。那么在压缩的时候,找不到人脸的有效特征,就会乱七八糟的压缩,得到的向量也没有什么价值,最后解压出来的结果也不会和原来输入的图像有什么关联
而生成器就相当于用了半个判别器,它只用到了解压的过程,也就是把一个带有特征的向量,生成一个人脸数据,自己画了一个简单的图
(其实我并不喜欢把这个结构看成是生成器-判别器的结构,而更喜欢看作是生成器-特征提取器的结构)
BEGAN的损失函数
一般生成对抗网络的两个结构(生成器、判别器)的损失函数都直接来源于判别器的输出结果,那现在这个判别器是一个特征提取器时,要怎么设计损失函数呢?
首先,一开始特征提取器的效果并不好,还学不到完全的人脸特征。所以我们需要让特征提取器尽量准确的提取特征,也就是让真图像经过特征提取器的压缩和解压之后,尽可能的形成和原图相似的图片(使用L1_loss
)
于是有了第一个损失函数,下面的input_real
是真实的图像,d_model_real
是真实图像经过判别器(特征提取器)重构后的图像
d_real = tf.reduce_mean(tf.abs(input_real - d_model_real)) # 使用了L1_loss
d_loss = d_real
这个d_loss
就是判别器(特征提取器)的损失函数原型。通过让重构后的图像和原图像尽量相似,来让特征提取器能够更加准确的提取人脸特征并进行重构。
因为这里是为了训练提取人脸特征的能力,所以我们主要是应用了真实人脸的重构数据,因为一开始假的人脸还非常假,所以其重构的结构不能作为判断条件
那生成器的
Loss
呢?
在论文中,生成器的Loss
是下述代码中的g_loss
,其中
d_fake = tf.reduce_mean(tf.abs(g_model_fake - d_model_fake))
g_loss = d_fake
很明显,它是通过让“人造人脸” 经过特征提取器后 重构的人脸 更加接近于 原来输入的“人造人脸”
因为这个特征提取器是一个“人脸特征提取器”,它可以很好的把人脸中的特征提取出来,压缩再解压,进行还原。假如现在有一张图像,通过这个特征提取器后,重构的图像和原图像很类似,那这个图像一定就是人脸图像!这也就是为什么可以用上述损失函数来作为生成器的损失函数,让生成器生成的人脸越来越逼真
但是论文中,还有另一个参数,叫k_t
刚才上面的判别器的损失函数,只是原型,其完整的损失函数如下
d_real = tf.reduce_mean(tf.abs(input_real - d_model_real))
d_fake = tf.reduce_mean(tf.abs(g_model_fake - d_model_fake))
d_loss = d_real - k_t * d_fake
也就是说,判别器不仅仅是用到了真实图像的重构结果,也用到了假的图像的重构结果
假的图像一开始生成的肯定不是人脸,为什么可以把它作为特征提取器的训练内容呢?
在这里,这个k_t
的变量是不断变化的,其一开始是一个很小的小数,比如0.0001
,所以在一开始生成器的结果还不是很好时,几乎就是真实图像在起作用。当训练了一段时间之后,k_t
就会慢慢增加,差不多到2000次时,k_t
增加到了0.04
也就是说,在训练了一段时间之后,随着生成的人脸图像越来越好。人造的人脸图像也会被加入到特征提取器的训练当中。
那为什么,是
d_real - k_t * d_fake
而不是d_real + k_t * d_fake
呢
如果是用加号,那么我们是希望d_real
和d_fake
都越小越好。也就是说我们希望真假图像在重构后,和原图一模一样
但是实际上这并不是我们想要的,而且这种训练方式会很难,在将一张图片进行压缩后,必定会损失某些信息,完全无损的还原,几乎是不可能的
所以在使用上述的——“让真图的重构结果和真图更相近的方法”训练判别器(特征提取器)时,在收敛到一定的层次之后就无法继续收敛
我们需要的是:当真实人脸经过 提取特征重构 之后,在眉头增加了一颗痣,那么这个重构误差就是这颗痣;当生成的人脸经过 提取特征重构 之后,也在眉头增加了一颗痣,那么重构误差也是一颗痣,他们的重构误差是接近的
所以当出现上述这种情况时,这个特征提取器就是一个非常好的特征提取器,也就是让真假图像的 重构误差的分布相似,以训练整个特征提取器提取的特征越来越好
判别器的损失函数总结
生成器在一开始生成图像的质量并不高时,k_t
值很小,可以当做只是在让真实人脸重构后尽量像真实人脸,以达到快速收敛的效果。在收敛到一定程度之后,k_t
的值已经是一个不可忽略的值了,而这时候仅适用真实图像重构的相似度也已经很难优化了,所以使用两个重构的误差来进行优化,达到进一步收敛的效果
所以,生成器和判别器的损失函数以及具体k_t
值的变化过程如下
其中:
是真实图像的重构误差
是生成的图像的重构误差
另一种理解方式
另一种理解方式,假设真假图像经过判别器(特征提取器)重构后得到的和原图的误差分布分别为A'和B'
那么判别器D的目的就是让A'和B'的尽可能的相差大一点,也就是让特征提取器可以更好的分辨真假图像
然后生成器G的目的则是让假图像经过判别器 与原图的误差分布B'尽可能小,也就是让A'和B'尽可能相差的小一点
在论文中证明了A'和B'都是满足正态分布的,所以A'和B'的距离可以用
Wasserstein
距离来得到
大概的概括一下原理就是:根据Wasserstein
距离,来匹配自编码器的损失分布。并采用神经网络结构,在训练中添加额外的均衡过程,来平衡生成器和判别器(具体见论文和代码)
当然以上内容只是个人对该网络结构以及损失函数的理解而已,具体的推导过程可以见其他阐述原理的文章,或者是直接看 BEGAN论文
有一篇文章也不错 BEGAN论文阅读