机器学习模型预测服务
Model Serving/Inference

机器学习技术将已有数据转变为模型,用于预测新的数据。大多数机器学习方法可以看做是学习一个函数,将输入数据(给定的trainX)映射到输出数据(给定的trainY),一旦这个函数学习完成,我们就可以用它来预测新的输入数据(TestX),从而得到我们预测的结果(TestY)。这是机器学习中学习本身的重点,可以称作是model-building。

模型预测服务,意味着我们想把预测这件事放到一个独立的节点(或模块)去处理。外界给到一条testX,制定一个model,服务就能够进行预测并传回一个所预测的testY。

设计原则

从训练环境到预测环境

Moving models from training to serving in production at scale. 一些常见的部署框架和工具包括

模型格式

模型存储格式对模型逻辑(结构+参数)的一种中间表示。类比:tensorflow/pytorch的python程序是高级语言; runtime硬件执行的程序是低级语言。 以下三类是当前常见的模型存储格式,均是把存储模型结构和模型参数分别存储。

onnx

ONNX是一个开源的机器学习模型格式。 onnx文件是一个ModelProto,它包含了一些版本信息,生产者信息和一个GraphProto。在GraphProto里面又包含了四个repeated数组,它们分别是node(NodeProto类型),input(ValueInfoProto类型),output(ValueInfoProto类型)和initializer(TensorProto类型),其中node中存放了模型中所有的计算节点,input存放了模型的输入节点,output存放了模型中所有的输出节点,initializer存放了模型的所有权重参数。

onnx opset

pytorch

pytoch参数状态字典。

tf

TF savedmodel。

模型分布式推理

将一个超大模型拆解部署在多个计算节点。(流量负载均衡、稀疏参数分布式,不在本章的讨论范围)

?

模型压缩 (model compression and acceleration)

模型太复杂、参数太多,对于成本的要求都是很高的。因而需要模型压缩技术来尽可能权衡效果和成本。 主流的模型压缩方法,包括量化、剪枝、蒸馏、稀疏化。

精度量化(参数精度压缩)

量化是指降低模型参数的数值表示精度,比如 从 FP32 降低到 FP16 或者 INT8

训练和推理的需求不同:在训练阶段,使用高精度的浮点数可以提供更好的模型收敛性和表达能力。而在推理阶段,使用低精度可以提供更高的计算效率。因此,直接在训练过程中使用低精度可能会降低模型的准确性和性能。训练过程中的梯度计算:训练过程中需要计算梯度来更新模型参数。使用低精度表示可能导致梯度计算的不准确性,从而影响模型的收敛性和训练效果。

对称量化

import numpy as np
n_bit = 4
xf= np.array([0.1,0.2,1.2,3,2.1,-2.1,-3.5])
xf= np.array([15,25,35,40,50, 60, 70])
range_xf=np.max(np.abs(xf))
print('range:{}'.format(range_xf))
alpha = (2**(n_bit-1)-1)/(range_xf)
print('alpha:{}'.format(alpha))
xq=np.round(alpha*xf)
print('xq:{}'.format(xq))
de_xf=xq/alpha
print('de_xf:{}'.format(de_xf))
print('error:{}'.format(np.abs(de_xf-xf)))
print('error(sum):{}'.format(np.sum(np.abs(de_xf-xf))))

非对称量化

import numpy as np
n_bit = 4
xf= np.array([0.1,0.2,1.2,3,2.1,-2.1,-3.5])
xf= np.array([15,25,35,40,50, 60, 70])

range_xf=np.max(xf)-np.min(xf)
print('range:{}'.format(range_xf))
alpha = (2**(n_bit-0)-1)/(range_xf)
print('alpha:{}'.format(alpha))
zp=np.round(np.min(xf)*alpha)
print('zeropoint:{}'.format(zp))
xq=np.round(alpha*xf)-zp
print('xq:{}'.format(xq))
de_xf=(xq+zp)/alpha
print('de_xf:{}'.format(de_xf))
print('error:{}'.format(np.abs(de_xf-xf)))
print('error(sum):{}'.format(np.sum(np.abs(de_xf-xf))))

