vLLM 实战

2023-11-14

引言

随着人工智能技术的飞速发展,以及今年以来 ChatGPT 的爆火,大语言模型 (Large Language Model, LLM) 受到越来越多的关注。

为了实现 LLM 部署时的推理优化,全球各地有众多团队做出了各种优化框架。本文以加州大学伯克利分校开发的 vLLM 框架为例,进行实战探索。

1. 整体介绍

根据公开文档中的实验结果, vLLM 吞吐量比 Hugging Face Transformers 高出 24 倍,比 TGI 高出 3.5 倍。

9d35a62a785406f699cfed5a7c83405b.png

vLLM 整体框架如下图所示。

7af58aa829a2211a1878d63642dfdbad.jpeg

其中的关键技术点包括:

  • KVCache 显存优化

  • PagedAttention

  • Continuous Batching

笔者通过实际使用,认为该框架优点如下:

  • 调试方便: 主框架由 Python 实现,便于用户断点调试。

  • 系统设计工整规范: LLMEngine、Scheduler、Worker 结构清晰,初学者可以方便地理清脉络。

  • 推理速度快: 经过理论计算与实测, 8 卡 A100-40G 足以支持千人试用。

2. offline_inference 示例复现分析

(1) 调试环境配置

为方便复现,笔者制作了 dockerfile 用于编译 base 镜像,base 镜像把 vllm 的依赖库都安装好,基于 base 镜像直接再安装 vllm 库即可复现。

docker build -t vllm_ci-benchmark:base -f ci/docker/ci-benchmark-base.dockerfile .

docker build -t vllm_ci-benchmark:v1 -f ci/docker/ci-benchmark.dockerfile .

镜像是基于 nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04 (95d242fe9108) (9.83GB) 制作而来,篇幅所限,此处只展示 ci-benchmark.dockerfile 内容。

FROM vllm_ci-benchmark:base

COPY . /code/vllm

RUN cd /code/vllm && \
    python3 -m pip install -e . && \
    rm -rf ~/.cache

而后基于 vllm_ci-benchmark:v1 镜像创建容器,配置 vscode 断点调试环境,便于跟踪 offline_inference 示例的全流程。

(2) 模型下载与复现

提前从 facebook/opt-125m 下载 pytorch_model.bin 格式的模型和源码文件夹,而后将 offline_inference 中的模型路径改为本地路径,复现结果如下图所示。

c2063a6ac3edc175cd98a065075c717d.png

(3) offline_inference 流程梳理

(a) Create sampling_params

根据用户设置,创建采样参数类对象 sampling_params,只指定 temperature=0.8, top_p=0.95 的情况下,其他默认值如下所示。

SamplingParams(n=1,
               best_of=1,
               presence_penalty=0.0,
               frequency_penalty=0.0,
               temperature=0.8,
               top_p=0.95,
               top_k=-1,
               use_beam_search=False,
               stop=[],
               ignore_eos=False,
               max_tokens=16,
               logprobs=None)

各参数的取值范围见 vllm/sampling_params.py 里相关 _verify_xxx 函数。

(b) Create an LLM

LLM 类对象的构造函数中,首先创建 EngineArgs 类对象 engine_args 如下。

EngineArgs(model='/bigdata/shared/models/huggingface/opt-125m',
           tokenizer='/bigdata/shared/models/huggingface/opt-125m',
           tokenizer_mode='auto',
           trust_remote_code=False,
           download_dir=None,
           use_np_weights=False,
           use_dummy_weights=False,
           dtype='auto',
           seed=0,
           worker_use_ray=False,
           pipeline_parallel_size=1,
           tensor_parallel_size=1,
           block_size=16,
           swap_space=4,
           gpu_memory_utilization=0.9,
           max_num_batched_tokens=2560,
           max_num_seqs=256,
           disable_log_stats=True,
           quant_mode=None)

然后基于 engine_args ,构造 LLM 类内核心变量 llm_engine ,最后添加一个类内计数器 request_counter。

self.llm_engine = LLMEngine.from_engine_args(engine_args)
self.request_counter = Counter()
(c) Generate

LLM.generate 的处理过程中,核心操作分为两步。

