pytroch反向传播梯度累加及清零

传统的训练函数,一个batch是这么训练的:

for i,(images,target) in enumerate(train_loader):
    # 1. input output
    images = images.cuda(non_blocking=True)
    target = torch.from_numpy(np.array(target)).float().cuda(non_blocking=True)
    outputs = model(images)
    loss = criterion(outputs,target)
    ****************************
    # 2. backward
    optimizer.zero_grad()   # reset gradient
    loss.backward()
    ++++++++++++++++++++++++++++++
    optimizer.step()

1.optimizer.zero_grad()清空过往梯度

backward()反向传播,可计算出各个变量的梯度,见https://blog.csdn.net/weixin_38145317/article/details/104777259

2. optimizer.step() 更新权重参数

简单来说,就是进来一个batch_size的数据,计算一次梯度,更新一次网络.

从pytorch的设计原理上来说,在每次进行前向计算得到pred时,会产生一个用于梯度回传的计算图,这张图储存了进行back propagation需要的中间结果,当调用了.backward()后,会从内存中将这图释放,而随着当我们使用loss.backward()和optimize.step()进行梯度下降更新参数的时候,梯度并不会自动清零.pytorch的特点就是每一步都是独立功能的操作,因此也就有需要梯度清零的说法,如若不显式的进行optimizer.zero_grad()这一操作,backward()的时候就会累加梯度.

若计算机内存受限,可以考虑梯度累加的trick,使用梯度累加是这么写的:

for i,(images,target) in enumerate(train_loader):
    # 1. input output
    images = images.cuda(non_blocking=True)
    target = torch.from_numpy(np.array(target)).float().cuda(non_blocking=True)
    outputs = model(images)
    loss = criterion(outputs,target)

    # 2.1 loss regularization
    loss = loss/accumulation_steps   
    # 2.2 back propagation
    loss.backward()
    # 3. update parameters of net
    if((i+1)%accumulation_steps)==0:
        # optimizer the net
        optimizer.step()        # update parameters of net
        optimizer.zero_grad()   # reset gradient

1.获取loss,输入图像和标签,通过infer计算得到预测值,计算损失函数

2. loss.backward()反向传播,计算当前梯度

3. 多次循环步骤1-2,不清空梯度,使梯度累加在已有梯度上

4.梯度累加了一定次数后,先optimizer.step()根据累计的梯度更新网络参数,然后optimizer.zero_grad()清空过往梯度,为下一波梯度累加做准备

总结来说,梯度增加就是,每次获取1个batch的数据,计算1次梯度,梯度不清空,不断累加,累加到一定次数后,根据累加的梯度更新网络参数,然后清空梯度,进行下一次循环.

一定条件下,batchsize越大训练效果越好,梯度累加则实现了batchsize的变相扩大,如果accumulation_steps为8,则batchsize变相扩大了8倍,是实验室解决显存受限的一个不错的trick,使用时需要注意,学习率也要适当放大.

注意:

1.梯度累加时,BN是否有影响,之前有人是这么说的:

As far as I know, batch norm statistics get updated on each forward pass, so no problem if you don't do  .backward() every time.

BN的估算是在forward阶段就已经完成的,并不冲突,只是accumulation_steps=8和真实的batchsize放大8倍相比,效果自然是差一些,毕竟8倍batchsize的BN估算出来的均值和方差肯定更精准一些.

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值