1. 前言

Accelerate 能帮助我们:

  • 方便用户在不同设备上 run Pytorch training script.

    • mixed precision
    • 不同的分布式训练场景, e.g., multi-GPU, TPUs, …
  • 提供了一些 CLI 工具方便用户更快的 configure & test 训练环境,launch the scripts.

方便使用:

用一个例子感受一下。传统的 PyTorch training loop一般长这样:

my_model.to(device)for batch in my_training_dataloader:my_optimizer.zero_grad()inputs, targets = batchinputs = inputs.to(device)targets = targets.to(device)outputs = my_model(inputs)loss = my_loss_function(outputs, targets)loss.backward()my_optimizer.step()

Accelerate 配合使用,只需要增加一丢丢代码:

+ from accelerate import Accelerator+ accelerator = Accelerator()
- # my_model.to(device)## Pass every important object (model, optimizer, dataloader) to *accelerator.prepare*
+ my_model, my_optimizer, my_training_dataloader = accelerate.prepare(
+     my_model, my_optimizer, my_training_dataloader
+ )for batch in my_training_dataloader:my_optimizer.zero_grad()inputs, targets = batch
- #    inputs = inputs.to(device)
- #    targets = targets.to(device)outputs = my_model(inputs)loss = my_loss_function(outputs, targets)# Just a small change for the backward instruction
-     loss.backward()
+     accelerator.backward(loss)my_optimizer.step()

Script Launcher:

Accelerate 通过一个 CLI tool 使得用户不需要再去学习 torch.distributed.lauch,也不需要了解如何专门面向 TPU training 写 specific launcher. 具体操作为:

  • 在用户的 machine(s) 上面 run:
accelerate config
  • 回答相关问题。此时会生成 一个 config 文件,该文件将在用户执行以下命令时被自动调用,来进行正确的配置 (properly set the default options)
accelerate launch my_script.py --args_to_my_script

Accelerate 具体支持:

  • 仅 CPU 可用的设备
  • 单个 GPU
  • 单个 node 多个 GPU
  • 多个 nodes 上的多个 GPU
  • TPU
  • FP16 with native AMP (apex on the roadmap)
  • DeepSpeed (experimental support)

2. 入门小教程

2.1 典型使用方法

1. import Accelorator 并实例化

from accelerate import Acceleratoraccelerator = Accelerator()
【注意】
- 越早越好,比如在进入 main 函数的第一步,此时会初始化(分布式)训练所需要的 everything.
- 不需要指明实验环境,accelerator 会自动检测。

2. 删除 model 和 data 对 .to(device).cuda() 的调用。accelerator 会帮你自动把模型和数据 place 到正确的 device 上面。

【注意】
- 可以保留对 .to(device) 的调用,但此时需保证 device = accelerator.device.
- 若不想采用 accelerator 的自动配置,则需要在初始化 Accelerator 的时候设置 device_placement=False.

3. 将所有 training 设计的对象 (optimizer, model, training_dataloader, learning rate scheduler) 送进 prepare().

model, optimizer, train_dataloader, lr_scheduler = accelerator.prepare(model, optimizer, train_dataloader, lr_scheduler
)

此时,training dataloader 将在所有的 GPU/TPU 中间进行分享,也就是说,每个 device 拿到了 training dataset 的不同部分。
同时,所有 processes 的 random states 将在 dataloader 开始每个 iteration的时候进行同步,来确保 data 以相同的方式进行 shuffle (如果设置sampler shuffle=True 的话)。

【注意】
- 实际的 batch_size = number_of_devices * batch_size_set_in_script.
- 如果在 initialize Accelerator 的时候设置 split_batches=True,则 batch_size 不会随 device 的数量改变。
- 在所有关于 training 的 object 创建结束之后的第一时刻调用 prepare()。
- 对 len(training_dataloader) 的调用应当出现在 prepare() 之后。
- 如果不需要进行分布式 evaluation, 则无需将 eval_dataloader() 送入 prepare()。

4. 用 accelerator.backward(loss) 替换 loss.backward().

以上即为 accelerator 关于分布式训练的基本操作。Accelerate launcher 可以。

2.2 分布式 evaluation

  • 如何进行 regular evaluation?:不要将 eval_dataloader 送入 prepare(),但注意此时需要手动将 data 执行 .to(accelerator.device) 操作。
  • 如何进行 distributed evaluation?
