训练大型神经网络方法总结

一只小狐狸带你解锁 炼丹术&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)              # 计算lossoptimizer.zero_grad()								      # 清空梯度loss.backward()                           # 反向计算梯度optimizer.step()                          # 更新参数

加入梯度累加后:

for i, (inputs, labels) in enumerate(training_set):loss = model(inputs, labels)                    # 计算lossloss = loss / accumulation_steps                # Normalize our loss (if averaged)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*xfloat2 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的梯度更新权重

!!手工分割线:接下来就是壕赛道了!!

4. 分布式训练 Distributed Training

分布式训练就是多张卡并行训练,一般有以下两种情况:

  • Multi-GPU:单机多卡,通过PCIE、NVlink、GPU Direct P2P来通信

  • Multi-Node:多机多卡,通过Sockets (Ethernet) 或者InfiniBand with GPU Direct RDMA通信

实践中可以使用英伟达的NCCL通信框架,多机通过IB(InfiniBand)可以接近机内的通信速度[6]。底层的东西就不多说了(我也不太懂),实际上对于炼丹师来说就是找运维爸爸提供帮助,并借助开源框架配置上服务器地址就行了。

并行训练有多种优化策略,主要目的就是减少计算中的参数同步(Sync)和数据传输。

目前32GB的卡最多能放1.3B参数的模型,塞得下的话可以使用数据并行的方式,否则可以把不同层放在不同机器上进行训练。两种方式的区别看下图[7]就明白啦:

4.1 数据并行 Data Parallelism

数据并行有两种方式[9]:

Parameter Server

集群中有一个master和多个worker,master需要等待所有节点计算完毕统一计算梯度,在master上更新参数,之后把新的参数广播给worker。这种方式的主要瓶颈在master,因此也可以异步训练,即不等待其他节点,收到一个worker的梯度后就更新参数,但这样其他worker在旧参数上算完后的梯度会作用到新参数上,导致模型优化过头,陷入次优解。

Ring All-Reduce

集群中所有worker形成一个闭环,把数据分成K份,计算完一份就把累加好的梯度传给下家,同时接受上家的梯度,迭代到最后所有worker的梯度都是相等的,可以同步更新参数,比PS架构要高效,是目前的主流方式。下图[10]展示了Scatter Reduce和All Gather两个阶段:

preview

4.2 模型并行 Model Parallelism

模型并行目前并不常见,一是因为大部分模型单卡都放得下,二是因为通讯开销比数据并行多,因为反向传播需要把loss对每层激活值的梯度都传回去,样本数量大的话激活值也有很多。

Pipelined Parallelism

Pipeline的并行方式就是把模型的不同层放到不同机器上,顺序地进行前向和反向计算。19年谷歌和微软先后放出了GPipe[11]和PipeDream[12]的论文和源码,给大家梳理一下他们的心路历程:

首先来看最naive的模型并行方式,实在是有些浪费生命:

注:反向需要计算对参数和激活值的偏导,所以耗时更长。

所以谷歌GPipe提出了一个改进,其实就是把数据分片,像allreduce一样计算完一些就传给下个节点,最后同步更新参数,但这样看还是不能挽救我们的青春:

于是微软提出了PipeDream,其实就是把同步变为了小数据上的异步,计算完一个数据分片就立刻反向,反向完了就更新梯度,谁也别等谁,大家一起疯狂干起来:

但这样就有一个问题,就是大家越干越乱,比如worker1在计算5的前向时用的是1反向后的参数,但之后计算5反向的梯度时参数早就被2/3/4更新了。于是作者加入了Weight stashing机制,把每个数据对应的参数都存起来!这样worker1在5反向的时候就可以从百宝箱里拿出之前的参数,进行更新:

