参考代码:
https://github.com/FacelessManipulator/keras-dcgan/blob/master/dcgan.py
参考文章:
https://www.leiphone.com/news/201703/Y5vnDSV9uIJIQzQm.html
生成对抗网络(Generative Adversarial Networks,GAN)最早由 Ian Goodfellow 在 2014 年提出,是目前深度学习领域最具潜力的研究成果之一。它的核心思想是:同时训练两个相互协作、同时又相互竞争的深度神经网络(一个称为生成器 Generator,另一个称为判别器 Discriminator)来处理无监督学习的相关问题。在训练过程中,两个网络最终都要学习如何处理任务。
通常,我们会用下面这个例子来说明 GAN 的原理:将警察视为判别器,制造假币的犯罪分子视为生成器。一开始,犯罪分子会首先向警察展示一张假币。警察识别出该假币,并向犯罪分子反馈哪些地方是假的。接着,根据警察的反馈,犯罪分子改进工艺,制作一张更逼真的假币给警方检查。这时警方再反馈,犯罪分子再改进工艺。不断重复这一过程,直到警察识别不出真假,那么模型就训练成功了。
一、源码分析:
(1) 生成器generator_model
def generator_model():
model = Sequential()
model.add(Dense(input_dim=100, output_dim=1024))
model.add(Activation('tanh'))
model.add(Dense(128*7*7)) #对上一层的神经元进行全部连接,实现特征的非线性组合,对特征进行综合考虑
model.add(BatchNormalization())
model.add(Activation('tanh'))
model.add(Reshape((7, 7, 128), input_shape=(128*7*7,)))
model.add(UpSampling2D(size=(2, 2))) #第一个2表示行重复2次,第二个2表示列重复2次,可以用于复原图像等
model.add(Convolution2D(64, 5, 5, border_mode='same')) #卷积提取特征,卷积核64个,核大小为5*5,就是用64个5*5大小的卷积核去提取不同的特征,步长(就是卷积核每次移动的大小)默认为1,不为1时会改变输出矩阵的大小,例如步长strides为2则会缩小一半
model.add(Activation('tanh'))
model.add(UpSampling2D(size=(2, 2)))
model.add(Convolution2D(1, 5, 5, border_mode='same'))
model.add(Activation('tanh'))
return model
(2)判别器discriminator
def discriminator_model():
model = Sequential()
model.add(Convolution2D(
64, 5, 5,
border_mode='same',
input_shape=(28, 28, 1))) #输入一张图片,,卷积核64个,核大小为5*5,就是用64个5*5大小的卷积核去提取不同的特征,步长(就是卷积核每次移动的大小)默认为1
model.add(Activation('tanh'))
model.add(MaxPooling2D(pool_size=(2, 2))) #空间池化,定义了空间上的邻域(2x2的窗)并且从纠正特征映射中取出窗里最大的元素,逐步减少输入特征的空间尺寸
model.add(Convolution2D(128, 5, 5))
model.add(Activation('tanh'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten()) #把多维的输入一维化,常用在从卷积层到全连接层的过渡
model.add(Dense(1024)) #对上一层的神经元进行全部连接,实现特征的非线性组合,对特征进行综合考虑
model.add(Activation('tanh'))
model.add(Dense(1))
model.add(Activation('sigmoid'))
return model
(3)对抗模型
def generator_containing_discriminator(generator, discriminator):
model = Sequential()
model.add(generator)
discriminator.trainable = False
model.add(discriminator)
return model
(4)训练
def train(BATCH_SIZE):
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = (X_train.astype(np.float32) - 127.5)/127.5 #范围调整为[-1,1]
X_train = X_train.reshape((X_train.shape[0], 1) + X_train.shape[1:]) #需要上机调试看看
discriminator = discriminator_model()
generator = generator_model()
discriminator_on_generator = \
generator_containing_discriminator(generator, discriminator)
d_optim = SGD(lr=0.0005, momentum=0.9, nesterov=True)
g_optim = SGD(lr=0.0005, momentum=0.9, nesterov=True)
generator.compile(loss='binary_crossentropy', optimizer="SGD") #生成器,损失函数为(亦称作对数损失,logloss),SGD-随机梯度下降算法
discriminator_on_generator.compile(
loss='binary_crossentropy', optimizer=g_optim) #对抗模型
discriminator.trainable = True
discriminator.compile(loss='binary_crossentropy', optimizer=d_optim) #判别器
noise = np.zeros((BATCH_SIZE, 100)) #每次BATCH_SIZE个样本
for epoch in range(100): #所有样本重复100次
print("Epoch is", epoch)
print("Number of batches", int(X_train.shape[0]/BATCH_SIZE)) #总共有多少批
for index in range(int(X_train.shape[0]/BATCH_SIZE)): #所有样本按照批大小训练一次
for i in range(BATCH_SIZE):
noise[i, :] = np.random.uniform(-1, 1, 100) #产生BATCH_SIZE个噪点
image_batch = X_train[index*BATCH_SIZE:(index+1)*BATCH_SIZE] #获取对应的BATCH_SIZE个训练样本
image_batch = image_batch.transpose((0,2,3,1)) #???改变下标
generated_images = generator.predict(noise, verbose=0) #产生BATCH_SIZE个图片
if index % 20 == 0:
generated_images_tosave = generated_images.transpose((0,3,1,2)) #???改变下标
image = combine_images(generated_images_tosave)#???
image = image*127.5+127.5 #重新变回图像数据
Image.fromarray(image.astype(np.uint8)).save(
str(epoch)+"_"+str(index)+".png") #保存一部分图片,下标能被20整除的
print(image_batch.shape, generated_images.shape)
X = np.concatenate((image_batch, generated_images)) #训练和产生的图片合并在一起
y = [1] * BATCH_SIZE + [0] * BATCH_SIZE #y为输出,???一部分为1,另一部分为0
d_loss = discriminator.train_on_batch(X, y)
print("batch %d d_loss : %f" % (index, d_loss))
for i in range(BATCH_SIZE):
noise[i, :] = np.random.uniform(-1, 1, 100)
discriminator.trainable = False
g_loss = discriminator_on_generator.train_on_batch(
noise, [1] * BATCH_SIZE) #对抗模型,只是把生成器和判别器联合在一起
discriminator.trainable = True
print("batch %d g_loss : %f" % (index, g_loss)) #损失函数,应该是检验生成的图片是否能够判别出来?直到无法判别真假,损失函数与输出(0-1之间的值)之间的关系???
if index % 10 == 9:
generator.save_weights('generator', True) #生成器模型
discriminator.save_weights('discriminator', True) #判别器模型,而对抗模型是他们的联合不需要保存
(5)运行结果
对所有训练样本进行100次重复训练后的变化过程。刚开始生成的都是噪点,慢慢地接近样本的效果,最后已经非常逼真。
源码地址:
https://github.com/gjq246/pythontest/blob/master/dcgan_mnist.py