Text Generation
Transformers
Safetensors
PyTorch
English
hfp
causal-lm
linear-attention
long-context
recurrent-memory
o1-memory
custom_code
Instructions to use kayrahan35/HFP-O1-Memory-Model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use kayrahan35/HFP-O1-Memory-Model with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="kayrahan35/HFP-O1-Memory-Model", trust_remote_code=True)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("kayrahan35/HFP-O1-Memory-Model", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use kayrahan35/HFP-O1-Memory-Model with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "kayrahan35/HFP-O1-Memory-Model" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "kayrahan35/HFP-O1-Memory-Model", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/kayrahan35/HFP-O1-Memory-Model
- SGLang
How to use kayrahan35/HFP-O1-Memory-Model with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "kayrahan35/HFP-O1-Memory-Model" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "kayrahan35/HFP-O1-Memory-Model", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "kayrahan35/HFP-O1-Memory-Model" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "kayrahan35/HFP-O1-Memory-Model", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use kayrahan35/HFP-O1-Memory-Model with Docker Model Runner:
docker model run hf.co/kayrahan35/HFP-O1-Memory-Model
Upload 11 files
Browse files- .gitattributes +1 -0
- README.md +103 -0
- bulk_trigger_decoder.py +264 -0
- config.json +40 -0
- configuration_hfp.py +107 -0
- generation_config.json +8 -0
- hfp_bulk_state.py +426 -0
- hfp_config.py +49 -0
- hfp_utils.py +116 -0
- model.safetensors +3 -0
- modeling_hfp.py +232 -0
.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 |
+
}
|