那问题又来了:worker1上5的前向是用1的参数,但worker3上是用3的,最后汇总的时候不就又乱了?于是作者又加入了Vertical Sync机制,强制所有worker在计算5的时候都用1的参数。这样在最后汇总模型的时候,就能拿到一致的参数了。但这样同步会导致很多计算作废,比如5更新时用的1的权重,但2/3/4的权重都白计算了,所以默认是不用Vertical Sync的,这样每层虽然不完全一致,但由于weight stashing,所有的参数都是有效的。

Tensor Slicing

神经网络可以看作一个复合函数,本质就是各个tensor之间的计算,我们定义好的CNN、RNN其实就是计算函数的集合。从这个角度来思考,模型并行其实就是把各个tensor计算分散到不同的机器上。这方面的研究有18年的FlexFLow和Mesh-TensorFlow,英伟达的威震天[13]也是使用这个策略。下面以Transformer为例说明一下如何拆分。

Transformer主要有self-attention和FFN组成,对于FFN中的第一层Y=GLUE(XA)可以有两种拆分方式:

可以看到,第一种需要在计算GLUE时同步,因此威震天通过第二种方式进行tensor切片,self-attention也采用类似的策略,这样只需要在前向时通过g聚合,反向时通过f聚合就可以了:

剩下的Layernorm和dropout还是需要同步后计算:

同时,作者也在vocab的维度对embedding进行了切分,并把最后的MLM预测和cross-entropy融合到一起,减少网络通信量(否则需要传输batch_size*seq_len *vocab_size个prob,改过后只传batch_size *seq_len个loss值)。

随着模型越来越大,分布式训练甚至推理肯定是一个趋势,在工程上还有很多可以优化的点,不仅是上面介绍的分布式策略,还有网络通信优化、内存优化等。

5. 加速优化器 LAMB

上文提到的数据并行虽然可以接近线性地提升训练速度,但过大的Batch会降低模型精度和收敛速度(对数据的拟合变差)。因此谷歌在19年推出了LAMB[14]优化器,全称为Layer-wise Adaptive Moments optimizer for Batch training,针对大batch做了优化,在分布式训练的场景下可训65536/32768的样本,减少迭代次数,从而缩短训练时间,感受一下金钱的味道:

LAMB主要是综合了Adam和LARS(Layerwise Adaptive Rate Scaling),对学习率进行调整。上文提到当batch变大时学习率也需要变大,这样会导致收敛不稳定,LARS通过给LR乘上权重与梯度的norm比值来解决这个问题[15]:

这里的norm都是取一层的权重计算,所以是layerwise。可以这样理解上面的公式:刚开始训练时,权重比较小,而loss和梯度比较大,所以学习率开始较小,但随着权重变大&梯度变小会慢慢warmup。当对一些样本拟合很好,loss接近0时,梯度变小,学习率又会增大,跳出局部最优,防止过拟合。

LAMB融合了这种layerwise的自适应思想:

图中的公式稍稍有改动,一个是给权重norm加了映射,本质都是起scale的作用;另一个是梯度公式中加了weight decay,也就是目标函数中的L2正则化。

总结

本文介绍了从速度和内存去优化模型训练的几种方式,实践中各种都是可以混合起来的,比如混合精度+数据并行、数据并行+模型并行、数据并行+梯度检查点等。DeepSpeed里基本涵盖了本文所讲的策略,用pytorch的同学可以安排起来了~

最后,在介绍各种策略的时候,由于篇幅原因也有省略一些假设和最终效果,感兴趣的同学们可以深入研读参考资料里的内容~如果路过的大佬们发现哪里有错误烦请指出~

  • 如何让BERT拥有视觉感知能力?两种方式将视频信息注入BERT

  • 模型训练太慢?显存不够用?这个算法让你的GPU老树开新花

  • 训练效率低?GPU利用率上不去?快来看看别人家的tricks吧~

  • 如何打造高质量的NLP数据集

  • 万万没想到,我的炼丹炉玩坏了

参考文献

[1] 微软Turing-NLG:https://www.microsoft.com/en-us/research/blog/turing-nlg-a-17-billion-parameter-language-model-by-microsoft/

