写点什么

飞桨 x 昇腾生态适配方案:04_ 模型精度对齐

作者:小顺637
  • 2025-05-12
    北京
  • 本文字数:2810 字

    阅读完需:约 9 分钟

精度对齐说明

精度对齐旨在确保模型在训练一定轮次后,其损失(LOSS)或评分能够与原硬件训练的结果基本相符。

精度对齐标准

下图所示为在原硬件 GPU 上的训练精度:



迁移到 NPU 上后要求与 GPU 训练精度相差在千分之五左右,若精度误差过大则需要通过前向、反向对齐操作定位问题算子。


精度对齐思路

一旦精度出现偏差,首先确认环境变量配置(例如,NPU 私有格式环境变量是否关闭export FLAGS_npu_storage_format=0)、输入数据是否一致,如以上两项一致,则极有可能是算子的问题。


常用的问题算子定位方法是分模块对齐,在单模块内用二分法逐步缩小排查范围,直至确定最小问题单元。

前向对齐

前向对齐时可先进行单步对齐,再做多步验证。通常而言,单步对齐要求误差在百分之五以内;而多步验证则要求平均相对误差或平均绝对误差小于百分之二。


前向计算结果可在模型侧代码中打印输出。对比时逐模块进行,若模块结果差异大,采用二分法逐步收缩排查模块内部,直至定位问题算子。

模型结构分析

YAML 配置文件中的 Architecture 部分定义了模型的整体结构。


Architecture:  model_type: rec  algorithm: SVTR_HGNet  Transform: null  Backbone:    name: PPHGNet_small  Head:    name: MultiHead
复制代码


关键信息说明:


  • "model_type: rec":指定模型的类型为识别(recognition)任务,在 OCR 场景中,通常分为检测(detection)和识别两个主要任务,这里明确该模型用于文字识别。

  • "algorithm: SVTR_HGNet":指定使用的算法为 SVTR_HGNet。SVTR(Scene Text Visual Recognition)是一种用于场景文本识别的模型架构。

  • "Backbone":模型的骨干网络模块,主要负责从输入数据中提取特征。

  • "name: PPHGNet_small":指定骨干网络使用 PPHGNet_small 模型。PPHGNet 是 PaddlePaddle 团队提出的一种轻量级骨干网络,small 表示使用其小型版本,通常具有较少的参数和较低的计算量。

  • "Head":模型的头部网络模块,用于根据骨干网络提取的特征进行具体的任务预测。

  • "name: MultiHead":表示使用多头部网络结构。

模块代码查找

根据模型结构中各个模块的名称查找对应模块的代码实现:


# 进入模型结构代码目录cd  paddleOCR/ppocr/modeling
# 根据模块名称查找对应代码实现# Backbones模块名称为PPHGNet_small,则在./backbones目录下搜索:grep -rn "PPHGNet_small" ./backbones/
# Head模块名称为MultiHead,则在./heads目录下搜索:grep -rn "MultiHead" ./heads/
复制代码

模块结果打印

找到各个模块代码后,对各模块的计算结果进行打印输出,可以分别打印平均值,最大最小值,形状和数据类型。


本节以 Head 模块为例,MultiHead 代码实现在 rec_multi_head.py 文件中,其中 forward 方法实现如下:


def forward(self, x, targets=None):    if self.use_pool:        x = self.pool(            x.reshape([0, 3, -1, self.in_channels]).transpose([0, 3, 1, 2])        )    ctc_encoder = self.ctc_encoder(x)    ctc_out = self.ctc_head(ctc_encoder, targets)    head_out = dict()    head_out["ctc"] = ctc_out    head_out["ctc_neck"] = ctc_encoder    # eval mode    if not self.training:        return ctc_out    if self.gtc_head == "sar":        sar_out = self.sar_head(x, targets[1:])        head_out["sar"] = sar_out    else:        gtc_out = self.gtc_head(self.before_gtc(x), targets[1:])        head_out["gtc"] = gtc_out    return head_out
复制代码


在"return head_out"语句之前,添加如下代码段:


