【大模型实战篇】vLLM的由来以及大模型部署、推理加速实践

1. 问题背景分析及vLLM的由来

        大模型毫无疑问,在工作、生活中已经逐渐扮演越来越重要的角色。但大模型的尺寸一般都比较大,处理一个大模型请求的成本可能比传统关键字查询高出 10 倍。推理的成本代价较高,因此提高大模型服务系统的吞吐量,从而降低每次请求的成本,变得越来越重要【1】。

        大模型的核心是自回归Transformer 模型,该模型基于输入提示词和先前生成的序列逐个 token生成输出。每个请求都会重复这一高耗资源的过程,直到模型输出终止 token。这种序列生成过程使得任务受内存限制,未充分利用 GPU 的计算能力,限制了服务吞吐量。可以通过将多个请求一起批处理来提高吞吐量。为了批处理多个请求,必须高效管理每个请求的内存。一般上,约 65% 的内存分配用于模型权重,在服务期间保持不变。接近 30% 的内存用于存储请求的动态状态。对于 Transformer 模型,这些状态由注意力机制的键和值张量组成,也称为 KV 缓存,用于表示从之前的 token 生成新输出 token 的上下文。剩余的少量内存用于其他数据,包括评估大模型时创建的瞬时张量。由于模型权重是常量,激活仅占用 GPU 内存的一小部分,KV 缓存的管理方式对于确定最大批处理大小至关重要。如果管理不当,KV 缓存内存会显著限制批处理大小,从而影响大模型的吞吐量。

        部分大模型服务系统在管理KV缓存内存方面比较一般,主要原因是它们将每个请求的KV缓存存储在连续的内存空间,但是与传统深度学习任务中的张量不同,KV缓存有一些自己的特点,它会随着模型生成新token而动态增长和收缩,生命周期和长度在事先也不可知。所以这种特性会导致现有系统在两个方面效率明显下降:

        (1)现有系统会受到内存碎片的影响。为了在连续空间中存储请求的KV缓存,系统会根据请求的最大长度,比如2048个token,预分配连续的内存块。这可能会造成碎片的形成,因为请求的实际长度可能远小于最大长度。另外,在请求的生命周期内,整个内存块被保留,其他较短的请求无法使用未被占用的部分。由于每个请求的预分配大小存在差异,可能会出现外部内存碎片。据统计,现有系统仅有20%到40%之间的KV缓存内存用于存储实际token状态,其他部分都是碎片。

        (2)其次,现有系统无法利用内存共享的机会。大模型服务一般涉及解码算法,如并行采样和束搜索,每个请求生成多个输出。在这些场景中,请求由多个序列组成,这些序列可以部分共享它们的KV缓存。但是在现有系统中不可能进行内存共享,因为序列的KV缓存存储在单独的连续空间中。

        鉴于上述存在的内存问题,【1】提出了PagedAttention,一种借鉴虚拟内存与分页的处理思想。关于PA的描述,可以参考《自注意力机制计算加速工程优化技巧》。PagedAttention将请求的KV缓存划分为块,每个块可以包含固定数量的token的注意力键和值。在PagedAttention中,KV缓存的块不一定存储在连续的空间中。因此,可以像操作系统的虚拟内存一样更灵活地管理KV缓存:可以将块视为页面,tokens视为字节,请求视为进程。这种设计通过使用相对较小的块并按需分配它们来减轻内部碎片化。此外,它消除了外部碎片化,因为所有块的大小相同。最后,它在块的粒度上启用内存共享,跨越与同一请求相关联的不同序列,甚至跨越不同的请求。

2. vLLM及模型部署推理实践

       vLLM就是一个基于PagedAttention的高吞吐量分布式LLM服务引擎,实现了KV缓存内存几乎零浪费。vLLM使用与PagedAttention共同设计的块级内存管理和抢占式请求调度。老样子,因为国内的网络环境,我们依然利用modelscope模型库中的大模型来做实践,并且modelscope推出了ms-swift框架【2】,能够支持vLLM的大模型部署和推理。如果想研究最纯正版本的vLLM,建议看vLLM项目【3,4,5】。

        【6】罗列了一些常用大模型推理框架并做了相关特性对比。

  1. vLLM:适用于大批量Prompt输入,并对推理速度要求高的场景;
  2. Text generation inference:依赖HuggingFace模型,并且不需要为核心模型增加多个adapter的场景;
  3. CTranslate2:可在CPU上进行推理;
  4. OpenLLM:为核心模型添加adapter并使用HuggingFace Agents,尤其是不完全依赖PyTorch;
  5. Ray Serve:稳定的Pipeline和灵活的部署,适合更成熟的项目;
  6. MLC LLM:可在客户端(边缘计算)(例如,在Android或iPhone平台上)本地部署LLM;
  7. DeepSpeed-MII:使用DeepSpeed库来部署LLM;

        本文主要是采用ms-swift(Scalable lightWeight Infrastructure for Fine-Tuning)框架来实施vllm模型的部署和推理【7,8】。         

        SWIFT是基于PyTorch的轻量级、开箱即用的模型微调、推理框架。集成了各类开源tuners,如LoRA、QLoRA、Adapter等,并且融合了ModelScope特有tuner ResTuning。

