大模型训练技巧|单卡&多卡|训练性能评测

原视频:【单卡、多卡 BERT、GPT2 训练性能【100亿模型计划】】
此笔记主要参考了李沐老师的视频,感兴趣的同学也可以去看视频~
视频较长,这里放上笔记,与大家分享~

大模型对于计算资源的要求越来越高,如何在有限的资源下开展训练?

对于公司尤其是个人开发者来说,是一个非常有价值的问题。

本文将主要介绍大模型训练技巧,在单卡和多卡上的不同策略,以及对于性能的评测。

1.GPU训练性能的测试脚本

在这里插入图片描述

2.设置

在这里插入图片描述
画红框的部分,会影响GPU的性能。

16位是半精度,32位是单精度,64位是双精度。bf16和fp16是精度。

optim是优化器。(adamw其实是一个多此一举的优化器。直接使用adam优化器就行。)

grad_accum表示是否要做梯度的累加。

steps表示要跑多少次的模型更新。

deepspeed是一种跑分布式的方式。

在这里插入图片描述
计算量:TFLOPS
在这里插入图片描述
huggingface是一个模型库

在这里插入图片描述
log文件
在这里插入图片描述
读取和解析log文件

核心是读取两个参数:gpu显存的峰值,和每秒读取的样本数
在这里插入图片描述

3.单卡性能

内存消耗(这里指GPU的内存,即显存)

1.模型的参数(大模型参数量大,占用空间大)

2.每一层的输出,即前向运算的中间计算结果,也叫activation

3.用的库,背后所占的内存。比如通信、cudnn

一般来说,占大头的是前两个。
在这里插入图片描述
注意:使用16位计算,并不能节省模型占用的空间。因为模型还是用32位来存的,模型的权重还是会转化为32位,进行更新。

但是如果使用16位运算,前向计算的中间结果(即activation)是16位的,这样就节省了空间。而且activation的大小和batchsize、序列长度、浮点运算量呈正比,所以如果使用16位运算,可以提高batchsize或者序列长度。

优先使用bf16,其次是fp16。

实验现象

fp32换为了fp16,性能并没有翻倍,说明还有别的地方在使用内存。
可能是内存带宽,造成了GPU性能的瓶颈。

性能优化

1.kernal fusion操作:

麻烦的python操作,用c++的for loop重写一遍。

目的:减少中间变量的读写过程,同时减少调用python运算产生的额外开销。
在这里插入图片描述
一般不需要自己重写,直接调用apex库就可以。

2.grad_accum

每次处理完一个batch,不直接更新梯度。而是计算多个batch,将梯度进行累加,再做梯度更新。
在这里插入图片描述
如果batchsize=10,grad_accum=4,那么会在总的10*4=40个batch后,才会进行梯度更新。

但是grad_accum或者总的批量大小不能太大,批量大小太大会影响算法的收敛。

做微调的时候,批量大小不能太大,因为数据集本来就不大;如果做预训练,批量大小可以大一些,因为数据集本身就很大。

3.丢弃中间结果

前向运算的时候,每一层的中间结果都会被保存。

可以将中间的一些结果丢弃,节省内存消耗。等运算完最后输出,进行梯度反传的时候,再重新进行前向计算,重新得到中间结果。

增加一部分计算量,换取一部分内存空间,至少能让模型跑起来。

当模型真的非常大的时候,这一操作特别有用!可以用来增加批量大小。

在这里插入图片描述

Megatron模型库

在这里插入图片描述
在这里插入图片描述
Megatron模型库性能好,是因为自己手写了很多算子:
在这里插入图片描述

优化总结

1.尽量增加批量大小(提高训练效率)

2.尽量使用16位的浮点数(降低中间结果占用内存数目)

3.使用Megatron这样的模型库(对重点算子,进行了手写,优化性能)

4.多卡性能

在这里插入图片描述
NV4表示两张卡使用四条nv-link进行两张GPU的连接。
在这里插入图片描述
使用一个脚本进行gpu之间的带宽的测试。
在这里插入图片描述
由于除了前向计算和反向计算,通信和模型更新还占用了新能。

所以一张GPU变为两张GPU,性能并没有翻倍。(只有一张GPU,并不需要GPU间的通信)

数据并行

在这里插入图片描述
没有使用nv-link,导致通信减慢,耗时明显增加。