validation_dataloader = accelerator.prepare(validation_dataloader)
for inputs, targets in validation_dataloader:predictions = model(inputs)# Gather all predictions and targetsall_predictions = accelerator.gather(predictions)all_targets = accelerator.gather(targets)# Example of use with a *Datasets.Metric*metric.add_batch(all_predictions, all_targets)
【注意】
- gather() 要求由不同 process 得到的 tensor 具有相同的 siz
- 若此条件不满足 (e.g., dynamic padding),则应当通过 pad_across_processes() 将不同 process 的 tensor pad 到相同 size.
model.eval()
samples_seen = 0
for step, batch in enumerate(eval_dataloader):with torch.no_grad():outputs = model(**batch)predictions = outputs.logits.argmax(dim=-1)labels = batch["labels"]if not args.pad_to_max_length:  # necessary to pad predictions and labels for being gatheredpredictions = accelerator.pad_across_processes(predictions, dim=1, pad_index=-100)labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100)predictions_gathered, labels_gathered = accelerator.gather((predictions, labels))# If we are in a multiprocess environment, the last batch has duplicatesif accelerator.num_processes > 1:if step == len(eval_dataloader):predictions_gathered = predictions_gathered[: len(eval_dataloader.dataset) - samples_seen]labels_gathered = labels_gathered[: len(eval_dataloader.dataset) - samples_seen]else:samples_seen += labels_gathered.shape[0]preds, refs = get_labels(predictions_gathered, labels_gathered)metric.add_batch(predictions=preds,references=refs,)  # predictions and preferences are expected to be a nested list of labels, not label_ids

2.3 Launching your distributed script

2.4 Launching training from a notebook

2.5 Training on TPU

2.6 一些常见问题及解决方法

  • 2.6.1 仅在一个 process 中执行一些操作,如 download data, logging, progress bar…
if accelerator.is_local_main_process:# Is executed once per server
from tqdm.auto import tqdmprogress_bar = tqdm(range(args.max_train_steps), disable=not accelerator.is_local_main_process)

注意,上面 code 中的 local 指的是 per machine。对于一些只需要进行一次的操作,例如将 train 好的 model upload 到 huggingface model hub,则需要

if accelerator.is_main_process:# Is executed once onlyaccelerator.print('Test!')
  • 2.6.2 当有多个process的时候,难免出现执行速度不一致的情况,只需要执行 (当只有一张 CPU/GPU 时,则无事发生……):
accelerator.wait_for_everyone()
  • 2.6.3 保存/载入模型
    当 model 被送入 prepare() 之后,可能会被 place 到一个更大的 model 之中来便于进行分布式训练。因此在 save model 之前首先需要进行 unwarp():
accelerator.wait_for_everyone()
unwrapped_model = accelerator.unwrap_model(model)
# save
accelerator.save(unwrapped_model.state_dict(), filename)

如果在模型通过prepare() 后使用load函数时,则需要:

unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.load_state_dict(torch.load(filename))

2.7 保存所有状态

当我们在训练模型时,我们可能想要保存 model, optimizer, random generators, learning rate schedulers 等的当前状态。此时我们可以通过调用 accelerator.save_state(path_str)accelerator.load_state(path_str) 来分别实现相关对象状态的存储和调用。

其他通过 accelerator.register_for_checkingpointing register 的涉及状态的 items,也将通过上述函数的调用被存储/调用。

注意,送入 register_for_checkpointing 对象必须具有 load_state_dictsave_dict 函数可以调用。

  • Gradient clipping:如果我们的 code 调用了 torch.nn.utils.clip_grad_norm_torch.nn.utils.clip_grad_value_,我们应当使用 accelerator.clip_grad_norm_accelerator.clip_grad_value_ 进行替换。
  • Mixed precision training:当基于 Accelerate 进行 Mixed Precision 训练时,我们对于 loss 的计算也是在模型内(inside your model)完成的,例如 Transformer 模型。模型之外的所有计算都将以full precision 执行(这通常是我们在计算loss所期望的精度,尤其涉及softmax时)。此时,我们可以通过 accelerator.autocast() 实现:
with accelerator.autocast():loss = complex_loss_function(outputs, target):

【注意】在 Mixed Precision training 中,起始阶段可能会 skip 几步梯度更新(由 dynamic loss scaling stratergy 造成:在训练过程中,有些点会出现梯度溢出现象,此时会减小 loss scaling factor 的取值来避免在后续更新中再次发生这种情况)。在这种情况之下,我们可能在没有梯度更新的时候更新 learning rate scheduler (该现象暂记为 mismatch)。一般情况下,出现 mismatch 现象无伤大雅,但当训练样本很少时可能存在一些问题。如果学习率的初始值对于我们的模型训练十分关键,此时我们可以通过 skip learning rate scheduler 的更新来避免 mismatch 的发生:

if not accelerator.optimizer_step_was_skipped:lr_scheduler.step()

2.8 内部机制

=> 本质上说,accelerate lib 首先会分析 launch 当前 script 的环境来决定 i) 具体采用的 distributed setup, ii) 不同 processes 的数目, iii) 当前 script 所在的 process. 相关信息均存储在 ~AcceleratorState 中。

当我们实例化 Accelerator (并根据我们所需的 distributed setup 执行个性化初始化) 时会进行第一次初始化,然后共享至 AcceleratorState 的所有实例。

=> 当我们调用 prepare() 时,accelerate lib 会

  • Wrap your model(s) in the container adapted for the distributed setup.
  • Wrap your optimizer(s) in a AcceleratedOptimizer.
  • Create a new version of your dataloader(s) in a DataLoaderShard.

