Skip to main content

如何处理训练推理的一致性

本节介绍如何保证部署结果与训练结果的一致性以及调试方面的经验。

常见不一致点

  • gpu解码和前处理 与 训练时使用的库不一致

  • 对于使用opencv进行cpu解码和前处理, 通常来说,训练和推理有较大概率结果保持一致;部分环境下,可能因为cpu版本,底层库(libjpeg, libjpeg-turbo), 编译方式(WITH_IPP=ON/OFF) 等因素的差异,导致结果出现一定差异。

  • 流程差异;比如对于相同的图片resize,送入uint8类型的图片和送入float类型的图片,结果不同。

  • tensorrt fp16 带来一定差异;fp32有可能带来小数点后四位的差异;部分模型没有办法全部层都做fp16量化,需要用工具进行部分量化。

  • c++逻辑和python逻辑带来的差异

调试技巧

对于部署代码,与使用python做原型的代码的输出结果不同时,可以定位不同点的方法有:

  • 从头到尾逐行/逐节点比较输入输出; 可输出到python侧,也可使用如下后端输出到文件: SaveMat, SaveTensor, Mat2Tensor, Tensor2Mat.

  • 局部输入替换。可以跳过有差异的部分节点,比较后续流程。可使用的后端工具有:LoadTensor

  • 使用 torch_utils.hpp 中的函数保存tensor:

void ipipe::save(std::string name, at::Tensor input)
// 保存 at::Tensor 到文件。等价于 torch.save(name: str, tensor: torch.Tensor)

// 参数:

// name – 文件路径
// input – 输入的tensor
  • 采用 GDB调试 或者 打印的方式检查结果。

解决训练推理一致性问题的策略

  • 建议对于一些小的差异定位出来并以局部输入替换的方式跳过后,继续定位后续差异点;最终部署时,部分差异可忽略。

  • 建议上线之前,进行大量的数据测试,防止出现小概率错误导致的结果错误情况,保证最终部署的稳定性。

  • 可以以部署时的相关前处理流程,在线或者离线处理训练时的输入数据。

c++ first vs. python first

由于一些工程和现实原因(更少的工作量实现高性能目标),当前阶段主要依赖于脱离python的静态图达到最理想加速效果, 导致调试不太友好。

好的一点是 torchpipe 可以渐进式的分阶段采用,减轻调试的痛苦。