1 介绍
- 随着模型规模的增大,并行处理已成为在有限硬件上训练大型模型和提高训练速度的重要策略。
- Hugging Face 创建了Accelerate库,帮助用户在任何类型的分布式环境中轻松训练Transformers模型,无论是单机多GPU还是跨多机的多GPU
2 创建Accelerator对象
from accelerate import Accelerator
accelerator = Accelerator()
3 训练对象传递给prepare方法
train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare(
train_dataloader,
eval_dataloader,
model,
optimizer
)
4 反向传播
唯一不同的是把loss.backward()替换成Accelerate的backward
5 总结
绿色的是加上的,红色的是去掉的
6 训练
运行以下命令创建并保存配置文件
accelerate config
然后启动训练:
accelerate launch train.py
7 保存和加载
- 使用 save_state() 将所有内容保存到一个文件夹位置
- 使用 load_state() 加载之前通过 save_state() 保存的所有内容
- 通过使用 register_for_checkpointing(),可以注册自定义对象以便通过前两个函数自动存储或加载
7.1 unwrap_model
解包模型,在保存模型之前,用于从 prepare() 可能添加的额外层中解包模型
# 假设有两个GPU进程
from torch.nn.parallel import DistributedDataParallel
from accelerate import Accelerator
accelerator = Accelerator()
model = accelerator.prepare(MyModel())
print(model.__class__.__name__)
#DistributedDataParallel
model = accelerator.unwrap_model(model)
print(model.__class__.__name__)
#MyModel
torch.save(model.state_dict(), path)
#解包之后,可以用torch的save函数
8 分布式评估
8.1 gather_for_metrics
- 在分布式系统中,每个设备只接收一部分评估数据,这意味着你应该使用 gather_for_metrics() 方法将你的预测结果组合在一起。
- 此方法会收集 input_data 并可能在最后一个批次中删除重复项。
- 可应用于收集用于指标计算的输入和目标。
- 此方法要求每个进程上的所有张量大小相同,因此如果张量在每个进程上的大小不同(例如在批处理中动态填充到最大长度时),应该使用 pad_across_processes() 方法将你的张量填充到跨进程的最大大小
for inputs, targets in validation_dataloader:
predictions = model(inputs)
# Gather all predictions and targets
all_predictions, all_targets = accelerator.gather_for_metrics((predictions, targets))
# Example of use with a *Datasets.Metric*
metric.add_batch(all_predictions, all_targets)
8.2 pad_across_processes
( tensordim = 0,pad_index = 0,pad_first = False ) → torch.Tensor,
递归地填充来自所有设备的嵌套列表/元组/字典中的张量,以便它们可以安全地被聚合。
tensor | 要聚合的数据 |
dim | 填充的维度 |
pad_index | 用于填充的值 |
pad_first | 是否在开始或结束时进行填充 |
# 假设有两个进程,第一个进程有一个大小为1的张量,第二个进程的张量大小为2
import torch
from accelerate import Accelerator
accelerator = Accelerator()
process_tensor = torch.arange(accelerator.process_index + 1).to(accelerator.device)
'''
accelerator.process_index:这是当前进程的索引。
在两个进程的设置中,第一个进程的索引为 0,第二个进程的索引为 1。
'''
padded_tensor = accelerator.pad_across_processes(process_tensor)
'''
它确保所有进程中的张量都被填充到相同的大小,这样它们就可以安全地聚合或进行其他并行操作
'''
padded_tensor.shape
#torch.Size([2])
9 accelerate原理
- 在内部,Accelerate 首先分析启动脚本的环境,以确定使用的分布式设置类型、有多少个不同的进程以及当前脚本位于哪个进程中
-
然后,调用 prepare() 时,库会:
-
将模型封装在适用于分布式设置的容器中,
-
将优化器封装在 AcceleratedOptimizer 中,
-
将调度器封装在 AcceleratedScheduler 中,
-
在 DataLoaderShard 或 DataLoaderDispatcher 中创建数据加载器的新版本。
-
创建的原因是, PyTorch 不允许用户在数据加载器创建后更改其批处理采样器
-
DataLoaderShard 继承自 DataLoader,添加了以下功能:
- 它在每次新迭代时同步所有进程的适当随机数生成器,以确保任何随机化(如洗牌)都以完全相同的方式跨进程完成。
- 它在产生批次之前将批次放置在适当的设备上(除非选择了 device_placement=True)。
- DataLoaderDispatcher 与 DataLoaderShard 的不同之处在于,在迭代 DataLoader 时,数据都是从进程 0 开始的,然后分割并发送到每个进程,而不是在数据集级别进行
-
-