1.GAN-学习生成手写数字

第一次写博客,希望大家担待,一起学习,一起进步!

1.导入模块并且指定模型输入维度

%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np

from keras.datasets import mnist
from keras.layers import Dense, Flatten, Reshape
from keras.layers.advanced_activations import LeakyReLU
from keras.models import Sequential
from keras.optimizer_v2 import adam as Adam

此处是直接从keras中直接导入的mnist手写数据集

提醒大家注意一下那个优化器导入的时候后面有个_v2,我最开始没有注意到这个,一直报错。

2.模型输入维度

img_rows = 28
img_cols = 28
channels = 1

# 图像输入的维度
img_shape = (img_rows, img_cols, channels)

# 噪声向量的大小,用作生成器的输入
z_dim = 100

mnist数据集中每张图片都是28*28像素的单通道图像。

3.生成器

def build_generator(img_shape, z_dim):

    model = Sequential()

    # 全连接层
    model.add(Dense(128, input_dim=z_dim))

    # Leaky ReLU 激活函数
    model.add(LeakyReLU(alpha=0.01))

    # 带有tanh函数的激活层
    model.add(Dense(28 * 28 * 1, activation='tanh'))

    # 将生成器的输出改变为图像尺寸
    model.add(Reshape(img_shape))

    return model

这个生成器只有一个隐藏层的神经网络。此处使用的是LeakyReLU激活函数,它的好处是存在一个小的正梯度,这样可以防止梯度在训练中消失。在输出层使用tanh而不是使用sigmoid。

4.鉴定器

def build_discriminator(img_shape):

    model = Sequential()

    # 将输入图像展平
    model.add(Flatten(input_shape=img_shape))

    # 全连接层
    model.add(Dense(128))

    # Leaky ReLU 激活函数
    model.add(LeakyReLU(alpha=0.01))

    # 带有sigmoid的输出层
    model.add(Dense(1, activation='sigmoid'))

    return model

输出层应用了sigmoid激活函数,这确保了输出值将介于0和1之间

5.构建并编译GAN

def build_gan(generator, discriminator):

    model = Sequential()

    # 将生成器和鉴定器结合到一起
    model.add(generator)
    model.add(discriminator)

    return model
# 构建并编译鉴定器(使用了二元交叉熵作为损失函数,Adam的优化算法)
discriminator = build_discriminator(img_shape)
discriminator.compile(loss='binary_crossentropy',
                      optimizer=Adam.Adam(),
                      metrics=['accuracy'])

# 构建生成器
generator = build_generator(img_shape, z_dim)

# 在生成器训练的时候,将鉴定器的参数固定
discriminator.trainable = False

#构建并编译固定的鉴定器的GAN模型,并训练生成器
gan = build_gan(generator, discriminator)
gan.compile(loss='binary_crossentropy', optimizer=Adam.Adam())

此处要注意鉴定器设置为不可训练,仅训练生成器。

6.GAN训练循环

losses = []
accuracies = []
iteration_checkpoints = []


def train(iterations, batch_size, sample_interval):

    # 导入mnist数据集
    (X_train, _), (_, _) = mnist.load_data()

    # 将灰度像素值[0, 255]缩放到[-1, 1]
    X_train = X_train / 127.5 - 1.0
    X_train = np.expand_dims(X_train, axis=3)#增加维度,就是(28,28,1)

    # 真实图像的标签:都是1
    real = np.ones((batch_size, 1))

    # 假的图像标签:都是0
    fake = np.zeros((batch_size, 1))

    for iteration in range(iterations):

        # -------------------------
        #  训练鉴定器
        # -------------------------

        # 获取一批随机的真实照片
        idx = np.random.randint(0, X_train.shape[0], batch_size)
        imgs = X_train[idx]

        # 生成一批假的照片
        z = np.random.normal(0, 1, (batch_size, 100))
        gen_imgs = generator.predict(z)

        # 训练鉴定器
        d_loss_real = discriminator.train_on_batch(imgs, real)
        d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)
        d_loss, accuracy = 0.5 * np.add(d_loss_real, d_loss_fake)

        # ---------------------
        #  训练生成器
        # ---------------------

        #生成一批次假的照片
        z = np.random.normal(0, 1, (batch_size, 100))
        gen_imgs = generator.predict(z)

        # 训练生成器
        g_loss = gan.train_on_batch(z, real)

        if (iteration + 1) % sample_interval == 0:

            # 保存损失和精度,便于在后面绘制
            losses.append((d_loss, g_loss))
            accuracies.append(100.0 * accuracy)
            iteration_checkpoints.append(iteration + 1)

            # 输出训练过程
            print("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" %
                  (iteration + 1, d_loss, 100.0 * accuracy, g_loss))

            # 输出生成图像的采样
            sample_images(generator)

7.生成合成图像

def sample_images(generator, image_grid_rows=4, image_grid_columns=4):

    # 样本的随机噪声(4*4张的合成图)
    z = np.random.normal(0, 1, (image_grid_rows * image_grid_columns, z_dim))

    # 从随机噪声中生成图像
    gen_imgs = generator.predict(z)

    # 将图像像素值重新缩放为[0,1]内
    gen_imgs = 0.5 * gen_imgs + 0.5

    # 建立图像网格
    fig, axs = plt.subplots(image_grid_rows,
                            image_grid_columns,
                            figsize=(4, 4),
                            sharey=True,
                            sharex=True)

    cnt = 0
    for i in range(image_grid_rows):
        for j in range(image_grid_columns):
            # 输出一个图像网格
            axs[i, j].imshow(gen_imgs[cnt, :, :, 0], cmap='gray')
            axs[i, j].axis('off')
            cnt += 1

可以通过此模型检查生成器生成的图片.

8.运行模型

# 设置超参数(迭代次数,批次,间隔采样)
iterations = 20000
batch_size = 128
sample_interval = 1000

# 训练模型
train(iterations, batch_size, sample_interval)

要注意一个点就是批次的选择(典型使用的批次大小是2的幂:32,64,128,256,512),适合内存器处理

9.绘制一个关于鉴定器和生成器的训练损失表格

losses = np.array(losses)

# 绘制表格
plt.figure(figsize=(15, 5))
plt.plot(iteration_checkpoints, losses.T[0], label="Discriminator loss")
plt.plot(iteration_checkpoints, losses.T[1], label="Generator loss")

plt.xticks(iteration_checkpoints, rotation=90)

plt.title("Training Loss")
plt.xlabel("Iteration")
plt.ylabel("Loss")
plt.legend()

 10.绘制鉴定器精度的表格

accuracies = np.array(accuracies)


plt.figure(figsize=(15, 5))
plt.plot(iteration_checkpoints, accuracies, label="Discriminator accuracy")

plt.xticks(iteration_checkpoints, rotation=90)
plt.yticks(range(0, 100, 5))

plt.title("Discriminator Accuracy")
plt.xlabel("Iteration")
plt.ylabel("Accuracy (%)")
plt.legend()

下面是我自己跑完程序后生成的图片 

1.GAN-学习生成手写数字1.GAN-学习生成手写数字

1.GAN-学习生成手写数字 1.GAN-学习生成手写数字

 

 随机选取了4张采样图

 

 

第一次发博客,希望大家可以指出不足之处,我会慢慢改进,谢谢

上一篇:计算机视觉-生成模型


下一篇:我在b站读研究生——跟着李沐读论文1 ——Gan