第一步是调用 LLM._add_request ,通过 LLM.llm_engine.add_request 将用户传入的请求添加到请求列表中,添加完后,请求列表 LLM.llm_engine.scheduler.waiting 中内容如下。

[ \
    SequenceGroup(request_id=0, sampling_params=SamplingParams(n=1, best_of=1, presence_penalty=0.0, frequency_penalty=0.0, temperature=0.8, top_p=0.95, top_k=-1, use_beam_search=False, stop=[], ignore_eos=False, max_tokens=16, logprobs=None), num_seqs=1),
    SequenceGroup(request_id=1, sampling_params=SamplingParams(n=1, best_of=1, presence_penalty=0.0, frequency_penalty=0.0, temperature=0.8, top_p=0.95, top_k=-1, use_beam_search=False, stop=[], ignore_eos=False, max_tokens=16, logprobs=None), num_seqs=1),
    SequenceGroup(request_id=2, sampling_params=SamplingParams(n=1, best_of=1, presence_penalty=0.0, frequency_penalty=0.0, temperature=0.8, top_p=0.95, top_k=-1, use_beam_search=False, stop=[], ignore_eos=False, max_tokens=16, logprobs=None), num_seqs=1),
    SequenceGroup(request_id=3, sampling_params=SamplingParams(n=1, best_of=1, presence_penalty=0.0, frequency_penalty=0.0, temperature=0.8, top_p=0.95, top_k=-1, use_beam_search=False, stop=[], ignore_eos=False, max_tokens=16, logprobs=None), num_seqs=1)
]

第二步是调用 LLM._run_engine,通过 LLM.llm_engine.step(),转到 LLM.llm_engine._run_workers 函数中进行处理。

LLM.generate 的处理过程中,LLMEngine, Scheduler, Worker 协作配合,LLMEngine 负责总控,Scheduler 负责调度,Worker 负责执行,脉络清晰,其设计思路很值得学习借鉴。

3. 总结

vLLM 框架通过 PagedAttention 等关键技术,在多 batch 推理时,与传统 Hugging Face Transformers 框架相比,大幅提高了推理速度和吞吐量。

本文针对 vLLM 框架的 offline_inference 示例进行了复现与梳理分析,接下来准备进一步深入探索 PagedAttention 等特性。受限于笔者知识水平,文中可能会存在某些理解身上的偏差,欢迎各位大佬进行交流,共同进步。

