新智元引荐
修正:元子
【新智元导读】百度和Nvidia研究院结合N卡底层核算优化,提出了一种有用的神经网络练习加快办法,不只是预练习,在全民finetune BERT的今日变得反常有用。「福利:今晚8点,刘天义博士为您解读云游戏性能及优化,戳右边链接上新智元小程序参加直播!」
全部还要从2018年ICLR的一篇论文说起。
《MIXED PRECISION TRAINING》是百度&Nvidia研究院一同宣布的,结合N卡底层核算优化,提出了一种灰常有用的神经网络练习加快办法,不只是预练习,在全民finetune BERT的今日变得反常有用哇。
并且调研发现,不只百度的paddle结构支撑混合精度练习,在Tensorflow和Pytorch中也有相应的完成。下面咱们先来讲讲理论,后边再剖析混合精度练习在三大深度学习结构中的打开方法。
理论原理
练习过神经网络的小伙伴都知道,神经网络的参数和中心成果绝大部分都是单精度浮点数(即float32)存储和核算的,当网络变得超级大时,下降浮点数精度,比方运用半精度浮点数,显然是进步核算速度,下降存储开支的一个很直接的办法。
可是副作用也很显然,假如咱们直接下降浮点数的精度直观上必定导致模型练习精度的丢掉。可是呢,天外有天,这篇文章用了三种机制有用地避免了模型的精度丢掉。待小夕逐个说来o(* ̄▽ ̄*)ブ
权重备份(master weights)
咱们咱们都知道半精度浮点数(float16)在核算机中的表明分为1bit的符号位,5bits的指数位和10bits的尾数位,所以它能表明的最小的正数即2^-24(也便是精度到此为止了)。当神经网络中的梯度灰常小的时分,网络练习过程中每一步的迭代(灰常小的梯度 也黑小的learning rate)会变得更小,小到float16精度无法表明的时分,相应的梯度就无法得到更新。
论文核算了一下在Mandarin数据集上练习DeepSpeech 2模型时产生过的梯度,发现在未乘以learning rate之前,就有挨近5%的梯度直接悲惨剧的变成0(精度比2^-24还要高的梯度会直接变成0),形成严重的丢掉呀/(ㄒoㄒ)/~~
还有更难的,假定迭代量逃过一劫预备贡献自己的时分。。。由于网络中的权重往往远大于咱们要更新的量,当迭代量小于Float16当时区间内能表明的最小距离的时分,更新也会失利(哭瞎┭┮﹏┭┮我怎样这么难鸭)
所以怎样办呢?作者这儿提出了一个十分simple but effective的办法,便是前向传达和梯度核算都用float16,可是存储网络参数的梯度时要用float32!这样就能够某些特定的程度上的处理上面说的两个问题啦~~~
咱们来看一下练习曲线,蓝色的线是正常的float32精度练习曲线,橙色的线是运用float32存储网络参数的learning curve,绿色滴是不运用float32存储参数的曲线,两者一比就相形见绌啦。
丢掉放缩(loss scaling)
有了上面的master weights现已能够满足高精度的练习许多网络啦,可是有点强迫症的小夕来说怎样仍是觉得有点不对呀o((⊙﹏⊙))o.
尽管运用float32来存储梯度,的确不会丢掉精度了,可是核算过程中呈现的指数位小于 -24 的梯度不仍是会丢掉的嘛!相当于用漏水的筛子从河滨往村里运水,为了多存点水,乡民们把储水的碗换成了大缸,燃鹅筛子依然是漏的哇,在路上的时分水就现已漏的木有了。。
所以loss scaling办法来了。首要作者核算了一下练习过程中激活函数梯度的散布状况,由于网络中的梯度往往都十分小,导致在运用FP16的时分右边有很多的规模是没有运用的。这种状况下,咱们咱们能够经过扩大loss来把整个梯度右移,削减由于精度随时变为0的梯度。
那么问题来了,怎样合理的扩大loss呢?一个最简略的办法是常数缩放,把loss一股脑一致扩大S倍。float16能表明的最大正数是2^15*(1+1-2^-10)=65504,咱们咱们能够核算网络中的梯度,核算出一个常数S,使得最大的梯度不超越float16能表明的最大整数即可。
当然啦,还有愈加智能的动态调整(automatic scaling) o(* ̄▽ ̄*)ブ
咱们先初始化一个很大的S,假如梯度溢出,咱们就把S缩小为本来的二分之一;假如在许屡次迭代中梯度都没有溢出,咱们也能够测验把S扩大两倍。以此类推,完成动态的loss scaling。
运算精度(precison of ops)
精雕细镂再进一步,神经网络中的运算首要可大致分为四大类,混合精度练习把一些有更高精度要求的运算,在核算过程中运用float32,存储的时分再转换为float16。
matrix multiplication: linear, matmul, bmm, conv
pointwise: relu, sigmoid, tanh, exp, log
reductions: batch norm, layer norm, sum, softmax
loss functions: cross entropy, l2 loss, weight decay
像矩阵乘法和绝大多数pointwise的核算能够直接运用float16来核算并存储,而reductions、loss function和一些pointwise(如exp,log,pow等函数值远大于变量的函数)需求愈加精密的处理,所以在核算中运用用float32,再将成果转换为float16来存储。
总结:三大深度学习结构的打开方法
混合精度练习做到了在前向和后向核算过程中均运用半精度浮点数,并且没有像之前的一些作业相同还引进额定超参,并且重要的是,完成分外的简略却能带来十分明显的收益,在显存half以及速度double的状况下坚持模型的精度,几乎不能再凶猛啦。
看完了硬核技术细节之后,咱们赶忙来看看代码完成吧!如此强壮的混合精度练习的代码完成不要太简略了吧
Pytorch
导入Automatic Mixed Precision (AMP),不要998不要288,只需3行无痛运用!
from apex import ampmodel, optimizer = amp.initialize(model, optimizer, opt_level="O1") # 这儿是“欧一”,不是“零一”with amp.scale_loss(loss, optimizer) as scaled_loss:scaled_loss.backward()
来看个比如,将上面三行依照正确的方位刺进到自己本来的代码中就能轻松完成酷炫的半精度练习啦!
import torchfrom apex import ampmodel = ... optimizer = ...#包装model和optimizermodel, optimizer = amp.initialize(model, optimizer, opt_level="O1")for data, label in data_iter: out = model(data) loss = criterion(out, label) optimizer.zero_grad() #loss scaling,替代loss.backward() with amp.scaled_loss(loss, optimizer) as scaled_loss:scaled_loss.backward() optimizer.step()
Tensorflow
一句话完成混合精度练习之修正环境变量,在python脚本中设置环境变量
os.environ[ TF_ENABLE_AUTO_MIXED_PRECISION ] = 1
除此之外,也能够用相似pytorch的方法来包装optimizer。
Graph-based示例
opt = tf.train.AdamOptimizer()#add a lineopt = tf.train.experimental.enable_mixed_precision_graph_rewrite( opt, loss_scale= dynamic ) train_op = opt.miminize(loss)
Keras-based示例
opt = tf.keras.optimizers.Adam()#add a lineopt = tf.train.experimental.enable_mixed_precision_graph_rewrite( opt, loss_scale= dynamic ) model.compile(loss=loss, optimizer=opt)model.fit(...)
PaddlePaddle
一句话完成混合精度练习之增加config(惊呆究竟混合精度练习是百度家提出的,内部早就娴熟应用了叭)
--use_fp16=true
举个栗子,根据BERT finetune XNLI使命时,只需在执行时设置use_fp16为true即可。
export FLAGS_sync_nccl_allreduce=0export FLAGS_eager_delete_tensor_gb=1export CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7BERT_base_PATH="chinese_L-12_H-768_A-12"TASK_NAME= XNLI DATA_PATH=/path/to/xnli/data/CKPT_PATH=/path/to/save/checkpoints/python -u run_classifier.py --task_name ${TASK_NAME} --use_fp16=true #!!!!!!add a line --use_cuda true --do_train true --do_val true --do_test true --batch_size 32 --in_tokens false --init_pretraining_params ${BERT_base_PATH}/params --data_dir ${DATA_PATH} --vocab_path ${BERT_base_PATH}/vocab.txt --checkpoints ${CKPT_PATH} --save_steps 1000 --weight_decay 0.01 --warmup_proportion 0.1 --validation_steps 100 --epoch 3 --max_seq_len 128 --bert_config_path ${BERT_base_PATH}/bert_config.json --learning_rate 5e-5 --skip_steps 10 --num_iteration_per_drop_scope 10 --verbose true
本文授权转载自大众号:夕小瑶的卖萌屋