• 模型部署时的调试技巧,debug方法


    调试法则

    1. 善用python工作流,联合python/cpp一起进行问题调试。因为python的工作流比较完善,比如有pycharm等。总之遇到一个问题时不要想着用c++调试,最多用c++进行print一下,尽可能将工作流程转到python上,这样效率比较高(写cuda和c++同理),比如在终端打印由于内容太长显示不完全,这时候就可以利用pycharm调试 。尤其是深度学习的东西,都是张量矩阵居多,在python上分析问题效率更高。比如onnx模型推理在python工作流上的复现就可以用onnxruntime实现推理。
    2. 去掉前后处理情况下,确保onnx与pytorch结果一致,排除所有因素。这一点通常是能够保证的。例如都输入全为5的张量,必须使得输出之间差距小于1e-4,确保中间没有例外情况发生
    3. 推理时的预处理和pytorch中的预处理一般很难保证完全一样(比如pytorch中用的PIL,推理时是opencv),考虑把python的预处理结果储存文件,c++加载文件后推理,得到的结果应该差异小于1e-4
    4. 考虑把python模型推理后的结果储存为文件,先用numpy写一遍后处理。然后用c++复现。总之是优先在python上做实验调通,理解清楚,再上到c++,这时其实就是个代码转换的过程。解决问题的效率就会变得很高。
    5. 如果出现bug,应该把tensor从c++中储存文件后,python加载文件后,放到python上调试查看。避免在c++中debug。

    python中加载Tensor和储存Tensor的代码

    # 以下代码是python中加载Tensor
     import numpy as np
    
     def load_tensor(file):
         
         with open(file, "rb") as f:
             binary_data = f.read()
    
         magic_number, ndims, dtype = np.frombuffer(binary_data, np.uint32, count=3, offset=0)
         assert magic_number == 0xFCCFE2E2, f"{file} not a tensor file."
         
         dims = np.frombuffer(binary_data, np.uint32, count=ndims, offset=3 * 4)
    
         if dtype == 0:
             np_dtype = np.float32
         elif dtype == 1:
             np_dtype = np.float16
         else:
             assert False, f"Unsupport dtype = {dtype}, can not convert to numpy dtype"
             
         return np.frombuffer(binary_data, np_dtype, offset=(ndims + 3) * 4).reshape(*dims)
    
    
     def save_tensor(tensor, file):
    
         with open(file, "wb") as f:
             typeid = 0
             if tensor.dtype == np.float32:
                 typeid = 0
             elif tensor.dtype == np.float16:
                 typeid = 1
             elif tensor.dtype == np.int32:
                 typeid = 2
             elif tensor.dtype == np.uint8:
                 typeid = 3
    
             head = np.array([0xFCCFE2E2, tensor.ndim, typeid], dtype=np.uint32).tobytes()
             f.write(head)
             f.write(np.array(tensor.shape, dtype=np.uint32).tobytes())
             f.write(tensor.tobytes())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    部署时实现一个模型的流程

    1. 先把代码跑通predict(模型的predict),单张图作为输入。屏蔽一切与该目标不符的东西,可以修改删除任意多余的东西
    2. 自行写一个新的python程序,简化predict的流程,掌握predict所需要的最小依赖和最少代码。比如原始的predict流程可能依赖于dataset,dataloader,config等等,所以这时候应该考虑把它简化掉,因为推理时只考虑先用单张图片作为输入,所以简化的目的就是只用几行代码把predict写出来。这里的predict指的是模型的predict,并没有包含前后处理
    3. 如果第二步比较困难,则可以考虑,直接在pred = model(x)这个步骤上研究,例如直接在此处写torch.onnx.export(model, (pred,) … )。或者直接把pred的结果储存下来研究,等等
    4. 把前处理、后处理分析出来并实现一个python最简化版本。
    5. 利用简化版本进行debug、理解分析。然后考虑预处理后处理的合理安排,例如是否可以把部分后处理放到onnx中
    6. 导出onnx,在c++上先复现预处理部分(这时先不要复现后处理),使得其结果接近(因为大多时候不能得到一样的结果)
    7. 把python上的pred结果储存后,使用c++读取并复现所需要的后处理部分。确保结果正确。(因为这样做就可以在每次debug我们写的后处理模块时,避免去等待tensorrt的编译推理,那样的话效率太低了。)
    8. 把前后处理与onnx对接起来,形成完整的推理
  • 相关阅读:
    若依微服务集成Mybatis-plus详细教程
    Msql_流程控制case
    shell编程基础
    springboot+vue+elementUI大学生体质测试管理系统#毕业设计
    单机服务器docker搭建mysql5.7主从同步
    CSRF 001
    【C++ string简单】就不告诉你(倒置输出结果)
    [论文笔记]GTE
    低代码+BPM为一体构建的知识管理系统
    HarmonyOS脚手架:快捷实现ArkTs中json转对象
  • 原文地址:https://blog.csdn.net/Rolandxxx/article/details/127814207