马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
天生对抗网络(GAN,Generative Adversarial Network)是一种深度学习模子,由两部门构成:天生器(Generator)和辨别器(Discriminator)。天生器的目标是天生逼真的样本,而辨别器的目标是区分真实样本与天生样本。它们通过对抗过程相互训练,终极使天生器可以大概天生高度逼真的数据。
根本概念
- 天生器:从随机噪声(通常是高斯噪声)天生数据,表现为 G(z)G(z)G(z),此中 zzz 是埋伏变量(噪声)。
- 辨别器:判定输入数据是否真实,表现为 D(x)D(x)D(x),此中 xxx 是输入数据。辨别器输出一个值,表现其对输入数据为真实的概率。
目标函数
GAN 的目标是通过最小化以下对抗丧失来训练天生器和辨别器:
minGmaxDV(D,G)=Ex∼pdata(x)[logD(x)]+Ez∼pz(z)[log(1−D(G(z)))]\min_G \max_D V(D, G) = \mathbb{E}_{x \sim p_{data}(x)}[\log D(x)] + \mathbb{E}_{z \sim p_z(z)}[\log(1 - D(G(z)))]GminDmaxV(D,G)=Ex∼pdata(x)[logD(x)]+Ez∼pz(z)[log(1−D(G(z)))]
- pdata(x)p_{data}(x)pdata(x):真实数据分布。
- pz(z)p_z(z)pz(z):埋伏变量分布(通常为高斯分布)。
- D(x)D(x)D(x):辨别器对真实样本的辨别概率。
- G(z)G(z)G(z):天生器天生的样本。
训练过程
- 辨别器训练:通过真实样本和天生样本的丧失来优化辨别器。
- 天生器训练:通过辨别器的反馈,优化天生器,使得天生的样本更逼近真实样本。
通过不停的对抗训练,天生器终极可以大概天生靠近真实数据的样本,辨别器则不停进步其区分本领。
以下是一个使用 PyTorch 实现的简朴 GAN 案例,目标是天生手写数字(MNIST 数据集)。代码包罗天生器和辨别器的界说,以及训练过程。
GAN 案例代码
假如你要使用自界说的 MNISTDataset 类来加载数据,可以将它集成到之前的 GAN 示例中。以下是完备的代码示例,连合你的 MNISTDataset 实现。
完备的 GAN 示例代码
epoch设置为20,以作示例。- import torch
- import torch.nn as nn
- import torch.optim as optim
- import numpy as np
- import os
- import matplotlib.pyplot as plt
- from torch.utils.data import Dataset, DataLoader
- # 自定义 MNIST 数据集类
- class MNISTDataset(Dataset):
- def __init__(self, images_path, labels_path, transform=None):
- self.images = self.load_images(images_path)
- self.labels = self.load_labels(labels_path)
- self.transform = transform
- def load_images(self, path):
- with open(path, 'rb') as f:
- f.read(16) # 跳过前16个字节
- images = np.frombuffer(f.read(), np.uint8).reshape(-1, 1, 28, 28)
- return torch.tensor(images, dtype=torch.float32) / 255.0 # 归一化到 [0, 1]
- def load_labels(self, path):
- with open(path, 'rb') as f:
- f.read(8) # 跳过前8个字节
- labels = np.frombuffer(f.read(), np.uint8)
- return labels
- def __len__(self):
- return len(self.labels)
- def __getitem__(self, idx):
- image = self.images[idx]
- label = self.labels[idx]
- if self.transform:
- image = self.transform(image)
- return image, label
- # 超参数
- latent_size = 100
- num_epochs = 20
- batch_size = 64
- learning_rate = 0.0002
- # 数据准备
- data_root = r'./MNIST'
- train_dataset = MNISTDataset(
- images_path=os.path.join(data_root, 'train-images-idx3-ubyte'),
- labels_path=os.path.join(data_root, 'train-labels-idx1-ubyte')
- )
- data_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
- # 生成器模型
- class Generator(nn.Module):
- def __init__(self):
- super(Generator, self).__init__()
- self.model = nn.Sequential(
- nn.Linear(latent_size, 256),
- nn.ReLU(),
- nn.Linear(256, 512),
- nn.ReLU(),
- nn.Linear(512, 1024),
- nn.ReLU(),
- nn.Linear(1024, 28 * 28),
- nn.Tanh() # 输出在[-1, 1]范围内
- )
- def forward(self, z):
- return self.model(z).view(-1, 1, 28, 28)
- # 判别器模型
- class Discriminator(nn.Module):
- def __init__(self):
- super(Discriminator, self).__init__()
- self.model = nn.Sequential(
- nn.Linear(28 * 28, 1024),
- nn.LeakyReLU(0.2),
- nn.Linear(1024, 512),
- nn.LeakyReLU(0.2),
- nn.Linear(512, 256),
- nn.LeakyReLU(0.2),
- nn.Linear(256, 1),
- nn.Sigmoid() # 输出在[0, 1]范围内
- )
- def forward(self, x):
- return self.model(x.view(-1, 28 * 28))
- # 初始化模型和优化器
- device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 检查是否有 GPU
- generator = Generator().to(device) # 移动到 GPU
- discriminator = Discriminator().to(device) # 移动到 GPU
- criterion = nn.BCELoss()
- optimizer_G = optim.Adam(generator.parameters(), lr=learning_rate)
- optimizer_D = optim.Adam(discriminator.parameters(), lr=learning_rate)
- # 训练过程
- for epoch in range(num_epochs):
- for i, (images, _) in enumerate(data_loader):
- images = images.to(device) # 移动输入数据到 GPU
- # 标签
- real_labels = torch.ones(images.size(0), 1).to(device) # 移动到 GPU
- fake_labels = torch.zeros(images.size(0), 1).to(device) # 移动到 GPU
- # 判别器训练
- optimizer_D.zero_grad()
- outputs = discriminator(images)
- d_loss_real = criterion(outputs, real_labels)
- z = torch.randn(images.size(0), latent_size).to(device) # 随机噪声,移动到 GPU
- fake_images = generator(z)
- outputs = discriminator(fake_images.detach())
- d_loss_fake = criterion(outputs, fake_labels)
- d_loss = d_loss_real + d_loss_fake
- d_loss.backward()
- optimizer_D.step()
- # 生成器训练
- optimizer_G.zero_grad()
- outputs = discriminator(fake_images)
- g_loss = criterion(outputs, real_labels)
- g_loss.backward()
- optimizer_G.step()
- if (epoch + 1) % 10 == 0:
- print(f'Epoch [{epoch + 1}/{num_epochs}], d_loss: {d_loss.item():.4f}, g_loss: {g_loss.item():.4f}')
- # 可视化生成的图像
- with torch.no_grad():
- z = torch.randn(64, latent_size).to(device) # 随机噪声,移动到 GPU
- fake_images = generator(z)
- # 显示生成的图像
- grid_img = fake_images.cpu().numpy() # 移动到 CPU 以便绘图
- grid_img = grid_img.reshape(-1, 28, 28)
- plt.figure(figsize=(8, 8))
- for i in range(64):
- plt.subplot(8, 8, i + 1)
- plt.imshow(grid_img[i], cmap='gray')
- plt.axis('off')
- plt.show()
复制代码
代码阐明
- 自界说数据集:MNISTDataset 类用于从指定的路径加载 MNIST 数据。
- 数据归一化:在 load_images 方法中,将图像数据归一化到 [0, 1] 范围。
- 数据加载:使用 DataLoader 创建训练数据集的加载器。
- GAN 模子:包罗天生器和辨别器的界说。
- 训练过程:辨别器和天生器瓜代更新。
- 可视化天生图像:训练竣事后天生并表现手写数字图像。
你可以运行这个代码,并观察天生的手写数字。确保 MNIST 数据集文件在指定的路径下。
|