记录一次推理精度退化问题的解决
收藏回复举报
记录一次推理精度退化问题的解决
发表于2024-03-15 19:11:20
0 查看

记录一次推理精度退化问题的解决

作者:昇腾论坛 - sjyzzgbj

1 前言

这段时间尝试在Atlas 200 DK上开发行人重识别推理应用(本文接下来的内容也以此行人重识别推理应用为研究对象展开),期间发现模型的推理会出现严重的精度退化(mAP只有百分之零点几)。为了定位问题所在,查阅了一些资料,初步形成了一个基本有效的解决流程。现记录在此,希望能给遇到类似问题的人一点参考

2 推理应用开发流程

在介绍具体内容之前,首先介绍一下推理应用开发流程(此处结合自己的理解简要介绍,详细开发资料请见参考资料[1]:

  1. 准备开发环境
    1. 本文硬件环境:搭载昇腾310 NPU芯片的Atlas 200 DK作为硬件环境
      • Atlas 200 DK环境搭建请见参考资料[2]
    2. 本文软件环境:Ubuntu 18.04.6 LTS;CANN Toolkit社区版6.0.RC1.alpha005
      1. CANN Toolkit的安装请见参考资料[3]。需要注意的是,Atlas 200 DK配套的CANN Toolkit没有商用版,只能使用社区版(理论上兼容性和稳定性都比商用版差些,但没得选)
      2. CANN的社区版文档在发布一段时间后会清退,此时可以使用对应的商用版文档代替(商用版文档不会被清退,比如社区版6.0.RC1.alpha005对应商用版6.0.RC1)
    3. 有的资料还将环境划分为分设(开发环境和运行环境不在同一台机器)和合设(开发环境和运行环境在同一台机器,本文属于此类)
  2. 开发场景分析
    • 就是对任务进行需求分析、划分程序模块等工作
  3. 参考官方样例,若有相似的可作为开发基础
    • 请见参考资料[4]
  4. 开发应用,主要包括三个阶段的逻辑:
    1. 资源准备阶段:运行管理资源申请、模型加载、开辟输入输出内存等
    2. 迭代阶段:一般包括数据预处理、填充输入内存、执行推理、读取输出内存等
    3. 后处理阶段:视任务需要可有可无。对于本文开发的行人重识别应用,后处理主要就是计算mAP和CMC指标
  5. 运行应用
    • 需要提前准备好OM模型

3 模型导出和转换

昇腾NPU上的模型推理需要使用OM模型。具体来说,需要先将已训练的PyTorch模型导出为ONNX模型,再使用昇腾提供的ATC工具将ONNX模型转换为OM模型,步骤如下:

  1. 使用torch.onnx.export导出ONNX模型

    1. 该API的工作原理是使用模拟输入(第二个参数)在模型(第一个参数)上进行推理,记录计算图路径,再导出。因此,如果输入中除了Tensor之外还有和执行路径有关的参数(比如需要设置为True还是False的标志位等。这常见于训练模型和推理模型不一致的场景,比如互学习、集成学习等),需要和Tensor一起组成元组传入,比如(dummy_input, True)。这种方式可以去除模型中的冗余分支,只保留必要的推理路径
    2. 更多信息请见参考资料[5]
  2. 使用昇腾ATC(Ascend Tensor Compiler,即昇腾张量编译器,用于模型转换)工具将ONNX模型转换为OM模型,命令如下:

    • ATC工具详细使用方式请见参考资料[6]
    atc --framework=5 --model="ONNX模型名称.onnx" --output="OM模型名称(不带后缀)" --input_format=NCHW --input_shape="输入节点名称:N,C,H,W" --log=debug --soc_version="芯片型号"

    其中,

    --framework=5表示输入的模型格式为ONNX

    --input_shape="输入节点名称:N,C,H,W"中的输入节点名称可以通过Netron工具可视化ONNX模型获知,比如imagesN,C,H,W表示输入的shape,比如1,3,128,256表示输入shape为$1 \times 3 \times 256 \times 128$

    --soc_version="芯片型号"参数十分重要,需要根据实际硬件设置,比如本文的实验中指定该参数为Ascend 310

4 推理精度测试

使用PyTorch模型、ONNX模型、OM模型分别在GPU上、CPU上、NPU上进行精度测试,结果如下:

模型硬件mAPRank1
PyTorchGPU71.2083.30
ONNXCPU69.2083.80
OMNPU0.401.10

可以看到ONNX模型精度相对PyTorch略有降低,但是降幅在2%以内,工程上可以接受,但是OM模型精度非常低,只有百分之零点几,显然出现了严重的精度退化,需要进行问题定位并解决

5 AIT工具介绍

首先,介绍一下进行推理精度问题定位所使用的AIT工具

AIT的全称是Ascend Inference Tools,即昇腾推理工具箱,包含多种推理开发中会用到精度调优、性能调优工具,本文会涉及到其中debug工具的compare功能。该功能可以在模型(支持TensorFlow、ONNX、Caffe模型)之间进行精度比对,找出精度出现差异的算子,定位问题算子所在(详细信息请见参考资料[7])

本文后续实验为了找出OM模型中的精度退化算子,对比了OM模型和ONNX模型各对应算子的精度,对比的基本原理如下:

  1. 对ONNX模型进行修改,在每个节点后面插入一个输出节点,修改前后的ONNX模型如图所示(右侧红框表示新插入的输出节点)

    true

    • 猜测对OM模型应该也进行了类似操作,但是没有找到资料佐证
  2. 使用相同的输入(可以是随机数据,也可以自定义数据)对ONNX模型和OM模型进行推理,并记录每个节点的输出值

  3. 使用多种指标衡量不同模型对应算子输出值间的相似度,比如余弦相似度、KL散度等

  4. 按输入端到输出端的顺序查看指标(因为后面的精度问题可能是由前面的精度问题导致,所以采用从前到后的顺序),对于指标超过阈值的算子,认为存在精度退化问题,具体问题具体分析进行解决。指标阈值如下:

    指标精度达标阈值重要程度
    CosineSimilarity<0.99重要
    KullbackLeiblerDivergence>0.005重要
    RelativeEuclideanDistance>0.05供参考
    RootMeanSquareError>1.0供参考
    MeanRelativeError>1.0供参考

6 推理精度问题定位和解决

本小节会涉及ATC工具的高级使用方式,请见参考资料[6]

  1. 使用AIT比较ONNX模型和OM模型,结果如图所示:

    true

    可知,第174号算子存在溢出问题,这是因为ATC工具会将模型转换为FP16,而FP16的表示范围比训练时采用的FP32小很多。此时可以尝试在ATC转换模型时强制设定174号算子的计算方式为FP32以进行算子精度保持:

    atc --framework=5 --model="ONNX模型名称.onnx" --output="ONNX模型名称.onnx" --input_format=NCHW --input_shape="输入节点名称:N,C,H,W" --log=debug --soc_version="芯片型号" --keep_dtype "config.ini"

    其中,--keep_dtype "config.ini"表示将config.ini文件中设定的算子进行精度保持,config.ini文件内容如下:

    ;config.ini文件内容
    PartitionedCall_/mean_net/global_pooling/Clip_ClipByValue_17

    进行精度测试,结果如下:

    模型硬件mAPRank1备注
    PyTorchGPU71.2083.30
    ONNXCPU69.2083.80
    OMNPU0.401.10
    OMNPU0.401.10算子精度保持

    显然还是存在精度退化问题,实验继续进行

  2. 使用AIT比较ONNX模型和进行算子精度保持的OM模型,结果如图所示:

    true

    可知,第176号算子存在精度退化(CosineSimilarity < 0.99)。又从名字可知,这是一个融合算子,因此合理猜测精度退化可能是由于算子融合导致的。通过Netron查看OM模型中该算子的pass_name属性可知,此处算子融合匹配到的规则是TbeReduceElemwiseFusionPass,如图所示

    true

    此时可以尝试在ATC转换模型时关闭对应的算子融合规则以进行算子融合优化(同时,之前进行的算子精度保持也需要保留):

    atc --framework=5 --model="ONNX模型名称.onnx" --output="OM模型名称(不带后缀)" --input_format=NCHW --input_shape="输入节点名称:N,C,H,W" --log=debug --soc_version="芯片型号" --keep_dtype "config.ini" --fusion_switch_file "config.cfg"

    其中,--fusion_switch_file "config.cfg"表示按config.cfg文件中设定的规则进行算子融合(ATC工具已经内置了不少默认的算子融合策略,通过--fusion_switch_file "config.cfg"设定的融合策略优先级更高),config.cfg文件内容如下:

    ;config.cfg文件内容
    TbeReduceElemwiseFusionPass:off

    再次进行精度测试,结果如下:

    模型硬件mAPRank1备注
    PyTorchGPU71.2083.30
    ONNXCPU69.2083.80
    OMNPU0.401.10
    OMNPU0.401.10算子精度保持
    OMNPU69.1083.80算子精度保持 + 算子融合优化

    可知,精度退化问题解决

  3. (可选)使用AIT比较ONNX模型和进行算子精度保持+算子融合优化的OM模型,结果如图所示:

    true

    如果按照上面给出的阈值范围,第185号算子仍存在精度退化问题(CosineSimilarity为0.312404,小于0.99),但是实验结果又显示精度已经对齐。实际上这种情况经常出现,特别是当算子靠近输出端时(第185号算子就属此类情况),所以实际问题是否解决的判定还是需要靠端到端的精度测试实验

7 总结

  1. 本文给出了一种精度退化问题的解决方式:使用AIT工具对比OM模型和标杆模型(ONNX或其他格式模型)找出精度退化算子 --> 尝试解决 --> 进行精度测试实验。以上过程循环进行,直到OM模型精度和标杆模型对齐
  2. 希望本帖能对大家提供一点参考,也希望昇腾能不断完善推理应用开发工具集,提供更好的使用体验
  3. 实验中涉及到的所有文件请在提取码:8q2k下载

8 参考资料

[1] 学习向导-应用开发 (Python)-推理应用开发-...-文档首页-昇腾社区 (hiascend.com)

[2] 简介-环境部署-1.0.13-Atlas 200 DK开发者套件-文档首页-昇腾社区 (hiascend.com)

[3] 安装须知-软件安装-环境准备-...-文档首页-昇腾社区 (hiascend.com)

[4] inference/modelInference · Ascend/samples - 码云 - 开源中国 (gitee.com)

[5] TorchScript-based ONNX Exporter — PyTorch 2.2 documentation

[6] 前言-ATC模型转换-推理应用开发-...-文档首页-昇腾社区 (hiascend.com)

[7] ait: 统一推理工具链入口,提供客户一体化开发工具,支持一站式调试调优 - Gitee.com

我要发帖子