×

签到

分享到微信

打开微信,使用扫一扫进入页面后,点击右上角菜单,

点击“发送给朋友”或“分享到朋友圈”完成分享

【CN-PT5】Cambricon PyTorch 混合精度训练 小飞人2023-07-14 09:49:14 回复 查看 社区交流 干货资源
【CN-PT5】Cambricon PyTorch 混合精度训练
分享到:

若是初学者,建议先看前面的,尤其是其中 PyTorch 相关的模块。

1、混合精度训练简介

1 基本概念




  • FP16 数据存储一共占用两个字节,表示的范围是 -65504 ~ 65504,其中最小间隔是 2^(-24) (浮点数表示的数据范围里面具体数字不是均匀分布的,不同区间的间隔不一样);FP32 占用 4 个字节,表示的范围大约是 -3.4 * e38 ~ 3.4 * e38,其中最小间隔是 2^(-149)

  • 混合精度的训练方法是指在训练中前向推理、反向求梯度的过程,部分算子使用 FP16 的数据表示,而在卷积核更新的过程中使用 FP32 的数据表示

2 优势和缺陷

优势

  • 减少内存占用:FP16 的位宽是 FP32 的一半,因此内存占用也是 FP32 一半

  • 加快通讯效率:占用的位宽少了意味着通讯数据量减小,加快数据的流通

  • 计算效率更高:FP16 占用位宽少,运算比 FP32 快

缺陷:

  • 数据溢出:FP16 表示的数据范围比 FP32 窄很多,计算时超出数据范围,就会出现上溢和下溢

  • 舍入误差:FP16 能表示的数据精度有限,对于 FP32 转 FP16 的场景,小数点后过小的数会自动舍入,造成误差。比如0.11111111在FP32可以正常表示,转换成 FP16 就变成了0.1111

3 相关实现技术

针对上述两个问题,这里对应提出了解决方案:

1)解决数据溢出问题

①给前向计算的 Loss 乘以一个系数 S,使得反向计算的梯度能够在 FP16 的表示范围内。

②反向计算得到梯度

③在更新权值之前,将梯度再除以 S。

2)解决舍入误差问题

①输入 FP16 的数据,部分运算继续使用 FP16 计算,得到 FP16 结果

②将部分运算转成 FP32 类型进行计算,得到 FP32 中间结果

③输出时将所有的 FP32 数据转换为 FP16

需要转成FP32 涉及算子:向量点乘,batch norm,softmax,sigmoid等

2、PyTorch 混合精度

1 PyTorch AMP 介绍

1)总体框架

主要根据 autocast和GradScaler实现。



2)autocast



3) GradScaler



  • GradScaler主要是解决部分算子采用 FP16 计算时梯度下溢问题。

  • 主要的方式是将 loss 乘上 scale 值,然后反向传播,再判断梯度是否出现溢出,如果出现,则不更新梯度,并缩小 scale 值大小;如果连续 N 次正常梯度更新,则扩大 scale 值。

2 CambriconPyTorch适配 AMP

1) 适配 autocast



主要是通过修改 PyTorch 框架原生的代码,在 autocast 涉及的代码中,添加对 MLU 设备的支持,让整体代码逻辑可以在MLU平台正常运行。

2) 适配 GradScaler



Grad scaler的适配主要有两部分:

  • 一部分和前面 autocast 类似,就是在 gradscaler 内部添加支持 MLU 设备的代码。

  • 另一部分是在 catch 里面添加一个 unscale 算子,用来进行梯度的缩放,这个算子会在 PyTorch 的 gradscaler内部调用。

3、混合精度训练案例分析

1 核心代码

# 初始化 GradScalerscaler = torch.mlu.amp.GradScaler(enabled=amp)# autocast 实例通过上下文管理器进行混合精度训练with torch.mlu.amp.autocast(amp):
       pred = model(imgs)
       loss, loss_items = compute_loss(pred, targets.to(device))# 通过比例因子来缩放 loss,随后进行反向传播scaler.scale(loss).backward()# 梯度除以比例因子。如果没有梯度溢出,则更新梯度scaler.step(optimizer)# 更新比例因子scaler.update()

2 单机2卡并启用混合精度

和上一个课程的代码完全相同。(借用课程代码:拉取寒武纪docker pytorch1.9的镜像包)根据实验准备好环境

git clone cd cambricon_mlu_learning/23_PyTorch/pytorch_yolov5_trainmkdir -p ./datasets/coco/ln -s /data/datasets/COCO2017/* ./datasets/coco/cd yolov5python -m torch.distributed.launch \       --nproc_per_node 2 \       train.py --data coco.yaml \       --cfg yolov5n.yaml --weights '' \       --epochs 2 \       --batch-size 64  --device mlu  --pyamp
  • torch.distributed.lauch可以实现创建多个训练进程,每个进程绑定一张加速卡

  • --nproc_per_node指定需要创建的进程数量

  • train.py 是对应的包含 DDP 分布式训练的代码

  • --pyamp 表示使用混合精度

  • 代码主要来源:gitee.com/cambricon/pra

结果如下:



对比上次课用测试的 0.384 小时,这里用时 0.294小时,训练效率有较大提升。


注意:代码在相关链接的:22_pytorch

相关链接

1.    在线课程:在线课程寒武纪开发者社区 (cambricon.com)

2.    文档资料:文档中心寒武纪开发者社区 (cambricon.com)

3.    代码库:https://gitee.com/yifanrensheng/cambricon_mlu_learningc


版权所有 © 2024 寒武纪 Cambricon.com 备案/许可证号:京ICP备17003415号-1
关闭