ad80048d69b436b6f874a14bc5bc1316.png

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vLLM 实战 的相关文章

  • wms系统与物联网发展趋势密切相关

    物联网 简称IoT 是指通过各种信息传感器 射频识别技术 全球定位系统 红外感应器 激光扫描器等各种装置与技术 实时采集任何需要监控 连接 互动的物体或过程 采集其声 光 热 电 力学 化学 生物 位置等各种需要的信息 通过各类可能的网络接
  • 海德拉 暴力破解ssh密码

    上一篇博客写到怎么有效地防护ssh密码遭到暴力破解 今天给大家介绍下如何暴力破解ssh密码 作为一名云计算工程师 懂得如何防护比如何攻击更重要 hydra是世界顶级密码破解工具 支持几乎所有协议的在线密码破解 密码能否被破解取决于密码字典是
  • 华为OD机试真题-优雅子数组Python实现【2023.Q1】

    题目内容 如果一个数组中出现次数最多的元素出现大于等于K次 被称为K 优雅数组 k也可以被称为优雅阈值 例如 数组1 2 3 1 2 3 1 它是一个3 优雅数组 因为元素1出现次数大于等于3次 数组1 2 3 1 2就不是一个3 优雅数组
  • MySQL 日期格式化

    本文旨在以最快的速度 提供你需要的 MySQL 日期格式化方案 1 将时间格式化为 YYYY mm dd HH ii ss 格式 我想你要搜的就是这个 哈哈哈 SELECT DATE FORMAT NOW Y m d H i s 效果如图
  • python中dump与dumps的区别

    Python3 JSON模块的使用 参考链接 https docs python org 3 library json html 这里只是介绍最常用的dump dumps和load loads import json 自定义了一个简单的数据
  • flume使用(二):采集远程日志数据到MySql数据库

    本文内容可查看目录 本文内容包含单节点 单agent 和多节点 多agent 采集远程日志 说明 一 环境 linux系统 Centos7 Jdk 1 7 Flume 1 7 0 二 安装 linux中jdk mysql的安装不多赘述 fl
  • Redis清除缓存命令

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 方案1 windows操作系统 进入redis的安装目录 双击redis cli exe 执行 dbsize 执行 flushall 退出 方案2 linux操作系统 进入
  • vue-quill-editor富文本编辑器使用及配置更改

    quill editor支持了常用的功能 但是有2点 需要我们自己定制一下 vue集成quill editor很简单 网上有很多介绍 自行百度下即可 1 图片上传 因为编辑器默认是将图片转成base64存储的 而我们实际开发需要将图片存在自
  • 怎么给PDF签名?来看看这几个方法吧

    年关将至 这几天我所在的部门每个人都很忙碌 都在对今天年尾的申报文件以及明年的商家合同进行处理 今天 领导让我将几份商家合同扫描成PDF电子版本 同时将负责人签名导入文件中 不过由于我之前只接触过扫描文档 并不会在电子文件上导入签名 于是我
  • 终于搞懂了 @Configuration 和 @Component 的区别

    一句话概括就是 Configuration 中所有带 Bean 注解的方法都会被动态代理 因此调用该方法返回的都是同一个实例 理解 调用 Configuration类中的 Bean注解的方法 返回的是同一个示例 而调用 Component类
  • 寓教于乐——PyGame游戏编程,Python小游戏制作实战教学

    Python非常受欢迎的一个原因是它的应用领域非常广泛 其中就包括游戏开发 而是用Python进行游戏开发的首选模块就是PyGame 1 初识Pygame PyGame是跨平台Python模块 专为电子游戏设计 包含图像 声音等 创建在SD
  • javaScript 实现冒泡排序与快速排序

    javaScript 实现冒泡排序与快速排序 下面代码是否正确 有没有大神帮忙看下 谢谢
  • Pandas数据处理(续)/数据聚合[groupby+sum,mean/apply/transform]

    5 数据聚合 重点 数据聚合是数据处理的最后一步 通常是要使每一个数组生成一个单一的数值 数据分类处理 分组 先把数据分为几组 用函数处理 为不同组的数据应用不同的函数以转换数据 合并 把不同组得到的结果合并起来 数据分类处理的核心 gro
  • FPGA图像处理——YCbCr灰度转换

    之前的单通道灰度转换作为一个图像处理FPGA框架搭建完成后的一个简单效果的测试 其图像的层次感有待提高 图像处理灰度转换用的更多的还是YCbCr 一 YCbCr YCbCr或Y CbCr有的时候会被写作 YCBCR或是Y CBCR Y 为颜
  • 如何一启动web程序,直接访问某个controller里的方法进而跳转页面

    随便写一个JSP页面 在页面里面在转发到你要的Action web xml 里面添加
  • 【QT】:QT实现一个信号与多个槽的关联和实现多个信号与一个槽的关联

    这个问题很简单 我们定义一个按钮就是一个信号 而相应的事件就是一个槽 而这里用到的方法就是connect connect的两个实例如下 connect ui gt pushButton 3 SIGNAL clicked this SLOT
  • vue使用高德或百度等地图计算两个经纬度之间的距离

    1 计算两个经纬度之间的距离 lng1 lat1 第一个经纬度 lng2 lat2 第二个经纬度 export function calculateDiscount lng1 number lat1 number lng2 number l
  • C# 中Console.ReadLine() 与 Console.ReadKey() 的区别

    C 中Console ReadLine 与 Console ReadKey 的区别 在我们封装类时 输出控制台会闪退 而Console ReadLine 与 Console ReadKey 可以让控制台不会闪退 那它们两者之间的区别是什么呢
  • 《Python程序设计》实验一报告

    20222108 多乐 2022 2023 2 Python程序设计 实验一报告 课程 Python程序设计 班级 2221 姓名 多乐 学号 20222108 实验教师 王志强 实验日期 2022年3月9日 必修 选修 公选课 1 实验内
  • HDU1085 Holding Bin-Laden Captive!

    Problem Description We all know that Bin Laden is a notorious terrorist and he has disappeared for a long time But recen

随机推荐