From 88ec63121d230b56b7a2ccfa8309851d004531f2 Mon Sep 17 00:00:00 2001 From: ViperEkura <3081035982@qq.com> Date: Thu, 25 Jun 2026 15:04:27 +0800 Subject: [PATCH] feat : GPT-2 residual scaling weight init - Linear: normal(0, init_std) replaces kaiming_uniform_(a=sqrt(5)) - o_proj / mlp.down: init_std = 0.02 / sqrt(2 * n_layers) - MoE: expert down scaled by 1/sqrt(1/n_shared + 1/K) - Embedding: normal(0, 0.02), unchanged --- astrai/model/components/attention.py | 8 ++++++-- astrai/model/components/decoder_block.py | 1 + astrai/model/components/linear.py | 7 +++++-- astrai/model/components/mlp.py | 17 +++++++++++++---- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/astrai/model/components/attention.py b/astrai/model/components/attention.py index 3cf00a7..3a64b4c 100644 --- a/astrai/model/components/attention.py +++ b/astrai/model/components/attention.py @@ -38,6 +38,7 @@ class GQA(nn.Module): norm_eps: float, use_gated_attention: bool, layer_id: int, + n_layers: int = 1, ): super().__init__() assert dim % n_heads == 0 @@ -55,7 +56,7 @@ class GQA(nn.Module): self.q_proj = Linear(dim, n_heads * self.head_dim) self.k_proj = Linear(dim, n_kv_heads * self.head_dim) self.v_proj = Linear(dim, n_kv_heads * self.head_dim) - self.o_proj = Linear(dim, dim) + self.o_proj = Linear(dim, dim, init_std=0.02 / (2 * n_layers) ** 0.5) if self.use_qk_norm: self.q_norm = RMSNorm(self.head_dim, norm_eps) @@ -121,6 +122,7 @@ class MLA(nn.Module): use_qk_norm: bool, use_gated_attention: bool, layer_id: int, + n_layers: int = 1, ): super().__init__() self.dim = dim @@ -148,7 +150,9 @@ class MLA(nn.Module): n_kv_heads * (2 * self.head_dim), ) - self.o_proj = Linear(dim, dim, bias=False) + self.o_proj = Linear( + dim, dim, bias=False, init_std=0.02 / (2 * n_layers) ** 0.5 + ) if use_gated_attention: self.gate = Linear(dim, dim, bias=False) diff --git a/astrai/model/components/decoder_block.py b/astrai/model/components/decoder_block.py index d5c71aa..18d71a3 100644 --- a/astrai/model/components/decoder_block.py +++ b/astrai/model/components/decoder_block.py @@ -14,6 +14,7 @@ class DecoderBlock(nn.Module): def __init__(self, config, layer_id: int): super().__init__() cfg = asdict(config) + cfg["down_init_std"] = 0.02 / (2 * config.n_layers) ** 0.5 self.attention = AttnFactory.create(config.attn_type, **cfg, layer_id=layer_id) self.input_norm = RMSNorm(config.dim, config.norm_eps) self.post_attention_norm = RMSNorm(config.dim, config.norm_eps) diff --git a/astrai/model/components/linear.py b/astrai/model/components/linear.py index c90b1a3..f3a9aeb 100644 --- a/astrai/model/components/linear.py +++ b/astrai/model/components/linear.py @@ -5,13 +5,16 @@ from torch import Tensor class Linear(nn.Module): - def __init__(self, in_dim: int, out_dim: int, bias: bool = False): + def __init__( + self, in_dim: int, out_dim: int, bias: bool = False, init_std: float = 0.02 + ): super().__init__() self.weight = nn.Parameter(torch.empty((out_dim, in_dim))) self.bias = nn.Parameter(torch.zeros(out_dim)) if bias else None + self.init_std = init_std def reset_parameters(self): - nn.init.kaiming_uniform_(self.weight, a=5**0.5) + nn.init.normal_(self.weight, mean=0.0, std=self.init_std) if self.bias is not None: fan_in, _ = nn.init._calculate_fan_in_and_fan_out(self.weight) bound = 1 / (fan_in**0.5) diff --git a/astrai/model/components/mlp.py b/astrai/model/components/mlp.py index 0270bad..08a42ab 100644 --- a/astrai/model/components/mlp.py +++ b/astrai/model/components/mlp.py @@ -13,11 +13,11 @@ class FFNFactory(BaseFactory[nn.Module]): @FFNFactory.register("mlp") class MLP(nn.Module): - def __init__(self, dim: int, dim_ffn: int): + def __init__(self, dim: int, dim_ffn: int, down_init_std: float = 0.02): super().__init__() self.up = Linear(dim, dim_ffn) self.gate = Linear(dim, dim_ffn) - self.down = Linear(dim_ffn, dim) + self.down = Linear(dim_ffn, dim, init_std=down_init_std) def forward(self, x: Tensor) -> Tensor: gated = self.up(x) * F.silu(self.gate(x)) @@ -35,6 +35,7 @@ class DeepSeekMoE(nn.Module): n_shared_experts: int = 1, n_activated_experts: int = 2, topk_method: str = "greedy", + n_layers: int = 1, ): super().__init__() self.dim = dim @@ -44,12 +45,20 @@ class DeepSeekMoE(nn.Module): self.topk_method = topk_method self.router = Linear(dim, n_routed_experts, bias=False) + moe_scale = 1 / max(n_shared_experts, 1) + 1 / n_activated_experts + down_init_std = 0.02 / (2 * n_layers * moe_scale) ** 0.5 self.shared_experts = nn.ModuleList( - [MLP(dim, dim_ffn) for _ in range(n_shared_experts)] + [ + MLP(dim, dim_ffn, down_init_std=down_init_std) + for _ in range(n_shared_experts) + ] ) self.routed_experts = nn.ModuleList( - [MLP(dim, dim_ffn) for _ in range(n_routed_experts)] + [ + MLP(dim, dim_ffn, down_init_std=down_init_std) + for _ in range(n_routed_experts) + ] ) def forward(self, x: Tensor) -> Tensor: