【生成对抗网络GAN】原理及实现

【生成对抗网络GAN】原理及实现

文献链接

1. GAN的实现原理

GAN的基本架构如下图所示。
在这里插入图片描述
图源
GAN的核心是生成器Generator判别器Discriminator。二者本质上都是多层感知机网络。

  • Generator:负责根据随机信号产生数据(无中生有
  • Discriminator:负责判定Generator生成数据的真伪(火眼金睛

GAN训练的基本流程:每一轮梯度反向传播过程中,先训练Discriminator,再训练Generator。

具体来说,假设现在进行第k轮训练:

  1. 先训练Discriminator:先固定Gennerator,即Gennerator的参数此时不更新。将真图像和上一轮产生的假图像 G k − 1 ( z ) G^{k-1}(z) Gk1(z)拼接在一起,分别打上标签1和0拼接的图像x输入Discriminator进行打分,得到一个score。根据score和标签的损失函数loss就可以梯度反向传播,更新Discriminator的参数。(相当于训练一个二分类神经网络D
  2. 后训练Generator:先固定Discriminatordiscriminator.trainable = False,即Discriminator的参数此时不能更新。Generator根据输入随机信号z产生假图像G^{k-1}(z),输入Discriminator进行打分score。score和标签1之间的差值作为损失函数loss反向传播,更新Generator的参数。

2. GAN的数学原理(简单了解的同学可以不看这里)

变量命名:

  • p d a t a p_{data} pdata:产生数据的概率分布(真图像)
  • p g p_{g} pg:随机信号的先验概率(假图像)

2.1. 训练Discriminator的数学原理

2.1.1. 最优解 D G ∗ ( x ) D^*_G(x) DG(x)
D G ( x ) D_G(x) DG(x)表示假图像与真图像之间的相似性,即上文的score。 D G ( x ) D_G(x) DG(x)越大,则Generator以假乱真的能力越强。
固定Generator时,Discriminator的最优解(极大值点)为: 在这里插入图片描述
2.1.2. 优化问题 max ⁡ V ( G , D ) \max V(G,D) maxV(G,D)
Discriminator的优化目标是增强判别真假的能力,因此可以归纳为一个优化问题,即 max ⁡ D V ( G , D ) \max_D V(G,D) maxDV(G,D)。因为Generator已经固定,有 x = g ( z ) x=g(z) x=g(z) x x x z z z一一映射。因此,第二项可以用 x x x替换 z z z
在这里插入图片描述
很明显, V ( G , D ) V(G,D) V(G,D)是一个香农熵(Jesen-Shannon Divergence,JSD)的形式,是为了衡量两种概率分布(这里是, p d a t a p_{data} pdata p g p_g pg)的相似性提出的方法。
D J S ⁡ ( P ∥ Q ) = 1 2 D K L ( P ∥ M ) + 1 2 D K L ( Q ∥ M ) \operatorname{D_{\mathrm{JS}}}(P \| Q)=\frac{1}{2} D_{\mathrm{KL}}(P \| M)+\frac{1}{2} D_{\mathrm{KL}}(Q \| M) DJS(PQ)=21DKL(PM)+21DKL(QM)
其中, M = P + Q 2 M=\frac{P+Q}{2} M=2P+Q D K L ( ∗ ) D_{\mathrm{KL}}(*) DKL()表示相对熵(Kullback-Leibler Divergence,KLD)。
D K L ( P ∥ Q ) = ∫ x P ( x ) ln ⁡ P ( x ) Q ( x ) D_{\mathrm{KL}}(P \| Q)=\int_x P(x) \ln \frac{P(x)}{Q(x)} DKL(PQ)=xP(x)lnQ(x)P(x)

我们要找到 V ( G , D ) V(G,D) V(G,D)的极大值,因此对式(3)积分号内的数学表达式关于 D ( x ) D(x) D(x)求导,导数为0处即为极大值点:
p d a t a ( x ) 1 ln ⁡ 10 1 D ( x ) − p g 1 ln ⁡ 10 1 1 − D ( x ) = 0 p_{data}(x)\frac{1}{\ln10}\frac{1}{D(x)}-p_g\frac{1}{\ln10}\frac{1}{1-D(x)}=0 pdata(x)ln101D(x)1pgln1011D(x)1=0
进而有
D G ∗ ( x ) = p data  ( x ) p data  ( x ) + p g ( x ) ∈ [ 0 , 1 ] D_{G}^{*}(\boldsymbol{x})=\frac{p_{\text {data }}(\boldsymbol{x})}{p_{\text {data }}(\boldsymbol{x})+p_{g}(\boldsymbol{x})}\in[0,1] DG(x)=pdata (x)+pg(x)pdata (x)[0,1]
易知, p g = p d a t a p_g=p_{data} pg=pdata时, D G ∗ D^*_G DG的值最大。
D G , m a x ∗ = 1 2 D^*_{G,max}=\frac{1}{2} DG,max=21

2.2. 训练Generator的数学原理

Discriminator固定时, 令损失函数 C ( G ) = V ( G , D G ∗ ) = max ⁡ D V ( G , D ) C(G)=V(G, D^*_G)=\max _{D} V(G,D) C(G)=V(G,DG)=maxDV(G,D),优化目标转变成使生成假图像尽可能接近真实图像。因此,形成了一个新的优化问题: min ⁡ G C ( G ) = min ⁡ G max ⁡ D V ( G , D ) \min_G C(G)=\min_G \max _{D} V(G, D) minGC(G)=minGmaxDV(G,D)

那什么时候 C ( G ) C(G) C(G)最小呢?
应该是 p g p_g pg p d a t a p_{data} pdata最接近的时候,即生成的假图像最接近真实图像。理想的情况就是和真图像一摸一样。
那么,用香农熵考察 p g p_g pg p d a t a p_{data} pdata的相似性:
D J S ( p d a t a ∥ p g ) = 1 2 D K L ( p d a t a ∥ p d a t a + p g 2 ) + 1 2 D K L ( p g ∥ p d a t a + p g 2 ) = 1 2 ( log ⁡ 2 + ∫ x p d a t a ( x ) log ⁡ p d a t a ( x ) p d a t a + p g ( x ) d x ) + 1 2 ( log ⁡ 2 + ∫ x p g ( x ) log ⁡ p g ( x ) p d a t a + p g ( x ) d x ) = 1 2 ( log ⁡ 4 + V ( G , D G ∗ ) ) = 1 2 ( log ⁡ 4 + C ( G ) ) \begin{aligned} D_{J S}\left(p_{data} \| p_{g}\right)=& \frac{1}{2} D_{K L}\left(p_{data} \| \frac{p_{data}+p_{g}}{2}\right)+\frac{1}{2} D_{K L}\left(p_{g} \| \frac{p_{data}+p_{g}}{2}\right) \\ =& \frac{1}{2}\left(\log 2+\int_{x} p_{data}(x) \log \frac{p_{data}(x)}{p_{data}+p_{g}(x)} d x\right)+\\ & \frac{1}{2}\left(\log 2+\int_{x} p_{g}(x) \log \frac{p_{g}(x)}{p_{data}+p_{g}(x)} d x\right) \\ =& \frac{1}{2}\left(\log 4+V\left(G, D^{*}_G\right)\right)\\ =& \frac{1}{2}\left(\log 4+C\left(G\right)\right) \end{aligned} DJS(pdatapg)====21DKL(pdata2pdata+pg)+21DKL(pg2pdata+pg)21(log2+xpdata(x)logpdata+pg(x)pdata(x)dx)+21(log2+xpg(x)logpdata+pg(x)pg(x)dx)21(log4+V(G,DG))21(log4+C(G))
进而, C ( G ) C(G) C(G)可以表示为
C ( G ) = − log ⁡ ( 4 ) + 2 ⋅ D J S ( p data  ∥ p g ) C(G)=-\log (4)+2 \cdot D_{JS}\left(p_{\text {data }} \| p_{g}\right) C(G)=log(4)+2DJS(pdata pg)
因为香农熵 D J S ( ∗ ) D_{JS}(*) DJS()非负,且在 p g = p d a t a p_g=p_{data} pg=pdata时取到 D J S ( p data  ∥ p g ) = 0 D_{JS}\left(p_{\text {data }} \| p_{g}\right)=0 DJS(pdata pg)=0,有损失函数最小值 C ∗ ( G ) = − log ⁡ 4 C^*(G)=-\log4 C(G)=log4

3. GAN的算法实现(Python)

我将实现的GAN开源在Colab上:Code

4. ArcaneGAN虚拟人脸生成

介绍一个GitHub上好玩的GAN项目《双城之战》风格人脸生成ArcaneGAN

这里是引用
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用TensorFlow实现GAN的代码示例: ```python import tensorflow as tf from tensorflow.keras.datasets import mnist from tensorflow.keras.layers import Input, Dense, Reshape, Flatten, Dropout, LeakyReLU from tensorflow.keras.models import Sequential, Model from tensorflow.keras.optimizers import Adam import numpy as np import matplotlib.pyplot as plt # 定义生成器模型 def build_generator(latent_dim): model = Sequential() # 添加一个全连接层 model.add(Dense(128 * 7 * 7, activation="relu", input_dim=latent_dim)) model.add(Reshape((7, 7, 128))) # 添加反卷积层 model.add(Conv2DTranspose(128, kernel_size=3, strides=2, padding="same")) model.add(BatchNormalization()) model.add(LeakyReLU(alpha=0.01)) model.add(Conv2DTranspose(64, kernel_size=3, strides=1, padding="same")) model.add(BatchNormalization()) model.add(LeakyReLU(alpha=0.01)) model.add(Conv2DTranspose(1, kernel_size=3, strides=2, padding="same", activation="tanh")) # 输出生成器模型 noise = Input(shape=(latent_dim,)) img = model(noise) return Model(noise, img) # 定义判别器模型 def build_discriminator(img_shape): model = Sequential() # 添加卷积层 model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=img_shape, padding="same")) model.add(LeakyReLU(alpha=0.01)) model.add(Conv2D(64, kernel_size=3, strides=2, padding="same")) model.add(BatchNormalization()) model.add(LeakyReLU(alpha=0.01)) model.add(Conv2D(128, kernel_size=3, strides=2, padding="same")) model.add(BatchNormalization()) model.add(LeakyReLU(alpha=0.01)) model.add(Flatten()) model.add(Dense(1, activation="sigmoid")) # 输出判别器模型 img = Input(shape=img_shape) validity = model(img) return Model(img, validity) # 定义训练过程 def train(generator, discriminator, combined, epochs, batch_size, save_interval): # 加载MNIST数据集 (X_train, _), (_, _) = mnist.load_data() # 将像素值缩放到[-1, 1]之间 X_train = X_train / 127.5 - 1. X_train = np.expand_dims(X_train, axis=3) # 真实样本的标签为1,生成样本的标签为0 real = np.ones((batch_size, 1)) fake = np.zeros((batch_size, 1)) for epoch in range(epochs): # --------------------- # 训练判别器 # --------------------- # 随机选择一个批次的真实样本 idx = np.random.randint(0, X_train.shape[0], batch_size) imgs = X_train[idx] # 生成一批噪声作为输入 noise = np.random.normal(0, 1, (batch_size, latent_dim)) # 使用生成器生成一批假样本 gen_imgs = generator.predict(noise) # 训练判别器 d_loss_real = discriminator.train_on_batch(imgs, real) d_loss_fake = discriminator.train_on_batch(gen_imgs, fake) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # --------------------- # 训练生成器 # --------------------- # 生成一批噪声作为输入 noise = np.random.normal(0, 1, (batch_size, latent_dim)) # 训练生成器 g_loss = combined.train_on_batch(noise, real) # 打印损失 print("%d [D loss: %f] [G loss: %f]" % (epoch, d_loss[0], g_loss)) # 每隔save_interval个epoch保存一次生成器的输出 if epoch % save_interval == 0: save_imgs(generator, epoch) # 保存生成器的输出 def save_imgs(generator, epoch): r, c = 5, 5 noise = np.random.normal(0, 1, (r * c, latent_dim)) gen_imgs = generator.predict(noise) # 将像素值缩放到[0, 1]之间 gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(r, c) cnt = 0 for i in range(r): for j in range(c): axs[i,j].imshow(gen_imgs[cnt, :,:,0], cmap='gray') axs[i,j].axis('off') cnt += 1 fig.savefig("gan_mnist_%d.png" % epoch) plt.close() # 设置超参数 latent_dim = 100 img_shape = (28, 28, 1) optimizer = Adam(0.0002, 0.5) # 构建判别器 discriminator = build_discriminator(img_shape) discriminator.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy']) # 构建生成器 generator = build_generator(latent_dim) # 构建组合模型 z = Input(shape=(latent_dim,)) img = generator(z) validity = discriminator(img) combined = Model(z, validity) combined.compile(loss='binary_crossentropy', optimizer=optimizer) # 训练模型 epochs = 20000 batch_size = 128 save_interval = 1000 train(generator, discriminator, combined, epochs, batch_size, save_interval) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值