长线学习-4

先定位------它既不属于"能跑什么"(横向改装位),也不属于"跑起来之后怎么快"(纵向后半段),而是​纵向主线的最前端​:

scss 复制代码
请求进来 → 装模型 → step() 循环 → 吐字
            ↑
        本篇在这里:循环开始之前

所以它是​主线的"前传"​,我叫它 ​外传 · 前传:餐厅开张前的进货与摆盘​。


前传:餐厅开张前的进货与摆盘

先说清楚:为什么加载值得单独一篇

前面讲的所有东西------FlashAttention、PagedAttention、连续批、调度器------有个共同前提:模型已经在显存里了。

但一个几百 GB 的模型,从磁盘到能跑,中间有很长的路。​这条路慢起来是分钟级的 ​:你上次那条日志里,光 load_model 就 ​218 秒​。

所以这一篇回答一个问题:

那一堆上百 GB 的"零件",是怎么搬进厂房、组装成生产线、然后才开工的?


第一层:先用你的真实日志,看清加载到底慢在哪

这一步比文档讲的任何理论都有价值,因为它能直接检验文档的说法对不对。

回顾你贴的那段日志------​里面有两个时间,含义完全不同​:

less 复制代码
Multi-thread loading shards: 100% | 74/74 [00:17<00:00, 4.30it/s]   ← 17 秒
...
Loading model weights took 41.2679 GB
Model runner load_model total time: 218.68 seconds                   ← 218 秒
阶段 耗时 占比 在干什么
​读文件​(74 个 shard) 17 秒 ​8%​​ 从磁盘把权重读进 CPU 内存
加载全流程​ 218 秒 100% 上面那 17 秒 + 另外 200 秒

结论:读文件只占 8%。剩下 92%(约 200 秒)在做别的事。

那 200 秒在干什么:

动作 说明
搬运​ 权重从 CPU 内存搬到 NPU 显存(41.27 GB)
量化处理​ --quantization ascend+ w8a8,要做量化变换,不是简单搬运
TP/EP 切分重排​ 按并行规则把矩阵切开、分给各卡
MTP draft 模型加载​ 日志里llm_base_proposer.py那些行

​这个分解非常重要​------它直接决定了文档推荐的优化手段对你有没有用。下面会反复回到这个数字。


第二层:三个技术逐个拆(餐厅版)

技术一:HuggingFace 集成 ------ "按菜谱进货,按自家图纸摆盘"

0 基础理解

模型目录里存的是:​一堆权重表格(safetensors 文件)+ 一个 config.json 说明书​。

但​光有一堆表格,不等于有个能跑的模型​。就像你买回来一堆零件,还得知道"哪个零件装在哪"。

vLLM 的做法分三步:

arduino 复制代码
① 读 config.json
   → 看到 architectures: "LlamaForCausalLM"
   → 查自己的"花名册",翻到对应那一页

② 拿出 vLLM 自己那套生产线图纸
   (注意:不是 transformers 的原始图纸,是 vLLM 重画过的)

③ 把权重按图纸填进去
关键认知:vLLM 不是"跑" transformers 的代码

文档 1.2 这句话说得对:

vLLM 运行的是一套​逻辑等价、但为自己引擎高度优化过的重实现​。

为什么非要重画?因为 vLLM 的层要​配合 PagedAttention​------权重得填进"能接受 block_table 索引"的自定义层里。原始 transformers 的层没有这个接口。

打个比方:

arduino 复制代码
transformers 的图纸:标准厨房,灶台固定位置
vLLM 的图纸:      同样的菜,但灶台位置按"传送带动线"重新排过
                   菜一样好吃,但出餐快得多
⚠️ 文档 1.1 的说法过时了

文档说:

"vLLM 底层仍然调用了 ​ transformers 的 from_pretrained 方法"

​这个说法不准确。​ ​ vLLM 早就不用 from_pretrained 了------它用自己的 loader 直接读 safetensors 文件。

理由很简单:既然要把权重填进​自定义的层结构 ​,那走 transformers 的原始构建流程(先建标准模型、再拆、再搬)纯属绕远路。文档后面自己也打了补丁说"等效的底层代码(​概念性​)"。

以"概念性"为准,别以为真在调 from_pretrained。

对你日志的意义

你那 74 个 shard、17 秒读完 41 GB(约 ​2.4 GB/s​),正是这三个参数的效果:

css 复制代码
--safetensors-load-strategy 'prefetch'                                  ← 预取
--model-loader-extra-config='{"enable_multithread_load": "true",
                              "num_threads": 128}'                      ← 128 线程并发读

​IO 环节你基本已经优化到头了​------这点下面还会说。

附带:load_format="dummy" 是什么

