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

时间:2024-09-29 14:46:28
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,UpSampling2D,Conv2D,ZeroPadding2D,Conv2DTranspose 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 ACGAN(): def __init__(self): #28,28,1 self.img_shape = (28,28,1) self.latent_dim=100 #输入维度--100 self.num_classes=10 #10分类 optimizer = Adam(0.0002, 0.5)#定义Adam优化器 losses=['binary_crossentropy','sparse_categorical_crossentropy'] #判别器 self.discriminator=self.build_discriminator() 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,1)--tanh) def build_generator(self): model=Sequential() model.add(Dense(256*7*7, activation='relu',input_dim=self.latent_dim))#全连接 model.add(BatchNormalization(momentum=0.8)) model.add(Reshape((7,7,256))) #第一层转置卷积层 model.add(Conv2DTranspose(128,kernel_size=3,strides=2,padding="same")) model.add(BatchNormalization(momentum=0.8)) model.add(Activation('relu'))#激活函数 #第二层转置卷积层 model.add(Conv2DTranspose(64,kernel_size=3,strides=2,padding="same")) model.add(BatchNormalization(momentum=0.8)) model.add(Activation('relu'))#激活函数 #第三层转置卷积层 model.add(Conv2DTranspose(32,kernel_size=3,padding="same")) model.add(BatchNormalization(momentum=0.8)) model.add(Activation('relu'))#激活函数 #第四层转置卷积层 model.add(Conv2DTranspose(1,kernel_size=3,padding="same")) model.add(Activation('tanh'))#激活函数 model.summary()#输出模型参数状况 noise=Input(shape=(self.latent_dim,))#输入 label = Input(shape=(1,), dtype='int32') label_embedding = Flatten()(Embedding(self.num_classes, 100)(label)) model_input = multiply([noise, label_embedding]) 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): img=Input(shape=self.img_shape) model=Sequential() #卷积层1 model.add(Conv2D(64,kernel_size=3,strides=2,input_shape=self.img_shape,padding="same")) model.add(LeakyReLU(alpha=0.2))#激活函数 model.add(Dropout(0.25)) #卷积层2 model.add(Conv2D(128,kernel_size=3,strides=2,padding="same")) model.add(LeakyReLU(alpha=0.2))#激活函数 model.add(Dropout(0.25)) #卷积层3 model.add(Conv2D(256,kernel_size=3,strides=2,padding="same")) model.add(LeakyReLU(alpha=0.2))#激活函数 model.add(Dropout(0.25)) #卷积层4 model.add(Conv2D(512,kernel_size=3,strides=1,padding="same")) model.add(LeakyReLU(alpha=0.2))#激活函数 model.add(Dropout(0.25)) #输出层 model.add(Flatten())#铺平 model.summary()#输出模型参数状况 features = model(img) #一个是真假,一个是类别向量 validity=Dense(1,activation="sigmoid")(features)#判断真伪 label=Dense(self.num_classes+1,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.save_model()#需要在同级文件夹下新建一个名为saved_model的文件夹 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) #绘制2*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() def save_model(self): def save(model, model_name): model_path = "saved_model/%" % model_name weights_path = "saved_model/%s_weights.hdf5" % model_name options = {"file_arch": model_path, "file_weights": weights_path} json_string = model.to_json() open(options['file_arch'], 'w').write(json_string) model.save_weights(options['file_weights']) save(self.generator, "generator") save(self.discriminator, 'discriminator') if __name__=='__main__': if not os.path.exists("./images"): os.makedirs("./images") acgan = ACGAN() acgan.train(epochs=5000, batch_size=256, sample_interval=200)