使用Colossal-AI分布式训练BERT模型

2024-01-14 07:30

本文主要是介绍使用Colossal-AI分布式训练BERT模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

最近几周在研究分布式训练中的模型并行技术。为了直观感受和加深记忆,阅读相关论文的同时,动手用开源的大模型训练框架Colossal-AI逐步改写出了一个数据并行+模型并行的BERT来帮助理解。在这里想介绍一下借助Colossal-AI提供的零冗余优化器、张量并行、流水线并行等技术一点点缩小BERT模型内存占用的过程。

文章内容:
  1. 大规模模型对分布式训练带来了什么挑战?什么是Colossal-AI?

  2. 用Colossal-AI提供的分布式技术训练BERT模型

    • 数据并行
    • 零冗余优化器
    • 张量并行
    • 流水线并行
  3. 实验

  4. 总结

背景知识

大规模模型训练

NLP领域中新的预训练模型不断对各种语言任务的效果做出了突破。这些预训练模型依赖于深而宽的网络结构来“记忆”某些语言表征,往往把模型的Layer增多增宽(参数量也随之变多)能进一步提升模型表现,因此近年来NLP模型的模型参数也越来越多。比如BERT论文中提到的BERT-base有1亿参数和BERT-large有3亿参数;最近的GPT-3和PaLM的large更是高达1750亿参数和5400亿参数。 大规模模型为分布式训练带来了新的挑战:过去单卡就能放下的小规模模型仅用数据并行就能达到优秀的性能和可扩展性;而如今单个模型甚至算子的参数量就超过了单卡内存,需要用更复杂的并行技术来将参数分布到各个节点多张卡上,使分布式训练能支持更大规模的模型训练。

Colossal-AI