量化工具:

Q:如何理解对weights(权值)进行量化?

Q:如何理解对activations(激活)进行量化?

Q:为什么有人说对激活量化对精度效果影响很大?

Q: llm.int8 所谓的 “绝大部分权重和激活用8bit量化,对离群特征的几个维度保留16bit,进行高精度的矩阵乘法。” 如何识别离群特征? https://arxiv.org/pdf/2208.07339 https://fancyerii.github.io/2024/01/16/int8/

Q: onnx_tensorrt_gpu 是怎么服务的?

参数个数压缩 (weight sharing)

复用取值相同的参数,用更少的数值表示更多的数。

剪枝 (Weight Pruning)

剪枝是指合理地利用策略删除神经网络中的部分参数,比如从单个权重到更高粒度组件如权重矩阵到通道,这种方法在视觉领域或其他较小语言模型中比较奏效。

蒸馏 (Knowledge Distillation)

蒸馏是指利用一个较小的学生模型去学习较大的老师模型中的重要信息而摒弃一些冗余信息的方法。 核心思想是通过迁移知识,从而通过训练好的大模型得到更加适合推理的小模型。

稀疏化

稀疏化将大量的冗余变量去除,简化模型的同时保留数据中最重要的信息。 大语言模型的稀疏化技术

低秩分解(Low-Rank Decomposition, low-rank factorization)

当矩阵的秩较低时(r « n, m),就可以视其为低秩矩阵。低秩矩阵意味着,此矩阵中有较多的行(或列)是线性相关的,即:信息冗余较大。

低秩分解的基本思想: 将原来大的权重矩阵分解成多个小的矩阵,用低秩矩阵近似原有权重矩阵。这样可以大大降低模型分解之后的计算量.

early exit

推理的时候提前结束,以优化推理速度。

token skipping

模型编译

模型编译是将定义好的模型结构和相关参数配置转化为可执行的计算图或计算图优化的过程。 在编译阶段,模型的结构和参数被转化为底层计算库或硬件设备可执行的指令序列,以便进行高效的计算和推理。

开源推理框架

onnxruntime

https://github.com/microsoft/onnxruntime 微软推出的一种模型标准,它设计了一种模型文件的表达结构,又实现了一个跨平台的执行引擎,用于在各种硬件设备上执行这个模型的推理过程。

TensorFlow Serving

https://github.com/tensorflow/serving TensorFlow Serving is a prediction serving system developed by Google to serve models trained in TensorFlow. Google称它的处理能力可以达到100000 requests per second per core。

TFlite

https://www.tensorflow.org/lite/guide

TorchServe

https://github.com/pytorch/serve

Clipper

https://github.com/ucbrise/clipper

Model Server for Apache MXNet

https://github.com/awslabs/mxnet-model-server

DeepDetect

https://github.com/jolibrain/deepdetect

Microsoft Contextual Decision Service

