PyTorch计算机视觉(7)——条件生成对抗网络(cGAN)
PyTorch计算机视觉(7)——条件生成对抗网络(cGAN)
0. 前言
尽管深度卷积生成对抗网络 (Deep Convolutional Generative Adversarial Network, DCGAN) 能够生成高质量的伪造图像,但无法根据我们设定的特定类别或风格进行定向生成。论文《Conditional Generative Adversarial Nets》中,提出了条件生成对抗网络 (conditional convolutional GAN, cDCGAN),它能够根据需求生成特定类型的图像。我们甚至可以使用文本或声音指令引导 cDCGAN,生成与训练数据集中真实图像高度相似的各类图像。
在 MNIST 图像生成项目中,我们丢弃了标签信息。在本节中,我我们将为每张图像的标签编码,将其作为附加通道信息与图像数据融合。随后,这批携带标签信息的图像将被打包成四维张量,作为 cDCGAN 中判别器 D 的输入。在《生成对抗网络》一节中,我们使用 1×100 的噪声张量作为生成器 G 的输入来生成图像,在本节中,我们将采用 1×110 的张量进行生成——其中新增的 10 个元素对应 MNIST 数据集中 0 到 9 的预设标签。模型的训练代码与 DCGAN 几乎相同,通过模型训练过程中参数的持续更新,我们的模型将能精准生成符合指定数字要求的逼真图像。本节中,我们采用 PyTorch 的嵌入类来实现标签与图像的编码融合。
1. 条件生成对抗网络
条件生成对抗网络 (Conditional Generative Adversarial Network, CGAN) 是生成对抗网络的一种扩展,它同时接受噪声数据和条件数据作为输入,以控制生成的数据样本。与标准的生成对抗网络 (Generative Adversarial Network, CGAN)不同,输入到 CGAN 的随机噪声向量和条件向量一起传递到生成网络中,以生成具有所需特征的样本,条件向量可以是数字或对象的标签,这样生成网络可以控制生成出来的图像具有特定的属性,例如,猫或狗的图像,或戴眼镜的人的图像。
条件生成网络由两部分组成:生成网络和判别网络。生成网络负责接收条件信息和噪声向量,通过一系列的神经网络层逐步生成数据。判别网络则用于评估生成的数据与真实数据之间的差异,以辨别生成数据的真实性。生成网络和判别网络通过对抗训练的方式相互竞争和改进,从而提高生成网络的性能。
条件生成网络的应用非常广泛。例如,在图像生成领域,条件生成网络可以根据特定的类别标签生成具有特定特征或风格的图像;在文本生成领域,条件生成网络可以根据给定的文本描述生成相应的文本段落或文章。
2. cDCGAN 在 MNIST/Fashion MNIST 数据集上的应用
展示 MNIST 数据加载器中一批图像的五个标签。嵌入类实例将在模型训练前,将这个一维张量转换为填充随机数的5×3张量。该实例的第一个参数是 MNIST 的类别总数 (10),一维张量的最大值应为 9;第二个参数决定嵌入输出的列数,而行数则自动与一维标签张量的长度对齐。由于示例中首尾标签相同,嵌入输出的首行与末行内容也将完全一致。嵌入实例的参数将在模型训练过程中持续更新。
import torch; import torch.nn as nn
from torch.utils.data import DataLoader
import torch.optim.lr_scheduler as lr_scheduler
from torchvision import transforms as T
from torchvision.datasets import MNIST
from torchvision.utils import make_grid
import numpy as np
import pandas as pd
from tqdm import trange
import matplotlib.pyplot as plt
n_epochs = 20
batch_size = 100
img_size = 28
img_dim = img_size*img_size # img_dim = 28x28=784
img_channels = 1
n_class = 10
z_dim = 100
lr = 2e-4
k = 5 # k = G_lr/D_lr
fixed_latent = torch.randn(batch_size, z_dim, device='cuda')
fixed_labels = torch.tensor([i for i in range(n_class) for j in range(n_class)], dtype=torch.long, device='cuda')
trainData = MNIST('./data/', train=True, download=False,
transform=T.Compose([T.ToTensor(), T.Normalize([0.5],[0.5])]))
n_samples = len(trainData)
train_dataloader = DataLoader(trainData, batch_size=batch_size, shuffle=True)
n_batch = len(train_dataloader)
for imgs, labels in train_dataloader:
print('imgs_batch.shape=', imgs.shape)
print('labels=', labels.view(-1, 10))
break

