参考一篇非常全面的博文(传送门),把最原始的GAN网络过了一遍,虽然还是心中有疑虑,还是有问题,但是好事多磨,总会想明白的。
自己想不懂的问题:
1.在训练网络(generator)中,它是怎么生成一个虚假图片的?
build_generator()这个函数就是一个全连接网络,都说generator就是来生成一个虚假图片的,但是最后build_generator返回不是一个造好的虚假图片啊!
在代码部分:
noise= np.random.normal(0,1, (batch_size, 100))
fake_images = generator.predict(noise)由np.random.normal函数,生成正态分布的数据。将数据传入predict函数,为输入样本生成输出预测,预测的 Numpy 数组(或数组列表)。
这个地方的fake_images,我在程序中输出看了一下,图片信息看不懂。
所以很困惑,generator生成的虚假图片,是个什么样子的?我们给出的数据集是手写数据集,生成的虚假图片不应该是数字吗?
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
哈哈!我看懂啦!
1.
fake_images的维度是(128,784)的,生成的图像是叠加在一起的,这就是我为什么看不懂生成的图片是个什么东西,因为我输出的维度不对,128是128张图片,784是28*28。(128,784)整体理解为,输出了128张28*28的图片。下面我就开始调整我输出的图像的维度了。
2.我把bach_size设置为1,这样输出的fake_images的维度就是(1,784),然后我再把生成的图片的维度转换一下,把一维的784,转换为二维的28*28
将图片转换维度后,就生成了上面的图片,这个图片就是生成器生成的图片。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2.real_images = X_train[np.random.randint(0, X_train.shape[0], batch_size)]
这个是真实图像,X_train的维度是(60000,784)。np.random.randint(low,high,size,dtype)生成一个128维的行向量,行向量的数字范围是0-60000
输出的真实图像的维度是(128, 784);而且真实图像也是我所看不懂的。
为什么是这个样子的呢?
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
解答:
1.首先,生成的real_images图片的维度是错误的,一开始的batch_size的大小是128,所以生成的real_images的维度是(128,784)。
现在,我把batch_size的大小设置为了1,维度大小为(1.784),即生成了1张一维的图片,我把一维的784转换为二维的28*28
这样就能显示出来,从训练集中选出的真实图片里的数字是多少了
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3.GAN.train_on_batch(noise, label_real)
这个地方的代码是在生成训练网络,让鉴别网络停止训练
向网络中输入一堆噪声,期待的输出是将假图片预测为真。
我所理解:生成的假的图片,将假的图片预测为真了,说明生成假图片的能力提升了,下面该提升的就是鉴别能力了。
生成了虚假图片和真实图片之后,还生成了图片的标签,将图片和标签一起放进鉴别器里去鉴别,来提高鉴别器的鉴别能力。
再之后是鉴别器停止训练,训练生成器, 生成的假的图片,将假的图片预测为真了,说明生成假图片的能力提升了,下面该提升的就是鉴别能力了。
# -*- coding: utf-8 -*-
"""
Created on Sat May 22 15:40:12 2021
@author: LiMeng
"""
from keras.datasets import mnist
from keras.layers import Dense, Dropout, Input
from keras.models import Model,Sequential
from keras.layers.advanced_activations import LeakyReLU
from keras.optimizers import Adam
from tqdm import tqdm
import numpy as np
import matplotlib.pyplot as plt
#%matplotlib inline
#from google.colab import drive
# Load the dataset
def load_data():
(x_train, y_train), (_, _) = mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5)/127.5
# Convert shape from (60000, 28, 28) to (60000, 784)
x_train = x_train.reshape(60000, 784)
return (x_train, y_train)
X_train, y_train = load_data()
print(X_train.shape, y_train.shape)
def build_generator():
model = Sequential()
model.add(Dense(units=256, input_dim=100))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(units=512))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(units=1024))
model.add(LeakyReLU(alpha=0.2))
model.add(Dense(units=784, activation='tanh'))
model.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))
return model
generator = build_generator()
generator.summary()
"""
dropout是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃。注意是暂时,对于随机梯度下降来说,由于是随机丢弃,故而每一个mini-batch都在训练不同的网络。
dropout是CNN中防止过拟合提高效果的一个大杀器
"""
def build_discriminator():
model = Sequential()
model.add(Dense(units=1024 ,input_dim=784))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.3))
model.add(Dense(units=512))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.3))
model.add(Dense(units=256))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.3))
model.add(Dense(units=1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))
return model
discriminator = build_discriminator()
discriminator.summary()
def build_GAN(discriminator, generator):
discriminator.trainable=False
GAN_input = Input(shape=(100,))
x = generator(GAN_input)
GAN_output= discriminator(x)
GAN = Model(inputs=GAN_input, outputs=GAN_output)
GAN.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))
return GAN
GAN = build_GAN(discriminator, generator)
GAN.summary()
def draw_images(generator, epoch, examples=25, dim=(5,5), figsize=(10,10)):
noise= np.random.normal(loc=0, scale=1, size=[examples, 100])
generated_images = generator.predict(noise)
generated_images = generated_images.reshape(25,28,28)
plt.figure(figsize=figsize)
for i in range(generated_images.shape[0]):
plt.subplot(dim[0], dim[1], i+1)
plt.imshow(generated_images[i], interpolation='nearest', cmap='Greys')
plt.axis('off')
plt.tight_layout()
plt.savefig('Generated_images %d.png' %epoch)
def train_GAN(epochs=1, batch_size=128):
#Loading the data
X_train, y_train = load_data()
# Creating GAN
generator= build_generator()
discriminator= build_discriminator()
GAN = build_GAN(discriminator, generator)
# print("\nepochs %d\n" %epochs)
for i in range(1, epochs+1):
print("\nEpoch %d\n" %i)
for _ in tqdm(range(batch_size)):
# Generate fake images from random noiset
"""
np.random.normal生成正态分布:均值为0,方差为1,维度为(batch_size,100)--->(128,100)
generator生成器的输入是128张100维的数据 fake_images即为generator生成的虚假图像
np.random.randint(low,high,size,dtype) array = np.random.randint(0, X_train.shape[0], batch_size)
生成128维(行向量) 0-60000的数字,X_train.shape[0]为 60000,
"""
noise= np.random.normal(0,1, (batch_size, 100))
fake_images = generator.predict(noise)
#画出虚假图像
#plt.imshow(fake_images)
#plt.title("fake_images")
# Select a random batch of real images from MNIST
real_images = X_train[np.random.randint(0, X_train.shape[0], batch_size)]
#画出真实图像
#plt.imshow(real_images)
#plt.title("real_images")
# Labels for fake and real images
label_fake = np.zeros(batch_size)
label_real = np.ones(batch_size)
# Concatenate fake and real images
X = np.concatenate([fake_images, real_images])
y = np.concatenate([label_fake, label_real])
# Train the discriminator
discriminator.trainable=True
discriminator.train_on_batch(X, y)
# Train the generator/chained GAN model (with frozen weights in discriminator)
discriminator.trainable=False
GAN.train_on_batch(noise, label_real)
#Draw generated images every 15 epoches
if i == 1 or i % 10 == 0:
draw_images(generator, i)
train_GAN(epochs=400, batch_size=128)