深度学习推理系统(一):TorchServe快速入门

Wings Lv1

为什么需要推理框架

上一篇文章已经提到,当前很多应用都增加了深度学习功能,但深度学习模型的一个特点是,模型能力越强,需要的算力也越多。这和传统的提供互联网服务有类似但也有不同,互联网的服务是不得不通过网络方式进行,比如移动支付需要进行网络验证,网络游戏,需要通过服务器通信。

而深度学习模型能力,其实可以不通过互联网的方式直接使用,但对于大部分的用户来说,为了使用模型能力本质上是使用背后的算力,所以不管是直接使用模型,还是使算力自主构建模型都只能通过服务的方式提供,前者直接通过访问模型厂商所提供的API服务,后者则需要自主购买算力服务。

那我们从模型厂商的视角出发,模型厂商本质上背后是拥有一群算力资源将其部署对应的模型服务提供给用户,那么为了更高效地提供模型服务,比如多个用户的模型服务请求,能否合并到模型进行计算,从而提升计算效率;亦或是将模型计算进行压缩,以更低地成本进行模型推理从而提供低成本的模型服务。

那么为了提供上述所说的模型推理服务,自然需要对应的组件,那就是推理框架,未来一段时间会逐渐介绍常用的推理框架: TorchServe,TFServe,Kserve,TritonServe,以及一些常见的推理框架。

PS

在写这篇推文的时候,TorchServe已经更新了一个公告,未来不会继续维护TorchServe这个仓库,感觉写着写着要给每一个曾经出现的推理框架进行一个一个祷告,但总之先开这个系列来介绍。

为了澄清一下概念:首先推理系统/本身是涵盖很多东西的,提供服务只是他对外所看到的一面,而如何提供服务,深度学习模型如何推理,背后需要用到推理引擎,还有现在的LLM大模型,VLLM的推理算法等,有时候还需要针对模型做优化,有模型结构上的优化,有基于硬件的模型计算优化等。

总之这一块并没有那么简单,后续就是遇到了就会额外说一下。

2 TorchServe的介绍与快速入门

2.1 TorchServe的背景

官方代码仓库:链接,实际上安装TorchServe是很简单的,它所需要的依赖很少,就是服务端的jdk-17和框架的一些基础依赖,不要求有推理引擎比如Pytorch,huggingface。

根据个人的调研,其实TorchServe一开始在2020年4月份出场就不被大家看好,从目前的最新消息,已经公布不会再进行更新来看,确实如此,经过了不到5年的时间TrochServe更新到0.12版本就已经停止更新了。

更新公告
不再积极维护

从个人的视角来猜测其被弃坑的情况,直接原因是团队对这一块的已经没有精力维护,后续的更新也只是维护这个框架的漏洞,但我个人的猜测更多是,在2020年的深度学习模型主要还是以小模型为主,而在2023年以后,大模型的兴起,使得之前这种基于小模型推理的框架很难适应大模型推理的到来,特别是,该框架在个人使用的过程中,他的推理引擎实际上可以用各种引擎,不止Pytorch本身。

虽然叫做TorchServe,但实际上没有Pytorch作为引擎推理模型也是可以的,所以换句话说,虽然网上大部分材料说该框架限制在Pytorch引擎,但由于其本质上是启动Java作为服务端和python运行模型程序,而只需要符合TorchServe框架的模型推理规范文件即可。

话不多说,开始介绍本文的主角TorchServe吧。

2.2 TorchServe入门前的碎碎念

如果是23年之前,我可能会以TorchServe的官方Get Start进行介绍并快速入门TorchServe。

现在的“不再积极维护”其实也可以预见,相关的资料可能存在与当前版本对不上的情况,这就导致Github的教程实际上和官网Pytorch的教程是存在偏差的,具体来说,是因为后续更新中增加了一个安全策略,使得一些命令不能直接使用,所以最终导致的结果就是无法直接调用模型服务。

此外,由于之前在2020年左右,深度学习领域主要还是以小模型为主(其特点有,占用显存小,可以做batch多个输入合并计算等特点),所以利用TorchServe开发模型的思路主要是以小模型为主,比如教程所述的图像分类的模型,通过torch-model-archiver将其压入.mar文件,方便在后续的torchserve中启动。

但是在2023年以后,或者说,深度学习存在一个特点是,当模型参数越多的时候在有充足的数据下是能够越做越好,虽然能够越做越好,但存在的一个问题是:模型也越来越大,所以如果你在2023年入门推理框架,并且选择了TorchServe,那么你甚至不能按照当前的教程直接部署大参数的深度学习,比如3B,7B,13B等,因为这些模型文件本身就有几G,导致你在构建.mar时候,由于本质上.mar是将模型文件压缩在.mar文件里面以及在后续部署的时候将.mar解压执行对应的文件。这就导致,不仅.mar文件特别大移动困难,且在部署的时候,还需要从.mar中解压出对应的模型文件,这需要大量的时间。

