今天目标是介绍一下 GAN 是如何做到输出图片的这个样任务。在 GAN 中分别有两个阶段,在生成阶段就是固定生成器来训练判别器,而在判别阶段中固定判别器来训练生成器,这个可能和大家理解显得约有不同,但是其实都一样的。
gan_002.jpeg生成阶段
例如我们可以让机器生成图片或生成文章,这些都是 GAN 那首好戏。在 GAN 我们见到都是在生成阶段由 generator 生成图像或文字。
也就是我们给 generator 输入服从某种分布随机具有一定维度的向量,generator 就会输出张图片或文字。不同于之前机器只是做预测和分类任务,今天 GAN 可以生产一些东西,不过你会问到除了有趣这些又有什么用呢?
这样结果不可控制的生成,看起来的确是没有什么用的,如果我们能够控制输出就好,这一点是可以做到,随后会介绍我们如何控制 generator 输出来得到我们想要的图像或文字。
屏幕快照 2020-03-03 上午6.20.23.png我们同过输入向量某一个值控制输入,例如修改值来改变输出卡通人物头发的颜色,更改她们的表情,这些都是可以做到的。
判别阶段
- 固定住首先生成器使用服从一定分布的提取具有一定维度的向量,向量维度可以由你来定,20、50 和 100 都可以。生成图像,
- 我们固定住判别器,开始训练生成器,这个阶段应该属于判别阶段
可以把判别器和生成器整合为一个模型,网络模型前半部分是生成器,后半部分是判别器,假设他们个 5 层,在中间输出一个高维向量(图像的维度),在训练生成器时候,我们需要网络后半部分固定住。如果不固定住后端网络,只要后端给出高分就达到预期的效果。
生成器和判别器
屏幕快照 2020-03-03 上午6.51.11.png在 GAN 的架构中通常会有两部分组成分别是 Generator 和 Discriminator
-
NN(神经网络,随后我们就用 NN 表示神经网络) 分别是 Generator(生成器)
-
在 Discriminator 输入一张图,然后会给输入进行打分
-
先固定住生成器(Generator) 也就是固定住 Generator 参数,然后输入服从一定分布的随机向量 给 Generator 来生成图片
-
然后从准备好的 数据集中抽取图片,如果图片就要准备一些你要生成图片类似,加下来将真实图片和Generator 生成图片输入到 Discriminator,并给真实图片较高分和给 generator 生产的图较低的分数,通过使用数据进行训练 Discriminator 来提高 Discriminator 的鉴别能力。
更新判别器
在实践中,我们希望当真实图片输入到 Discriminator 时候,希望他能给分数越接近 1 越好,反之越接近 0 越好。 -
然后固定住 Discriminator 然后调节 Generator 的参数来努力骗过 Discriminator 来获取高分
这些 Generator 根据输入向量生成图片表示为
这是 Discriminator 的目标函,期望 值越大越好,数当输入真实图片到 D 我们希望 值越大越好,而输入 希望 越小越好,从而会的得到一个较大
有了目标函数,我们就可以朝着目标不断更新参数 训练完 Discriminator 我们就可以开始训练 Generator 了。我们可以再随机抽取 m 个,下面式子就是 G 用向量输出图片,将图片输入判别函数D 希望他给出高分,这就是训练 G 的目标。
这里对抗意思,大家都是用做赝品和鉴别专家来比喻generator和discriminator。其实他们鸣人和佐助的关系,相辅相成共同进步
Discriminator(判别器)
我们可能会问为什么判别器不自己生产图片呢?他已经知道什么样图片是真的,什么样图片是伪造的了。判别器是接受图片或文本输入然后会输出一个分数,也就是判别器给这个
我们想生成器通常是一个一个 component(在图像里就是像素)地生产,而且批次独立,这样就在生成阶段很难考虑到像素像素之间的关系。而判别器时候却不同,他接收一张图片作为输入,这样从整体来审核一张图好坏
不过现在Discriminator 只是知道凡是生成器就是不好,其实也就是只有正例样本,我们需要准备一些反例样本告诉判别器什么样是不好的除了是生成器伪造那些图片和文本以外。
先开一下跑的结果
随机生产 200 迭代 400 迭代 2000 迭代 19000 迭代
# coding=utf-8
from keras.datasets import mnist
from keras.layers import Input, Dense, Reshape, Flatten, Dropout
from keras.layers import BatchNormalization, Activation, ZeroPadding2D
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D, Conv2D
from keras.models import Sequential, Model
from keras.optimizers import Adam
import matplotlib.pyplot as plt
import sys
import os
import numpy as np
class GAN():
def __init__(self):
# --------------------------------- #
# 行28,列28,也就是mnist的shape
# --------------------------------- #
self.img_rows = 28
self.img_cols = 28
self.channels = 1
# 28,28,1
self.img_shape = (self.img_rows, self.img_cols, self.channels)
self.latent_dim = 100
# adam优化器
optimizer = Adam(0.0002, 0.5)
# 初始化判别器
self.discriminator = self.build_discriminator()
self.discriminator.compile(loss='binary_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
# 创建生成器
self.generator = self.build_generator()
gan_input = Input(shape=(self.latent_dim,))
img = self.generator(gan_input)
# 在训练generate的时候,固定住 discriminator
self.discriminator.trainable = False
# 对生成的假图片进行预测
validity = self.discriminator(img)
# input
self.combined = Model(gan_input, validity)
self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)
def build_generator(self):
# --------------------------------- #
# 生成器,输入一串随机数字
# --------------------------------- #
model = Sequential()
model.add(Dense(256, input_dim=self.latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(1024))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
model.add(Dense(np.prod(self.img_shape), activation='tanh'))
model.add(Reshape(self.img_shape))
noise = Input(shape=(self.latent_dim,))
img = model(noise)
return Model(noise, img)
def build_discriminator(self):
# ----------------------------------- #
# 评价器,对输入进来的图片进行评价
# ----------------------------------- #
model = Sequential()
# 输入一张图片
model.add(Flatten(input_shape=self.img_shape))
model.add(Dense(512))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(256))
model.add(LeakyReLU(alpha=0.2))
# 判断真伪
model.add(Dense(1, activation='sigmoid'))
img = Input(shape=self.img_shape)
validity = model(img)
# 输出模型
return Model(img, validity)
def train(self, epochs, batch_size=128, sample_interval=50):
# 获得数据
(X_train, _), (_, _) = mnist.load_data()
# 进行标准化
X_train = X_train / 127.5 - 1.
X_train = np.expand_dims(X_train, axis=3)
# 创建标签
valid = np.ones((batch_size, 1))
fake = np.zeros((batch_size, 1))
for epoch in range(epochs):
# --------------------------- #
# 随机选取batch_size个图片
# 对discriminator进行训练
# --------------------------- #
idx = np.random.randint(0, X_train.shape[0], batch_size)
imgs = X_train[idx]
noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
# 生成器创建图片
gen_imgs = self.generator.predict(noise)
# 开始训练判别器,输入真实图片给判别器传入 valid 高分告诉这是真实图片
d_loss_real = self.discriminator.train_on_batch(imgs, valid)
d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake)
d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
# --------------------------- #
# 训练generator
# --------------------------- #
noise = np.random.normal(0, 1, (batch_size, self.latent_dim))
g_loss = self.combined.train_on_batch(noise, valid)
print ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss))
if epoch % sample_interval == 0:
self.sample_images(epoch)
def sample_images(self, epoch):
r, c = 5, 5
noise = np.random.normal(0, 1, (r * c, self.latent_dim))
gen_imgs = self.generator.predict(noise)
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("images/%d.png" % epoch)
plt.close()
if __name__ == '__main__':
if not os.path.exists("./images"):
os.makedirs("./images")
gan = GAN()
gan.train(epochs=30000, batch_size=256, sample_interval=200)
网友评论