93 layers › 68 KDA layers › Latent mixture of experts › 896 routed experts
Bound the up branch
×no parametersup · 81
Pass each up feature through a tanh that levels off at 25.
Why
Both factors of SwiGLU’s product are unbounded, so large coordinates that coincide produce activation outliers and risk overflow in low-precision arithmetic. A plain sigmoid gate is bounded but loses the nearly linear positive side of Swish. Kimi K3 report §2.3.2
A scaled tanh is nearly linear near zero and bounded far from it. Applied to the linear factor of the gate and to the up branch, it keeps SwiGLU’s response near the origin and bounds the product at 4 × 25 = 100. Kimi K3 report §2.3.2
- in
- [B batch, T positions, 3072 expert d_ff]
- out
- [B batch, T positions, 3072 expert d_ff]
Explanation
With the up branch is close to the identity for ordinary features and bounded for large ones, so the product stays below .
Codemodeling_kimi_linear.py 64–91, 242–270
class KimiBlockSparseMLP(nn.Module):
def __init__(self, config: KimiLinearConfig, hidden_size=None, intermediate_size=None):
super().__init__()
self.config = config
self.ffn_dim = config.intermediate_size if intermediate_size is None else intermediate_size
self.hidden_dim = config.hidden_size if hidden_size is None else hidden_size
self.w1 = nn.Linear(self.hidden_dim, self.ffn_dim, bias=False) # gate
self.w2 = nn.Linear(self.ffn_dim, self.hidden_dim, bias=False) # down
self.w3 = nn.Linear(self.hidden_dim, self.ffn_dim, bias=False) # up
if config.hidden_act == "situ":
beta, linear_beta = _get_situ_activation_params(config)
self.act_fn = SituAndMul(
beta=beta,
linear_beta=linear_beta,
)
else:
self.act_fn = ACT2FN[config.hidden_act]
def forward(self, hidden_states):
if self.config.hidden_act == "situ":
gate_up = torch.cat([self.w1(hidden_states), self.w3(hidden_states)], dim=-1)
current_hidden_states = self.act_fn(gate_up)
else:
current_hidden_states = self.act_fn(
self.w1(hidden_states)) * self.w3(hidden_states)
current_hidden_states = self.w2(current_hidden_states)
return current_hidden_statesclass SituAndMul(nn.Module):
"""
SituAndMul activation: beta * tanh(gate / beta) * sigmoid(gate) * up
When linear_beta is set, up is also transformed by linear_beta * tanh(up / linear_beta).
"""
def __init__(self, beta: float = 1.0, linear_beta: float | None = None):
super().__init__()
self.beta = beta
self.linear_beta = linear_beta
def forward(self, x: torch.Tensor) -> torch.Tensor:
d = x.shape[-1] // 2
gate = x[..., :d].to(torch.float32)
up = x[..., d:].to(torch.float32)
situ_a = self.beta * torch.tanh(gate / self.beta) * torch.sigmoid(gate)
if self.linear_beta is not None:
up = self.linear_beta * torch.tanh(up / self.linear_beta)
return (situ_a * up).to(x.dtype)
ACT2FN["situ"] = SituAndMul
def _get_situ_activation_params(config: KimiLinearConfig):
beta = getattr(config, "activation_situ_beta", None)
linear_beta = getattr(config, "activation_situ_linear_beta", None)
return beta or 1.0, linear_betaSources2
Direct evidence
Each routed expert is its own gated MLP of moe_intermediate_size hidden features on the routed-expert width, with the SiTU activation.
expert · moonshotai/Kimi-K3 / modeling_kimi_linear.py
Pinned revision f831ab668142 ↗ · lines 242–270
Read code excerpt
class KimiBlockSparseMLP(nn.Module):
def __init__(self, config: KimiLinearConfig, hidden_size=None, intermediate_size=None):
super().__init__()
self.config = config
self.ffn_dim = config.intermediate_size if intermediate_size is None else intermediate_size
self.hidden_dim = config.hidden_size if hidden_size is None else hidden_size
self.w1 = nn.Linear(self.hidden_dim, self.ffn_dim, bias=False) # gate
self.w2 = nn.Linear(self.ffn_dim, self.hidden_dim, bias=False) # down
self.w3 = nn.Linear(self.hidden_dim, self.ffn_dim, bias=False) # up
if config.hidden_act == "situ":
beta, linear_beta = _get_situ_activation_params(config)
self.act_fn = SituAndMul(
beta=beta,
linear_beta=linear_beta,
)
else:
self.act_fn = ACT2FN[config.hidden_act]
def forward(self, hidden_states):
if self.config.hidden_act == "situ":
gate_up = torch.cat([self.w1(hidden_states), self.w3(hidden_states)], dim=-1)
current_hidden_states = self.act_fn(gate_up)
else:
current_hidden_states = self.act_fn(
self.w1(hidden_states)) * self.w3(hidden_states)
current_hidden_states = self.w2(current_hidden_states)
return current_hidden_statesDirect evidence
SiTU: beta·tanh(gate/beta)·sigmoid(gate), multiplied by the up branch passed through linear_beta·tanh(up/linear_beta), computed in float32.
situ · moonshotai/Kimi-K3 / modeling_kimi_linear.py
Pinned revision f831ab668142 ↗ · lines 64–91
Read code excerpt
class SituAndMul(nn.Module):
"""
SituAndMul activation: beta * tanh(gate / beta) * sigmoid(gate) * up
When linear_beta is set, up is also transformed by linear_beta * tanh(up / linear_beta).
"""
def __init__(self, beta: float = 1.0, linear_beta: float | None = None):
super().__init__()
self.beta = beta
self.linear_beta = linear_beta
def forward(self, x: torch.Tensor) -> torch.Tensor:
d = x.shape[-1] // 2
gate = x[..., :d].to(torch.float32)
up = x[..., d:].to(torch.float32)
situ_a = self.beta * torch.tanh(gate / self.beta) * torch.sigmoid(gate)
if self.linear_beta is not None:
up = self.linear_beta * torch.tanh(up / self.linear_beta)
return (situ_a * up).to(x.dtype)
ACT2FN["situ"] = SituAndMul
def _get_situ_activation_params(config: KimiLinearConfig):
beta = getattr(config, "activation_situ_beta", None)
linear_beta = getattr(config, "activation_situ_linear_beta", None)
return beta or 1.0, linear_beta