训练生成手写体数字 对抗神经网络

下面是一个使用TensorFlow和Keras的生成对抗网络(GAN)的基本示例,用于生成手写体数字。这个示例基于MNIST数据集。

 

我没有包括所有可能的最佳实践,如模型保存、加载、超参数调整、日志记录等。

首先,确保你安装了所需的库,特别是TensorFlow:

pip install tensorflow

接下来是GAN的代码:

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense, Flatten, Reshape, LeakyReLU, BatchNormalization
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
import numpy as np
import matplotlib.pyplot as plt

# 加载MNIST数据集
(X_train, _), (_, _) = mnist.load_data()
X_train = X_train / 255.0 * 2 - 1  # 将像素值缩放到[-1, 1]

# GAN参数
img_rows, img_cols, channels = 28, 28, 1
img_shape = (img_rows, img_cols, channels)
latent_dim = 100

# 生成器
def build_generator():
    model = Sequential()
    model.add(Dense(256, input_dim=latent_dim))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(512))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(1024))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Dense(np.prod(img_shape), activation='tanh'))
    model.add(Reshape(img_shape))
    return model

# 判别器
def build_discriminator():
    model = Sequential()
    model.add(Flatten(input_shape=img_shape))
    model.add(Dense(512))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(256))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dense(1, activation='sigmoid'))
    return model

# 编译判别器
discriminator = build_discriminator()
discriminator.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5), metrics=['accuracy'])

# 编译生成器
generator = build_generator()

# 生成器输入噪声并生成图像
z = tf.keras.Input(shape=(latent_dim,))
img = generator(z)

# 对于组合模型,我们只训练生成器
discriminator.trainable = False

# 判别器尝试区分真实和生成的图像
valid = discriminator(img)

# 组合模型(叠加生成器和判别器)
combined = tf.keras.Model(z, valid)
combined.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))

# 训练GAN
def train(epochs, batch_size=128, save_interval=50):
    half_batch = batch_size // 2
    
    for epoch in range(epochs):
        # 随机选择一半的图像
        idx = np.random.randint(0, X_train.shape[0], half_batch)
        imgs = X_train[idx]

        # 生成一半的新图像
        noise = np.random.normal(0, 1, (half_batch, latent_dim))
        gen_imgs = generator.predict(noise)

        # 训练判别器
        d_loss_real = discriminator.train_on_batch(imgs, np.ones((half_batch, 1)))
        d_loss_fake = discriminator.train_on_batch(gen_imgs, np.zeros((half_batch, 1)))
        d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

        # 训练生成器
        noise = np.random.normal(0, 1, (batch_size, latent_dim))
        valid_y = np.array([1] * batch_size)
        g_loss = combined.train_on_batch(noise, valid_y)

        # 打印进度
        print(f"{epoch} [D loss: {d_loss[0]}, acc.: {100 * d_loss[1]}] [G loss: {g_loss}]")

        # 如果到了保存间隔,则保存生成的图像样本
        if epoch % save_interval == 0:
            save_imgs(epoch)

# 保存图像
def save_imgs(epoch):
    r, c = 5, 5
    noise = np.random.normal(0, 1, (r * c, latent_dim))
    gen_imgs = generator.predict(noise)

    # 缩放图片从[-1, 1]到[0, 1]
    gen_imgs = 0.5 * gen_imgs + 0.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].axis('off')
            cnt += 1
    fig.savefig(f"mnist_{epoch}.png")
    plt.close()

# 训练GAN
train(epochs=10000, batch_size=32, save_interval=1000)

在这个代码中,首先定义了生成器和判别器的架构,然后将它们结合起来形成一个GAN网络。

train函数负责训练过程,它交替地训练判别器和生成器。save_imgs函数用于保存生成的图像,以便我们可以查看GAN在训练过程中的进步。

这是一个非常基础的GAN实现,对于实际应用,你可能需要进行很多调整和优化,包括更复杂的模型架构、更细致的训练过程控制、超参数调整等。

逐行注释的代码,解释了每一步的作用:

# 导入所需的库
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense, LeakyReLU, BatchNormalization, Reshape, Flatten
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

# 加载MNIST数据集
(X_train, _), (_, _) = mnist.load_data()

# 数据预处理,将像素值归一化到[-1, 1]的范围
X_train = X_train / 127.5 - 1.0
# 增加一个维度,使图像有单通道,即形状为(batch_size, 28, 28, 1)
X_train = np.expand_dims(X_train, axis=-1)

