Load constant expert values at the load_weights boundary.
Initial loading and direct weight updates both go through load_weights.
Explicitly named values are always consumed and loaded if their layer is
built by this model. approx_value tensors of layers built elsewhere
(other pipeline stages, MTP layers) are passed through, so the model's own
loader skips them like any other weight of a layer it does not own.
Source code in vllm/model_executor/models/expert_substitution.py
| def as_expert_substitution_model(model_cls: type[_T], model_config: Any) -> type[_T]:
"""Load constant expert values at the ``load_weights`` boundary.
Initial loading and direct weight updates both go through ``load_weights``.
Explicitly named values are always consumed and loaded if their layer is
built by this model. ``approx_value`` tensors of layers built elsewhere
(other pipeline stages, MTP layers) are passed through, so the model's own
loader skips them like any other weight of a layer it does not own.
"""
spec = get_expert_substitution_spec(model_config)
if spec is None:
return model_cls
value_names = spec.value_names
class ExpertSubstitutionModel(model_cls): # type: ignore[valid-type, misc]
@wraps(model_cls.__init__) # type: ignore[misc]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._expert_substitutions = _collect_expert_substitutions(self)
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
if any(s.values.is_meta for _, s in self._expert_substitutions.values()):
# Put the previous weights back so the model stays usable.
finalize_layerwise_reload(self, model_config)
raise NotImplementedError(
"expert substitution does not support layerwise weight reload"
)
loaded_substitutions: set[str] = set()
def remaining_weights():
for name, loaded_weight in weights:
targets = value_names.get(name)
if targets is None:
key = _parse_approx_value_name(name)
if key is None or key[0] not in self._expert_substitutions:
yield name, loaded_weight
continue
targets = (key,)
for layer_idx, expert_id in targets:
if layer_idx not in self._expert_substitutions:
continue
param_name, substitution = self._expert_substitutions[layer_idx]
param = substitution.values
param.weight_loader(param, loaded_weight, expert_id)
loaded_substitutions.add(param_name)
loaded = super().load_weights(remaining_weights())
if loaded is not None:
loaded.update(loaded_substitutions)
return loaded
def process_weights_after_loading(self) -> None:
for param_name, substitution in self._expert_substitutions.values():
substitution.validate_loaded_values(param_name)
finalize = getattr(super(), "process_weights_after_loading", None)
if finalize is not None:
finalize()
ExpertSubstitutionModel.__name__ = model_cls.__name__
ExpertSubstitutionModel.__qualname__ = model_cls.__qualname__
return ExpertSubstitutionModel
|