推理引擎

推理系统与推理引擎

训练和推理服务

推理和训练的区别:

  • 模型部署后,长期运行;
  • 不需要反向传播;
  • 部署设备更加多样。

推理服务系统的功能(与 AI 算法关系不大,更多地是平台性的工作):

  • 模型加载;
  • 版本管理;
  • 数据管理;
  • 服务接口。

优化目标

  • 低延迟;
  • 高吞吐:高负载;
  • 高效率:低功耗使用 CPU/GPU;
  • 灵活性:支持多框架;
  • 扩展性。

部署态

场景:数据中心的服务端、边缘侧的移动端。

  • 云端;
  • 边侧:严格约束功耗、算力不足、数据分散、平台多样化。

推理系统架构

推理服务化、推理服务框架。

基本概念:

  • 推理:前向计算;
  • 部署:将模型部署到硬件上,包括:移植、压缩、加速等;
  • 服务化:将模型封装为 sdk 或 web 服务。

Triton 服务化框架:

  • 接入层:HTTP、gRPC、CAPI;
  • 模型仓库;
  • 模型预编排:解析 URL 请求;
  • 框架后端:指推理引擎(如 TensorRT、ONNX Runtime、MindSpore Lite 等);
  • 监控功能:健康管理。

模型版本管理

模型生命周期管理:

  • 金丝雀策略(Canary);
  • 回滚策略(Rollback)。

推理引擎介绍

特点:

  • 高性能:充分发挥芯片算力;
  • 轻量化:端侧部署(手机、手表);
  • 通用性:支持多种主流模型文件格式、主流网络结构、嵌入式设备、操作系统;
  • 易用性:提供丰富的 API。

技术挑战:

  • 需要适配不同 AI 框架的大量算子;
  • 需要深入优化计算资源的性能;
  • 需要端侧的模型变小(压缩),但精度保持不变(有限的精度损失)。

推理引擎架构

  • API 接口;
  • 模型格式转换、图优化;
  • 模型压缩:量化、蒸馏、剪枝、二值化;
  • 端侧学习:联邦学习、增量学习;
  • 其它:性能测试等;
  • IR/Schema:中间表达(推理引擎自己的模型格式、计算图?);
  • Runtime:模型加载、模型执行,功能包括:动态 Batch、内存分配、大小核调度;
  • 高性能算子层(Kernel 层):算子优化、算子执行、算子调度。

推理流程

  1. 模型转换:将多种 AI 框架训练得到的模型转换为推理引擎所需的格式,得到推理模型;
  2. 对推理模型进行模型压缩;
  3. 准备环境:拉取模型等;
  4. 开发/编译推理程序:
    1. 模型离线转换;
    2. 推理配置管理:模型路径、运行 Kernel、优化选项;
    3. 调用推理引擎:图优化、算子融合、内存优化;
    4. 执行推理过程。
  5. 执行推理:在推理引擎的 Runtime 中运行模型。

模型压缩

模型压缩的好处

  • 减少模型大小:节省内存;
  • 加快训练速度;
  • 保持相同精度。

模型量化

模型量化:将浮点计算转成低比特定点计算(FP32/FP16 -> INT16/INT8/INT4),可以有效降低模型的计算强度、参数大小和内存消耗,但往往带来精度上的损失。

量化方法:

  • 量化训练(感知量化,QAT):让模型感知量化运算对模型精度带来的影响,使用大量带标签的数据进行 finetune;
  • 动态离线量化(动态训练后量化,PTQ dynamic):仅将模型中特定算子的权重从 FP32 映射成 INT8/16;
  • 静态离线量化(静态训练后量化,PTQ static):使用少量无标签的数据进行校准。

量化的原理:在定点与浮点之间建立数据映射关系,以较小的精度损失为代价获得较好的收益。

量化的类型:

  • 对称量化:-127 ~ 127;
  • 非对称量化:0 ~ 255。

模型小型化

推理参数介绍

  • FLOPs(浮点运算次数):计算量,用于衡量算法/模型的时间复杂度;
  • FLOPS(每秒执行的浮点运算次数):计算速度,用于衡量硬件性能(芯片算力)/模型速度;
  • MACCs(乘加操作次数):大约是 FLOPs 的一半;
  • Params(模型参数数量):单位是 M,训练时参数通常使用 float32,因此模型大小是参数数量的 4 倍;
  • MAC(内存访问代价):单个样本完成一次前向传播所需的内存交换总量,用于衡量模型的空间复杂度,单位是 Byte;
  • 内存带宽:将数据从内存移动到计算核心的速度。