Colossal-AI是一个专注于大规模模型训练的深度学习系统,Colossal-AI基于PyTorch开发,旨在支持完整的高性能分布式训练生态。Colossal-AI已在GitHub上开源,且多次登顶GitHub
trending榜单,感兴趣的同学可以访问我们的GitHub主页(https://github.com/hpcaitech/ColossalAI)。在Colossal-AI中,我们支持了不同的分布式加速方式,包括张量并行、流水线并行、零冗余数据并行、异构计算等。

简单的来说,就像我们借助PyTorch、Tensorflow等训练框架提供的方法来写单机模型训练一样,Colossal-AI旨在帮助用户像写单机训练一样去写大规模模型的分布式训练,并提供了PyTorch-like的接口和使用方式,使用户尽量无痛迁移目前的单机模型。

分布式加速方式

关于上面提到的各种优化技术,Colossal-AI官方文档有原论文地址和详细的探讨,这里不赘述,想了解细节的朋友移步我们的文档Paradigms of Parallelism | Colossal-AI。

Colossal-AI:从数据并行的BERT模型到模型并行的BERT模型

下面我们用一个PyTorch开发的BERT模型由易到难逐步实验各种优化技术的效果。 原始模型我们直接采用huggingface-BERT的BERTForMaskedLM,该模型用Masked Language Model单任务预训练BERT。Colossal-AI使用v0.1.0。参考Colossal-AI官方的初始化和engine文档,我们定义配置文件config.py,并用colossalai.launch和colossalai.initialize接口启动一个engine来运行BERTForMaskedLM训练。
下面展示一些 内联代码片。

1  import colossalai
2 
3  colossalai.launch(config='./config.py', ...)
4
5  # define model, optimizer, dataloader, criterion just like using PyTorch
6  ...
7
8  engine, trainloader, testloader, _ = colossalai.initialize(
9          model=model,
10         optimizer=optimizer,
11         criterion=criterion,
12         train_dataloader=train_dataloader,
13         test_dataloader=test_dataloader,
14     )
15
16  for data, label in trainloader:
17      data, label = data.cuda(), label.cuda()
18      engine.zero_grad()
19      output = engine(data)
20      loss = engine.criterion(output, label)
21      engine.backward(loss)
22      engine.step()
数据并行

首先实验数据并行。数据并行对于模型代码是非侵入式的,只需要正常启动colossal-AI engine即可,Colossal-AI默认会自动配置数据并行。由于GPU的数量等于数据并行大小 x 张量并行大小(default=1) x 流水线并行大小(default=1),Colossal-AI会根据张量并行和流水线并行配置自动配置数据并行。不传入自己实现的梯度处理器时,默认会使用PyTorch自带的DistributedDataParallel来做数据并行。所以我们的训练不额外添加任何config,在启动并传入了GPU Number=8后,已经自动启动了8卡数据并行。

零冗余优化器

其次实验零冗余优化器ZeRO。ZeRO也不需要修改任何原生模型代码,只需要我们配置config和在colossalai.zero.init_ctx.ZeroInitContext的上下文内创建模型,Colossal-AI会自动检测ZeRO相关配置然后管理模型训练过程中需要减少冗余的参数。

第一步是修改config文件,增加如下ZeRO配置表明我们要启动ZeRO,参数解释见注释。ZeRO更全面的设置参见ZeRO文档。

1  from colossalai.zero.shard_utils import TensorShardStrategy
2
3  zero = dict(
4     model_config=dict( #模型参数
5         offload_config=dict(device="cpu"), #在不参与计算时将模型参数卸载到CPU上,进一步减少显存开销
6         shard_strategy=TensorShardStrategy() #指定使用的切片策略,这里我们使用Colossalai默认策略、将每个张量均匀地分片到所有rank上
7     ),
8     optimizer_config=dict( #优化器参数
9         cpu_offload=True, #将优化器状态从 GPU 卸载到 CPU,以节省 GPU 的内存使用
10        initial_scale=2**5, #自动混合精度训练的初始scale
11    )
12  )

第二步是在Colossalai ZeRO上下文内创建模型,让Colossalai能管理原生的PyTorch模型。

1  from colossalai.zero.init_ctx import ZeroInitContext
2
3  zero_ctx = ZeroInitContext(
4              target_device=torch.cuda.current_device(),
5               #gpc.config is all things defined in config.py as a dict
6               shard_strategy=gpc.config.zero.model_config.shard_strategy, 
7               shard_param=True,
8           )
9
10  ...
11
12  with zero_ctx:
13      model = build_model()
14   
15  ...
16  # colossalai.initialize(...)
17  # start your train


这样我们就能启动Colossalai的零冗余优化器来减少原生模型的显存使用,也是非常便捷。

张量并行

然后实验张量并行。张量并行比起前两个优化技术稍微复杂一些,需要在config中配置和改动模型代码来使用。
第一步仍然是修改config文件,增加如下设置表明我们希望在传入的8卡上启动一个数据并行大小为4(自动配置)、张量并行大小为2的1D张量并行。

1  parallel = dict(
2      tensor=dict(size=2, mode='1d')
3  )

第二步我们需要更改模型代码。

  1. 首先是将原生BertForMaskedLM中的torch.nn.Linear/LayerNorm/Embedding/Dropout以及损失函数torch.nn.CrossEntropyLoss替换成colossalai.nn.Linear/LayerNorm/Embedding/Dropout/CrossEntropyLoss。Colossalai提供的这些算子会根据当前配置的张量并行模式自动切分模型参数:如张量并行大小为2的1D模式下,一个Linear层6x8的weight张量会根据所在位置被切分为2个3x8或者6x4的张量,其输出结果张量也会相应的切分,并在forward和backward的过程中处理合并逻辑,从而完成自动张量并行。同样,只要在配置文件中修改合适的size和mode,方法会自动根据配置文件变更张量并行方式,非常方便。

  2. 因为Colossalai要求colossalai.nn算子定义的顺序和forward调用的顺序一致来保证多个算子间输入输出切分的维度匹配,我们需要严格将所有colossalai.nn算子定义顺序按照实际使用顺序排序。

  3. 对于注意力算子中的qkv Linear算子做特殊处理。目前默认状态下,Colossal 1D Linear算子会尝试将qkv三个连续定义的colossalai.nn.Linear算子划分成:q-按列切(col)|k-按行切(row)|v-col,预期三个Linear算子将会是q(k(v(input)))的计算路径,这样的计算路径下col-row-col的切分能保证运算形状正确。但这样不符合我们对qkv的实际使用期望。我们可以直接调用colossalai.nn.Linear1D_col手动指定1D按列切分来处理,这样可以在1D mode正确计算注意力。不过为了让模型代码能保持根据config适配1D、2D、2.5D和3D的能力,我们可以选择将qkv直接合并为一个size*3的colossalai.nn.Linear算子,然后在forward计算中再重新chunk成3份来表示qkv,避免k在1D下被误切分为row。

1  def __init__(self, ...):
2      ...
3      self.query_key_value = colossalai.nn.Linear(hidden_size, 
4                          num_attention_heads * attention_head_size * 3)
5      ...
6
7  def forward(self, ...):
8      ...
9      qkv = self.query_key_value(hidden_states)
10     q, k, v = torch.chunk(qkv, 3, dim=-1) 
11     ...
  1. 对于模型最后一层Head使用的Linear层,调用特殊算子colossalai.nn.Classifier替换。Classifier对于Bert的MLM任务输出会做vocab切分并行,也就是将num_class维度切分。得到的输出再交给同样对vocab做切分并行的colossalai.nn.CrossEntropyLoss计算loss。到这里,大部分使用Colossal做张量并行的工作已经完成,已经可以运行切分逻辑最简单的1D张量并行。

  2. 接下来我们对attention mask的维度做微调,来确保1D、2D、2.5D和3D张量并行时候注意力计算都能正确。对于多维(>1D)的张量并行,为了保证模型切分后计算的正确性,需要将attention mask先用colossalai.nn.partition_batch从batch维度切分,并从[partition_batch_size, seq_length]reshape[partition_batch_size, 1, 1, seq_length],这样计算注意力时可以广播成[partition_batch_size, num_heads, from_seq_length, to_seq_length],以便于多维张量并行计算。最后的转化dtype是因为我们这里的初始化赋值有可能改变attention mask的dtype,需要转化为原本的dtype。

1  extended_attention_mask = attention_mask.view(batch_size, -1)
2  extended_attention_mask = col_nn.partition_batch(extended_attention_mask)
3  extended_attention_mask = extended_attention_mask.unsqueeze(1).unsqueeze(2)
4  extended_attention_mask = (1.0 - extended_attention_mask) * -10000.0
5  extended_attention_mask = extended_attention_mask.to(dtype=embedding_output.dtype)

这样我们就改写了一个1D、2D、2.5D和3D支持张量并行的Colossal Bert模型,并可以通过config文件灵活更改张量并行大小和方式。通过张量并行,我们能将算子和模型分布到多张GPU上,减少显存开销。

流水线并行

最后实验流水线并行。流水线并行需要配置config、修改模型、使用Colossalai封装的高级API trainer代替engine训练。新版本Colossalai流水线并行的接口做了简化,请参考Pipeline Parallel | Colossal-AI。 配置config,启动一个2阶段的流水线并行:

1  parallel = dict(
2      pipeline=2,
3  )

流水线并行对原生模型的主要修改是要切分每个流水线阶段应该执行的逻辑。这里的BertForMaskedLM修改可以通过让Embedding只被first执行,输出token分类结果只被last执行,然后将中间的Encoder Layers切分给各流水线阶段完成:

1  class PipelineBertForMaskedLM(nn.Module):
2      def __init__(..., first, last):
3          ...
4          self.first = first
5          self.last = last
6        
7          if self.first:
8              ...
9              # The logic will be executed only in the first stage
10
11         ...
12         # The logic will be executed in every pipeline stage
13
14         if self.last:
15             ...
16             # The logic will be executed only in the last stage
17         ...
18
19    def forward(
20        ...
21    ):
22        ...
23        if self.first:
24            ...
25            # The logic will be executed only in the first stage
26
27        ...
28        # The logic will be executed in every pipeline stage
29
30        if self.last:
31            ...
32            # The logic will be executed only in the last stage
33
34         ...

使用trainer替代engine来启动Colossalai训练。trainer是Colossalai提供的高级API,可以简化训练过程,并且为流水线并行的自动调度提供支持:

1  from colossalai.logging import get_dist_logger
2  from colossalai.trainer import Trainer, hooks
3
4  # build components and initialize with colossalai.initialize
5  ...
6
7  # create a logger so that trainer can log on the console
8  logger = get_dist_logger()
9
10  # create a trainer object
11  trainer = Trainer(
12     engine=engine,
13     logger=logger
14  )
15
16  # define the hooks to attach to the trainer
17  hook_list = [
18      hooks.LossHook(),
19      hooks.LRSchedulerHook(lr_scheduler=lr_scheduler, by_epoch=True),
20      hooks.AccuracyHook(accuracy_func=Accuracy()),
21      hooks.LogMetricByEpochHook(logger),
22  ]
23
24  # start training
25  trainer.fit(
26      train_dataloader=train_dataloader,
27      epochs=NUM_EPOCHS,
28      test_dataloader=test_dataloader,
29      test_interval=1,
30      hooks=hook_list,
31      display_progress=True
32  )

实验

实验环境为搭载8张GPU的小型服务器,每张显卡显存为16GB。 因为Colossal-AI可以通过配置文件灵活修改并行方式,我们可以通过构建不同的config来测试显存占用。config的取值如下:

1  数据并行大小DP size取值{1, 2, 4, 8}
2  张量并行大小TP mode和size取值{1, 1d: {2, 4, 8}, 2d: {4, 8}, 2.5d|depth=2: {8}, 3d: {8}}
3  流水线并行大小PP size取值{1, 2, 4, 8}
4  DP size * TP size * PP size = 8
5  零冗余优化器根据不使用,使用切片且卸载到CPU上,取值{F, T}

测试BERT-large在不同Colossal-AI并行配置下的单张GPU内存占用峰值:
在这里插入图片描述实验结果表明通过使用Colossal-AI提供的各类并行技术,能有效控制模型训练中的GPU内存使用,从而支持更大规模的规模的模型训练。

总结

  1. 大规模模型训练对分布式训练框架提出了更高的要求。
  2. Colossal-AI基于PyTorch提供了强大的数据并行、零冗余优化器、张量并行、流水线并行等训练技术,帮助用户尽可能简单地从单机训练模型迁移至分布式的训练模型。
  3. Colossal-AI能通过配置文件灵活地配置不同的混合并行策略,有效支持更大规模的模型训练。

项目团队

潞晨技术团队的核心成员均来自美国加州大学伯克利分校,斯坦福大学,清华大学,北京大学,新加坡国立大学,新加坡南洋理工大学等国内外知名高校;拥有Google Brain、IBM、Intel、 Microsoft、NVIDIA等知名厂商工作经历。公司成立即获得创新工场、真格基金等多家顶尖VC机构种子轮投资。

目前,潞晨科技还在广纳英才,招聘全职/实习AI分布式系统、架构、编译器、网络、CUDA、SaaS、k8s等核心系统研发人员,开源社区运营、销售人员。

潞晨科技提供有竞争力的薪资回报,特别优秀的,还可以申请远程工作。也欢迎各位向潞晨科技引荐优秀人才,如果您推荐优秀人才成功签约潞晨科技,我们将为您提供数千元至数万元的推荐费。

工作地点:中国北京,新加坡,美国。(可相互转岗)
简历投递邮箱:hr@luchentech.com

传送门

BERT项目地址:
https://github.com/hpcaitech/ColossalAI-Examples

Colossal-AI项目地址:
https://github.com/hpcaitech/ColossalAI

Colossal-AI文档地址:
https://www.colossalai.org/

这篇关于使用Colossal-AI分布式训练BERT模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/604381

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

AI绘图怎么变现?想做点副业的小白必看!

在科技飞速发展的今天,AI绘图作为一种新兴技术,不仅改变了艺术创作的方式,也为创作者提供了多种变现途径。本文将详细探讨几种常见的AI绘图变现方式,帮助创作者更好地利用这一技术实现经济收益。 更多实操教程和AI绘画工具,可以扫描下方,免费获取 定制服务:个性化的创意商机 个性化定制 AI绘图技术能够根据用户需求生成个性化的头像、壁纸、插画等作品。例如,姓氏头像在电商平台上非常受欢迎,

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传