ONNXRuntime学习笔记(一)
一. DL模型落地步骤
一般情况下,一个DL任务落地的流程一般包含训练和部署两大部分,具体细分我认为可以分为以下几个步骤:
- 1. 明确任务目标:首先要明确我们最终要达到一个什么样的效果,假设我们的DL模型是一个函数y=f(x), 送入一张图片x后,模型需要吐出来一个什么样的y(基于此区分不同任务,如分类、检测或分割),然后这个y是否符合预期应该如何评价(评价指标,如recall或precision),eg.: 我们需要一个模型可以将街景图片中的行人数量统计出来。这个时候我们一般会有几个相对较优的方案可以选择:①基于HOG特征的行人检测方案,该方案是传统数字图像处理中行人检测经典方案,依靠纯数字图像特征提取实现,简单但效果不及DL方案;②深度学习方案,如人脸检测或者直接行人检测。人脸检测显然无法适应遮挡场景,所以直接检测人体更加靠谱。此外,视野中的行人的远近会导致目标尺度范围较大,所以应当确定评价指标是否要区分不同尺度的人或者不考虑尺度小于某一比例的行人。此外还需要考虑我们对漏检(FN)和误检(FP)的容忍度,以选择合适的Recall和Precision预期,或者分别加权来确定加权F-Score如何计算。
- 2. 模型选择与训练:这部分接上面我们以目标检测模型为例,有很多选择,如Anchor-based或Anchor-Free的等等,近几年的模型多的一批,不再一一列举,总之这个模型喂进去一张图,会输出该图中所有检测到的行人的BBox(当然多类检测还会有预测Label)。在模型构建的过程中,也需要考虑利用一些先验知识加一些定制module或者trick,或者在Loss上做文章,训练后的最终模型效果只看测试集上获得的评价指标结果,另外考虑部署的话,还需要提前考虑到自己模型的计算量,以及加的一些算子是否在部署环境中支持良好。在工作中,如果训练模型的和部署的不是同一个人,这种问题就很容易出现,所以提前沟通很有必要。在得到一个符合预期的pytorch模型后,就可以用troch.onnx.export导出对应的onnx模型,这个模型会记录模型结构(输入输出和Graph)和每个算子的参数信息,是可以单独拿来推理的。
- 3. 部署前准备:拿到的onnx模型推理效果是否和原始pytorch模型一致是需要再次验证的,因为导出onnx的过程有可能出错。验证可以通过只测试一个样本,然后精确验证输出数据是否和原型一致,以及会不会出现推理库不支持的算子;也可以拿整个测试集用推理库的python接口跑一遍测试效果,但这样会比较麻烦,因为预处理和输出数据后处理以及整个推理流程得再去弄个python实现。此外,为提高效率,通常是需要做量化的(直接用半精度或int8训练就不需要量化了),量化一般都有开源工具可用,思路也比较简单,首先是输入后加转量化后类型的cast,输出前加转单精度的cast,这样能保证我们只给模型float类型的数据即可;另外每个内部算子如果有参数还需要转为指定量化类型。量化后的模型和原始模型的推理效果肯定有差异,比如行人检测有可能漏检一些小目标之类的,我们需要保证精度下降在可接受范围内(一般1%),这里又会用到评价指标。量化成功那么就可以使用推理库运行了。
- 4. 部署和测试:考虑到效率,量化后的onnx我们一般会用C++推理库部署,像ONNXRuntime也提供了Python接口,但用C++可以方便使用多线程以及C++语言本身的高效性,无论在云端还是在移动端部署C++都是首选。以云端部署为例,我们的C++部署环境会提供一套完整的调用流程,最终会打包为一个SDK提供出去,其内部核心是调用推理库完成DL模型推理,但其前后还需要很多模块配合,如预处理和后处理模型、配置文件解析模块、资源管理模块、输出模块。这些模块一般都会对应有一个各自的Class继承体系,配合配置文件和如工厂模式的设计策略还可以实现一套SDK能实现多种能力。部署完成需要测试效率和效果是否符合预期,还需要考虑多线程调用环境下的稳定性。
小结:以上流程中很多细微的点没有讲到,但大概总结一下要完成以上流程需要具备的一些能力:
- 初级:能训练开源模型,简单调整模型结构,导出float32的onnx模型,调用开源推理库开发demo进行推理,保证效果不保证效率;
- 中级:能将开源算法应用到业务场景并针对性对模型结构调整,未开源算法能完成复现,训练过程可控,熟练使用一些结构设计trick和训练trick,导出onnx并能完成量化,能解决或规避算子不支持或支持差的问题,能在现有C++推理框架下开发要部署的模型的相关模块;
- 高级:我猜啊,首先要能设计模型确定方案,并预判某一模型方案在具体业务上的可行性,提前避免资源浪费;应该不再上手训模型了吧,也不会亲自导模型了吧,因为这些任务相对较独立而且目标很明确,扔给子线程去做最后用的时候同步一下就OK了。部署的框架这块需要明确整体架构,保证接口稳定可靠,因为SDK接口是提供给外部的,不能经常动,接口类亲自设计,实现类code review把关,内部核心推理库也是把关整体架构,kernel实现code review把关。到这个级别深耕的方向大概有两个:要么深入研究算法模型,要么深入研究部署。
- 再高就是,见识太少,是我无法描述的level了,或许真的宇宙的尽头是编制吧
二. 一个小项目
ONNXRuntime是微软出品的机器学习推理库,目前两大深度学习训练框架Pytorch和Tensorflow训练后的模型都可以导出为onnx格式,可以直接用ONNXruntime推理。打算用CIFAR-100数据集训练一个分类模型进行部署。确定一下方案:
- 总体目标:训练一个pytorch模型,CIFAR-100数据集测试集acc达到90%;部署后推理效率达到50ms/张, 部署平台为window10+3050Ti+RX5800h.
- 模型选择与训练:用VGG结构+ResNet来构建,尽可能轻量。
- 导出onnx并量化
- 部署:单线程调用ONNXRunTime pythonAPI的demo跑通,单线程调用C++API的demo跑通;进阶完成多线程调用。