# 定义生成器模型
def build_generator():
    model = Sequential()
    model.add(Dense(256, input_shape=(100,)))  # 输入层,输入维度为100(噪声向量)
    model.add(LeakyReLU(alpha=0.2))  # 使用LeakyReLU激活函数
    model.add(BatchNormalization(momentum=0.8))  # 批量归一化
    model.add(Dense(512))  # 第二层,512个单元
    model.add(LeakyReLU(alpha=0.2))  # LeakyReLU激活函数
    model.add(BatchNormalization(momentum=0.8))  # 批量归一化
    model.add(Dense(1024))  # 第三层,1024个单元
    model.add(LeakyReLU(alpha=0.2))  # LeakyReLU激活函数
    model.add(BatchNormalization(momentum=0.8))  # 批量归一化
    model.add(Dense(np.prod((28, 28, 1)), activation='tanh'))  # 输出层,输出与图像像素数相同的单元数
    model.add(Reshape((28, 28, 1)))  # 将输出重塑为28x28图像
    return model

# 定义判别器模型
def build_discriminator():
    model = Sequential()
    model.add(Flatten(input_shape=(28, 28, 1)))  # 输入层,将28x28图像展平
    model.add(Dense(512))  # 第二层,512个单元
    model.add(LeakyReLU(alpha=0.2))  # LeakyReLU激活函数
    model.add(Dense(256))  # 第三层,256个单元
    model.add(LeakyReLU(alpha=0.2))  # LeakyReLU激活函数
    model.add(Dense(1, activation='sigmoid'))  # 输出层,一个单元输出0到1之间的值
    return model

# 编译判别器和生成器
discriminator = build_discriminator()
# 使用二元交叉熵作为损失函数,Adam优化器,以及准确度评估
discriminator.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5), metrics=['accuracy'])
generator = build_generator()

# GAN模型组合
z = tf.keras.Input(shape=(100,))  # 输入层,100维噪声向量
img = generator(z)  # 生成器生成图像
discriminator.trainable = False  # 在训练生成器时冻结判别器的权重
valid = discriminator(img)  # 判别器对生成的图像进行评估
combined = tf.keras.Model(z, valid)  # 组合模型,输入是噪声,输出是判别器的评估结果
combined.compile(loss='binary_crossentropy', optimizer=Adam(0.0002, 0.5))

# 训练GAN
epochs = 10000  # 训练轮数
batch_size = 32  # 批量大小
save_interval = 1000  # 保存图片的间隔
noise_dim = 100  # 噪声向量的维度
half_batch = batch_size // 2  # 半批量大小
valid = np.ones((half_batch, 1))  # 真实图片标签
fake = np.zeros((half_batch, 1))  # 伪造图片标签

for epoch in range(epochs):
    # 随机选择真实图片
    idx = np.random.randint(0, X_train.shape[0], half_batch)
    imgs = X_train[idx]
    # 生成噪声
    noise = np.random.normal(0, 1, (half_batch, noise_dim))
    # 使用噪声生成伪造图片
    gen_imgs = generator(noise, training=False)
    
    # 训练判别器
    d_loss_real = discriminator.train_on_batch(imgs, valid)
    d_loss_fake = discriminator.train_on_batch(gen_imgs, fake)
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)
    
    # 生成更多噪声
    noise = np.random.normal(0, 1, (batch_size, noise_dim))
    # 训练生成器
    g_loss = combined.train_on_batch(noise, np.ones((batch_size, 1)))
    
    # 如果达到保存间隔,打印损失并保存生成的图片
    if epoch % save_interval == 0:
        print("Epoch {}/{} [D loss: {:.4f}, acc.: {:.2f}%] [G loss: {:.4f}]".format(
            epoch, epochs, d_loss[0], 100 * d_loss[1], g_loss))
        save_imgs(generator, epoch, noise_dim)

# 定义函数以保存生成的手写数字图像
def save_imgs(generator, epoch, noise_dim):
    r, c = 5, 5  # 生成5x5网格的图片
    noise = np.random.normal(0, 1, (r * c, noise_dim))  # 生成噪声
    gen_imgs = generator(noise, training=False)  # 使用噪声生成图片
    gen_imgs = 0.5 * gen_imgs + 0.5  # 将图片的像素值从[-1, 1]缩放到[0, 1]
    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].axis('off')  # 关闭坐标轴
            cnt += 1
    fig.savefig("mnist_%d.png" % epoch)  # 保存生成的图片
    plt.close()  # 关闭图形显示窗口

