Skip to content

DefaultModelLoader: moving weights from HF Hub onto the GPU ​

源码版本v0.25.1

Responsibilities ​

The model loader is the stage in vLLM's startup flow that moves model weights from disk or Hugging Face Hub into GPU memory. DefaultModelLoader is the most commonly used implementation; it handles multiple on-disk formats — safetensors / .pt / Mistral's native format / npcache — stitches sharded weights into a (name, tensor) iterator, and hands it to the model's own load_weights method to populate nn.Module one tensor at a time. Built on top of BaseModelLoader, it strings together four jobs — download, filter, parse, iterate — without caring about how tensors are sharded or quantized. Those two concerns are owned by layers like ColumnParallelLinear and by QuantizationConfig.

A typical load goes roughly: __init__ validates model_loader_extra_config inside LoadConfig (default_loader.py:74-126), allowing only enable_multithread_load, num_threads, enable_weights_track. download_model delegates to _prepare_weights, which picks allow_patterns based on load_format, globs the local directory directly, or calls download_weights_from_hf for remote sources (default_loader.py:194-207). load_weights is the entry that actually does the work: it initializes the EP filter (default_loader.py:425-426), feeds the get_all_weights iterator into model.load_weights, then uses track_weights_loading to verify no parameters were missed (default_loader.py:444-445).

Design motivation ​

Why split the loader into a Loader + Source two-layer design?

  • Multi-source weights: Some models carry secondary_weights outside the main body (e.g. a multimodal visual encoder with its own checkpoint). The Source dataclass lets each source carry its own prefix, fall_back_to_pt, allow_patterns_overrides (default_loader.py:49-69), and get_all_weights stitches them into a single iterator (default_loader.py:321-340).
  • Format fork: A single load_format field decides which path to take; auto probes for consolidated*.safetensors and switches to mistral (default_loader.py:151-163); safetensors / fastsafetensors / instanttensor force .safetensors only, while pt / npcache take the legacy path.
  • Multi-threaded acceleration: enable_multithread_load switches to multi_thread_safetensors_weights_iterator or multi_thread_pt_weights_iterator, default 8 threads (default_loader.py:278-308); but the multi-threaded mode only supports the default lazy strategy and is mutually exclusive with other safetensors_load_strategy options (default_loader.py:116-126).
  • EP weight filtering: For MoE + expert parallelism, only the experts owned by this rank are loaded. _init_ep_weight_filter computes local_expert_ids (default_loader.py:351-412), and the safetensors iterator later skips non-local expert tensors, saving disk IO.
  • Safetensors index dedup: Models like Mistral-7B-Instruct-v0.3 ship both sharded and consolidated safetensors; a naive glob would read both and conflict. filter_duplicate_safetensors_files uses model.safetensors.index.json to filter (default_loader.py:217-235).
  • Load tracking: Non-quantized models default to enable_weights_track=True; after loading, it diffs against named_parameters to flag missing weights, so inference never silently runs with random weights (default_loader.py:434-445).

Key files ​

Data flow ​

The caller (typically the worker's load_model) first constructs a DefaultModelLoader via __init__, then calls load_weights(model, model_config). Inside the function body, the first step adjusts the safetensors load strategy when quantization == "torchao", then _init_ep_weight_filter computes the EP filter set, get_all_weights feeds each Source into _get_weights_iterator to build a generator, and finally model.load_weights consumes it:

python
@instrument(span_name="Load weights")
def load_weights(self, model: nn.Module, model_config: ModelConfig) -> None:
    if model_config.quantization == "torchao":
        quant_config = get_quant_config(model_config, self.load_config)
        if (
            hasattr(quant_config, "is_checkpoint_torchao_serialized")
            and quant_config.is_checkpoint_torchao_serialized
            and torchao_version_at_least("0.15.0")
        ):
            self.load_config.safetensors_load_strategy = "torchao"

    self._init_ep_weight_filter(model_config)

    loaded_weights = model.load_weights(self.get_all_weights(model_config, model))

    self.counter_after_loading_weights = time.perf_counter()
    logger.info_once(
        "Loading weights took %.2f seconds",
        self.counter_after_loading_weights - self.counter_before_loading_weights,
    )
    # We only enable strict check for non-quantized models
    # that have loaded weights tracking by default.
    default_enable_weights_track = (
        model_config.quantization is None and loaded_weights is not None
    )

(default_loader.py:414-438) Note that model.load_weights(...) is where tensors are actually copied into nn.Module. Every vLLM model implementation customizes this method, matching each tensor name to its corresponding weight_loader (e.g. ColumnParallelLinear.weight_loader_v2); sharding and quantization happen at that layer. See Tensor-parallel linear layers and Quantized layer loading for details.

Boundaries and failure modes ​

  • Unknown load_format: Any value outside hf / safetensors / fastsafetensors / instanttensor / mistral / pt / npcache directly raises ValueError (default_loader.py:183-184).
  • Weight files not found: When the glob matches nothing, it raises Cannot find any model weights (default_loader.py:237-240).
  • Multi-threading + safetensors_load_strategy incompatibility: enable_multithread_load=True only supports the default lazy strategy; combining it with other strategies raises ValueError (default_loader.py:118-126).
  • extra_config type errors: model_loader_extra_config not a dict, keys outside the whitelist, or num_threads not a positive integer all error immediately (default_loader.py:79-110).
  • Skip EP filter under EPLB: When enable_eplb is on, redundant expert slots point to another rank's logical expert; filtering would leave these slots unfilled, so the entire block returns early (default_loader.py:370-375).
  • Quantized models skip tracking validation: When the quantization method has process_weights_after_loading or uses_meta_device, the checkpoint may not contain the corresponding scales, so these parameters are excluded from the tracking set (default_loader.py:453-462).

Summary ​

DefaultModelLoader handles three things well — find files, download files, iterate tensors — and leaves sharding / quantization / dequantization to the layers and quantization methods. Its seam with Tensor-parallel linear layers is that model.load_weights looks up the weight_loader for each tensor name internally; its seam with Quantized layer loading is that quant_config.get_quant_method installs a LinearMethodBase onto each layer, which the loader itself is unaware of.

See official docs: vLLM docs · README