OzTianlu commited on
Commit
e6277d9
·
verified ·
1 Parent(s): 9af979a

Upload 12 files

Browse files
AsteriskForCausalLM.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hybrid ASPP-Attention Architecture (Asterisk Model)
3
+ Combines Adjacency-Structured Parallel Propagation (ASPP) with standard attention mechanisms
4
+ to enhance model expressiveness while maintaining efficiency.
5
+
6
+ Architecture Design:
7
+ - Hybrid layers: Standard attention + ASPP operator in parallel
8
+ - Gate mechanism for dynamic fusion
9
+ - Knowledge distillation from SmolLM2-135M base model
10
+ """
11
+
12
+ import torch
13
+ import torch.nn as nn
14
+ import torch.nn.functional as F
15
+ from transformers import LlamaConfig, LlamaForCausalLM, LlamaModel
16
+ from transformers.models.llama.modeling_llama import (
17
+ LlamaAttention,
18
+ LlamaDecoderLayer,
19
+ LlamaRMSNorm,
20
+ LlamaMLP,
21
+ )
22
+ from transformers import AutoConfig, AutoModelForCausalLM
23
+ from typing import Optional, Tuple, List
24
+
25
+
26
+ class AsteriskConfig(LlamaConfig):
27
+ """
28
+ Configuration class for Asterisk model.
29
+ Inherits from LlamaConfig with custom model_type.
30
+ """
31
+ model_type = "asterisk"
32
+
33
+ def __init__(
34
+ self,
35
+ hybrid_layer_indices: Optional[List[int]] = None,
36
+ aspp_hidden_dim: Optional[int] = None,
37
+ aspp_num_steps: int = 2,
38
+ aspp_dropout: float = 0.1,
39
+ **kwargs
40
+ ):
41
+ super().__init__(**kwargs)
42
+ self.hybrid_layer_indices = hybrid_layer_indices
43
+ self.aspp_hidden_dim = aspp_hidden_dim
44
+ self.aspp_num_steps = aspp_num_steps
45
+ self.aspp_dropout = aspp_dropout
46
+
47
+
48
+ class ASPPOperator(nn.Module):
49
+ """
50
+ Asterisk Operator (ASPP) - Point-wise Parallel Propagation
51
+
52
+ Simplified version WITHOUT neighbor gathering to reduce overfitting:
53
+ - Optional dimensionality reduction for efficiency
54
+ - Point-wise evolution: h_i^(t+1) = φ(h_i^(t)) [NO neighbors]
55
+ - Multi-step evolution for depth without added complexity
56
+ - Dropout for regularization
57
+
58
+ Args:
59
+ hidden_size: Dimension of hidden states (input/output)
60
+ aspp_hidden_dim: Internal dimension for ASPP (default: None, use hidden_size)
61
+ num_steps: Number of evolution steps K (default: 2)
62
+ dropout: Dropout rate for regularization (default: 0.1)
63
+ """
64
+
65
+ def __init__(self, hidden_size: int, aspp_hidden_dim: Optional[int] = None, num_steps: int = 2, dropout: float = 0.1):
66
+ super().__init__()
67
+ self.hidden_size = hidden_size
68
+ self.aspp_hidden_dim = aspp_hidden_dim or hidden_size
69
+ self.num_steps = num_steps
70
+
71
+ # Projection to lower dimension (if specified)
72
+ self.use_projection = (self.aspp_hidden_dim != hidden_size)
73
+ if self.use_projection:
74
+ self.down_proj = nn.Linear(hidden_size, self.aspp_hidden_dim)
75
+ self.up_proj = nn.Linear(self.aspp_hidden_dim, hidden_size)
76
+ self.proj_dropout = nn.Dropout(dropout)
77
+
78
+ # Point-wise update function φ - NO neighbor gathering
79
+ # Much smaller: only processes current position
80
+ self.update_net = nn.Sequential(
81
+ nn.Linear(self.aspp_hidden_dim, self.aspp_hidden_dim * 2),
82
+ nn.SiLU(),
83
+ nn.Dropout(dropout),
84
+ nn.Linear(self.aspp_hidden_dim * 2, self.aspp_hidden_dim),
85
+ nn.Dropout(dropout),
86
+ )
87
+
88
+ # Learnable K-step parameter
89
+ # sigmoid(1.0) ≈ 0.73, giving k_steps ≈ 1.5 → 2 steps initially
90
+ self.k_logit = nn.Parameter(torch.tensor(1.0))
91
+
92
+ # Learnable residual scale
93
+ self.residual_scale = nn.Parameter(torch.tensor(0.1))
94
+
95
+ # Layer norm for stability
96
+ self.norm = nn.LayerNorm(self.aspp_hidden_dim, eps=1e-5)
97
+
98
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
99
+ """
100
+ Args:
101
+ hidden_states: [batch_size, seq_len, hidden_size]
102
+ Returns:
103
+ evolved_states: [batch_size, seq_len, hidden_size]
104
+ """
105
+ # Project to lower dimension if needed
106
+ if self.use_projection:
107
+ h_t = self.down_proj(hidden_states)
108
+ h_t = self.proj_dropout(h_t)
109
+ else:
110
+ h_t = hidden_states
111
+
112
+ # Learnable number of steps
113
+ k_steps = max(1, int(torch.sigmoid(self.k_logit) * self.num_steps))
114
+
115
+ # K-step point-wise evolution (NO neighbor gathering)
116
+ for t in range(k_steps):
117
+ # Apply point-wise update rule φ
118
+ h_t_next = self.update_net(h_t)
119
+
120
+ # Scaled residual connection for stability
121
+ h_t = h_t + self.residual_scale * h_t_next
122
+ h_t = self.norm(h_t)
123
+
124
+ # Project back to original dimension if needed
125
+ if self.use_projection:
126
+ h_t = self.up_proj(h_t)
127
+ h_t = self.proj_dropout(h_t)
128
+
129
+ return h_t
130
+
131
+
132
+ class HybridASPPAttentionLayer(LlamaDecoderLayer):
133
+ """
134
+ Hybrid layer combining ASPP operator and standard attention
135
+ Inherits from LlamaDecoderLayer to maintain compatibility
136
+
137
+ Architecture:
138
+ 1. Parallel branches:
139
+ - ASPP operator for local structured reasoning
140
+ - Standard LlamaAttention for global context
141
+ 2. Gated fusion of both outputs
142
+ 3. Feed-forward network
143
+ """
144
+
145
+ def __init__(self, config: LlamaConfig, layer_idx: int, aspp_hidden_dim: Optional[int] = None, aspp_num_steps: int = 2, aspp_dropout: float = 0.1):
146
+ # Initialize parent LlamaDecoderLayer
147
+ super().__init__(config, layer_idx)
148
+
149
+ # Add ASPP branch
150
+ self.aspp_operator = ASPPOperator(
151
+ hidden_size=config.hidden_size,
152
+ aspp_hidden_dim=aspp_hidden_dim,
153
+ num_steps=aspp_num_steps,
154
+ dropout=aspp_dropout
155
+ )
156
+
157
+ # Gated fusion mechanism with dropout
158
+ self.fusion_gate = nn.Sequential(
159
+ nn.Linear(config.hidden_size * 2, config.hidden_size),
160
+ nn.Dropout(aspp_dropout),
161
+ nn.Sigmoid()
162
+ )
163
+
164
+ # Initialize gate to be balanced (output 0.5 initially)
165
+ with torch.no_grad():
166
+ self.fusion_gate[0].bias.fill_(0.0) # sigmoid(0) = 0.5
167
+
168
+ def forward(
169
+ self,
170
+ hidden_states: torch.Tensor,
171
+ attention_mask: Optional[torch.Tensor] = None,
172
+ position_ids: Optional[torch.LongTensor] = None,
173
+ past_key_values = None,
174
+ use_cache: Optional[bool] = False,
175
+ cache_position: Optional[torch.LongTensor] = None,
176
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
177
+ **kwargs,
178
+ ) -> torch.Tensor:
179
+ """
180
+ Override LlamaDecoderLayer.forward to add ASPP branch
181
+ Returns single tensor to match LlamaDecoderLayer API in transformers 4.57.6
182
+ """
183
+ residual = hidden_states
184
+ hidden_states = self.input_layernorm(hidden_states)
185
+
186
+ # ASPP branch
187
+ aspp_output = self.aspp_operator(hidden_states)
188
+
189
+ # Attention branch - use parent's self_attn
190
+ attn_outputs = self.self_attn(
191
+ hidden_states,
192
+ position_embeddings,
193
+ attention_mask=attention_mask,
194
+ past_key_values=past_key_values,
195
+ cache_position=cache_position,
196
+ )
197
+ attn_output = attn_outputs[0]
198
+
199
+ # Gated fusion
200
+ fusion_input = torch.cat([aspp_output, attn_output], dim=-1)
201
+ gate = self.fusion_gate(fusion_input)
202
+
203
+ # Combine with gating: gate * ASPP + (1-gate) * Attention
204
+ fused_output = gate * aspp_output + (1 - gate) * attn_output
205
+
206
+ # Residual connection
207
+ hidden_states = residual + fused_output
208
+
209
+ # MLP block (use parent's mlp)
210
+ residual = hidden_states
211
+ hidden_states = self.post_attention_layernorm(hidden_states)
212
+ hidden_states = self.mlp(hidden_states)
213
+ hidden_states = residual + hidden_states
214
+
215
+ # Return single tensor like LlamaDecoderLayer
216
+ return hidden_states
217
+
218
+
219
+ class AsteriskLlamaModel(LlamaModel):
220
+ """
221
+ Asterisk-Llama model with full hybrid ASPP-Attention architecture
222
+
223
+ All layers use hybrid ASPP+Attention by default for maximum expressiveness.
224
+ """
225
+
226
+ def __init__(self, config: LlamaConfig, hybrid_layer_indices: Optional[List[int]] = None, aspp_hidden_dim: Optional[int] = None, aspp_num_steps: int = 2, aspp_dropout: float = 0.1):
227
+ super().__init__(config)
228
+
229
+ # Determine which layers to make hybrid (default: ALL layers)
230
+ if hybrid_layer_indices is None:
231
+ # Use ALL layers as hybrid (full hybrid architecture)
232
+ num_layers = config.num_hidden_layers
233
+ hybrid_layer_indices = list(range(num_layers))
234
+
235
+ self.hybrid_layer_indices = hybrid_layer_indices
236
+
237
+ # Replace specified layers with hybrid layers
238
+ for idx in hybrid_layer_indices:
239
+ if idx < len(self.layers):
240
+ self.layers[idx] = HybridASPPAttentionLayer(
241
+ config,
242
+ layer_idx=idx,
243
+ aspp_hidden_dim=aspp_hidden_dim,
244
+ aspp_num_steps=aspp_num_steps,
245
+ aspp_dropout=aspp_dropout
246
+ )
247
+
248
+ # Initialize weights
249
+ self.post_init()
250
+
251
+
252
+ class AsteriskForCausalLM(LlamaForCausalLM):
253
+ """
254
+ Asterisk Causal LM with Hybrid ASPP-Attention architecture
255
+
256
+ Registered as: AsteriskForCausalLM
257
+ """
258
+
259
+ config_class = AsteriskConfig
260
+
261
+ def __init__(self, config: AsteriskConfig, hybrid_layer_indices: Optional[List[int]] = None, aspp_hidden_dim: Optional[int] = None, aspp_num_steps: int = 2, aspp_dropout: float = 0.1):
262
+ # Read all ASPP parameters from config if not explicitly provided
263
+ if hybrid_layer_indices is None and hasattr(config, 'hybrid_layer_indices'):
264
+ hybrid_layer_indices = config.hybrid_layer_indices
265
+ if aspp_hidden_dim is None and hasattr(config, 'aspp_hidden_dim'):
266
+ aspp_hidden_dim = config.aspp_hidden_dim
267
+ if hasattr(config, 'aspp_num_steps'):
268
+ aspp_num_steps = config.aspp_num_steps
269
+ if hasattr(config, 'aspp_dropout'):
270
+ aspp_dropout = config.aspp_dropout
271
+
272
+ super().__init__(config)
273
+
274
+ # Replace model with Asterisk version
275
+ self.model = AsteriskLlamaModel(config, hybrid_layer_indices, aspp_hidden_dim, aspp_num_steps, aspp_dropout)
276
+
277
+ # Store hybrid layer info in config for serialization
278
+ self.config.hybrid_layer_indices = hybrid_layer_indices
279
+
280
+ # Initialize weights
281
+ self.post_init()
282
+
283
+ @classmethod
284
+ def from_pretrained_base(
285
+ cls,
286
+ base_model_path: str,
287
+ hybrid_layer_indices: Optional[List[int]] = None,
288
+ aspp_hidden_dim: Optional[int] = None,
289
+ aspp_num_steps: int = 2,
290
+ aspp_dropout: float = 0.1,
291
+ **kwargs
292
+ ):
293
+ """
294
+ Load base model and convert to Asterisk architecture
295
+
296
+ Args:
297
+ base_model_path: Path to base SmolLM2 model
298
+ hybrid_layer_indices: Which layers to make hybrid (None for all)
299
+ aspp_hidden_dim: Internal dimension for ASPP (None = use model hidden_size)
300
+ aspp_num_steps: Number of evolution steps K for ASPP (default: 2)
301
+ aspp_dropout: Dropout rate for ASPP regularization (default: 0.1)
302
+ """
303
+ # Load base model
304
+ base_model = LlamaForCausalLM.from_pretrained(base_model_path, **kwargs)
305
+ base_config = base_model.config
306
+
307
+ # Create Asterisk config from base config with ASPP params
308
+ asterisk_config = AsteriskConfig(
309
+ **base_config.to_dict(),
310
+ hybrid_layer_indices=hybrid_layer_indices,
311
+ aspp_hidden_dim=aspp_hidden_dim,
312
+ aspp_num_steps=aspp_num_steps,
313
+ aspp_dropout=aspp_dropout
314
+ )
315
+
316
+ # Create Asterisk model
317
+ asterisk_model = cls(asterisk_config, hybrid_layer_indices, aspp_hidden_dim, aspp_num_steps, aspp_dropout)
318
+
319
+ # Transfer weights from base model (non-hybrid layers and embeddings)
320
+ asterisk_model.load_state_dict(base_model.state_dict(), strict=False)
321
+
322
+ print(f"✓ Converted base model to Asterisk architecture")
323
+ print(f" Hybrid layers: {asterisk_model.model.hybrid_layer_indices}")
324
+ aspp_dim_str = f"{aspp_hidden_dim}" if aspp_hidden_dim else f"{base_config.hidden_size} (full)"
325
+ print(f" ASPP config: dim={aspp_dim_str}, steps={aspp_num_steps}, dropout={aspp_dropout}")
326
+
327
+ return asterisk_model, base_model
328
+
329
+
330
+ # Register the model for AutoModel
331
+ AutoConfig.register("asterisk", AsteriskConfig)
332
+ AutoModelForCausalLM.register(AsteriskConfig, AsteriskForCausalLM)
333
+
334
+
335
+ def get_model_info(model):
336
+ """Print model architecture information"""
337
+ total_params = sum(p.numel() for p in model.parameters())
338
+ trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
339
+
340
+ print(f" • Total parameters: {total_params:,}")
341
+ print(f" • Trainable parameters: {trainable_params:,}")
342
+ print(f" • Model size: {total_params * 4 / 1024**2:.2f} MB (fp32)")
343
+
344
+ if isinstance(model, AsteriskForCausalLM):
345
+ print(f" • Hybrid layer indices: {model.model.hybrid_layer_indices}")
346
+ print(f" • Number of hybrid layers: {len(model.model.hybrid_layer_indices)}")
347
+
348
+
349
+ # Example usage
350
+ if __name__ == "__main__":
351
+ print("=" * 80)
352
+ print("Asterisk Architecture - ASPP + Standard Attention")
353
+ print("=" * 80)
354
+
355
+ # Configuration
356
+ base_model_path = "SmolLM2-135M-Instruct"
357
+
358
+ # Create Asterisk model
359
+ print("\n🔧 Creating Asterisk model...")
360
+ asterisk_model, base_model = AsteriskForCausalLM.from_pretrained_base(
361
+ base_model_path,
362
+ hybrid_layer_indices=None, # Auto-select ALL layers (full hybrid)
363
+ aspp_num_steps=2, # Reduced from 3
364
+ aspp_neighbor_radius=1, # Reduced from 2
365
+ aspp_dropout=0.1, # Added dropout
366
+ torch_dtype=torch.bfloat16,
367
+ device_map="auto",
368
+ )
369
+
370
+ print("\n📊 Base model info:")
371
+ get_model_info(base_model)
372
+
373
+ print("\n📊 Asterisk model info:")
374
+ get_model_info(asterisk_model)
375
+
376
+ print("\n✨ Model ready for training!")
README.md CHANGED
@@ -1,3 +1,324 @@
1
- ---
2
- license: apache-2.0
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: transformers
3
+ model_name: Asterisk-135M
4
+ base_model: HuggingFaceTB/SmolLM2-135M-Instruct
5
+ tags:
6
+ - aspp
7
+ - hybrid-architecture
8
+ - graph-reasoning
9
+ - sft
10
+ - trl
11
+ license: apache-2.0
12
+ language:
13
+ - en
14
+ ---
15
+
16
+ # Asterisk-135M: Hybrid ASPP-Attention Architecture
17
+
18
+ **Asterisk** is a research implementation that combines the **ASPP (Adjacency-Structured Parallel Propagation)** operator with standard attention mechanisms to enhance the SmolLM2-135M model. The model implements a hybrid architecture that fuses graph-based local reasoning (ASPP) with global attention for improved expressiveness on structured reasoning tasks.
19
+
20
+ ## Model Description
21
+
22
+ - **Base Model**: [SmolLM2-135M-Instruct](https://huggingface.co/HuggingFaceTB/SmolLM2-135M-Instruct)
23
+ - **Architecture**: Hybrid ASPP-Attention (30 hybrid layers)
24
+ - **Parameters**: 171.2M (35M additional ASPP parameters)
25
+ - **Training**: Supervised Fine-Tuning on Capybara dataset
26
+ - **Framework**: Transformers 4.57.6, TRL 0.27.0
27
+
28
+ ### Key Innovation: The Asterisk Operator (★-operator)
29
+
30
+ The **Asterisk Operator** performs local parallel state evolution through point-wise transformations:
31
+
32
+ ```
33
+ h_i^(t+1) = φ(h_i^(t)) [K-step iterative evolution]
34
+ ```
35
+
36
+ This is then gated and fused with standard Llama attention outputs:
37
+
38
+ ```
39
+ output = gate * ASPP(x) + (1-gate) * Attention(x)
40
+ ```
41
+
42
+ ## Architecture
43
+
44
+ ### 1. ASPPOperator (Point-wise Parallel Propagation)
45
+
46
+ ```python
47
+ class ASPPOperator:
48
+ """
49
+ Simplified ASPP without neighbor gathering to reduce overfitting
50
+
51
+ Forward pass:
52
+ 1. Optional dimensionality reduction: h_t = down_proj(hidden_states)
53
+ 2. K-step evolution: h_t = h_t + α * φ(h_t) [K times]
54
+ 3. Layer normalization after each step
55
+ 4. Optional projection back: output = up_proj(h_t)
56
+
57
+ Parameters:
58
+ - hidden_size: 576 (model dimension)
59
+ - aspp_hidden_dim: 256 (internal ASPP dimension)
60
+ - aspp_num_steps: 8 (evolution iterations)
61
+ - aspp_dropout: 0.2
62
+ """
63
+ ```
64
+
65
+ **Pseudocode:**
66
+ ```
67
+ function ASPP(hidden_states):
68
+ # Optional dimensionality reduction
69
+ if use_projection:
70
+ h_t ← down_proj(hidden_states)
71
+ h_t ← dropout(h_t)
72
+ else:
73
+ h_t ← hidden_states
74
+
75
+ # Learnable number of steps
76
+ k_steps ← max(1, int(sigmoid(k_logit) * num_steps))
77
+
78
+ # K-step point-wise evolution
79
+ for t = 1 to k_steps:
80
+ # Point-wise update: φ(h_t) = MLP(h_t)
81
+ h_t_next ← update_net(h_t)
82
+
83
+ # Scaled residual connection
84
+ h_t ← h_t + residual_scale * h_t_next
85
+ h_t ← layer_norm(h_t)
86
+
87
+ # Project back to original dimension
88
+ if use_projection:
89
+ h_t ← up_proj(h_t)
90
+ h_t ← dropout(h_t)
91
+
92
+ return h_t
93
+ ```
94
+
95
+ ### 2. HybridASPPAttentionLayer
96
+
97
+ ```python
98
+ class HybridASPPAttentionLayer(LlamaDecoderLayer):
99
+ """
100
+ Extends LlamaDecoderLayer with parallel ASPP branch
101
+
102
+ Architecture:
103
+ 1. Input LayerNorm
104
+ 2. Parallel branches:
105
+ - ASPP operator for local structured reasoning
106
+ - Standard LlamaAttention for global context
107
+ 3. Gated fusion: gate * ASPP + (1-gate) * Attention
108
+ 4. Residual connection
109
+ 5. Feed-forward MLP
110
+ """
111
+ ```
112
+
113
+ **Pseudocode:**
114
+ ```
115
+ function HybridLayer(hidden_states, attention_mask, ...):
116
+ residual ← hidden_states
117
+ hidden_states ← input_layernorm(hidden_states)
118
+
119
+ # Parallel branches
120
+ aspp_output ← aspp_operator(hidden_states)
121
+ attn_output ← self_attention(hidden_states, attention_mask, ...)
122
+
123
+ # Gated fusion
124
+ fusion_input ← concat([aspp_output, attn_output])
125
+ gate ← sigmoid(linear(dropout(fusion_input)))
126
+ fused_output ← gate * aspp_output + (1 - gate) * attn_output
127
+
128
+ # Residual connection
129
+ hidden_states ← residual + fused_output
130
+
131
+ # MLP block
132
+ residual ← hidden_states
133
+ hidden_states ← post_attention_layernorm(hidden_states)
134
+ hidden_states ← mlp(hidden_states)
135
+ hidden_states ← residual + hidden_states
136
+
137
+ return hidden_states
138
+ ```
139
+
140
+ ### 3. AsteriskForCausalLM
141
+
142
+ ```python
143
+ class AsteriskForCausalLM(LlamaForCausalLM):
144
+ """
145
+ Main model class with custom model_type "asterisk"
146
+
147
+ Configuration:
148
+ - hybrid_layer_indices: None (all 30 layers are hybrid)
149
+ - aspp_hidden_dim: 256 (reduces overfitting)
150
+ - aspp_num_steps: 8 (learnable, actual steps ≈ 6)
151
+ - aspp_dropout: 0.2
152
+ """
153
+ ```
154
+
155
+ ## Evaluation Results
156
+
157
+ Evaluated on LM-Evaluation-Harness with `limit=50` per task:
158
+
159
+ | Task | Metric | Score | Stderr |
160
+ |------|--------|-------|--------|
161
+ | **MMLU** | acc | **0.2376** | ±0.0037 |
162
+ | - Humanities | acc | 0.2472 | ±0.0067 |
163
+ | - STEM | acc | 0.2245 | ±0.0074 |
164
+ | - Social Sciences | acc | 0.2327 | ±0.0076 |
165
+ | - Other | acc | 0.2430 | ±0.0077 |
166
+ | **GSM8K** | exact_match | **0.0240** | ±0.0048 |
167
+ | **HellaSwag** | acc_norm | **0.4430** | ±0.0157 |
168
+ | **ARC-Easy** | acc_norm | **0.5450** | ±0.0158 |
169
+ | **PIQA** | acc_norm | **0.6770** | ±0.0148 |
170
+ | **WinoGrande** | acc | **0.5210** | ±0.0158 |
171
+
172
+ **Note**: These are preliminary results with sample limits. Full evaluation pending.
173
+
174
+ ## Quick Start
175
+
176
+ ```python
177
+ from transformers import AutoModelForCausalLM, AutoTokenizer
178
+ import torch
179
+
180
+ # Load model and tokenizer
181
+ model = AutoModelForCausalLM.from_pretrained(
182
+ "path/to/Asterisk",
183
+ trust_remote_code=True,
184
+ torch_dtype=torch.bfloat16,
185
+ device_map="auto"
186
+ )
187
+ tokenizer = AutoTokenizer.from_pretrained("path/to/Asterisk")
188
+
189
+ # Generate text
190
+ messages = [{"role": "user", "content": "Explain quantum computing in simple terms."}]
191
+ inputs = tokenizer.apply_chat_template(messages, return_tensors="pt").to(model.device)
192
+
193
+ outputs = model.generate(
194
+ inputs,
195
+ max_new_tokens=256,
196
+ temperature=0.7,
197
+ do_sample=True,
198
+ )
199
+ print(tokenizer.decode(outputs[0], skip_special_tokens=True))
200
+ ```
201
+
202
+ ## Training Details
203
+
204
+ ### Training Configuration
205
+ - **Dataset**: Capybara (conversational instruction-following)
206
+ - **Optimizer**: AdamW (lr=2e-5, weight_decay=0.01)
207
+ - **Batch Size**: 4 per device, gradient accumulation=4 (effective batch=16)
208
+ - **Epochs**: 2
209
+ - **Scheduler**: Cosine with warmup (100 steps)
210
+ - **Mixed Precision**: bfloat16
211
+ - **Gradient Checkpointing**: Enabled
212
+
213
+ ### ASPP Configuration
214
+ ```python
215
+ aspp_hidden_dim = 256 # Internal dimension (vs 576 model hidden_size)
216
+ aspp_num_steps = 8 # Max evolution steps (learnable)
217
+ aspp_dropout = 0.2 # Regularization
218
+ hybrid_layer_indices = None # All 30 layers
219
+ ```
220
+
221
+
222
+ ## Model Creation from Base
223
+
224
+ ```python
225
+ from AsteriskForCausalLM import AsteriskForCausalLM
226
+
227
+ # Create Asterisk model from SmolLM2 base
228
+ model, base_model = AsteriskForCausalLM.from_pretrained_base(
229
+ "HuggingFaceTB/SmolLM2-135M-Instruct",
230
+ hybrid_layer_indices=None, # None = all layers
231
+ aspp_hidden_dim=256, # Internal ASPP dimension
232
+ aspp_num_steps=8, # K-step evolution
233
+ aspp_dropout=0.2, # Dropout rate
234
+ torch_dtype=torch.bfloat16,
235
+ device_map="auto",
236
+ )
237
+
238
+ # Base model parameters are transferred, ASPP parameters initialized randomly
239
+ model.load_state_dict(base_model.state_dict(), strict=False)
240
+ ```
241
+
242
+ ## Theoretical Background
243
+
244
+ ### Universality (Theorem 2.1)
245
+ ASPP can simulate any Message-Passing Neural Network (MPNN) function on finite graphs in D steps, where D is the graph diameter.
246
+
247
+ ### Convergence (Theorem 2.2)
248
+ Exponential convergence to fixed points with rate c=0.76 under Lipschitz continuity.
249
+
250
+ ### Turing Completeness
251
+ Proven via cyclic tag system simulation - ASPP can compute any Turing-computable function given sufficient depth.
252
+
253
+ **Implementation Note**: This implementation simplifies theoretical ASPP to point-wise evolution (no neighbor gathering) to reduce overfitting while maintaining iterative refinement benefits.
254
+
255
+ ## Files in Checkpoint
256
+
257
+ ```
258
+ Asterisk/
259
+ ├── AsteriskForCausalLM.py # Model implementation (required for trust_remote_code)
260
+ ├── config.json # Model configuration with auto_map
261
+ ├── model.safetensors # Model weights
262
+ ├── tokenizer.json # Tokenizer
263
+ ├── generation_config.json # Generation settings
264
+ └── README.md # This file
265
+ ```
266
+
267
+ ## Dependencies
268
+
269
+ ```bash
270
+ pip install torch>=2.0.0
271
+ pip install transformers>=4.40.0
272
+ pip install trl>=0.8.0
273
+ pip install datasets>=2.14.0
274
+ pip install accelerate>=0.25.0
275
+ pip install bitsandbytes
276
+ ```
277
+
278
+ ## Citations
279
+
280
+ If you use this model, please cite:
281
+
282
+ ```bibtex
283
+ @misc{asterisk2026,
284
+ title={Asterisk: Hybrid ASPP-Attention Architecture for Enhanced Language Modeling},
285
+ author={NoesisLab},
286
+ year={2026},
287
+ publisher={Huggingface},
288
+ }
289
+ ```
290
+
291
+ ```bibtex
292
+ @misc{vonwerra2022trl,
293
+ title={{TRL: Transformer Reinforcement Learning}},
294
+ author={Leandro von Werra and Younes Belkada and Lewis Tunstall and Edward Beeching and Tristan Thrush and Nathan Lambert and Shengyi Huang and Kashif Rasul and Quentin Gallouédec},
295
+ year={2020},
296
+ journal={GitHub repository},
297
+ publisher={GitHub},
298
+ howpublished={\url{https://github.com/huggingface/trl}}
299
+ }
300
+ ```
301
+
302
+ ```bibtex
303
+ @article{allal2024SmolLM2,
304
+ title={SmolLM2 - with great data, comes great performance},
305
+ author={Allal, Loubna Ben and Lozhkov, Anton and Penedo, Guilherme and Wolf, Thomas and von Werra, Leandro},
306
+ year={2024}
307
+ }
308
+ ```
309
+
310
+ ## License
311
+
312
+ This model inherits the Apache 2.0 license from SmolLM2-135M-Instruct.
313
+
314
+ ## Framework Versions
315
+
316
+ - **TRL**: 0.27.0
317
+ - **Transformers**: 4.57.6
318
+ - **PyTorch**: 2.8.0+cu128
319
+ - **Datasets**: 4.5.0
320
+ - **Tokenizers**: 0.22.2
321
+
322
+ ## Acknowledgments
323
+
324
+ Built on top of [SmolLM2-135M-Instruct](https://huggingface.co/HuggingFaceTB/SmolLM2-135M-Instruct) by HuggingFace. Training framework powered by [TRL](https://github.com/huggingface/trl).
chat_template.jinja ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system
2
+ You are a helpful AI assistant named Asterisk, trained by NoesisLab<|im_end|>
3
+ ' }}{% endif %}{{'<|im_start|>' + message['role'] + '
4
+ ' + message['content'] + '<|im_end|>' + '
5
+ '}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant
6
+ ' }}{% endif %}
config.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "AsteriskForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "AsteriskForCausalLM.AsteriskConfig",
7
+ "AutoModelForCausalLM": "AsteriskForCausalLM.AsteriskForCausalLM"
8
+ },
9
+ "aspp_dropout": 0.2,
10
+ "aspp_hidden_dim": 256,
11
+ "aspp_num_steps": 8,
12
+ "attention_bias": false,
13
+ "attention_dropout": 0.0,
14
+ "bos_token_id": 1,
15
+ "dtype": "float32",
16
+ "eos_token_id": 2,
17
+ "head_dim": 64,
18
+ "hidden_act": "silu",
19
+ "hidden_size": 576,
20
+ "hybrid_layer_indices": null,
21
+ "initializer_range": 0.041666666666666664,
22
+ "intermediate_size": 1536,
23
+ "is_llama_config": true,
24
+ "max_position_embeddings": 8192,
25
+ "mlp_bias": false,
26
+ "model_type": "asterisk",
27
+ "num_attention_heads": 9,
28
+ "num_hidden_layers": 30,
29
+ "num_key_value_heads": 3,
30
+ "pad_token_id": 2,
31
+ "pretraining_tp": 1,
32
+ "rms_norm_eps": 1e-05,
33
+ "rope_interleaved": false,
34
+ "rope_scaling": null,
35
+ "rope_theta": 100000,
36
+ "tie_word_embeddings": true,
37
+ "transformers.js_config": {
38
+ "kv_cache_dtype": {
39
+ "fp16": "float16",
40
+ "q4f16": "float16"
41
+ }
42
+ },
43
+ "transformers_version": "4.57.6",
44
+ "use_cache": true,
45
+ "vocab_size": 49152
46
+ }
generation_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": [
5
+ 2
6
+ ],
7
+ "pad_token_id": 2,
8
+ "transformers_version": "4.57.6"
9
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3af701c6eb2735e0c54417aa3eb6d2460ee92de8b646e22c6fe7106388611fdb
3
+ size 684933848
special_tokens_map.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>"
5
+ ],
6
+ "bos_token": {
7
+ "content": "<|im_start|>",
8
+ "lstrip": false,
9
+ "normalized": false,
10
+ "rstrip": false,
11
+ "single_word": false
12
+ },
13
+ "eos_token": {
14
+ "content": "<|im_end|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false
19
+ },
20
+ "pad_token": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false
26
+ },
27
+ "unk_token": {
28
+ "content": "<|endoftext|>",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false
33
+ }
34
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "<|im_start|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "3": {
29
+ "content": "<repo_name>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "4": {
37
+ "content": "<reponame>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "5": {
45
+ "content": "<file_sep>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "6": {
53
+ "content": "<filename>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "7": {
61
+ "content": "<gh_stars>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "8": {
69
+ "content": "<issue_start>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "9": {
77
+ "content": "<issue_comment>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "10": {
85
+ "content": "<issue_closed>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "11": {
93
+ "content": "<jupyter_start>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "12": {
101
+ "content": "<jupyter_text>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "13": {
109
+ "content": "<jupyter_code>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "14": {
117
+ "content": "<jupyter_output>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": true
123
+ },
124
+ "15": {
125
+ "content": "<jupyter_script>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": true
131
+ },
132
+ "16": {
133
+ "content": "<empty_output>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": true
139
+ }
140
+ },
141
+ "additional_special_tokens": [
142
+ "<|im_start|>",
143
+ "<|im_end|>"
144
+ ],
145
+ "bos_token": "<|im_start|>",
146
+ "clean_up_tokenization_spaces": false,
147
+ "eos_token": "<|im_end|>",
148
+ "extra_special_tokens": {},
149
+ "model_max_length": 8192,
150
+ "pad_token": "<|im_end|>",
151
+ "tokenizer_class": "GPT2Tokenizer",
152
+ "unk_token": "<|endoftext|>",
153
+ "vocab_size": 49152
154
+ }
training_args.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:49e41e7530752cf0d15a3251e00703b28ccee977859c7f621eca6e31227608ca
3
+ size 6353
vocab.json ADDED
The diff for this file is too large to render. See raw diff