# 选择性地保存生成器模型
generator.save('mnist_generator.h5')

这样的注释有助于理解代码的每一步,特别是对于初学者来说,可以更好地理解GAN的工作原理和实现细节。

版权所有 © 2023 王一帆。除非另有说明,本作品采用[知识共享 署名-非衍生作品 4.0 国际许可协议](https://creativecommons.org/licenses/by-nd/4.0/)进行许可。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生成对抗网络(GAN)是一种强大的深度学习技术,可以用于许多应用,包括手写体数字识别。在这里,我将向你展示如何使用Python实现手写体数字识别GAN。 首先,需要安装必要的库,包括TensorFlow和Keras。可以使用以下命令安装它们: ``` pip install tensorflow pip install keras ``` 接下来,我们需要准备MNIST数据集。可以使用以下代码加载数据集: ```python from keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() ``` 现在,我们将创建两个神经网络 - 一个生成器和一个判别器。生成器将随机噪声作为输入并生成手写数字图像,而判别器将接受手写数字图像并输出它们的真假。 ```python from keras.models import Sequential from keras.layers import Dense, Flatten, Reshape, Dropout from keras.layers.convolutional import Conv2DTranspose, Conv2D from keras.layers.normalization import BatchNormalization from keras.layers.advanced_activations import LeakyReLU def create_generator(): generator = Sequential() generator.add(Dense(128 * 7 * 7, input_dim=100, activation=LeakyReLU(0.2))) generator.add(Reshape((7, 7, 128))) generator.add(Conv2DTranspose(64, (3,3), strides=(2,2), padding='same', activation=LeakyReLU(0.2))) generator.add(BatchNormalization()) generator.add(Conv2DTranspose(1, (3,3), strides=(2,2), padding='same', activation='tanh')) return generator def create_discriminator(): discriminator = Sequential() discriminator.add(Conv2D(64, (3,3), padding='same', input_shape=(28,28,1))) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Conv2D(128, (3,3), strides=(2,2), padding='same')) discriminator.add(LeakyReLU(0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Flatten()) discriminator.add(Dense(1, activation='sigmoid')) return discriminator generator = create_generator() discriminator = create_discriminator() ``` 现在,我们将定义GAN模型。我们将训练生成器和判别器,以便它们可以通过相互竞争的方式共同学习并提高性能。 ```python from keras.optimizers import Adam def create_gan(generator, discriminator): discriminator.trainable = False gan = Sequential() gan.add(generator) gan.add(discriminator) gan.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5)) return gan gan = create_gan(generator, discriminator) ``` 现在我们将定义训练循环: ```python import numpy as np import matplotlib.pyplot as plt def train(generator, discriminator, gan, x_train, epochs=50, batch_size=128): # Rescale -1 to 1 x_train = x_train / 127.5 - 1. x_train = np.expand_dims(x_train, axis=3) real = np.ones((batch_size, 1)) fake = np.zeros((batch_size, 1)) for epoch in range(epochs): # Train discriminator idx = np.random.randint(0, x_train.shape[0], batch_size) real_imgs = x_train[idx] noise = np.random.normal(0, 1, (batch_size, 100)) fake_imgs = generator.predict(noise) d_loss_real = discriminator.train_on_batch(real_imgs, real) d_loss_fake = discriminator.train_on_batch(fake_imgs, fake) d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) # Train generator noise = np.random.normal(0, 1, (batch_size, 100)) g_loss = gan.train_on_batch(noise, real) # Plot the progress print("Epoch {}, Discriminator Loss: {}, Generator Loss: {}".format(epoch, d_loss, g_loss)) # Generate some digits to check the progress if epoch % 10 == 0: noise = np.random.normal(0, 1, (25, 100)) gen_imgs = generator.predict(noise) gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(5, 5) cnt = 0 for i in range(5): for j in range(5): axs[i,j].imshow(gen_imgs[cnt,:,:,0], cmap='gray') axs[i,j].axis('off') cnt += 1 plt.show() train(generator, discriminator, gan, x_train, epochs=1000, batch_size=128) ``` 在训练之后,我们可以使用生成器来生成一些手写数字图像: ```python noise = np.random.normal(0, 1, (25, 100)) gen_imgs = generator.predict(noise) gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(5, 5) cnt = 0 for i in range(5): for j in range(5): axs[i,j].imshow(gen_imgs[cnt,:,:,0], cmap='gray') axs[i,j].axis('off') cnt += 1 plt.show() ``` 这就是用Python实现手写体数字识别GAN的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值