- 推理引擎
- 大模型
【免费下载链接】FlexGen
Running large language models on a single GPU for throughput-oriented scenarios.
本文基于 FlexGen 仓库中
flexgen/apps/目录下的应用文档与配套源码,系统讲解如何在单 GPU 上利用 FlexGen 运行 OPT 系列大模型,完成三类典型任务:交互式文本补全(Completion)、数据清洗(Data Wrangling,含实体匹配、数据补全与错误检测)以及 HELM 大规模评测基准(如 MMLU 场景)。读完本文,你将掌握三个可运行的入口脚本(completion.py、data_wrangle_run.py、helm_run.py)的完整命令行参数、FlexGen 六元组 offload 策略(--percent)的配置方法,以及如何在 16GB 显存等受限硬件上跑通 6.7B/30B/175B 级模型并解读其吞吐数据。
一、apps 目录与核心概念速览
flexgen/apps/是 FlexGen 面向实际应用场景提供的开箱即用示例集合,目录结构如下:
- flexgen/apps/completion.py:单机文本补全入口,演示用 OPT 模型完成句子;
- flexgen/apps/helm_run.py:HELM 评测场景执行器,可跑 MMLU、WikiFact、XSUM 等大规模评测;
- flexgen/apps/data_wrangle/:数据清洗任务(实体匹配 EM、数据补全 DI、错误检测 ED)的完整实现与基准脚本;
- flexgen/apps/helm_fast_test.py 与 flexgen/apps/helm_passed_30b.sh:HELM 场景清单与批量跑测脚本。
在深入各场景前,必须先理解 FlexGen 的核心编程模型,这些概念在三个入口脚本中被反复使用,均来自 flexgen/flex_opt.py:
ExecutionEnv:执行环境,通过ExecutionEnv.create(offload_dir)创建,负责管理 CPU/GPU/NVMe SSD 之间的张量搬运线程;脚本结束后需调用env.close_copy_threads()关闭拷贝线程(见 completion.py)。OptLM:OPT 模型封装,OptLM(model_name, env, path, policy)加载模型;--path指向权重缓存目录(~/opt_weights),若没有缓存权重,FlexGen 会自动从 HuggingFace 下载。Policy:offload 策略对象,其核心字段是六元组百分比percent,在 flex_opt.py 中定义为权重在 GPU/CPU、注意力缓存(KV cache)在 GPU/CPU、激活值在 GPU/CPU 的占比;剩余比例(100 - w_gpu - w_cpu)自动落到 NVMe 磁盘(w_disk_percent,见 flex_opt.py)。- 量化压缩:
--compress-weight/--compress-cache分别对权重和 KV 缓存做分组量化,默认配置为 4-bit、group_size=64(权重按group_dim=0分组、缓存按group_dim=2分组,非对称量化),可在 completion.py 与 helm_run.py 中看到一致的构造方式。
三个脚本都通过argparse暴露相同的一组 FlexGen 参数,这是本文所有命令的基础:
| 参数 | 默认值 | 含义 |
|---|---|---|
--model | facebook/opt-6.7b(completion)/facebook/opt-1.3b(helm、data_wrangle) | 模型名 |
--path | ~/opt_weights | 权重路径,无缓存时自动下载 |
--offload-dir | ~/flexgen_offload_dir | 张量 offload 目录 |
--percent | 100 0 100 0 100 0 | 六个数:权重 GPU%、权重 CPU%、缓存 GPU%、缓存 CPU%、激活 GPU%、激活 CPU% |
--pin-weight | True | 是否将 CPU 权重固定在(不可换页的)内存中 |
--cpu-cache-compute | 关闭 | 是否在 CPU 上计算注意力缓存 |
--compress-weight | 关闭 | 是否对权重做 4-bit 量化压缩 |
--compress-cache | 关闭 | 是否对 KV 缓存做 4-bit 量化压缩 |
--gpu-batch-size | 16 | 单轮 GPU batch 大小 |
--num-gpu-batches | 1 | GPU batch 批次数,二者乘积即有效批量 |
二、场景一:Completion 文本补全
flexgen/apps/README.md 给出的首个示例是文本补全:在一台拥有32GB 系统内存 + 24GB 显存的机器上直接跑 OPT-30B 与 OPT-66B:
python completion.py --model facebook/opt-30b --percent 100 0 100 0 100 0 --compress-weight python completion.py --model facebook/opt-66b --percent 50 10 100 0 100 0 --compress-weight两个命令的差异恰好演示了 offload 策略的调整思路:
- OPT-30B(约 60GB 权重):显存足够时优先使用
100 0 100 0 100 0,即权重、缓存、激活全部放 GPU,配合--compress-weight将权重压到 4-bit,进一步降低显存占用; - OPT-66B(约 132GB 权重):单卡显存已不足以全量放权重,因此改用
50 10 100 0 100 0——50% 权重放 GPU、10% 放 CPU、剩余 40% 由 FlexGen 自动 offload 到 NVMe 磁盘,同时保持缓存与激活 100% 在 GPU 上,保证推理吞吐。
从 completion.py 源码可以看到,脚本内置了两组 QA 风格的示例 prompt(如"2004 年奥运会在哪里举办?""从文本中抽取机场代码"),并做了以下配置:
- 使用
AutoTokenizer.from_pretrained("facebook/opt-30b", padding_side="left")加载左填充分词器,关闭 BOS token(tokenizer.add_bos_token = False); - 以换行符
\n的 token id 作为生成停止符(stop = tokenizer("\n").input_ids[0]); - 将 prompt 统一 padding 到 128 长度后调用
model.generate(input_ids, do_sample=True, temperature=0.7, max_new_tokens=32, stop=stop)(见 completion.py)。
运行后脚本会打印首尾两条生成结果与分隔线,最后调用env.close_copy_threads()优雅关闭 offload 线程。该脚本是最轻量的 FlexGen 上手路径:改--model即可在不同规模的 OPT 模型间切换,--percent则负责按你的显存/内存比例分配负载。
三、场景二:Data Wrangling 数据清洗任务
3.1 任务背景与安装
FlexGen 对数据清洗任务的支持实现了 HazyResearch 的 fm_data_tasks 项目思路,覆盖三类任务(详见 flexgen/apps/data_wrangle/README.md):
- Entity Match(EM,实体匹配):判断两条记录是否指向同一实体,如 Fodors-Zagats、Beer、iTunes-Amazon、Walmart-Amazon、Amazon-Google、DBLP-ACM、DBLP-GoogleScholar 等 7 个数据集;
- Data Imputation(DI,数据补全):根据已有字段补全缺失属性值,如 Restaurant(补 city)与 Buy(补 manufacturer);
- Error Detection(ED,错误检测):发现数据中的拼写/取值错误,如 Hospital 数据集。
安装分两步(对应 install.sh):
cd data_wrangle bash install脚本会安装pandas==1.4.2、sentence-transformers==2.2.2、rich==12.2.0、pyarrow==7.0.0等依赖,并创建data/目录、从fm-data-tasks的公开存储桶下载datasets.tar.gz后解压。数据集目录与任务的映射关系定义在 flexgen/apps/data_wrangle/utils/constants.py(如entity_matching/structured/Beer→entity_matching),各数据集要丢弃的列、补全列也集中在此文件中,便于按需定制。
3.2 单查询与批量查询两种运行模式
主程序 flexgen/apps/data_wrangle/data_wrangle_run.py 通过--batch_run标志切换两种模式(见 data_wrangle_run.py):
- 单查询模式(
single_query_test):逐条构造 prompt 并调用model.generate,用于验证结果正确性。仓库提供了快速验证脚本:bash test_single_query_case.sh:验证 Restaurant 数据补全任务在 OPT-6.7B 上的输出;bash test_single_query_all_opt6.7b.sh:对 OPT-6.7B 跑完所有任务的单条样例(prompt 统一 pad 到 32 长度)。
- 批量查询模式(
batch_query_test):一次性处理全部样本,同时记录总耗时与吞吐,用于测试 FlexGen 的吞吐性能:bash test_batch_query_case.sh:验证 Restaurant 任务批量模式;bash test_batch_query_all_opt6.7b.sh/test_batch_query_all_opt30b.sh/test_batch_query_all_opt175b.sh:分别在三种规模模型上跑完整测试集。
以 test_batch_query_all_opt6.7b.sh 中的实体匹配任务为例(Fodors-Zagats):
python3 ./data_wrangle_run.py \ --num_run 189 --num_trials 1 --nan_tok "" --do_test \ --sample_method manual \ --data_dir data/datasets/entity_matching/structured/Fodors-Zagats \ --batch_run --pad-to-seq-len 744 --model facebook/opt-6.7b \ --percent 100 0 100 0 100 0 --gpu-batch-size 2 --num-gpu-batches 1OPT-6.7B 全部任务均采用100 0 100 0 100 0(全 GPU 策略);OPT-30B 脚本改用10 90 0 100 0 100(权重 10% GPU + 90% CPU,缓存与激活全 CPU,见 test_batch_query_all_opt30b.sh);OPT-175B 则使用--pin-weight 0 --percent 0 50 0 0 0 100(权重全放 CPU 并 offload 磁盘、激活全 CPU,见 test_batch_query_all_opt175b.sh),并通过增大--gpu-batch-size与--num-gpu-batches的乘积换取更高批量吞吐。
各任务差异参数一览(以 6.7B 脚本为例):
| 任务数据集 | --num_run | --pad-to-seq-len | --max_tokens | --gpu-batch-size |
|---|---|---|---|---|
| EM: Fodors-Zagats | 189 | 744 | 3(默认) | 2 |
| EM: Beer | 91 | 592 | 3(默认) | 2 |
| EM: iTunes-Amazon | 109 | 529 | 3(默认) | 2 |
| EM: Walmart-Amazon | 200 | 748 | 3(默认) | 2 |
| EM: Amazon-Google | 200 | 876 | 3(默认) | 1 |
| EM: DBLP-ACM | 200 | 1274 | 3(默认) | 1 |
| EM: DBLP-GoogleScholar | 200 | 1209 | 3(默认) | 1 |
| DI: Restaurant | 86 | 123 | 5 | 8 |
| DI: Buy | 65 | 488 | 10 | 2 |
| ED: Hospital | 200 | 200 | 3(默认) | 5 |
从 data_wrangle_run.py 源码可见批量模式的内部逻辑:先逐条 tokenize 并记录max_prompt_seq_length,再统一 padding 后按flexgen_batch_size = gpu_batch_size * num_gpu_batches切分成多个 mini-batch 循环调用model.generate;吞吐按两个口径统计:output_throughput = num_run * max_tokens / total_time与total_throughput = (num_run * max_prompt_seq_length + num_run * max_tokens) / total_time(即输入 + 输出 token 合计)。每次 trial 结束后预测、查询、ground-truth 会以 feather 格式落盘,指标(Prec/Recall/Acc/F1 及其均值方差)写入metrics.json(见 data_wrangle_run.py)。
3.3 提示构造方式
提示词由 flexgen/apps/data_wrangle/utils/prompt_utils.py 负责构造,支持三种--sample_method(random/manual/validation_clusters,默认random):
- manual:使用各数据集预定义的固定前缀模板(
get_manual_prompt,见 prompt_utils.py); - random:从训练集中随机采样
--k条带标签样例作为 few-shot 前缀(get_random_prompt); - validation_clusters:基于 sentence embedding 聚类挑选"难样本"作为提示(
get_validation_prompt,使用sentence-transformers/sentence-t5-base)。
其余相关参数还包括--k(prompt 中示例条数,默认 1)、--sep_tok(属性-值对分隔符,默认.)、--nan_tok(缺失值记号,默认nan)、--temperature(默认 0.0)、--max_tokens(默认 3)、--stop_token(默认\n)以及--num_trials(重复试验次数,默认 1)等(见 data_wrangle_run.py)。
3.4 基准测试结果
flexgen/apps/data_wrangle/README.md 明确指出此类任务的特点:输入序列很长(123~1274 token),而输出很短(3/5/10 token),推理时间几乎全部消耗在 prefill 阶段,因此基准采用"输入 + 输出 token 合计"的吞吐口径。实验环境为:单张 T4(16GB)GPU、200GB DRAM、1.5TB NVMe SSD,与 HELM 基准采用相同设置。
OPT-6.7B 结果:
| 任务 | 测试样本 | 输入长度 | 输出长度 | 耗时 (s) | 输入+输出吞吐 (token/s) |
|---|---|---|---|---|---|
| EM: Fodors-Zagats | 189 | 744 | 3 | 109.556 | 1281.871 |
| EM: Beer | 91 | 592 | 3 | 42.087 | 1272.360 |
| EM: iTunes-Amazon | 109 | 529 | 3 | 59.467 | 966.178 |
| EM: Walmart-Amazon | 200 | 748 | 3 | 126.538 | 1186.992 |
| EM: Amazon-Google | 200 | 876 | 3 | 144.593 | 1215.828 |
| EM: DBLP-ACM | 200 | 1274 | 3 | 207.513 | 1230.767 |
| EM: DBLP-GoogleScholar | 200 | 1209 | 3 | 232.65 | 1097.78 |
| DI: Restaurant | 86 | 123 | 5 | 10.397 | 984.865 |
| DI: Buy | 65 | 488 | 10 | 43.077 | 739.876 |
| ED: Hospital | 200 | 200 | 3 | 30.137 | 1347.203 |
OPT-30B 结果:
| 任务 | 测试样本 | 输入长度 | 输出长度 | 耗时 (s) | 输入+输出吞吐 (token/s) |
|---|---|---|---|---|---|
| EM: Fodors-Zagats | 189 | 744 | 3 | 541.550 | 248.287 |
| EM: Beer | 91 | 592 | 3 | 238.58 | 224.450 |
| EM: iTunes-Amazon | 109 | 529 | 3 | 267.639 | 198.775 |
| EM: Walmart-Amazon | 200 | 748 | 3 | 682.635 | 220.030 |
| EM: Amazon-Google | 200 | 876 | 3 | 799.514 | 219.884 |
| EM: DBLP-ACM | 200 | 1274 | 3 | 1119.272 | 228.184 |
| EM: DBLP-GoogleScholar | 200 | 1209 | 3 | 1271.534 | 190.636 |
| DI: Restaurant | 86 | 123 | 5 | 60.310 | 169.790 |
| DI: Buy | 65 | 488 | 10 | 185.882 | 160.747 |
| ED: Hospital | 200 | 200 | 3 | 158.329 | 256.429 |
OPT-175B 结果:
| 任务 | 测试样本 | 输入长度 | 输出长度 | 耗时 (s) | 输入+输出吞吐 (token/s) |
|---|---|---|---|---|---|
| EM: Fodors-Zagats | 189 | 744 | 3 | 3928.310 | 34.228 |
| EM: Beer | 91 | 592 | 3 | 1356.786 | 35.083 |
| EM: iTunes-Amazon | 109 | 529 | 3 | 1569.062 | 33.906 |
| EM: Walmart-Amazon | 200 | 748 | 3 | 4171.319 | 36.008 |
| EM: Amazon-Google | 200 | 876 | 3 | 4893.572 | 35.925 |
| EM: DBLP-ACM | 200 | 1274 | 3 | 7624.726 | 33.496 |
| EM: DBLP-GoogleScholar | 200 | 1209 | 3 | 8275.828 | 29.290 |
| DI: Restaurant | 86 | 123 | 5 | 648.762 | 16.968 |
| DI: Buy | 65 | 488 | 10 | 2086.961 | 14.317 |
| ED: Hospital | 200 | 200 | 3 | 1154.133 | 35.178 |
三组数据可以清晰看出:模型规模从 6.7B → 30B → 175B,吞吐量大致以约 5 倍、再约 6 倍的速度递减,但即便在单张 16GB T4 上,OPT-175B 也能以 30 token/s 左右的合计吞吐完成全部 10 个数据清洗任务——这正是 FlexGen 通过 CPU/磁盘 offload 换来的"单卡跑大模型"能力。
四、场景三:HELM 大规模评测基准
4.1 入口命令与参数
flexgen/apps/README.md 展示了用 FlexGen 运行 HELM 的 MMLU(Massive Multitask Language Understanding)场景示例:
python3 helm_run.py --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该命令的关键配置:--pad-to-seq-len 512统一 padding 长度;--percent 20 80 0 100 0 100将 20% 权重放 GPU、80% 放 CPU、缓存与激活全部放 CPU(对应 helm_passed_30b.sh 中 OPT-IML-30B 的评测设置);--gpu-batch-size 48 --num-gpu-batches 3使有效批量为 144;--max-eval-instance 100限制评测实例数。
helm_run.py 在helm(HELM 0.2.1 版本)之上做了完整适配,其执行流水线(对应 helm_run.py 的run_entry函数)为:
- 通过
RunEntry(description, ...)与run_entries_to_run_specs将场景描述解析为RunSpec; - 用自定义
OptTokenizer(包装 HuggingFace tokenizer,见 helm_run.py)创建 HELM adapter 与 scenario,拉取评测实例; get_batches将全部 prompt 按pad_to_seq_len统一 padding,并按gpu_batch_size * num_gpu_batches的有效批量切分成多个 batch(见 helm_run.py);若输入超长会按 256 的倍数自动向上取整重新 padding;execute初始化ExecutionEnv与Policy后逐 batch 调用model.generate(do_sample=True,温度从 HELM 请求映射而来,stop 序列映射为eos_token_id,见 helm_run.py);- 将生成结果重组为 HELM 的
RequestResult/ScenarioState,交由 HELM metric 评估(默认取第一个 metric),并把run_spec.json、scenario.json、scenario_state.json、stats.json、per_instance_stats.json等产物写入--run-path(默认runs)目录。
4.2 已通过的 HELM 场景清单
helm_fast_test.py 维护了一份经过验证的 HELM 场景清单(passed列表),涵盖:
- 阅读理解/问答:
boolq、narrative_qa、quac、natural_qa、commonsense、truthful_qa、msmarco、babi_qa; - 知识/推理:
mmlu(如subject=abstract_algebra)、wikifact、math、gsm、synthetic_reasoning、synthetic_reasoning_natural、lsat_qa、med_qa; - 文本分类/毒性:
imdb、raft、civil_comments、real_toxicity_prompts、bbq、bold; - 摘要:
summarization_cnndm、summarization_xsum_sampled; - 语言学/语法:
blimp、wikitext_103、twitter_aae、dyck_language; - 数据清洗:
entity_matching(如dataset=Beer)、entity_data_imputation(如dataset=Buy); - 其他:
legal_support、lextreme、lex_glue、copyright、disinformation、synthetic_efficiency。
helm_passed_30b.sh 则给出了在 OPT-IML-30B 上的完整实测命令,例如 WikiFact 与 MMLU:
model=facebook/opt-iml-30b # WikiFact (plaintiff),约 10 分钟 time python3 helm_run.py --description wikifact:model=text,k=5,subject=plaintiff \ --model $model --percent 20 80 0 100 0 100 --gpu-batch-size 96 --num-gpu-batches 3 --cpu \ --max-eval-instance 96 # MMLU (abstract_algebra),约 31 分钟 time python3 helm_run.py --description mmlu:model=together/opt-175b,subject=abstract_algebra,data_augmentation=canonical \ --model $model --percent 20 80 0 100 0 100 --gpu-batch-size 48 --num-gpu-batches 3 --cpu \ --max-eval-instance 100注意:脚本中还包含--cpu标志与model=together/opt-175b这类来自 HELM 描述约定的占位字段,直接照搬仓库脚本即可复现;若自行构造--description,建议以 helm_fast_test.py 的passed清单为模板,并用--max-eval-instance控制评测规模。从 helm_fast_test.py 可看到其快速验证做法:先用facebook/opt-125m+ 全 GPU 策略 +--max-eval-instance 10验证场景跑通,再切换到目标大模型做完整评测。
五、offload 策略选型建议(基于仓库实测配置)
综合三个场景的脚本,可以归纳出仓库实测验证过的--percent配置规律:
| 模型规模 | 典型配置 | 适用硬件假设 | 出处 |
|---|---|---|---|
| OPT-6.7B | 100 0 100 0 100 0 | 16GB 显存即可全 GPU | test_batch_query_all_opt6.7b.sh |
| OPT-30B | 10 90 0 100 0 100/20 80 0 100 0 100 | 单 T4 + 大内存 | test_batch_query_all_opt30b.sh、helm_passed_30b.sh |
| OPT-66B | 50 10 100 0 100 0+--compress-weight | 24GB 显存 + 32GB 内存 | flexgen/apps/README.md |
| OPT-175B | 0 50 0 0 0 100+--pin-weight 0 | 单 T4 + 200GB DRAM + NVMe SSD | test_batch_query_all_opt175b.sh |
选型要点(均有源码依据):
- 六元组之和不必等于 100——权重的剩余比例会落到 NVMe 磁盘(
w_disk_percent,见 flex_opt.py),这是 FlexGen 单卡跑百亿级模型的关键机制; - 数据清洗/评测类任务输入很长、输出很短,prefill 占绝对主导,此时把激活与缓存放在算力更强的设备(GPU 或高带宽内存)通常收益更大;
- 量化压缩(
--compress-weight/--compress-cache)可在不显著牺牲精度的前提下进一步压低显存峰值,与 offload 策略叠加使用; - 批量吞吐通过
--gpu-batch-size × --num-gpu-batches控制,OPT-175B 脚本中单任务批量最高达 90(如 Restaurant 的86 × 1、Hospital 的50 × 4)。
六、总结
flexgen/apps/为 FlexGen 提供了三个可直接落地的应用入口:completion.py适合快速验证补全效果与 offload 配置;data_wrangle_run.py(含配套install.sh与 6 个测试脚本)覆盖实体匹配、数据补全、错误检测三类数据清洗任务,并在单张 T4 上实测了 6.7B/30B/175B 的吞吐数据;helm_run.py将 FlexGen 接入 HELM 评测体系,可稳定运行 MMLU、WikiFact、XSUM 等数十个场景。三者共享同一套Policy+--percent六元组 offload 编程模型,掌握了本文的参数表与配置规律,即可在受限单卡环境下按需组合出适合自己硬件预算的"单卡大模型"推理方案。更深入的调度与 offload 实现细节,可继续阅读 flexgen/flex_opt.py 与仓库根目录 README.md。
- 推理引擎
- 大模型
【免费下载链接】FlexGen
Running large language models on a single GPU for throughput-oriented scenarios.
相关推荐
FlexGen 数据整理应用实战:用单 GPU 运行实体匹配、数据补全与错误检测
FlexGen 数据整理应用实战:用单 GPU 运行实体匹配、数据补全与错误检测 本指南以 FlexGen 仓库内置的 data_wrangle 应用为例,系统
推理引擎大模型4个真实场景实战:用stats4cj从数据清洗到分位数分析的完整流程
4个真实场景实战:用stats4cj从数据清洗到分位数分析的完整流程 stats4cj 是一个基于仓颉语言实现的数学统计库,内置总体/样本均值、总体/样本方差、
数据分析科学计算Password Safe安全审计指南:如何验证你的密码库完整性
Password Safe安全审计指南:如何验证你的密码库完整性 Password Safe是一款广受欢迎的安全密码管理器,帮助用户安全存储和管理各类密码信息。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考