☰
FlexGen 单 GPU 高吞吐大模型推理引擎:论文解读与源码实战指南
2026/9/25 6:02:49 网站建设 项目流程
  • 推理引擎
  • 大模型

【免费下载链接】FlexGen

Running large language models on a single GPU for throughput-oriented scenarios.

项目地址:https://gitcode.com/gh_mirrors/fl/FlexGen
点击查看免费下载

本文以 FlexGen 仓库中收录的论文《High-throughput Generative Inference of Large Language Models with a Single GPU》为核心骨架,结合仓库源码(flexgen/flex_opt.py、flexgen/compression.py、experimental/cost_model.py 等)展开解读。通过本文,你将理解 FlexGen 如何在单块普通 GPU(如 16GB T4)上通过 GPU/CPU/磁盘三级异构聚合、线性规划策略搜索与 4-bit 分组量化,将 OPT-175B 级别的模型吞吐推升至 1 token/s 以上;并掌握--percent卸载策略、压缩开关、HELM 基准接入与分布式扩展的完整实操方法。

FlexGen 的定位是面向吞吐优先(throughput-oriented)场景的生成引擎:这类任务(批量评测、信息抽取、数据整理、表单处理)需要以批处理方式在数百万 token 上反复运行 LLM,对单次延迟不敏感,但对整段运行时间的 token 吞吐率极为敏感。其核心思想是用 I/O 效率换延迟,在低成本单 GPU 硬件上把批大小做到传统方案无法企及的规模,从而显著提升最大吞吐。仓库 README 同时明确列出了其局限性:作为基于卸载(offloading)的系统,在弱 GPU 上、尤其是小批量场景下,其速度仍远低于拥有足够强 GPU 将整个模型驻留显存的方案,因此它主要针对单 GPU 上的批量处理设置优化。

一、论文核心贡献:为什么单卡能跑 175B 模型

1.1 问题背景:LLM 推理的资源门槛

论文摘要指出,大语言模型推理的传统路径需要多块高端加速器才能可行。而现实中出现了一批延迟不敏感(latency-insensitive)的批量处理任务:公司内部全部私有文档的分类与抽取、HELM 基准上全部任务的跑分等。这类工作负载允许"晚上提交作业、隔夜跑完"的运行方式,代价是吞吐率直接决定成本——吞吐被定义为任务整个运行时间(可达数小时)内每秒处理的 token 数。这种特性使得"用延迟换吞吐"成为可行策略,也让低成本的普通商用 GPU 有了用武之地。

1.2 三大关键技术

FlexGen 应对资源约束的三大手段(README "How It Works" 一节与论文摘要一致):

  1. 异构资源聚合(GPU + CPU + Disk):在不同硬件资源约束下灵活配置,把权重、激活、注意力 KV cache 分散存放在 GPU 显存、CPU 内存与磁盘上,按需加载计算;
  2. 线性规划(LP)策略优化器:通过线性规划自动搜索张量"存哪里、何时访问"的最优模式,在给定硬件(GPU/CPU/磁盘容量与带宽)约束下最大化吞吐;
  3. 4-bit 分组量化压缩:对权重与注意力 KV cache 均压缩到 4 bit,精度损失可忽略(negligible),从而把"可容纳的批大小"上限大幅抬升。

1.3 代表性结果(以论文/README 为准)

论文摘要给出了两个标志性结论,均基于 GCP 上单块 NVIDIA T4(16GB)实例、208GB DRAM、1.5TB SSD 的环境(input seq len=512,output seq len=32,批大小调至各系统最大吞吐值):

  • 运行 OPT-175B 时,FlexGen首次在单 16GB GPU 上达到 1 token/s 的生成吞吐,有效批大小 144(配合压缩后的数字见下文性能表);
  • 在 HELM 基准上,FlexGen 用 16GB GPU 在 21 小时内完成了 30B 模型在 7 个代表性子场景下的跑分。

二、上手实测:从 OPT-1.3B 到 OPT-175B

2.1 安装

