Gradient Accumulation 梯度累加 (Pytorch)

        我们在训练神经网络的时候,batch_size的大小会对最终的模型效果产生很大的影响。一定条件下,batch_size设置的越大,模型就会越稳定。batch_size的值通常设置在 8-32 之间,但是当我们做一些计算量需求大的任务(例如语义分割、GAN等)或者输入图片尺寸太大的时候,我们的batch size往往只能设置为2或者4,否则就会出现 “CUDA OUT OF MEMORY” 的不可抗力报错。

      那么如何在有限的计算资源的条件下,训练时采用更大的batch size呢?这就是梯度累加(Gradient Accumulation)技术了。

常规训练过程

for i, (inputs, labels) in enumerate(trainloader):
    optimizer.zero_grad()                   # 梯度清零
    outputs = net(inputs)                   # 正向传播
    loss = criterion(outputs, labels)       # 计算损失
    loss.backward()                         # 反向传播,计算梯度
    optimizer.step()                        # 更新参数
    if (i+1) % evaluation_steps == 0:
        evaluate_model()

使用梯度累加的训练过程

for i, (inputs, labels) in enumerate(trainloader):
    outputs = net(inputs)                   # 正向传播
    loss = criterion(outputs, labels)       # 计算损失函数
    loss = loss / accumulation_steps        # 损失标准化
    loss.backward()                         # 反向传播,计算梯度
    if (i+1) % accumulation_steps == 0:
        optimizer.step()                    # 更新参数
        optimizer.zero_grad()               # 梯度清零
        if (i+1) % evaluation_steps == 0:
            evaluate_model()

就是加了个if

注意这里的loss每次要除以accumulation_step,所以当累加到一定步数optimizer更新的值其实是这些累加值的均值。其实就相当于扩大了batch_size,让更新的loss更加平稳。一个batch的数据最后算的loss也是这个batch的数据个数的均值。

  总结来讲,梯度累加就是每计算一个batch的梯度,不进行清零,而是做梯度的累加(平均),当累加到一定的次数之后,再更新网络参数,然后将梯度清零。

通过这种参数延迟更新的手段,可以实现与采用大batch_size相近的效果。知乎上有人说

"在平时的实验过程中,我一般会采用梯度累加技术,大多数情况下,采用梯度累加训练的模型效果,要比采用小batch_size训练的模型效果要好很多"。

你可能感兴趣的:(Gradient Accumulation 梯度累加 (Pytorch))