4.2.8. 损失函数与优化器#
在正式开始训练前,需定义损失函数。DCGAN的损失函数LGAN表示为以下形式:
其中,D表示判别器,G表示生成器,x表示训练数据,z表示随机噪声,表示数学期望。上式等号左边包含了两个部分,即min G和max D,因此我们可以将损失计算分为两步进行。
首先,对于判别器来说,有:
我们希望判别器能够正确分辨生成图片和真实图片,相当于要使D(x)接近1、D(G(z))接近0,即1-D(G(z))也接近1。由于log是一个单调递增的函数,因此,我们希望D(x)接近1、1-D(G(z))接近1,可等价为希望判别器计算出的函数值最大化。
对于生成器来说,由于只与损失函数中的第二项有关,因此只需考虑损失函数中的第二项,即:
我们要通过训练,使生成器能够生成以假乱真的图片,这时,判别器对于生成样本G(z) 的判别值D(G(z))应接近1。又因为D(G(z))的值接近1的过程,会让log(1- D(G(z)))的值逐渐减小,因此,我们的期望即等价于希望生成器计算出的函数值最小化。
下面我们详细说明如何使用二进制交叉熵损失BCELoss表示DCGAN的损失函数。
在第二章中,我们给出了BCELoss的表达式如下所示,其中yi是真实标签,p(yi)是模型对该标签预测值:
DCGAN先训练判别器,再训练生成器。训练判别器时,首先输入一批真实图像x,判别器的输出为D(x),又因为真实图像的标签都为1,那么此时的损失BCELoss1即为:
然后输入一批生成的图像G(z),判别器的输出为D(G(z)),生成图像的标签都为0,那么此时的损失BCELoss2可表示为:
把上面两个损失值加起来,我们可以表示出判别器的二元交叉熵损失:
容易发现,它和判别器损失函数的值恰好相反。这样,我们就可以通过最小化判别器的BCELoss实现判别器损失函数值最大化的目标了! 现在,让我们尝试将生成器的损失函数也转换为用BCELoss表示。先前提到过,我们希望生成器最终生成的图片能够以假乱真,即判别器对生成图片G(z)的判别结果D(G(z))趋于1,使得log(1- D(G(z)))最小化,这可以等价为对-log(D(G(z)))的最小化:
不难看出,如果我们将上式补全,即可用BCELoss表示生成器的损失,这样我们便可以同样地通过计算BCELoss来得到生成器损失值了。补全后的损失函数可表示如下:
我们已经成功用BCELoss表示出了DCGAN生成器和判别器的损失函数!在程序中,我们可以通过定义BCELoss函数在训练时计算生成器和判别器的损失值。除此之外,我们还需要定义优化器。我们把生成器和判别器的优化器都设置为Adam,如下示代码:
1import torch
2from torch import nn
3
4from chapter_4_2_3_01 import lr, beta
5from chapter_4_2_7_01 import netG, netD
6
7# 损失函数与优化器
8criterion = nn.BCELoss()
9optimizerD = torch.optim.Adam(netD.parameters(), lr=lr, betas=(beta, 0.999))
10optimizerG = torch.optim.Adam(netG.parameters(), lr=lr, betas=(beta, 0.999))