|
55 | 55 | if TYPE_CHECKING: |
56 | 56 | from mobius.components._attention import GQAContext |
57 | 57 |
|
| 58 | + |
| 59 | +# --------------------------------------------------------------------------- |
| 60 | +# Shared weight preprocessing helpers |
| 61 | +# --------------------------------------------------------------------------- |
| 62 | + |
| 63 | + |
| 64 | +def _remap_moe_expert_weights( |
| 65 | + state_dict: dict[str, torch.Tensor], |
| 66 | + config: Gemma4Config, |
| 67 | +) -> None: |
| 68 | + """Rename HF MoE expert weights and fold router scale in-place. |
| 69 | +
|
| 70 | + Shared by ``Gemma4CausalLMModel`` and ``Gemma4Model`` to avoid |
| 71 | + duplicating the rename/fold logic. |
| 72 | + """ |
| 73 | + # experts.gate_up_proj → fc1_experts_weights |
| 74 | + # experts.down_proj → fc2_experts_weights |
| 75 | + for key in list(state_dict.keys()): |
| 76 | + if ".experts.gate_up_proj" in key: |
| 77 | + new_key = key.replace(".experts.gate_up_proj", ".fc1_experts_weights") |
| 78 | + state_dict[new_key] = state_dict.pop(key) |
| 79 | + elif ".experts.down_proj" in key: |
| 80 | + new_key = key.replace(".experts.down_proj", ".fc2_experts_weights") |
| 81 | + state_dict[new_key] = state_dict.pop(key) |
| 82 | + |
| 83 | + # Fold hidden_size^-0.5 into router.scale |
| 84 | + if config.enable_moe_block: |
| 85 | + scale_factor = float(config.hidden_size**-0.5) |
| 86 | + for key in list(state_dict.keys()): |
| 87 | + if ".router.scale" in key and ".per_expert_scale" not in key: |
| 88 | + state_dict[key] = state_dict[key] * scale_factor |
| 89 | + |
| 90 | + |
58 | 91 | # --------------------------------------------------------------------------- |
59 | 92 | # Scale-free RMSNorm (Gemma4RMSNorm with with_scale=False) |
60 | 93 | # --------------------------------------------------------------------------- |
@@ -1653,27 +1686,8 @@ def preprocess_weights( |
1653 | 1686 | for i in range(num_layers): |
1654 | 1687 | shard = value[:, i * per_layer_dim : (i + 1) * per_layer_dim] |
1655 | 1688 | state_dict[f"model.embed_tokens_per_layer.{i}.weight"] = shard |
1656 | | - # Map HF expert weight names to our 3D stacked parameter names. |
1657 | | - # HF stores: layers.N.experts.gate_up_proj [E, 2*inter, H] |
1658 | | - # layers.N.experts.down_proj [E, H, inter] |
1659 | | - # We store: layers.N.fc1_experts_weights [E, 2*inter, H] |
1660 | | - # layers.N.fc2_experts_weights [E, H, inter] |
1661 | | - for key in list(state_dict.keys()): |
1662 | | - if ".experts.gate_up_proj" in key: |
1663 | | - new_key = key.replace(".experts.gate_up_proj", ".fc1_experts_weights") |
1664 | | - state_dict[new_key] = state_dict.pop(key) |
1665 | | - elif ".experts.down_proj" in key: |
1666 | | - new_key = key.replace(".experts.down_proj", ".fc2_experts_weights") |
1667 | | - state_dict[new_key] = state_dict.pop(key) |
1668 | | - # Fold hidden_size^-0.5 into router.scale. |
1669 | | - # The router computes: x_normed * scale * hidden_size^-0.5. |
1670 | | - # We pre-multiply scale by hidden_size^-0.5 here so the forward only needs |
1671 | | - # x_normed * self.scale, avoiding float-constant name collisions across layers. |
1672 | | - if self.config.enable_moe_block: |
1673 | | - scale_factor = float(self.config.hidden_size**-0.5) |
1674 | | - for key in list(state_dict.keys()): |
1675 | | - if ".router.scale" in key: |
1676 | | - state_dict[key] = state_dict[key] * scale_factor |
| 1689 | + # Map HF expert weight names and fold router scale |
| 1690 | + _remap_moe_expert_weights(state_dict, self.config) |
1677 | 1691 | return super().preprocess_weights(state_dict) |
1678 | 1692 |
|
1679 | 1693 |
|
@@ -2150,22 +2164,7 @@ def preprocess_weights( |
2150 | 2164 | else: |
2151 | 2165 | renamed[key] = value |
2152 | 2166 |
|
2153 | | - # Map HF expert weight names to our 3D stacked parameter names. |
2154 | | - # HF: decoder.model.layers.N.experts.gate_up_proj [E, 2*inter, H] |
2155 | | - # Us: decoder.model.layers.N.fc1_experts_weights [E, 2*inter, H] |
2156 | | - for key in list(renamed.keys()): |
2157 | | - if ".experts.gate_up_proj" in key: |
2158 | | - new_key = key.replace(".experts.gate_up_proj", ".fc1_experts_weights") |
2159 | | - renamed[new_key] = renamed.pop(key) |
2160 | | - elif ".experts.down_proj" in key: |
2161 | | - new_key = key.replace(".experts.down_proj", ".fc2_experts_weights") |
2162 | | - renamed[new_key] = renamed.pop(key) |
2163 | | - |
2164 | | - # Fold hidden_size^-0.5 into router.scale |
2165 | | - if self.config.enable_moe_block: |
2166 | | - scale_factor = float(self.config.hidden_size**-0.5) |
2167 | | - for key in list(renamed.keys()): |
2168 | | - if ".router.scale" in key and ".per_expert_scale" not in key: |
2169 | | - renamed[key] = renamed[key] * scale_factor |
| 2167 | + # Map HF expert weight names and fold router scale |
| 2168 | + _remap_moe_expert_weights(renamed, self.config) |
2170 | 2169 |
|
2171 | 2170 | return renamed |
0 commit comments