什么是逐层(重)加载?¶
逐层重加载(Layerwise reloading)是用于处理将新权重数据加载到现有权重数据目标位置的系统,而无需触发 CUDA 图(cuda graph)和其他运行时制品的重新编译。该系统用于支持 QeRL 风格的训练后流程,其中全精度训练器权重被量化并加载到目标 vLLM 实例中,以实现快速、高探索性的 rollout。核心实现可以在 layerwise.py 中找到。
用于 QeRL 的逐层重加载¶
为了将新权重加载到现有权重数据目标中,权重必须经过以下操作:
- 传输(Transfer):权重必须从训练器模型传输到目标节点/设备
- 融合(Fuse):权重分区必须进行融合,例如 qkv/gate_up
- 处理(Process):这通常意味着在线量化以及特定于算子的填充(padding)或跨步(striding)
- 切分(Shard):权重必须根据选定的并行策略进行切分
- 复制(Copy):权重必须复制到现有的权重数据目标中
逐层重加载通过以下步骤实现这一目标:
- 权重从训练器传输到目标(参见 weight_transfer)
- 权重通过
model.load_weights加载,期间进行切分和融合 - 一旦某一层的所有权重都加载完毕,权重就会以在线方式进行处理
- 权重被复制到现有的权重数据目标中
有关实现的更多信息,请参阅 底层级 layerwise API。
带有在线量化的逐层加载¶
在线量化(Online quantization)是指用户提供全精度权重,而这些权重在加载到模型中时即时进行量化。逐层重加载系统通过将在线量化视为一个处理步骤来处理它,该步骤在首次加载和重加载期间都以在线方式处理。典型的在线量化方法实现应如下所示
class Fp8PerTensorOnlineLinearMethod(LinearMethodBase):
"""Online version of FP8 per-tensor quantization which loads a full
precision checkpoint and quantizes weights during loading."""
uses_meta_device: bool = True
def create_weights(self, layer: torch.nn.Module, ...):
# weight is materialized and processed during loading
layer.weight = ModelWeightParameter(
data=torch.empty(..., device="meta"),
weight_loader=weight_loader,
)
# set up online processing
initialize_online_processing(layer)
def process_weights_after_loading(self, layer: Module) -> None:
if getattr(layer, "_already_called_process_weights_after_loading", False):
return
layer.weight, layer.weight_scale = ops.scaled_fp8_quant(layer.weight)
# Prevent duplicate processing (e.g., during weight reload)
layer._already_called_process_weights_after_loading = True
用法示例¶
高层级权重传输 API¶
逐层重加载系统已与训练后权重传输系统集成。要将逐层重加载与权重传输系统结合使用,请参考 这里的示例。检查点格式的权重传输引擎(例如 NCCL 和 IPC 后端)会在其 start_weight_update/finish_weight_update 生命周期内自动运行逐层重加载。
中层级 reload_weights API¶
逐层重加载也可以通过 reload_weights API 暴露。此接口可以使用以下代码调用
此接口还允许指定 weights_path,用于选择要加载的检查点路径
from vllm import LLM
# fine tuned model checkpoints for testing
mul_path = "inference-optimization/Qwen3-0.6B-debug-multiply"
add_path = "inference-optimization/Qwen3-0.6B-debug-add"
llm = LLM("Qwen/Qwen3-0.6B")
llm.collective_rpc("reload_weights", kwargs={"weights_path": mul_path})
llm.generate("3 4 = ") # 12
llm.collective_rpc("reload_weights", kwargs={"weights_path": add_path})
llm.generate("3 4 = ") # 7
最后,可以直接提供 weights_iterator。此迭代器可以是惰性定义的,也可以是立即定义的。
from vllm import LLM
weights_iterator = [("q_proj", ...), ("k_proj", ...), ...]
llm = LLM("Qwen/Qwen3-0.6B")
llm.collective_rpc("reload_weights", kwargs={"weights_iterator": weights_iterator})
底层级 layerwise API¶
layerwise.py 实现了以下函数以执行其生命周期:
| 函数 | 目的 | 量化重加载 | 在线量化 |
|---|---|---|---|
record_metadata_for_reloading | 记录张量元数据,以便在元设备(meta device)上还原层 | 由 BaseModelLoader 调用 | 由 BaseModelLoader 调用 |
restore_layer_on_meta | 在重加载开始时将层还原为模型格式 | 由 initialize_layerwise_reload 调用 | 未调用。在线量化权重已通过 ...OnlineLinearMethod.create_weights 在元设备上启动 |
initialize_online_processing | 使用 online_process_loader 封装器封装权重加载器,该封装器会缓冲权重,直到加载完所有层权重 | 由 initialize_layerwise_reload 调用 | 由 ...OnlineLinearMethod.create_weights 调用 |
_layerwise_process | 一旦所有权重加载完毕,立即处理该层 | 加载期间由 online_process_loader 调用 | 加载期间由 online_process_loader 调用 |
_copy_and_restore_kernel_tensors | 将处理后的权重复制到原始张量位置,以影响已编译的 CUDA 图等。 | 在 process_weights_after_loading 之后由 _layerwise_process 调用 | 未调用。目前还没有编译好的 CUDA 图 |
finalize_layerwise_processing | 捕获任何未加载全部权重的层(例如注意力权重或带填充的权重) | 由 BaseModelLoader 调用 | 由 BaseModelLoader 调用 |
你可以通过调用 initialize_layerwise_reload、加载权重,然后调用 finalize_layerwise_processing 来直接接入此生命周期
from vllm import LLM
from vllm.model_executor.model_loader.reload import initialize_layerwise_reload, finalize_layerwise_processing
llm = LLM("Qwen/Qwen3-0.6B")
# this model path requires `VLLM_ENABLE_V1_MULTIPROCESSING=0` and is not stable
model = llm.llm_engine.engine_core.engine_core.model_executor.driver_worker.worker.get_model()
# layerwise reload
initialize_layerwise_reload(model)
model.load_weights(...)
finalize_layerwise_processing(model, llm.model_config)
排查内存占用过高问题¶
逐层重加载允许用户在权重加载到模型时增量地加载和处理权重。该系统依赖于在设备上缓冲层权重,直到该层的所有权重都已加载。然而,在没有卸载(offloading)的情况下,如果权重加载顺序混乱,这种方法必然会导致过度缓冲。
因此,用户在重新加载到模型时必须注意权重的顺序。权重应“按顺序”加载,这意味着在开始加载下一层的权重之前,每一层的权重都已完全加载。“乱序”加载会导致某些层权重在其他层权重加载时保持缓冲状态,从而导致内存占用过高。在下面的示例中,q_proj、k_proj、v_proj 和 up_proj 同时被缓冲,比在 q_proj、k_proj 和 v_proj 之后加载 up_proj 消耗更多内存。
| 正确的加载方式 | 错误的加载方式 |
|---|---|
![]() | ![]() |
如果权重乱序加载,用户将看到如下警告。


