
from keras.layers import LeakyReLU
from keras.layers import BatchNormalization
from keras.optimizers import RMSprop
import math
def build_generator(inputs, image_size):
'''
生成者网络与编解码网络中的解码器如出一辙,输入给它的一维随机向量相当于输入解码器网络的编码向量,
解码器网络将一维向量反向构造成图片所对应的二维向量,这也是生成者要做的工作,所以下面代码与我们做过
的解码器网络几乎一模一样
'''
image_resize = image_size // 4
kernel_size = 5
layer_filters = [128, 64, 32, 1]
x = Dense(image_resize * image_resize * layer_filters[0])(inputs)
x = Reshape((image_resize, image_resize, layer_filters[0]))(x)
#构造三层反卷积网络
for filters in layer_filters:
if filters > layer_filters[-2]:
strides = 2
else:
strides = 1
#使用batch normalization将输入反卷积网络的向量做预处理,没有这一步GAN的训练就会失败
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = Conv2DTranspose(filters = filters, kernel_size = kernel_size,
strides = strides,
padding = 'same')(x)
x = Activation('sigmoid')(x)
generator = Model(inputs, x, name = 'generator')
return generator
def build_discriminator(inputs):
'''
识别者网络与编码器很像,它使用三层卷积网络从图片中抽取信息,最后使用sigmoid函数输出
图片是否为真的概率
'''
kernel_size = 5
layer_filters = [32, 64, 128, 256]
x = inputs
for filters in layer_filters:
if filters == layer_filters[-1]:
strides = 1
else:
strides = 2
x = LeakyReLU(alpha = 0.2)(x)
x = Conv2D(filters=filters,
kernel_size=kernel_size ,
strides = strides,
padding = 'same')(x)
x = Flatten()(x)
x = Dense(1)(x)
x = Activation('sigmoid')(x)
discriminator = Model(inputs, x, name='discriminator')
return discriminator
def build_and_train_models():
'''
将生成者和识别者连城一个网络进行训练
'''
(x_train, _), (_, _) = mnist.load_data()
image_size = x_train.shape[1]
x_train = np.reshape(x_train, [-1, image_size, image_size, 1])
x_train = x_train.astype('float32') / 255
#设置训练相关的参数
model_name = '/content/gdrive/My Drive/dcgan_mnist'
latent_size = 100
batch_size = 64
train_steps = 40000
lr = 2e-4
decay = 6e-8
input_shape = (image_size, image_size, 1)
#构建识别者网络
inputs = Input(shape = input_shape, name = 'discriminator_input')
discriminator = build_discriminator(inputs)
optimizer = RMSprop(lr = lr, decay = decay)
discriminator.compile(loss = 'binary_crossentropy', optimizer = optimizer,
metrics = ['accuracy'])
#构建生成者网络
input_shape = (latent_size, )
inputs = Input(shape = input_shape, name = 'z_input')
generator = build_generator(inputs, image_size)
optimizer = RMSprop(lr = lr * 0.5, decay = decay * 0.5)
#将生成者和识别者连接成一个网络时要冻结识别者,因为训练生成者时识别者网络要保持不变
discriminator.trainable = False
adversarial = Model(inputs, discriminator(generator(inputs)),
name = model_name)
adversarial.compile(loss = 'binary_crossentropy',
optimizer = optimizer,
metrics = ['accuracy'])
models = (generator, discriminator, adversarial)
params = (batch_size, latent_size, train_steps, model_name)
train(models, x_train, params)
def train(models, x_train, params):
'''
训练时需要遵守的步骤是,先冻结生成者网络,把真实图片输入到识别者网络,训练识别者网络识别真实图片。
然后冻结识别者网络,让生成者网络构造图片输入给识别者网络识别,根据识别结果来改进生成者网络
'''
#先获得生成者,识别者,以及两者的结合体
generator, discriminator, adversarial = models
batch_size, latent_size , train_steps, model_name = params
save_interval = 500
#构造给生成者网络的一维随机向量
noise_input = np.random.uniform(-1.0, 1.0, size = [16, latent_size])
train_size = x_train.shape[0]
for i in range(train_steps):
#先训练识别者网络,将真实图片和伪造图片同时输入识别者,让识别者学会区分真假图片
rand_indexes = np.random.randint(0, train_size, size = batch_size)
real_images = x_train[rand_indexes]
noise = np.random.uniform(-1.0, 1.0, size = [batch_size, latent_size])
#让生成者构造虚假图片
fake_images = generator.predict(noise)
x = np.concatenate((real_images, fake_images))
y = np.ones([2 * batch_size, 1])
#真实图片对应标签1,虚假图片对应标签0
y[batch_size : , :] = 0.0
loss, acc = discriminator.train_on_batch(x, y)
log = "%d: [discriminator loss: %f, acc: %f]" % (i, loss, acc)
#冻结识别者,让生成者构造一系列图片输入识别者,根据识别者识别结果改进生成者网络
noise = np.random.uniform(-1.0, 1.0, size = [batch_size, latent_size])
y = np.ones([batch_size, 1])
#训练生成者时需要使用到识别者返回的结果,因此我们从两者连接后的网络进行训练
loss, acc = adversarial.train_on_batch(noise, y)
log = "%s [adversarial loss: %f, acc: %f]" % (log, loss, acc)
print(log)
if (i + 1) % save_interval == 0:
if (i + 1) == train_steps:
show = True
else:
show = False
#将生成者构造的图片绘制出来
plot_images(generator, noise_input = noise_input,
show = show, step = (i + 1),
model_name = model_name)
#将生成者当前的网络参数存储成文件
generator.save(model_name + ".h5")
def plot_images(generator, noise_input, show = False,
step = 0,
model_name = ''):
os.makedirs(model_name, exist_ok = True)
filename = os.path.join(model_name, "%05d.png" % step)
images = generator.predict(noise_input)
plt.figure(figsize = (2.2, 2.2))
num_images = images.shape[0]
image_size = images.shape[1]
rows = int(math.sqrt(noise_input.shape[0]))
for i in range(num_images):
plt.subplot(rows, rows, i + 1)
image = np.reshape(images[i], [image_size, image_size])
plt.imshow(image, cmap= 'gray')
plt.axis('off')
plt.savefig(filename)
if show:
plt.show()
else:
plt.close('all')
from google.colab import drive
drive.mount('/content/gdrive')