2.1 环境准备

GPU设备

3090

使用nvidia-smi查看cuda版本

配置全局镜像        

pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/

安装三方包(搞工程最麻烦的环节可能就是配置环境 ,会出现一些包版本不兼容冲突,需要挨个处理

# 仅使用llm能力

pip install 'ms-swift[llm]' -U


pip install vllm
pip install openai -U        

可能在运行代码的时候会出现报错:

AttributeError: module 'tensorflow._api.v2.compat.v2.__internal__' has no attribute 'register_load_context_function'

需要重新安装一下tensorflow,我后来用的版本是2.12.0, 最新版本2.18.0会出现numpy的版本兼容性问题。

运行代码的时候还出了个小插曲,因为在root目录下启动jupyter操作,下载模型直接给撑爆了磁盘,后续切换了工作目录区。

jupyter下需要更改配置:

通过指令jupyter notebook --generate-config找到配置文件

然后修改其中的c.NotebookApp.notebook_dir配置

另外,代码中增加一行地址指定配置:

os.environ['MODELSCOPE_CACHE']='/data/llm'

2.2 vLLM部署Qwen-7B及推理

代码参考【7,10】

2.2.1 单卡推理

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['MODELSCOPE_CACHE']='/data/llm'from swift.llm import (ModelType, get_vllm_engine, get_default_template_type,get_template, inference_vllm, inference_stream_vllm
)model_type = ModelType.qwen_7b_chat
model_id_or_path = None
llm_engine = get_vllm_engine(model_type, model_id_or_path=model_id_or_path)
template_type = get_default_template_type(model_type)
template = get_template(template_type, llm_engine.hf_tokenizer)
llm_engine.generation_config.max_new_tokens = 256
generation_info = {}request_list = [{'query': '你好!'}, {'query': '江苏哪个城市最有活力?'}]
resp_list = inference_vllm(llm_engine, template, request_list, generation_info=generation_info)
for request, resp in zip(request_list, resp_list):print(f"query: {request['query']}")print(f"response: {resp['response']}")
print(generation_info)history1 = resp_list[1]['history']
request_list = [{'query': '这有什么好玩的景点', 'history': history1}]
gen = inference_stream_vllm(llm_engine, template, request_list, generation_info=generation_info)
query = request_list[0]['query']
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for resp_list in gen:resp = resp_list[0]response = resp['response']delta = response[print_idx:]print(delta, end='', flush=True)print_idx = len(response)
print()history = resp_list[0]['history']
print(f'history: {history}')
print(generation_info)

       

# 批量回答
request_list = [{'query': '帮我出一道研究生数学题!'}, {'query': '浙江杭州笤溪会在哪年拆迁?'}, {'query': '浙江金华当地有哪些小吃?'}]
resp_list = inference_vllm(llm_engine, template, request_list, generation_info=generation_info)
for request, resp in zip(request_list, resp_list):print(f"query: {request['query']}")print(f"response: {resp['response']}")
print(generation_info)# 基于历史记忆回答
history1 = resp_list[1]['history']
request_list = [{'query': '这有什么好玩的景点', 'history': history1}]
gen = inference_stream_vllm(llm_engine, template, request_list, generation_info=generation_info)
query = request_list[0]['query']
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for resp_list in gen:resp = resp_list[0]response = resp['response']delta = response[print_idx:]print(delta, end='', flush=True)print_idx = len(response)
print()history = resp_list[0]['history']
print(f'history: {history}')
print(generation_info)

2.2.2 双卡推理

import os
# 用两张卡
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
os.environ['MODELSCOPE_CACHE']='/data/llm'from swift.llm import (ModelType, get_vllm_engine, get_default_template_type,get_template, inference_vllm, inference_stream_vllm
)model_type = ModelType.qwen_7b_chat
model_id_or_path = None
llm_engine = get_vllm_engine(model_type, model_id_or_path=model_id_or_path)
template_type = get_default_template_type(model_type)
template = get_template(template_type, llm_engine.hf_tokenizer)
llm_engine.generation_config.max_new_tokens = 256
generation_info = {}

2.2.3 使用命令行启动的方式

CUDA_VISIBLE_DEVICES=0 swift infer --model_type qwen-7b-chat --infer_backend vllm

2.2.4 服务端部署

CUDA_VISIBLE_DEVICES=0 swift deploy --model_type qwen-7b-chat

curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-7b-chat",
"messages": [{"role": "user", "content": "最近取得了很多突破,感觉很好,你怎么看?"}],
"max_tokens": 256,
"temperature": 0
}'