仓库 README 给出两种安装方式,唯一硬性要求是PyTorch >= 1.12:

# 方式一:pip 安装 pip install flexgen # 方式二:源码安装 git clone https://github.com/FMInference/FlexGen.git cd FlexGen pip install -e .

2.2 OPT-1.3B:无卸载快速体验

小模型可直接放进单 GPU,无需卸载。FlexGen 会自动从 Hugging Face 下载权重:

python3 -m flexgen.flex_opt --model facebook/opt-1.3b

运行后会看到 OPT-1.3B 生成的文本以及 benchmark 结果(prefill/decode 延迟与吞吐,见 flex_opt.py 的日志逻辑)。

2.3 OPT-30B:引入 CPU 卸载与--percent

python3 -m flexgen.flex_opt --model facebook/opt-30b --percent 0 100 100 0 100 0

--percent是 FlexGen 最核心的参数。它接收 6 个整数,依次表示(源码注释原文,见 flex_opt.py):

位置含义默认值
1权重放在 GPU 的百分比100
2权重放在 CPU 的百分比0
3注意力 cache 放在 GPU 的百分比100
4注意力 cache 放在 CPU 的百分比0
5激活(activations)放在 GPU 的百分比100
6激活放在 CPU 的百分比0

每一类的"磁盘百分比"是隐含的第三项,由Policy属性计算得出(flex_opt.py):

@property def w_disk_percent(self): # 权重磁盘占比 return 100 - self.w_gpu_percent - self.w_cpu_percent @property def cache_disk_percent(self): # cache 磁盘占比 return 100 - self.cache_gpu_percent - self.cache_cpu_percent @property def act_disk_percent(self): # 激活磁盘占比 return 100 - self.act_gpu_percent - self.act_cpu_percent

实际分配时,init_weight_list会按张量体积的累计分布(cumsum)把不同权重切成三段,分别落到磁盘、CPU、GPU(flex_opt.py)。因此--percent 0 100 100 0 100 0的含义是:权重全部放 CPU、cache 与激活全部放 GPU——这是 30B 在 16GB 显卡上的典型起点。参考策略可见 benchmark/flexgen/bench_suite.py:30B 无压缩时通常采用--percent 20 80 0 100 0 100或--percent 10 90 0 100 0 100(约 10%~20% 权重驻留 GPU,其余在 CPU),并搭配--gpu-batch-size 48 --num-gpu-batches 3之类的分批参数。

2.4 OPT-175B:全量卸载到磁盘

OPT-175B 需要先从 metaseq 项目下载权重,并按 Alpa 格式转换,然后可将全部权重卸载到 SSD:

python3 -m flexgen.flex_opt --model facebook/opt-175b --percent 0 0 100 0 100 0 --offload-dir YOUR_SSD_FOLDER

--offload-dir默认值为~/flexgen_offload_dir(flex_opt.py),用于存放卸载到磁盘的张量。

三、吞吐优先场景:HELM 基准与数据整理应用

3.1 将 FlexGen 接入 HELM

FlexGen 可以作为 HELM 的执行后端。README 给出的 MMLU 场景示例命令,可在单块 T4(16GB)+ 200GB DRAM 上运行:

pip install crfm-helm python3 -m flexgen.apps.helm_run --description mmlu:model=text,subject=abstract_algebra,data_augmentation=canonical --pad-to-seq-len 512 --model facebook/opt-30b --percent 20 80 0 100 0 100 --gpu-batch-size 48 --num-gpu-batches 3 --max-eval-instance 100

实现侧,flexgen/apps/helm_run.py 中的execute会构造ExecutionEnv与Policy,将 HELM 请求按effective_bs分批:get_batches先用 tokenizer 把 prompt 填充到pad_to_seq_len,再按 batch_size 切分(helm_run.py)。README 提醒:仅测试了部分 HELM 场景,已测试场景清单见 flexgen/apps/helm_passed_30b.sh。

3.2 数据整理(Data Wrangling)任务

