| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- # SPDX-License-Identifier: Apache-2.0
- """Zero-pad GLM-5.3-Flash weights at load time so uneven dims split at TP=3.
- The served config.json carries padded sizes (num_attention_heads,
- linear_num_heads, moe_intermediate_size) plus ``tp_pad_orig`` with the
- checkpoint's real ones. Every checkpoint tensor that is sized by one of those
- dims is zero-extended here, before vLLM's loaders narrow it per rank, so the
- extra heads / intermediate columns land at the end (the last rank's slice).
- Zero rows/cols are exact no-ops:
- - MLA: a zero head has q=0 and zero kv_b rows (so V=0) and zero o_proj cols.
- - KDA: q=k=v=0 keeps the recurrent state at 0, the gated RMSNorm of a zero
- vector is 0, and the o_proj cols are 0.
- - MoE / shared expert: gate=up=0 gives silu(0)*0=0, down cols are 0.
- NVFP4 tensors: packed uint8 zero = two FP4 +0 codes, fp8 block scale 0.
- """
- import torch
- from vllm.logger import init_logger
- logger = init_logger(__name__)
- def _pad(t: torch.Tensor, dim: int, size: int) -> torch.Tensor:
- if t.shape[dim] == size:
- return t
- assert t.shape[dim] < size, (tuple(t.shape), dim, size)
- src = t.view(torch.uint8) if t.element_size() == 1 else t
- shape = list(src.shape)
- shape[dim] = size
- out = src.new_zeros(shape)
- out.narrow(dim, 0, src.shape[dim]).copy_(src)
- return out.view(t.dtype) if t.element_size() == 1 else out
- def _cols(name: str, t: torch.Tensor, logical: int) -> int:
- """Physical width of a padded input dim for this tensor's format."""
- if name.endswith(".weight_scale"):
- return logical // 16
- if t.dtype == torch.uint8:
- return logical // 2
- return logical
- def pad_weights(weights, config):
- orig = getattr(config, "tp_pad_orig", None)
- if not orig:
- yield from weights
- return
- H0, H1 = orig["num_attention_heads"], config.num_attention_heads
- K0, K1 = orig["linear_num_heads"], config.linear_num_heads
- I0, I1 = orig["moe_intermediate_size"], config.moe_intermediate_size
- qk = config.qk_nope_head_dim + config.qk_rope_head_dim
- kvb = config.qk_nope_head_dim + config.v_head_dim
- v = config.v_head_dim
- hd = config.linear_head_dim
- ns = config.n_shared_experts or 1
- n = 0
- for name, t in weights:
- new = t
- if ".self_attn." in name and ".indexer." not in name:
- s = name.rsplit(".self_attn.", 1)[1]
- if s == "q_b_proj.weight" and t.shape[0] == H0 * qk:
- new = _pad(t, 0, H1 * qk)
- elif s == "kv_b_proj.weight" and t.shape[0] == H0 * kvb:
- new = _pad(t, 0, H1 * kvb)
- elif s == "o_proj.weight" and t.shape[1] == H0 * v:
- new = _pad(t, 1, H1 * v)
- elif s == "o_proj.weight" and t.shape[1] == K0 * hd:
- new = _pad(t, 1, K1 * hd)
- elif s in ("q_proj.weight", "k_proj.weight", "v_proj.weight",
- "f_b_proj.weight", "g_b_proj.weight", "dt_bias",
- "q_conv1d.weight", "k_conv1d.weight", "v_conv1d.weight") \
- and t.shape[0] == K0 * hd:
- new = _pad(t, 0, K1 * hd)
- elif s in ("b_proj.weight", "A_log") and t.shape[0] == K0:
- new = _pad(t, 0, K1)
- elif ".mlp.experts." in name or ".mlp.shared_experts." in name:
- i0, i1 = (I0 * ns, I1 * ns) if ".shared_experts." in name else (I0, I1)
- if name.endswith((".weight", ".weight_scale")):
- if (".gate_proj." in name or ".up_proj." in name) and t.shape[0] == i0:
- new = _pad(t, 0, i1)
- elif ".down_proj." in name and t.shape[1] == _cols(name, t, i0):
- new = _pad(t, 1, _cols(name, t, i1))
- if new is not t:
- n += 1
- yield name, new
- logger.info("tp3pad: zero-padded %d tensors (heads %d->%d, kda %d->%d, moe I %d->%d)",
- n, H0, H1, K0, K1, I0, I1)
|