Text Generation
Transformers
Safetensors
English
kent
recurrent
linear-time
frequency-domain
dct
custom_code
fp16
base
Instructions to use Vi-LAB/KenT-30M-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Vi-LAB/KenT-30M-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Vi-LAB/KenT-30M-Base", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Vi-LAB/KenT-30M-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Vi-LAB/KenT-30M-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Vi-LAB/KenT-30M-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Vi-LAB/KenT-30M-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/Vi-LAB/KenT-30M-Base
- SGLang
How to use Vi-LAB/KenT-30M-Base 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 "Vi-LAB/KenT-30M-Base" \ --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": "Vi-LAB/KenT-30M-Base", "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 "Vi-LAB/KenT-30M-Base" \ --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": "Vi-LAB/KenT-30M-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use Vi-LAB/KenT-30M-Base with Docker Model Runner:
docker model run hf.co/Vi-LAB/KenT-30M-Base
Upload 3 files
Browse files- README.md +11 -11
- config.json +1 -0
- model.py +69 -23
README.md
CHANGED
|
@@ -14,26 +14,24 @@ tags:
|
|
| 14 |
- custom_code
|
| 15 |
- fp16
|
| 16 |
- base
|
| 17 |
-
datasets:
|
| 18 |
-
- wikimedia/wikipedia
|
| 19 |
-
- HuggingFaceFW/fineweb-edu
|
| 20 |
---
|
| 21 |
|
| 22 |
# KenT-30M-Base
|
| 23 |
|
| 24 |
-
KenT is a recurrent language model. This ~30M-parameter version stacks 24 identical layers;
|
| 25 |
-
|
| 26 |
-
and keeps a learned-forgetting memory (EMA)
|
|
|
|
| 27 |
|
| 28 |
> This repo contains `trust_remote_code` code; weights are stored in **FP16**.
|
| 29 |
|
| 30 |
## Layer
|
| 31 |
|
| 32 |
```
|
| 33 |
-
Z = ResProj_in(Norm(X)) # n -> M x d
|
| 34 |
Z = Z + SwiGLU(DCT_M(RMSNorm(Z))) # WNN block: fixed DCT-II over the M axis, SwiGLU over the d axis
|
| 35 |
-
H_t = (1 -
|
| 36 |
-
X' = X + ResProj_out(Norm(H_t))
|
| 37 |
```
|
| 38 |
|
| 39 |
| | value |
|
|
@@ -42,7 +40,9 @@ X' = X + ResProj_out(Norm(H_t)) # M x d -> n
|
|
| 42 |
| layers | 24 |
|
| 43 |
| resolution `M` x features `d` | 12 x 96 (M·d = 1152 = 4.5n) |
|
| 44 |
| SwiGLU hidden | 384 (4d) |
|
| 45 |
-
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
## Quickstart
|
| 48 |
|
|
@@ -66,4 +66,4 @@ Long documents: `python infer.py --model ./KenT-30M-Base --prompt-file doc.txt -
|
|
| 66 |
## Notes
|
| 67 |
|
| 68 |
- Research model, trained from scratch; evaluate before real-world use.
|
| 69 |
-
- The tokenizer and weights must match `vocab_size` in `config.json`.
|
|
|
|
| 14 |
- custom_code
|
| 15 |
- fp16
|
| 16 |
- base
|
|
|
|
|
|
|
|
|
|
| 17 |
---
|
| 18 |
|
| 19 |
# KenT-30M-Base
|
| 20 |
|
| 21 |
+
KenT is a recurrent language model. This ~30M-parameter version reads **one token per step** and stacks 24 identical layers;
|
| 22 |
+
each layer expands the token vector into `M` resolution positions, mixes them with a fixed DCT-II, transforms the features
|
| 23 |
+
with a SwiGLU, and keeps a learned-forgetting memory (EMA) whose decay is a learned **matrix** (one coefficient per
|
| 24 |
+
resolution position and feature). The memory is read back through a DCT-II and projected to the token dimension.
|
| 25 |
|
| 26 |
> This repo contains `trust_remote_code` code; weights are stored in **FP16**.
|
| 27 |
|
| 28 |
## Layer
|
| 29 |
|
| 30 |
```
|
| 31 |
+
Z = ResProj_in(Norm(X)) # 1 -> M: token vector n -> M x d
|
| 32 |
Z = Z + SwiGLU(DCT_M(RMSNorm(Z))) # WNN block: fixed DCT-II over the M axis, SwiGLU over the d axis
|
| 33 |
+
H_t = (1 - A) * H_{t-1} + A * Z_t # EMA Learner Matrix: A = sigmoid(logits), shape M x d, per layer
|
| 34 |
+
X' = X + ResProj_out(DCT_M(Norm(H_t))) # DCT-II Proj, then M -> 1; residual with the layer input
|
| 35 |
```
|
| 36 |
|
| 37 |
| | value |
|
|
|
|
| 40 |
| layers | 24 |
|
| 41 |
| resolution `M` x features `d` | 12 x 96 (M·d = 1152 = 4.5n) |
|
| 42 |
| SwiGLU hidden | 384 (4d) |
|
| 43 |
+
| EMA decay | learned matrix `(12, 96)` per layer (`ema_per_feature=false` -> vector `(12,)`) |
|
| 44 |
+
| recurrent state | `H`: `(12, 96)` per layer, constant size |
|
| 45 |
+
| parameters | ~29.75M (embedding 12.9M + layers 16.9M) |
|
| 46 |
|
| 47 |
## Quickstart
|
| 48 |
|
|
|
|
| 66 |
## Notes
|
| 67 |
|
| 68 |
- Research model, trained from scratch; evaluate before real-world use.
|
| 69 |
+
- The tokenizer and weights must match `vocab_size` in `config.json`.
|
config.json
CHANGED
|
@@ -26,6 +26,7 @@
|
|
| 26 |
"dtype": "float16",
|
| 27 |
"ema_alpha_first": 0.5,
|
| 28 |
"ema_alpha_last": 0.01,
|
|
|
|
| 29 |
"ema_block_size": 128,
|
| 30 |
"use_gradient_checkpointing": false
|
| 31 |
}
|
|
|
|
| 26 |
"dtype": "float16",
|
| 27 |
"ema_alpha_first": 0.5,
|
| 28 |
"ema_alpha_last": 0.01,
|
| 29 |
+
"ema_per_feature": true,
|
| 30 |
"ema_block_size": 128,
|
| 31 |
"use_gradient_checkpointing": false
|
| 32 |
}
|
model.py
CHANGED
|
@@ -1,24 +1,25 @@
|
|
| 1 |
# coding=utf-8
|
| 2 |
"""KenT: kiến trúc hồi quy hai luồng (representation X_t / temporal-memory H_t).
|
| 3 |
|
| 4 |
-
Mỗi
|
|
|
|
| 5 |
|
| 6 |
-
Z = ResProj_in(Norm_X(X)) #
|
| 7 |
Z = Z + SwiGLU( DCT_M( RMSNorm(Z) ) ) # WNN Block: DCT-II cố định trên trục M, SwiGLU trên trục d, skip quanh cả cụm
|
| 8 |
-
H_t = (1 -
|
| 9 |
-
X' = X + ResProj_out(Norm_H(H_t))
|
| 10 |
|
| 11 |
Mỗi layer xếp K = `num_wnn_blocks` WNN Block nối tiếp (mặc định K = 1, đúng sơ đồ); độ sâu đến từ việc xếp chồng
|
| 12 |
-
nhiều layer ("xN" trong sơ đồ).
|
| 13 |
|
| 14 |
-
Bộ nhớ H có cơ chế quên:
|
| 15 |
-
|
| 16 |
-
|
|
|
|
| 17 |
|
| 18 |
-
EMA là một phép hồi quy tuyến tính nên vẫn song song hóa được theo thời gian
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
layer: O(1) theo độ dài.
|
| 22 |
|
| 23 |
Trọng số được lưu ở FP16; EMA và normalization chạy ở FP32.
|
| 24 |
"""
|
|
@@ -55,9 +56,11 @@ class KentConfig(PretrainedConfig):
|
|
| 55 |
use_bias: dùng bias trong Resolution Proj (SwiGLU không bias).
|
| 56 |
initializer_range: độ lệch chuẩn khởi tạo trọng số.
|
| 57 |
ema_alpha_first: hệ số a khởi tạo của layer đầu, vị trí đầu (quên nhanh).
|
| 58 |
-
ema_alpha_last: hệ số a khởi tạo của layer cuối, vị trí cuối (nhớ lâu); phần còn lại nội suy theo
|
| 59 |
-
nhân theo trung bình chỉ số layer
|
| 60 |
-
|
|
|
|
|
|
|
| 61 |
use_cache: trả về KentCache khi suy luận.
|
| 62 |
use_gradient_checkpointing: bật gradient checkpointing theo từng KenT layer khi khởi tạo model
|
| 63 |
(chỉ có tác dụng ở chế độ train; tương đương gọi `model.gradient_checkpointing_enable()`).
|
|
@@ -79,6 +82,7 @@ class KentConfig(PretrainedConfig):
|
|
| 79 |
initializer_range: float = 0.02,
|
| 80 |
ema_alpha_first: float = 0.5,
|
| 81 |
ema_alpha_last: float = 0.01,
|
|
|
|
| 82 |
ema_block_size: int = 128,
|
| 83 |
use_cache: bool = True,
|
| 84 |
use_gradient_checkpointing: bool = False,
|
|
@@ -100,6 +104,7 @@ class KentConfig(PretrainedConfig):
|
|
| 100 |
self.initializer_range = initializer_range
|
| 101 |
self.ema_alpha_first = ema_alpha_first
|
| 102 |
self.ema_alpha_last = ema_alpha_last
|
|
|
|
| 103 |
self.ema_block_size = ema_block_size
|
| 104 |
self.use_cache = use_cache
|
| 105 |
self.use_gradient_checkpointing = use_gradient_checkpointing
|
|
@@ -119,10 +124,22 @@ class KentConfig(PretrainedConfig):
|
|
| 119 |
return [float(self.ema_alpha_first * ratio ** (0.5 * (r_l + (p / (n_p - 1) if n_p > 1 else 0.0))))
|
| 120 |
for p in range(n_p)]
|
| 121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
def alpha_init(self, layer_idx: int) -> float:
|
| 123 |
-
"""Trung bình của
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
|
| 128 |
# --------------------------------------------------------------------------- #
|
|
@@ -164,11 +181,37 @@ def _affine_scan(a: torch.Tensor, b: torch.Tensor):
|
|
| 164 |
|
| 165 |
|
| 166 |
def ema_scan(u: torch.Tensor, mask: torch.Tensor, h0: torch.Tensor, a: torch.Tensor, block: int = 128):
|
| 167 |
-
"""EMA song song, luôn chạy fp32 (tắt autocast để matmul không bị ép về fp16).
|
|
|
|
|
|
|
|
|
|
| 168 |
with torch.autocast(device_type=u.device.type, enabled=False):
|
|
|
|
|
|
|
| 169 |
return _ema_scan_fp32(u.float(), mask, h0.float(), a.float(), block)
|
| 170 |
|
| 171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
def _ema_scan_fp32(u: torch.Tensor, mask: torch.Tensor, h0: torch.Tensor, a: torch.Tensor, block: int = 128):
|
| 173 |
"""H_t = (1 - a m_t) ⊙ H_{t-1} + a m_t ⊙ u_t, tính song song cho mọi t.
|
| 174 |
|
|
@@ -308,12 +351,14 @@ class KentLayer(nn.Module):
|
|
| 308 |
self.wnn = nn.ModuleList([KentWNNBlock(config) for _ in range(config.num_wnn_blocks)])
|
| 309 |
self.norm_h = KentRMSNorm(config.feature_dim, config.rms_norm_eps)
|
| 310 |
self.res_out = nn.Linear(self.n * self.d, config.hidden_size, bias=config.use_bias) # Resolution Proj M -> 1
|
| 311 |
-
a0 = torch.tensor(
|
|
|
|
|
|
|
| 312 |
self.ema_logit_init = torch.log(a0 / (1.0 - a0))
|
| 313 |
-
self.ema_logit = nn.Parameter(self.ema_logit_init.clone()) # (M,)
|
| 314 |
|
| 315 |
def alpha(self) -> torch.Tensor:
|
| 316 |
-
"""
|
| 317 |
return torch.sigmoid(self.ema_logit.float()).clamp_max(0.999)
|
| 318 |
|
| 319 |
def forward(self, x, mask, h0, chunked: bool = False):
|
|
@@ -331,7 +376,8 @@ class KentLayer(nn.Module):
|
|
| 331 |
h0 = u.new_zeros((u.shape[0], self.n, self.d))
|
| 332 |
h, h_last = ema_scan(u, m, h0, self.alpha(), self.block_size)
|
| 333 |
h = h.reshape(b, t, self.n, self.d)
|
| 334 |
-
|
|
|
|
| 335 |
return x + dx, h_last
|
| 336 |
|
| 337 |
|
|
|
|
| 1 |
# coding=utf-8
|
| 2 |
"""KenT: kiến trúc hồi quy hai luồng (representation X_t / temporal-memory H_t).
|
| 3 |
|
| 4 |
+
Mỗi bước nhận ĐÚNG MỘT token (cửa sổ trượt từng token một); lịch sử nằm trong trạng thái H của từng layer.
|
| 5 |
+
Mỗi KenT layer (hộp "WNN" trong sơ đồ) thực hiện:
|
| 6 |
|
| 7 |
+
Z = ResProj_in(Norm_X(X)) # 1 -> M: một vector token thành M resolution, mỗi resolution d feature
|
| 8 |
Z = Z + SwiGLU( DCT_M( RMSNorm(Z) ) ) # WNN Block: DCT-II cố định trên trục M, SwiGLU trên trục d, skip quanh cả cụm
|
| 9 |
+
H_t = (1 - A) ⊙ H_{t-1} + A ⊙ Z_t # "EMA Learner Matrix": A = sigmoid(ema_logit), MA TRẬN M x d học được / layer
|
| 10 |
+
X' = X + ResProj_out( DCT_M( Norm_H(H_t) ) ) # DCT-II Proj rồi M -> 1; Add với X vào layer (residual)
|
| 11 |
|
| 12 |
Mỗi layer xếp K = `num_wnn_blocks` WNN Block nối tiếp (mặc định K = 1, đúng sơ đồ); độ sâu đến từ việc xếp chồng
|
| 13 |
+
nhiều layer ("xN" trong sơ đồ). Layer cuối cho X' -> norm cuối -> lm_head (tied với embedding).
|
| 14 |
|
| 15 |
+
Bộ nhớ H có cơ chế quên: A là ma trận M x d (mỗi vị trí resolution VÀ mỗi feature có hệ số quên riêng), học được và
|
| 16 |
+
riêng từng layer. Khởi tạo: nội suy theo cấp số nhân từ `ema_alpha_first` (layer đầu, vị trí đầu, feature đầu) tới
|
| 17 |
+
`ema_alpha_last` (layer cuối, vị trí cuối, feature cuối) theo trung bình của chỉ số layer, vị trí và feature.
|
| 18 |
+
`ema_per_feature=False` quay về vector M phần tử (chung cho mọi feature), dùng scan theo khối.
|
| 19 |
|
| 20 |
+
EMA là một phép hồi quy tuyến tính (đường chéo theo từng kênh) nên vẫn song song hóa được theo thời gian bằng
|
| 21 |
+
affine-scan log-depth (Hillis-Steele): kết quả bằng đúng hồi quy tuần tự. Trạng thái giải mã chỉ là H cho mỗi
|
| 22 |
+
layer, shape (M, d): O(1) theo độ dài.
|
|
|
|
| 23 |
|
| 24 |
Trọng số được lưu ở FP16; EMA và normalization chạy ở FP32.
|
| 25 |
"""
|
|
|
|
| 56 |
use_bias: dùng bias trong Resolution Proj (SwiGLU không bias).
|
| 57 |
initializer_range: độ lệch chuẩn khởi tạo trọng số.
|
| 58 |
ema_alpha_first: hệ số a khởi tạo của layer đầu, vị trí đầu (quên nhanh).
|
| 59 |
+
ema_alpha_last: hệ số a khởi tạo của layer cuối, vị trí cuối, feature cuối (nhớ lâu); phần còn lại nội suy theo
|
| 60 |
+
cấp số nhân theo trung bình các chỉ số (layer, vị trí[, feature]). a vẫn là tham số học được.
|
| 61 |
+
ema_per_feature: True = EMA Learner Matrix (hệ số quên riêng cho mỗi (vị trí M, feature d), ema_logit shape
|
| 62 |
+
(M, d)); False = vector M phần tử, chung cho mọi feature (ema_logit shape (M,)).
|
| 63 |
+
ema_block_size: độ dài khối của EMA song song (chỉ dùng khi ema_per_feature=False; ảnh hưởng tốc độ/bộ nhớ).
|
| 64 |
use_cache: trả về KentCache khi suy luận.
|
| 65 |
use_gradient_checkpointing: bật gradient checkpointing theo từng KenT layer khi khởi tạo model
|
| 66 |
(chỉ có tác dụng ở chế độ train; tương đương gọi `model.gradient_checkpointing_enable()`).
|
|
|
|
| 82 |
initializer_range: float = 0.02,
|
| 83 |
ema_alpha_first: float = 0.5,
|
| 84 |
ema_alpha_last: float = 0.01,
|
| 85 |
+
ema_per_feature: bool = True,
|
| 86 |
ema_block_size: int = 128,
|
| 87 |
use_cache: bool = True,
|
| 88 |
use_gradient_checkpointing: bool = False,
|
|
|
|
| 104 |
self.initializer_range = initializer_range
|
| 105 |
self.ema_alpha_first = ema_alpha_first
|
| 106 |
self.ema_alpha_last = ema_alpha_last
|
| 107 |
+
self.ema_per_feature = ema_per_feature
|
| 108 |
self.ema_block_size = ema_block_size
|
| 109 |
self.use_cache = use_cache
|
| 110 |
self.use_gradient_checkpointing = use_gradient_checkpointing
|
|
|
|
| 124 |
return [float(self.ema_alpha_first * ratio ** (0.5 * (r_l + (p / (n_p - 1) if n_p > 1 else 0.0))))
|
| 125 |
for p in range(n_p)]
|
| 126 |
|
| 127 |
+
def alpha_init_matrix(self, layer_idx: int):
|
| 128 |
+
"""Ma trận a (M x d) khởi tạo của layer: giảm theo cấp số nhân theo độ sâu, vị trí và feature."""
|
| 129 |
+
n_l, n_p, n_d = self.num_hidden_layers, self.resolution_size, self.feature_dim
|
| 130 |
+
r_l = layer_idx / (n_l - 1) if n_l > 1 else 0.0
|
| 131 |
+
ratio = self.ema_alpha_last / self.ema_alpha_first
|
| 132 |
+
return [[float(self.ema_alpha_first * ratio ** ((r_l + (p / (n_p - 1) if n_p > 1 else 0.0)
|
| 133 |
+
+ (j / (n_d - 1) if n_d > 1 else 0.0)) / 3.0))
|
| 134 |
+
for j in range(n_d)] for p in range(n_p)]
|
| 135 |
+
|
| 136 |
def alpha_init(self, layer_idx: int) -> float:
|
| 137 |
+
"""Trung bình của a khởi tạo của layer (để log)."""
|
| 138 |
+
if self.ema_per_feature:
|
| 139 |
+
flat = [x for row in self.alpha_init_matrix(layer_idx) for x in row]
|
| 140 |
+
else:
|
| 141 |
+
flat = self.alpha_init_vector(layer_idx)
|
| 142 |
+
return float(sum(flat) / len(flat))
|
| 143 |
|
| 144 |
|
| 145 |
# --------------------------------------------------------------------------- #
|
|
|
|
| 181 |
|
| 182 |
|
| 183 |
def ema_scan(u: torch.Tensor, mask: torch.Tensor, h0: torch.Tensor, a: torch.Tensor, block: int = 128):
|
| 184 |
+
"""EMA song song, luôn chạy fp32 (tắt autocast để matmul không bị ép về fp16).
|
| 185 |
+
|
| 186 |
+
a: (M, d) -> hệ số riêng từng kênh (EMA Learner Matrix, scan Hillis-Steele); a: (M,) -> theo khối (chung cho d).
|
| 187 |
+
"""
|
| 188 |
with torch.autocast(device_type=u.device.type, enabled=False):
|
| 189 |
+
if a.dim() == 2:
|
| 190 |
+
return _ema_scan_diag(u.float(), mask, h0.float(), a.float())
|
| 191 |
return _ema_scan_fp32(u.float(), mask, h0.float(), a.float(), block)
|
| 192 |
|
| 193 |
|
| 194 |
+
def _ema_scan_diag(u: torch.Tensor, mask: torch.Tensor, h0: torch.Tensor, a: torch.Tensor):
|
| 195 |
+
"""H_t = (1 - a m_t) ⊙ H_{t-1} + a m_t ⊙ u_t với a: (M, d) khác nhau theo từng kênh.
|
| 196 |
+
|
| 197 |
+
u: (B,T,M,d) fp32 | mask: (B,T) {0,1} (0 = padding: H giữ nguyên) | h0: (B,M,d) fp32.
|
| 198 |
+
Mỗi bước là ánh xạ affine h -> A_t h + B_t (A_t = 1 - a m_t, B_t = a m_t u_t); inclusive scan log-depth
|
| 199 |
+
(Hillis-Steele) cho trạng thái sau mọi t. Mọi A_t nằm trong (0, 1] nên ổn định.
|
| 200 |
+
Trả về H (B,T,M,d) và h_cuối (B,M,d).
|
| 201 |
+
"""
|
| 202 |
+
bsz, t, n, d = u.shape
|
| 203 |
+
am = a.view(1, 1, n, d) * mask.to(u.dtype).view(bsz, t, 1, 1)
|
| 204 |
+
dec = 1.0 - am
|
| 205 |
+
acc = am * u
|
| 206 |
+
off = 1
|
| 207 |
+
while off < t:
|
| 208 |
+
acc = torch.cat([acc[:, :off], dec[:, off:] * acc[:, :-off] + acc[:, off:]], dim=1)
|
| 209 |
+
dec = torch.cat([dec[:, :off], dec[:, off:] * dec[:, :-off]], dim=1)
|
| 210 |
+
off *= 2
|
| 211 |
+
h = dec * h0.unsqueeze(1) + acc
|
| 212 |
+
return h, h[:, -1]
|
| 213 |
+
|
| 214 |
+
|
| 215 |
def _ema_scan_fp32(u: torch.Tensor, mask: torch.Tensor, h0: torch.Tensor, a: torch.Tensor, block: int = 128):
|
| 216 |
"""H_t = (1 - a m_t) ⊙ H_{t-1} + a m_t ⊙ u_t, tính song song cho mọi t.
|
| 217 |
|
|
|
|
| 351 |
self.wnn = nn.ModuleList([KentWNNBlock(config) for _ in range(config.num_wnn_blocks)])
|
| 352 |
self.norm_h = KentRMSNorm(config.feature_dim, config.rms_norm_eps)
|
| 353 |
self.res_out = nn.Linear(self.n * self.d, config.hidden_size, bias=config.use_bias) # Resolution Proj M -> 1
|
| 354 |
+
a0 = torch.tensor(
|
| 355 |
+
config.alpha_init_matrix(layer_idx) if config.ema_per_feature else config.alpha_init_vector(layer_idx),
|
| 356 |
+
dtype=torch.float32)
|
| 357 |
self.ema_logit_init = torch.log(a0 / (1.0 - a0))
|
| 358 |
+
self.ema_logit = nn.Parameter(self.ema_logit_init.clone()) # (M, d) hoặc (M,)
|
| 359 |
|
| 360 |
def alpha(self) -> torch.Tensor:
|
| 361 |
+
"""EMA Learner Matrix a (M, d) (hoặc vector (M,)) trong (0,1), tính ở fp32."""
|
| 362 |
return torch.sigmoid(self.ema_logit.float()).clamp_max(0.999)
|
| 363 |
|
| 364 |
def forward(self, x, mask, h0, chunked: bool = False):
|
|
|
|
| 376 |
h0 = u.new_zeros((u.shape[0], self.n, self.d))
|
| 377 |
h, h_last = ema_scan(u, m, h0, self.alpha(), self.block_size)
|
| 378 |
h = h.reshape(b, t, self.n, self.d)
|
| 379 |
+
spec = dct2(self.norm_h(h).to(x.dtype)) # DCT-II Proj trên trục M của H
|
| 380 |
+
dx = self.res_out(spec.reshape(b, t, self.n * self.d))
|
| 381 |
return x + dx, h_last
|
| 382 |
|
| 383 |
|