不是优化,是​测试技巧​:不加载真实权重,用随机值填,几秒起来。

​对你的用途 ​:调配置、验证启动流程时用它,能跳过那 218 秒。等配置确认无误了,再跑真实加载。这是你调试阶段最实用的一个开关。


技术二:Tensorizer ------ "整店拍个快照,下次直接恢复"

0 基础理解

传统加载慢,慢在​组装​:

erlang 复制代码
读文件 → 反序列化 → 创建 Python 对象 → 构建层 → 搬运 → 切分 → ...

Tensorizer 的想法极其直接:

既然组装这么慢,那我第一次组装好之后,把"组装完的最终状态"整个拍个快照存下来。下次直接把快照恢复回显存不就行了?

复制代码
传统:      零件 → 一步步组装 → 生产线
Tensorizer:把组装好的生产线整个拍快照 → 下次直接快照恢复

文档那句"保存的不是如何构建结构的指令,而是权重在内存中的最终形态",说的就是这个。

但是------你的日志给出了一个明确的反证

文档宣称:能把分钟级压到 ​10~30 秒​。

​可你的日志显示:读文件只占 17 秒。就算把这 17 秒完全归零,你也只能省 8%。​ ​ 剩下 200 秒的搬运、量化、切分,Tensorizer ​一样都帮不上​。

所以在你的场景里,Tensorizer 的收益​远小于文档宣称​。三条原因:

① safetensors 本身已经是 mmap 零拷贝了

现代 vLLM 默认的 safetensors loader 就用内存映射。Tensorizer 当年快,是相对老旧的 pickle / torch.load ​ 而言的------现在两者差距已经大幅缩小。文档没说这个前提已经变了。

② 你是量化模型,量化发生在加载时

你的模型是 w8a8,--quantization ascend。量化变换是加载过程中现做 的,不是预先算好存文件里的。而 Tensorizer 存的是"最终内存形态"------​换个量化配置就得重新生成快照​(文档 2.3 自己也承认这点)。

③ 昇腾上大概率根本用不了

Tensorizer 是 CoreWeave 为 NVIDIA GPU ​ 做的,深度依赖 CUDA 和 GPU 架构(文档说"与 CUDA 版本、GPU 架构如 sm_80 强绑定")。你跑的是昇腾 NPU,​这条路基本走不通​。

结论

​Tensorizer 对你这套配置基本不适用。​ ​ 文档把它列为"生产部署首选",是基于 NVIDIA + 非量化模型的假设,跟你的场景不匹配。


技术三:分片加载 ------ "零件直接分给 8 个车间,各装各的"

0 基础理解

这就是之前讲的 ​TP(张量并行)​​ 在加载语境下的含义。

ini 复制代码
不分片:  每张卡都加载完整模型 → 装不下,且浪费
分片(TP=8):8 张卡各加载自己负责的 1/8

文档 3.1 的例子:8B 参数、TP=4 → 每卡约 2B 参数。

怎么切:切分规则预写在模型实现里

不是随便切,而是在模型代码里​提前定义好每个矩阵怎么切 ​(按列切还是按行切)。文档 4.3 提到的 _verify_and_get_linear_layer 就是干这个的。

这就是为什么 vLLM 要自己重画图纸------​切分规则也得自己写进图纸里​。

加载时的额外好处:省 IO

每个 worker 只读自己那份 → ​磁盘读取总量不变,但每张卡的内存占用降到 1/N​。

⚠️ 但你日志里有个数字对不上,值得你去核实

每个 worker 都报:

rust 复制代码
Loading model weights took 41.2679 GB
Actual usage: 41.27 GiB for weights

如果是 TP=8,每卡应该只占约 1/8 的权重,不该是完整的 41.27 GB。

三种可能:

  1. 实际是 TP=1、EP=8------注意力层每卡复制一份完整权重,只有专家被分散
  2. 这行日志打印的是"模型权重总量",不是"本卡占用量"
  3. TP/EP 的实际度数跟你以为的不一样

​怎么核实 ​:看你 run_p1.sh 里 --tensor-parallel-size 实际传的是几;再看日志里 Worker_TP2_EP2 这种编号的​最大值 ​------如果只到 TP1_EP8,那 TP 就是 1。

​为什么这个数字重要 ​:它决定了你整张显存账怎么算。如果每卡真是 41.27 GB 权重,那 60 GB 卡里剩给 KV Cache 的就那么点,跟你看到的 12.46 GiB 是对得上的;但如果 TP 真是 8,那整个账就不是这么算的。


第三层:文档问题清单

延续这个系列的一贯规律------​讲思想靠谱,讲 API 基本过时​:

位置 问题
1.1​ "底层仍调用from_pretrained"------已不准确,vLLM 用自己的 loader
2.1​ Tensorizer 的收益是相对老式 pickle 加载 而言,对现代 safetensors+mmap 边际收益大幅缩小,文档没说这个前提已变​
2.2​ 建议enforce_eager=True配合 tensorizer------你确实开了--enforce-eager,但​原因不是 tensorizer​(你是因为 MTP/PD 分离下图模式有问题),别混淆
2.3​ "版本强绑定"说得对,但没明说​只适用于 NVIDIA​,昇腾用不了
3.3​ pipeline_parallel_size=2, tensor_parallel_size=4标注了"概念性示例"------V1 里 PP 支持有限,别当真​
3.2​ placement_config手动指定设备,高级 API,​可能变动​,且不确定昇腾插件支持
4.2​ 通信库写的是​NCCL ​(NVIDIA),你在昇腾上对应的是HCCL​
通篇 所有示例是​V0 早期 API​,你跑的是 V1

第四层:对你实际工作的三条建议

1. 别在"读文件"上再花力气了

17 秒 / 218 秒 = ​**8%**​。你已经开了 128 线程 + 预取,IO 基本到头。继续加线程、换更快的盘,收益极其有限。

2. 218 秒启动时间,固定部署下可以不管

关键是​这是一次性开销​。服务起来跑几天,218 秒摊薄到近乎为零。

​只有这三种场景才需要优化它​:

场景 为什么
K8s 按流量自动扩实例 每次扩容干等 3.6 分钟
需要快速故障恢复 实例挂了要秒级拉起
频繁改配置重启调试 → 用load_format="dummy"更快

你是固定裸机、长期跑着的,​这 218 秒根本不用管​。

3. 如果真要优化,方向不是 tensorizer

在你场景下更实际的:

  • 权重常驻高速盘/共享内存,避免每次冷读
  • **dummy 模式验证配置**,最后一次真实加载
  • ⭐ 确认量化能否离线预做 ------如果 w8a8 能在离线阶段算好直接存盘(而不是加载时现算),能省掉相当一部分的 200 秒。这可能是你唯一能吃到的、真正的加载加速,值得去查你们量化工具链支不支持"离线量化存档"。

知识树:补上这一篇

arduino 复制代码
vLLM 知识体系
│
├─ 【前传·本篇】模型怎么装进来(step 循环之前)
│   ├─ HF 集成:读 config.json → 查注册表 → 按 vLLM 图纸填权重
│   ├─ 分片加载:TP=N,每卡只拿 1/N   ← 日志 41.27GB 待核实
│   └─ Tensorizer:整机快照(NVIDIA 专属,你用不上)
│
├─ 【主线】装完之后怎么跑得快
│   ├─ FlashAttention / PagedAttention
│   ├─ Scheduler / Worker / Engine(连续批)
│   └─ 图模式
│
└─ 【外传】能跑什么
    ├─ 底盘变体:decoder-only / encoder-only
    └─ 改装位:MoE / 多模态 / Embedding

一句总结

加载 = ​搬零件 + 组装 ​。你的日志显示搬零件只占 ​8%(17 秒)​,组装占 ​ 92%(200 秒)​------所以文档主推的 Tensorizer(本质是加速搬零件)​对你收益极小,且昇腾上大概率不可用 ​。真正该做的不是加速加载,而是​核实那 41.27 GB 是每卡量还是总量 ​,以及​量化能否离线预做​。


相关推荐
大明二代44 分钟前
Mastra RAG 进阶:使用 Drizzle ORM 和 pgvector 实现文档版本管理与 Version-aware Retrieval
人工智能
stormzhangV44 分钟前
AI 平权后,最该重视的 8 种能力
人工智能·aigc·产品
RockChinQ1 小时前
QQ 好友申请与被拉进群:两道审批交给同一个 Agent
人工智能
江润舟1 小时前
万物|炼器:从零手搓工业级旋转目标检测网络·卷5 —— YAML蓝图与parse_model动态引擎(一)
人工智能·深度学习
用户1917291270831 小时前
企业 Agent 接不进现有系统?跨厂商协议网关选型与接入自查
人工智能
柯南46681 小时前
【AI工程师精讲】15:DPO:不训奖励模型、不做强化学习,也能完成对齐
人工智能·ai编程
亚远景aspice1 小时前
亚远景-低空经济与具身智能:具身智能飞行器量产落地,过程合规与安全体系怎么搭
人工智能·安全·过程改进·低空经济·研发管理·亚远景科技·过程能力评估
天远数科1 小时前
Java数据工程:利用天远车辆估值优化商业银行汽车抵押贷款押品估值合规体验
人工智能
第404号工位1 小时前
手机到底有没有偷听我们?我抓包了 72 小时,抓到了真凶
linux·人工智能·架构