Fashion-MNIST 数据结构与 MNIST 完全一致:包含 60000 张训练图像和 10000 张测试图像,均为 28×28 分辨率的黑白标注图像。这些图像被分为十类 (0-9),分别对应T恤/上衣、裤子、套头衫、连衣裙、外套、凉鞋、衬衫、运动鞋、手提包和短靴。执行代码 train_Dataset.classes,即可查看具体类别名称。鉴于两个数据集结构完全相同,代码可通过修改数据集名称,分别应用于 MNIST 和 Fashion-MNIST 数据集。下图展示了 cDCGAN 生成的 MNIST 图像与时装 MNIST 图像,其质量相较于真实图像已达到令人满意的水准。

嵌入类的实例定义为 nn.Embedding(10, 784)。在模型 D 的前向函数中,数据加载器中每批次图像被重塑为包含 784 个元素的一维张量。利用嵌入实例,前向传播函数将该批次每个标签编码为同样具有 784 个元素的一维张量。此时我们获得两个形状相同的张量:batch_size × 784。沿行方向 (dim = 1) 拼接这两个张量后,得到形状为 batch_size × 1568 的加长张量。随后该张量被重塑为四维张量 batch_size × 2 × 28 × 28,并如常输入判别器 D 的卷积网络进行处理。经过判别器 D 中的 sigmoid 激活函数处理后,其输出为具有批次大小元素数的一维张量,每个元素均为 0 到 1 之间的正值。根据 GAN 原始论文的设定,第一层和第四层未使用批归一化操作,此时两个卷积层的偏置选项默认设置为 True。
def weights_init(m):
if(type(m) == nn.ConvTranspose2d or type(m) == nn.Conv2d):
nn.init.normal_(m.weight.data, 0.0, 0.02)
elif(type(m) == nn.BatchNorm2d):
nn.init.normal_(m.weight.data, 1.0, 0.02)
nn.init.constant_(m.bias.data, 0)
def basic_D(in_channels, p=1):
return nn.Sequential(nn.Conv2d(in_channels, 2*in_channels, kernel_size=4,
stride=2, padding=p, bias=False),
nn.BatchNorm2d(2*in_channels),
nn.LeakyReLU(0.2, inplace=True))
class Discriminator(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.Conv2d(img_channels+1, 64, kernel_size=4, stride=2, padding=1),
nn.LeakyReLU(0.2, inplace=True),
basic_D(64, p=2),
basic_D(128, p=1),
nn.Conv2d(256, 1, kernel_size=4, stride=1, padding=0),
nn.Flatten(),
nn.Sigmoid()
)
self.label_emb = nn.Embedding(n_class, img_dim)
def forward(self, images, labels):
x = images.view(-1, img_dim)
c = self.label_emb(labels)
x_c = torch.cat([x, c], dim=1)
input = x_c.view(-1, img_channels+1, img_size, img_size)
out = self.model(input)
return out
D = Discriminator().cuda()
D.apply(weights_init)
生成器 G 的前向传播函数需要两个输入:其一是常规的潜在向量批次张量,其二是经过嵌入处理后变为 batch_size × 10 形状的伪标签一维张量。这两个张量沿行方向 (dim = 1) 拼接后形成 batch_size × 110 的张量,随后被重塑为四维张量 batch_size × 110 × 1 × 1,并如常通过生成器 G 的转置卷积网络进行处理。生成器 G 的输出为一批图像,其第四层同样未使用批归一化操作。
def basic_G(out_channels, f=4):
return nn.Sequential(nn.ConvTranspose2d(2*out_channels, out_channels,
kernel_size=f, stride=2, padding=1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(True))
class Generator(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(
nn.ConvTranspose2d(z_dim+10, 256, 4, 1, 0, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(True),
basic_G(128, f=3),
basic_G(64, f=4),
nn.ConvTranspose2d(64, 1, 4, 2, 1),
nn.Tanh()
)
self.label_emb = nn.Embedding(n_class, 10)
def forward(self, z, labels):
z = z.view(-1, z_dim)
c = self.label_emb(labels)
z_c = torch.cat([z, c], dim=1)
input = z_c.view(-1, z_dim+10, 1, 1)
out = self.model(input)
return out
G = Generator().cuda()
G.apply(weights_init)
与原始 GAN 相比,区别在于系统中加入了标签信息。通过 [i for i in range(10) for j in range(10)] 创建了一个名为 fixed_labels 的一维长张量,其中包含 100 个数字。这个一维张量与另一个名为 fixed_latent 的 100×100 张量,将用于在模型训练过程中生成 MNIST 图像,以便我们检查生成图像的质量。
optimizer_D = torch.optim.Adam(D.parameters(), lr=lr, betas=(0.5, 0.999))
optimizer_G = torch.optim.Adam(G.parameters(), lr=k*lr, betas=(0.5, 0.999))
criterion = nn.BCELoss(reduction='sum')
v = lambda i: 1
scheduler = lr_scheduler.LambdaLR(optimizer_D, lr_lambda = v)
def train_D(inputs, labels, optimizer_D):
batch_size = inputs.shape[0]
real_preds = D(inputs, labels)
one_targets = torch.ones(batch_size, 1, device='cuda')
real_loss = criterion(real_preds, one_targets)
real_score = torch.mean(real_preds).item()
latent = torch.randn(batch_size, z_dim, device='cuda')
fake_labels = torch.LongTensor(
torch.randint(0, 10, (batch_size,))).cuda()
fake_images = G(latent, fake_labels)
zero_targets = torch.zeros(batch_size, 1, device='cuda')
fake_preds = D(fake_images.detach(), fake_labels.detach())
fake_loss = criterion(fake_preds, zero_targets)
fake_score = torch.mean(fake_preds).item()
loss = real_loss + fake_loss
optimizer_D.zero_grad()
loss.backward()
optimizer_D.step()
return loss.item(), real_score, fake_score
def train_G(optimizer_G):
# Create fake images and labels
latent = torch.randn(batch_size, z_dim, device='cuda')
fake_labels = torch.LongTensor(
torch.randint(0, 10, (batch_size,))).cuda()
fake_images = G(latent, fake_labels)
# Try to fool the discriminator
preds = D(fake_images, fake_labels)
one_targets = torch.ones(batch_size, 1, device='cuda')
loss = criterion(preds, one_targets)
optimizer_G.zero_grad()
loss.backward()
optimizer_G.step()
return loss.item()
训练这两个模型非常简便。使用恒定的 lambda 调度器 (v = lambda i: 1) 和学习率比例 k=5,在约 10 分钟内就获得了高质量的 MNIST 图像。针对 Fashion-MNIST 数据集,cDCGAN 采用了可变学习率。此时的损失曲线、D(X) 曲线和 D(G(Z)) 曲线都近乎直线。
def fit(epochs):
torch.cuda.empty_cache()
df = pd.DataFrame(np.empty([epochs, 5]),
index = np.arange(epochs),
columns=['Loss_G', 'Loss_D', 'D(X)', 'D(G(Z))', 'lr'])
for i in trange(epochs):
loss_G = 0.0; loss_D = 0.0; real_sc = 0.0; fake_sc = 0.0
for real_images, labels in train_dataloader:
inputs = real_images.cuda()
labels = labels.cuda()
loss_d, real_score, fake_score = train_D(inputs, labels, optimizer_D)
loss_D += loss_d; real_sc += real_score; fake_sc += fake_score
loss_g = train_G(optimizer_G)
loss_G += loss_g
df.iloc[i, 0] = loss_G/n_samples
df.iloc[i, 1] = loss_D/n_samples
df.iloc[i, 2] = real_sc/n_batch
df.iloc[i, 3] = fake_sc/n_batch
df.iloc[i, 4] = optimizer_D.param_groups[0]['lr'] #Record lr_D
scheduler.step() #Update lr_D
optimizer_G.param_groups[0]['lr'] = df.iloc[i,4]*k #G_lr=k*G_lr
if i==0 or (i+1)%5==0:
print(
"Epoch={}, Ls_G={:.4f}, Ls_D={:.4f}, D(X)={:.4f}, D(G(Z))={:.4f}"
.format(i+1, df.iloc[i,0], df.iloc[i,1], df.iloc[i,2], df.iloc[i,3]))
print('G_lr=', optimizer_G.param_groups[0]['lr'])
fake_images = G(fixed_latent, fixed_labels)
show_imgs(fake_images.detach().cpu())
return df
train_history = fit(n_epochs)
import matplotlib.pyplot as plt; import matplotlib.ticker as ticker
history= train_history
fig, ax = plt.subplots(1,3, figsize=(15,4), sharex=True)
history.plot(ax=ax[0], y=[0,1], style=['r-+', 'b-d'])
history.plot(ax=ax[1], y=[2,3], style=['b-+', 'r-d'])
history.plot(ax=ax[2], y=[4], style=['r-+'])
for i in range(3):
ax[i].set_xlabel('epoch')
ax[i].grid(which='major', axis='both', color='g', linestyle=':')
#ax[0].set_ylabel('Loss')
ax[0].set(ylabel='Loss', ylim=[0,2.5])
ax[0].axhline(y=2*np.log(2), color='k', linestyle='--') #Theory D loss Value
ax[0].axhline(y=np.log(2), color='k', linestyle='--') #Theory G loss Value
ax[1].axhline(y=0.5, color='k', linestyle='--') #Theory D(X), D(G(Z)) values
ax[1].set_ylim([0, 1]); ax[2].set_ylim([-0.25e-4, 2.5e-4])
ax[2].ticklabel_format(style='sci', axis='y', scilimits=(0,0));

3. 使用 cDCGAN 生成石头剪子布图像
接下来,我们采用“石头剪刀布”手势数据集训练 cDCGAN。这是一个包含三个类别的小型彩色图像数据集。来自不同种族、年龄和性别的三种手势图像,分别保存在测试集、训练集和验证集三个文件夹中。训练文件夹下设有三个子文件夹,分别对应“石头剪刀布”游戏中的三种手势:握拳代表“石头”(标签 1),摊掌代表“布”(标签 0),伸出拇指、食指和中指代表“剪刀”(标签 2)。
当 Torchvision 的 ImageFolder 工具将训练文件夹中的图像打包成数据集时,每个子文件夹的名称将作为该文件夹内图像的标签。训练数据集包含三个类别,每个类别有 840 张分辨率为 300×300 的图像。导入并打包数据集,将数据集图像切片成数据加载器,并展示如下图所示的一批图像。
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
import torch.optim.lr_scheduler as lr_scheduler
import torchvision.transforms as T
from torchvision.utils import make_grid
from torchvision.datasets import ImageFolder
import numpy as np
import pandas as pd
from tqdm import trange
import matplotlib.pyplot as plt
n_epochs = 50
batch_size=32
z_dim = 100
n_class = 3
lr = 4e-4
k = 25
img_size = 128
img_dim = img_size*img_size
img_channels = 3
fixed_latent = torch.randn(48, z_dim, device='cuda')
fixed_labels = torch.cuda.LongTensor(
[i for i in range(n_class) for _ in range(16)])
train_dataset = ImageFolder('./data/RockPaperScissors/train',
transform=T.Compose([T.Resize(img_size),
T.ToTensor(),
T.Normalize([0.5]*3, [0.5]*3)]))
n_samples = len(train_dataset)
print(n_samples)
train_dataloader = DataLoader(train_dataset, batch_size=batch_size,
shuffle=True, num_workers=4, pin_memory=True)
n_batch = len(train_dataloader) #n_batch=79
for imgs, labels in train_dataloader:
print('imgs.shape=', imgs.shape)
print('labels=', '\n', labels.view(-1, 16))
break
def denorm(img_tensors): # Shift image pixel values to [0,1]
return img_tensors * 0.5 + 0.5
def show_imgs(images):
fig, ax = plt.subplots(figsize=(16,10))
inputs = make_grid(denorm(images), nrow=16)
ax.imshow(inputs.permute(1,2,0))
ax.set(xticks=[], yticks=[])
plt.show()
show_imgs(imgs)

本项目代码结构与 MNIST 数据集训练 CDCGAN 一节基本一致,但针对分辨率为 128×128 的三类别彩色图像进行了调整。判别器 D 包含六个卷积层,而生成器 G 仅有五个转置卷积层。由于层数差异,判别器 D 比生成器 G 更具鉴别优势。
def weights_init(m):
if(type(m) == nn.ConvTranspose2d or type(m) == nn.Conv2d):
nn.init.normal_(m.weight.data, 0.0, 0.02)
elif(type(m) == nn.BatchNorm2d):
nn.init.normal_(m.weight.data, 1.0, 0.02)
nn.init.constant_(m.bias.data, 0)
def basic_D(in_channels):
return nn.Sequential(
nn.Conv2d(in_channels, 2*in_channels, 4, 2, 1, bias=False),
nn.BatchNorm2d(2*in_channels),
nn.LeakyReLU(0.2, inplace=True)
)
class Discriminator(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(img_channels+1, 64, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(64),
nn.LeakyReLU(0.2, inplace=True),
basic_D(64),
basic_D(128),
basic_D(256),
basic_D(512),
nn.Conv2d(1024, 1, kernel_size=4, stride=1, padding=0),
nn.Flatten(),
nn.Sigmoid()
)
self.label_code = nn.Embedding(n_class, 1*img_dim)
def forward(self, images, labels):
x = images.view(-1, img_channels*img_dim)
c = self.label_code(labels)
x_c = torch.cat([x, c], dim=1)
input = x_c.view(-1, img_channels+1, img_size, img_size)
out = self.net(input)
return out
D = Discriminator().cuda()
D.apply(weights_init)
def basic_G(in_channels):
return nn.Sequential(
nn.ConvTranspose2d(in_channels, int(in_channels/2), 4, 2, 1, bias=False),
nn.BatchNorm2d(int(in_channels/2)),
nn.ReLU(True))
class Generator(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
basic_G(512),
basic_G(256),
basic_G(128),
basic_G(64),
nn.ConvTranspose2d(32, img_channels, 4, 2, 1),
nn.Tanh()
)
self.label_emb = nn.Embedding(n_class, 1*4*4)
self.latent = nn.Linear(z_dim, 511*4*4)
def forward(self, z, labels):
x = self.latent(z)
c = self.label_emb(labels)
x_c = torch.cat([x, c], dim=1)
input = x_c.view(-1, 512, 4, 4)
output = self.net(input)
return output
G = Generator().cuda()
G.apply(weights_init)
采用乘法学习率调度器进行模型训练,其学习率函数曲线如下图所示。学习率从 4×10⁻⁴ 开始,按照函数关系 4×10⁻⁴×(0.91)^epoch 呈指数衰减。这种乘法学习率调度机制能有效防止损失函数值爆炸的问题。
criterion = nn.BCELoss(reduction='sum')
optimizer_D = torch.optim.Adam(D.parameters(), lr=lr, betas=(0.5, 0.999))
optimizer_G = torch.optim.Adam(G.parameters(), lr=k*lr, betas=(0.5, 0.999))
v = lambda i: 0.91
scheduler = lr_scheduler.MultiplicativeLR(optimizer_D, lr_lambda=v)
def train_D(images, labels, optimizer_D):
batch_size = images.shape[0]
real_preds = D(images, labels)
one_targets = torch.ones(batch_size, 1, device='cuda')
real_loss = criterion(real_preds, one_targets)
real_score = torch.mean(real_preds).item()
latent = torch.randn(batch_size, z_dim, device='cuda')
fake_labels = torch.randint(0, 3, (batch_size,), device='cuda')
fake_images = G(latent, fake_labels)
zero_targets = torch.zeros(fake_images.shape[0], 1, device='cuda')
fake_preds = D(fake_images.detach(), fake_labels.detach())
fake_loss = criterion(fake_preds, zero_targets)
fake_score = torch.mean(fake_preds).item()
loss = real_loss + fake_loss
optimizer_D.zero_grad()
loss.backward()
optimizer_D.step()
return loss.item(), real_score, fake_score
def train_G(optimizer_G):
latent = torch.randn(batch_size, z_dim, device='cuda')
fake_labels = torch.randint(0, 3, (batch_size,), device='cuda')
fake_images = G(latent, fake_labels)
preds = D(fake_images, fake_labels)
one_targets = torch.ones(batch_size, 1, device='cuda')
loss = criterion(preds, one_targets)
optimizer_G.zero_grad()
loss.backward()
optimizer_G.step()
return loss.item()
def fit(epochs):
torch.cuda.empty_cache()
df = pd.DataFrame(np.empty([epochs, 5]),
index = np.arange(epochs),
columns=['Loss_G', 'Loss_D', 'D(X)', 'D(G(Z))', 'lr_D'])
for i in trange(epochs):
loss_G = 0.0; loss_D = 0.0; real_sc = 0.0; fake_sc = 0.0
for real_images, labels in train_dataloader:
inputs = real_images.cuda()
labels = labels.cuda()
loss_d, real_score, fake_score = train_D(inputs, labels, optimizer_D)
loss_D += loss_d; real_sc += real_score; fake_sc += fake_score
loss_g = train_G(optimizer_G)
loss_G += loss_g
df.iloc[i, 0] = loss_G/n_samples
df.iloc[i, 1] = loss_D/n_samples
df.iloc[i, 2] = real_sc/n_batch
df.iloc[i, 3] = fake_sc/n_batch
df.iloc[i, 4] = optimizer_D.param_groups[0]['lr'] #Record lr_D
scheduler.step() #Update lr_D
optimizer_G.param_groups[0]['lr'] = df.iloc[i, 4]*k #G_lr=k*G_lr
if i==0 or (i+1)%10==0:
print(
"Epoch={}, Ls_G={:.2f}, Ls_D={:.2f}, D(X)={:.2f}, D(G(Z))={:.2f}"
.format(i+1, df.iloc[i,0], df.iloc[i,1], df.iloc[i,2], df.iloc[i,3]))
fake_images = G(fixed_latent, fixed_labels)
show_imgs(fake_images.detach().cpu())
return df
train_history = fit(n_epochs)
history= train_history
fig, ax = plt.subplots(1,3, figsize=(15,4), sharex=True)
history.plot(ax=ax[0], y=[0,1], style=['r-+', 'b-'])
history.plot(ax=ax[1], y=[2,3], style=['b-+', 'r-'])
history.plot(ax=ax[2], y=[4], style=['r-+'])
for i in range(3):
ax[i].set_xlabel('epoch')
ax[i].grid(which='major', axis='both', color='g', linestyle=':')
ax[0].set(ylabel='Loss')#, ylim=[0,2])
ax[0].axhline(y=2*np.log(2), color='k', linestyle='--') #Theory D loss Value
ax[0].axhline(y=np.log(2), color='k', linestyle='--') #Theory G loss Value
ax[1].axhline(y=0.5, color='k', linestyle='--') #Theory D(X), D(G(Z)) values
ax[2].set(ylabel='learning rate of D')
ax[2].ticklabel_format(style='sci', axis='y', scilimits=(0,0))
plt.show()

通过调用 generate_image() 函数可以生成指定标签( 0 到 2 的整数)对应的单张彩色伪造图像。与真实图像相比,其生成质量仍有明显差距。
def generate_image(G, digital):
z = torch.randn(1, 100).cuda()
N = len(train_dataset.classes)-1
if digital <= N:
label = torch.LongTensor([digital]).cuda()
img = G(z, label).data.cpu()
show_imgs(img)
else:
print("Your label is bigger than ", N)
generate_image(G, 0)

小结
本节介绍了条件生成对抗网络 (Conditional Generative Adversarial Net, cGAN) 的原理与实现。CGAN 通过在生成器和判别器中同时引入标签信息(如图像类别),实现了对生成图像类型的精确控制。实践部分首先在 MNIST 和 Fashion-MNIST 数据集上构建 cDCGAN 模型,利用 nn.Embedding 将标签编码并与图像/噪声拼接,成功生成了指定数字的高质量图像。随后将该方法扩展到三分类的石头剪刀布手势数据集,采用 128×128 分辨率彩色图像,通过五层转置卷积生成器和六层卷积判别器配合指数衰减学习率调度器进行训练。实验表明,条件信息的引入有效解决了 DCGAN 无法定向生成的问题,使模型能够根据用户指定的类别生成相应的伪造图像。
系列链接
PyTorch计算机视觉(1)——计算机视觉的数学工具
PyTorch计算机视觉(2)——神经网络模型训练与PyTorch基础
PyTorch计算机视觉(3)——卷积神经网络(CNN)详解与实现
PyTorch计算机视觉(4)——迁移学习(Transfer Learning)详解与实现
PyTorch计算机视觉(5)——生成对抗网络(Generative Adversarial Network,GAN)
PyTorch计算机视觉(6)——深度卷积对抗神经网络(DCGAN)
更多推荐



所有评论(0)