模型端部署 Acemyzoe

深度学习框架

一般流程:模型设计和训练,针对推断框架的模型转换,模型部署。

一般从离线训练到在线部署,训练需要依赖离线训练框架(tensorflow、pytorch等),部署需要依赖在线推理的框架(如TFlite、阿里的MNN、腾讯的NCNN等)。对于NVIDIA的产品,一般都会使用TensorRT来加速推理,TensorRT用了CUDA、CUDNN,而且还有图优化、fp16、int8量化等。

TensorFlow Lite

2017年5月17日 Goole在I/O大会推出TensorFlow Lite,是专门为移动设备而优化的 TensorFlow 版本。

TensorFlow Lite 具备以下三个重要功能:

轻量级(Lightweight):支持机器学习模型的推理在较小二进制数下进行,能快速初始化/启动

跨平台(Cross-platform):可以在许多不同的平台上运行,现在支持 Android 和 iOS

快速(Fast):针对移动设备进行了优化,包括大大减少了模型加载时间、支持硬件加速

模块如下:

TensorFlow Model: 存储在硬盘上已经训练好的 TensorFlow 模型

TensorFlow Lite Converter: 将模型转换为 TensorFlow Lite 文件格式的程序

TensorFlow Lite Model File: 基于 FlatBuffers 的模型文件格式,针对速度和大小进行了优化。

TensorFlow Lite 目前支持很多针对移动端训练和优化好的模型。

部署环境及方式

部署环境

包括硬件和软件,首先需要明确的是模型需要部署在什么样的硬件环境中:服务器(公有云或者私有云,能否支持GPU显卡加速),嵌入式,或者移动端;硬件决定了上面可以跑的软件系统,也就在很大程度上决定了需要使用的技术栈(框架、语言等)。

部署方式

取决于模型推理计算的环境是在服务器还是终端。负荷预测部分采用Online方式,异常识别部分采用Offline方式。

Online 方式

首先在嵌入式终端做初步数据预处理,然后把数据传到服务器进行预测后存储结果或将结果返回终端。

优点:部署相对简单,现成的框架(tensorflow,pytorch等) 做下封装就可以直接拿来用;使用服务器进行计算,性能强,能够处理比较大的模型。

缺点:不适合实时性要求高的应用。

Offline 方式

根据硬件的性能选择模型,离线训练得到模型,在嵌入式终端上进行推理。

优点:不需要使用网络,可以保护隐私

缺点:计算的性能、耗时等取决于终端的性能,有些模型只能使用CPU,精度可能会有影响,无法进行类似云端的大规模分布式训练;终端部署相对较麻烦,需要针对终端进行优化;大模型耗费大量的资源(计算、内存、存储、电)。

部署类型

主要分实时在线预测和离线批量预测两大类。

针对实时预测,部署服务通常提供API以供客户端调用,比如使用流行的REST接口;

离线预测一般是在服务器端部署,比如设定定时任务,每天定时从数据库中读取某一时间段数据,并且把预测结果再写入数据库以供后续的使用。

按照需求,该项目采用离线预测即可。

部署方法

首先模型最好用c++重写,像tensorflow可以直接编译成二进制。c++对矩阵、张量、图像运算、并行计算可以使用opencv,openml,opencl,opengl,cuda、cudnn等加速,性能要求不高可以直接使用TFlite等框架。放入嵌入式移动设备时,需要有专门的加速芯片,对权重进行剪枝,可能要重新编译。

现在模型部署主流的做法是将模型和模型的服务环境做成docker image。好处是屏蔽了模型对环境的依赖,因为深度学习模型在服务的时候可能对各种框架版本和依赖库有要求。将模型通过docker服务化后意味着深度学习模型可以在各种环境使用,比如云端直接通过k8s调度拉起,采用web service,开放API 接口,即简单的网页服务开发。或者在一些IOT领域,比方说一些嵌入式终端也可以通过拉起镜像服务的方式使用模型。

例如,使用TensorFlow框架,导出pd格式的模型,在嵌入式终端中使用docker拉取实例,直接用tensorflow的core lib加载模型。在服务器上,用Docker做容器,用Kubernetes做集群,用python的flask做成web微服务。

