第六周:生成式对抗网络
- 视频总结
- 问题总结
- 代码练习
- 3.1 GAN
- 3.2 CGAN
- 3.3 DCGAN
-
视频总结
-
生成式对抗网络主要是设置两个网络,其中一个是生成器,另外一个是判断器,对生成器生成的数据使用判断器进行检测,而后返回结果更新判断器,进而慢慢使得模型优化
-
GAN可以用于图像着色,图像超像素,背景模糊,人脸生成,文本生成图片,图像修复等
-
CGAN是进行条件限定的GAN,对输入的数据非但要求数据本身,而且要求数据的标签,当数据标签与数据本身不一致时,就算数据本身为真实的,也判断为错的,这样就可以对生成的数据进行控制
-
DCGAN主要是引进了卷积的结构对模型进行优化,在输入数据为图片的时候,可以得到令人满意的结果
-
以下为GAN的目标函数
\[\mathop{min}\limits_{G}\mathop{max}\limits_{D} V(G,D)= E_{x\sim p_{data}}[logD(x)]+E_{z\sim p_z}[log(1-D(G(z)))] \] -
GAN的训练策略如下
-
KL散度主要是为了度量两个分布之间的差距,由于KL散度不具有对称性,所以引入了JS散度进行改进
\[KL(P_1||P_2)=\mathbb{E}_{x\sim P_1}[log\frac{P_1}{P_2}] \\ for\ continuous,\ \ KL(P_1||P_2)==\int_xP_1(x)log\frac{P_1(x)}{P_2(x)}dx\\ for\ discrete,\ KL(P_1||P_2)=\sum_xP_1(x)log\frac{P_1(x)}{P_2(x)}dx\\ \\ JS(P_1||P_2)=\frac{1}{2}KL(P_1||\frac{P_1+P_2}{2})+\frac{1}{2}KL(P_2||\frac{P_1+P_2}{2}) \] -
极大似然估计实际上就是最小化KL散度的一种策略,他的思想为,既然抽样已经得到了样本,那么得到该样本观测值的概率应该是比较大的,进行多次抽样,做积式求极值得到参数
\[\theta^*=\mathop{arg\ max}_\theta \prod_{i=1}^mP_G(x^i;\theta) \]接下来可以使用数理统计的方法进行推导
-
-
代码练习
-
3.1 GAN
-
示例代码中的网络结构是比较简单的
生成器为
net_G = nn.Sequential( nn.Linear(z_dim,hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 2))
判别器为
net_D = nn.Sequential( nn.Linear(2,hidden_dim), nn.ReLU(), nn.Linear(hidden_dim,1), nn.Sigmoid())
其中
z_dim = 32 hidden_dim = 128
-
对模型进行训练时 ,按照对抗生成式网络的训练策略,对两个模型逐次进行训练
for e in range(nb_epochs): #打乱训练数据的顺序 np.random.shuffle(X) real_samples = torch.from_numpy(X).type(torch.FloatTensor) loss_G = 0 loss_D = 0 for t, real_batch in enumerate(real_samples.split(batch_size)): # 固定生成器G,改进判别器D # 使用normal_()函数生成一组随机噪声,输入G得到一组样本 z = torch.empty(batch_size,z_dim).normal_().to(device) fake_batch = net_G(z) # 将真、假样本分别输入判别器,得到结果 D_scores_on_real = net_D(real_batch.to(device)) D_scores_on_fake = net_D(fake_batch) # 优化过程中,假样本的score会越来越小,真样本的score会越来越大,下面 loss 的定义刚好符合这一规律, # 要保证loss越来越小,真样本的score前面要加负号 # 要保证loss越来越小,假样本的score前面是正号(负负得正) loss = -torch.mean(torch.log(1-D_scores_on_fake) + torch.log(D_scores_on_real)) # 梯度清零 optimizer_D.zero_grad() # 反向传播优化 loss.backward() # 更新全部参数 optimizer_D.step() loss_D += loss # 固定判别器,改进生成器 # 生成一组随机噪声,输入生成器得到一组假样本 z = torch.empty(batch_size,z_dim).normal_().to(device) fake_batch = net_G(z) # 假样本输入判别器得到 score D_scores_on_fake = net_D(fake_batch) # 我们希望假样本能够骗过生成器,得到较高的分数,下面的 loss 定义也符合这一规律 # 要保证 loss 越来越小,假样本的前面要加负号 loss = -torch.mean(torch.log(D_scores_on_fake)) optimizer_G.zero_grad() loss.backward() optimizer_G.step() loss_G += loss
这里的学习率和batchsize大小对结果的影响很大
可以看到在训练判别器的时候,牵扯到两组训练数据。分别用real和fake来表示,其中real是训练数据集中真实存在的数据,而fake则是利用生成器生成的数据,最终通过对损失函数的降低 ,使得生成器生成的结果以假乱真
-
-
3.2 CGAN
-
CGAN主要是在根据标签生成结果方面对GAN进行了改进,当真实数据与标签不符时,虽然是真实的数据,但我们也将其作为错误来判断,叠加在损失函数中
-
网络结构如下
-
判别器
self.model = nn.Sequential( nn.Linear(28*28+10, 512), nn.LeakyReLU(0.2, inplace=True), nn.Linear(512, 256), nn.LeakyReLU(0.2, inplace=True), nn.Linear(256, 1), nn.Sigmoid() )
-
生成器
self.model = nn.Sequential( nn.Linear(z_dim+10, 128), nn.LeakyReLU(0.2, inplace=True), nn.Linear(128, 256), nn.BatchNorm1d(256, 0.8), nn.LeakyReLU(0.2, inplace=True), nn.Linear(256, 512), nn.BatchNorm1d(512, 0.8), nn.LeakyReLU(0.2, inplace=True), nn.Linear(in_features=512, out_features=28*28), nn.Tanh() )
-
-
训练过程为
# 生成数据 # 用正态分布中采样batch_size个随机噪声 z = torch.randn([batch_size, z_dim]).to(device) # 生成 batch_size 个 ont-hot 标签 c = torch.FloatTensor(batch_size, 10).zero_() c = c.scatter_(dim=1, index=torch.LongTensor(np.random.choice(10, batch_size).reshape([batch_size, 1])), value=1) c = c.to(device) # 生成数据 fake_images = generator(z,c) # 计算判别器损失,并优化判别器 real_loss = bce(discriminator(real_images, real_labels), ones) fake_loss = bce(discriminator(fake_images.detach(), c), zeros) d_loss = real_loss + fake_loss d_optimizer.zero_grad() d_loss.backward() d_optimizer.step() # 计算生成器损失,并优化生成器 g_loss = bce(discriminator(fake_images, c), ones) g_optimizer.zero_grad() g_loss.backward() g_optimizer.step()
可以看到与GAN的主要区别是在计算损失函数时考虑了labels
-
-
3.3 DCGAN
-
DCGAN主要是针对图像输入 ,引入了滑动卷积操作以提高效率
-
网络结构为
-
判别器
self.conv = nn.Sequential( # 第一个滑动卷积层,不使用BN,LRelu激活函数 nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, stride=2, padding=1), nn.LeakyReLU(0.2, inplace=True), # 第二个滑动卷积层,包含BN,LRelu激活函数 nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=2, padding=1), nn.BatchNorm2d(32), nn.LeakyReLU(0.2, inplace=True), # 第三个滑动卷积层,包含BN,LRelu激活函数 nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=2, padding=1), nn.BatchNorm2d(64), nn.LeakyReLU(0.2, inplace=True), # 第四个滑动卷积层,包含BN,LRelu激活函数 nn.Conv2d(in_channels=64, out_channels=128, kernel_size=4, stride=1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True) )
可以看到引入了卷积,而且除最后一个卷积外步长都为2,这与GAN和CGAN都不同。DCGAN可以增加效率
-
-
-