【大模型实战篇】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.xdnf.cn/news/17104.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

[JAVAEE] 网络编程

目录 一. 什么是socket套接字 二. socket套接字 2.1 socket套接字根据传输层协议分类 2.2 TCP流套接字 UDP数据报套接字主要特点 三. UDP数据报套接字编程 3.1 DatagramSocket 是UDP socket, 用于发送和接受数据报 3.2 DatagramPacket 是UDP socket 发送和接收的数据报 …

SDF,一个从1978年运行至今的公共Unix Shell

关于SDF 最近发现了一个很古老的公共Unix Shell服务器,这个项目从1978年运行至今,如果对操作系统,对Unix感兴趣,可以进去玩一玩体验一下 SDF Public Access UNIX System - Free Shell Account and Shell Access 注册方式 我一…

物联网低功耗广域网LoRa开发(二):LoRa开发环境搭建及驱动移植

一、STM32CubeMX加载固件库 将F0固件库添加进来 二、IAR介绍、安装及快捷操作 (一)IAR介绍 1、简介 C/C编译器和调试器 集成开发环境(IDE) 实时操作系统和中间件 开发套件 硬件仿真器以及状态机建模工具2、IAR与Keil对比 MDK默认只创建工程&#xf…

RK3568平台开发系列讲解(设备树篇)device_node 转换成 platform_device

🚀返回专栏总目录 文章目录 一、DTB转换规则二、转换源码分析沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍通过设备树 device_node 转换成 platform_device 一、DTB转换规则 device 部分是用 platform_device 结构体来描述硬件资源的, 所以内核最终会…

深入理解 source 和 sh、bash 的区别

1 引言 在日常使用 Linux 的过程中,脚本的执行是不可避免的需求之一,而 source、sh、bash 等命令则是执行脚本的常用方式。尽管这些命令都能运行脚本,但它们之间的执行方式和效果却有着显著的区别。这些区别可能会影响到脚本的环境变量、工作…

基于Java Springboot鲜花商城系统

一、作品包含 源码数据库设计文档PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA 数据库:MySQL8.0 …

413: Quick Sort

解法&#xff1a; #include <bits/stdc.h> using namespace std; const int N1e55; int a[N]; int n;int main(int argc, char** argv) {cin>>n;for (int i0;i<n;i) cin>>a[i];sort(a,an);for (int i0;i<n;i) cout<<a[i]<<" "…

通过轻易云高效实现ERP数据无缝传输

高效集成领星ERP数据至金蝶云星空 领星ERP数据集成到金蝶云星空&#xff1a;发货结算报告对接销售出库单&#xff08;日本站&#xff09; 在企业的日常运营中&#xff0c;数据的高效流动和准确处理至关重要。本文将分享一个实际运行的系统对接集成案例&#xff1a;如何将领星E…

在 WSL2 Ubuntu22.04环境安装 MySQL

一、安装步骤 1.1. 确保/etc/apt/sources.list源配置文件一切正常 sudo nano /etc/apt/sources.list需要包括以下内容 deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse deb-src http://archive.ubuntu.com/ubuntu/ focal main restricted…

通信塔台、网点、线路数据

通信塔台&#xff1a; 数量&#xff1a; 通信电缆&#xff1a; 通信网点&#xff1a;

C#桌面应用制作计算器

C#桌面应用制作简易计算器&#xff0c;可实现数字之间的加减乘除、AC按键清屏、Del按键清除末尾数字、/-按键取数字相反数、%按键使数字缩小100倍、按键显示运算结果等...... 页面实现效果 功能实现 布局 计算器主体使用Panel容器&#xff0c;然后将button控件排列放置Pane…

【C++进阶】C++11 -- 智能指针

【C进阶】C11 -- 智能指针 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C&#x1f96d; &#x1f33c;文章目录&#x1f33c; 1. 智能指针的使用场景分析 2. RAII和智能指针的设计思路 3. C标准库智能指针的使用 4. 智能指针的原…

web——upload-labs——第一关

今天新开一个upload-labs的靶场&#xff0c;文件上传&#xff0c;加油&#xff01;&#xff01;&#xff01;&#xff01; 先讲讲文件上传 文件上传&#xff1a;在Web开发中&#xff0c;文件上传功能是一个允许用户将文件&#xff08;例如图片、文档&#xff09;上传到服务器…

提升企业库存管理效率:聚水潭与金蝶云星空集成方案

查询聚水潭库存生成金蝶物料盘点作业 在企业的日常运营中&#xff0c;库存管理和物料盘点是至关重要的环节。为了实现高效、准确的数据对接&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将聚水潭的库存数据无缝集成到金蝶云星空系统中。本案例将详细介绍如何通过API接…

MacOS下,如何在Safari浏览器中打开或关闭页面中的图片文字翻译功能

MacOS下&#xff0c;如何在Safari浏览器中打开或关闭页面中的图片文字翻译功能 在Mac上的Safari浏览器中&#xff0c;可以通过实况文本功能来实现图片中的文本翻译。关闭步骤具体步骤如下&#xff1a; 在浏览器地址栏&#xff0c;鼠标右击翻译按钮&#xff0c;然后点击“首选…

使用 PyAnsys 在 Ansys 随机振动分析中检索螺栓连接中的力和应力

介绍 随机振动模拟通常用于评估组件承受运输过程中振动的能力。随机振动分析利用先前模态分析的频率和模式内容对通过功率谱密度 (PSD) 负载定义的频谱和功率内容进行线性叠加。在大多数装配模型中&#xff0c;螺栓连接&#xff08;由求解器变为 BEAM188 元素&#xff09;通常…

使用Axios函数库进行网络请求的使用指南

目录 前言1. 什么是Axios2. Axios的引入方式2.1 通过CDN直接引入2.2 在模块化项目中引入 3. 使用Axios发送请求3.1 GET请求3.2 POST请求 4. Axios请求方式别名5. 使用Axios创建实例5.1 创建Axios实例5.2 使用实例发送请求 6. 使用async/await简化异步请求6.1 获取所有文章数据6…

让你的 环境变量 更合理

PATH PATH 环境变量由 shell 或 libc 读取来查找并执行程序&#xff0c;这就是当在终端中键入 ls 时 shell 可以找到 /bin/ls 的方式。 在基于 Debian 的桌面系统上&#xff0c;默认 PATH 变量如下所示&#xff1a; PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sb…

vue3中将在线url地址转为图片显示方法教程

vue3中将在线url地址转为图片显示方法教程 转化后&#xff1a; 原来&#xff1a; 代码&#xff1a; <el-table-column label"制单人" align"center"><template #default"scope"><imgv-if"scope.row.maker":src"s…

idea项目运行时 java: 错误: 不支持发行版本 21

java项目运行时&#xff0c;同样的项目别的都是正常运行&#xff0c;单个这个项目一直报 java: 错误: 不支持发行版本 21&#xff0c; 报错的解释 这个错误表明你正在尝试使用Java编译器编译一个类&#xff0c;但是编译器遇到了一个它不支持的版本号&#xff0c;在这个上下文…