kayrahan35 commited on
Commit
f9b2068
·
verified ·
1 Parent(s): f6fb715

Upload 11 files

Browse files
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ model.safetensors filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: agpl-3.0
3
+ library_name: transformers
4
+ pipeline_tag: text-generation
5
+ tags:
6
+ - pytorch
7
+ - causal-lm
8
+ - linear-attention
9
+ - long-context
10
+ - recurrent-memory
11
+ - o1-memory
12
+ - hfp
13
+ - custom_code
14
+ language:
15
+ - en
16
+ ---
17
+
18
+ # HFP — Hyper-Flux Projection (O(1)-Memory Causal LM)
19
+
20
+ > **Status: research preview — architecture only, weights are UNTRAINED.**
21
+ > This repository ships the model *code* and a randomly-initialized checkpoint so
22
+ > the architecture can be loaded, inspected and trained. It is not a usable
23
+ > language model yet. Canonical source & experiments:
24
+ > **[github.com/kayra-hn/HFP](https://github.com/kayra-hn/HFP)**
25
+
26
+ HFP is an experimental causal LM that pairs **windowed local attention** with a
27
+ **per-layer recurrent linear-attention memory** (`M ∈ ℝ^{key_dim×H}`, `z ∈ ℝ^{key_dim}`).
28
+ The inference-time state is **constant in context length** (O(1) memory instead of
29
+ a growing KV-cache); long-range information must flow through the recurrent memory.
30
+
31
+ Its distinguishing feature is a selectable **retention law** for that memory:
32
+
33
+ - `decay_mode="exp"` — standard geometric decay (the RetNet/GLA/Mamba family baseline).
34
+ - `decay_mode="cubic_flux"` — an exact discretization of the cubic relaxation
35
+ `dθ/dτ = −η·θ³`: a **state-magnitude-dependent** decay
36
+ `λ_t = 1/√(1+2η·z_t²)`. Empty channels barely decay (plateau); full channels
37
+ forget actively (self-limiting).
38
+
39
+ Two further independent axes: a **binding convolution** on the Q/K path
40
+ (`conv_kernel`, ablate with 1) and a **capacity axis** via DPFP key feature maps
41
+ (`key_feature_map="dpfp"`).
42
+
43
+ ## Honest status of results
44
+
45
+ Full multi-seed record: [RESULTS.md on GitHub](https://github.com/kayra-hn/HFP/blob/main/RESULTS.md).
46
+ Highlights (small scale, synthetic recall; patterns seed-robust across 3 seeds):
47
+
48
+ - **Length generalization**: trained at 160 tokens, the model transfers to
49
+ 1280-token streams (8x), with fixed-gap recall *improving* as fact density falls —
50
+ train-short / infer-long is the supported deployment mode of the O(1) state.
51
+ - **DPFP capacity axis** (`key_feature_map="dpfp"`): first mechanism with a clear
52
+ advantage — 2-6x baseline accuracy at long gaps under high interference, plus
53
+ more stable training. Recommended: `exp` + additive + `dpfp` + `ffn_type="standard"`.
54
+ - `cubic_flux` currently trails the exponential baseline at this scale (parked as
55
+ a long-horizon hypothesis; exact parallel form implemented). No LM-benchmark
56
+ claims are made. Weights in this repo remain untrained/architecture-only.
57
+
58
+ ## Usage
59
+
60
+ ```python
61
+ import torch
62
+ from transformers import AutoModelForCausalLM
63
+
64
+ model = AutoModelForCausalLM.from_pretrained(
65
+ "kayrahan35/HFP-O1-Memory-Model",
66
+ trust_remote_code=True, # custom architecture (HFPForCausalLM)
67
+ )
68
+
69
+ # Streaming inference with constant memory:
70
+ past = None
71
+ for chunk in token_chunks: # e.g. 256-token chunks
72
+ out = model(chunk, past_key_values=past, use_cache=True)
73
+ past = out.past_key_values # fixed-size state, does not grow
74
+ ```
75
+
76
+ Switch the retention law / capacity axis at construction:
77
+
78
+ ```python
79
+ from transformers import AutoConfig, AutoModelForCausalLM
80
+ cfg = AutoConfig.from_pretrained("kayrahan35/HFP-O1-Memory-Model", trust_remote_code=True)
81
+ cfg.decay_mode = "cubic_flux" # or "exp"
82
+ cfg.key_feature_map = "dpfp" # or "elu"
83
+ model = AutoModelForCausalLM.from_config(cfg, trust_remote_code=True)
84
+ ```
85
+
86
+ Note: `cubic_flux` uses a sequential scan (O(L)) and is ~2–3× slower than the
87
+ parallel `exp` path.
88
+
89
+ ## Files
90
+
91
+ `modeling_hfp.py` / `configuration_hfp.py` — HF-compatible model & config;
92
+ `hfp_bulk_state.py` — the recurrent memory (retention laws, binding conv, DPFP);
93
+ `bulk_trigger_decoder.py` — decoder layer (windowed attention + shared-bulk FFN).
94
+ Training scripts, regression tests (`smoke_test.py`) and the retention/recall
95
+ experiment suite live in the [GitHub repository](https://github.com/kayra-hn/HFP).
96
+
97
+ ## Links & license
98
+
99
+ Theory preprint: [OSF](https://osf.io/xc7e4) (inspiration for the retention law;
100
+ the model neither validates nor is validated by the physics).
101
+
102
+ **GNU AGPL-3.0.** Network deployment of this architecture or derivatives
103
+ requires open-sourcing modifications under the same license.
bulk_trigger_decoder.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import torch
18
+ import torch.nn as nn
19
+ import torch.nn.functional as F
20
+ import math
21
+ from .hfp_config import config as hfp_config
22
+ from .hfp_utils import compute_curvature, compute_entropy_map, magnitude_defect_flag, coherence_score, conservation_check, holographic_information_bound
23
+ from .hfp_bulk_state import HFPBulkState
24
+
25
+ class HFPLinear(nn.Module):
26
+ def __init__(self, in_features, out_features):
27
+ super(HFPLinear, self).__init__()
28
+ self.linear = nn.Linear(in_features, out_features)
29
+
30
+ def forward(self, x):
31
+ return self.linear(x)
32
+
33
+ # [FIX K3] TunnelingDropout KALDIRILDI: 3 forward onceki, FARKLI batch'e ait
34
+ # detached aktivasyonlari simdiki ciktiya ekliyordu -> batch'ler arasi sizinti +
35
+ # train/eval davranis farki. Ne dropout ne fizik; standart Dropout kullanilir.
36
+ # (Eski kod referans icin _legacy_reference/ altinda.)
37
+
38
+ class EntangledLinear(nn.Module):
39
+ """Tek Bulk agirligindan (W_bulk) iki projeksiyon (P_A, P_B) - physics-inspired
40
+ parametre baglama. Analoji: Paper II'nin 'tek Bulk vektorunun iki golgesi';
41
+ izomorfizm/simulasyon iddiasi degildir."""
42
+ def __init__(self, in_features_A, out_features_A, in_features_B, out_features_B, bulk_dim=128):
43
+ super(EntangledLinear, self).__init__()
44
+ self.max_in = max(in_features_A, in_features_B)
45
+ self.W_bulk = nn.Parameter(torch.randn(bulk_dim, self.max_in) / math.sqrt(self.max_in))
46
+
47
+ self.P_A = nn.Parameter(torch.randn(out_features_A, bulk_dim) / math.sqrt(bulk_dim))
48
+ self.P_B = nn.Parameter(torch.randn(out_features_B, bulk_dim) / math.sqrt(bulk_dim))
49
+
50
+ self.bias_A = nn.Parameter(torch.zeros(out_features_A))
51
+ self.bias_B = nn.Parameter(torch.zeros(out_features_B))
52
+
53
+ def get_orthogonality_loss(self):
54
+ dot = self.P_A @ self.P_B.t()
55
+ return torch.norm(dot, p='fro')
56
+
57
+ def forward_A(self, x):
58
+ if not self.training:
59
+ if not hasattr(self, 'W_A_cache'):
60
+ self.W_A_cache = self.P_A @ self.W_bulk[:, :x.size(-1)]
61
+ W_A = self.W_A_cache
62
+ else:
63
+ if hasattr(self, 'W_A_cache'):
64
+ del self.W_A_cache
65
+ W_A = self.P_A @ self.W_bulk[:, :x.size(-1)]
66
+ return F.linear(x, W_A, self.bias_A)
67
+
68
+ def forward_B(self, x):
69
+ if not self.training:
70
+ if not hasattr(self, 'W_B_cache'):
71
+ self.W_B_cache = self.P_B @ self.W_bulk[:, :x.size(-1)]
72
+ W_B = self.W_B_cache
73
+ else:
74
+ if hasattr(self, 'W_B_cache'):
75
+ del self.W_B_cache
76
+ W_B = self.P_B @ self.W_bulk[:, :x.size(-1)]
77
+ return F.linear(x, W_B, self.bias_B)
78
+
79
+ class EntangledFFN(nn.Module):
80
+ def __init__(self, hidden_size, feedforward_dim, bulk_dim=128, dropout_p=0.1):
81
+ super(EntangledFFN, self).__init__()
82
+ self.entangled = EntangledLinear(hidden_size, feedforward_dim, feedforward_dim, hidden_size, bulk_dim)
83
+ self.gelu = nn.GELU()
84
+ # [FIX K3] Standart dropout (TunnelingDropout'un yerine)
85
+ self.dropout = nn.Dropout(dropout_p)
86
+
87
+ def forward(self, x):
88
+ mid = self.entangled.forward_A(x)
89
+ mid = self.gelu(mid)
90
+ mid = self.dropout(mid)
91
+ out = self.entangled.forward_B(mid)
92
+ return out
93
+
94
+ def get_orthogonality_loss(self):
95
+ return self.entangled.get_orthogonality_loss()
96
+
97
+ class StandardFFN(nn.Module):
98
+ """[HFP-SCALE] Rank kisiti olmayan standart Transformer FFN'i.
99
+ EntangledFFN paylasilan W_bulk yuzunden rank<=bulk_dim darbogazi tasir
100
+ (or. bulk_dim=128, H=768'de FFN rank-128'e sikisir). Olcekleme kosulari
101
+ icin ffn_type="standard" bu darbogazi kaldirir. Parametre sayisi
102
+ EntangledFFN'den fazladir; A/B kiyaslarinda parametre esitligine dikkat."""
103
+ def __init__(self, hidden_size, feedforward_dim, dropout_p=0.1):
104
+ super().__init__()
105
+ self.fc1 = nn.Linear(hidden_size, feedforward_dim)
106
+ self.fc2 = nn.Linear(feedforward_dim, hidden_size)
107
+ self.gelu = nn.GELU()
108
+ self.dropout = nn.Dropout(dropout_p)
109
+
110
+ def forward(self, x):
111
+ return self.fc2(self.dropout(self.gelu(self.fc1(x))))
112
+
113
+ def get_orthogonality_loss(self):
114
+ return torch.zeros((), device=self.fc1.weight.device)
115
+
116
+ class BulkTriggerDecoderLayer(nn.Module):
117
+ """
118
+ BulkTriggerDecoderLayer V3: Lokal (pencereli) attention + recurrent Bulk hafiza.
119
+
120
+ Mimari niyet (eski V2 yorumundaki 'Local Attention over Brane ONLY') artik
121
+ gercekten uygulanir: [FIX K5]
122
+ - local_window=None -> tam causal attention (eski davranis, geriye uyumlu).
123
+ - local_window=w -> her sorgu yalnizca son w tokeni gorur; uzun menzil
124
+ bilgi YALNIZCA Bulk hafizadan (M, z) akabilir. Bellek iddialarini test
125
+ etmek icin bu mod sarttir (aksi halde attention tum baglami gorur ve
126
+ bellek olculmez).
127
+ - Ring buffer'in yazilmamis (sifir) slotlari artik MASKELENIR (eski D2 sorunu).
128
+ """
129
+ def __init__(self, hidden_size, num_heads, feedforward_dim, bulk_dim=128,
130
+ vocab_size=None, return_aux=False, local_window=None, dropout_p=0.1,
131
+ ffn_type="entangled"):
132
+ super(BulkTriggerDecoderLayer, self).__init__()
133
+ self.hidden_size = hidden_size
134
+ self.num_heads = num_heads
135
+ self.local_window = local_window
136
+
137
+ self.cross_attention = nn.MultiheadAttention(embed_dim=hidden_size, num_heads=num_heads, batch_first=True, dropout=0.1)
138
+ self.return_aux = return_aux
139
+ self.norm1 = nn.LayerNorm(hidden_size)
140
+
141
+ # [HFP-SCALE] ffn_type: "entangled" (parametre-bagli, rank<=bulk_dim) |
142
+ # "standard" (kisitsiz, olcekleme onerilen)
143
+ if ffn_type == "standard":
144
+ self.ffn = StandardFFN(hidden_size, feedforward_dim, dropout_p=dropout_p)
145
+ else:
146
+ self.ffn = EntangledFFN(hidden_size, feedforward_dim, bulk_dim=bulk_dim, dropout_p=dropout_p)
147
+ self.norm2 = nn.LayerNorm(hidden_size)
148
+
149
+ self.vocab_size = vocab_size
150
+ if vocab_size is not None:
151
+ self.lm_head = HFPLinear(hidden_size, vocab_size)
152
+ else:
153
+ self.lm_head = None
154
+
155
+ def _build_mask(self, seq_len, n_past, valid_past, device):
156
+ """True = maskeli. Sutunlar: [simdiki chunk (seq_len) | ring buffer (n_past)]."""
157
+ ii = torch.arange(seq_len, device=device).view(-1, 1)
158
+ jj = torch.arange(seq_len, device=device).view(1, -1)
159
+ causal = jj > ii
160
+ if self.local_window is not None:
161
+ # [K5] Sliding window: yalnizca son w token gorulur
162
+ causal = causal | (jj <= ii - self.local_window)
163
+ if n_past > 0:
164
+ # [K5/D2] Yazilmamis (sifir) slotlar maskelenir. Buffer dolana kadar
165
+ # yazim sirasi 0,1,2,... oldugundan gecerli slotlar ilk valid_past tanedir.
166
+ past_cols = (torch.arange(n_past, device=device) >= valid_past).view(1, -1)
167
+ past_mask = past_cols.expand(seq_len, n_past)
168
+ return torch.cat([causal, past_mask], dim=1)
169
+ return causal
170
+
171
+ def forward(self, x, bulk_state, past_state=None, return_past_state=False,
172
+ return_aux=None, detach_state=True):
173
+ if return_aux is None:
174
+ return_aux = getattr(self, 'return_aux', False)
175
+
176
+ # 1. Recurrent Bulk hafiza guncelle + oku ([K2] artik gradyanli yol)
177
+ short_mem, retrieved_memory, new_past_state = bulk_state.update(
178
+ x, past_state=past_state, detach_state=detach_state)
179
+
180
+ aux_losses = []
181
+
182
+ # Opsiyonel physics-inspired aux teshisleri (default kapali)
183
+ if hfp_config.ENABLE_RYU_TAKAYANAGI:
184
+ gate_entropy_tensor = bulk_state.gate_entropy_loss() / hfp_config.REG_WEIGHT if hfp_config.ENABLE_ENTROPY_MAP else torch.tensor(0.0, device=x.device)
185
+ M_matrix = new_past_state[1]
186
+ rt_loss = holographic_information_bound(gate_entropy_tensor, M_matrix)
187
+ aux_losses.append(rt_loss.mean().unsqueeze(0))
188
+
189
+ if hfp_config.ENABLE_ENTROPY_MAP:
190
+ aux_losses.append(bulk_state.gate_entropy_loss())
191
+
192
+ if hfp_config.ENABLE_5D_CURVATURE or hfp_config.ENABLE_CURVATURE:
193
+ aux_losses.append(compute_curvature(short_mem).unsqueeze(0))
194
+
195
+ if hfp_config.ENABLE_DEFECT_FLAG:
196
+ aux_losses.append(magnitude_defect_flag(short_mem).mean().unsqueeze(0))
197
+ if hfp_config.ENABLE_COHERENCE:
198
+ aux_losses.append(coherence_score(short_mem).unsqueeze(0))
199
+ if hfp_config.ENABLE_CONSERVATION:
200
+ aux_losses.append(torch.tensor(1.0 if conservation_check(short_mem) else 0.0, device=short_mem.device))
201
+
202
+ # 2. Lokal attention: simdiki chunk + (varsa) onceki chunk'larin ring buffer'i
203
+ seq_len = x.size(1)
204
+ if past_state is not None and past_state[0] is not None:
205
+ past_short_mem = past_state[0]
206
+ # [K5] state'teki token_count (index 3) gecerli slot sayisini verir
207
+ valid_past = min(int(past_state[3]), past_short_mem.size(1))
208
+ else:
209
+ past_short_mem = None
210
+ valid_past = 0
211
+
212
+ if past_short_mem is not None and valid_past > 0:
213
+ memory_bank = torch.cat([x, past_short_mem], dim=1)
214
+ n_past = past_short_mem.size(1)
215
+ else:
216
+ memory_bank = x
217
+ n_past = 0
218
+
219
+ dual_mask = self._build_mask(seq_len, n_past, valid_past, x.device)
220
+ attn_out, _ = self.cross_attention(query=x, key=memory_bank, value=memory_bank, attn_mask=dual_mask)
221
+
222
+ # 3. Bulk hafizadan okunan icerik eklenir
223
+ attn_out = attn_out + retrieved_memory
224
+
225
+ x = self.norm1(x + attn_out)
226
+
227
+ # 4. FFN
228
+ ffn_out = self.ffn(x)
229
+ x = self.norm2(x + ffn_out)
230
+
231
+ if return_aux:
232
+ aux_losses.append(self.ffn.get_orthogonality_loss().unsqueeze(0))
233
+
234
+ # 5. Logits
235
+ if self.lm_head is not None:
236
+ logits = self.lm_head(x)
237
+ else:
238
+ logits = x
239
+
240
+ if return_aux:
241
+ return logits, bulk_state, new_past_state, aux_losses
242
+ if return_past_state:
243
+ return logits, bulk_state, new_past_state
244
+ return logits, bulk_state
245
+
246
+ if __name__ == "__main__":
247
+ batch_size = 2
248
+ hidden_size = 256
249
+ num_heads = 8
250
+ feedforward_dim = 1024
251
+ vocab_size = 50000
252
+
253
+ layer = BulkTriggerDecoderLayer(
254
+ hidden_size=hidden_size,
255
+ num_heads=num_heads,
256
+ feedforward_dim=feedforward_dim,
257
+ vocab_size=vocab_size
258
+ )
259
+ memory_system = HFPBulkState(hidden_size=hidden_size)
260
+ current_token = torch.randn(batch_size, 1, hidden_size)
261
+ logits, updated_memory = layer(current_token, memory_system)
262
+
263
+ print(f"Girdi Boyutu: {current_token.shape}")
264
+ print(f"Logits Çıktı Boyutu: {logits.shape}")
config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ENABLE_COHERENCE": false,
3
+ "architectures": [
4
+ "HFPForCausalLM"
5
+ ],
6
+ "auto_map": {
7
+ "AutoConfig": "configuration_hfp.HFPConfig",
8
+ "AutoModelForCausalLM": "modeling_hfp.HFPForCausalLM"
9
+ },
10
+ "aux_gate_entropy_weight": 0.0,
11
+ "aux_ortho_weight": 0.0,
12
+ "bos_token_id": 1,
13
+ "bptt_across_chunks": false,
14
+ "bulk_dim": 128,
15
+ "conv_kernel": 3,
16
+ "decay_mode": "exp",
17
+ "dpfp_nu": 2,
18
+ "dropout_p": 0.1,
19
+ "dtype": "float32",
20
+ "eos_token_id": 2,
21
+ "ffn_type": "entangled",
22
+ "hidden_size": 768,
23
+ "intermediate_size": 3072,
24
+ "key_feature_map": "elu",
25
+ "local_window": 64,
26
+ "max_position_embeddings": 4096,
27
+ "max_short_len": null,
28
+ "model_type": "hfp",
29
+ "num_attention_heads": 12,
30
+ "num_hidden_layers": 12,
31
+ "pe_scale": 0.3,
32
+ "rec_block": 64,
33
+ "short_len": 8,
34
+ "tie_word_embeddings": true,
35
+ "transformers_version": "5.13.0",
36
+ "tunnel_decay": 0.8,
37
+ "tunnel_depth": 3,
38
+ "vocab_size": 50257,
39
+ "write_rule": "additive"
40
+ }
configuration_hfp.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ from transformers import PretrainedConfig
18
+
19
+ class HFPConfig(PretrainedConfig):
20
+ model_type = "hfp"
21
+
22
+ def __init__(
23
+ self,
24
+ vocab_size=5000,
25
+ hidden_size=256,
26
+ num_hidden_layers=4,
27
+ num_attention_heads=8,
28
+ intermediate_size=512,
29
+ bulk_dim=128,
30
+ tunnel_depth=3,
31
+ tunnel_decay=0.8,
32
+ dropout_p=0.1,
33
+ short_len=8,
34
+ max_short_len=None, # [FIX K4] ring buffer kapasitesi; None -> max(short_len, 32)
35
+ local_window=None, # [FIX K5] None=tam causal attention; w=yalnizca son w token
36
+ # (bellek testleri icin sart: aksi halde attention tum baglami gorur)
37
+ pe_scale=0.3, # [FIX K7] pozisyonel kodlama olcegi; ham PE (1.0) token
38
+ # icerigini ~35x boguyordu -> recall imkansizdi. 0.3 = dengeli.
39
+ rec_block=64, # [K2] chunk-ici recurrence blok boyutu (hiz/bellek; sonucu degistirmez)
40
+ decay_mode="exp", # [HFP-CORE] "exp"=geometrik decay baseline; "cubic_flux"=
41
+ # makalenin dth/dtau=-eta*th^3 kubik-plato retention'i (ayirt edici);
42
+ # "cubic_flux_chunked"=[HFP-SCALE] iki-gecisli TAM paralel form
43
+ # (z-taramasi + GLA-tarzi chunkwise M; her rec_block'ta birebir)
44
+ conv_kernel=3, # [FIX K8] binding conv kernel'i (Q/K token-karisimi). 1=kapali (ablasyon)
45
+ key_feature_map="elu", # [HFP-CAP] bellek anahtar ozellik-haritasi. "elu"=elu+1 (baseline,
46
+ # D=H). "dpfp"=Deterministic Parameter-Free Projection (D=2H*nu):
47
+ # efektif boyutu buyutur -> rank-collapse'i geciktirir, KAPASITE artar.
48
+ dpfp_nu=2, # [HFP-CAP] dpfp genisleme faktoru (key_dim = 2*hidden_size*nu)
49
+ bptt_across_chunks=False, # [K2] True -> chunk'lar arasi state detach edilmez (TBPTT)
50
+ max_position_embeddings=8192, # [FIX A1] onceden tanimsizdi -> from_1b_profile cokuyordu
51
+ aux_gate_entropy_weight=0.0, # [C1] opsiyonel gate-entropy duzenleyici; 0.0 = kapali (durust baseline)
52
+ write_rule="additive", # [HFP-DELTA] "additive"=k v^T toplama (baseline);
53
+ # "delta"=olcum-guncelleme yazimi (girisim-dirençli, sirali)
54
+ ffn_type="entangled", # [HFP-SCALE] "entangled"=paylasilan-bulk FFN (rank<=bulk_dim);
55
+ # "standard"=kisitsiz FFN (olcekleme icin onerilir)
56
+ aux_ortho_weight=0.0, # [ORTHO] EntangledFFN P_A/P_B ortogonallik cezasi; 0.0 = kapali
57
+ bos_token_id=1,
58
+ eos_token_id=2,
59
+ **kwargs
60
+ ):
61
+ self.vocab_size = vocab_size
62
+ self.hidden_size = hidden_size
63
+ self.num_hidden_layers = num_hidden_layers
64
+ self.num_attention_heads = num_attention_heads
65
+ self.intermediate_size = intermediate_size
66
+ self.bulk_dim = bulk_dim
67
+ self.tunnel_depth = tunnel_depth
68
+ self.tunnel_decay = tunnel_decay
69
+ self.dropout_p = dropout_p
70
+ self.short_len = short_len
71
+ self.max_short_len = max_short_len
72
+ self.local_window = local_window
73
+ self.pe_scale = pe_scale
74
+ self.rec_block = rec_block
75
+ self.decay_mode = decay_mode
76
+ self.conv_kernel = conv_kernel
77
+ self.key_feature_map = key_feature_map
78
+ self.dpfp_nu = dpfp_nu
79
+ self.bptt_across_chunks = bptt_across_chunks
80
+ self.max_position_embeddings = max_position_embeddings
81
+ self.aux_gate_entropy_weight = aux_gate_entropy_weight
82
+ self.write_rule = write_rule
83
+ self.ffn_type = ffn_type
84
+ self.aux_ortho_weight = aux_ortho_weight
85
+ # [TEMIZLIK B1] medium_freq / long_freq / medium_momentum kaldirildi:
86
+ # mimari lineer-attention (M, z + decay) oldugundan bunlarin hicbir entegrasyonu yok.
87
+ self.ENABLE_COHERENCE = kwargs.pop("ENABLE_COHERENCE", False)
88
+ # [D1] Weight tying resmen bildirilir: transformers v5 bunu gormezse
89
+ # from_pretrained sonrasi lm_head/embedding baglantisini KURMAZ.
90
+ kwargs.setdefault("tie_word_embeddings", True)
91
+ super().__init__(bos_token_id=bos_token_id, eos_token_id=eos_token_id, **kwargs)
92
+
93
+ @classmethod
94
+ def from_1b_profile(cls, vocab_size=50257):
95
+ """Creates a 1 Billion Parameter configuration for Cloud Training."""
96
+ return cls(
97
+ vocab_size=vocab_size,
98
+ hidden_size=2048,
99
+ num_hidden_layers=24,
100
+ num_attention_heads=16,
101
+ intermediate_size=8192,
102
+ bulk_dim=512,
103
+ short_len=64,
104
+ max_short_len=64, # [FIX K4] eskiden sessizce 32'ye kirpiliyordu
105
+ max_position_embeddings=32768, # [FIX A1] 1B profili icin pozisyon tavani
106
+ ENABLE_COHERENCE=False
107
+ )
generation_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": 2,
5
+ "output_attentions": false,
6
+ "output_hidden_states": false,
7
+ "transformers_version": "5.13.0"
8
+ }
hfp_bulk_state.py ADDED
@@ -0,0 +1,426 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import torch
18
+ import torch.nn as nn
19
+ import torch.nn.functional as F
20
+ import logging
21
+
22
+ logging.basicConfig(level=logging.WARNING, format='[%(levelname)s] %(message)s')
23
+ from .hfp_utils import LandmarkBuffer, compute_gate_entropy, coherence_score
24
+ from .hfp_config import config as hfp_config
25
+
26
+ class HFPBulkState(nn.Module):
27
+ """
28
+ HFPBulkState V4 (Recurrent Edition): Causal chunkwise linear attention.
29
+
30
+ [FIX K2 - GRADYAN AKISI] Onceki surumde retrieval, M guncellemesinden ONCE
31
+ yapiliyordu; tek-parca egitimde M=0 oldugundan retrieval hep sifirdi ve
32
+ W_k/W_v/decay/importance_gate LM loss'tan HIC gradyan alamiyordu (bellek
33
+ egitimde olu agirlikti). Bu surum gercek causal lineer attention'dir:
34
+ her token, o ana KADARKI kumulatif M/z'den okur (kendi KV'si dahil),
35
+ per-token decay ile. Boylece bellek yolu ayni forward icinde ciktiya
36
+ baglanir ve TUM bellek parametreleri gradyan alir.
37
+
38
+ Matematik (RetNet/GLA tarzi chunkwise form, tum usler >= 0 -> stabil):
39
+ lam = sigmoid(decay) (K-kanali basina, 0..1)
40
+ M_t = lam (.) M_{t-1} + k_t v_t^T , z_t = lam (.) z_{t-1} + k_t
41
+ out_t = (q_t M_t) / (q_t . z_t)
42
+ Blok ici (m token):
43
+ cross: (q_i * lam^i) M_0 intra: S_ij = q_i . (lam^{i-j} (.) k_j), j<=i
44
+ Uretim yolu (1 token/cagri) ayni formulun m=1 halidir -> egitim/uretim
45
+ decay semantigi artik TUTARLI (eski surum decay'i cagri basina 1 kez
46
+ uyguluyordu; 256-token chunk ile 1-token generate farkli davraniyordu).
47
+
48
+ Onceki yapisal duzeltmeler korunur:
49
+ - Matrix blowup: decay init sigmoid(2.19)~0.9 + retrieval LayerNorm.
50
+ - Gate collapse: importance_gate bias -2.0.
51
+ - Ring buffer: sabit boyutlu, vektorize yazim (Python token-dongusu kaldirildi).
52
+ [FIX K4] max_short_len artik parametre: config.short_len > 32 sessizce
53
+ kirpilmiyor (1B profili short_len=64 gercekten 64 slot alir).
54
+ [FIX D3] batch>16'da sessiz half() donusumu kaldirildi.
55
+ """
56
+
57
+ def __init__(self, hidden_size, short_len=8, max_short_len=None,
58
+ rec_block=64, use_mixed_precision=False, clip_value=1.0,
59
+ decay_mode="exp", conv_kernel=3, key_feature_map="elu", dpfp_nu=2,
60
+ write_rule="additive"):
61
+ super(HFPBulkState, self).__init__()
62
+ self.hidden_size = hidden_size
63
+ self.base_short_len = short_len
64
+ # [HFP-CAP] Anahtar ozellik-haritasi ve efektif anahtar boyutu (key_dim).
65
+ # "elu": elu(x)+1, key_dim=H (baseline). "dpfp": Deterministic Parameter-Free
66
+ # Projection, key_dim=2*H*nu -> daha yuksek efektif boyut, rank-collapse
67
+ # geciktirilir, bellek KAPASITESI (kac ayri olgu) artar. M artik (key_dim, H),
68
+ # z (key_dim); deger (V) boyutu H olarak kalir. Retention (exp/cubic) ve
69
+ # binding conv'dan BAGIMSIZ eksen.
70
+ self.key_feature_map = key_feature_map
71
+ self.dpfp_nu = max(1, dpfp_nu)
72
+ self.key_dim = hidden_size if key_feature_map != "dpfp" else 2 * hidden_size * self.dpfp_nu
73
+ # [HFP-CORE] Retention yasasi. "exp" = standart geometrik decay (RetNet/GLA
74
+ # ailesi, baseline). "cubic_flux" = makalenin dth/dtau=-eta*th^3 kubik
75
+ # akisinin birebir ayriklastirmasi: state-buyuklugune bagli, plato+power-law
76
+ # unutma. Ailedeki hicbir modelde olmayan ayirt edici mekanizma.
77
+ self.decay_mode = decay_mode
78
+ # [HFP-DELTA] Yazim kurali. "additive" = M += k(x)v^T (baseline; ayni anahtara
79
+ # tekrarli yazimlar GIRISIM yapar). "delta" = DeltaNet-tarzi olcum-guncelleme:
80
+ # M~ = lam (.) M ; v_old = k^T M~ ; M = M~ + beta * k (v - v_old)^T
81
+ # Eski iliskiyi okuyup FARKI yazar -> ayni anahtarin eski degeri silinir,
82
+ # girisim birikmez. k L2-normalize edilir, beta=sigmoid(gate) in (0,1) ->
83
+ # (I - beta k k^T) kontraksiyon, state patlamaz. Payda (q.z) kullanilmaz
84
+ # (delta'da kutle birikimi anlamsiz); cikti q.M -> retrieval_norm olcekler.
85
+ # Sirali O(L) (WY/chunkwise formu ileriki is; GPU olcek icin gerekli).
86
+ self.write_rule = write_rule
87
+
88
+ # [FIX K4] Kapasite en az short_len; eskisi gibi sessizce 32'ye kirpma yok.
89
+ if max_short_len is None:
90
+ max_short_len = max(short_len, getattr(hfp_config, 'MAX_SHORT_LEN', 32))
91
+ assert max_short_len >= short_len, \
92
+ f"max_short_len ({max_short_len}) < short_len ({short_len})"
93
+ self.max_short_len = max_short_len
94
+
95
+ # [K2] Chunk-ici recurrence blok boyutu (dogruluk degil hiz/bellek dengesi;
96
+ # sonuc blok boyutundan BAGIMSIZDIR - bkz. smoke_test.py tutarlilik testi).
97
+ self.rec_block = max(1, rec_block)
98
+
99
+ self.landmark_max = hfp_config.LANDMARK_MAX
100
+ self.gate_temperature = nn.Parameter(torch.tensor(1.0), requires_grad=False)
101
+ self.use_mixed_precision = use_mixed_precision # [D3] no-op; geriye uyumluluk icin duruyor
102
+ self.clip_value = clip_value
103
+ self.dynamic_short_thresh = hfp_config.ENTROPY_THRESH
104
+
105
+ # Selective Scan Gating (Information Bottleneck)
106
+ self.importance_gate = nn.Linear(hidden_size, hidden_size)
107
+ # [GATE COLLAPSE FIX] sigmoid(-2.0) ~ 0.12 baslangici
108
+ nn.init.constant_(self.importance_gate.bias, -2.0)
109
+ self.gate_dropout = nn.Dropout(0.1)
110
+
111
+ # [FIX K8 - KISA CAUSAL CONV / BINDING] Lineer-attention BELLEGININ
112
+ # associative-recall yapabilmesi icin sart olan token-karisimi. Onceki
113
+ # surumde her token bellege KENDI key(x_t)⊗value(x_t)'sini yaziyordu;
114
+ # v1'in anahtari onu ONCELEYEN k1'i kodlamadigindan sorgu=k1 ile v1
115
+ # GETIRILEMIYORDU (MQAR loss ln(val_space)'te sabit, full-attention %100).
116
+ # Depthwise causal conv (kernel=3) Q/K yoluna uygulanir -> K[v1-pozisyonu]
117
+ # artik onceki token k1'i kodlar, Q[k1] ile eslesir. V ORIJINAL x'ten
118
+ # (temiz deger). Mamba/H3/Based hepsi bu kisa conv'u icerir. Retention
119
+ # yasasindan (exp/cubic_flux) BAGIMSIZ - kimlige dokunmaz. Chunk-tutarlilik
120
+ # icin conv state chunk'lar arasi tasinir (T4 korunur).
121
+ self.conv_kernel = max(1, conv_kernel)
122
+ self.short_conv = nn.Conv1d(hidden_size, hidden_size, kernel_size=self.conv_kernel,
123
+ groups=hidden_size, bias=True, padding=0)
124
+
125
+ # Linear Attention Projections
126
+ self.W_q = nn.Linear(hidden_size, hidden_size, bias=False)
127
+ self.W_k = nn.Linear(hidden_size, hidden_size, bias=False)
128
+ self.W_v = nn.Linear(hidden_size, hidden_size, bias=False)
129
+
130
+ # [FIX K2b - COK-OLCEKLI DECAY] Eskiden tum kanallar sigmoid(2.19)~0.9
131
+ # ile TEK olcekte baslardi -> bellek ufku ~1/(1-0.9)=10 token; 100 token
132
+ # geriden recall matematiksel olarak imkansizdi (lam^100~2e-5). Simdi
133
+ # kanal basina lam 0.90..0.999 arasi lineer dagilir (RetNet/GLA-tarzi
134
+ # multi-timescale): bazi kanallar ~10 token, bazilari ~1000 token tutar.
135
+ # Sigmoid ciktisi (0,1) oldugundan matrix-blowup korumasi korunur; tum
136
+ # usler >= 0 stabilite degismez. decay hala LM loss'tan gradyan alir.
137
+ # [HFP-CAP] decay/eta artik anahtar-kanali basina -> key_dim boyutunda.
138
+ lam_min = getattr(hfp_config, 'DECAY_LAM_MIN', 0.90)
139
+ lam_max = getattr(hfp_config, 'DECAY_LAM_MAX', 0.999)
140
+ lam_init = torch.linspace(lam_min, lam_max, self.key_dim)
141
+ decay_logit = torch.log(lam_init / (1.0 - lam_init)) # sigmoid^{-1}
142
+ self.decay = nn.Parameter(decay_logit)
143
+
144
+ # [HFP-CORE] Kubik-flux esnekligi eta (per-kanal, >0). Tek-adim kararli
145
+ # cozumden lam_t = 1/sqrt(1 + 2*eta*s_t^2), s_t = anlik state buyuklugu.
146
+ # Gecis olcegi t* ~ 1/sqrt(2*eta): eta buyuk -> kisa plato, kucuk -> uzun.
147
+ # Kanallar arasi 1e-4..1e-2 log-dagilir -> plato ~7..70 token, ogrenilebilir.
148
+ eta_init = torch.logspace(-4.0, -2.0, self.key_dim)
149
+ self.log_eta = nn.Parameter(torch.log(eta_init))
150
+
151
+ # [HFP-DELTA] per-token yazim siddeti beta (0,1); bias +1 -> ~0.73 baslangic
152
+ self.beta_gate = nn.Linear(hidden_size, 1)
153
+ nn.init.constant_(self.beta_gate.bias, 1.0)
154
+
155
+ self.retrieval_norm = nn.LayerNorm(hidden_size)
156
+ self.landmark_buffer = LandmarkBuffer(max_size=hfp_config.LANDMARK_MAX)
157
+
158
+ def _feat(self, u):
159
+ """[HFP-CAP] Anahtar/sorgu ozellik-haritasi -> (..., key_dim), hep >= 0."""
160
+ if self.key_feature_map == "dpfp":
161
+ u = torch.cat([F.relu(u), F.relu(-u)], dim=-1) # (..., 2H)
162
+ parts = [u * torch.roll(u, shifts=i + 1, dims=-1) for i in range(self.dpfp_nu)]
163
+ return torch.cat(parts, dim=-1) # (..., 2H*nu) >= 0
164
+ return F.elu(u) + 1.0 # (..., H) > 0
165
+
166
+ def get_initial_state(self, batch_size, device, dtype):
167
+ M = torch.zeros(batch_size, self.key_dim, self.hidden_size, device=device, dtype=dtype)
168
+ z = torch.zeros(batch_size, self.key_dim, device=device, dtype=dtype)
169
+ short_memory = torch.zeros(batch_size, self.max_short_len, self.hidden_size, device=device, dtype=dtype)
170
+ # [FIX K8] conv_state: onceki chunk'in son (kernel-1) girdisi (causal conv icin)
171
+ conv_state = torch.zeros(batch_size, self.conv_kernel - 1, self.hidden_size, device=device, dtype=dtype)
172
+ # state: (short_memory, M, z, token_count, short_len_dynamic, write_idx, conv_state)
173
+ return (short_memory, M, z, 0, self.base_short_len, 0, conv_state)
174
+
175
+ def reset_state(self):
176
+ self.landmark_buffer.clear()
177
+ if hasattr(self, "_last_gate"):
178
+ del self._last_gate
179
+ if hasattr(self, "_gate_entropy_live"):
180
+ del self._gate_entropy_live
181
+
182
+ def gate_entropy_loss(self):
183
+ if not hasattr(self, "_last_gate"):
184
+ return torch.tensor(0.0, device=next(self.parameters()).device)
185
+ if hfp_config.ENABLE_ENTROPY_MAP:
186
+ return compute_gate_entropy(self._last_gate) * hfp_config.REG_WEIGHT
187
+ else:
188
+ return torch.tensor(0.0, device=next(self.parameters()).device)
189
+
190
+ def _write_ring_buffer(self, short_memory, x, write_idx):
191
+ """[K6] Vektorize ring-buffer yazimi (eski per-token Python dongusu yerine).
192
+ clone(): detach edilmemis state ile in-place autograd hatasini onler."""
193
+ B, L, H = x.shape
194
+ cap = self.max_short_len
195
+ short_memory = short_memory.clone()
196
+ if L >= cap:
197
+ # yalnizca son 'cap' token buffer'da kalir
198
+ tail = x[:, L - cap:, :]
199
+ idx = (write_idx + (L - cap) + torch.arange(cap, device=x.device)) % cap
200
+ short_memory[:, idx, :] = tail
201
+ else:
202
+ idx = (write_idx + torch.arange(L, device=x.device)) % cap
203
+ short_memory[:, idx, :] = x
204
+ new_write_idx = (write_idx + L) % cap
205
+ return short_memory, new_write_idx
206
+
207
+ def update(self, x, past_state=None, detach_state=True):
208
+ if x.dim() == 2:
209
+ x = x.unsqueeze(1)
210
+ batch_size, seq_len, _ = x.size()
211
+ device = x.device
212
+ dtype = x.dtype
213
+
214
+ if past_state is not None:
215
+ (short_memory, M, z, token_count, short_len_dynamic, write_idx, conv_state) = past_state
216
+ if short_memory is not None and short_memory.size(0) != batch_size:
217
+ (short_memory, M, z, token_count, short_len_dynamic, write_idx, conv_state) = self.get_initial_state(batch_size, device, dtype)
218
+ else:
219
+ (short_memory, M, z, token_count, short_len_dynamic, write_idx, conv_state) = self.get_initial_state(batch_size, device, dtype)
220
+
221
+ # [K2] detach_state artik cagiran tarafindan kontrol edilir (TBPTT icin False).
222
+ if detach_state:
223
+ if short_memory is not None: short_memory = short_memory.detach()
224
+ if M is not None: M = M.detach()
225
+ if z is not None: z = z.detach()
226
+ if conv_state is not None: conv_state = conv_state.detach()
227
+
228
+ # 1. Ring buffer (vektorize)
229
+ short_memory, write_idx = self._write_ring_buffer(short_memory, x, write_idx)
230
+ token_count += seq_len
231
+ active_len = min(token_count, short_len_dynamic)
232
+
233
+ # 2. [FIX K8] Binding conv: Q/K'yi conv'lanmis girdiden hesapla (komsu token
234
+ # karisimi -> anahtar onceki token'i kodlar), V'yi ORIJINAL x'ten (temiz deger).
235
+ kk = self.conv_kernel
236
+ if kk > 1:
237
+ if conv_state is None:
238
+ conv_state = torch.zeros(batch_size, kk - 1, self.hidden_size, device=device, dtype=dtype)
239
+ x_pad = torch.cat([conv_state, x], dim=1) # (B, kk-1+L, H)
240
+ x_qk = self.short_conv(x_pad.transpose(1, 2)).transpose(1, 2) # (B, L, H) causal
241
+ new_conv_state = x_pad[:, x_pad.size(1) - (kk - 1):, :] # son kk-1 girdi
242
+ else:
243
+ x_qk = x
244
+ new_conv_state = conv_state
245
+
246
+ Q = self._feat(self.W_q(x_qk)) # (B,L,key_dim) >= 0 [HFP-CAP]
247
+ K = self._feat(self.W_k(x_qk)) # (B,L,key_dim) >= 0
248
+ V_raw = self.W_v(x) # (B,L,H) temiz deger
249
+
250
+ # 3. Gating (retrieval'dan ONCE: gate'li V hem intra-chunk okumaya
251
+ # hem M guncellemesine girer -> gate gradyan alir)
252
+ gate_logits = self.importance_gate(x) / self.gate_temperature
253
+ gate = torch.sigmoid(self.gate_dropout(gate_logits))
254
+ gate = gate.to(dtype)
255
+ self._last_gate = gate.clone().detach()
256
+ # [C1] Gradyanli gate-entropy - modeling opsiyonel olarak loss'a ekler.
257
+ self._gate_entropy_live = compute_gate_entropy(gate)
258
+
259
+ gate_entropy = None
260
+ if hfp_config.ENABLE_ENTROPY_MAP or hfp_config.ENABLE_DEFECT_FLAG or hfp_config.ENABLE_RYU_TAKAYANAGI:
261
+ gate_entropy = compute_gate_entropy(gate)
262
+
263
+ V = V_raw * gate
264
+
265
+ # 4. Retention recurrence — mod secilir (exp baseline / cubic_flux HFP-core).
266
+ outputs = []
267
+
268
+ if self.write_rule == "delta":
269
+ # [HFP-DELTA] Sirali delta-yazim; decay_mode lam'i belirler (exp/cubic).
270
+ beta = torch.sigmoid(self.beta_gate(x)).to(dtype) # (B,L,1)
271
+ if self.decay_mode == "exp":
272
+ lam_exp = torch.sigmoid(self.decay).to(dtype).unsqueeze(0) # (1,D)
273
+ else:
274
+ eta = torch.exp(self.log_eta).to(dtype).unsqueeze(0) # (1,D)
275
+ for t in range(seq_len):
276
+ kt = K[:, t]; vt = V[:, t]; qt = Q[:, t] # (B,D)/(B,H)
277
+ kn = kt / (kt.norm(dim=-1, keepdim=True) + 1e-6) # ||k||=1
278
+ if self.decay_mode == "exp":
279
+ lam_t = lam_exp
280
+ else:
281
+ lam_t = 1.0 / torch.sqrt(1.0 + 2.0 * eta * z * z) # (B,D)
282
+ Mt = M * lam_t.unsqueeze(-1)
283
+ v_old = torch.einsum('bd,bdh->bh', kn, Mt) # mevcut iliski
284
+ M = Mt + beta[:, t].unsqueeze(-1) * torch.einsum('bd,bh->bdh', kn, vt - v_old)
285
+ z = z * lam_t + kn
286
+ outputs.append(torch.einsum('bd,bdh->bh', qt, M).unsqueeze(1))
287
+ retrieved = torch.cat(outputs, dim=1) # (B,L,H)
288
+
289
+ elif self.decay_mode == "cubic_flux":
290
+ # [HFP-CORE] Makalenin dth/dtau = -eta*th^3 kubik akisinin birebir
291
+ # ayriklastirmasi. Tek-adim kararli cozum -> per-kanal decay faktoru:
292
+ # lam_t = 1/sqrt(1 + 2*eta*z_{t-1}^2) (z = anahtar-akumulatoru, per-kanal)
293
+ # M_t = lam_t (.) M_{t-1} + k_t v_t^T ; z_t = lam_t (.) z_{t-1} + k_t
294
+ # out_t = (q_t M_t)/(q_t . z_t) (causal-inclusive, kendi KV dahil)
295
+ # NOT: decay M'in degil Z'nin (anahtar kutlesi) buyuklugune baglidir.
296
+ # z bos iken lam~1 (PLATO, unutma yok); z buyudukce lam<1 (aktif, buyukluge
297
+ # bagli unutma) -> plato + power-law kuyruk. Kendini-sinirlayan: decay
298
+ # buyuklukle arttigindan state patlamaz. Sirali (O(L)); mod default degil.
299
+ # Saf recurrence oldugundan chunk-tutarli (full == state-tasiyan chunked).
300
+ eta = torch.exp(self.log_eta).to(dtype).unsqueeze(0) # (1,H) > 0
301
+ for t in range(seq_len):
302
+ kt = K[:, t]; vt = V[:, t]; qt = Q[:, t] # (B,H)
303
+ lam_t = 1.0 / torch.sqrt(1.0 + 2.0 * eta * z * z) # (B,H)
304
+ M = M * lam_t.unsqueeze(-1) + torch.einsum('bh,bg->bhg', kt, vt)
305
+ z = z * lam_t + kt
306
+ num = torch.einsum('bh,bhg->bg', qt, M) # (B,H)
307
+ den = (qt * z).sum(-1, keepdim=True) + 1e-6 # (B,1)
308
+ outputs.append((num / den).unsqueeze(1)) # (B,1,H)
309
+ retrieved = torch.cat(outputs, dim=1) # (B,L,H)
310
+
311
+ elif self.decay_mode == "cubic_flux_chunked":
312
+ # [HFP-SCALE] cubic_flux'in IKI-GECISLI TAM paralel formu (yaklasim DEGIL).
313
+ # Gozlem: lam_t yalnizca z_{t-1}'e baglidir ve z'nin recurrence'i M'siz,
314
+ # elementwise-ucuzdur. O halde:
315
+ # GECIS 1: z-taramasi (sirali ama per-adim O(B*D) elementwise) ->
316
+ # per-token lam_t TAM olarak bilinir.
317
+ # GECIS 2: lam_t bilindiginde M-recurrence, GLA/Mamba2-tarzi
318
+ # chunkwise-paralel cozulur (log-uzayda kumulatif carpim;
319
+ # tum katsayilar <= 1 -> stabil).
320
+ # Sonuc her rec_block icin sirali cubic_flux ile birebir aynidir
321
+ # (bkz. review_scripts/scaling_checks.py); rec_block yalnizca hiz/bellek
322
+ # dengesidir. Bellek: intra-blok tensoru (B,m,m,key_dim).
323
+ eta = torch.exp(self.log_eta).to(dtype).unsqueeze(0) # (1,D)
324
+ lam_list = []
325
+ z_run = z
326
+ for t in range(seq_len): # GECIS 1 (ucuz)
327
+ lam_t = 1.0 / torch.sqrt(1.0 + 2.0 * eta * z_run * z_run) # (B,D)
328
+ lam_list.append(lam_t)
329
+ z_run = z_run * lam_t + K[:, t]
330
+ lam_seq = torch.stack(lam_list, dim=1) # (B,L,D)
331
+ loglam = torch.log(lam_seq.clamp_min(1e-12))
332
+
333
+ for s0 in range(0, seq_len, self.rec_block): # GECIS 2
334
+ Qb = Q[:, s0:s0 + self.rec_block]
335
+ Kb = K[:, s0:s0 + self.rec_block]
336
+ Vb = V[:, s0:s0 + self.rec_block]
337
+ m = Qb.size(1)
338
+ cs = torch.cumsum(loglam[:, s0:s0 + m], dim=1) # (B,m,D): log A_i, A_i = prod_{j<=i} lam_j
339
+ A = torch.exp(cs) # (B,m,D) <= 1
340
+
341
+ # cross-block: M_0/z_0 katkisi A_i ile soner
342
+ Q_dec = Qb * A # (B,m,D)
343
+ num_cross = torch.bmm(Q_dec, M) # (B,m,H)
344
+ den_cross = (Q_dec * z.unsqueeze(1)).sum(-1) # (B,m)
345
+
346
+ # intra-blok: pair (i,j<=i) katsayisi prod_{s=j+1..i} lam_s = exp(cs_i - cs_j) <= 1
347
+ ii = torch.arange(m, device=device).view(m, 1)
348
+ jj = torch.arange(m, device=device).view(1, m)
349
+ causal = (ii >= jj).to(dtype) # (m,m)
350
+ Dm = torch.exp(cs.unsqueeze(2) - cs.unsqueeze(1)) # (B,m,m,D): exp(cs_i - cs_j)
351
+ Dm = Dm * causal.view(1, m, m, 1)
352
+
353
+ S = torch.einsum('bih,bijh,bjh->bij', Qb, Dm, Kb) # (B,m,m)
354
+ num_intra = torch.bmm(S, Vb) # (B,m,H)
355
+ den_intra = S.sum(dim=2) # (B,m)
356
+
357
+ den = (den_cross + den_intra + 1e-6).unsqueeze(-1)
358
+ outputs.append((num_cross + num_intra) / den)
359
+
360
+ # state guncelle (blok sonu): A_m = tum blok carpimi
361
+ A_m = A[:, -1] # (B,D)
362
+ K_dec = Kb * torch.exp(cs[:, -1:] - cs) # (B,m,D): prod_{s=j+1..m}
363
+ M = M * A_m.unsqueeze(-1) + torch.bmm(K_dec.transpose(1, 2), Vb)
364
+ z = z * A_m + K_dec.sum(dim=1)
365
+ retrieved = torch.cat(outputs, dim=1) # (B,L,H)
366
+
367
+ else:
368
+ # [K2] exp mod: paralel chunkwise (per-token geometrik decay, causal-inclusive)
369
+ lam = torch.sigmoid(self.decay).to(dtype) # (H,), 0..1
370
+ for s in range(0, seq_len, self.rec_block):
371
+ Qb = Q[:, s:s + self.rec_block]
372
+ Kb = K[:, s:s + self.rec_block]
373
+ Vb = V[:, s:s + self.rec_block]
374
+ m = Qb.size(1)
375
+
376
+ p = torch.arange(1, m + 1, device=device, dtype=dtype) # 1..m
377
+ lam_i = lam.unsqueeze(0).pow(p.unsqueeze(1)) # (m,H): lam^i
378
+ lam_rev = lam.unsqueeze(0).pow((m - p).unsqueeze(1)) # (m,H): lam^{m-i}
379
+
380
+ # cross-block: eski state'ten oku
381
+ Q_dec = Qb * lam_i.unsqueeze(0) # (B,m,H)
382
+ num_cross = torch.bmm(Q_dec, M) # (B,m,H)
383
+ den_cross = (Q_dec * z.unsqueeze(1)).sum(-1) # (B,m)
384
+
385
+ # intra-block: D_ij = lam^{i-j} (i>=j), tum usler >= 0 -> stabil
386
+ ii = torch.arange(m, device=device).view(m, 1)
387
+ jj = torch.arange(m, device=device).view(1, m)
388
+ e = (ii - jj).clamp_min(0).to(dtype) # (m,m)
389
+ causal = (ii >= jj).to(dtype)
390
+ D = lam.view(1, 1, -1).pow(e.unsqueeze(-1)) * causal.unsqueeze(-1) # (m,m,H)
391
+
392
+ S = torch.einsum('bih,ijh,bjh->bij', Qb, D, Kb) # (B,m,m)
393
+ num_intra = torch.bmm(S, Vb) # (B,m,H)
394
+ den_intra = S.sum(dim=2) # (B,m) > 0 (Q,K>0)
395
+
396
+ den = (den_cross + den_intra + 1e-6).unsqueeze(-1)
397
+ outputs.append((num_cross + num_intra) / den)
398
+
399
+ # state guncelle (blok sonu)
400
+ lam_m = lam.pow(float(m))
401
+ K_dec = Kb * lam_rev.unsqueeze(0)
402
+ M = M * lam_m.view(1, -1, 1) + torch.bmm(K_dec.transpose(1, 2), Vb)
403
+ z = z * lam_m.view(1, -1) + K_dec.sum(dim=1)
404
+ retrieved = torch.cat(outputs, dim=1) # (B,L,H)
405
+
406
+ retrieved_memory = self.retrieval_norm(retrieved) # (B,L,H)
407
+
408
+ # 5. Dynamic Context Windowing & Landmarks (opsiyonel teshis yollari)
409
+ if gate_entropy is not None:
410
+ if gate_entropy < self.dynamic_short_thresh and short_len_dynamic < self.max_short_len:
411
+ short_len_dynamic = min(short_len_dynamic + 4, self.max_short_len)
412
+
413
+ if hfp_config.ENABLE_DEFECT_FLAG:
414
+ coherence = None
415
+ if hfp_config.ENABLE_COHERENCE:
416
+ coherence = coherence_score(short_memory)
417
+ if gate_entropy is not None and coherence is not None:
418
+ priority = coherence.item() * gate_entropy.item()
419
+ else:
420
+ priority = gate.mean().item()
421
+ self.landmark_buffer.push(priority, x.mean(dim=1))
422
+
423
+ new_past_state = (short_memory, M, z, token_count, short_len_dynamic, write_idx, new_conv_state)
424
+
425
+ active_short_view = short_memory[:, :active_len, :]
426
+ return active_short_view, retrieved_memory, new_past_state
hfp_config.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import dataclasses
18
+
19
+ @dataclasses.dataclass
20
+ class HFPConfig:
21
+ """Feature flags and hyper-parameters for optional physics-inspired analogues.
22
+
23
+ All flags are *disabled* by default to keep the baseline model clean, fast
24
+ and honest: these physics-inspired aux terms are experimental hooks, NOT
25
+ load-bearing parts of the trained model. Enable one only to *test* whether
26
+ it adds value; when off, no wasted compute and no false "physics" claim.
27
+ (Onceki surumde hepsi True idi ama modeling bunlari loss'a hic baglamiyordu
28
+ -> olu hesap. Durust baseline icin kapatildi; ilham olarak deneye acik kalir.)
29
+ """
30
+ # Feature toggles - deneysel, default kapali (opt-in)
31
+ ENABLE_CURVATURE: bool = False
32
+ ENABLE_ENTROPY_MAP: bool = False
33
+ ENABLE_DEFECT_FLAG: bool = False
34
+ ENABLE_COHERENCE: bool = False
35
+ ENABLE_CONSERVATION: bool = False
36
+ ENABLE_RYU_TAKAYANAGI: bool = False
37
+ ENABLE_5D_CURVATURE: bool = False
38
+
39
+ # Hyper-parameters (used when the feature is enabled)
40
+ REG_WEIGHT: float = 0.01 # gate-entropy regularisation weight
41
+ LANDMARK_MAX: int = 49 # max entries in landmark buffer
42
+ ENTROPY_THRESH: float = 0.25 # threshold for dynamic short-memory expansion
43
+ MAX_SHORT_LEN: int = 32 # maximum short-memory length (tokens)
44
+ GRAD_CLIP_VAL: float = 0.5 # gradient-clipping value per memory block
45
+ MIXED_PRECISION: bool = True # use torch.float16 for gate logits only
46
+ WARP_K: float = 0.5 # Witten propagator warp factor
47
+
48
+ # Global singleton configuration used throughout the package
49
+ config = HFPConfig()
hfp_utils.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import heapq
18
+ import torch
19
+
20
+ def compute_gate_entropy(gate_tensor):
21
+ """Compute entropy of gate probabilities.
22
+ gate_tensor is expected to be in [0,1] range (after sigmoid).
23
+ Returns scalar tensor (float). DIFFERENTIABLE.
24
+ """
25
+ eps = 1e-8
26
+ p = torch.clamp(gate_tensor, min=eps, max=1 - eps)
27
+ entropy = - (p * torch.log(p) + (1 - p) * torch.log(1 - p))
28
+ return entropy.mean()
29
+
30
+ class LandmarkBuffer:
31
+ """Priority buffer that keeps the top-k token summaries based on gate strength.
32
+ Uses a min-heap of size max_size; lower strengths are popped.
33
+ """
34
+ def __init__(self, max_size=49):
35
+ self.max_size = max_size
36
+ self.heap = [] # each entry: (strength, counter, tensor)
37
+ self.counter = 0
38
+
39
+ def clear(self):
40
+ self.heap.clear()
41
+ self.counter = 0
42
+
43
+ def push(self, strength, token_summary):
44
+ entry = (strength, self.counter, token_summary.clone().detach())
45
+ self.counter += 1
46
+ if len(self.heap) < self.max_size:
47
+ heapq.heappush(self.heap, entry)
48
+ else:
49
+ if strength > self.heap[0][0]:
50
+ heapq.heapreplace(self.heap, entry)
51
+
52
+ def get_buffer(self):
53
+ """Return a tensor of stacked token summaries sorted by strength descending."""
54
+ if not self.heap:
55
+ return None
56
+ sorted_entries = sorted(self.heap, key=lambda e: e[0], reverse=True)
57
+ tensors = [e[2] for e in sorted_entries]
58
+ return torch.stack(tensors, dim=1) # shape: (batch, slots, hidden)
59
+
60
+ def compute_curvature(vector: torch.Tensor) -> torch.Tensor:
61
+ """Discrete geometric curvature via second-order finite differences across time.
62
+ vector shape: (batch, seq_len, hidden_dim).
63
+ NOT: kaynak tensor detach edilmisse gradyan tasimaz; regularizer olarak kullanilacaksa
64
+ gradyanli bir tensore (or. katman girisi) uygulanmalidir.
65
+ """
66
+ if vector.size(1) < 3:
67
+ return torch.tensor(0.0, device=vector.device)
68
+ second_deriv = vector[:, 2:, :] - 2 * vector[:, 1:-1, :] + vector[:, :-2, :]
69
+ return torch.norm(second_deriv, dim=-1).mean()
70
+
71
+ def compute_entropy_map(gates: torch.Tensor) -> torch.Tensor:
72
+ """Per-gate entropy map, shape (batch, seq_len)."""
73
+ eps = 1e-8
74
+ p = torch.clamp(gates, min=eps, max=1 - eps)
75
+ entropy = - (p * torch.log(p) + (1 - p) * torch.log(1 - p))
76
+ return entropy.mean(dim=-1)
77
+
78
+ def magnitude_defect_flag(vector: torch.Tensor, threshold: float = 1.0) -> torch.Tensor:
79
+ """[DIAGNOSTIC ONLY - NON-DIFFERENTIABLE] norm(vector) > threshold.
80
+ Bir '>' karsilastirmasi -> gradyan TASIMAZ. Loss olarak kullanmayin; teshis metrigidir.
81
+ """
82
+ norm = torch.norm(vector, dim=-1)
83
+ return (norm > threshold).float()
84
+
85
+ def coherence_score(memory_states: torch.Tensor) -> torch.Tensor:
86
+ """Average cosine similarity between consecutive memory states along the sequence dim.
87
+ Returns a scalar tensor.
88
+ """
89
+ if memory_states.size(1) < 2:
90
+ return torch.tensor(0.0, device=memory_states.device)
91
+ sims = torch.nn.functional.cosine_similarity(
92
+ memory_states[:, :-1, :], memory_states[:, 1:, :], dim=-1
93
+ )
94
+ return sims.mean()
95
+
96
+ def conservation_check(state: torch.Tensor) -> bool:
97
+ """[DIAGNOSTIC ONLY - NON-DIFFERENTIABLE] Python bool dondurur -> gradyan TASIMAZ.
98
+ Temporal 'korunum' teshisi: gizli boyuttaki toplam zaman icinde suruklenmiyor mu?
99
+ Loss olarak kullanmayin; yalnizca izleme metrigidir. state shape: (batch, seq_len, hidden)
100
+ """
101
+ if state.size(1) < 2:
102
+ return True
103
+ eps = 1e-2
104
+ temporal_sum = state.sum(dim=-1)
105
+ drift = torch.abs(temporal_sum[:, 1:] - temporal_sum[:, :-1])
106
+ return torch.all(drift < eps).item()
107
+
108
+ def holographic_information_bound(entropy_val: torch.Tensor, memory_matrix: torch.Tensor) -> torch.Tensor:
109
+ """Holographic Information Bound (V2.1): soft penalty ensuring current attention entropy
110
+ does not exceed the Frobenius-norm capacity of the [hidden, hidden] memory matrix.
111
+ DIFFERENTIABLE (softplus).
112
+ """
113
+ matrix_capacity = torch.linalg.matrix_norm(memory_matrix, ord='fro', dim=(-2, -1)).mean()
114
+ ratio = entropy_val / (matrix_capacity + 1e-8)
115
+ bound_violation = torch.nn.functional.softplus(ratio - 1.0)
116
+ return bound_violation
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:91261fe89cfc09c74dfe52b94dfe88d80d77e4f3d6cc254f0eea62c85e0ccd3b
3
+ size 436820144
modeling_hfp.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hyper Flux Projection (HFP) — O(1)-memory causal language model
2
+ # Copyright (C) 2026 Kayrahan Yılmaz
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU Affero General Public License as published
6
+ # by the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU Affero General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Affero General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+ import torch
18
+ import torch.nn as nn
19
+ import math
20
+ from transformers import PreTrainedModel
21
+ from transformers.modeling_outputs import CausalLMOutputWithPast, BaseModelOutputWithPast
22
+ from .configuration_hfp import HFPConfig
23
+
24
+ from .hfp_bulk_state import HFPBulkState
25
+ from .bulk_trigger_decoder import BulkTriggerDecoderLayer
26
+
27
+ class SinusoidalPositionalEncoding(nn.Module):
28
+ def __init__(self, hidden_size, max_len=5000, pe_scale=0.3):
29
+ super().__init__()
30
+ self.max_len = max_len
31
+ # [FIX K7] PE olcegi. Onceden ham (norm=sqrt(d/2)=8) eklenirken embedding
32
+ # normu 0.02*sqrt(d)=0.23 idi -> PE, token icerigini ~35x BOGUYORDU;
33
+ # anahtar/deger'ler ~%97 pozisyon oluyor, icerik-tabanli recall imkansiz
34
+ # (MQAR loss ln(val_space)'te sabitlenip binding hic ogrenilmiyordu).
35
+ # embed *sqrt(d) (bkz. HFPModel) + PE *0.3 ile normlar dengelenir.
36
+ self.pe_scale = pe_scale
37
+ pe = torch.zeros(max_len, hidden_size)
38
+ position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
39
+ div_term = torch.exp(torch.arange(0, hidden_size, 2).float() * (-math.log(10000.0) / hidden_size))
40
+ pe[:, 0::2] = torch.sin(position * div_term)
41
+ pe[:, 1::2] = torch.cos(position * div_term)
42
+ self.register_buffer('pe', pe.unsqueeze(0))
43
+
44
+ def forward(self, x, offset: int = 0):
45
+ # [FIX A2] Streaming/chunked prefill'de her chunk'a 0..L degil, GLOBAL pozisyon eklenir.
46
+ seq_len = x.size(1)
47
+ if offset + seq_len > self.max_len:
48
+ offset = max(0, self.max_len - seq_len)
49
+ return x + self.pe_scale * self.pe[:, offset:offset + seq_len, :].to(x.device)
50
+
51
+ class HFPPreTrainedModel(PreTrainedModel):
52
+ config_class = HFPConfig
53
+ base_model_prefix = "hfp"
54
+ _supports_cache_class = False
55
+
56
+ def _init_weights(self, module):
57
+ if isinstance(module, nn.Linear):
58
+ module.weight.data.normal_(mean=0.0, std=0.02)
59
+ if module.bias is not None:
60
+ # importance_gate bias'i bilerek -2.0 (gate-collapse onlemi); ezme.
61
+ if torch.all(module.bias.data == -2.0):
62
+ pass
63
+ else:
64
+ module.bias.data.zero_()
65
+ elif isinstance(module, nn.Embedding):
66
+ module.weight.data.normal_(mean=0.0, std=0.02)
67
+ if module.padding_idx is not None:
68
+ module.weight.data[module.padding_idx].zero_()
69
+ elif isinstance(module, nn.LayerNorm):
70
+ module.bias.data.zero_()
71
+ module.weight.data.fill_(1.0)
72
+
73
+ class HFPModel(HFPPreTrainedModel):
74
+ def __init__(self, config):
75
+ super().__init__(config)
76
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
77
+ # [FIX K7] Vaswani sqrt(d) olcegi: emb (init std 0.02) tek basina norm~0.23;
78
+ # sqrt(d) ile ~2.56'ya cikar ve sonuchennmus PE (*0.3, norm~2.4) ile dengelenir.
79
+ self.embed_scale = math.sqrt(config.hidden_size)
80
+ self.pos_encoder = SinusoidalPositionalEncoding(
81
+ config.hidden_size, max_len=config.max_position_embeddings,
82
+ pe_scale=getattr(config, "pe_scale", 0.3))
83
+
84
+ self.layers = nn.ModuleList([
85
+ BulkTriggerDecoderLayer(
86
+ hidden_size=config.hidden_size,
87
+ num_heads=config.num_attention_heads,
88
+ feedforward_dim=config.intermediate_size,
89
+ bulk_dim=config.bulk_dim,
90
+ vocab_size=None,
91
+ local_window=getattr(config, "local_window", None), # [FIX K5]
92
+ dropout_p=getattr(config, "dropout_p", 0.1), # [FIX K3]
93
+ ffn_type=getattr(config, "ffn_type", "entangled") # [HFP-SCALE]
94
+ )
95
+ for _ in range(config.num_hidden_layers)
96
+ ])
97
+
98
+ # Katman-basi recurrent bellek (physics-inspired 'Bulk' analojisi;
99
+ # teknik olarak: decay'li lineer-attention state'i M, z)
100
+ # [TEMIZLIK B1] medium_freq/long_freq/medium_momentum kaldirildi.
101
+ self.bulk_states = nn.ModuleList([
102
+ HFPBulkState(
103
+ hidden_size=config.hidden_size,
104
+ short_len=config.short_len,
105
+ max_short_len=getattr(config, "max_short_len", None), # [FIX K4]
106
+ rec_block=getattr(config, "rec_block", 64), # [K2]
107
+ decay_mode=getattr(config, "decay_mode", "exp"), # [HFP-CORE]
108
+ conv_kernel=getattr(config, "conv_kernel", 3), # [FIX K8] binding
109
+ key_feature_map=getattr(config, "key_feature_map", "elu"), # [HFP-CAP]
110
+ dpfp_nu=getattr(config, "dpfp_nu", 2), # [HFP-CAP]
111
+ write_rule=getattr(config, "write_rule", "additive") # [HFP-DELTA]
112
+ )
113
+ for _ in range(config.num_hidden_layers)
114
+ ])
115
+ # [K2] TBPTT: True ise chunk'lar arasi state detach edilmez
116
+ self._detach_state = not getattr(config, "bptt_across_chunks", False)
117
+
118
+ self.norm = nn.LayerNorm(config.hidden_size)
119
+ self.post_init()
120
+
121
+ @staticmethod
122
+ def _offset_from_state(past_key_values_list):
123
+ # state tuple: (short_memory, M, z, token_count, short_len_dynamic, write_idx, conv_state)
124
+ first = past_key_values_list[0]
125
+ if first is not None and len(first) >= 4 and isinstance(first[3], int):
126
+ return int(first[3])
127
+ return 0
128
+
129
+ def forward(self, input_ids, attention_mask=None, past_key_values=None, use_cache=False, **kwargs):
130
+ x = self.embed_tokens(input_ids) * self.embed_scale # [FIX K7]
131
+
132
+ if past_key_values is None or not isinstance(past_key_values, (tuple, list)):
133
+ past_key_values_list = [None] * len(self.layers)
134
+ else:
135
+ past_key_values_list = past_key_values
136
+
137
+ # [FIX A2] Global pozisyon offseti (chunked prefill icin)
138
+ offset = self._offset_from_state(past_key_values_list)
139
+ x = self.pos_encoder(x, offset=offset)
140
+
141
+ new_past_key_values = []
142
+ gate_entropies = []
143
+ for i, (layer, bulk_state) in enumerate(zip(self.layers, self.bulk_states)):
144
+ x, _, new_past_state = layer(x, bulk_state, past_state=past_key_values_list[i],
145
+ return_past_state=True, detach_state=self._detach_state)
146
+
147
+ # [C1] Gradyanli gate-entropy topla (yalnizca agirlik > 0 iken loss'a katilir)
148
+ if self.training and getattr(bulk_state, "_gate_entropy_live", None) is not None:
149
+ gate_entropies.append(bulk_state._gate_entropy_live)
150
+
151
+ if use_cache:
152
+ new_past_key_values.append(new_past_state)
153
+
154
+ x = self.norm(x)
155
+
156
+ out = BaseModelOutputWithPast(
157
+ last_hidden_state=x,
158
+ past_key_values=new_past_key_values if use_cache else None
159
+ )
160
+ out.gate_entropy = (torch.stack(gate_entropies).mean() if gate_entropies else None)
161
+ return out
162
+
163
+ from transformers.generation import GenerationMixin
164
+
165
+ class HFPForCausalLM(HFPPreTrainedModel, GenerationMixin):
166
+ # [D1] lm_head, embed_tokens'a bagli (weight tying) — safetensors kaydinin
167
+ # paylasilan tensoru dogru ele almasi icin bildirilmeli.
168
+ # transformers v5: dict (hedef -> kaynak); v4'te de sorunsuz calisir.
169
+ _tied_weights_keys = {"lm_head.weight": "hfp.embed_tokens.weight"}
170
+
171
+ def __init__(self, config):
172
+ super().__init__(config)
173
+ self.hfp = HFPModel(config)
174
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
175
+ # [D1] Weight tying (GPT standardi): embedding ve lm_head paylasimi
176
+ self.lm_head.weight = self.hfp.embed_tokens.weight
177
+ self.post_init()
178
+
179
+ # [D1] tie_weights()'in from_pretrained SONRASI baglantiyi yeniden kurabilmesi
180
+ # icin standart erisimciler (bunlarsiz yukleme tying'i sessizce koparir).
181
+ def get_input_embeddings(self):
182
+ return self.hfp.embed_tokens
183
+
184
+ def set_input_embeddings(self, value):
185
+ self.hfp.embed_tokens = value
186
+
187
+ def get_output_embeddings(self):
188
+ return self.lm_head
189
+
190
+ def set_output_embeddings(self, value):
191
+ self.lm_head = value
192
+
193
+ def forward(self, input_ids, attention_mask=None, labels=None, past_key_values=None, use_cache=False, **kwargs):
194
+ outputs = self.hfp(input_ids, attention_mask=attention_mask, past_key_values=past_key_values, use_cache=use_cache, **kwargs)
195
+ hidden_states = outputs.last_hidden_state
196
+ logits = self.lm_head(hidden_states)
197
+
198
+ loss = None
199
+ if labels is not None:
200
+ shift_logits = logits[..., :-1, :].contiguous()
201
+ shift_labels = labels[..., 1:].contiguous()
202
+ loss_fct = nn.CrossEntropyLoss()
203
+ loss = loss_fct(shift_logits.view(-1, self.config.vocab_size), shift_labels.view(-1))
204
+
205
+ # [C1] Opsiyonel gate-entropy duzenleyici - default kapali (weight=0.0).
206
+ w = float(getattr(self.config, "aux_gate_entropy_weight", 0.0))
207
+ if w > 0.0 and getattr(outputs, "gate_entropy", None) is not None:
208
+ loss = loss + w * outputs.gate_entropy
209
+
210
+ # [ORTHO] EntangledFFN ortogonallik duzenleyicisi. Paylasilan W_bulk'tan
211
+ # turetilen P_A/P_B'nin farkli ("tek bulk'in iki ayri golgesi") kalmasi
212
+ # icin baski. Onceden implement edilmis ama loss'a HIC bagli degildi
213
+ # (olu kod); artik opsiyonel + default kapali (weight=0.0 => baseline degismez).
214
+ w_o = float(getattr(self.config, "aux_ortho_weight", 0.0))
215
+ if w_o > 0.0:
216
+ ortho = sum(layer.ffn.get_orthogonality_loss() for layer in self.hfp.layers)
217
+ loss = loss + w_o * ortho
218
+
219
+ return CausalLMOutputWithPast(
220
+ loss=loss,
221
+ logits=logits,
222
+ past_key_values=outputs.past_key_values
223
+ )
224
+
225
+ def prepare_inputs_for_generation(self, input_ids, past_key_values=None, **kwargs):
226
+ if past_key_values:
227
+ input_ids = input_ids[:, -1:]
228
+ return {
229
+ "input_ids": input_ids,
230
+ "past_key_values": past_key_values,
231
+ "use_cache": kwargs.get("use_cache", True)
232
+ }