1.首先,GAN网络是有生成器和判别器,比如可以生成新的图像,而CGAN则是添加了条件,生成有限制的图像,比如生成带微笑的人脸。CGAN的架构如下:
2.主要部分的代码
class Discriminator(nn.Module):
def __init__(self):
super().__init__()
self.label_emb = nn.Embedding(10,10)
#Embedding类返回的是一个形状为[每句词个数, 词维度]的矩阵。
self.model = nn.Sequential(
nn.Linear(794,1024),
nn.LeakyReLU(0.2,inplace=True),
nn.Dropout(0.4),
nn.Linear(1024,512),
nn.LeakyReLU(0.2,inplace=True),
nn.Dropout(0.4),
nn.Linear(512,256),
nn.LeakyReLU(0.2,inplace=True),
nn.Dropout(0.4),
nn.Linear(256,1),
nn.Sigmoid()
)
def forward(self,x,labels):
x = x.view(x.size(0),784)
c = self.label_emb(labels)
x = torch.cat([x,c],1)
out = self.model(x)
return out.squeeze()
#可以删除数组形状中的单维度条目,即把shape中为1的维度去掉,但是对非单维的维度不起作用。
class Generator(nn.Module):
def __init__(self):
super().__init__()
self.label_emb = nn.Embedding(10,10)
self.model = nn.Sequential(
nn.Linear(110,256),
nn.LeakyReLU(0.2,inplace=True),
nn.Linear(256,512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 1024),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(1024, 784),
nn.Tanh()
)
def forward(self,z,labels):
z = z.view(z.size(0),100)
c = self.label_emb(labels)
x = torch.cat([z,c],1)
out = self.model(x)
return out.view(x.size(0),28,28)
for epoch in range(num_epochs):
for i,(images,labels) in enumerate(data_loader):
step = epoch*len(data_loader)+i+1
images = images.to(device)
labels = labels.to(device)
# 定义图像是真或假的标签
real_labels = torch.ones(batch_size).to(device) #真标签全是1
fake_labels = torch.randint(0,10,(batch_size,)).to(device)
#返回均匀分布的[0,10]之间的整数随机值
#训练判别器
# 定义判断器对真图片的损失函数
real_validity = D(images,labels)
d_loss_real = criterion(real_validity,real_labels) #损失比较,与1
real_score = real_validity #判别器生成的值
# 定义判别器对假图片(即由潜在空间点生成的图片)的损失函数
z = torch.randn(batch_size,100).to(device)
#创建batch_size行100列的随机数的tensor,随机值的分布式均值为0,方差为1
fake_labels = torch.randint(0, 10, (batch_size,)).to(device)
#创建batch_size行列不指定的随机整数的tensor,随机值的区间是[low, high)[0,10]
fake_images = G(z,fake_labels)
fake_validity = D(fake_images,fake_labels)
d_loss_fake = criterion(fake_validity, torch.zeros(batch_size).to(device))
#损失比较,与0
fake_score = fake_images #生成器生成的值
d_loss= d_loss_fake + d_loss_real
# 对生成器、判别器的梯度清零
reset_grad()
d_loss.backward()
d_optimizer.step()
# 训练生成器
# 定义生成器对假图片的损失函数,这里我们要求
# 判别器生成的图片越来越像真图片,故损失函数中
# 的标签改为真图片的标签,即希望生成的假图片,
# 越来越靠近真图片
z = torch.randn(batch_size, 100).to(device)
fake_images = G(z, fake_labels)
validity = D(fake_images, fake_labels)
g_loss = criterion(validity, torch.ones(batch_size).to(device)) #标签为1
# 对生成器、判别器的梯度清零
# 进行反向传播及运行生成器的优化器
reset_grad()
g_loss.backward()
g_optimizer.step()
3.具体的整个代码:https://github.com/maojinjiayou/CGAN
4.一些注意的点:
- import os 简单来说,是对文件进行操作,比如说列出当前文件夹里面有啥文件、删除文件.
- 安装tensorboardX To install this package with conda run one of the following:
conda install -c conda-forge tensorboardx
conda install -c conda-forge/label/gcc7 tensorboardx
conda install -c conda-forge/label/cf201901 tensorboardx
其中有一个nn.Embedding(vocab_size,embed_dim)类,它是Module类的子类,这里它接受最重要的两个初始化参数:词汇量大小,每个词汇向量表示的向量维度。Embedding类返回的是一个形状为[每句词个数, 词维度]的矩阵。
import torch
import torch.nn as nn
embedding=nn.Embedding(10,3)
input=torch.LongTensor([[1,2,4,5],[4,3,2,9]])
embedding(input)
tensor([[[ 0.8052, -0.1044, -0.6971],
[ 1.3792, -0.1265, -1.1444],
[ 1.4152, -0.1551, -1.2433],
[ 0.7060, -1.0585, 0.5130]],
[[ 1.4152, -0.1551, -1.2433],
[-0.9881, -0.1601, 0.6339],
[ 1.3792, -0.1265, -1.1444],
[-1.1703, 1.8496, 0.8113]]], grad_fn=<EmbeddingBackward>)
第一个参数是字的总数,第二个参数是字的向量表示的维度。我们的输入input是两个句子,每个句子都是由四个字组成的,使用每个字的索引来表示,于是使用nn.Embedding对输入进行编码,每个字都会编码成长度为3的向量。
参考文章:https://www.cnblogs.com/xiximayou/p/13343608.html
模块将按照构造函数中传递的顺序添加到模块中。另外,也可以传入一个有序模块。
-
nn.LeakyReLU(0.2,inplace=True) 是否需要覆盖之前的值。
-
torch.randint(0,10,(batch_size,))
创建batch_size行列不指定的随机整数的tensor,随机值的区间是[low, high)[0,10]
- torch.randn([3,4])
创建3行4列的随机数的tensor,随机值的分布式均值为0,方差为1
-
make_grid(images, nrow=10, normalize=True)
make_grid用于把几个图像按照网格排列的方式绘制出来,每行的图片数量为10,
normalize如果为True,则把图像的像素值通过range指定的最大值和最小值归一化到0-1。
-
fig, ax = plt.subplots(figsize=(10,10))
fig代表绘图窗口(Figure);ax代表这个绘图窗口上的坐标系(axis),一般会继续对ax进行操作。
figsize表示figure 的大小为宽、长(单位为inch)
grid.permute(1, 2, 0)将tensor的维度换位,原来的顺序是(0,1,2)
当使用detach()分离tensor但是没有更改这个tensor时,并不会影响backward()
cmap='binary' 显示设置,两端发散的色图 colormaps