模型部署需要的技术栈还是比较复杂的,不仅需要底层并行知识,还需要模型算法知识,不过对于两者的要求都不是很高,只需要能看得懂最新进展,能跟着复现就行,模型部署,最重要的还是工程能力。
模型有几种形式
模型的形式很多种,模型部署说到底还是编程任务,是用代码来实现一套函数,只不过这个函数中的参数都被提取出来封装到了一起,称为模型。
也正是因为如此,不同的框架不同的代码生成的模型格式五花八门,从Pytorch到tf到mxnet等训练框架,他们保持的模型各不相同,我们首先要解决的就是统一模型格式,这里的统一格式并不是指文件的后缀一样就可以了,而是指所要支持的算子要统一。
Pytorch
- 保存为pt文件或者pth文件,pytorch导出模型有两种方案:第一种是不仅仅包含参数,还包含了模型结构,读取的时候不需要预先建立模型,第二种是仅仅包含参数,读取之前需要将模型建立好,通过pth文件往里面填参数。但是第一种的方案也不是挪到任何地方都可以直接用,还是要有模型定义代码,也就是说这两种模型都只能由pytorch使用。
# Define model
class TheModelClass(nn.Module):
def __init__(self):
super(TheModelClass, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# Initialize model
model = TheModelClass()
# Initialize optimizer
model.eval() # 导出前一定要设定为和目标用途一致的模式,否则有可能导致结果不同,因为dropout等层在训练和推理时作用是不一样的。
torch.save(model.state_dict(), PATH) # 保存参数,不保存结构
torch.save(model, PATH) # 保存参数和格式,其实这种不应该叫导出,而是直接把model的二进制数据整体压缩保存起来。
pytorch还支持另一种导出:导出成torchscript格式,这种确确实实是将模型结构和参数都保存了,不仅可以用在pytorch,还可以用在C++推理,不过C++推理依旧需要torchlib,相当于还是离不开torch。
model_scripted = torch.jit.script(model) # Export to TorchScript
model_scripted.save('model_scripted.pt') # Save
onnx
pytorch导出的模型离不开pytorch,tf导出的模型离不开tf,这么搞下去怎么大家还怎么一起玩?所以几个巨头牵头提出了onnx,onnx是一套开放的中间格式标准,目前大部分深度学习相关的工具都支持onnx。onnx与训练框架,推理框架都无关。
onnx模型由三部分组成:
- 节点Node:就是神经网络中的一层
- 输入Input:存储了输入矩阵的维度信息
- 初始化器Initializer:存储了权重和参数
三种之间相互关联,相互依赖,很难修改。
在编译器领域,为了支持不同的编程语言和不同的运行平台,提出了一种与编程语言和运行平台无关的中间表达语言称为IR,onnx也可以看作是深度学习领域的IR。
推理系统
有了通用的模型格式,深度学习要融入到整个产品中需要设计成一个单独的系统,响应处理外界请求,这就是推理系统的工作。
推理系统需要考虑包括模型管理,服务接口设计,系统监控,系统调度等,推理系统更多的是将推理工作包装成一个服务,供外界使用。
推理系统需要考虑的事情:
- 吞吐量
- 相应效率
- 扩展性
- 灵活性
推理系统再调用推理引擎进行模型推理
推理引擎
推理引擎主要做的就是:优化模型,实现核心算子,开发目标平台调度引擎。本来像OpenVINO和TensorRT这种是厂家做出来的,支持的平台也只有他们自己的平台。随着深度学习大火,各种推理框架都发展了起来,推理引擎主要做三件事情:1、模型,2、算子实现,3、runtime调度引擎。
AI编译器
但是深度学习越发展,模型越来越复杂,如何能高效运行,提高模型性能,成了一大难题,为了解决这一问题,提出了AI编译器,AI编译器的主要目的是:进行模型图优化,算子优化,生成目标平台代码。
这里也体现了AI编译器和AI推理引擎的异同:
相同之处:都是以AI模型作为输入
不同之处:AI编译器主要任务是输出目标平台高性能代码,AI推理引擎是在目标平台上高效运行,得到结果。
模型部署的常见工具
编程语言
Pytorch
C++
推理引擎
Onnxruntime:onnx项目配套推理引擎
TensorRT:英伟达的推理引擎,主要用于英伟达产品
OpenVINO:英特尔的推理引擎,主要用于英特尔产品
ncnn:腾讯做的手机端的推理引擎
onnx-MLIR:以MLIR为后端的一个推理引擎
推理引擎,推理系统,在理论上是这么分的,但是实际开发起来,有的厂商就一套做到了一起,所以对于一个工具有时候不需要特别在乎他到底是什么层的,会用就行。
高性能算子库
cudnn:英伟达提供的高性能算子库
AI编译器
TVM:AI编译器,这个过程会对模型进行一系列优化
MLIR:编译器框架
看到有一种说法:AI编译器也可以理解为编译性推理框架,AI编译器可以将模型编译成硬件级优化后的模型,也可以直接编译成目标代码。如果编译成优化后的模型,还是需要推理引擎进行推理。传统的推理引擎被称为解释型推理引擎,相较于传统推理引擎,AI编译器能做的优化更多。
配套工具:
transformers:huggingface提供的一个模型库,包括很多模型
Optimum:huggingface开发的一个用于优化模型的transformers插件,只做优化,推理还是调用推理引擎进行推理。
容器docker,k8s:为了解决运行时环境依赖与资源隔离
gRPC:跨语言跨进程通信
模型部署的工作内容
模型部署的工作主要包括:
模型压缩
模型优化
Kernel优化
如果算子不支持,还要手写算子。
所以cuda也要学
还有需要注意的一点是:使用推理框架,跟开发推理框架,是两码事,工作内容也不同。
模型部署的发展趋势
在模型越来越复杂的同时,模型部署发展的主要方向就是如何更高效地推理,提高推理速度,提高对深度学习的支持度。
目前一个大的发展趋势就是,软硬件两面开弓,软件方面AI编译器MLIR,TVM等,另一方面AI专用芯片:TPU,NPU等等,最近大火的groq芯片,大模型推理速度超英伟达10倍。
在这两者之外,还有一个发展方向:MLOps,深度学习服务,这个方向的主要目的是将深度学习融入到产品开发流程和服务开发流程中来,将深度学习的产品化流程进行标准化,并提供相应的配套工具。