原理分析:
网络结构:
DCGAN 的判别器和生成器都使用了卷积神经网络(CNN)来替代GAN 中的多层感知机,同时为了使整个网络可微,拿掉了CNN 中的池化层,另外将全连接层以全局池化层替代以减轻计算量。
从上图中可以看到,生成器G 将一个100 维的噪音向量扩展成64 * 64 * 3 的矩阵输出,整个过程采用的是反卷积deconvolutions(也叫Transposed Convolution,Fractional Strided Convolution)的方式。
那deconvolutions具体是什么?
逆卷积(Deconvolution)比较容易引起误会,转置卷积(Transposed Convolution)是一个更为合适的叫法,相对于卷积在神经网络结构的正向和反向传播中做相反的运算。
举个栗子:
4x4的输入,卷积Kernel为3x3, 没有Padding / Stride, 则输出为2x2。
输入矩阵可展开为16维向量,记作
输出矩阵可展开为4维向量,记作
卷积运算可表示为
不难想象
平时神经网络中的正向传播就是转换成了如上矩阵运算。
那么当反向传播时又会如何呢?首先我们已经有从更深层的网络中得到的
回想第一句话,你猜的没错,所谓逆卷积其实就是正向时左乘
实验:
先看看要使用到的数据集:
使用的数据是经过矫正之后的图片。为什么要矫正呢?因为原始数据集不仅有人脸,还有身体,人脸所占图片的区域比较小。
实验结果(DCGAN生成的图片):
还挺像的。
代码解读:
- 数据集类型定义:
class
2.模型结构定义:
import
需要注意的是G使用了nn.ConvTranspose2d(),D使用了nn.Conv2d()。
3.模型训练:
import
nz代表隐变量的维度。
ngf = 128代表G的特征数,ndf = 128代表D的特征数。
real_idx = 1 为正样本的标签,fake_idx = 0为负样本的标签。其实训练时候可以采用Label smooth技术,即令real_idx = 0.9 为正样本的标签,fake_idx = 0.1为负样本的标签。
transforms.Normalize把数值归一化到[-1,1],因为产生的noise的分布也是[-1,1],G(z)的分布也是[-1,1],而且在这个区间里面ReLU的梯度更大,不易造成gradient vanishing的问题。
正式训练时首先update D的参数,那想要去更新D的参数你就既要有正样本,也要有负样本。
正样本图片:
real_img
正样本标签:
b_size
负样本图片:
noise
负样本标签:
fake_label
正样本预测值及loss:
out_d_real
负样本预测值及loss:
out_d_fake
D(x):
d_x = out_d_real.mean().item()
D(G(z)):
d_g_z1 = out_d_fake.mean().item()
然后再update G的参数:
相当于minimize -logG(D(Z)),代码也是这样实现的。
必须先梯度清0,最后再step()。
D(G(z)):
d_g_z2
保存生成的图片:
plt.savefig(os.path.join(out_dir, "{}_epoch.png".format(epoch)))
将模型以字典的形式保存起来(模型的state_dict()函数就是返回模型的所有参数的):
state_dict()返回的是一个字典,每一个张量都对应的有层的名字
if
导入训练好的模型生成图片:
import