Backpropagation 如何计算多个图像的损耗,然后反向传播平均损耗并更新网络权重
我正在做一个批量大小为1的任务,即每个批量只包含1个图像。因此,我必须进行手动批处理:当累积损失的数量达到一个数字时,对损失进行平均,然后进行反向传播。 我的原始代码是:Backpropagation 如何计算多个图像的损耗,然后反向传播平均损耗并更新网络权重,backpropagation,pytorch,loss,Backpropagation,Pytorch,Loss,我正在做一个批量大小为1的任务,即每个批量只包含1个图像。因此,我必须进行手动批处理:当累积损失的数量达到一个数字时,对损失进行平均,然后进行反向传播。 我的原始代码是: real\u batchsize=200 对于范围(1,5)内的历元: net.train() 总损耗=变量(torch.zeros(1.cuda(),需要梯度=真) iter_计数=0 对于enumerate(train_loader)中的batch_idx(输入,目标): 输入,目标=变量(input.cuda()),变量
real\u batchsize=200
对于范围(1,5)内的历元:
net.train()
总损耗=变量(torch.zeros(1.cuda(),需要梯度=真)
iter_计数=0
对于enumerate(train_loader)中的batch_idx(输入,目标):
输入,目标=变量(input.cuda()),变量(target.cuda())
输出=净(输入)
损失=F.nll\U损失(输出、目标)
总损失=总损失+损失
如果batch\u idx%real\u batchsize==0:
iter_计数+=1
平均损耗=总损耗/实际批量大小
ave_loss.backward()
optimizer.step()
如果iter_计数%10==0:
打印(“历元:{},迭代:{},丢失:{}”。格式(历元,
国际热核聚变实验堆计数,
平均损失数据[0]))
总损失数据为零
optimizer.zero_grad()
此代码将给出错误消息
RuntimeError:第二次尝试向后遍历图形,但缓冲区已被释放。第一次向后调用时指定retain_graph=True
我试过以下方法
第一条路(失败)
我读了一些关于这个错误消息的帖子,但不能完全理解它。将ave_loss.backward()
更改为ave_loss.backward(retain_graph=True)
防止错误消息,但丢失不会改善即将变为nan的性能
第二条路(失败)
我还尝试更改total\u loss=total\u loss+loss.data[0]
,这也将防止出现错误消息。但损失总是一样的。所以一定是出了什么问题
第三条道路(成功)
按照中的说明,对于每个图像的丢失,我将丢失除以real\u batchsize
,然后将其反向投影。当输入图像的数量达到real\u batchsize
时,我使用optimizer.step()
更新一个参数。随着训练过程的进行,损失逐渐减少。但是训练速度真的很慢,因为我们对每幅图像都进行了反向支撑
我的问题
在我的案例中,错误消息意味着什么?还有,为什么第一条路和第二条路不起作用?如何正确地编写代码,以便我们能够在每个real\u batchsize
图像中反向投影梯度,并更新梯度一次,从而加快训练速度?我知道我的代码几乎是正确的,但我只是不知道如何更改它。
这里遇到的问题与PyTorch如何在不同的过程中累积梯度有关。(有关类似问题的另一篇帖子,请参见)
那么,让我们看看当您有以下形式的代码时会发生什么:
loss_total = Variable(torch.zeros(1).cuda(), requires_grad=True)
for l in (loss_func(x1,y1), loss_func(x2, y2), loss_func(x3, y3), loss_func(x4, y4)):
loss_total = loss_total + l
loss_total.backward()
在这里,当不同迭代中的loss\u total
具有以下值时,我们进行反向传递:
total_loss = loss(x1, y1)
total_loss = loss(x1, y1) + loss(x2, y2)
total_loss = loss(x1, y1) + loss(x2, y2) + loss(x3, y3)
total_loss = loss(x1, y1) + loss(x2, y2) + loss(x3, y3) + loss(x4, y4)
因此,当您每次在total_loss
上调用.backward()
时,实际上您在loss(x1,y1)
上调用了.backward()
四次!(在丢失时(x2,y2)
三次,以此类推)
将其与另一篇文章中讨论的内容结合起来,即为了优化内存使用,PyTorch将在调用.backward()
(从而破坏连接x1
到y1
,x2
到y2
等的渐变)时释放附加到变量的图形,您可以看到错误消息的含义—您多次尝试对丢失进行反向传递,但在第一次传递后,底层图形被释放。(当然,除非指定retain\u graph=True
)
至于您尝试过的具体变体:
第一种方法:在这里,您将永远累积(即,总结-再次,请参阅另一篇文章)渐变,它们(可能)相加为inf
。
第二种方法:在这里,通过执行loss.data
,删除变量
包装,从而删除梯度信息(因为只有变量包含梯度),将损失
转换为张量。
第三种方法:在这里,您只需对每个xk,yk
元组执行一次传递,因为您立即执行backprop步骤,从而避免了上述问题
解决方案:我没有测试过它,但从我收集的信息来看,解决方案应该非常简单:在每个批次开始时创建一个新的total_loss
对象,然后将所有损失相加到该对象中,然后在最后执行一个backprop步骤 每次参数更新后,创建一个新变量total_loss
解决了这个问题。太棒了!那么你能接受这个答案吗?非常感谢。