Update modeling_neollm.py
Browse files- modeling_neollm.py +98 -18
modeling_neollm.py
CHANGED
|
@@ -676,7 +676,9 @@ class VectorMultiplier(nn.Module):
|
|
| 676 |
class LinearWithMultipliers(nn.Module):
|
| 677 |
"""
|
| 678 |
Linear layer with optional row and/or column learnable multipliers.
|
| 679 |
-
Implements: y = (r ⊙ (W @ (c ⊙ x))) + b
|
|
|
|
|
|
|
| 680 |
"""
|
| 681 |
def __init__(
|
| 682 |
self,
|
|
@@ -684,16 +686,18 @@ class LinearWithMultipliers(nn.Module):
|
|
| 684 |
out_features: int,
|
| 685 |
bias: bool = True,
|
| 686 |
use_row_multiplier: bool = False,
|
| 687 |
-
use_column_multiplier: bool = False
|
|
|
|
| 688 |
):
|
| 689 |
super().__init__()
|
| 690 |
self.linear = nn.Linear(in_features, out_features, bias=bias)
|
| 691 |
-
self.
|
| 692 |
-
self.
|
|
|
|
| 693 |
|
| 694 |
-
if use_row_multiplier:
|
| 695 |
self.row_multiplier = VectorMultiplier(out_features, multiplier_type="row")
|
| 696 |
-
if use_column_multiplier:
|
| 697 |
self.column_multiplier = VectorMultiplier(in_features, multiplier_type="column")
|
| 698 |
|
| 699 |
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
@@ -705,6 +709,53 @@ class LinearWithMultipliers(nn.Module):
|
|
| 705 |
return x
|
| 706 |
|
| 707 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
# ==================== LEVIATHAN CONTINUOUS TOKEN GENERATOR ====================
|
| 709 |
|
| 710 |
class LeviathanGenerator(nn.Module):
|
|
@@ -3204,7 +3255,9 @@ class NeoLLMAttention(nn.Module):
|
|
| 3204 |
|
| 3205 |
o_proj variants (controlled by config.use_hadamard_o_proj):
|
| 3206 |
False (default): dense LinearWithMultipliers — full expressivity,
|
| 3207 |
-
|
|
|
|
|
|
|
| 3208 |
True: HadamardOProj — fixed WHT + learnable α/β,
|
| 3209 |
κ = 1 by construction, 25% fewer attention params,
|
| 3210 |
FP8-friendly (Aggarwal & Kumar, 2026, arXiv:2603.08343).
|
|
@@ -3242,6 +3295,7 @@ class NeoLLMAttention(nn.Module):
|
|
| 3242 |
getattr(config, "lucid_attention_eps", config.rms_norm_eps)
|
| 3243 |
)
|
| 3244 |
self.use_hadamard_o_proj = getattr(config, "use_hadamard_o_proj", False)
|
|
|
|
| 3245 |
|
| 3246 |
self.fan_layer = FANLayer(
|
| 3247 |
hidden_size=config.hidden_size,
|
|
@@ -3254,6 +3308,7 @@ class NeoLLMAttention(nn.Module):
|
|
| 3254 |
self.q_proj = LinearWithMultipliers(
|
| 3255 |
fan_output_dim, config.num_attention_heads * self.head_dim * 2,
|
| 3256 |
bias=config.attention_bias, use_row_multiplier=True, use_column_multiplier=False,
|
|
|
|
| 3257 |
)
|
| 3258 |
self.num_mea_component_heads = (
|
| 3259 |
self.mea_component_key_value_heads
|
|
@@ -3283,6 +3338,7 @@ class NeoLLMAttention(nn.Module):
|
|
| 3283 |
self.o_proj = LinearWithMultipliers(
|
| 3284 |
_o_in, config.hidden_size,
|
| 3285 |
bias=config.attention_bias, use_row_multiplier=True, use_column_multiplier=True,
|
|
|
|
| 3286 |
)
|
| 3287 |
|
| 3288 |
self.q_norm = SeeDNorm(self.head_dim, eps=config.rms_norm_eps)
|
|
@@ -4800,11 +4856,13 @@ class VersatileFFN(nn.Module):
|
|
| 4800 |
self.gate_proj = LinearWithMultipliers(
|
| 4801 |
fan_dim, config.intermediate_size,
|
| 4802 |
bias=False, use_row_multiplier=True, use_column_multiplier=False,
|
|
|
|
| 4803 |
)
|
| 4804 |
self.up_proj = nn.Linear(fan_dim, config.intermediate_size, bias=False)
|
| 4805 |
self.down_proj = LinearWithMultipliers(
|
| 4806 |
config.intermediate_size, config.hidden_size,
|
| 4807 |
bias=False, use_row_multiplier=True, use_column_multiplier=True,
|
|
|
|
| 4808 |
)
|
| 4809 |
self.act_fn = PolyNorm(exclusive=False)
|
| 4810 |
self.dropout = nn.Dropout(config.dropout_rate)
|
|
@@ -4868,10 +4926,11 @@ class VersatileFFN(nn.Module):
|
|
| 4868 |
|
| 4869 |
Returns x_in + expert_out (residual included, matching Eq. 8).
|
| 4870 |
"""
|
| 4871 |
-
# Gate projection: sliced rows + row multiplier
|
| 4872 |
-
g_w
|
| 4873 |
-
|
| 4874 |
-
|
|
|
|
| 4875 |
|
| 4876 |
# Up projection: sliced rows, no multiplier on up_proj
|
| 4877 |
u_w = self.up_proj.weight[idx] # [seg, fan_dim]
|
|
@@ -4881,11 +4940,13 @@ class VersatileFFN(nn.Module):
|
|
| 4881 |
act = self.act_fn(gate) * up # [N, seg]
|
| 4882 |
act = self.dropout(act)
|
| 4883 |
|
| 4884 |
-
# Down projection: column multiplier on input,
|
| 4885 |
-
|
| 4886 |
-
|
| 4887 |
-
|
| 4888 |
-
out
|
|
|
|
|
|
|
| 4889 |
|
| 4890 |
return x_in + out
|
| 4891 |
|
|
@@ -5186,11 +5247,13 @@ class NeoLLMMLP(nn.Module):
|
|
| 5186 |
self.gate_proj = LinearWithMultipliers(
|
| 5187 |
fan_dim, config.intermediate_size,
|
| 5188 |
bias=False, use_row_multiplier=True, use_column_multiplier=False,
|
|
|
|
| 5189 |
)
|
| 5190 |
self.up_proj = nn.Linear(fan_dim, config.intermediate_size, bias=False)
|
| 5191 |
self.down_proj = LinearWithMultipliers(
|
| 5192 |
config.intermediate_size, config.hidden_size,
|
| 5193 |
bias=False, use_row_multiplier=True, use_column_multiplier=True,
|
|
|
|
| 5194 |
)
|
| 5195 |
self.act_fn = PolyNorm(exclusive_init=0.00, exclusive=getattr(config, "polynorm_exclusive", True))
|
| 5196 |
self.dropout = nn.Dropout(config.dropout_rate)
|
|
@@ -6179,6 +6242,10 @@ class NeoLLMPreTrainedModel(PreTrainedModel):
|
|
| 6179 |
if hasattr(module, "multiplier"):
|
| 6180 |
module.multiplier.data.fill_(1.0)
|
| 6181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6182 |
elif isinstance(module, LeviathanGenerator):
|
| 6183 |
nn.init.normal_(module.codebooks,
|
| 6184 |
mean=0.0, std=self.config.initializer_range)
|
|
@@ -6297,9 +6364,22 @@ class NeoLLMModel(NeoLLMPreTrainedModel):
|
|
| 6297 |
if config.use_token_generator:
|
| 6298 |
self.token_generator = LeviathanGenerator(config)
|
| 6299 |
else:
|
| 6300 |
-
|
| 6301 |
-
config
|
|
|
|
|
|
|
| 6302 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6303 |
|
| 6304 |
# ── Spelling Bee Embeddings (Rabe et al., 2026) ───────────────────────
|
| 6305 |
# Active when use_spelling_bee_embeddings=True, compatible with both
|
|
|
|
| 676 |
class LinearWithMultipliers(nn.Module):
|
| 677 |
"""
|
| 678 |
Linear layer with optional row and/or column learnable multipliers.
|
| 679 |
+
Implements: y = (r ⊙ (W @ (c ⊙ x))) + b when enabled.
|
| 680 |
+
With ``enable_multipliers=False`` no multiplier parameters are instantiated
|
| 681 |
+
and the module reduces to its wrapped ``nn.Linear``.
|
| 682 |
"""
|
| 683 |
def __init__(
|
| 684 |
self,
|
|
|
|
| 686 |
out_features: int,
|
| 687 |
bias: bool = True,
|
| 688 |
use_row_multiplier: bool = False,
|
| 689 |
+
use_column_multiplier: bool = False,
|
| 690 |
+
enable_multipliers: bool = True,
|
| 691 |
):
|
| 692 |
super().__init__()
|
| 693 |
self.linear = nn.Linear(in_features, out_features, bias=bias)
|
| 694 |
+
self.enable_multipliers = bool(enable_multipliers)
|
| 695 |
+
self.use_row_multiplier = bool(use_row_multiplier and self.enable_multipliers)
|
| 696 |
+
self.use_column_multiplier = bool(use_column_multiplier and self.enable_multipliers)
|
| 697 |
|
| 698 |
+
if self.use_row_multiplier:
|
| 699 |
self.row_multiplier = VectorMultiplier(out_features, multiplier_type="row")
|
| 700 |
+
if self.use_column_multiplier:
|
| 701 |
self.column_multiplier = VectorMultiplier(in_features, multiplier_type="column")
|
| 702 |
|
| 703 |
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
|
|
| 709 |
return x
|
| 710 |
|
| 711 |
|
| 712 |
+
|
| 713 |
+
class EmbeddingWithMultipliers(nn.Module):
|
| 714 |
+
"""
|
| 715 |
+
Token embedding matrix with optional vocabulary-row and hidden-channel
|
| 716 |
+
learnable multipliers.
|
| 717 |
+
|
| 718 |
+
Effective embedding:
|
| 719 |
+
E_eff[token, channel] = r_token * E[token, channel] * c_channel
|
| 720 |
+
|
| 721 |
+
This mirrors the Learnable Multipliers paper's embedding recommendation,
|
| 722 |
+
while keeping the actual weight available as ``.weight`` for tooling that
|
| 723 |
+
expects a standard ``nn.Embedding``-like object. It is only intended for
|
| 724 |
+
the untied, non-generator embedding path.
|
| 725 |
+
"""
|
| 726 |
+
def __init__(
|
| 727 |
+
self,
|
| 728 |
+
num_embeddings: int,
|
| 729 |
+
embedding_dim: int,
|
| 730 |
+
padding_idx: Optional[int] = None,
|
| 731 |
+
enable_multipliers: bool = True,
|
| 732 |
+
):
|
| 733 |
+
super().__init__()
|
| 734 |
+
self.embedding = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx)
|
| 735 |
+
self.num_embeddings = num_embeddings
|
| 736 |
+
self.embedding_dim = embedding_dim
|
| 737 |
+
self.padding_idx = padding_idx
|
| 738 |
+
self.enable_multipliers = bool(enable_multipliers)
|
| 739 |
+
self.use_row_multiplier = self.enable_multipliers
|
| 740 |
+
self.use_column_multiplier = self.enable_multipliers
|
| 741 |
+
|
| 742 |
+
if self.enable_multipliers:
|
| 743 |
+
self.row_multiplier = nn.Parameter(torch.ones(num_embeddings))
|
| 744 |
+
self.column_multiplier = VectorMultiplier(embedding_dim, multiplier_type="column")
|
| 745 |
+
|
| 746 |
+
@property
|
| 747 |
+
def weight(self) -> torch.nn.Parameter:
|
| 748 |
+
return self.embedding.weight
|
| 749 |
+
|
| 750 |
+
def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
|
| 751 |
+
x = self.embedding(input_ids)
|
| 752 |
+
if self.use_column_multiplier:
|
| 753 |
+
x = self.column_multiplier(x)
|
| 754 |
+
if self.use_row_multiplier:
|
| 755 |
+
row_scale = F.embedding(input_ids, self.row_multiplier.unsqueeze(-1)).to(dtype=x.dtype)
|
| 756 |
+
x = x * row_scale
|
| 757 |
+
return x
|
| 758 |
+
|
| 759 |
# ==================== LEVIATHAN CONTINUOUS TOKEN GENERATOR ====================
|
| 760 |
|
| 761 |
class LeviathanGenerator(nn.Module):
|
|
|
|
| 3255 |
|
| 3256 |
o_proj variants (controlled by config.use_hadamard_o_proj):
|
| 3257 |
False (default): dense LinearWithMultipliers — full expressivity,
|
| 3258 |
+
with Learnable Multipliers controlled by
|
| 3259 |
+
config.use_learnable_multipliers; develops high κ
|
| 3260 |
+
during training (FP8 risk).
|
| 3261 |
True: HadamardOProj — fixed WHT + learnable α/β,
|
| 3262 |
κ = 1 by construction, 25% fewer attention params,
|
| 3263 |
FP8-friendly (Aggarwal & Kumar, 2026, arXiv:2603.08343).
|
|
|
|
| 3295 |
getattr(config, "lucid_attention_eps", config.rms_norm_eps)
|
| 3296 |
)
|
| 3297 |
self.use_hadamard_o_proj = getattr(config, "use_hadamard_o_proj", False)
|
| 3298 |
+
self.use_learnable_multipliers = getattr(config, "use_learnable_multipliers", True)
|
| 3299 |
|
| 3300 |
self.fan_layer = FANLayer(
|
| 3301 |
hidden_size=config.hidden_size,
|
|
|
|
| 3308 |
self.q_proj = LinearWithMultipliers(
|
| 3309 |
fan_output_dim, config.num_attention_heads * self.head_dim * 2,
|
| 3310 |
bias=config.attention_bias, use_row_multiplier=True, use_column_multiplier=False,
|
| 3311 |
+
enable_multipliers=self.use_learnable_multipliers,
|
| 3312 |
)
|
| 3313 |
self.num_mea_component_heads = (
|
| 3314 |
self.mea_component_key_value_heads
|
|
|
|
| 3338 |
self.o_proj = LinearWithMultipliers(
|
| 3339 |
_o_in, config.hidden_size,
|
| 3340 |
bias=config.attention_bias, use_row_multiplier=True, use_column_multiplier=True,
|
| 3341 |
+
enable_multipliers=self.use_learnable_multipliers,
|
| 3342 |
)
|
| 3343 |
|
| 3344 |
self.q_norm = SeeDNorm(self.head_dim, eps=config.rms_norm_eps)
|
|
|
|
| 4856 |
self.gate_proj = LinearWithMultipliers(
|
| 4857 |
fan_dim, config.intermediate_size,
|
| 4858 |
bias=False, use_row_multiplier=True, use_column_multiplier=False,
|
| 4859 |
+
enable_multipliers=getattr(config, "use_learnable_multipliers", True),
|
| 4860 |
)
|
| 4861 |
self.up_proj = nn.Linear(fan_dim, config.intermediate_size, bias=False)
|
| 4862 |
self.down_proj = LinearWithMultipliers(
|
| 4863 |
config.intermediate_size, config.hidden_size,
|
| 4864 |
bias=False, use_row_multiplier=True, use_column_multiplier=True,
|
| 4865 |
+
enable_multipliers=getattr(config, "use_learnable_multipliers", True),
|
| 4866 |
)
|
| 4867 |
self.act_fn = PolyNorm(exclusive=False)
|
| 4868 |
self.dropout = nn.Dropout(config.dropout_rate)
|
|
|
|
| 4926 |
|
| 4927 |
Returns x_in + expert_out (residual included, matching Eq. 8).
|
| 4928 |
"""
|
| 4929 |
+
# Gate projection: sliced rows + optional row multiplier
|
| 4930 |
+
g_w = self.gate_proj.linear.weight[idx] # [seg, fan_dim]
|
| 4931 |
+
gate = F.linear(x_fan, g_w) # [N, seg]
|
| 4932 |
+
if self.gate_proj.use_row_multiplier:
|
| 4933 |
+
gate = gate * self.gate_proj.row_multiplier.multiplier[idx]
|
| 4934 |
|
| 4935 |
# Up projection: sliced rows, no multiplier on up_proj
|
| 4936 |
u_w = self.up_proj.weight[idx] # [seg, fan_dim]
|
|
|
|
| 4940 |
act = self.act_fn(gate) * up # [N, seg]
|
| 4941 |
act = self.dropout(act)
|
| 4942 |
|
| 4943 |
+
# Down projection: optional column multiplier on input, optional row on output
|
| 4944 |
+
d_w = self.down_proj.linear.weight[:, idx] # [hidden, seg]
|
| 4945 |
+
if self.down_proj.use_column_multiplier:
|
| 4946 |
+
act = act * self.down_proj.column_multiplier.multiplier[idx]
|
| 4947 |
+
out = F.linear(act, d_w) # [N, hidden]
|
| 4948 |
+
if self.down_proj.use_row_multiplier:
|
| 4949 |
+
out = out * self.down_proj.row_multiplier.multiplier
|
| 4950 |
|
| 4951 |
return x_in + out
|
| 4952 |
|
|
|
|
| 5247 |
self.gate_proj = LinearWithMultipliers(
|
| 5248 |
fan_dim, config.intermediate_size,
|
| 5249 |
bias=False, use_row_multiplier=True, use_column_multiplier=False,
|
| 5250 |
+
enable_multipliers=getattr(config, "use_learnable_multipliers", True),
|
| 5251 |
)
|
| 5252 |
self.up_proj = nn.Linear(fan_dim, config.intermediate_size, bias=False)
|
| 5253 |
self.down_proj = LinearWithMultipliers(
|
| 5254 |
config.intermediate_size, config.hidden_size,
|
| 5255 |
bias=False, use_row_multiplier=True, use_column_multiplier=True,
|
| 5256 |
+
enable_multipliers=getattr(config, "use_learnable_multipliers", True),
|
| 5257 |
)
|
| 5258 |
self.act_fn = PolyNorm(exclusive_init=0.00, exclusive=getattr(config, "polynorm_exclusive", True))
|
| 5259 |
self.dropout = nn.Dropout(config.dropout_rate)
|
|
|
|
| 6242 |
if hasattr(module, "multiplier"):
|
| 6243 |
module.multiplier.data.fill_(1.0)
|
| 6244 |
|
| 6245 |
+
elif isinstance(module, EmbeddingWithMultipliers):
|
| 6246 |
+
if hasattr(module, "row_multiplier"):
|
| 6247 |
+
module.row_multiplier.data.fill_(1.0)
|
| 6248 |
+
|
| 6249 |
elif isinstance(module, LeviathanGenerator):
|
| 6250 |
nn.init.normal_(module.codebooks,
|
| 6251 |
mean=0.0, std=self.config.initializer_range)
|
|
|
|
| 6364 |
if config.use_token_generator:
|
| 6365 |
self.token_generator = LeviathanGenerator(config)
|
| 6366 |
else:
|
| 6367 |
+
use_embedding_multipliers = (
|
| 6368 |
+
bool(getattr(config, "use_learnable_multipliers", True))
|
| 6369 |
+
and bool(getattr(config, "use_embedding_multipliers", True))
|
| 6370 |
+
and not bool(getattr(config, "tie_word_embeddings", False))
|
| 6371 |
)
|
| 6372 |
+
if use_embedding_multipliers:
|
| 6373 |
+
self.embed_tokens = EmbeddingWithMultipliers(
|
| 6374 |
+
config.vocab_size,
|
| 6375 |
+
config.hidden_size,
|
| 6376 |
+
padding_idx=config.pad_token_id,
|
| 6377 |
+
enable_multipliers=True,
|
| 6378 |
+
)
|
| 6379 |
+
else:
|
| 6380 |
+
self.embed_tokens = nn.Embedding(
|
| 6381 |
+
config.vocab_size, config.hidden_size, config.pad_token_id
|
| 6382 |
+
)
|
| 6383 |
|
| 6384 |
# ── Spelling Bee Embeddings (Rabe et al., 2026) ───────────────────────
|
| 6385 |
# Active when use_spelling_bee_embeddings=True, compatible with both
|