Instructions to use eduardoworrel/alias3-micro-1026-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use eduardoworrel/alias3-micro-1026-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
alias3-micro-1026 · LiteRT.js (WebGPU int4, int8, int4-b64)
LiteRT.js @litertjs/core 2.6.0 builds of aliasrobotics/alias3-micro-1026 with the weights streamed into WebGPU buffers and the hidden state exposed for System 1 heads.
Browser: litert/int4/ (b32, default) — graph + 2.10 GB of int4 weights streamed into WebGPU, 3.66 GB in all. Four quantizations of the same graph, each in its own folder: litert/int4/, litert/int8/, litert/int4-b64/, and litert/fp16/ (native CPU; its 8.43 GB graph is above the 4 GiB WebGPU buffer limit measured here, so it is not a browser build). About 5.3 s per decision in Chrome for the default int4 build. Loaded by ct0-edge with runtime: "litert".
Base model: aliasrobotics/alias3-micro-1026 (Alias Robotics), whose card labels the weights a “research preview”. Paper: arXiv:2610.16550. System 1 / System 2 and the bilinear pointer-head interface come from that paper, which draws on Kahneman's dual-process framing and adapts the typed-decision head from the Jev / System One lineage of TypeSafe AI (pointer networks, Vinyals et al., 2015).
Limits. The browser builds (int4, int8, int4-b64) are WebGPU only (no WASM / CPU path for the 4B in the browser) and were validated in Chrome 156 on an Apple M2 Pro. Not picked by
ct0-edge's"auto": the GenAI build is about 10× faster (~0.5 s against ~5.3 s per decision).
ONNX · transformers.js | ONNX · GenAI | ONNX · decode-only | MLC q4f32_1 | MLC q4f16_1 | LiteRT.js
Score vs size
Produced by: litert-torch f61d0b7 + our patches (GQA head-repeat as CONCATENATION; the hidden output), the Gated-DeltaNet decomposed, FullyConnected weights quantized with ai_edge_quantizer (int4 block 32, int4 block 64, int8 per channel, or fp16 cast) and, for the integer builds, externalized so they stream as external buffers, packaged by our route-B rebundle. Composite accuracy is yes/no (head) · multiple choice (head) · severity ±1 (head), as in the sibling cards: int4 83.8, int8 87.2, int4-b64 83.1, fp16 85.9.
System 1 per file
Accuracy is not statistically distinguishable from the original (0 of 32 paired tests, McNemar, before or after Holm correction); individual decisions change on 2.3–26.2% of questions; the test set (50–65 questions per mode) only detects large losses. The fp16 bundle sits within one answer of the original on every read; the 4-bit builds lose multiple choice (the logits read most: 32/57 vs 39/57 for the original), the choice-mode drop that the head read partly recovers.
Dark segment: accuracy when the answer is read straight from the model's logits (the Yes/No, option or digit tokens). Lighter segment: the extra accuracy when the readout head (head.bin, or head_score.bin for severity) reads the hidden state instead. Severity (head_score.bin) is a proof of concept: fitted on 30 synthetic cases; using it as a severity scorer calls for a larger, independently labelled set.
System 1 table on the decision test set (logits / head per mode)
Status vs the original model: 🟢 within 2 answers of the original (or better) · 🟡 3+ below the original, not significant · 🔴 significantly below the original (McNemar p < 0.05) · ⚪ original model (PyTorch bf16), the reference.
| file | yes/no (65) · logits | yes/no (65) · head.bin | multiple choice (57) · logits | multiple choice (57) · head.bin | severity (50) exact · logits | severity (50) exact · head_score.bin | severity (50) ±1 · head_score.bin | changed answers vs original (default read) |
|---|---|---|---|---|---|---|---|---|
Original (PyTorch bf16) |
⚪ 54/65 | ⚪ 54/65 | ⚪ 39/57 | ⚪ 46/57 | ⚪ 20/50 | ⚪ 26/50 | ⚪ 47/50 | — |
litert/int4 |
🟢 56/65 | 🟢 53/65 | 🟡 32/57 | 🟡 41/57 | 🟢 19/50 | 🟢 26/50 | 🟢 49/50 | 21.5% |
litert/int8 |
🟢 54/65 | 🟢 54/65 | 🟢 41/57 | 🟢 47/57 | 🟢 21/50 | 🟡 21/50 | 🟢 48/50 | 8.7% |
litert/int4-b64 |
🟢 57/65 | 🟢 53/65 | 🟡 32/57 | 🟡 42/57 | 🟢 20/50 | 🟡 20/50 | 🟢 47/50 | 26.2% |
litert/fp16 |
🟢 54/65 | 🟢 54/65 | 🟢 38/57 | 🟢 46/57 | 🟢 20/50 | 🟢 26/50 | 🟢 47/50 | 2.3% |
The default read per mode is yes/no logits, multiple choice head.bin, severity head_score.bin.
Browser details (load, timing, same answers as native)
| build | fits | load | time per decision, median · max | same answers: browser vs native CPU (default read per mode) |
|---|---|---|---|---|
litert/int4 (b32) |
✅ | 19.6 s | 5.3 s · 22.5 s | 159/172 (yes/no 64/65 · multiple choice 53/57 · severity 42/50) |
litert/int8 |
✅ | 46.4 s | 5.6 s · 30.1 s | 161/172 (65/65 · 53/57 · 43/50) |
litert/int4-b64 |
✅ | 23.5 s | 4.7 s · 25.4 s | 154/172 (63/65 · 46/57 · 45/50) |
litert/fp16 |
❌ | — | — | graph 8.43 GB > the 4 GiB WebGPU buffer limit; native CPU only |
Chrome 156 (WebGPU, Apple M2 Pro, Metal-3 adapter; maxBufferSize 4,294,967,292), @litertjs/core through ct0-edge, the same 172 questions as above, one run per build. Time per decision is the wall time of one prefill per question, including the token-embedding reads. All 23,790 embedding reads per run were served as HTTP 206 (Range), so the full-file fallback was never used. "Same answers" compares the browser's decisions with the native CPU run of the same file; the cause of the differing answers was not isolated.
Files: size, tool, runtime
Folder layout (the baseUrl for ct0-edge is the folder): litert/int4/ (b32, default), litert/int8/, litert/int4-b64/, litert/fp16/ (graph + manifest + embed only; edge-only).
| file | bytes | sha256 (first 16) | notes |
|---|---|---|---|
litert/int4/model.graph.tflite |
282,002,344 | 2f39fb1433640020 |
the graph (logits and hidden outputs) |
litert/int4/model.weights.bin |
2,102,394,880 | 09ca2af6c8c100d8 |
external int4 FullyConnected weights (group tflite_weights), streamed into WebGPU via loadModelAndWeights |
litert/int4/embed.f16.bin |
1,271,398,400 | 084b44680de857f1 |
token-embedding table (248,320 × 2,560, fp16), read per row via HTTP Range where the host supports it; falls back to fetching the whole file once and slicing if the server ignores Range |
litert/int4/manifest.json |
34,169 | 60335f9667f52ea1 |
shapes, signatures, tokenizer ids |
litert/int8/model.graph.tflite |
48,766,672 | 4ee0cae6cfe6e0b3 |
same layout |
litert/int8/model.weights.bin |
4,204,789,760 | a68375bc45696bcf |
external int8 FullyConnected weights (group tflite_weights), streamed into WebGPU via loadModelAndWeights |
litert/int8/embed.f16.bin |
1,271,398,400 | 084b44680de857f1 |
token-embedding table, identical to litert/int4/embed.f16.bin |
litert/int8/manifest.json |
34,168 | 2cb5aa80acbadf74 |
same layout |
litert/int4-b64/model.graph.tflite |
150,602,664 | 8ab2f7f827fd59d8 |
same layout |
litert/int4-b64/model.weights.bin |
2,102,394,880 | b92b67ceb005a5a3 |
external int4 FullyConnected weights (group tflite_weights), streamed into WebGPU via loadModelAndWeights |
litert/int4-b64/embed.f16.bin |
1,271,398,400 | 084b44680de857f1 |
token-embedding table, identical to litert/int4/embed.f16.bin |
litert/int4-b64/manifest.json |
34,169 | 6d14f8a5cbc46357 |
same layout |
litert/fp16/model.graph.tflite |
8,428,761,008 | dce6591d25799ba7 |
same layout; carries the fp16 weights, so there is no weights file |
litert/fp16/embed.f16.bin |
1,271,398,400 | 084b44680de857f1 |
token-embedding table, identical to litert/int4/embed.f16.bin |
litert/fp16/manifest.json |
34,161 | 344ad724cdb4bf71 |
same layout |
Runtime: LiteRT.js (@litertjs/core 2.6.0) in the browser (WebGPU), loaded by ct0-edge; the builds also run on native LiteRT CPU, where the System 1 accuracy table was measured.
| folder | total | dtype | produced by | runtime |
|---|---|---|---|---|
litert/int4/ ⭐ |
3,655,829,793 B (3.66 GB) | int4, block 32 | O+P · litert-torch f61d0b7 + patches 0001/0002, ai_edge_quantizer int4 block 32, LiteRT externalize tool restricted to FullyConnected by a local edit, S route-B rebundle |
browser WebGPU · native CPU |
litert/int8/ |
5,524,989,000 B (5.52 GB) | int8, per channel | same, ai_edge_quantizer int8 per channel |
browser WebGPU · native CPU |
litert/int4-b64/ |
3,524,430,113 B (3.52 GB) | int4, block 64 | same, ai_edge_quantizer int4 block 64 |
browser WebGPU · native CPU |
litert/fp16/ |
9,700,193,569 B (9.70 GB) | fp16 | same, ai_edge_quantizer fp16 cast; no weights file |
native CPU only |
Provenance: O = official tool as-is · O+P = official tool + our patch or wrapper · S = our script (what the official tool does not do). ⭐ = recommended for the browser.
Provenance and export recipe
- Source checkpoint:
aliasrobotics/alias3-micro-1026, revision61c0e7100c052a252563ceb0711d15dc58bda2d0(model.safetensorssha256062756404947caffee60cb1cc399b5c0ff33782abbb4ce3fc100d23e8020a6c1). - Exported with
litert-torchatf61d0b7plus local patches: 0001 GQA head-repeat as CONCATENATION (noBROADCAST_TO, required for full WebGPU delegation), 0002 thehidden-state output (post final norm). Gated-DeltaNet decomposed (use_fused_gdn=False): LiteRT.js does not register the fusedgated_delta_updateop. Short-conv composite off. Signaturesprefill_16anddecode; cache length 2,048; pad token<|vision_pad|>. - Quantization recipes (
ai_edge_quantizer,min_max_uniform_quantize, applied to FullyConnected ops only, all other tensors as exported; the embedding table is kept fp16 in its own file):litert/int4/: 4-bit, symmetric, BLOCKWISE_32litert/int8/: 8-bit, symmetric, CHANNELWISElitert/int4-b64/: 4-bit, symmetric, BLOCKWISE_64litert/fp16/:float_castingto 16-bit float
- Packaging: the integer builds have their FullyConnected weights moved out of the graph into
model.weights.bin(LiteRT external buffers, grouptflite_weights) soloadModelAndWeightscan stream them into WebGPU buffers; the fp16 build has no integer weights to move, so its weights file is empty and the graph carries the weights (8.4 GB graph, hence edge-only).
Generation (System 2)
System 1 = single-forward typed decisions through the bilinear pointer head (sections above); System 2 = generation, the usual decode loop from the same weights. Terms as in the base model card and the paper.
96-step greedy, 22-token prompt, run natively on LiteRT CPU (Linux x86). Reference = the decode-only fp32 ONNX tokens on onnxruntime CPU (method of record; there is no bf16 original generation run).
Generation details per file
| file | test | free-running = fp32 | first divergence | teacher-forced | notes |
|---|---|---|---|---|---|
litert/fp16 |
96-step greedy | 96/96 | — | 96/96 | free-running cos min 1.00000 |
litert/int8 |
96-step greedy | 96/96 | — | 96/96 | free-running cos min 0.84839 |
litert/int4 |
96-step greedy | 3/96 | step 2 | 90/96 | teacher-forced cos mean 0.959 |
litert/int4-b64 |
96-step greedy | 3/96 | step 2 | 90/96 | teacher-forced cos mean 0.949 |
Every 4-bit file diverges at step 2 when free-running (a near-tie after <think>).
Peculiarities
- graph: two signatures:
prefill_16(16 embedded tokens, outputshidden) anddecode(1 token, outputslogitsandhidden); the recurrent / KV cache state is passed in and out as tensors (cache length 2,048) - inputs:
embeddings(float32, looked up by the runtime fromembed.f16.bin),input_pos, the cache tensors - head outputs exposed: hidden name:
hidden(post final norm, patch 0002) - GPU-friendly graph (litert-torch + our patch 0001): the stock
qwen3_5exporter repeats the key heads for grouped-query attention with an op that lowers to BROADCAST_TO, which the GPU delegates do not support, so the graph is split and, with streamed weights, the CPU parts have no weight data; it also ignores the typeduse_short_conv_compositeflag, and the GPU runtime reads the short-conv composite as its gated variant (prefill logits off by 0.13–0.35 nats; with the composite off it is exact). Patch 0001 repeats the heads by concatenation (numerically identical) and honours the flag; we export with the composite off. Proposed upstream: https://github.com/google-ai-edge/litert-torch/pull/1396. - hidden output (our patch 0002): the stock exporter returns logits only. Patch 0002 adds an
output_hiddenoption that returns the post-final-norm hidden state, whichprefillanddecodeemit as a float32 output namedhidden; off by default. Checked on a small test model: it equals the PyTorch last hidden state to 1.1e-5, andlm_head(hidden)reproduces the logits exactly. - Gated-DeltaNet decomposed: LiteRT.js 2.6.0 does not register the fused
gated_delta_updateoperator (it is unresolved on WASM and fails WebGPU delegation), so we export with the exporter's own decomposed path (use_fused_gdn=False). Effect: the graph uses standard operators only, and many more of them than the fused form (760 operators against 121 in a one-layer test slice). - weights streamed from outside the graph: litert-torch writes one flatbuffer with the weights inside, and a model above 2 GiB cannot be loaded that way in the browser. We move the FullyConnected weights out with LiteRT's own externalize tool, restricted by a local edit to FullyConnected only (quantizing and externalizing the depthwise convolution fails with “Unsupported quantization scale size”), and repackage graph,
model.weights.bin,embed.f16.binand manifest with a rebundling script of ours soloadModelAndWeightscan stream them. The fp16 build has no integer weights to move, so its graph carries the weights (8.43 GB) and it is not a browser build. - quantization recipes (FullyConnected only):
ai_edge_quantizeris applied with recipe files of ours that touch FullyConnected ops only (int4 block 32, int4 block 64, int8 per channel, fp16 cast); every other tensor stays as exported. Effect: a ~3.5–5.5 GB browser download, with the accuracy changes in the tables above. - embedding table kept outside the graph: the token embedding is a separate fp16 file (
embed.f16.bin); the graph takes embeddings as input. ct0-edge reads one row at a time with HTTP Range requests and falls back to downloading the file once if the server ignores Range. - weight streaming reader:
loadModelAndWeightsin LiteRT.js 2.6.0 runs one session per WebGPU partition from offset 0 on a single weight stream and fails with “Stream ended before all weights were loaded”; ct0-edge hands each session its own fresh reader. - System 1 head file (
head.binrecovered from a truncated release file) and prompt markers: the officialhead.ptis a truncated streaming zip and cannot be loaded, sohead.binis recovered from it (qexact;k.weight89% of rows;k.biaslost and estimated as one offset). The marker-to-id mapping is not released, so the prompt markers are plain text, and the official System 1 endpoint needs a fork of SGLang (--systemone-head) that is not in public SGLang. Table and numbers: “Changes to the official head” below.
Our patches and scripts are kept by the authors and are available on request.
Usage
npm i ct0-edge @huggingface/transformers @litertjs/core@2.6.0
import { CT0 } from "ct0-edge";
const ct0 = await CT0.load({
runtime: "litert",
litertBaseUrl: "https://huggingface.co/eduardoworrel/alias3-micro-1026-LiteRT/resolve/main/litert/int4/",
});
const p = await ct0.decide(htmlSnippet, "Is this a reflected XSS vulnerability?");
Heads
| file | size | read by | shipped |
|---|---|---|---|
heads/head.bin |
2,622,548 B | yes/no, multiple choice — bilinear pointer head over the hidden at <decide> and at the last / option positions |
✅ in this repo, heads/ (sha256 1138a7745037fb29; the same file as in the other CT0 repos) |
heads/head_score.bin |
2,622,668 B | severity (levels 1–5) — ridge probe on the last-position hidden, same file format (proof of concept: fitted on 30 synthetic cases; using it as a severity scorer calls for a larger, independently labelled set.) | ✅ in this repo, heads/ (sha256 82640a99653d49d6; the same file as in the other CT0 repos) |
| mode | ct0-edge default read | alternative |
|---|---|---|
| yes/no | logits Yes vs No (no head) |
head.bin |
| multiple choice (1 of K) | head.bin |
logits of each option's first token |
| severity (1–5) | head_score.bin |
logits of digits 1…5 |
Hidden positions: <decide> (the final > of its 4 tokens >< dec ide >) and the last prompt position (choice: each option's position).
Changes to the official head
Each decision is read two ways from one prefill: by the logits at the last prompt position (no extra weights) and by the head on the hidden states at <decide> and the key positions (the rows after the first).
| official (base card / paper) | ours | why | |
|---|---|---|---|
| logits read | not part of the official System 1 (the paper leaves head-vs-logits to future work) | compare next-token logits: Yes vs No; first token of each option; digits 1–5 |
weight-free baseline every runtime supports; the dark segment in the System 1 figure |
| weights file | head.pt on the base repo: truncated streaming zip (no central directory), cut inside k.weight |
head.bin, recovered from it: q.weight/q.bias 100% (CRC match), k.weight 89% (227/256 rows), k.bias lost → one score offset (+16.27) estimated without labels |
the official file cannot be loaded |
| format | PyTorch head.pt for the CSI SGLang fork (--systemone-head) |
head.bin (fp16, JSON header) read by ct0-edge systemone.ts in JS, same math |
on-device runtimes |
| yes/no read | bilinear pointer head with K = 2 options | query at <decide>, key at the last position, plus the offset |
marker-to-id mapping and prompt row are not published |
| severity read | ordinal scale as a K-option pointer (System 1 severity 44.4% in the paper) | new head_score.bin: ridge probe on the last-position hidden (λ = 10), encoded exactly in head.bin's 2-row layout; trained on 30 labelled cases, measured on the 50 severity questions (proof of concept: fitted on 30 synthetic cases; using it as a severity scorer calls for a larger, independently labelled set.) |
the released head does not order severity |
| prompt markers | reserved ids (mapping unpublished) | plain-text markers | see the note below the table |
| temperature / orientation | T = 2.0; query at <decide>, keys at </opt> |
kept as released | — |
Prompt markers: the paper maps the markers (<state>, <q>, <opt>, </opt>, <decide>) onto reserved token ids. The model has 243 unnamed embedding slots (ids 248077–248319) beyond the tokenizer's last token (248076), but the marker-to-id mapping isn't published, so we write the markers as plain text, which the tokenizer splits into ordinary tokens.
“Extra from the head” in the System 1 figure = how many more questions the head read gets right than the logits read on the same decision test set (ours).
How measured
- Decision test set (ours): 172 security questions with known answers, written by us (not part of the CT0 release): 65 yes/no, 57 multiple choice (chance 0.272), 50 severity (1–5, held out from
head_score.bin); sha25688e0f6c5… - Stats: 95% bootstrap CI (2000 resamples) · McNemar exact, paired per question, vs the original model (PyTorch bf16, revision
61c0e710) - Platform: all four bundles on the same platform: native LiteRT CPU on Linux x86, the same 172 questions as the sibling cards, one prefill per question, logits and the
hiddenoutput read at the decision positions - Browser: the three browser builds were run in Chrome WebGPU on an Apple M2 Pro, one run each, over the same 172 questions (see Browser details); every one loaded and answered all 172
- Platform control: the same int4 file on a Mac ARM CPU changes 13 of 172 answers (default read per mode), so numerics differ between x86 and ARM on a few close calls
- Files: eduardoworrel/alias3-micro-1026-LiteRT · base model: aliasrobotics/alias3-micro-1026
Citation
If you use these files, please cite the base model:
@article{ct0_2026,
title = {{CT0}: Cybersecurity Transformer},
author = {Mayoral-Vilches, V{\'i}ctor and {Alias Robotics}},
journal = {arXiv preprint arXiv:2610.16550},
year = {2026},
url = {https://arxiv.org/abs/2610.16550}
}
Base model card: aliasrobotics/alias3-micro-1026.
License: Apache-2.0 (weights, as upstream).
- Downloads last month
- 3