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()