调节温度:

扩展阅读:

《全方位解读大模型:多样知识点的深度探讨与技术分享小结》

3. 参考材料

【1】Efficient Memory Management for Large Language Model Serving with PagedAttention

【2】https://github.com/modelscope/ms-swift/

【3】vllm:Easy, fast, and cheap LLM serving for everyone

【4】Deploying LLMs with TorchServe + vLLM

【5】vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention

【6】llm推理框架简单总结

【7】VLLM Inference Acceleration and Deployment

【8】SWIFT:魔搭社区轻量级微调推理框架

【9】基于Swift搭建一个大模型API服务

【10】VLLM推理加速与部署

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/472035.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用在汽车PKE无钥匙进入系统的高度集成SOC芯片:CSM2433

CSM2433是一款集成2.4GHz频段发射器、125KHz接收器和8位RISC(精简指令集)MCU的SOC芯片,用在汽车PKE无钥匙进入系统里。 什么是汽车PKE无钥匙进入系统? 无钥匙进入系统具有无钥匙进入并且启动的功能,英文名称是PKE&…

路由器基本原理与配置

一 , 路由是什么? 从源主机到目标主机的转发过程; 二 , 路由器 (1)路由器的工作原理 路由器是一种三层设备,是使用IP地址寻址,实现从源IP到达目标IP地址的端到端的服务&#xff0c…

NPOI 实现Excel模板导出

记录一下使用NPOI实现定制的Excel导出模板&#xff0c;已下实现需求及主要逻辑 所需Json数据 对应参数 List<PurQuoteExportDataCrInput> listData [{"ItemName": "电缆VV3*162*10","Spec": "电缆VV3*162*10","Uom":…

element plus的表格内容自动滚动

<el-table:data"tableData"ref"tableRef"borderstyle"width: 100%"height"150"><el-table-column prop"date" label"名称" width"250" /><el-table-column prop"name" label&…

【Linux网络编程】简单的UDP网络程序

目录 一&#xff0c;socket编程的相关说明 1-1&#xff0c;sockaddr结构体 1-2&#xff0c;Socket API 二&#xff0c;基于Udp协议的简单通信 一&#xff0c;socket编程的相关说明 Socket编程是一种网络通信编程技术&#xff0c;它允许两个或多个程序在网络上相互通信&…

AI 写作(九)实战项目二:智能新闻报道(9/10)

一、项目概述 在当今信息爆炸的时代&#xff0c;新闻传播行业正面临着前所未有的挑战与机遇。随着科技的飞速发展&#xff0c;人们获取信息的渠道日益多样化&#xff0c;对新闻的时效性、准确性和个性化需求也不断提高。在这样的背景下&#xff0c;AI 写作在智能新闻报道中的重…

针对gitgitee的使用

1.下载git 链接 打开终端&#xff0c;桌面鼠标右键 2.配置密钥 登录gitee。 设置密钥 查看官方文档 跟着教程 复制最后的输出进行密钥添加 验证是否添加成功 3.创建&连接远程仓库 创建仓库 git终端进行配置 远程仓库克隆到本地 桌面终端clone,克隆他人|自己的仓库到本地…

DNS批量解析管理软件有什么用

在复杂的网络环境中&#xff0c;DNS批量解析管理软件犹如一把功能强大的钥匙&#xff0c;开启了高效网络管理的大门&#xff0c;为网络运营和维护带来了诸多便利。 1、对于网络服务提供商而言&#xff0c;DNS批量解析管理软件极大地提高了工作效率 传统的DNS解析管理方式在处…

二叉树遍历的非递归实现和复杂度分析

一&#xff0c;用栈实现二叉树先序遍历 1&#xff0c;原理 我用自己的口水话解释一下&#xff1a;准备一个栈&#xff0c;从根节点开始&#xff0c;先判断栈是否为空&#xff0c;如果否&#xff0c;就弹出一个元素&#xff0c;对弹出元素进行自定义处理&#xff0c;再将它的左…

