我如何处理pytorch中的多重损失?

新手上路,请多包涵

在此处输入图像描述

例如,我想使用一些辅助损失来提升我的模型性能。

哪种类型的代码可以在pytorch中实现?

 #one
loss1.backward()
loss2.backward()
loss3.backward()
optimizer.step()
#two
loss1.backward()
optimizer.step()
loss2.backward()
optimizer.step()
loss3.backward()
optimizer.step()
#three
loss = loss1+loss2+loss3
loss.backward()
optimizer.step()

感谢您的回答!

原文由 heiheihei 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 685
2 个回答

第一次和第三次尝试完全相同且正确,而第二种方法是完全错误的。

在 Pytorch 中,低层梯度 不会 被后续的 backward() 调用“覆盖”,而是被累积或求和。这使得第一种和第三种方法相同,但如果你有低内存 GPU/RAM,第一种方法可能更可取(批量大小为 1024,一个 backward() + step() 调用与具有 8 个大小为 128 和 8 的批次相同 backward() 电话,最后有一个 step() 电话)。

为了说明这个想法,这里有一个简单的例子。我们想让我们的张量 x 接近 40,50 and 60 同时:

 x = torch.tensor([1.0],requires_grad=True)
loss1 = criterion(40,x)
loss2 = criterion(50,x)
loss3 = criterion(60,x)

现在第一种方法:(我们使用 tensor.grad 为我们的张量获取当前梯度 x

 loss1.backward()
loss2.backward()
loss3.backward()

print(x.grad)

此输出: tensor([-294.]) (编辑:将 retain_graph=True 放在前两个 backward 调用更复杂的计算图)

第三种方法:

 loss = loss1+loss2+loss3
loss.backward()
print(x.grad)

再次输出: tensor([-294.])

opt.zero_grad 方法不同,因为我们在调用 step() 方法后不调用 --- 。这意味着在所有 3 step 调用中使用第一个 backward --- 调用的梯度。例如,如果 3 次损失提供梯度 5,1,4 相同的权重,而不是 10 (=5+1+4),现在你的权重将有 5*3+1*2+4*1=21 作为梯度。

进一步阅读: 链接 1链接 2

原文由 Shihab Shahriar Khan 发布,翻译遵循 CC BY-SA 4.0 许可协议

对第一种方法的评论已删除,请参阅其他答案

您的第二种方法需要您使用 retain_graph=True 进行反向传播,这会产生大量的计算成本。此外,这是错误的,因为您将使用第一个优化器步骤更新网络权重,然后您的下一个 backward() 调用将在更新之前计算梯度,这意味着 second step() 调用会在您的更新中插入噪音。另一方面,如果您执行另一个 forward() 调用以通过更新的权重进行反向传播,您最终将进行异步优化,因为第一层将使用第一层更新一次 step() ,然后对每个后续的 step() 调用再次调用(本身没有错,但效率低下并且可能不是您首先想要的)。

长话短说,要走的路是最后的方法。将每个损失减少为标量,对损失求和并反向传播产生的损失。边注;确保你的缩减方案是有意义的(例如,如果你使用 reduction=‘sum’ 并且损失对应于多标签分类,请记住每个目标的类别数量是不同的,因此每个损失所贡献的相对权重也会不同)

原文由 KonstantinosKokos 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题