Downloads · 30 days
11
4% of all-time downloads
glassbox/gpt-alpha-bg-14m-onnx
gpt-alpha-bg-14m-onnx is a text generation model from glassbox. Use it when you need the model to write or continue text. The card lists the license as mit.
A 13.77M-parameter Bulgarian language model, trained from scratch, exported to ONNX and quantized to int8, 17.3 MB. Small enough to ship as a static asset and run in a browser tab with onnxruntime-web, which is where…
Downloads · 30 days
11
4% of all-time downloads
All-time downloads
255
Public
Parameters
13.8M
140 MB on disk
Likes
0
Public
Click a slice to open those files.
.onnx85.3 MB · 60%
From the Hugging Face model README
A 13.77M-parameter Bulgarian language model, trained from scratch, exported to ONNX and quantized
to int8, 17.3 MB. Small enough to ship as a static asset and run in a browser tab with
onnxruntime-web, which is where it already runs:
restorer-interp-lab.iksnerd.workers.dev/live-lm.
It generates fluent Bulgarian and it does not know things:
Столицата на България е -> Столицата на България е най-добрата част от населението на България.
Fluent, grammatical, and wrong. That is what 13.77M parameters buys, and the limits section measures it rather than hedging about it. If fluency judging is the actual goal, the 91.26M sibling is measurably better at it (92.3% paired preference on real error/correction pairs, a statistical tie with a frontier model). This model is the one that fits in a browser tab.
Python, with onnxruntime and tokenizers:
import numpy as np, onnxruntime as ort
from tokenizers import Tokenizer
tok = Tokenizer.from_file("bg15m.tokenizer.json")
sess = ort.InferenceSession("bg15m.int8.onnx")
ids = tok.encode("Столицата на България е").ids
for _ in range(12): # greedy continuation
logits = sess.run(None, {"idx": np.array([ids[-256:]], dtype=np.int64)})[0]
ids.append(int(logits[0, -1].argmax()))
print(tok.decode(ids))
The graph is one stateless function:
idx: int64 [batch, seq] -> logits: float32 [batch, seq, 8192]
Opset 17, both axes dynamic, no KV cache in the graph, so the same call serves prompt ingestion and one-token-at-a-time decode. At a 256-token context a full recompute per token is fast enough in a browser, and it keeps the artifact a single file with no session state to manage.
In the browser it is the same graph under onnxruntime-web, with the byte-level BPE ported to
TypeScript. That port is pinned: the tokenizer is fixed id-for-id against the Python
implementation on 512 real sentences, and the runner against reference logits and perplexities.
One backend caveat, found the hard way. ONNX Runtime's wasm and CPU int8 kernels disagree by up to 0.12 on a logit. Across 72 greedy steps that flipped exactly one argmax, at a 0.028 margin, and one flip redirects the whole continuation. Identical greedy output across backends is not something this model, or any int8 model, guarantees. If you need reproducibility, condition each step on a fixed prefix and compare distributions rather than sampled strings.
It saw its training data exactly once: 18,300 iterations over a cleaned mixed Bulgarian corpus (books, news, wiki, forum), ~300M tokens, no example twice. On a shared external held-out set it reaches 2.0620 bits per character, beating both 29M models trained on a narrower fiction-only diet at under half their size:
| model | parameters | corpus | bpc, external held-out |
|---|---|---|---|
| this model | 13.77M | mixed, one epoch | 2.0620 |
| books-only sibling | 29.37M | fiction | 2.0765 |
| earlier books-era model | 29.36M | fiction | 2.1304 |
Single seed per configuration, so read this as a strong result about data diet rather than a measured margin. Bits per character rather than validation loss, because these models do not share a tokenizer and loss across tokenizers is not comparable.
Both graphs are verified against the PyTorch original on the same held-out text:
<!-- BEGIN generated: card-verification (uv run python datatools/gen_card_verification.py) -->| size | max abs logit difference vs PyTorch | top-1 agreement | held-out bpc | |
|---|---|---|---|---|
bg15m.onnx (fp32) | 68.0 MB | 1.7e-05 | 1.00 | 2.0620 |
bg15m.int8.onnx (dynamic int8) | 17.3 MB | 0.55 | 1.00 | 2.0638 |
int8 costs +0.0018 bpc, measured on the same held-out slice in the same invocation as fp32 — scoring the two separately is how a moved --max-chars default once read as a headline failing to reproduce.
For scale: at this model size, switching the training corpus from fiction-only to a mixed diet was worth 0.086 bpc on the same metric, so quantizing costs about a fiftieth of what the data choice bought. Quantization-aware training was on the roadmap and got cut on the strength of this measurement: at 14M there is nothing for it to recover.
Note the two columns that disagree. int8's worst logit moves by 0.55, yet the argmax never changed on the probe: individual logits shift, the ranking mostly does not. Do not read "top-1 agreement 1.00" as determinism, per the backend caveat above.
384 embedding dim, 6 heads, 6 layers, block size 256, vocab 8192. RoPE, RMSNorm, SwiGLU, weight tying, and highway-gated residuals (a gate on the residual stream, validated against the plain stack in a multi-seed ablation before being adopted). Trained on a cloud GPU with AdamW, 200 warmup steps then cosine decay from lr 3e-4, batch 64, dropout 0.2. 13,772,172 parameters.
| file | what it is |
|---|---|
bg15m.int8.onnx | 17.3 MB dynamic-int8 graph, the one to use in a browser |
bg15m.onnx | 68 MB fp32 graph, the reference, for when the 0.0018 bpc matters |
bg15m.tokenizer.json | byte-level BPE, vocab 8192 (HuggingFace tokenizers format) |
bg15m.export.json | the verification record behind the table above: sizes, logit deltas, top-1 agreement, bpc per graph |
model.safetensors | the torch weights both graphs were exported from, so the 1.7e-05 fp32 delta is something you can re-measure rather than take on trust |
config.json | the resolved architecture behind those weights, every toggle spelled out |
Six models from one project on small models doing narrow tasks, these among them:
gpt-alpha-bg-91m - the 91M flagship: a fluency judge that ties a frontier model on Bulgarian error/correction pairsgpt-alpha-bg-restorer - shlyokavitsa to Cyrillic, character by character, running in your browsergpt-alpha-bg-14m-onnx - you are hereThe other three appear under huggingface.co/glassbox as each ships.
<!-- END generated: family -->Findings, the interpretability lab and the full model roster: restorer-interp-lab.iksnerd.workers.dev.
MIT.