性能要求

API的各种性能指标,包括服务的稳定性等。

针对实时预测主要性能指标包括单条响应时间(RT)和吞吐量(Throughput)等。

对于离线批量预测来说主要在于吞吐量,确保在规定的时间完成批量预测任务。

基于现有指标,即系统对延迟(比如100ms以内)和吞吐(比如数万的qps),使用docker即可。

模型管理

机器学习项目始终是一个循环迭代的过程,需要能够快速上线新的模型,并且在不影响调用端的情况下自由切换模型版本、进行AB测试等。

AI部署的基本步骤或要求

  • 训练一个模型或者拿一个预训练好的模型
  • 针对不同平台对生成的模型进行转换,也就是俗称的parse、convert,即前端解释器
  • 针对转化后的模型进行优化
  • 在特定的平台(嵌入端或者服务端)成功运行优化后的模型
  • 在模型可以运行的基础上,保证模型的速度、精度和稳定性

对于硬件公司来说,需要将深度学习算法部署到性能低到离谱的开发板上。在算法层面优化模型是一方面,但更重要的是从底层优化这个模型,涉及到部署落地方面的各个知识(手写汇编算子加速、算子融合等等);

对于软件公司来说,需要将算法运行到服务器上,服务器可以是布满2080TI的高性能GPU机器,QPS请求足够高的话,需要的服务器数量也是相当之大的。

算法部署算是开发,不仅需要和训练好的模型打交道,有时候也会干一些粗活累活(也就是dirty work),用C++、cuda写算子(预处理、op、后处理等等)去实现一些独特的算子。也需要经常调bug、联合编译、动态静态库混搭等等。

部署

部署不光是从研究环境到生产环境的转换,更多的是模型速度的提升和稳定性的提升。

  • 模型结构
  • 剪枝
  • 蒸馏
  • 稀疏化训练
  • 量化训练
  • 算子融合、计算图优化、底层优化

部署框架

Tensoflow lite

Pytorch C++

ONNX

NCNN

MNN

TNN

TensorRT

案例

模型是使用Pytorch训练的,部署的平台是英伟达的GPU服务器。

训练好的模型通过以下几种方式转换:

  • Pytorch->ONNX->trt onnx2trt 最成熟
  • Pytorch->trt torch2trt 较灵活
  • Pytorch->torchscipt->trt trtorch

常见的服务部署搭配:

  • triton server + TensorRT/libtorch
  • flask + Pytorch
  • Tensorflow Server

ONNX

ONNX结构的定义基本都在这一个onnx.proto文件里面

  • ModelProto
  • GraphProto
  • NodeProto
  • AttributeProto
  • ValueInfoProto
  • TensorProto

将ONNX模型load进来之后,得到的是一个ModelProto,包含了一些版本信息,生产者信息和一个非常重要的GraphProto

GraphProto中包含了四个关键的repeated数组,分别是node(NodeProto类型),input(ValueInfoProto类型),output(ValueInfoProto类型)和initializer(TensorProto类型),其中node中存放着模型中的所有计算节点,不仅仅包含我们一般理解中的图片输入的那个节点,还包含了模型当中所有权重。input中存放着模型所有的输入节点,output存放着模型所有的输出节点,initializer存放着模型所有的权重;

节点与节点之间的拓扑是如何定义的呢?每个计算节点都同样会有inputoutput这样的两个数组(不过都是普通的string类型),通过inputoutput的指向关系快速构建出一个深度学习模型的拓扑图。

最后每个计算节点当中还包含了一个AttributeProto数组,用于描述该节点的属性,例如Conv层的属性包含grouppadsstrides等等,具体每个计算节点的属性、输入和输出可以参考这个Operators.md文档。

onnx的部署

直接使用ONNX模型来做部署的话,有下列几种情况:第一种情况,目标平台是CUDA或者X86的话,又怕环境配置麻烦采坑,比较推荐使用的是微软的onnxruntime;第二种情况,而如果目标平台是CUDA又追求极致的效率的话,可以考虑转换成TensorRT;第三种情况,如果目标平台是ARM或者其他IoT设备,考虑使用端侧推理框架了,例如NCNN、MNN和MACE等等。