print("head_out['ctc']")print("平均值:", head_out["ctc"].mean())print("最小值:", head_out["ctc"].min())print("最大值:", head_out["ctc"].max())print("形状:", head_out["ctc"].shape)print("数据类型:", head_out["ctc"].dtype)
print("head_out['ctc_neck']")print("平均值:", head_out["ctc_neck"].mean())print("最小值:", head_out["ctc_neck"].min())print("最大值:", head_out["ctc_neck"].max())print("形状:", head_out["ctc_neck"].shape)print("数据类型:", head_out["ctc_neck"].dtype)
print("head_out['gtc']")print("平均值:", head_out["gtc"].mean())print("最小值:", head_out["gtc"].min())print("最大值:", head_out["gtc"].max())print("形状:", head_out["gtc"].shape)print("数据类型:", head_out["gtc"].dtype)
复制代码

前向输出对比

添加打印代码后,执行以下命令行,分别开启 NPU 与 CPU(本文仅以 CPU 为例,实际需与 GPU 输出对比)上的训练。


  • NPU:


python -m paddle.distributed.launch --devices 0,1,2,3,4,5,6,7 tools/train.py -c PP-OCRv4_server_rec_ic15_data.yaml -o Global.use_gpu=False Global.use_npu=True > ocr_npu.log  2>&1
复制代码


  • CPU:


python  tools/train.py -c PP-OCRv4_server_rec_ic15_data.yaml -o Global.use_gpu=False -o  Global.use_cpu=True > ocr_cpu.log  2>&1
复制代码


对比结果如下:



合格标准:平均值的绝对误差或者相对误差在百分之一以内。

反向对齐

固定输入和权重,采用相同配置,在 GPU 和 NPU 上对比训练一步的 loss 和梯度。在前向对齐的情况下,若梯度不一致,在 loss.backward() 后用 tensor.grad 获取梯度值,再通过二分法逐步缩小范围查找差异,定位无法与 GPU 梯度对齐的 API 或操作。

反向代码查找

在模型训练脚本中,找到训练入口定位到反向代码,步骤如下:


  • 在 tools/train.py 中搜索关键词 program.train,进入 program.py 文件;

  • 在训练循环中找到和 scaled_avg_loss.backward()或 avg_loss.backward(),如下图所示:


梯度值打印

在 avg_loss.backward()方法之后,使用 tensor.grad 获取梯度值,随后打印出梯度值的最大最小和平均值,代码如下:



反向结果对比

添加打印代码后,执行以下命令行,分别开启 NPU 与 CPU(本文仅以 CPU 为例,实际需与 GPU 输出对比)上的训练。NPU:


python -m paddle.distributed.launch --devices 0,1,2,3,4,5,6,7 tools/train.py -c PP-OCRv4_server_rec_ic15_data.yaml -o Global.use_gpu=False Global.use_npu=True > ocr_npu.log  2>&1
复制代码


CPU:


python  tools/train.py -c PP-OCRv4_server_rec_ic15_data.yaml -o Global.use_gpu=False -o  Global.use_cpu=True > ocr_cpu.log  2>&1
复制代码


对比结果如下:



合格标准:平均值的绝对误差或者相对误差在百分之一以内。

其它可能精度问题

私有格式问题

私有格式常出现问题,目前默认关闭,确认是否关闭:


export FLAGS_npu_storage_format=0
复制代码

梯度消失/爆炸

确认是否存在梯度消失/梯度爆炸问题,尝试加上梯度裁剪等策略。

特殊 shape

有些偶现问题常见与出现在特殊的 shape,如 0 维 Tensor,需要特别注意。

多模型场景

在同时对多个模型进行调优时,常常会出现大部分模型能够实现精度对齐,而个别模型却出现异常的情况。此时,可以通过对不同算子进行筛查,找出可疑算子,最终通过将可疑算子列入黑名单的方式进行排查,以解决精度问题。


用户头像

小顺637

关注

还未添加个人签名 2023-01-19 加入

还未添加个人简介

评论

发布
暂无评论
飞桨x昇腾生态适配方案:04_模型精度对齐_飞桨_小顺637_InfoQ写作社区