Accelerator 入门实践

转载自:Huggingface Accelerator踩坑指南 | 广哥拉斯的树洞

因为是个人网页,怕今后什么时候丢了,所以特意复制。

前言

最近因为做实验的数据集较大(百万条中文语句对),传统的单机单卡的速度实在不可恭维,所以笔者转向尝试单机多卡训练。最开始使用的是torch自带的torch.distributed包,引入了很多配置相关的代码,导致原来的代码结构混乱,再加上本身分布式并行计算就难以调试,笔者不得不花费大量时间一点点纠错才跑起来(一把辛酸泪)

然后机缘巧合下看到了hugginface开发的accelerate。在阅读完其简介和例子后,心中不经暗想:这也太方便了,事出反常必有妖!不过笔者还是决定付诸实践,看看这库是否如其宣传的那般好用。

目前的体验感想,仅一家之言

  • 和torch一样,分布式环境难以调试,但比torch容易
  • 网上的教程和huggingface自带的论坛里的提问很少有回答(活跃度太低,遇到bug可能得自己解决…)
  • 非常多的配置选项,虽然“好像”能提升训练效率但是笔者(一枚菜鸟)看不懂啊
  • 代码改动少很多,且模型训练和推理过程几乎和单卡一致
  • accelerate支持单卡和多卡,几乎可以无缝切换
  • 无需指定模型和数据分配的设备,accelerate会自动将两者分配到正确的设备!(可以极大提高显存使用效率)
  • 解决了日志打印混乱的问题,accelerate自带的logger默认只在主进程打印日志,所以就不会再被眼花缭乱、上蹿下跳的不知道哪路进程打印的log迷惑了双眼
  • more than what I mentioned aboved…

总结:值得一试

下面主要讲讲accelerate的简单使用和踩坑记录,代码和介绍主要参考Accelerate (huggingface.co)

入门实践

添加accelerator

首先导入和创建一个Accelerator实例,后面的所有几乎操作都离不开它

 
 
from accelerate import Accelerator
accelerator = Accelerator()

设置device

如果你要用到device的话需要如下配置,accelerator会将pytorch object放入正确的device

 
device = accelerator.device
# 笔者实践中,发现只需要将模型显示放入device,其他代码再见不到.to(xxx)和.cuda()了
model.to(device)

调用prepare()处理对象

prepare()为传递的所有对象做好用于进行分布式训练和混合精度(能加速训练)的准备,返回相同顺序的对象

  • 只接受继承自torch.nn.Module的对象
  • inference阶段无需使用
  • 返回的对象可以正常使用,而torch.distributed则需要model.module才能访问到真正的model
 
model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)

替换backward()

使用accelerator.backward()函数进行反向传播,后续很多针对梯度和误差的操作都依赖此接口

loss.backward() -> accelerator.backward(loss)

初步完成代码

将上面描述的内容组合起来就可以跑了,但是如果想要实现分布式,我们必须将上述代码放入函数里边,即不能写在脚本里直接用

所以我们初步完成的代码应该如下所示

 
from accelerate import Accelerator
+ def main():
accelerator = Accelerator()
model, optimizer, training_dataloader, scheduler = accelerator.prepare(
model, optimizer, training_dataloader, scheduler
)
for batch in training_dataloader:
optimizer.zero_grad()
# 注意到,这里无需将数据导入到指定设备,accelerator会自动帮你完成
# 传统来说应该先将inputs和targets传入gpu,cuda()或to(device)
inputs, targets = batch
outputs = model(inputs)
loss = loss_function(outputs, targets)
# 这里不再使用loss.backward()!!!
accelerator.backward(loss)
optimizer.step()
scheduler.step()
+ if __name__ == "__main__":
+ main()

如何运行

官方推荐运行前最好先调用accelerate config配置训练方式和相关参数,但笔者懒得搞(其实是不会),所以只讲最简单的运行方式

类似torch.distributed launch,我们这里用accelerate launch代替,紧跟着是运行的py脚本和你自己想传入的参数

 
# 默认是单机单卡训练,非混合精度(这样运行会有很多warning)
accelerate launch {script_name.py} --arg1 --arg2 ...
# 限制使用的GPU
CUDA_VISIBLE_DEVICES="0" accelerate launch {script_name.py} --arg1 --arg2 ...
# 单机多卡训练,非混合精度
accelerate launch --multi_gpu {script_name.py} {--arg1} {--arg2} ...
# 单机多卡训练,混合精度
accelerate launch --multi_gpu --mixed_precision=fp16 {script_name.py} {--arg1} {--arg2} ...
# 指定进程数
accelerate launch --multi_gpu --mixed_precision=fp16 --num_processes=2 {script_name.py} {--arg1} {--arg2} ...
# 指定机器数量,笔者的配置,这样就没有warning了
CUDA_VISIBLE_DEVICES="0,1" accelerate launch --multi_gpu --mixed_precision=fp16 --num_processes=2 --num_machines=1 train.py

具体还可以设置的参数使用accelerate launch -h获取

seed设置

如果想要重复实验,seed设置必不可少,accelerate提供的方法非常容易使用,一行代码解决

 
from accelerate import set_seed
set_seed(42)

实际上做的事

 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值