[Model] Laguna: support per-element output gating (#28400)

Co-authored-by: Jimmy Shong <69131491+Jiminator@users.noreply.github.com>
Co-authored-by: Jimmy Shong <jimmy.shong@radixark.ai>
This commit is contained in:
Joe Rowell
2026-06-17 17:09:04 -07:00
committed by GitHub
co-authored by Jimmy Shong Jimmy Shong
parent d773b49e5b
commit 343aeeef39
2 changed files with 44 additions and 17 deletions
+2
View File
@@ -78,6 +78,7 @@ class LagunaConfig(PretrainedConfig):
tie_word_embeddings: bool = False,
attention_bias: bool = False,
attention_dropout: float = 0.0,
gating: bool | str = True,
sliding_window: int = 512,
layer_types: Optional[List[str]] = None,
mlp_layer_types: Optional[List[str]] = None,
@@ -120,6 +121,7 @@ class LagunaConfig(PretrainedConfig):
self.use_cache = use_cache
self.attention_bias = attention_bias
self.attention_dropout = attention_dropout
self.gating = "per-head" if gating is True else gating
self.sliding_window = sliding_window
self.num_experts = num_experts
+42 -17
View File
@@ -241,6 +241,7 @@ class LagunaAttention(nn.Module):
attention_bias: bool,
sliding_window_size: int,
layer_type: str,
gating: bool | str = True,
quant_config: Optional[QuantizationConfig] = None,
prefix: str = "",
) -> None:
@@ -248,6 +249,13 @@ class LagunaAttention(nn.Module):
self.hidden_size = hidden_size
self.head_dim = head_dim
self.layer_id = layer_id
if gating not in (True, False, None, "per-head", "per-element"):
raise ValueError(
f"Unsupported gating value {gating!r}; expected one of "
'True, False, None, "per-head", or "per-element".'
)
self.gating = bool(gating)
self.gate_per_head = gating is True or gating == "per-head"
attn_tp_rank = get_attention_tp_rank()
attn_tp_size = get_attention_tp_size()
@@ -287,18 +295,24 @@ class LagunaAttention(nn.Module):
prefix=add_prefix("o_proj", prefix),
)
# Per-head softplus gate (`gating=True` in HF). Shard like Q so the
# local output dim matches `num_heads`.
self.g_proj = ColumnParallelLinear(
hidden_size,
self.total_num_heads,
bias=False,
gather_output=False,
quant_config=None,
tp_rank=attn_tp_rank,
tp_size=attn_tp_size,
prefix=add_prefix("g_proj", prefix),
)
if self.gating:
g_proj_dim = (
self.total_num_heads
if self.gate_per_head
else self.total_num_heads * self.head_dim
)
self.g_proj = ColumnParallelLinear(
hidden_size,
g_proj_dim,
bias=False,
gather_output=False,
quant_config=None,
tp_rank=attn_tp_rank,
tp_size=attn_tp_size,
prefix=add_prefix("g_proj", prefix),
)
else:
self.g_proj = None
self.q_norm = RMSNorm(self.head_dim, eps=rms_norm_eps)
self.k_norm = RMSNorm(self.head_dim, eps=rms_norm_eps)
@@ -348,11 +362,15 @@ class LagunaAttention(nn.Module):
attn_output = self.attn(q, k, v, forward_batch)
gate, _ = self.g_proj(hidden_states)
gate = F.softplus(gate.float()).to(attn_output.dtype)
attn_output = attn_output.view(-1, self.num_heads, self.head_dim)
attn_output = attn_output * gate.view(-1, self.num_heads, 1)
attn_output = attn_output.reshape(-1, self.num_heads * self.head_dim)
if self.gating and self.g_proj is not None:
gate, _ = self.g_proj(hidden_states)
gate = F.softplus(gate.float()).to(attn_output.dtype)
if self.gate_per_head:
attn_output = attn_output.view(-1, self.num_heads, self.head_dim)
attn_output = attn_output * gate.view(-1, self.num_heads, 1)
attn_output = attn_output.reshape(-1, self.num_heads * self.head_dim)
else:
attn_output = attn_output * gate
output, _ = self.o_proj(attn_output)
return output
@@ -401,6 +419,7 @@ class LagunaDecoderLayer(nn.Module):
# SGLang's window is exclusive; HF's `sliding_window` is inclusive.
sliding_window_size=config.sliding_window - 1,
layer_type=layer_type,
gating=config.gating,
quant_config=quant_config,
prefix=add_prefix("self_attn", prefix),
)
@@ -748,6 +767,12 @@ class LagunaForCausalLM(nn.Module):
if name.endswith(".bias") and name not in params_dict:
continue
if name not in params_dict:
if ".g_proj." in name:
raise RuntimeError(
f"Checkpoint provides gate weight {name!r} but the model built no "
"g_proj (gating is disabled in the config). Set gating to True, "
'"per-head", or "per-element" to load this checkpoint.'
)
logger.warning("Parameter %s not found in params_dict", name)
continue
param = params_dict[name]