深入浅出对抗神经网络GAN

GAN简介

生成式对抗网络(GAN, Generative Adversarial Networks )是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一。

模型通过框架中(至少)两个模块:生成模型(Generative Model)和判别模型(Discriminative Model)的互相博弈学习产生相当好的输出。

通俗的讲,初始的生成网络(generated)与判别网络(discriminator)什么都不懂, 把初始的生成网络比喻成画家,那么初始的判别网络就是鉴画师,什么都不懂的画师画了幅画,于是给鉴画师辨认是否画的好,鉴画师也什么都不懂,只能对比世界名画判断好坏, 将意见反馈给画师,不停重复操作,画师不断进步的同时,鉴画师也会进步,画师最终会努力接近世界名画的水平,这就是GAN。

GAN应用

目前GAN最常使用的地方就是图像生成,如超分辨率任务语义分割数据增加等等

GAN的基本结构

GAN是将一组向量矩阵输入生成网络中训练出一组虚假数据,再与真数据进行合并进入判别网络训练,虚假数据的判别网络训练标签为0,真数据的判别网络训练标签为1,不断循环训练,使生成图像逼近原始图像。
在这里插入图片描述

GAN的基本原理

首先从现有的数据中挑选出一批数据,组成Pdata(x)Pdata(x),然后训练一个PG(x;θ)PG(x;θ)来产生数据(例如一个高斯混合模型),我们希望产生的数据集PG(x;θ)PG(x;θ)与原来的数据Pdata(x)Pdata(x)越接近越好,即使得下面的似然函数达到最大值:
在这里插入图片描述

因此需要求得的参数为:
θ∗=argmaxθ∏i=1mPG(xi;θ)
取对数,得:
在这里插入图片描述

GAN实践

激活函数

tanh
在这里插入图片描述
ReLu
在这里插入图片描述
sigmoid
在这里插入图片描述
Leaky ReLUs
ReLU是将所有的负值都设为零,相反,Leaky ReLU是给所有负值赋予一个非零斜率。Leaky ReLU激活函数是在声学模型(2013)中首次提出的。以数学的方式我们可以表示为:

在这里插入图片描述
在这里插入图片描述是(1,+∞)区间内的固定参数。
下图是ReLU、Leaky ReLU、PReLU和RReLU的比较:
在这里插入图片描述

GAN在MNIST数据集上的体现



import os

os.environ["KERAS_BACKEND"] = "tensorflow"
import numpy as np
from tqdm import tqdm
import matplotlib.pyplot as plt

from keras.layers import Input
from keras.models import Model, Sequential
from keras.layers.core import Reshape, Dense, Dropout, Flatten
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import Convolution2D, UpSampling2D
from keras.layers.normalization import BatchNormalization
from keras.datasets import mnist
from keras.optimizers import Adam
from keras import backend as K
from keras import initializers

K.set_image_dim_ordering('th')

np.random.seed(1000)

# 为了与其他GAN实现保持一致,维度保留为100。
randomDim = 100

# MNIST数据加载
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = (X_train.astype(np.float32) - 127.5) / 127.5
X_train = X_train.reshape(60000, 784)

# Optimizer
adam = Adam(lr=0.0002, beta_1=0.5)

generator = Sequential()
generator.add(Dense(256, input_dim=randomDim, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
generator.add(LeakyReLU(0.2))
generator.add(Dense(512))
generator.add(LeakyReLU(0.2))
generator.add(Dense(1024))
generator.add(LeakyReLU(0.2))
generator.add(Dense(784, activation='tanh'))
generator.compile(loss='binary_crossentropy', optimizer=adam)

discriminator = Sequential()
discriminator.add(Dense(1024, input_dim=784, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(512))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(256))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy', optimizer=adam)

# 联合网络
discriminator.trainable = False
ganInput = Input(shape=(randomDim,))
x = generator(ganInput)
ganOutput = discriminator(x)
gan = Model(inputs=ganInput, outputs=ganOutput)
gan.compile(loss='binary_crossentropy', optimizer=adam)

dLosses = []
gLosses = []


# 绘制每个批次的损失
def plotLoss(epoch):
    plt.figure(figsize=(10, 8))
    plt.plot(dLosses, label='Discriminitive loss')
    plt.plot(gLosses, label='Generative loss')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend()
    plt.savefig('images/gan_loss_epoch_%d.png' % epoch)


#创建一个生成MNIST图像
def plotGeneratedImages(epoch, examples=100, dim=(10, 10), figsize=(10, 10)):
    noise = np.random.normal(0, 1, size=[examples, randomDim])
    generatedImages = generator.predict(noise)
    generatedImages = generatedImages.reshape(examples, 28, 28)

    plt.figure(figsize=figsize)
    for i in range(generatedImages.shape[0]):
        plt.subplot(dim[0], dim[1], i + 1)
        plt.imshow(generatedImages[i], interpolation='nearest', cmap='gray_r')
        plt.axis('off')
    plt.tight_layout()
    plt.savefig('images/gan_generated_image_epoch_%d.png' % epoch)


# 保存生成器和鉴别器网络(和权重),以供以后使用
def saveModels(epoch):
    generator.save('models/gan_generator_epoch_%d.h5' % epoch)
    discriminator.save('models/gan_discriminator_epoch_%d.h5' % epoch)


def train(epochs=1, batchSize=128):
    batchCount = X_train.shape[0] / batchSize
    print('Epochs:', epochs)
    print('Batch size:', batchSize)
    print('Batches per epoch:', batchCount)

    for e in range(1, epochs + 1):
        print('-' * 15, 'Epoch %d' % e, '-' * 15)
        # tqdm在运行行记录输出每轮训练进度
        for _ in tqdm(range(int(batchCount))):
            # 获得一组随机的输入噪声和图像
            noise = np.random.normal(0, 1, size=[batchSize, randomDim])
            imageBatch = X_train[np.random.randint(0, X_train.shape[0], size=batchSize)]
            
            # 生成虚假MNIST图像
            generatedImages = generator.predict(noise)
            X = np.concatenate([imageBatch, generatedImages])

            # 生成和实际数据的标签
            yDis = np.zeros(2 * batchSize)
            # One-sided label smoothing
            yDis[:batchSize] = 0.9

            # 训练判别器
            discriminator.trainable = True
            dloss = discriminator.train_on_batch(X, yDis)

            # 训练生成器
            noise = np.random.normal(0, 1, size=[batchSize, randomDim])
            yGen = np.ones(batchSize)
            discriminator.trainable = False
            gloss = gan.train_on_batch(noise, yGen)

        dLosses.append(dloss)
        gLosses.append(gloss)

        if e == 1 or e % 20 == 0:
            plotGeneratedImages(e)
            saveModels(e)

    # 描绘每个时代的损失
    plotLoss(e)


if __name__ == '__main__':
    train(200, 128)

训练结果

迭代1轮对抗生成的图片
在这里插入图片描述
迭代100轮对抗生成的图片
在这里插入图片描述
迭代200轮对抗生成的图片
在这里插入图片描述
模型实际在迭代80轮左右就相对成型了

模型训练损失折线图

在这里插入图片描述
代码地址

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值