【问题标题】:Will it cause gradient vanishing by adding a constant positive and constant negative loss?它会通过添加恒定的正负损失导致梯度消失吗?
【发布时间】:2021-03-08 21:37:34
【问题描述】:

我想问一个关于使用两个损失来训练一个模型的问题。
我将生成一些特定类型的疑问句。
为了实现它,我使用
(1) 一个正常的 GAN 来生成正常的问题空间。然后
(2) 一个辅助分类器,让生成器专注于生成这类问题。

通过预实验,当我在 Generator-Discriminator 损失 (loss_G_D) 上使用 BCELoss() 时,损失值约为 3。
当我在 Generator-Classifier loss (loss_G_C) 上使用 -Entropy 时,损失值总是负数,而且非常大,例如-300.
为了不让他们相互影响训练过程,我采用了这种训练方式。

optimizer.zero_grad()
loss_G_D = BCELoss(discriminator(generated_data))
loss_G_D.backward()
optimizer.step()

optimizer.zero_grad()
loss_G_C = -Entropy(classifier(generated_data))
loss_G_C.backward()
optimizer.step()

但是,此训练过程有点慢,似乎他们将网络训练“来回”。 所以一个朋友建议我这个方法:

optimizer.zero_grad()
loss_G_D = BCELoss(discriminator(generated_data))
loss_G_C = -Entropy(classifier(generated_data))
loss = loss_G_D+loss_G_C
# if you worry about the scale, give some weight, like
# loss = loss_G_D+0.01*loss_G_C
loss.backward()
optimizer.step()

我认为这是有道理的。但是,就像loss_G_D是3,loss_G_C是-300,加起来不会导致梯度消失吗?使用 loss = loss_G_D+0.01*loss_G_C=0 ?
或者我可以说因为它们是不同类型的损失,考虑到总是正面和负面的,我们不应该把它们加起来吗?
(PS。我想也许将 -Entropy 损失映射到一个始终为正的激活函数中,然后将两个损失相加就可以了?)

【问题讨论】:

    标签: machine-learning deep-learning pytorch


    【解决方案1】:

    不,不会的。在您的情况下,“消失”的是总损失,而不是梯度。梯度只是从两个损失计算的两个独立梯度的总和。由于一个损失只在classifier 上强制执行,而另一个只在discriminator 上强制执行,所以反向传播前者应该只将梯度分配给classifier,而反向传播后者应该只将梯度分配给discriminator。所以它们不会相互影响。

    让我也用一个简单的例子来解释一下。假设您只有两个参数xy。并且您想通过强制损失L_x = abs(x) 使x 尽可能小。同时,您还希望通过强制执行L_y=-abs(y) 使y 尽可能大。所以总损失实际上是L=abs(x)-abs(y)。假设最初我们有x=y=1。那么梯度是(dL/dx,dL/dy)=(1,-1),而损失是L=0

    更具体地说,(x,y)=(1,1)L_x=1 给出了(d(L_x)/dx,d(L_x)/y)=(1,0) 的梯度,L_y=-1 给出了(d(L_y)/dx,d(L_y)/y)=(0,-1) 的梯度。您会看到,即使 L_xL_y 相互抵消,它们的渐变也不会。

    【讨论】:

    • 谢谢!现在我明白了“损失消失!=梯度消失”。我想我可以安全地使用方法2。
      但是如果真的如你所说,我朋友的方法(代码中带有#号)可能不太好,对吧? XD。当他把这两个损失加起来并倒退时。或者即使我做了总和,pytorch 也会将每个损失反向传播到他们的来源? (也许我应该在 pytorch 论坛上问这个问题......)
    • 另一个问题是,我使用两个“分类器”——鉴别器和辅助分类器来增强生成器。但是,如果如您所说,我似乎正在训练这两个“分类器”......我想是不是有一个额外的步骤可以将梯度从“分类器”带到生成器? (抱歉总是问菜鸟问题..)
      PS:我在训练之前设置了 discriminator.eval() 和 classifier.eval() 通过...
    • 很抱歉我的第一条评论不清楚,我的意思是根据您的意见,我可以安全地使用optimizer.zero_grad() loss_G_D = ... loss_G_D.backward() loss_G_C = ... loss_G_C.backward() optimizer.step(),对吧?但是如何将它们加起来和向后加呢?这两个部分的损失会分别正确地反向传播到它们的源吗?谢谢!
    • @PeterNova 通常添加它们就可以了。这取决于您如何实现分类器和判别器,还取决于您在优化器中放入的内容。但由于您的代码对此不清楚,我无法确定您的代码会如何表现。
    猜你喜欢
    • 1970-01-01
    • 2012-04-13
    • 2019-11-10
    • 2022-10-13
    • 2018-01-16
    • 2015-12-31
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    相关资源
    最近更新 更多