from keras.datasets import mnist
from keras.layers import LeakyReLU
from keras.layers import Activation
from keras.optimizers import RMSprop
import os
build_and_train_models()

from keras.models import load_model
import os
generator = load_model('/content/gdrive/My Drive/dcgan_mnist.h5')
#构造一批随机初始化的一维向量让生成者网络创造图片
noise = np.random.randint(-1.0, 1.0, size=[16, 100])
plot_images(generator, noise_input = noise,
show = True, model_name="test_image")

from keras.layers.merge import concatenate
from keras.utils import to_categorical
def build_cgan_discriminator(inputs, y_labels, image_size):
'''
识别图片,并将图片与输入的one-hot-vector关联起来
'''
kernel_size = 5
layer_filters = [32, 64, 128, 256]
x = inputs
y = Dense(image_size * image_size)(y_labels)
y = Reshape((image_size, image_size, 1))(y)
#把图片数据与one-hot-vector拼接起来,这里是唯一与前面代码不同之处
x = concatenate([x, y])
for filters in layer_filters:
if filters == layer_filters[-1]:
strides = 1
else:
strides = 2
x = LeakyReLU(alpha=0.2)(x)
x = Conv2D(filters = filters,
kernel_size = kernel_size,
strides = strides,
padding = 'same')(x)
x = Flatten()(x)
x = Dense(1)(x)
x = Activation('sigmoid')(x)
discriminator = Model([inputs, y_labels], x ,
name = 'discriminator')
return discriminator
def build_cgan_generator(inputs, y_labels, image_size):
'''
生成者网络在构造图片时,需要将输入向量与对应的one-hot-vector结合在一起考虑
'''
image_resize = image_size // 4
kernel_size = 5
layer_filters = [128, 64, 32, 1]
#将输入向量与One-hot-vector结合在一起
x = concatenate([inputs, y_labels], axis = 1)
x = Dense(image_resize * image_resize * layer_filters[0])(x)
x = Reshape((image_resize, image_resize, layer_filters[0]))(x)
for filters in layer_filters:
if filters > layer_filters[-2]:
strides = 2
else:
strides = 1
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = Conv2DTranspose(filters = filters,
kernel_size = kernel_size,
strides = strides,
padding = 'same')(x)
x = Activation('sigmoid')(x)
generator = Model([inputs, y_labels], x, name='generator')
return generator
def train_cgan(models, data, params):
generator, discriminator, adversarial = models
#获取图片数据以及图片对应数字的one-hot-vector
x_train, y_train = data
batch_size, latent_size, train_steps, num_labels, model_name = params
save_interval = 500
noise_input = np.random.uniform(-1.0, 1.0, size=[16, latent_size])
'''
np.eye产生对角矩阵,例如np.eye(3) = [[1,0,0], [0,1,0], [0,0,1]],
于是np.eye(3)[2, 3, 1] = [[0,1,0], [0,0,1], [1,0,0]]
'''
noise_class = np.eye(num_labels)[np.arange(0, 16) % num_labels]
train_size = x_train.shape[0]
print(model_name, "Labels for generated images: ", np.argmax(noise_class, 1))
for i in range(train_steps):
rand_indexes = np.random.randint(0, train_size, size = batch_size)
real_images = x_train[rand_indexes]
#增加图片对应的one-hot-vector
real_labels = y_train[rand_indexes]
noise = np.random.uniform(-1.0, 1.0, size = [batch_size, latent_size])
#增加构造图片对应的one-hot-vector
fake_labels = np.eye(num_labels)[np.random.choice(num_labels, batch_size)]
fake_images = generator.predict([noise, fake_labels])
#把真实图片和虚假图片连接起来
x = np.concatenate((real_images, fake_images))
#将真实图片对应的one-hot-vecotr和虚假图片对应的One-hot-vector连接起来
y_labels = np.concatenate((real_labels, fake_labels))
y = np.ones([2 * batch_size, 1])
#上半部分图片为真,下半部分图片为假
y[batch_size:, :] = 0.0
#先训练识别者网络,这里需要将图片及对应的one-hot-vector输入
loss, acc = discriminator.train_on_batch([x, y_labels], y)
log = "%d: [discriminator loss : %f, acc: %f]" % (i, loss, acc)
'''
冻结识别者网络,构造随机一维向量以及指定数字的one-hot-vector输入生成者
网络进行训练
'''
noise = np.random.uniform(-1.0, 1.0, size=[batch_size, latent_size])
fake_labels = np.eye(num_labels)[np.random.choice(num_labels, batch_size)]
y = np.ones([batch_size, 1])
loss, acc = adversarial.train_on_batch([noise, fake_labels], y)
log = "%s [adversarial loss :%f, acc: %f]" % (log, loss, acc)
if (i + 1) % save_interval == 0:
print(log)
if (i+1) == train_steps:
show = True
else:
show = False
plot_images_cgan(generator,
noise_input = noise_input,
noise_class = noise_class,
show = show,
step = (i+1),
model_name = model_name)
generator.save(model_name + ".h5")
def build_and_train_models_cgan():
(x_train, y_train), (_,_) = mnist.load_data()
image_size = x_train.shape[1]
x_train = np.reshape(x_train, [-1, image_size, image_size, 1])
x_train = x_train.astype('float32') / 255
#获得要生成数字的最大值
num_labels = np.amax(y_train) + 1
#转换为one-hot-vector
y_train = to_categorical(y_train)
model_name = "/content/gdrive/My Drive/cgan_mnist"
latent_size = 100
batch_size = 64
train_steps = 40000
lr = 2e-4
decay = 6e-8
input_shape = (image_size, image_size, 1)
label_shape = (num_labels, )
inputs = Input(shape=input_shape, name='discriminator_input')
labels = Input(shape=label_shape, name = 'class_labels')
#构建识别者网络时要传入图片对应的One-hot-vector
discriminator = build_cgan_discriminator(inputs, labels, image_size)
optimizer = RMSprop(lr=lr, decay = decay)
discriminator.compile(loss='binary_crossentropy',
optimizer=optimizer,
metrics = ['accuracy'])
input_shape = (latent_size,)
inputs = Input(shape=input_shape, name='z_input')
#构造生成者时也要传入one-hot-vector
generator = build_cgan_generator(inputs, labels, image_size)
optimizer = RMSprop(lr = lr*0.5, decay = decay * 0.5)
#将生成者和识别者连接起来时要冻结识别者
discriminator.trainable = False
outputs = discriminator([generator([inputs, labels]), labels])
adversarial = Model([inputs, labels], outputs, name = model_name)
adversarial.compile(loss ='binary_crossentropy',
optimizer = optimizer,
metrics = ['accuracy'])
models = (generator, discriminator, adversarial)
data = (x_train, y_train)
params = (batch_size, latent_size, train_steps, num_labels, model_name)
train_cgan(models, data, params)
def plot_images_cgan(generator,
noise_input,
noise_class,
show = False,
step = 0,
model_name = ''):
os.makedirs(model_name, exist_ok = True)
filename = os.path.join(model_name, "%05d.png" % step)
images = generator.predict([noise_input, noise_class])
print(model_name, "labels for generated images: ", np.argmax(noise_class,
axis =1))
plt.figure(figsize = (2.2, 2.2))
num_images = images.shape[0]
image_size = images.shape[1]
rows = int(math.sqrt(noise_input.shape[0]))
for i in range(num_images):
plt.subplot(rows, rows, i + 1)
image = np.reshape(images[i], [image_size, image_size])
plt.imshow(image, cmap= 'gray')
plt.axis('off')
plt.savefig(filename)
if show:
plt.show()
else:
plt.close('all')
from keras.layers import LeakyReLU
from keras.layers import BatchNormalization
from keras.optimizers import RMSprop
import math
from keras.layers import Activation, Dense, Input
build_and_train_models_cgan()