nv-link可以增加带块,每次通信可以多传输信息,减少每一轮的通信次数。
在这里插入图片描述
数据并行的时候,每次梯度更新,GPU间都要进行通信。

所以使用梯度累加(grad-accum),减少梯度更新次数,从而减少通信次数,可以提高性能。

张量并行

如果有2张GPU,则将每一层的张量计算,拆为两部分。每个GPU计算完一部分张量后,再进行通信的交互。

好处是每张GPU的计算量减少了,坏处是需要计算和通信必须是串行的。
在这里插入图片描述
这里无法计算通信事件,因为通信时间都在前向计算和反向计算里了。
在这里插入图片描述
TP表示张量并行。TP的时候,梯度累加效果很小。因为通信次数已经很多了,就算减少梯度更新的次数,也没用。
在这里插入图片描述
张量并行的好处是,可以训练大模型(比如1.3B的参数量)。将每一层的运算在多个卡上计算。否则,批量大小为1也跑不起来。

由于参数量太大,所以梯度更新、进行优化的时间占比就比较大。所以使用梯度累加,还是有一些效果的。

ZeRO并行

在这里插入图片描述
使用ZeRO2,是将整个模型和adam里的状态,将梯度进行切分,每个GPU只需要维护一部分。

这样可以显著降低模型相关的内存占用,可以训练更大的模型。

5.结论

训练大模型的方法

1.使用足够大的批量大小。

一方面可以使得单个的算子的性能上升。另一方面可以降低模型梯度更新和通信带来的额外开销。

处理方法:1.GPU内存更大。2.使用16位运算。3.kernal fusion合并运算。4.梯度累加。5.梯度的ckpt记录中间结果。

但是特别大批量大小,会使得算法收敛变慢,需要更多的迭代才能使得算法收敛。

微调的时候,数据规模小,就不能使用太大的批量大小。预训练的时候,可以使用更大的批量大小。

当GPU数目特别大(成百上千)的时候,每张卡分配到的批量大小也会缩小,这个也需要改变。

2.并行运算

优先在单卡内部做数据并行。因为通信消耗少。

多卡并行。

ZeRO并行。划分模型和中间状态。

张量并行。将每一层的计算切开。

3.设备性能

nvi-link优化通信。

更大内存的GPU。

以上是针对大模型的一些训练技巧,相信可以给大家日常的训练带来一些有价值的建议~

欢迎大家关注我~分享有用的AI算法笔记~

在PyTorch中,我们可以使用DataParallel模块来实现在单卡导入训练模型。DataParallel可以将一个单卡模型并行复制到个GPU上,并且在每个上独立地进行前向传播和梯度计算,最后再将梯度进行平均并更新单卡模型。 为了使用DataParallel,首先需要导入所需的库和模块: ```python import torch import torch.nn as nn from torch.utils.data import DataLoader ``` 然后,定义一个继承自nn.Module的模型,例如: ```python class MyModel(nn.Module): def __init__(self): super(MyModel, self).__init__() self.fc = nn.Linear(10, 2) def forward(self, x): return self.fc(x) ``` 接下来,创建一个DataLoader来加载训练数据: ```python dataset = ... dataloader = DataLoader(dataset, batch_size=128, shuffle=True) ``` 然后,创建一个模型实例并将其放在指定的GPU上: ```python device = torch.device("cuda:0") model = MyModel().to(device) ``` 接下来,使用DataParallel将模型复制到所有可用的GPU上: ```python model = nn.DataParallel(model) ``` 这样,模型就能够在个GPU上并行运行了。在训练过程中,可以像使用单卡训练模型一样进行训练操作: ```python optimizer = torch.optim.Adam(model.parameters(), lr=0.001) criterion = nn.CrossEntropyLoss() for epoch in range(num_epochs): for images, labels in dataloader: images = images.to(device) labels = labels.to(device) outputs = model(images) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() ``` 需要注意的是,DataParallel模块会自动将模型进行复制,以及将输入数据划分到不同的GPU上进行运算,因此在定义模型时无需指定运算。在进行推理或测试时,可以使用.module属性获取到原始的单卡模型,并将其放在对应的设备(GPU或CPU)上运行。 以上就是使用PyTorch实现单卡导入训练模型的简要介绍。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来一块葱花饼

谢谢好兄弟的支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值