Prhub

#40183 [Core] Use fastsafetensors ParallelLoader for weight loading

原始 PR 作者 gitbisector 合并时间 2026-06-16 13:32 文件变更 3 提交数 8 评论 12 代码增减 +68 / -56

执行摘要

用 ParallelLoader 替换手动分片加载,提升速度并支持流水线

利用 fastsafetensors 0.2.0 引入的 ParallelLoader 实现 pipelined loading,在 75 GB 模型上即刻获得约 10% 的加载速度提升,并通过 copier 注册表自动继承未来 copier 改进(如 unified-memory copier),使 vLLM 无需额外适配即可受益。

此 PR 设计精巧,通过外部库新特性实现性能提升,同时保持向后兼容。值得精读其回退机制和环境变量设计。对于关注模型加载性能的工程师是重要参考。

讨论亮点
  1. @gemini-code-assist 建议在传递 use_tqdm_on_load 时使用 enable_tqdm 确保仅 rank 0 显示进度条,但 @gitbisector 回复指出 ParallelLoader 内部已实现 rank-0 门控(parallel_loader.py:340),因此无需重复处理。
  2. @DarkLight1337 指出 gguf import 未使用,@gitbisector 确认是 rebase 产物并已删除。

实现拆解

  1. 移除手动分片循环:在 weight_utils.py 中删除 _init_fastsafetensors_loader 函数和基于 SafeTensorsFileLoader 的循环,改为调用 parallel_loader.ParallelLoader
  2. 引入 ParallelLoader 工厂函数:在 fastsafetensors_weights_iterator 内部定义 _make_loader,封装参数并处理 GDS 运行失败回退。
  3. 配置流水线深度:在 envs.py 中添加 VLLM_FASTSAFETENSORS_QUEUE_SIZE 环境变量,默认 0 保持原内存占用,设置 >0 启用预取。
  4. 更新测试:在测试文件中添加 @pytest.mark.parametrize("queue_size", [0, 1]),用 monkeypatch 设置环境变量,覆盖两种加载路径并与参考实现对比。
文件 模块 状态 重要度
vllm/model_executor/model_loader/weight_utils.py 权重加载器 modified 8.09
vllm/envs.py 环境配置 modified 5.49
tests/model_executor/model_loader/fastsafetensors_loader/test_weight_utils.py 测试用例 modified 5.2

关键符号

fastsafetensors_weights_iterator _make_loader test_fastsafetensors_model_loader

关键源码片段

vllm/model_executor/model_loader/weight_utils.py core-logic

核心实现文件,替换手动循环为 ParallelLoader,添加 GDS 回退工厂函数

def fastsafetensors_weights_iterator(
    hf_weights_files: list[str],
    use_tqdm_on_load: bool,
) -> Generator[tuple[str, torch.Tensor], None, None]:
    """使用 fastsafetensors 库迭代模型权重文件,采用 ParallelLoader 实现流水线加载。"""
    from fastsafetensors.parallel_loader import ParallelLoader
​
    # 确定进程组:如果已初始化则用 WORLD,否则用单组
    pg = torch.distributed.group.WORLD if torch.distributed.is_initialized() else SingleGroup()
    device = torch.device(f"cuda:{current_platform.current_device()}")
    hf_weights_files = sorted(hf_weights_files, key=_natural_sort_key)
​
    # 当 TP > 1 时启用 nogds,避免 cuFileDriverOpen 创建多余 CUDA 上下文
    nogds = pg.size() > 1
    queue_size = envs.VLLM_FASTSAFETENSORS_QUEUE_SIZE
    tqdm_enabled = enable_tqdm(use_tqdm_on_load)
​
    def _make_loader(nogds: bool) -> "ParallelLoader":
        """创建 ParallelLoader 实例,封装所有参数。"""
        return ParallelLoader(
            pg=pg,
            hf_weights_files=hf_weights_files,
            queue_size=queue_size,
            use_tqdm_on_load=tqdm_enabled,
            device=str(device),
            nogds=nogds,
        )
​
    # 尝试使用 GDS(如果有),如果失败则回退到 nogds
    try:
        loader = _make_loader(nogds)
        yield from loader.iterate_tensors()
    except RuntimeError as e:
        if "gds" not in str(e).lower():
            raise # 非 GDS 错误直接向上传播
        logger.warning_once(
            "GDS 未启用,正在以 nogds=True 重试。"
        )
        loader = _make_loader(nogds=True)
        yield from loader.iterate_tensors()

评论区精华

分布式环境中 tqdm 进度条显示问题 正确性

@gemini-code-assist 建议在传递 use_tqdm_on_load 时使用 enable_tqdm 确保仅 rank 0 显示进度条,避免多 rank 重复输出。

结论:@gitbisector 回复指出 ParallelLoader 内部已实现 rank-0 门控,因此 vLLM 端无需重复处理。 · 已解决

未使用的 gguf import style

@DarkLight1337 发现 weight_utils.py 中新增的 gguf import 实际上未被使用。

结论:@gitbisector 承认是 rebase 引入的冗余,并立即删除该 import。 · 已解决

风险与影响

  1. 依赖外部库:需要 fastsafetensors>=0.2.0,但现有代码已有导入检查。
  2. VRAM 增加queue_size>0 会增加峰值 VRAM,用户需注意设置。
  3. GDS 回退可靠性:新回退逻辑捕获运行时 RuntimeError,但若异常字符串不包含 'gds' 则直接抛出,可能影响非 GDS 错误。
  4. 测试覆盖不完整:仅测试 queue_size=0,1,更高队列值未测试。

用户:使用 --load-format fastsafetensors 的模型可获得约 10% 的加载速度提升,且可通过环境变量调整。系统:无 Breaking Change,默认内存占用不变。团队:代码简化,并自动继承 fastsafetensors 的 copier 改进,降低后续维护成本。

核心路径变更 依赖外部库版本 VRAM 可能增加 GDS 回退可靠性

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论