optimizer.zero_grad()

传统的训练函数,一个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()            

过程:

  • 获取loss:输入图像和标签,通过infer计算得到预测值,计算损失函数;
  • optimizer.zero_grad():清空过往梯度;
  • loss.backward():反向传播,计算当前梯度;
  • optimizer.step():根据梯度更新网络参数

简单的说就是进来一个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.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

过程:

  • 获取loss:输入图像和标签,通过infer计算得到预测值,计算损失函数;
  • loss.backward()反向传播,计算当前梯度;
  • 多次循环步骤1-2,不清空梯度,使梯度累加在已有梯度上;
  • 梯度累加了一定次数后,先optimizer.step()根据累计的梯度更新网络参数,然后optimizer.zero_grad()清空过往梯度,为下一波梯度累加做准备;

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

一定条件下,batchsize越大训练效果越好,梯度累加则实现了batchsize的变相扩大,如果accumulation_steps为8,则batchsize"变相"扩大了8倍,学习率也要适当放大。

 

posted @ 2023-03-16 17:15  sqsq  阅读(137)  评论(0编辑  收藏  举报