ElasticSearch-全文检索(一)基本介绍

简介 Elasticsearch&#xff1a;官方分布式搜索和分析引擎 | Elastic 全文搜索属于最常见的需求&#xff0c;开源的Elasticsearch是目前全文搜索引擎的首选。 它可以快速地储存、搜索和分析海量数据。维基百科、StackOverflow、Github都采用它 Elastic的底层是开源库Lucene。但…

65 mysql 的 表元数据锁

前言 这里我们来看一下 mysql 这边的 元数据锁, 术语称之为 MDL 我们这里 忽略它的实现, 我们仅仅看 其具体的使用的地方 因为它的实现 也就可以理解为另外一个 表排他锁, 具体的实现来说 和表排他锁 类似 我们这里 仅仅去了解 在各种类型的语句中 MDL 的使用的地方 lock …

【eNSP】路由基础与路由来源——静态路由实验

路由是数据包从源地址到目的地址的传输路径&#xff0c;静态路由是指网络管理员手动配置的路由条目&#xff0c;用于指定数据包从源地址到目的地址的固定路径。以下是关于静态路由的详细介绍。 一、路由的基础知识点 路由的定义&#xff1a; 路由是指在计算机网络中&#xff…

androidstudio入门到放弃配置

b站视频讲解传送门 android_studio安装包&#xff1a;https://developer.android.google.cn/studio?hlzh-cn 下载安装 开始创建hello-world 1.删除缓存 文件 下载gradle文件压缩&#xff1a;gradle-8.9用自己创建项目时自动生成的版本即可&#xff0c;不用和我一样 https://…

从0开始学习--Day26--聚类算法

无监督学习(Unsupervised learning and introduction) 监督学习问题的样本 无监督学习样本 如图&#xff0c;可以看到两者的区别在于无监督学习的样本是没有标签的&#xff0c;换言之就是无监督学习不会赋予主观上的判断&#xff0c;需要算法自己去探寻区别&#xff0c;第二张…

java算法性能调优:详尽探讨时间复杂度与空间复杂度的分析与优化“

接下来我将带领大家进入Java数据结构的深入学习&#xff0c;让我们一同享受Java数据结构中的奥秘。 一、引言 二、时间复杂度 三、空间复杂度 四、Java中的时间复杂度和空间复杂度 五、优化时间复杂度和空间复杂度 七、时间复杂度和空间复杂度的重要性 一&#xff1a;时间…

「AI Infra 软件开源不是一个选项,而是必然」丨云边端架构和 AI Infra专场回顾@RTE2024

在人工智能和开源技术蓬勃发展的当下&#xff0c;AI Infra 项目正经历着日新月异的变革。从跨平台运行时到云边端 AI 基础设施&#xff0c;再到多模态知识助手&#xff0c;创新浪潮席卷而来。这些进步不仅显著提升了技术指标&#xff0c;也为实时音视频处理、边缘计算、大模型应…

【重生之我要苦学C语言】深入理解指针6

深入理解指针6 sizeof和strlen的对比 sizeof 操作符 整型&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() {int a 10;printf("%zd\n", sizeof(a));printf("%zd\n", sizeof(int));printf("%zd\n", sizeo…

创建vue插件,发布npm

开发步骤&#xff1a;1.创建一个vue项目&#xff0c;2.开发一个组件。 3.注册成插件。 4.vite和package.json配置。5.发布到npm &#xff11;.创建一个vue项目 npm create vuelatest 生成了vue项目之后&#xff0c;得到了以下结构。 在src下创建个plugins目录。用于存放开发的…

Java垃圾回收算法

垃圾回收之标记算法 1、引用计数法 通过判断对象的引用数量来决定对象是否被回收每个对象实例都有一个引用计数器&#xff0c;被引用则1&#xff0c;完成引用则-1 优点&#xff1a; 执行效率高&#xff0c;程序执行受影响小 缺点&#xff1a; 无法检测出循环引用的情况&#…

文献阅读 | Nature Communications:使用自适应图注意自动编码器从空间解析的转录组学中解读空间域

文献介绍 文献题目&#xff1a; 使用自适应图注意自动编码器从空间解析的转录组学中解读空间域 研究团队&#xff1a; 张世华&#xff08;中国科学院数学与系统科学研究院&#xff09; 发表时间&#xff1a; 2022-04-01 发表期刊&#xff1a; Nature Communications 影响因子…