pytorch GAN伪造手写体mnist数据集方式

1. 引言

GAN(Generative Adversarial Network) 是一种生成式模型,也是深度学习领域的一个重要研究问题,它能够学习如何生成与训练样本相似的数据。在本文中,我们将使用 PyTorch 这一深度学习框架来训练一个 GAN 模型来生成手写体数字数据集 MNIST。

2. 数据集介绍

MNIST 是一个手写体数字数据集,它由 70000 张 28x28 的灰度图像组成,其中训练集包含 60000 张图像,测试集包含 10000 张图像。每个图像都代表一个从 0 到 9 的数字。这个数据集是机器学习领域中广泛使用的数据集之一,也是 GAN 模型学习的常见数据集。

3. GAN 模型简介

GAN 是由 Goodfellow 等人于 2014 年提出的,它由一个生成器和一个判别器组成。生成器使用一个随机噪声向量作为输入,生成一个与训练数据相似的数据。判别器接收真实数据和生成器生成的数据,然后将它们分类为真实的或者假的。生成器和判别器通过对抗训练来提高它们的性能。

3.1 GAN 模型原理

GAN 模型的训练过程主要分为两个部分:生成器的训练和判别器的训练。

生成器是一个由全连接层和卷积层组成的神经网络模型,它将一个随机噪声向量转化为一个与训练数据相似的数据。我们用 $G(z)$ 表示生成器输出的数据,其中 $z$ 是一个从高斯分布中采样得到的随机向量。

判别器是一个二分类器,它用来判断输入的数据是真实数据还是生成器生成的假数据。我们用 $D(x)$ 表示判别器将输入的 $x$ 数据分类为真实数据的概率,用 $D(G(z))$ 表示判别器将由 $G(z)$ 生成的数据分类为真实数据的概率。判别器通过梯度下降法最小化分类错误的损失函数:

$$

\mathcal{L}_D=-\left[\sum_{x\sim p_{data}(x)}\log{D(x)}+\sum_{z\sim p_z(z)}\log{(1-D(G(z)))}\right]

$$

其中,$p_{data}(x)$ 表示训练数据的概率分布,$p_z(z)$ 表示随机噪声向量 $z$ 的概率分布。

生成器通过最大化判别器无法区分真实数据和生成数据的损失函数来进行训练:

$$

\mathcal{L}_G=\sum_{z\sim p_z(z)}\log{(1-D(G(z)))}

$$

3.2 GAN 模型的改进

GAN 模型的训练过程有时比较不稳定,并且可能会出现“崩溃”的情况,即生成器和判别器都无法有效地提高。解决这个问题的方法有很多,其中一种方法是借鉴 VAE(Variational Autoencoder) 的技术,使用 KL 散度来衡量生成数据和真实数据之间的差异。

此外,GAN 模型也可以使用多种网络结构来提高性能,比如 DCGAN(Deep Convolutional GAN) 和 WGAN(Wasserstein GAN) 等。

4. 使用 PyTorch 训练 GAN 模型

在使用 PyTorch 训练 GAN 模型之前,我们需要先准备好数据集和模型架构。这里我们使用 PyTorch 内置的 MNIST 数据集,并搭建一个简单的 GAN 模型。

首先,我们需要加载 MNIST 数据集。PyTorch 提供了一个 torchvision.datasets 包,可以方便地加载多种常见的数据集。

import torch

import torch.nn as nn

import torch.optim as optim

import torchvision.datasets as datasets

import torchvision.transforms as transforms

# 加载 MNIST 数据集

train_dataset = datasets.MNIST(root='data/', train=True, transform=transforms.ToTensor(), download=True)

test_dataset = datasets.MNIST(root='data/', train=False, transform=transforms.ToTensor(), download=True)

# 创建 DataLoader

batch_size = 128

train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=True)

接下来,我们定义生成器和判别器。这里我们使用的是一个简单的全连接层网络。

class Generator(nn.Module):

def __init__(self):

super(Generator, self).__init__()

self.fc1 = nn.Linear(100, 256)

self.fc2 = nn.Linear(256, 512)

