简记GAN网络的loss
《简记GAN loss的理解》
GAN 是一种思想,刚接触的时候极为震撼,后来通过GAN思想也做过模型的优化,写过一篇专利。最近在用 GAN 生成数据,顺手写一写对GAN loss的理解。
Key Words:GAN、SegAN
Beijing, 2021.01
作者:RaySue
文章目录
GAN loss
GAN 网络一般形式的 loss 如下:
min G max D E x ∼ P d a t a [ l o g ( D ( x ) ) ] + E z ∼ P z [ l o g ( 1 − D ( G ( z ) ) ) ] \min_{G}\max_{D} \mathbb{E}_{x \sim P_{data}} [log (D(x))] + \mathbb{E}_{z \sim P_{z}} [log (1 - D(G(z)))] GminDmaxEx∼Pdata[log(D(x))]+Ez∼Pz[log(1−D(G(z)))]
其中:D(x) 是判别器,G(z) 是生成器。判别器的目的是最大化 loss,生成器是为了最小化 loss。 GAN 是一种思想,GAN 可以做很多任务,但万变不离其宗,就是最大,最小化损失,以达到生成对抗的目的。
- 为什么 D(x) 是期望其最大化 ?
D(x) 对应的损失有两项,第一项 E x ∼ P d a t a [ l o g ( D ( x ) ) ] \mathbb{E}_{x \sim P_{data}} [log (D(x))] Ex∼Pdata[log(D(x))],第二项 E z ∼ P z [ l o g ( 1 − D ( G ( z ) ) ) ] \mathbb{E}_{z \sim P_{z}} [log (1 - D(G(z)))] Ez∼Pz[log(1−D(G(z)))],并且D(x) ∈ \in ∈ [0, 1],而 l o g ( x ) log(x) log(x) 在[0, 1] 上单调递增,我们期望真实的数据 D ( x ) D(x) D(x)是趋近于1 的,所以第一项期望增大。第二项中 D ( G ( z ) ) D(G(z)) D(G(z))是生成数据期望其趋向于 0,所以整体也是递增的,所以D(x) 对应的整体期望是要更大的,即 max D \max_{D} maxD 。
- G(x) 最小化的 loss 是什么?
G(x) 把生成数据的标签设置为1,并和输入生成数据输入 D ( x ) D(x) D(x)得到判别的结果,进行训练,来迷惑 D ( x ) D(x) D(x),这样如果生成数据太假就会产生很大的 loss ,注意,这里的loss仅用于优化生成器,所以整个网络才会work。
G(x) 对应的损失为第二项 E z ∼ P z [ l o g ( 1 − D ( G ( z ) ) ) ] \mathbb{E}_{z \sim P_{z}} [log (1 - D(G(z)))] Ez∼Pz[log(1−D(G(z)))] ,我们想让生成数据更接近 真实数据,所以 D ( G ( z ) ) D(G(z)) D(G(z))就趋向于1,整体就期望更小,即 min G \min_G minG。
整体的思想就是:
-
判别器和生成器各司其职,判别器通过先验知识,知道哪部分数据来自生成器,哪部分是真实数据,所以尽管生成的再像真实数据,也会当成负样本来学习,让判别器越来越强
-
而生成器将其生成的结果送入判别器,并将判别器返回的预测结果利用真实数据标签来训练,以此来迷惑判别器,从而产生更接近于真实数据的结果
通过代码理解 GAN
-
先训练 D(x) 再训练 G(x) 交替进行
-
判别器 D(x) 和生成器 G(x) 利用两个优化器,每个优化器单独负责优化对应的网络参数。
-
D(x) 训练的过程:将真实数据的标签定义为 1,将生成数据定义标签为 0
-
G(x) 训练的过程:将生成的数据的标签定义为1,和经过 D(x) 的判别结果计算损失来更新参数。
criterion = nn.BCELoss() # Binary cross entropy: http://pytorch.org/docs/nn.html#bceloss
d_optimizer = optim.SGD(D.parameters(), lr=d_learning_rate, momentum=sgd_momentum)
g_optimizer = optim.SGD(G.parameters(), lr=g_learning_rate, momentum=sgd_momentum)
D.zero_grad()
# 1A: Train D on real
d_real_data = Variable(d_sampler(d_input_size))
d_real_decision = D(preprocess(d_real_data))
d_real_error = criterion(d_real_decision, Variable(torch.ones([1,1]))) # ones = true
d_real_error.backward() # compute/store gradients, but don't change params
# 1B: Train D on fake
d_gen_input = Variable(gi_sampler(minibatch_size, g_input_size))
d_fake_data = G(d_gen_input).detach() # detach to avoid training G on these labels
d_fake_decision = D(preprocess(d_fake_data.t()))
d_fake_error = criterion(d_fake_decision, Variable(torch.zeros([1,1]))) # zeros = fake
d_fake_error.backward()
d_optimizer.step() # Only optimizes D's parameters; changes based on stored gradients from backward()
G.zero_grad()
gen_input = Variable(gi_sampler(minibatch_size, g_input_size))
g_fake_data = G(gen_input)
dg_fake_decision = D(preprocess(g_fake_data.t()))
g_error = criterion(dg_fake_decision, Variable(torch.ones([1,1]))) # Train G to pretend it's genuine
g_error.backward()
g_optimizer.step() # Only optimizes G's parameters
SegAN
投稿于 Neuroinformatics (2018) 的一篇论文
-
通过GAN加持语义分割,能够让学习到的结果更加精细
-
SegAN 和 GAN 一样的两部分 loss,
-
通过预测的 01 mask(生成数据)和原图取交然后输入到 D(x) 中得到一个 res_mask
-
通过真实的 01 mask(真实数据) 和原图取交然后输入到 D(x) 中得到 target_mask
-
训练D(x) 的时候直接取 -mae (res_mask, target_mask) 让误差向大了学,判别能力越来越强,越来越挑剔
-
训练G(x) 的时候则 mae(res_mask, target_mask) 让误差减小,让学到的更像target
损失函数:
min θ S max θ C L ( θ S , θ C ) = 1 N ∑ n = 1 N l m a e ( f C ( x n ⋅ S ( x n ) ) , f C ( x n ⋅ y n ) ) \min_{\theta_S}\max_{\theta_C} L(\theta_S, \theta_C) = \frac{1}{N}\sum_{n=1}^{N}l_{mae}(f_C(x_n \cdot S(x_n)), f_C(x_n \cdot y_n)) θSminθCmaxL(θS,θC)=N1n=1∑Nlmae(fC(xn⋅S(xn)),fC(xn⋅yn))
- x n x_n xn 原图
- y n y_n yn 预测结果
参考
https://www.cnblogs.com/walter-xh/p/10051634.html