[2] 梯度累加:https://www.zhihu.com/question/303070254/answer/573037166

[3] 陈天奇 Training Deep Nets with Sublinear Memory Cost: https://www.zhihu.com/question/274635237/answer/755102181

[4] 高开远 Reformer解读:https://zhuanlan.zhihu.com/p/104935987

[5] 混合精度训练:https://zhuanlan.zhihu.com/p/84219777

[6] 英伟达NCCL:https://www.zhihu.com/question/63219175/answer/206697974

[7] 数据并行与模型并行:https://www.zhihu.com/question/53851014/answer/158794752

[8] 分布式之数据并行:https://zhuanlan.zhihu.com/p/68615246

[9] AllReduce:https://zhuanlan.zhihu.com/p/100012827

[10] AllReduce细节:https://zhuanlan.zhihu.com/p/56991108

[11] GPipe:https://arxiv.org/pdf/1811.06965.pdf

[12] PipeDream:https://arxiv.org/pdf/1806.03377.pdf

[13] Megatron-LM:https://arxiv.org/abs/1909.08053

[14] LAMB:https://arxiv.org/abs/1904.00962v3

[15] LAMB解读:https://towardsdatascience.com/an-intuitive-understanding-of-the-lamb-optimizer-46f8c0ae4866

夕小瑶的卖萌屋

_

关注&星标小夕,带你解锁炼丹秘籍

订阅号主页下方「撩一下」有惊喜哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/480812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从Java程序员进阶架构师,必看的书单推荐!

算法与数据结构: 数据结构(严蔚敏) java数据结构和算法(美:拉佛) 算法导论 大话数据结构 剑指Offer 程序员面试金典 编程珠玑 编程之美 程序员笔试面试最优解 数据结构与算法经典问题解析&#xf…

论文浅尝 | 基于Freebase的问答研究

本文转载自公众号:PaperWeekly。 本期的论文笔记来自 PaperWeekly 社区用户 britin。本文给出了一种 end-to-end 的系统来自动将 NL 问题转换成 SPARQL 查询语言。作者综合了实体识别以及距离监督和 learning-to-rank 技术,使得 QA 系统的精度提高了不少…

机器学习中的特征建模(特征工程)和算法选型建模 - 以暴力破解识别为例

catalogue 1. 特征工程是什么?有什么作用? 2. 特征获取方案 - 如何获取这些特征? 3. 特征观察 - 运用各种统计工具、图标等工具帮助我们从直观和精确层面认识特征中的概率分布 4. 特征处理 - 特征清洗 5. 特征护理 - 特征预处理 6. 特征处理 …

NLP数据增强方法总结:EDA、BT、MixMatch、UDA

本文转载自公众号“夕小瑶的卖萌屋”,专业带逛互联网算法圈的神操作 -----》我是传送门 关注后,回复以下口令: 回复【789】 :领取深度学习全栈手册(含NLP、CV海量综述、必刷论文解读) 回复【入群】&#xf…

史上最全java架构师技能图谱(上)

java架构师最全技能图谱上篇,包含:数结构算法、java进阶、web开发、框架与工具四大技能图谱。 下篇将包含大数据以及性能、设计模式、UML、中间件、分布式集群、负载均衡、通讯协议、架构设计等技术图谱等章节 本文作者,陈睿 优知学院创始人…

王仲远 | 基于概念知识图谱的短文本理解

本文转载自公众号:大数据创新学习中心。3月10日,美团点评AI Lab NLP负责人王仲远博士,给大家进行了题为“基于概念化的短文本理解(Conceptualization for Short Text Understanding)”的报告。王博士的这次报告主要分为…

出行大数据,滴滴发布400城数据可视化分析

转 一:出行大数据,滴滴发布400城数据可视化分析 2018年01月04日 00:00:00 https://blog.csdn.net/zw0Pi8G5C1x/article/details/78976493 二:滴滴背后的大数据应用 前言:这是一篇大数据应用文章,不涉及高深技术&#…

