参考链接:
https://www.jb51.net/article/189433.htm
https://www.jianshu.com/p/c59b75f1064c
零梯度可改变:可利用requires_grad_()方法修改tensor的requires_grad属性.可以调用.detach()或with torch.no_grad():,姜不再计算张量的梯度,跟踪张量的历史记录.这点在评估模型、测试模型阶段中常常用到.
用法:
model.zero_grad()
optimizer.zero_grad()
model.zero_grad()的原代码
for p in self.parameters():
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
optimizer.zero_grad()的原代码
for group in self.param_groups:
for p in group['params']:
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
当使用optimizer = optim.Optimizer(net.parameters())设置优化器时,此时优化器中的param_groups等于模型中的parameters(),此时,二者是等效的,从二者的源码中也可以看出来。
首先了解pytorch的机制。在pytorch中有前向计算图和反向计算图两个独立的机制。并且pytorch会默认对梯度进行累加。默认累加的好处是当在多任务中对前面共享部分的tensor进行了多次计算操作后,调用不同任务loss的backward,那些tensor的梯度会自动累加,缺点是当你不想先前的梯度影响到当前梯度的计算时需要手动清零 。
总结知乎大佬的:
EPO1:
for idx, data in enumerate(train_loader):
xs, ys = data
pred1 = model1(xs)
pred2 = model2(xs)
loss1 = loss_fn1(pred1, ys)
loss2 = loss_fn2(pred2, ys)
******
loss = loss1 + loss2
optmizer.zero_grad()
loss.backward()
++++++
optmizer.step()
从PyTorch的设计原理上来说,在每次进行前向计算得到pred时,会产生一个用于梯度回传的计算图,这张图储存了进行back propagation需要的中间结果,当调用了.backward()后,会从内存中将这张图进行释放上述代码执行到******时,内存中是包含了两张计算图的,而随着求和得到loss,这两张图进行了合并,而且大小的变化可以忽略执行到++++++时,得到对应的grad值并且释放内存。这样,训练时必须存储两张计算图,而如果loss的来源组成更加复杂,内存消耗会更大
作者:Forever123
链接:https://www.zhihu.com/question/303070254/answer/608153308
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
for idx, data in enumerate(train_loader):
xs, ys = data
optmizer.zero_grad()
# 计算d(l1)/d(x)
pred1 = model1(xs) #生成graph1
loss1 = loss_fn1(pred1, ys)
loss1.backward() #释放graph1
# 计算d(l2)/d(x)
pred2 = model2(xs)#生成graph2
loss2 = loss_fn2(pred2, ys)
loss2.backward() #释放graph2
# 使用d(l1)/d(x)+d(l2)/d(x)进行优化
optmizer.step()
可以从代码中看出,利用梯度累加,可以在最多保存一张计算图的情况下进行multi-task任务的训练。另外一个理由就是在内存大小不够的情况下叠加多个batch的grad作为一个大batch进行迭代,因为二者得到的梯度是等价的综上可知,这种梯度累加的思路是对内存的极大友好,是由FAIR的设计理念出发的。
我没看懂
上一篇:【梯度下降】原理和过程(一)