Transformer 小型化

Kernel 优化

Kernel 层

Kernel 层:高性能算子层,供 Runtime 调度。

  • 人工高性能算子;
  • 高性能算子库。

Img2Col 算法

算法原理:对 kernel 和 input 数据进行重新排列,从而将卷积操作转换为矩阵相乘。具体地,将输入数据按卷积窗进行展开,并存储在矩阵的列中,多个通道的数据展开后拼接到矩阵的同一列中。最后,直接使用 GEMM 将两个矩阵相乘,得到输出矩阵。

  • 优点:高性能矩阵乘法库;
  • 缺点:多余的内存开销。

空间组合优化

算法原理:将大卷积计算拆分为若干个小卷积进行计算,计算总量不变,但计算小矩阵时,访存局部性更好,从而获得性能上的提升。

推理内存布局

Tensor 内存布局:

  • NCHW:以 GPU/NPU 为基础的 PyTorch 和 MindSpore 框架默认使用该格式,更适合并行操作,适合对每个通道单独做运算的操作(如 MaxPooling);
  • NHWC:推理引擎(大多以 Arm CPU 作为主要的计算单元)大多使用该格式,适合对不同通道的同一像素做某种运算的操作(如 Conv);
  • NCHWX。

模型转换与图优化

挑战 & 目标

推理引擎中模型转换模块的挑战:

  • 需要有自己的算子定义和格式,来对接不同 AI 框架的算子层;
  • 需要有自定义的计算图 IR,来对接不同 AI 框架的计算图(对接多种文件格式);
  • 需要有丰富的 Demo 和 Benchmark,来为主流的模型(网络结构)提供性能和功能基准;
  • 需要有良好的可扩展性,来支持多种 AI 特性。

推理引擎中优化模块的挑战:

  • 结构冗余:如无效的计算节点、重复的计算子图、相同的结构模块,去除冗余的同时保持计算图语义 -> 计算图优化:算子融合、算子替换、常量折叠等;
  • 精度冗余:压缩精度 -> 模型压缩:低比特量化、剪枝、蒸馏等;
  • 算法冗余:算子或 kernel 层面的算法本身冗余 -> 统一算子/计算图表达:kernel 提升泛化性;
  • 读写冗余:重复读写内存 -> 数据排布/内存分配优化

架构与流程

转换模块(Converter)架构:

  • Graph Converter(Frontends):负责支持不同的 AI 训练框架;
  • Graph Optimize:通过算子融合、算子替代、布局调整等方式优化计算图。

转换流程:

  1. 多种 AI 训练框架的模型格式,通过 Converter 转换为统一的 Inference IR,后续基于该 IR 进行图优化;
  2. Pre Optimize:公共表达式消除、死代码消除、代数简化;
  3. Optimize:算子融合、算子替换、常量折叠;
  4. Pos Optimize:数据格式转换、内存布局计算、重复算子合并。

模型格式转换

  • 模型序列化:将训练好的模型存储起来;
  • 模型反序列化:将硬盘中的二进制数据反序列化到内存中,得到模型对应的内存对象。

PyTorch 模型序列化(模型导出):torch.onnx.export()

目标文件格式:ProtoBuffer/FlatBuffer(推理引擎使用较多)。

自定义计算图

计算图的基本组成:

  • 基本数据结构:Tensor(张量);
  • 基本运算单元:Operator(算子);
  • 控制流。

不同计算图的区别:

  • AI 框架:前向传播+反向传播、动态图+静态图、支持分布式并行;
  • 推理引擎:反向传播、静态图为主、单卡推理为主。

张量的定义:

  • 数据维度(shape);
  • 数据内存排布格式;
  • 数据类型。

算子的定义(不同框架可能不同):

  • 输入数据;
  • 输出数据;
  • 算子公共属性和参数;
  • 算子类型;
  • 算子名称。

计算图的定义:

  • 网络模型:模型名称、输入 Tensor 名称、输出 Tensor 名称、算子列表、子图列表等;
  • 网络模型子图:子图名称、输入、输出、Tensor、节点(算子列表)等。

模型转换流程

  1. AI 框架:生成计算图;
  2. Converter:算子对接;
  3. Converter:格式转换;
  4. Converter:模型保存与导出。