所以如果是2023年以后再来入门TorchServe,就根本不能从.mar文件出发,那应该如何做才能部署大参数模型呢?其实TorchServe在github仓库中给出了一些解决方案,因为TorchServe已经是支持大参数模型的构建,比如扩散模型,比如LLM,所以我们仍然能够通过TorchServe构建大参数模型的推理服务。

接下来就是介绍一个快速入门的方式,不得不说,在写这份入门经验,刚好看到TorchServe更新不再积极维护,或许这份入门教材可以生存很久。

2.3 TorchServe的快速入门与开发指南

在这里以TorchServe官方所提供的案例huggingface_Transformers作为例子快速入门与开发:案例代码。同时,通过这份案例就能够知道,为什么TorchServe本身并不限制Pytorch作为推理引擎,事实上它是支持其他深度学习引擎比如huggingface等。

首先,从这份例子以及README.md文档能够了解如何开发,首先,该模型是一个Transformer模型,该模型支持多个功能,比如序列分类、QA、Token分类和对话等功能,但是在部署的时候,只能选择一个模型功能,为什么呢?

这就要说到,TorchServe真正的处理逻辑是带handler的python代码文件,里面已经说清楚了该模型的处理逻辑,而model-config.yaml则配置模型的参数文件,通过加载配置文件就已经确定了当前模型的功能,比如这份文档的默认参数配置:mode: sequence_classification

换句话说,我们在开发我们的模型的时候,主要就是符合handler.py的形式,通过torch-model-archiver命令将我们的模型文件打包即可。 那么首先我们先来看给出案例的handler是什么?这里列出handle.py必要的形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from ts.torch_handler.base_handler import BaseHandler
# 基础库加载
class TransformersSeqClassifierHandler(BaseHandler):
def __init__(self):
'''
这里是整类的初始化,主要是做参数上的初始化,可以省略
'''

def initialize(self, ctx):
'''
这里是服务的初始化,其中ctx就是传入控制模型的参数。
ctx读取的是目录下指定的配置文件信息config.yaml
通过该配置信息就能够控制模型,包括模型的worker、batchsize,以及模型本身的自定义参数。

定位:通过配置信息初始化模型服务。
'''

def preprocess(self, requests):
'''
这里是模型的预处理,都是也是请求传入的接口。
requests与python自带解析API请求的requests是类似的,传入的是字典,通过API固定下来。

定位:对用户请求进行预处理。
'''
return # 返回处理结果,会抵达下面的inference函数

def inference(self, input_batch):
'''
这里部分是模型推理部分,input_batch就是预处理函数处理以后所返回的结果。
所以经常,如果我们所使用的引擎比如pytorch,为了减少计算,比如梯度等加快推理,所以在这里就可以使用no_grad等函数进行包装。

定位:对请求进行模型推理。
'''
return inferences

def postprocess(self, inference_output):
'''
定位:对推理结果进行后处理,返回给用户
'''
return inference_output

通过上述的handler.py的关键形式,就能够快速理解TorchServe每一个服务的处理逻辑,而开发的时候也可以按照这样的逻辑进行开发,对每一个用户请求进行前处理,模型推理以及后处理三阶段进行处理。

接着构建好你的模型处理逻辑以后,就需要将其进行打包,以便后续模型启动的时候能够识别模型处理逻辑文件,此时使用的就是model-archiver进行打包,通过该命令能够将相关的文件进行打包处理。

model-archiver的命令参数含义在链接可以看到。注意到archive-format参数,有四种选择,就可以选择no-archive选项,虽然进行打包了但并没有真的进行压缩,该参数实际上只会输出一个文件夹,而该文件夹实际上就是之前内容的复制,从这里可以看出,如果使用其他选项打包成单独压缩文件,本质上就是将这些文件进行整理打包以不遗漏组件能够快速启动,有一种文件版的docker镜像的样子。

从docker的视角来看,此时就相当于将程序必要的文件进行整理与打包,在后续的启动中能够完整启动。如果是小文件,这一点没有问题,但是当我们的模型文件特别大的时候,哪怕使用了压缩都需要很长的时间,这可能就不是一个很好地方式,类似docker也不会将数据文件打包进入docker镜像。

那么打包以后,我们就可以利用trochserve命令启动从而执行我们的逻辑函数,进而部署我们模型以提供服务。TorchServe命令本身也有一些配置文件,需要配置,具体和后面的略微进阶一块说。

