没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
显存不够,如何训练⼤型神经⽹络?
3⽉3⽇
以下⽂章来源于NLPCAB ,作者李如
⼣⼩瑶的卖萌屋
NLPCAB
⼀些⾃然语⾔处理的学习经验和Paper解读
⼀只⼩狐狸带你解锁 炼丹术&NLP 秘籍
前阵⼦微软开源了DeepSpeed训练框架,从测试效果来看有10倍的速度提升,⽽且对内存进⾏了各种优化,最⼤可以训练
100B(illion)参数的模型。同时发布了这个框架训练出的17B模型 Turing-NLG,处于⽬前壕赛事的顶端。
训100B的模型就先别想了(狗头),先把110M的BERT-base训好上线吧。本⽂主要介绍模型训练中速度和内存的
优化策略,针对以下⼏种情况:
1. 我明天就要答辩了,今天必须把这⼗个实验跑完
2. 我的模型有些⼤,好不容易放到⼀张卡上,训完⼀亿样本之前我就可以领N+1了
3. 我想出了⼀个绝妙的T6模型,却加载不进12GB的卡⾥,⼜拿不到今年的best paper了
(以上纯属虚构,如有雷同请赶紧看下⽂)
现实总是残酷的,其实限制⼤模型训练只有两个因素:时间和空间(=GPU=钱),根据不同情况可以使⽤的⽅案⼤致
如下:
1. 梯度累加 Gradient Accumulation
如果只有单卡,且可以加载模型,但batch受限的话可以使⽤梯度累加,进⾏N次前向后反向更新⼀次参数,相当于
扩⼤了N倍的batch size。
正常的训练代码是这样的:
for i, (inputs, labels) in enumerate(training_set):
loss = model(inputs, labels) # 计算loss
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向计算梯
度
optimizer.step() # 更新参数
加⼊梯度累加后:
for i, (inputs, labels) in enumerate(training_set):
loss = model(inputs, labels) # 计算loss
loss = loss / accumulation_steps # Normalize our loss (if average
d)
loss.backward() # 反向计算梯度,累加到之前梯度上
if (i+1) % accumulation_steps == 0:
optimizer.step() # 更新参数
model.zero_grad() # 清空梯度
要注意的是,batch扩⼤后,如果想保持样本权重相等,学习率也要线性扩⼤或者适当调整。另外batchnorm也会受
到影响,⼩batch下的均值和⽅差肯定不如⼤batch的精准,可以调整BN中的momentum参数解决[2]。
2. 梯度检查点 Gradient Checkpointing
如果只有⼀张卡,⼜想训⼤模型,可以尝试压缩模型所占显存。
梯度检查点是⼀种以时间换空间的⽅法,通过减少保存的激活值压缩模型占⽤空间,但是在计算梯度时必须从新计
算没有存储的激活值。
细节可以参考陈天奇的Training Deep Nets with Sublinear Memory Cost[3]。
注:第⼀⾏节点是前向,第⼆⾏是反向
3. 混合精度训练 Mixed Precision Training
混合精度训练在单卡和多卡情况下都可以使⽤,通过cuda计算中的half2类型提升运算效率。⼀个half2类型中会存储
两个FP16的浮点数,在进⾏基本运算时可以同时进⾏,因此FP16的期望速度是FP32的两倍。举个Gelu的FP16优化
栗⼦:
//FP32
的
gelu
运算
float gelu(float x)
{
float cdf = 0.5f * (1.0f + tanhf((0.7978845608028654f * (x + 0.044715f * x * x * x))));
return x * cdf;
}
//FP16
的
gelu
运算
half2 gelu(half2 val)
{
half2 val_pow3 = __hmul2(val, __hmul2(val, val)); //
同时计算两个
x*x*x
float2 tmp_pow = __half22float2(val_pow3);
float2 cdf = __half22float2(val);
//
由于
tanhf
不⽀持
half2
类型,只能分开算
cdf.x = 0.5f * (1.0f + tanhf((0.7978845608028654f * (cdf.x + 0.044715f * tmp_pow.x))))
;
cdf.y = 0.5f * (1.0f + tanhf((0.7978845608028654f * (cdf.y + 0.044715f * tmp_pow.y))))
;
//
同时计算两个
x * cdf;return __hmul2(val, __float22half2_rn(cdf));
}
混合精度训练[5]不是很难理解,但要注意以下⼏点:
1. 混合精度训练不是单纯地把FP32转成FP16去计算就可以了,只⽤FP16会造成80%的精度损失
2. Loss scaling:由于梯度值都很⼩,⽤FP16会下溢,因此先⽤FP32存储loss并放⼤,使得梯度也得到放⼤,可以⽤FP16存储,更新时
变成FP32再缩放
3. 在涉及到累加操作时,⽐如BatchNorm、Softmax,FP16会上溢,需要⽤FP32保存,⼀般使⽤GPU中TensorCore的
FP16*FP16+FP32=FP32运算
整体流程:FP32权重 -> FP16权重 -> FP16计算前向 -> FP32的loss,扩⼤ -> 转为FP16 -> FP16反向计算梯度 ->
缩放为FP32的梯度更新权重
剩余11页未读,继续阅读
资源评论
地理探险家
- 粉丝: 1043
- 资源: 5416
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功