精度比对问题定位案例

问题现象

CenterNet检测模型在迁移到昇腾AI处理器上训练后,发现Loss收敛效果较GPU明显变差。迁移前后Loss曲线如下图所示。蓝色为GPU训练曲线,收敛正常;红线为NPU训练曲线,收敛效果变差。

图1 GPU训练Loss曲线与NPU训练Loss曲线对比

总体思路

在PyTorch模型迁移与训练过程中,出现loss变化收敛不一致,通过dump比对工具进行定位。检测是否存在单算子与标杆数据(GPU/CPU)存在精度差异,进行数据dump,分析dump数据比对结果,从而定位出单算子的适配与实现问题。

环境准备

请参考ptdbg_ascend工具使用说明安装ptdbg_ascend精度工具,并准备已适配NPU环境的CenterNet训练工程,点击获取链接-ModelZoo,下载CenterNet模型脚本。

Dump数据比对

  1. 进入模型脚本所在目录并打开。

    cd src
    vi main_npu_8p.py

  2. 在训练脚本中导入精度工具包,使能精度工具溢出定位。

    from ptdbg_ascend import register_hook, overflow_check, seed_all, set_dump_path, set_dump_switch, acc_cmp_dump

  3. 为了稳定复现溢出问题,在训练脚本主函数内添加以下代码,固定网络中的随机数。

    def main():
        seed_all()
        ...

  4. 在模型定义后,训练循环开始前,添加dump路径、hook函数和dump开关。acc_cmp_dump为数据dump比对开关。

    def main():
        ...
        model = create_model(opt.arch, opt.heads, opt.head_conv, opt.load_local_weights, opt.local_weights_path)  
        model = model.to(opt.device) #npu
        ...
        if opt.precision_mode == 'must_keep_origin_dtype':
            optimizer = torch.optim.Adam(model.parameters(), opt.lr)
            model, optimizer = amp.initialize(model, optimizer, opt_level="O0", combine_grad=False) ###npu
        else:
            optimizer = apex.optimizers.NpuFusedAdam(model.parameters(), opt.lr)      
            model, optimizer = amp.initialize(model, optimizer, opt_level="O1",loss_scale=19.0,combine_grad=True) ###npu
    
        set_dump_path("./dump_data_new/npu")    # 设置dump路径,最终数据保存在此路径下
    
        register_hook(model, acc_cmp_dump)    # 添加hook函数和数据比对dump开关
    
        start_epoch = 0
        ...

  5. 设置dump开关。

    用户根据实际需要的范围,在代码中设置dump开始位置set_dump_switch("ON")和结束位置set_dump_switch("OFF"),样例代码中开关设置在循环的开始与结束。
    set_dump_switch("ON") 
     
    for epoch in range(start_epoch + 1, opt.num_epochs + 1):
        ...
        logger.write('\n')
    
    set_dump_switch("OFF")

  6. 执行训练脚本。分别将模型在NPU和GPU/CPU上执行训练,注意两次执行训练前,要通过set_dump_path指定不同的输出目录,例如在CPU上可以将输出目录修改为./dump_data_new/cpu。

    #NPU训练命令
    bash ./test/train_full_1p.sh 

    模型训练结束后,数据会落盘到输出目录。样例输出目录如下图。

    图2 Dump输出数据目录

数据比对

  1. 参考比对脚本compare.py配置示例创建并配置精度比对脚本,样例参考如下。其中dump文件夹和pkl文件请用户根据dump时设置的实际目录修改。

    from ptdbg_ascend import compare
     
    dump_result_param={
        "npu_pkl_path": "/home/torch_test/dump_data_new/npu/ptdbg_dump_v2.0/rank0/dump.pkl",
        "bench_pkl_path": "/home/torch_test/dump_data_new/cpu/ptdbg_dump_v2.0/rank0/dump.pkl",
        "npu_dump_data_dir": "/home/torch_test/dump_data_new/npu/ptdbg_dump_v2.0/rank0/dump",  
        "bench_dump_data_dir": "/home/torch_test/dump_data_new/cpu/ptdbg_dump_v2.0/rank0/dump" 
    }
     
    compare(dump_result_param, "./out")

  2. 运行数据比对脚本。

    python3 compare.py

    比对完成后会在指定的输出目录中生成对比结果文件“compare_result_timestamp.csv”,示例文件如下所示。

    图3 示例文件
    图4 比对结果展示

分析比对结果

比对结果为csv类型文件,会包含两份Dump数据的比对信息,包括tensor shape信息,数据类型,余弦相似度,最大绝对误差,最大值,最小值,平均值等统计信息。

图5 样例比对结果文件

通常情况下,我们通过余弦相似度,来判断API的输入或输出是否存在问题。大部分API输入输出的余弦相似度要求大于0.99。我们以此为标准分析CenterNet在昇腾AI处理器上的比对结果,流程如下:

  1. 筛选“Accuracy Reached or Not”列中值为“No”的选项,即精度不达标的选项。

    工具内部定义的不达标规则如下:

    1. Cosine < 0.99 且 MaxAbsError > 0.001时,精度不达标,标记为“No”。
    2. Cosine < 0.9,精度不达标,标记为“No”。
    3. MaxAbsError > 1,精度不达标,标记为“No”。
    4. 其余情况下记为精度达标,标记为“Yes”。

  2. 筛选后CSV结果如下图所示,为了方便查看可以将其标黄:

    图6 筛选后CSV结果

  3. 还原表格进行分析,可以发现lstm反向输入正常,输出异常,说明是lstm的反向实现存在问题,进而影响了后续其他节点的精度。

    图7 lstm反向输入正常输出异常

  4. 基于上述流程,就可以根据比对表格,定位出问题API为lstm的反向实现。可以联系华为工程师反馈问题和寻求解决,可进入昇腾开源社区使用issue进行沟通。