论文的姊妹工作《Can Foundation Models Wrangle Your Data?》中的示例可以直接复现,操作说明位于 flexgen/apps/data_wrangle。该目录下 data_wrangle_run.py 同时提供single_query_test与batch_query_test两种模式,分别对应单条查询与批量查询测试脚本(如 test_batch_query_all_opt30b.sh),正是吞吐优先场景的典型落地。

四、API 使用:Hugging Face 风格的生成接口

4.1 生成 API

FlexGen 提供仿 Hugging Face transformers 风格的生成 API,核心签名见 completion.py:

output_ids = model.generate( input_ids, do_sample=True, temperature=0.7, max_new_tokens=32, stop=stop)

底层OptLM.generate支持debug_mode、cut_gen_len(截断生成长度用于快速调试)等参数,并内置 normal / overlap 两类生成循环(generation_loop_normal、generation_loop_overlap_single_batch、generation_loop_overlap_multi_batch等,见 flex_opt.py 中的方法定义)。

4.2 示例命令

  • 完整 OPT-6.7B,至少 15GB 显存:
python3 -m flexgen.apps.completion --model facebook/opt-6.7b
  • 完整 OPT-30B,约需 90GB CPU 内存:
python3 -m flexgen.apps.completion --model facebook/opt-30b --percent 0 100 100 0 100 0
  • 指令微调的 OPT-IML-MAX-30B,同样约需 90GB CPU 内存:
python3 -m flexgen.apps.completion --model facebook/opt-iml-max-30b --percent 0 100 100 0 100 0

注意completion.py内置了两个示例 prompt(奥运会地点问答、机场代码抽取),并在生成结束后调用env.close_copy_threads()关闭磁盘拷贝线程(completion.py)。

五、性能数据与复现方法

5.1 生成吞吐对比表

README "Performance Results" 中的对比表(括号内为有效批大小及其最低卸载层级;硬件为 GCP 上 T4 16GB + 208GB DRAM + 1.5TB SSD;workload 为 input=512 / output=32,批大小按各系统最大吞吐调优;吞吐定义为 生成 token 数 ÷(prompt 处理时间 + 生成时间)):

系统OPT-6.7BOPT-30BOPT-175B
Hugging Face Accelerate25.12 (2 on GPU)0.62 (8 on CPU)0.01 (2 on disk)
DeepSpeed ZeRO-Inference9.28 (16 on CPU)0.60 (4 on CPU)0.01 (1 on disk)
Petals8.25 (2 on GPU)2.84 (2 on GPU)0.08 (2 on GPU)
FlexGen25.26 (2 on GPU)7.32 (144 on CPU)0.69 (256 on disk)
FlexGen with Compression29.12(72 on GPU)8.38(512 on CPU)1.12(144 on CPU)

对应的有效批大小表与 Petals 基线说明见 benchmark/batch_size_table.md。完整复现方法(含 1x1 / 1x4 / 4x1 等多种拓扑的 shell 脚本与 bench_suite.py 自动化套件)见 benchmark/flexgen/README.md。

从 bench_suite.py 可以直观看到压缩带来的批大小提升:30B 无压缩时--gpu-batch-size 48 --num-gpu-batches 3(有效批 144),而启用--compress-cache后达到--gpu-batch-size 64 --num-gpu-batches 8(有效批 512)——与 README 表中数字一一对应。175B 压缩配置则采用--percent 0 100 0 100 0 100 --compress-weight --compress-cache的"全 CPU"策略,配合--pin-weight 0以缓解内存压力。

5.2 延迟-吞吐权衡(Pareto 前沿)

README 中docs/throughput_vs_latency.jpg(查看图片)展示了三个基于卸载的系统在 OPT-175B(左)与 OPT-30B(右)上的延迟-吞吐曲线:FlexGen 达成新的 Pareto 最优前沿,最大吞吐显著更高,而其他系统因内存不足无法继续增大批大小;图中 "FlexGen(c)" 即启用压缩的 FlexGen。

六、工作原理:批调度、I/O 重叠与策略搜索

