Text Generation
Transformers
Safetensors
English
tokle
causal-lm
custom-architecture
slm
small-language-model
spab
custom_code
Instructions to use techdotus/Tokle-SPAB-3M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use techdotus/Tokle-SPAB-3M with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="techdotus/Tokle-SPAB-3M", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("techdotus/Tokle-SPAB-3M", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use techdotus/Tokle-SPAB-3M with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "techdotus/Tokle-SPAB-3M" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "techdotus/Tokle-SPAB-3M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/techdotus/Tokle-SPAB-3M
- SGLang
How to use techdotus/Tokle-SPAB-3M 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 "techdotus/Tokle-SPAB-3M" \ --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": "techdotus/Tokle-SPAB-3M", "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 "techdotus/Tokle-SPAB-3M" \ --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": "techdotus/Tokle-SPAB-3M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use techdotus/Tokle-SPAB-3M with Docker Model Runner:
docker model run hf.co/techdotus/Tokle-SPAB-3M
Updated Files.
Browse files- model.safetensors +2 -2
- modeling_tokle.py +86 -1
- spab_table.safetensors +3 -0
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7161cefd6b1f5dfbf55b4c1ba5772327ccce5cab567865ed8ec43738eba44f25
|
| 3 |
+
size 11646604
|
modeling_tokle.py
CHANGED
|
@@ -8,6 +8,7 @@ Works on Transformers 4.x and 5.x. The v5 differences are marked inline; they
|
|
| 8 |
are not cosmetic, see the note above _M1.
|
| 9 |
"""
|
| 10 |
import math
|
|
|
|
| 11 |
from typing import Optional, Tuple, Union
|
| 12 |
|
| 13 |
import torch
|
|
@@ -62,6 +63,12 @@ def apply_rope(x, cos, sin):
|
|
| 62 |
|
| 63 |
|
| 64 |
# ----------------------------------------------------------------------------- spab
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
# Mixing constants for the pair hash. Plain ints, not buffers, and that matters:
|
| 66 |
# buffers here would be non-persistent, and Transformers 5 builds the model on
|
| 67 |
# the meta device and fills only what the checkpoint contains. Non-persistent
|
|
@@ -96,9 +103,12 @@ class SPABBias(nn.Module):
|
|
| 96 |
self.scale = nn.Parameter(torch.full((config.n_head,), init))
|
| 97 |
if not config.spab_enabled:
|
| 98 |
self.scale.requires_grad_(False)
|
|
|
|
|
|
|
| 99 |
self.register_buffer("table",
|
| 100 |
torch.zeros(config.spab_table_size, dtype=torch.float32),
|
| 101 |
-
persistent=
|
|
|
|
| 102 |
|
| 103 |
def hash(self, i, j):
|
| 104 |
# Murmur-style mix. Relies on int64 overflow wrapping, so keep it in
|
|
@@ -113,6 +123,11 @@ class SPABBias(nn.Module):
|
|
| 113 |
def forward(self, idx):
|
| 114 |
if not self.enabled:
|
| 115 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
# Materialises b*t*t int64 pairs, so this is the memory high-water mark
|
| 117 |
# of a forward pass. Fine at t=512; watch it if max_seq_len ever grows.
|
| 118 |
b, t = idx.shape
|
|
@@ -194,6 +209,48 @@ class ToklePreTrainedModel(PreTrainedModel):
|
|
| 194 |
_no_split_modules = ["TokleDecoderLayer"]
|
| 195 |
_supports_sdpa = True
|
| 196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
def _init_weights(self, module):
|
| 198 |
if isinstance(module, nn.Linear):
|
| 199 |
nn.init.normal_(module.weight, 0.0, 0.02)
|
|
@@ -213,6 +270,34 @@ class ToklePreTrainedModel(PreTrainedModel):
|
|
| 213 |
nn.init.normal_(out.weight, 0.0, 0.02 / math.sqrt(2 * self.config.n_layer))
|
| 214 |
|
| 215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
class TokleModel(ToklePreTrainedModel):
|
| 217 |
def __init__(self, config: TokleConfig):
|
| 218 |
super().__init__(config)
|
|
|
|
| 8 |
are not cosmetic, see the note above _M1.
|
| 9 |
"""
|
| 10 |
import math
|
| 11 |
+
import os
|
| 12 |
from typing import Optional, Tuple, Union
|
| 13 |
|
| 14 |
import torch
|
|
|
|
| 63 |
|
| 64 |
|
| 65 |
# ----------------------------------------------------------------------------- spab
|
| 66 |
+
# The table lives outside model.safetensors. It is frozen data, not weights, and
|
| 67 |
+
# keeping it separate stops it being counted as trained parameters. Cost of that
|
| 68 |
+
# choice: it has to be fetched and installed by hand after the weights load, so
|
| 69 |
+
# every load path below goes through _install_spab_table.
|
| 70 |
+
SPAB_TABLE_FILE = "spab_table.safetensors"
|
| 71 |
+
|
| 72 |
# Mixing constants for the pair hash. Plain ints, not buffers, and that matters:
|
| 73 |
# buffers here would be non-persistent, and Transformers 5 builds the model on
|
| 74 |
# the meta device and fills only what the checkpoint contains. Non-persistent
|
|
|
|
| 103 |
self.scale = nn.Parameter(torch.full((config.n_head,), init))
|
| 104 |
if not config.spab_enabled:
|
| 105 |
self.scale.requires_grad_(False)
|
| 106 |
+
# persistent=False keeps it out of state_dict and therefore out of
|
| 107 |
+
# model.safetensors; `loaded` guards against using the zeros.
|
| 108 |
self.register_buffer("table",
|
| 109 |
torch.zeros(config.spab_table_size, dtype=torch.float32),
|
| 110 |
+
persistent=False)
|
| 111 |
+
self.loaded = not config.spab_enabled
|
| 112 |
|
| 113 |
def hash(self, i, j):
|
| 114 |
# Murmur-style mix. Relies on int64 overflow wrapping, so keep it in
|
|
|
|
| 123 |
def forward(self, idx):
|
| 124 |
if not self.enabled:
|
| 125 |
return None
|
| 126 |
+
if not self.loaded:
|
| 127 |
+
raise RuntimeError(
|
| 128 |
+
f"the SPAB table was never loaded -- {SPAB_TABLE_FILE} is missing "
|
| 129 |
+
f"or was not installed. Load the model with from_pretrained(), "
|
| 130 |
+
f"which fetches it; an all-zero table silently ruins every output.")
|
| 131 |
# Materialises b*t*t int64 pairs, so this is the memory high-water mark
|
| 132 |
# of a forward pass. Fine at t=512; watch it if max_seq_len ever grows.
|
| 133 |
b, t = idx.shape
|
|
|
|
| 209 |
_no_split_modules = ["TokleDecoderLayer"]
|
| 210 |
_supports_sdpa = True
|
| 211 |
|
| 212 |
+
def _spab(self):
|
| 213 |
+
for m in self.modules():
|
| 214 |
+
if getattr(m, "is_spab", False):
|
| 215 |
+
return m
|
| 216 |
+
return None
|
| 217 |
+
|
| 218 |
+
def install_spab_table(self, table):
|
| 219 |
+
"""Copy the frozen table in. Accepts a tensor or a .safetensors path."""
|
| 220 |
+
spab = self._spab()
|
| 221 |
+
if spab is None:
|
| 222 |
+
return self
|
| 223 |
+
if isinstance(table, (str, os.PathLike)):
|
| 224 |
+
from safetensors.torch import load_file
|
| 225 |
+
table = load_file(str(table))["table"]
|
| 226 |
+
table = table.reshape(-1)
|
| 227 |
+
if table.numel() != spab.table_size:
|
| 228 |
+
raise ValueError(f"SPAB table has {table.numel()} entries, "
|
| 229 |
+
f"expected {spab.table_size}")
|
| 230 |
+
# Match the existing buffer's device and dtype so a model already moved
|
| 231 |
+
# to cuda/fp16 keeps behaving the way it did before the split.
|
| 232 |
+
ref = spab.table
|
| 233 |
+
spab.table = table.to(device=ref.device, dtype=ref.dtype)
|
| 234 |
+
spab.loaded = True
|
| 235 |
+
return self
|
| 236 |
+
|
| 237 |
+
@classmethod
|
| 238 |
+
def from_pretrained(cls, pretrained_model_name_or_path, *args, **kwargs):
|
| 239 |
+
model = super().from_pretrained(pretrained_model_name_or_path, *args, **kwargs)
|
| 240 |
+
if getattr(model.config, "spab_enabled", False):
|
| 241 |
+
model.install_spab_table(
|
| 242 |
+
_resolve_table(pretrained_model_name_or_path, **kwargs))
|
| 243 |
+
return model
|
| 244 |
+
|
| 245 |
+
def save_pretrained(self, save_directory, *args, **kwargs):
|
| 246 |
+
out = super().save_pretrained(save_directory, *args, **kwargs)
|
| 247 |
+
spab = self._spab()
|
| 248 |
+
if spab is not None and spab.enabled and spab.loaded:
|
| 249 |
+
from safetensors.torch import save_file
|
| 250 |
+
save_file({"table": spab.table.detach().cpu().to(torch.float32).contiguous()},
|
| 251 |
+
os.path.join(save_directory, SPAB_TABLE_FILE))
|
| 252 |
+
return out
|
| 253 |
+
|
| 254 |
def _init_weights(self, module):
|
| 255 |
if isinstance(module, nn.Linear):
|
| 256 |
nn.init.normal_(module.weight, 0.0, 0.02)
|
|
|
|
| 270 |
nn.init.normal_(out.weight, 0.0, 0.02 / math.sqrt(2 * self.config.n_layer))
|
| 271 |
|
| 272 |
|
| 273 |
+
def _resolve_table(repo, **kwargs):
|
| 274 |
+
"""Find spab_table.safetensors in a local dir, the HF cache, or the Hub."""
|
| 275 |
+
local = os.path.join(str(repo), SPAB_TABLE_FILE)
|
| 276 |
+
if os.path.isfile(local):
|
| 277 |
+
return local
|
| 278 |
+
try:
|
| 279 |
+
from transformers.utils import cached_file
|
| 280 |
+
return cached_file(str(repo), SPAB_TABLE_FILE,
|
| 281 |
+
**{k: kwargs[k] for k in
|
| 282 |
+
("revision", "token", "cache_dir", "local_files_only",
|
| 283 |
+
"subfolder") if k in kwargs})
|
| 284 |
+
except Exception:
|
| 285 |
+
pass
|
| 286 |
+
try:
|
| 287 |
+
from huggingface_hub import hf_hub_download
|
| 288 |
+
return hf_hub_download(str(repo), SPAB_TABLE_FILE,
|
| 289 |
+
revision=kwargs.get("revision"),
|
| 290 |
+
token=kwargs.get("token"))
|
| 291 |
+
except Exception as e:
|
| 292 |
+
# Worth a clear message: without the table the model loads happily and
|
| 293 |
+
# then produces nonsense, which is a miserable thing to debug.
|
| 294 |
+
raise FileNotFoundError(
|
| 295 |
+
f"{SPAB_TABLE_FILE} was not found in '{repo}'. Tokle ships its frozen "
|
| 296 |
+
f"SPAB table beside model.safetensors and cannot run without it; copy "
|
| 297 |
+
f"the whole repo, not just the weights. ({type(e).__name__}: {e})"
|
| 298 |
+
) from e
|
| 299 |
+
|
| 300 |
+
|
| 301 |
class TokleModel(ToklePreTrainedModel):
|
| 302 |
def __init__(self, config: TokleConfig):
|
| 303 |
super().__init__(config)
|
spab_table.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9b7c75290ad59adb2551d2db9bbc6bd8b2ff6f72e18d037c6ce8d741a1a596ba
|
| 3 |
+
size 33554512
|