TorchServe的API提供三种方式,默认端口是8080和8081,其中8080为模型推理端口,8081为模型管理端口,具体可参考文档:inference_apimanagement_api

作为基础入门就已经可以结束了。

2.4 略微进阶

如果只是完场上述的流程,那么只是利用了这个TorchServe开启了一个模型,如果仅此而已,那么与自定义的Fastapi或者Flask然后再部署对应的模型其实没有本质上的区别。可能会说,TorchServe是不是提供了模型优化,比如可以使用torchscript或者torch.compile对模型进行编译从而加速?亦或是采用onnxtorch-TensorRT对模型加速等等,所以使用这个框架就能够得到更好地性能?

事实上,上述的模型优化,在Fastapi和Flask上依然可以使用,所以这并不是这个框架的特点。这也是为什么个人认为,从这个框架入手是一个相对平缓的方式。这个框架除了提供一般的组件,比如模型打包,规范API等功能,更重要一点也是提供了规范编写模型处理服务的框架,即handler.py的文件中的类handler。

除此之外,自然该框架还有其他的特点:

推理框架所提供的特性

  1. 模型多副本worker。为了缓解用户请求的需求量,我们可以简单地启动多个模型副本为用户提供服务,且用户请求能够较好地分配到不同的服务上。单纯使用Fastapi和Flask实现起来就会比较复杂,是因为这是超越Fastapi和flask的逻辑,他们只负责一个服务,而无多服务之间的调度逻辑。

  2. 合并请求。有一些深度学习模型,实际上是可以一次性处理多个请求需求,比如图像分类服务,多个图片通过预处理进行变换成同大小的图片,就可以让模型一次性处理多张图片共同返回请求从而提高模型本身的吞吐量。

  3. 在用户请求较多的时候,通过判断请求时延来推断worker的负载情况,从而自动伸缩对应的worker数量,以缓解短时间来的请求过多的任务,比如休息时间请求较少,而工作时间请求较多的情况。

  4. 自动选择GPU启动模型。很多时候,我们的模型都需要GPU才能够启动,而TorchServe提供一个自动选择GPU的方式来启动我们的模型,一般都是均匀分配的,所以能够平缓地使用GPU资源。

那么如何控制,有什么参数,实际上上述的例子已经有告诉大家了,可以看这个来获得所有参数的含义,可以参考:链接

在这里主要是做一个提醒:有一些配置是启动TorchServe的配置,而有一些配置是针对模型本身的配置,这两点是需要分清楚的。

3 题外话

其实本来是想仔细写好TorchServe的入门介绍的,因为就我个人经验来看,TorchServe应该是最简单以及最快能够体验并且理解推理系统的作用的。同时其安装比较简单,哪怕不使用docker也能够快速安装,因为它本质上是与其他推理引擎分隔开来的。

甚至我们可以来讨论一下,为什么TorchServe要停止更新了:个人的观点——从一开始就是爹不亲妈不爱的状况。

首先,虽然TorchServe名义上是在Pytorch下面的一个代码库,为Pytorch服务,但它本身也可以脱离Pytorch的推理引擎,那么从另一方面来说,框架本身并没有和Pytorch很好地融合起来(比如推理加速,更底层地优化等),而只是提供了一个基础的推理特性,这个特性在其他的推理框架上都存在,甚至做得更好,

其次,推理框架一开始的出发点是小模型的快速部署,做了模型打包,模型工作流,以及常见的模型类,分类,回归等,在现代大参数模型的背景下都没人关注。

所以,最终迎来了自己终结(不再积极维护)的结局。

但是,如果是想要入门推理框架,TorchServe作为一个拥有基础推理框架特性且安装简单。对于小白来说,快速熟悉框架特性是一个比较不错的选择。当然,作为生产力工具,其仍然面临自己的问题,比如多模型的部署,多个模型之间如何配合,以及上述的端口请求如何合并,多个模型的版本的管理(主要是以文件的形式管理)所提供的支持都是比较弱的,当然,我们也可以这么说,我们只是写好服务,而至于API请求,模型管理应该交给其他组件来做,我们只需要负责模型服务的逻辑已经提供一个约定好的访问请求范式就好了。这当然也没有问题。

但从生产的角度,特别是当前的模型服务提供厂商,这些又是必须要解决的问题,所以TorchServe确实处在一个尴尬的状况,最终也确实再难以维系下去...

  • 标题: 深度学习推理系统(一):TorchServe快速入门
  • 作者: Wings
  • 创建于 : 2025-03-30 10:08:38
  • 更新于 : 2025-03-30 11:17:15
  • 链接: https://www.wingslab.top/深度学习推理系统/深度学习推理系统(一):TorchServe快速入门/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。