6.1 吞吐视角下的延迟-吞吐权衡

FlexGen 的关键洞见是主动利用延迟-吞吐权衡:卸载方案天生难以实现低延迟,但在吞吐优先场景下,卸载的 I/O 效率可以被大幅提升。具体手段是block schedule(块调度):按块复用权重、把 I/O 与计算重叠(overlap),而基线系统普遍采用低效的逐行(row-by-row)调度。README 用 docs/block_schedule.jpg 直观对比了两种调度方式(a 为基线逐行、b 为 FlexGen 块调度)。

这一思想在源码中落地为Policy的overlap字段(默认 True,见 flex_opt.py)以及OptLM的三套生成循环:generation_loop_overlap_single_batch与generation_loop_overlap_multi_batch专门负责在多 GPU batch 之间交错加载权重与计算,从而隐藏磁盘/CPU 加载延迟。benchmark 套件中常见--overlap False的对照实验(bench_suite.py),便于量化重叠带来的收益。

6.2 线性规划策略优化器与成本模型

论文所述"通过线性规划优化器搜索张量存储与访问的最优模式",对应仓库 experimental/cost_model.py。它基于pulp线性规划库实现,典型用法:

# 1. 在给定硬件约束下自动搜索最优策略 python cost_model.py --model facebook/opt-30b --prompt-len 512 --gen-len 32 \ --gpu-mem 16 --cpu-mem 200 --nvme-mem 1500 # 2. 估算给定策略的吞吐 python cost_model.py --model facebook/opt-30b --prompt-len 512 --gen-len 32 \ --gpu-mem 16 --cpu-mem 200 --nvme-mem 1500 \ --gpu-batch-size 48 --num-gpu-batches 3 \ --percent 20 80 0 100 0 100 \ --alpha-g 1.2 --alpha-c 1.2 --alpha-n 1.2

文件头部注释明确给出了使用须知(cost_model.py):硬件常数(CostModelConfig)需要针对自己的设备重新拟合(作者通过采集真实运行数据点用梯度下降拟合,直接 profile 单个算子或从网络抄数都不准确);alpha_g/alpha_c/alpha_n是峰值内存估计的松弛系数,调小策略偏保守、调大偏激进;当前模型不考虑 CPU 计算委托,且量化支持不完整。README 的 Roadmap 也标注"Release the cost model and policy optimizer"为已完成项([X])。

6.3 4-bit 分组量化:权重与 KV cache 双压缩

压缩由 flexgen/compression.py 实现,核心是CompressionConfig(分组量化配置)与TorchCompressedDevice(压缩张量管理设备)。运行时通过两个开关开启:

--compress-weight # 压缩权重(约省 70% 权重内存) --compress-cache # 压缩 KV cache

两者默认的分组量化配置(flex_opt.py)为:

  • 权重:CompressionConfig(num_bits=4, group_size=64, group_dim=0, symmetric=False)
  • cache:CompressionConfig(num_bits=4, group_size=64, group_dim=2, symmetric=False)

