对神经网络加速Mixed-Precision的理解

NVIDIA对AMP的介绍:

  1. 先把weight矩阵们转一份FP16的copy;
  2. 前向、后向计算,全部用FP16的(包括激活、W、激活的梯度、W的梯度);
  3. W的梯度,需要先从FP16转换为FP32,再更新总的FP32的W;为什么:如果总的W也使用FP16,则由于数值指数范围较小,也由于W的梯度的指数小于总的W的指数,则在“对齐”过程中,W的梯度很容易对齐到0,即总的W没有被更新;
  4. Optional: 某些网络,需要把Loss扩大S倍,目的是把其激活的梯度扩大S倍,从而不至于其一部分数值太小变成0;如果用了该技术,则需要在最后W的梯度往总梯度上更新之前,把W的梯度再缩小S倍;

问:为了把激活的梯度扩大S倍,为什么通过把Loss扩大S倍来实现:

答:链式法则;L的x的导数,把公式写出来,可以发现要把这个导数扩大S倍,只需要把L对y的导数扩大S倍即可,等价于把L扩大S倍;

 

问:为什么只提到了把激活的梯度扩大S倍:

答:有些网络,不扩大S倍也行;有些网络,只有激活的梯度(W的梯度,W,激活,都没事),在FP16情况下会落到0;

 

问:为什么要把W的梯度,最后要缩小S倍:

答:同理,还是根据链式法则(也就是求导公式),如果L扩大了S倍,则W的梯度也就扩大了S倍,所以要最后缩小S倍,才能保证正确;(我认为,先转成FP32, 再缩小S倍,再更新,更精确些,不知道是不是这么实现的?

 

问:为什么快:

答:FP16利用了TensorCore;

 

效果:在收敛效果相近的前提下,可以1. 加快速度;2.减少memory占用(从而enable更大的minibatch、更大的model);

NVIDIA自吹的是平均训练速度达到3X;Pytorch报道的是2X;

另:

AMP支持已经进入Pytorch核心代码了:torch.cuda.amp

细节:

如果要做gradient的norm或者cliping,需要手动先unscale,再执行GradScaler的step更新;

如果使用gradient-accumulation技术(即用多次小batch来模拟一个大batch),每次backward之后,scaled梯度会自动累加起来,最后调用GradScaler的step(自动unscaler)以及optimizer的zero_grad;

手动在Loss中加入W的正则项时,如果使用AMP技术,则要特殊处理一下(即把W先unscale,再在autocast区域里计算正则项并加入到Loss(我估计在autocast里,会先把W进行scale,再计算)),很Ugly...

浮点数原理:

符号位,指数位,尾数位;

指数位的全0和全1是表示0和NaN这种特殊数据用的;

位数位放在小数点后面,小数点前面隐含是1;

例如+1.10110*(2^(8-127))); 其中8是指数位的东西;127是定死的“指数偏移”(我的理解是,这样指数位就不需要使用补码表示了);其中10110是尾数位的东西;

 

你可能感兴趣的:(算法工程)