混合精度训练

减少所需显存。减少了IO.

  • 深度学习训练使用16bit表示/运算正逐渐成为主流。
  • 低精度带来了性能、功耗优势,但需要解决量化误差(溢出、舍入)。
  • 常见的避免量化误差的方法:为权重保持高精度(fp32)备份;损失放大,避免梯度的下溢出;一些特殊层(如BatchNorm)仍使用fp32运算。



“仅仅在权重更新的时候使用fp32,耗时的前向和后向运算都使用fp16”。在反向计算开始前,将dloss乘上一个scale,人为变大;权重更新前,除去scale,恢复正常值。目的是为了减小激活gradient下溢出的风险。

动态loss_scale:

基本思想是先选择一个较大的loss_scale初始值,如果梯度发生溢出(grads中有Inf或NaN)则跳过本次更新,并将loss_scale减小;如果没有发生溢出,则正常进行梯度更新,若连续N次迭代中梯度没有Inf或NaN,将loss_scale值增大。

混合精度训练过程如下:

  1. 使用FP16的输入;

  2. 前向计算:该场景中使用统一的FP32格式的初始化权重,训练时恢复checkpoint中的变量进行训练;将恢复的FP32参数转化为FP16供给前向运算;

  3. Loss计算:该场景中loss计算复杂,涉及到许多exp, log等可能会发生FP16溢出的不稳定操作,因此loss计算在FP32精度下进行;

  4. loss scale:将计算出来的loss乘以一个比例因子 scaled_loss = loss * loss_scale;

  5. 反向计算:grads = tf.gradients(scaled_loss , params,aggregation_method=aggmeth)

  6. 梯度计算完成后再将各梯度缩小相应的倍数:unscaled_grads = [(grad * (1. / loss_scale)) for grad in grads];

  7. 梯度规约:累加很多FP16数值容易造成数据溢出,选择在FP32下规约;

  8. 参数更新:根据梯度是否溢出选择是否进行参数更新并动态调整 loss_scale,若更新,直接在FP32精度的参数上进行参数更新。由于该场景中就是使用PF32的参数,更新时直接应用于该参数即可。

https://blog.csdn.net/qq_35209694/article/details/108541032

你可能感兴趣的:(混合精度训练)