Microsoft Contextual Decision Service (and accompanying paper provides a cloud-based service for optimizing decisions using multi-armed bandit algorithms and reinforcement learning, using the same kinds of explore/exploit algorithms as the Thompson sampling of LASER or the selection policies of Clipper.

glow

https://github.com/pytorch/glow

TVM

https://tvm.apache.org/

直接打击计算密集算子 提供了基本的图优化功能 需要人工撰写算子schedule

MNN

MNN是阿里巴巴推出的一个高效、轻量的深度学习框架。 https://github.com/alibaba/MNN

TNN

腾讯推出的推理引擎。

https://github.com/Tencent/ncnn

https://github.com/Tencent/TNN

Ray Serve

https://docs.ray.io/en/latest/serve/index.html

Nvidia GPU 全家桶

在模型推理方面,NVIDIA提供了基于GPU加速的推理软件。

TensorRT (TRT)

Nvidia’s TensorRT is a deep learning optimizer and runtime for accelerating deep learning inference on Nvidia GPUs. TensorRT严格来讲并不是以一个model server框架,他的重点在于性能优化。但TensorRT提供了REST方式的服务支持。TensorRT中的profile指的是优化推理的配置,它定义了一组输入张量的形状范围,并允许TensorRT为这些范围内的各种形状生成高效的推理引擎。

概念上,

  1. profile 是一个重要的概念,特别是在处理动态形状(dynamic shapes)和优化推理性能时

使用上, 1.先把TF/PyTorch模型转换为ONNX格式

python -m tf2onnx.convert \
   --input /Path/to/resnet50.pb --inputs input_1:0 \
   --outputs probs/Softmax:0 --output resnet50.onnx 

2.得到onnx格式之后,通过 trt.builder 将onnx构建出一个trt engine (plan文件,该文件由trt engine序列化导出得到。 The .plan file is a serialized file format of the TensorRT engine.)

import tensorrt as trt

TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
trt_runtime = trt.Runtime(TRT_LOGGER)
def build_engine(onnx_path, shape = [1,224,224,3]):

   """
   This is the function to create the TensorRT engine
   Args:
      onnx_path : Path to onnx_file. 
      shape : Shape of the input of the ONNX file. 
  """
  with trt.Builder(TRT_LOGGER) as builder,\
    builder.create_network(1) as network, \
    builder.create_builder_config() as config, \
    trt.OnnxParser(network, TRT_LOGGER) as parser:
       config.max_workspace_size = (256 << 20)
       with open(onnx_path, 'rb') as model:
           parser.parse(model.read())
       network.get_input(0).shape = shape
       engine = builder.build_engine(network, config)
       return engine

def save_engine(engine, file_name):
   buf = engine.serialize()
   with open(file_name, 'wb') as f:
       f.write(buf)

def load_engine(trt_runtime, plan_path):
   with open(plan_path, 'rb') as f:
       engine_data = f.read()
   engine = trt_runtime.deserialize_cuda_engine(engine_data)
   return engine

上面是python用法,下面看看c++接口

deserializeCudaEngine

TensorFlow-TensorRT (TF-TRT)

TensorFlow-TensorRT (TF-TRT)是一个编译器,使Tensorflow模型享受到TensorRT的加速能力。

savedmodel转换器: TF-TRT编译器会把一部分子图会被替换成 TRTEngineOp,这部分节点由 TensorRT 在GPU上运行。一整个模型图可能会被拆解为由若干个TensorFlow节点和若干个TensorRT共同组成。

from tensorflow.python.compiler.tensorrt import trt_convert as trt
 
# Instantiate the TF-TRT converter
converter = trt.TrtGraphConverterV2(
   input_saved_model_dir=SAVED_MODEL_DIR,
   precision_mode=trt.TrtPrecisionMode.FP32
)
 
# Convert the model into TRT compatible segments
trt_func = converter.convert()
converter.summary()

转换器构建之后,就可以build出trt engine

MAX_BATCH_SIZE=128
def input_fn():
   batch_size = MAX_BATCH_SIZE
   x = x_test[0:batch_size, :]
   yield [x]
 
converter.build(input_fn=input_fn)

TF-TRT使用介绍

trtexec

https://github.com/NVIDIA/TensorRT/tree/main/samples/trtexec 这是一个命令行工具, 可以根据onnx模型文件生成tensorrt引擎文件; 可以直接加载tensorrt引擎文件做推理;

Triton

https://github.com/triton-inference-server/server#readme

Triton Inference Server is an open source inference serving software that streamlines AI inferencing. (在AI系统领域,Triton其实是个有些歧义的名字,因为至少有两个足够有影响力的Triton相关的AI系统的工作,一个是NVIDIA用于在线服务布署的Triton Inference Server,另一个是由OpenAI发起的高层次Kernel开发语言Triton。)

FasterTransformer -> TensorRT-LLM

Nvidia的FasterTransformer是一个开源的高效Transformer层实现。 基于 CUDA, cuBLAS, cuBLASLt and C++。

https://github.com/NVIDIA/FasterTransformer https://github.com/NVIDIA/TensorRT-LLM/

参考

*****
Written by Lu.dev on 25 March 2019