从 compression.py 的实现可以看到压缩存储的具体形态:4-bit 数据按group_size=64分组,data张量按"每 2 个 4-bit 值打包成 1 个 uint8"的方式存放(data_shape = shape[:group_dim] + (num_groups * (group_size // 2),) + ...),并附带一个 fp16 的scale张量记录每组缩放因子。compress/decompress函数完成实际量化与反量化;cache 压缩时还会在 CPU 上分配 fp32 反量化工作区(init_attention_compute_workspace,见 compression.py)。README 提示,权重压缩大约可减少 70% 的权重内存,且论文报告压缩后精度损失可忽略(negligible)。

6.4 执行环境与内存层级抽象

FlexGen 把硬件抽象为统一的内存层级(utils.py 的ExecutionEnv+ pytorch_backend.py 中的TorchDevice/TorchDisk/TorchMixedDevice):

gpu = TorchDevice("cuda:0") cpu = TorchDevice("cpu") disk = TorchDisk(args.offload_dir) env = ExecutionEnv(gpu=gpu, cpu=cpu, disk=disk, mixed=TorchMixedDevice([gpu, cpu, disk]))

权重按Policy的百分比切分后分别allocate在 disk/cpu/gpu 上(init_weight_list),推理时通过load_weight/load_cache/store_cache在层级间搬运,磁盘侧使用多线程拷贝(TorchDisk默认 4 个拷贝线程)隐藏 I/O 延迟。--pin-weight 0可关闭 CPU 端权重页锁定(pinned memory),约减少 20% 以上的 CPU 权重内存占用(README FAQ),代价是拷贝稍慢。

6.5 分布式扩展:卸载 + 流水线并行

当多机多卡但聚合显存仍小于模型大小时,FlexGen 可把卸载与流水线并行(pipeline parallelism)结合:DistOptLM(dist_flex_opt.py)继承OptLM,引入pipeline_rank/num_pipeline_stages/comm_device等参数,并通过send_hidden/recv_hidden在流水线阶段间传递激活。README 提示:要获得可扩展的性能,GPU 应分布在多台机器上(同机多卡性能优化仍在其 Roadmap 中列为未完成项)。分布式 benchmark 脚本见 benchmark/flexgen/bench_dist_single_node.sh 与 benchmark/flexgen/bench_dist_multi_node.sh。

七、FAQ:策略调参与内存不足排查

7.1 如何设置卸载策略(--percent)?

README 明确说明:目前需要手工尝试若干策略(自动策略优化器已随 cost model 发布,但调优仍需人工)。总体原则是:尽可能把参数与注意力 cache 卸载到 CPU、必要时到磁盘,从而把显存让给更大的批大小。可直接参考 bench_suite.py 中的基准参考策略。出现 OOM 时,把--percent中对应项调向 CPU/磁盘方向即可卸载更多张量。

7.2 内存不足(OOM)时怎么办?

README FAQ 给出三条由"省内存 → 更慢"排序的应急手段:

  1. 不锁定权重:加--pin-weight 0,CPU 权重内存约省 20% 以上;
  2. 压缩权重:加--compress-weight,权重内存约省 70%;
  3. 权重全部落盘:--percent 0 0 100 0 100 0(配合--offload-dir),几乎不占 CPU 与 GPU 内存。

更进阶的排查可借助profile_bandwidth.py(flexgen/profile_bandwidth.py,测磁盘与 PCIe 带宽)与profile_matmul.py(flexgen/profile_matmul.py,测矩阵乘性能)先行刻画本机硬件常数,再用 cost_model.py 预估各策略的吞吐,减少盲目试参。

八、结语与路线图

FlexGen 证明了一条"弱硬件 + 极致 I/O 调度 + 压缩 + 大批量"的可行路径:在 16GB 单卡上首次达到 OPT-175B 的 1 token/s 生成吞吐,并把 HELM 30B 跑分压缩到 21 小时。它明确面向吞吐优先的批量场景,代价是小批量/低延迟场景不具优势。README Roadmap 显示其后续计划包括:优化同机多卡性能、支持更多模型(BLOOM、CodeGen、GLM)、Macbook(M1/M2)与 AMD 支持。论文全文出处为 docs/paper.md 所收录的 arXiv 论文《High-throughput Generative Inference of Large Language Models with a Single GPU》(arXiv:2303.06865,作者包括 Ying Sheng、Lianmin Zheng 等),Subj 分类为 cs.LG / cs.AI / cs.PF。

  • 推理引擎
  • 大模型

【免费下载链接】FlexGen

Running large language models on a single GPU for throughput-oriented scenarios.

项目地址:https://gitcode.com/gh_mirrors/fl/FlexGen
点击查看免费下载

相关推荐

上一篇:终极指南:如何使用 cmp-buffer 插件提升 Neovim 代码补全效率
下一篇:OpenVEX 漏洞披露数据管理指南:以 minikube 仓库 `.openvex` 模板目录与 `vexctl` 发布集成为例

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询