拒绝跟风,谈谈几种算法岗的区别和体验

这是一份小夕写给【准】算法工程师的手册和建议, 大概是因为马上要开始秋招提前批了,小夕在知乎和微信后台收到了不少小伙伴的岗位/团队选择的求助。于是小夕这里写一篇扫盲贴,给即将毕业的师弟师妹们提供一个参考(后面再有师弟师…

阿里P8架构师谈:分布式、集群、负载均衡、分布式数据一致性的区别与关联

服务器集群: 1.集群概念 集群就是一组相互独立的计算机,通过高速的网络组成一个计算机系统。服务器集群就是指将很多服务器集中起来一起进行同一种服务,在客户端看来就像是只有一个服务器。 2.集群的特点和优势 1)高性能 比如…

论文浅尝 | Know-Evolve: Deep Temporal Reasoning for Dynamic KG

论文链接:https://arxiv.org/abs/1705.05742对于事件数据,需要动态更新的知识图谱来保存知识图谱中关系的时许信息。本文提出了 Know-Evolve 这种基于神经网络的动态知识图谱来学习实体在不同时刻的表示。在动态知识图谱中,事件由四元组表示&…

阿里P8架构师谈:Docker容器的原理、特征、基本架构、与应用场景

什么是容器? 一句话概括容器:容器就是将软件打包成标准化单元,以用于开发、交付和部署。 容器镜像是轻量的、可执行的独立软件包 ,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。 容器化软…

中国电网招聘 计算机岗位

1.解密2018国家电网校园招聘,院校、专业、待遇盲区统统扫除! 2018国家电网校园招聘国家电网作为国内乃至世界知名的企业集团,是令无数求职者心仪的工作单位。那么如何才能进国家电网工作呢?国家电网的待遇究竟有传说中的那么好吗&…

系统设计:github上学习如何设计大型系统的项目

https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md 系统设计是一个很宽泛的话题。在互联网上,关于系统设计原则的资源也是多如牛毛。这个仓库就是这些资源的组织收集,它可以帮助你学习如何构建可扩展的系统。

高并发编程系列:NIO、BIO、AIO的区别,及NIO的应用和框架选型

谈到并发编程就不得不提到NIO,以及相关的Java NIO框架Netty等,并且在很多面试中也经常提到NIO和AIO、同步和异步、阻塞和非阻塞等的区别。我先简短介绍下几个NIO相关的概念,然后再谈NIO重点掌握内容,以及Java NIO框架选型。 高并…

论文浅尝 | 基于神经网络的推理(DeepMind Relational Reasoning)

本文转载自公众号:徐阿衡。论文:A simple neural network module for relational reasoning(2017)github代码: https://github.com/siddk/relation-network这篇回顾下 DeepMind 2017 年发表的关系推理方面的工作,Relational Networks(RNs)。关…

拒绝无脑试错:写给萌新的“科学炼丹”入门手册

近期在订阅号后台和文章评论区review了一下大家的问题,发现很多小伙伴现在已经把机器学习、深度学习的理论基础打好了,但是真正要解决一个现实中的算法问题的时候经常两手抓瞎,一顿毫无目的乱试,甚至认为模型表现不好一定是调参不…

箱线图和散点图叠加图形的绘制——R language

前几日偶然从科学网上看到了一副特别漂亮的统计图形,如下图(摘自博文:http://blog.sciencenet.cn/blog-397960-456174.html)所示:感觉美翻了都,刚好在学习R,又遇到课题组有一些数据要处理,就花了大约一天的…

企业战略咨询方法:学习SWOT分析

文章目录概述分析目标分析内容分析步骤几个例子1. Mbalib网站的SWOT2. 复杂的、全面的SWOT分析3. 一个SWOT矩阵4. 另一个SWOT矩阵5. POWER SWOT分析法概述 SWOT分析是企业战略咨询常用的方法。然而,仔细搜索比对网上资料和各类管理咨询书籍,分析的目标、…