图像生成:生成对抗网络 (GAN) 与深度卷积生成对抗网络 (DCGAN)
01
简介
生成对抗网络 (GAN) 是一种使用两个神经网络相互对抗的算法架构(因此称为“对抗”) ") 生成可以传递真实数据的新合成数据实例。它们广泛用于生成图像、视频和语音。
虽然大多数深层生成模型是通过最大化对数似然或对数似然下限来训练的,但GANs采用了完全不同的方法,不需要对数据的可能性进行推断或显式计算。相反,使用两个模型来解决最小化任务:对数据进行采样的生成器,以及将数据分类为真实数据或生成数据的鉴别器。
本文以最直观的方式向初学者介绍了生成对抗网络(GAN)的基本概念。目标是在不深入研究复杂数学的情况下,以更实用的方式描述这样一个网络的运行,以便读者能够开发自己的简单 GAN。
首先构建一个仅包含隐藏密集层的简单 GAN,并尝试输出有意义的图像。分析输出以发现简单 GAN 常见的特定问题。这个问题将在下一节中使用一种称为深度卷积生成对抗网络(DCGAN)的特定类型的 GAN 来解决。
这首歌《数据+代码》的内容已上传至百度网盘。有需要的朋友可以关注公众号【小Z日常科研】并在后台回复关键词【GAN】即可获得。
02
生成对抗网络 (GAN)
GAN 由两个组件组成 -
- 生成器 - 生成新的数据实例
- 鉴别器 - 尝试将生成的数据或虚假数据与真实数据集区分开来。来。
歧视性算法尝试对输入数据进行分类;也就是说,给定数据实例的特征,它们预测该数据所属的标签或类别。因此,判别算法将特征分配给标签。他们只关心这种相关性。或者,生成算法则相反。他们不是根据某些特征来预测标签,而是尝试根据特定标签来预测特征。
训练时,它们都从头开始,生成器学习在整个训练时期塑造随机分布。
它是如何工作的
生成生成网络以随机分布的形式输入噪声,并从噪声中生成虚假数据。来自生成器的错误数据被输入鉴别器。训练后,生成器应该能够从噪声中生成真实的可比较数据。
这里有趣的事实是,生成器甚至无需查看图像就可以学习生成有意义的图像。
鉴别器或敌对网络充当生成器的对手。它基本上是一个分类器或鉴别器,其功能是区分两个不同类别的数据。这里的类是真实数据(标记为 1)和生成器生成的假数据(标记为 0)。
训练网络
训练 GAN 时最重要的事情是这两个组件永远不应该一起训练。相反,网络在两个不同的阶段进行训练。第一阶段包括训练判别器并适当更新权重,下一步包括训练生成器,同时禁用判别器训练。
阶段 1 在训练的第一阶段,生成器接收随机数据(以分布的形式)作为噪声。生成器创建许多随机图像,并将其馈送到鉴别器。鉴别器还从真实图像数据集中获取输入。鉴别器通过学习或评估其输入的特征来学习区分真实数据和虚假数据。判别器输出一些概率,预测结果与实际结果之间的差异通过网络传播回来,并更新判别器的权重。请注意,在此阶段,反向传播在判别器末尾停止,并且生成器尚未经过训练或更新。
阶段 2 在此阶段,由生成器生成的一系列图像直接作为鉴别器的输入。这次没有真实图像被馈送到鉴别器。生成器通过欺骗鉴别器产生误报来学习。判别器输出概率,根据实际结果进行评估,生成器权重通过反向传播进行更新。在反向传播期间,判别器权重不应更新并保持原样。
简单 GAN 的损失函数
在这个实验中,生成器尝试最小化以下函数,而判别器尝试最大化它:
在这个函数中:
- D(x) 是判别器估计真实数据实例 x 为真的概率。
- Ex 是所有真实数据实例的预期值。
- G(z) 是给定噪声 z 的生成器的输出。
- D(G(z)) 是鉴别器对错误实例的真实概率的估计。
- Ez 是生成器的所有随机输入的期望值(实际上是所有生成的模拟实例 G(z) 的期望值)。
生成器无法直接影响函数中的 log(D(x)) 项,因此对于生成器来说,最小化损失相当于最小化 log(1 - D(G(z)))。
代码实现
导入有用的包:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from keras import preprocessing
from keras.models import Sequential
from keras.layers import Conv2D,Dropout,Dense,Flatten,Conv2DTranspose,BatchNormalization,LeakyReLU,Reshape
import tensorflow as tf
数据加载和预处理:
train_data = pd.read_csv('fasion_mnist/fashion-mnist_train.csv')
X_train = train_data.drop('label',axis=1)
X_train=X_train.values
print(f"X_train形状: {X_train.shape}")
X_train=X_train.reshape(-1,28,28,1)
print(f"X_train形状: {X_train.shape}")
数据可视化:
fig,axe=plt.subplots(4,4)
idx = 0
for i in range(4):
for j in range(4):
axe[i,j].imshow(X_train[idx].reshape(28,28),cmap='gray')
idx+=1
像素数据范围从0到255,所以将每个像素除以25 5,即比如说,对数据进行归一化,使其介于 0 和 1 之间。
注:归一化后,乘以2再减去1,所以范围是(-1,1),因为在DC中GANs最后一层生成模型激活是tanh,也就是范围(-1, 1) ,与 sigmoid 范围 (0.1) 相反。
X_train = X_train.astype('float32')
X_train = X_train/255
X_train = X_train*2 - 1.
print(X_train.max(),X_train.min())
简单GAN模型:
generator = Sequential()
generator.add(Dense(512,input_shape=[100]))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(256))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(128))
generator.add(LeakyReLU(alpha=0.2))
generator.add(BatchNormalization(momentum=0.8))
generator.add(Dense(784))
generator.add(Reshape([28,28,1]))
discriminator = Sequential()
discriminator.add(Dense(1,input_shape=[28,28,1]))
discriminator.add(Flatten())
discriminator.add(Dense(256))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.5))
discriminator.add(Dense(128))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.5))
discriminator.add(Dense(64))
discriminator.add(LeakyReLU(alpha=0.2))
discriminator.add(Dropout(0.5))
discriminator.add(Dense(1,activation='sigmoid'))
注意:生成器层不单独构建,因为它是作为组合模型的一部分进行训练的,但训练鉴别器是必要的,因为它是在组合模型之前训练的。
GAN =Sequential([generator,discriminator])
discriminator.compile(optimizer='adam',loss='binary_crossentropy')
discriminator.trainable = False
GAN.compile(optimizer='adam',loss='binary_crossentropy')
epochs = 30
batch_size = 100
noise_shape=100
with tf.device('/gpu:0'):
for epoch in range(epochs):
print(f"Currently on Epoch {epoch+1}")
for i in range(X_train.shape[0]//batch_size):
if (i+1)%50 == 0:
print(f"\tCurrently on batch number {i+1} of {X_train.shape[0]//batch_size}")
noise=np.random.normal(size=[batch_size,noise_shape])
gen_image = generator.predict_on_batch(noise)
train_dataset = X_train[i*batch_size:(i+1)*batch_size]
train_label=np.ones(shape=(batch_size,1))
discriminator.trainable = True
d_loss_real=discriminator.train_on_batch(train_dataset,train_label)
train_label=np.zeros(shape=(batch_size,1))
d_loss_fake=discriminator.train_on_batch(gen_image,train_label)
noise=np.random.normal(size=[batch_size,noise_shape])
train_label=np.ones(shape=(batch_size,1))
discriminator.trainable = False
d_g_loss_batch =GAN.train_on_batch(noise, train_label)
if epoch % 10 == 0:
samples = 10
x_fake = generator.predict(np.random.normal(loc=0, scale=1, size=(samples, 100)))
for k in range(samples):
plt.subplot(2, 5, k+1)
plt.imshow(x_fake[k].reshape(28, 28), cmap='gray')
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.show()
print('Training is complete')
使用 np.random.normal 生成的噪声作为生成器的输入。在下一步中,生成器从随机分布中生成一批有意义的、相似的图像。
noise=np.random.normal(size=[10,noise_shape])
gen_image = generator.predict(noise)
plt.imshow(noise)
plt.title('Noise')
有噪声的图像:
生成的图像显示:
fig,axe=plt.subplots(2,5)
fig.suptitle('Generated Images from Noise using GANs')
idx=0
for i in range(2):
for j in range(5):
axe[i,j].imshow(gen_image[idx].reshape(28,28),cmap='gray')
idx+=1
经过数十次迭代后,生成器学会仅用一类特定的输出图像来欺骗鉴别器,因此在该点之后停止学习。因此,完成训练后,输出只是一种特征非常相似的图像,即本例中的衬衫,并且生成图像的特征没有变化。
使用DCGAN可以解决上述问题,如下所示。
03
深度卷积对抗网络(DCGAN)
在这个模型中,我们使用转置卷积层而不是简单的密集层来构建生成器,这样可以更好地捕获特征并避免前面描述的问题。同样,在构建判别层时,它使用卷积层来提高分类效率,而不是简单的密集单元。
代码实现
DCGAN 模型:
generator = Sequential()
generator.add(Dense(7 * 7 * 128, input_shape=[100]))
generator.add(Reshape([7, 7, 128]))
generator.add(BatchNormalization())
generator.add(Conv2DTranspose(64, kernel_size=5, strides=2, padding="same",
activation="relu"))
generator.add(BatchNormalization())
generator.add(Conv2DTranspose(1, kernel_size=5, strides=2, padding="same",
activation="tanh"))
discriminator = Sequential()
discriminator.add(Conv2D(64, kernel_size=5, strides=2, padding="same",
activation=LeakyReLU(0.3),
input_shape=[28, 28, 1]))
discriminator.add(Dropout(0.5))
discriminator.add(Conv2D(128, kernel_size=5, strides=2, padding="same",
activation=LeakyReLU(0.3)))
discriminator.add(Dropout(0.5))
discriminator.add(Flatten())
discriminator.add(Dense(1, activation="sigmoid"))
模型训练:
GAN =Sequential([generator,discriminator])
discriminator.compile(optimizer='adam',loss='binary_crossentropy')
discriminator.trainable = False
GAN.compile(optimizer='adam',loss='binary_crossentropy')
epochs = 150
batch_size = 100
noise_shape=100
with tf.device('/gpu:0'):
for epoch in range(epochs):
print(f"Currently on Epoch {epoch+1}")
for i in range(X_train.shape[0]//batch_size):
if (i+1)%50 == 0:
print(f"\tCurrently on batch number {i+1} of {X_train.shape[0]//batch_size}")
noise=np.random.normal(size=[batch_size,noise_shape])
gen_image = generator.predict_on_batch(noise)
train_dataset = X_train[i*batch_size:(i+1)*batch_size]
train_label=np.ones(shape=(batch_size,1))
discriminator.trainable = True
d_loss_real=discriminator.train_on_batch(train_dataset,train_label)
train_label=np.zeros(shape=(batch_size,1))
d_loss_fake=discriminator.train_on_batch(gen_image,train_label)
noise=np.random.normal(size=[batch_size,noise_shape])
train_label=np.ones(shape=(batch_size,1))
discriminator.trainable = False #while training the generator as combined model,discriminator training should be turned off
d_g_loss_batch =GAN.train_on_batch(noise, train_label)
if epoch % 10 == 0:
samples = 10
x_fake = generator.predict(np.random.normal(loc=0, scale=1, size=(samples, 100)))
for k in range(samples):
plt.subplot(2, 5, k+1)
plt.imshow(x_fake[k].reshape(28, 28), cmap='gray')
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.show()
print('Training is complete')
使用 np.random.normal 生成的噪声作为生成器的输入。在下一步中,生成器从随机分布中生成一批有意义的、相似的图像。
noise=np.random.normal(loc=0, scale=1, size=(100,noise_shape))
gen_image = generator.predict(noise)
plt.imshow(noise)
plt.title('DCGAN Noise')
噪声图像:
显示生成图像:
fig,axe=plt.subplots(2,5)
fig.suptitle('Generated Images from Noise using DCGANs')
idx=0
for i in range(2):
for j in range(5):
axe[i,j].imshow(gen_image[idx].reshape(28,28),cmap='gray')
idx+=3
DCGAN生成图像下图:
04
总结
GAN的优点是可以生成与真实数据相似的新数据,并且它是a 具有广泛的应用前景;缺点是训练不稳定,容易陷入局部最优。 DCGAN 相对于常规 GAN 的优势在于它可以生成更真实、清晰的图像,但需要更多的计算机资源和时间来训练。
在这个实验中,我们比较了使用 DCGAN 和常规 GAN 在时尚 MNIST 图像生成上的效果。结果表明,DCGAN 生成的图像更加真实、清晰,而常规 GAN 生成的图像比较模糊。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。