self.fc3 = nn.Linear(512, 784)

def forward(self, x):

x = nn.LeakyReLU(0.2)(self.fc1(x))

x = nn.LeakyReLU(0.2)(self.fc2(x))

x = nn.Tanh()(self.fc3(x)) # 生成数据的范围是 [-1,1]

return x

class Discriminator(nn.Module):

def __init__(self):

super(Discriminator, self).__init__()

self.fc1 = nn.Linear(784, 512)

self.fc2 = nn.Linear(512, 256)

self.fc3 = nn.Linear(256, 1)

def forward(self, x):

x = nn.LeakyReLU(0.2)(self.fc1(x))

x = nn.LeakyReLU(0.2)(self.fc2(x))

x = nn.Sigmoid()(self.fc3(x))

return x

在定义了模型的架构之后,我们需要分别进行生成器和判别器的训练。

首先,我们定义损失函数和优化器。

# 定义损失函数和优化器

criterion = nn.BCELoss()

d_optimizer = optim.Adam(D.parameters(), lr=0.0002, betas=(0.5, 0.999))

g_optimizer = optim.Adam(G.parameters(), lr=0.0002, betas=(0.5, 0.999))

接下来,我们进行模型的训练。在每个训练周期中,我们分别训练生成器和判别器。

num_epochs = 200

for epoch in range(num_epochs):

for i, (real_images, _) in enumerate(train_loader):

# 训练判别器

real_labels = torch.ones(batch_size, 1) # 真实数据的标签为 1

fake_labels = torch.zeros(batch_size, 1) # 生成数据的标签为 0

real_images = real_images.view(batch_size, -1)

d_output_real = D(real_images)

d_real_loss = criterion(d_output_real, real_labels)

z = torch.randn(batch_size, 100)

fake_images = G(z)

d_output_fake = D(fake_images)

d_fake_loss = criterion(d_output_fake, fake_labels)

d_loss = d_real_loss + d_fake_loss

d_optimizer.zero_grad()

d_loss.backward()

d_optimizer.step()

# 训练生成器

z = torch.randn(batch_size, 100)

fake_images = G(z)

d_output = D(fake_images)

g_loss = criterion(d_output, real_labels)

g_optimizer.zero_grad()

g_loss.backward()

g_optimizer.step()

# 打印训练日志

print(f'Epoch [{epoch + 1}/{num_epochs}], Step [{i + 1}/{len(train_loader)}], d_loss: {d_loss.item():.4f}, g_loss: {g_loss.item():.4f}')

最后,我们生成一些新的手写体数字图像,并进行可视化展示。

import matplotlib.pyplot as plt

import numpy as np

# 生成手写体数字图像

z = torch.randn(64, 100)

fake_images = G(z)

# 可视化展示

fake_images = fake_images.reshape(-1, 28, 28).detach().numpy()

fig, axs = plt.subplots(8, 8, figsize=(8,8))

for i in range(8):

for j in range(8):

axs[i,j].imshow(fake_images[i*8+j], cmap='gray')

axs[i,j].axis('off')

plt.show()

经过训练,我们可以得到比较逼真的手写体数字图像,如下图所示。

![GAN 生成的手写体数字图像](https://img-blog.csdnimg.cn/20210927231519206.png)

在上述代码中,我们设置了 temperature=0.6 以控制生成数据的多样性。这个参数的取值越大,生成的图像就会越多样化,但同时也会增加图像的噪点和错误率。相反,如果取值过小,生成的图像将会变得相似且精细,但是可能会出现过拟合的情况。因此,我们需要在取值时进行适当的调整,以获得最佳的生成效果。

5. 总结

GAN 是一种有效的生成式模型,它能够学习如何生成与训练样本相似的数据。在本文中,我们使用 PyTorch 框架训练了一个 GAN 模型来生成 MNIST 手写体数字图像数据集。通过对模型的构建和训练,我们可以得到优秀的手写体数字生成效果。在实际应用中,GAN 模型也可以用于生成其他类型的数据,比如自然图像、音频等等,具有广泛的应用前景。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。

后端开发标签