基于Keras的生成对抗网络(3)——利用Keras搭建CGAN生成手写体数字并贴上标签

时间:2024-09-29 14:54:03
from keras.datasets import mnist from keras.models import Sequential,Model from keras.layers import Input, Dense, Reshape, Flatten,Embedding,multiply from keras.layers import BatchNormalization, Activation,Dropout from keras.layers import LeakyReLU from keras.optimizers import Adam from keras.utils.vis_utils import plot_model import matplotlib.pyplot as plt import numpy as np import os class CGAN(): def __init__(self): #28,28,1 self.img_shape = (28,28,1) self.num_classes=10 #分成10类 self.latent_dim=100 #输入维度--100 optimizer = Adam(0.0002, 0.5)#定义Adam优化器 #判别器 self.discriminator=self.build_discriminator() losses=['binary_crossentropy','sparse_categorical_crossentropy'] self.discriminator.compile(loss=losses, optimizer=optimizer, metrics=['accuracy'])#定义loss函数和优化器 #生成器 self.generator=self.build_generator() noise = Input(shape=(self.latent_dim,)) label=Input(shape=(1,)) img = self.generator([noise,label]) #训练生成器 # 在训练generator的时候不训练discriminator self.discriminator.trainable = False#冻结discriminator valid,target_label = self.discriminator(img)# 对生成的假图片进行预测 self.combined = Model([noise,label], [valid,target_label])#在Model中discriminator已经被冻结,仅剩下generator在运行了 self.combined.compile(loss=losses, optimizer=optimizer)#定义loss函数和优化器 #定义生成器模型 #输入:100维向量;输出:28*28图像(像素大小为(-1,1)--tanh) def build_generator(self): model=Sequential() #输入 label=Input(shape=(1,),dtype='int32') label_embedding=Flatten()(Embedding(self.num_classes, self.latent_dim)(label)) noise=Input(shape=(self.latent_dim,)) #带标签的随机数 model_input=multiply([noise,label_embedding])#相乘作为输入 #第一层全连接层:784-->256 model.add(Dense(256, input_dim=self.latent_dim))#全连接 model.add(LeakyReLU(alpha=0.2))#激活函数 model.add(BatchNormalization(momentum=0.8))#标准化 #第二层全连接层:256-->512 model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) #第三层全连接层:512-->1024 model.add(Dense(1024)) model.add(LeakyReLU(alpha=0.2)) model.add(BatchNormalization(momentum=0.8)) #第四层全连接层(输出层):1024-->784 model.add(Dense(np.prod(self.img_shape), activation='tanh'))#product--乘积,即28*28*1=784 model.add(Reshape(self.img_shape)) img = model(model_input) plot_model(model, to_file='', show_shapes=True, show_layer_names=False, rankdir='TB')#绘制模型 return Model([noise,label], img) #定义判别器模型 #输入:28*28图像;输出:0-1数字 def build_discriminator(self): model=Sequential() img=Input(shape=self.img_shape) label=Input(shape=(1,),dtype='int32') model.add(Flatten(input_shape=self.img_shape))#铺平 #第一层全连接层:784-->512 model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) #第二层全连接层:512-->512 model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) model.add(Dropout(0.2)) #第三层全连接层:512-->512 model.add(Dense(512)) model.add(LeakyReLU(alpha=0.2)) model.add(Dropout(0.2)) features = model(img) #一个是真假,一个是类别向量 validity=Dense(1,activation="sigmoid")(features)#判断真伪 label=Dense(self.num_classes,activation="softmax")(features)#判断是几 plot_model(model, to_file='', show_shapes=True, show_layer_names=False, rankdir='TB')#绘制模型 return Model(img,[validity,label]) #定义训练函数 def train(self,epochs,batch_size=128,sample_interval=50): #创建训练数据集 (X_train, y_train), (_, _) = mnist.load_data() # 从mnist数据集中获得数据 X_train =(X_train.astype(np.float32)-127.5)/127.5 # 将X_train的值转换为float类型,并标准化为(-1,1) X_train = np.expand_dims(X_train, axis=3) #60000*28*28变为60000*28*28*1;X_train的shape是60000*28*28*1 y_train=y_train.reshape(-1,1) #创建标签(0或者1)--二分类问题 valid = np.ones((batch_size, 1))#全1阵--真 fake = np.zeros((batch_size, 1))#全0阵--假 for epoch in range(epochs): #训练discriminator idx=np.random.randint(0,X_train.shape[0],batch_size)#随机选择batch_size个数 imgs,labels=X_train[idx],y_train[idx]#真图像,真标签 noise = np.random.normal(0, 1, (batch_size, self.latent_dim))#生成正态分布噪声 sampled_labels=np.random.randint(0,10,(batch_size,1)) gen_imgs = self.generator.predict([noise,sampled_labels])#假图像 #训练discriminator d_loss_real = self.discriminator.train_on_batch(imgs, [valid,labels])#真图像训练 d_loss_fake = self.discriminator.train_on_batch(gen_imgs, [fake,sampled_labels])#假图像训练 d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)#数据求和 #训练生成器 g_loss=self.combined.train_on_batch([noise,sampled_labels],[valid,sampled_labels]) print("steps:%d [D loss: %f, acc.: %.2f%%,ap_acc:%.2f%%] [G loss: %f]"% (epoch, d_loss[0], 100*d_loss[3],100*d_loss[4],g_loss[0])) #迭代50次打印一次 if epoch % sample_interval == 0: self.sample_images(epoch) def sample_images(self,epoch): r,c=2,5 noise=np.random.normal(0,1,(r*c,self.latent_dim))#生成随机噪声 sampled_labels = np.arange(0, 10).reshape(-1, 1) gen_imgs = self.generator.predict([noise,sampled_labels])#生成器预测的图像 gen_imgs = 0.5 * gen_imgs + 0.5 #将generator输出的(-1,1)像素值反归一化为(0,1) #绘制5*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].set_title("Digit: %d" % sampled_labels[cnt]) axs[i,j].axis('off') cnt += 1 fig.savefig("images/%" % epoch) plt.close() if __name__=='__main__': if not os.path.exists("./images"): os.makedirs("./images") cgan = CGAN() cgan.train(epochs=30000, batch_size=256, sample_interval=200)