=> 当把 model 和 optimizer 送入 wraper 后,lib 会重新 create dataloader(s)。这主要是因为 PyTorch dataloader 在实例化之后,用户无法更改 batch_sampler。而 lib 通过改变 batch_sampler 的方式来利用不同的 process 处理不同的数据分片。

DataLoader 的子类 DataLoaderShard 中新的功能主要包括:

  • 它在每个迭代中同步所有processes的随机数生成器,以确保所有随机化操作(例如 shuffle)在不同的 processes 之间以完全相同的方式完成。
  • 在生成batch之前,将batch放在合适的 device 上(除非我们设置 device\u placement=True)。

Huggingface Accelerate 学习笔记相关推荐

  1. Huggingface Transformers库学习笔记(二):使用Transformers(上)(Using Transformers Part 1)

    前言 本部分是Transformer库的基础部分的上半部分,主要包括任务汇总.模型汇总和数据预处理三方面内容,由于许多模型我也不太了解,所以多为机器翻译得到,错误再所难免,内容仅供参考. Huggin ...

  2. kvm虚拟化学习笔记(二)之linux kvm虚拟机安装

    1. 上传ISO文件,这里采用OEL5.8x64 iso 2. 开始安装OEL5.8 # virt-install --name=oeltest02 --ram 512 --vcpus=1 --dis ...

  3. 伯禹公益AI《动手学深度学习PyTorch版》Task 07 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 07 学习笔记 Task 07:优化算法进阶:word2vec:词嵌入进阶 微信昵称:WarmIce 优化算法进阶 emmmm,讲实 ...

  4. 线性代数库 Armadillo 学习笔记

    线性代数库 Armadillo 学习笔记 项目环境 Xcode 项目配置 前置代码 矩阵基本操作 全零矩阵 全一矩阵 对角矩阵 打印一个矩阵 修改获取矩阵元素 获取某行某列 获取对角向量 转置矩阵 逆 ...

  5. huggingface.transformers速成笔记:Pipeline推理和AutoClass

    诸神缄默不语-个人CSDN博文目录 本文属于huggingface.transformers全部文档学习笔记博文的一部分. 全文链接:huggingface transformers包 文档学习笔记( ...

  6. Android学习笔记:Android基础知识点(不断更新中)

    1.Android学习笔记:OkHttp 2.Android学习笔记:更新UI的方法(UI线程和非UI线程) 3.Android学习笔记:Volley 4.Android学习笔记:Handler 5. ...

  7. 不完全免疫算法简介DMMO--AIS学习笔记3

    不完全免疫算法简介DMMO–AIS学习笔记3 觉得有用的话,欢迎一起讨论相互学习~ 多目标优化 A double-module immune algorithm for MOP 参考文献 A doub ...

  8. Spark GraphX学习笔记

    概述 GraphX是 Spark中用于图(如Web-Graphs and Social Networks)和图并行计算(如 PageRank and Collaborative Filtering)的 ...

  9. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

最新文章

  1. 套娃成功!在《我的世界》里运行Win95、玩游戏,软件和教程现已公开
  2. python模块之序列化模块
  3. 整数划分问题(路径输出)【递归求解方式】
  4. php 去除 html 属性,用PHP 去掉所有html标签里的部分属性
  5. 高程 第7章函数表达式 7.1递归 7.2闭包
  6. 通过xshell在linux上安装mysql5.7(终极版)
  7. 手机计算机英语,计算机英语翻译
  8. 实习渗透工程师面试记录
  9. 《2022年Java开发者生产力报告》出炉啦
  10. Jetson Xavier NX
  11. Greenplum 添加mirror步骤
  12. 面试知识点——(金三银四你需要的是她)
  13. SQL语句实现查询SQL Server服务器名称和IP地址_MsSql
  14. 差错控制之检错编码与纠错编码
  15. 关键项目遇见瓶颈,你会如何应对?
  16. linux基本命令整理——鸟哥linux私房菜第五章
  17. “凡客好声音”摇滚派对专场 正火热抢票中!
  18. oracle 查看回收站空间,ORACLE 回收站当前状态查询整理
  19. ecshop mysql 标题表_ECshop每个数据库表结构说明_MySQL
  20. Stata:多个变量组间均值\中位数差异检验

热门文章

  1. 情缘沙世界,妙笔如生花
  2. fclose函数的作用
  3. STM32 日历读取和输出
  4. python 协程可以嵌套协程吗_Python学习后有哪些方向可以选择?Python有什么好的学习方法吗?(附教程)...
  5. Ngnix 简单使用
  6. ironbot智能编程机器人_RoboSpaceIronBot机器人套件 | 视频 | 可编程组装机器人,自定义玩法孩子超爱-极果...
  7. ros moveit rviz 中轨迹球消失了怎么办?
  8. 【C#】EventHandler委托详解
  9. 一千行MySQL学习笔记(MySQL常见SQL语句全详解)
  10. html中的if函数,countif函数的使用方法