我目前正在pytorch中做一个关于Wasserstein GAN的项目(https:/arxiv.orgpdf1701.07875.pdf).
在Wasserstain GAN中,使用waserstein距离定义了一个新的目标函数为 。
这就导致了以下训练GAN的算法。
我的问题是:
当在pytorch中实现算法的第5行和第6行时,我应该乘以损失-1吗?就像我的代码一样(我使用RMSprop作为生成器和批判器的优化器)。
############################
# (1) Update D network: maximize (D(x)) + (D(G(x)))
###########################
for n in range(n_critic):
D.zero_grad()
real_cpu = data[0].to(device)
b_size = real_cpu.size(0)
output = D(real_cpu)
#errD_real = -criterion(output, label) #DCGAN
errD_real = torch.mean(output)
# Calculate gradients for D in backward pass
errD_real.backward()
D_x = output.mean().item()
## Train with all-fake batch
# Generate batch of latent vectors
noise = torch.randn(b_size, 100, device=device) #Careful here we changed shape of input (original : torch.randn(4, 100, 1, 1, device=device))
# Generate fake image batch with G
fake = G(noise)
# Classify all fake batch with D
output = D(fake.detach())
# Calculate D's loss on the all-fake batch
errD_fake = torch.mean(output)
# Calculate the gradients for this batch
errD_fake.backward()
D_G_z1 = output.mean().item()
# Add the gradients from the all-real and all-fake batches
errD = -(errD_real - errD_fake)
# Update D
optimizerD.step()
#Clipping weights
for p in D.parameters():
p.data.clamp_(-0.01, 0.01)
如你所见,我的操作是errD = -(errD_real - errD_fake),errD_real和errD_fake分别是批判者对真实样本和假样本预测的平均值。
根据我的理解,RMSprop应该按照以下方式优化批判者的权重。
w <- w - alpha*gradient(w)
(α为学习率除以平方梯度的加权移动平均数的平方根)
由于优化问题要求与梯度 "走 "的方向一致,所以应该要求在优化权重之前将梯度(w)乘以-1。
你认为我的推理正确吗?
程序可以运行,但结果很差。
我按照同样的逻辑对生成器的权重进行优化,但这次是为了与梯度的方向相反。
############################
# (2) Update G network: minimize -D(G(x))
###########################
G.zero_grad()
noise = torch.randn(b_size, 100, device=device)
fake = G(noise)
#label.fill_(fake_label) # fake labels are real for generator cost
# Since we just updated D, perform another forward pass of all-fake batch through D
output = D(fake).view(-1)
# Calculate G's loss based on this output
#errG = criterion(output, label) #DCGAN
errG = -torch.mean(output)
# Calculate gradients for G
errG.backward()
D_G_z2 = output.mean().item()
# Update G
optimizerG.step()
对不起,问题太长了,我已经尽量把我的疑问解释清楚了。谢谢大家。
我注意到你的判别器训练协议的实现中存在一些错误。你调用了两次你的后向函数,真实值和假值损失都在不同的时间步长进行了后向传播。
从技术上讲,使用这种方案的实现是可能的,但非常不可读。你的 errD_real
在这种情况下,你的输出将是正的而不是负的,因为这是一个最佳的选择。D(G(z))>0
所以你惩罚它的正确性。总的来说,你的模型收敛,只是通过预测 D(x)<0
的所有输入。
要解决这个问题,不要调用你的 errD_readl.backward()
或您的 errD_fake.backward()
. 只需使用 errD.backward()
在您定义 errD
会完全正常工作。否则,你的发电机似乎是正确的。