A 124M-parameter chat language model, trained from scratch on a hobby budget.
NARC Tiny v1.0 is a modern (Llama-style) decoder-only Transformer, built and trained end-to-end from scratch in plain PyTorch by Madushan Bhashana Dissanayake — no training frameworks, no distillation, no fine-tuning of an existing model. It was pretrained on 8.4B tokens of quality-filtered educational web text and instruction-tuned into a conversational assistant, all on rented cloud GPUs for roughly $52 total.
It is a learning and research artifact: quality is around GPT-2 (124M) class — fluent, coherent English with unreliable facts. It runs locally on CPU.
⚠️ Expectation-setting: a model this size sounds like an assistant but confidently invents facts, names, and details. It is not a knowledge base or a production assistant. See Limitations.
Quickstart
pip install torch safetensors tiktoken
python
1import torch, tiktoken
2from modeling_narc import NarcTiny
34IM_START, IM_END =50257,502585model = NarcTiny.from_pretrained("model.safetensors","config.json")6enc = tiktoken.get_encoding("gpt2")78ids =[IM_START]+ enc.encode("user\nWhat is the capital of France?")+[IM_END]+ enc.encode("\n")9ids +=[IM_START]+ enc.encode("assistant\n")10out = model.generate(torch.tensor([ids]), max_new_tokens=128,11 temperature=0.7, top_k=50, rep_penalty=1.3, eos_token=IM_END)12print(enc.decode([t for t in out[0,len(ids):].tolist()if t <50257]).strip())13# -> "The capital of the French nation is Paris."
A runnable inference_example.py is included. For a full graphical experience, see the desktop app.
Run with Ollama
ollama run hf.co/Madushan996/NARC_Tiny_v1.0
Pulls narc-tiny-v1.0.gguf directly from this repo and chats using its embedded ChatML template — no Python, no PyTorch, just Ollama.
Prefer a named local model instead? Download narc-tiny-v1.0.gguf and Modelfile from this repo, then:
bash
1ollama create narc-tiny -f Modelfile
2ollama run narc-tiny
The GGUF is F16 (RMSNorm weights kept F32, per GGUF convention) and was verified to reproduce the original PyTorch model's logits (100% argmax agreement, differences only at fp16-rounding level) before publishing.
123,587,328 (embedding and LM head are weight-tied)
Layers / heads / d_model
12 / 12 / 768 (head_dim 64)
Context length
1,024 tokens
Positions
RoPE (rotary, θ=10,000) on Q/K — no learned position table
Normalization
RMSNorm, pre-norm, float32 internals
MLP
SwiGLU (gated), hidden ≈ 2,048 (8/3 × d_model)
Attention
Causal multi-head via FlashAttention (scaled_dot_product_attention); GQA-ready
Tokenizer
GPT-2 BPE (50,257), vocab padded to 50,304; 2 ids reused as ChatML specials
Other
No bias terms; dropout 0; GPT-2 scaled residual init
RoPE convention: the weights use the rotate-half (Llama/GPT-NeoX) layout — pairing dim i with dim i + D/2. The interleaved (GPT-J) convention is not compatible. The included modeling_narc.py implements it correctly.
ChatML, with two special tokens (<|im_start|> = 50257, <|im_end|> = 50258):
<|im_start|>user
What is the capital of France?<|im_end|>
<|im_start|>assistant
The capital of France is Paris.<|im_end|>
Generate from <|im_start|>assistant\n and stop at <|im_end|>. A system turn (<|im_start|>system\n…) is supported but followed only loosely at this scale.
Training
Built from scratch in ~7 PyTorch files; trained on Modal.com.
Stage 1 — Pretraining (val loss 3.07)
Data: 8.4B tokens of FineWeb-Edu (sample-10BT), Common Crawl filtered by an educational-quality classifier — the single highest-leverage quality decision.
Objective: next-token prediction, cross-entropy.
Schedule: 16,000 steps × 524,288 tokens/step, AdamW (β 0.9/0.95, wd 0.1 on matrices only), grad-clip 1.0, cosine LR 6e-4→6e-5 with 700-step warmup, bf16, DDP across 8×H100.
Throughput: ~3.17M tok/s (~30% MFU). Trained in two phases (7,000 then resumed to 16,000 steps).
Result: val loss 11.01 → 3.07 (perplexity ≈ 21.5).
Stage 2 — Instruction tuning / SFT (val loss 1.75)
Data: ~105M tokens of SmolTalk, rendered through the ChatML template.
Loss masking: loss computed on assistant tokens only (user/scaffolding targets set to ignore_index), so the model learns to answer, not to imitate users.
Schedule: 800 steps, warm-started from the base checkpoint with a fresh optimizer, LR 3e-5→3e-6 cosine, 100-step warmup, on a single A10G.
Result: val loss 1.75.
Full process and the engineering record (eight real incidents and their fixes — a compiler pin, a RoPE-convention bug, throughput reality vs. documentation, and more) are in docs/NARC-Tiny-v1.0-Technical-Documentation.pdf.
Evaluation
Benchmarks (loglikelihood scoring, no generation; the base model is the conventional reference point):
Benchmark
Metric
Base (val 3.07)
Chat (val 1.75)
GPT-2 124M
Random
HellaSwag (10,042 ex)
acc_norm
30.21%
29.81%
~29–31%
25%
ARC-Easy (2,376 ex)
acc
52.65%
48.48%
~43–44%
~25%
NARC Tiny is on par with GPT-2 124M on HellaSwag and exceeds it on ARC-Easy — a science-QA benchmark where the model's FineWeb-Edu (educational) pretraining data is an advantage over GPT-2's general-web training. acc_norm is the standard HellaSwag metric; acc is standard for ARC. Fully reproducible with the included benchmark_modal.py, eval_hellaswag.py, and eval_arc.py.
Quantitative loss: val loss 3.07 (base) / 1.75 (chat). The v1→v2 pretraining extension (3.7B→8.4B tokens) is visible qualitatively on identical prompts:
"Write a paragraph about Sri Lanka"
— early model: "Hello, Sri Lanka! My name is Sri Lanka, and I'm a unique and beautiful person…" (fluent filler, no content)
— this model: "The island of Lanka is home to a rich history, including ancient temples… inhabited for more than 10,000 years by the indigenous Sinhalese tribes…" (topical; fine details still invented)
Capabilities
Fluent, grammatical English; coherent paragraphs
Assistant-style turn-taking with structured (list/markdown) answers
Topical content on common subjects; learned stop behavior
Runs on CPU (~0.5 GB weights)
Limitations
Facts are unreliable and confidently invented — 124M parameters hold limited world knowledge (for scale, SmolLM2-135M saw ~2T tokens; NARC Tiny saw 8.4B, ~240× fewer)
Weak multi-step reasoning and arithmetic
Follows system prompts only loosely; no stable identity
1,024-token context; English only
No safety/alignment tuning beyond SFT data curation — may produce incorrect, biased, or inappropriate text. Use responsibly; not for production or high-stakes use.
Weights-only PyTorch checkpoint (for the desktop app)
app/
Source of the NARC Tiny desktop chat app (Electron + Python)
docs/
Technical documentation + architecture PDFs
RELEASE_NOTES.md
Version history
Desktop chat app
A local, private chat GUI (Electron front-end + Python inference backend) is included under app/ (source). To run it:
bash
1cd app
2npminstall3pip install -r requirements.txt # torch, tiktoken4npm start # or run START_NARC_TINY.bat on Windows
Point it at model.safetensors or NARC-Tiny-v1.0-chat.pt (from this repo) via the in-app model picker — the app supports both formats and prefers safetensors. A prebuilt Windows installer is available on request / from the project's other release channels.
Citation
bibtex
1@misc{dissanayake2026narctiny,
2 title = {NARC Tiny v1.0: A 124M chat language model trained from scratch},
3 author = {Dissanayake, Madushan Bhashana},
4 year = {2026},
5 howpublished = {\url{https://huggingface.co/Madushan996/NARC_Tiny_v1.0}}
6}
License
Apache-2.0. Trained on FineWeb-Edu (ODC-By) and SmolTalk (Apache-2.0); please observe those dataset licenses. Model outputs are provided without warranty.
Built from scratch as a learning project — pretraining builds capability, instruction tuning shapes behavior. Every frontier model is this same loop with more zeros.