Blog

Introducing Nandi-Mini-150M

A 150-million-parameter foundation model, pre-trained from scratch on English and ten Indic languages. Sixteen layers of weights, thirty-two layers of depth.

Nandi-Mini-150M: sixteen shared layers, each looped twice, beside the words Nandi-Mini-150M
Nandi-Mini-150M reuses 16 layers of weights to reach 32 layers of depth.

A small model has a small budget, and every parameter in it has to earn its place. Nandi-Mini-150M was designed around that constraint from the first line of code, then pre-trained from scratch on more than 500 billion tokens of English and ten Indic languages.

It is a foundation model with open weights under Apache 2.0, built for the places large models cannot go: edge devices, on-premises servers, and anywhere latency and memory are measured in small numbers.

Three ideas make it what it is: layers that are reused, an embedding table that is factored, and a tokenizer built for Indic scripts first. This post walks through each one, with the numbers.

Overview

A Foundation Model for Small Hardware

Nandi-Mini-150M is a decoder-only Transformer trained from scratch, with no borrowed weights. It is the base of the Nandi-Mini family.

150Mparameters

pre-trained from scratch, with 307 MB of bf16 weights

32effective layers

from 16 physical layers, each run twice

131Kvocabulary

131,072 tokens, tuned for Indic scripts

11languages

English plus ten Indic languages

SpecValue
ArchitectureDecoder-only Transformer
Layers16 physical layers, shared across 2 repeats (32 effective)
Hidden size832
AttentionGrouped-query: 16 query heads, 4 key-value heads, head dimension 52
Feed-forwardSwiGLU, intermediate size 2,496
NormalizationRMSNorm, pre-norm, no biases
PositionsRoPE, base 100,000
EmbeddingsFactorized (rank 196), input and output tied
Vocabulary131,072 tokens
Context length2,048 tokens
Pre-trainingMore than 500B tokens
LanguagesEnglish, Hindi, Bengali, Tamil, Telugu, Marathi, Gujarati, Kannada, Malayalam, Punjabi, Odia
LicenseApache 2.0

Head dimension is hidden size divided by head count. Source: the Nandi-Mini-150M model card and its config.

Architecture

The Architecture at a Glance

Here is the whole model in one picture, read from the bottom up: tokens enter at the bottom, pass through the shared blocks, and leave as next-token probabilities at the top. The two side panels zoom in on the parts that make Nandi-Mini different.

Figure · Nandi-Mini-150M Decoder Stack

Next-token probabilitiesOutput head, tied embedding196 → 131,072Linear · 832 → 196Final RMSNormTransformer block × 16RMSNormGrouped-Query Attention16 query heads · 4 KV heads · RoPERMSNormSwiGLU feed-forward832 → 2,496 → 832Linear · 196 → 832Embedding table, 131,072 × 196factorized, shared with the output headToken IDsrunstwiceZoom: grouped-query attention16 query heads4 KV headsK, V · 0K, V · 1K, V · 2K, V · 3Four query headsshare each K, V pair.Head dimension 52 · RoPE base 100,000 · context 2,048KV cache is 4× smaller than full multi-head attention.Zoom: layer sharingLayer ione set of weightspass 1, then pass 2Layer i + 1same pattern16 stored layers, 32 effective. No parameters added per pass.Each pass keeps its own KV-cache slots.AttentionFeed-forwardWhere Nandi-Mini differs
Nandi-Mini-150M, drawn from its published config. Copper marks where it differs from a conventional decoder: the factorized, tied embedding and the layer that runs twice.

Depth

Sixteen Layers, Thirty-Two Deep

Depth is what lets a Transformer refine its understanding: early layers settle which words are present, later layers settle what they mean together. But depth is paid for in parameters, and at 150 million there is not much to spend.

Nandi-Mini spends the same weights twice. The model stores 16 decoder layers. Each one is applied two times in a row before the signal moves on to the next, so every token passes through 32 layers of computation while the model stores only 16 layers of weights.

One way to picture it: the first pass writes a rough reading of each token in context, and the second pass, using the very same weights, reads that draft and sharpens it. There are no extra per-repeat parameters. The second pass uses the same attention, the same feed-forward and the same norms.

Figure 1 · Weights Reused, Depth Kept

A conventional 32-layer model32 layers, 32 sets of weights, about 281M parametersNandi-Mini-150M: 16 layers, each one run twice16 layers, 16 sets of weights, 32 layers of depth, about 153M parametersWhat the forward pass doesL0L0′L1L1′L2L2′…L15L15′L0′ is L0 again: same weights
Layer sharing in Nandi-Mini-150M. Every layer runs twice before the next one starts. Parameter counts are our arithmetic from the published config: about 281M for 32 distinct layers at this width, about 153M as built.

By that arithmetic, a conventional 32-layer model of this width would carry about 281 million parameters. Nandi-Mini carries about 153 million. That is the difference between a 560 MB download and a 307 MB one.

Sharing saves parameters, not compute. A shared layer still does its work every time it runs, so each token costs about as much as in a 32-layer model of the same width, and each repeat keeps its own key-value cache slots. What you gain is a smaller model to store, download, load into memory and fine-tune.

Embeddings

A Big Vocabulary Without the Weight

A vocabulary of 131,072 tokens is generous. It is how Nandi-Mini fits ten Indic scripts without shredding them, as the language results below show. But a vocabulary has a cost. A plain embedding table at the model's width of 832 would hold 131,072 × 832 parameters, about 109 million, nearly as many as the entire 16-layer stack at about 127 million.

So the table is factored. Tokens are looked up in a narrow table of width 196, and a small linear layer lifts them to 832 to enter the blocks. On the way out the model does the reverse: a projection down to 196, then the same table read backwards to produce the logits. Input and output share one table.

Figure 2 · One Narrow Table, Used Twice

Token ID1 of 131,072Embedding Table131,072 × 19625.7M parametersUp-Projection196 → 8320.16MShared Blocks16 layers × 2127.4MDown-Projection832 → 1960.16MOutput Headtable read backno new weightsOne table, shared by the input and the output
Factorized, tied embeddings. The table is narrow, the projections are small, and the output head reuses the table, so it adds no new weights.

The table drops from about 109M parameters to about 26M, and the two projections add 0.3M. That returns roughly 83M parameters to the part of the model that thinks.

Figure 3 · Where the Parameters Go

Nandi-Mini-150M as built16 shared layers · 127.4Mabout 153M in totalWith a full-width tied embedding (832 wide)16 shared layers · 127.4Mtable · 109.1M26MRoughly 83M parameters freed for the layers that do the thinking. A full-width table would total about 236M.
Parameter budget with and without factorized embeddings. Block parameters are computed from the config: 7.96M per layer across 16 layers. Our arithmetic, not a measured breakdown.

Block

The Rest of the Block

Around those two ideas sits a deliberately conventional core, chosen because it is well understood and fast on common hardware.

Attention

Grouped-Query

16 query heads share 4 key-value heads, a cache 4× smaller than full multi-head attention at the same head count.

Feed-forward

SwiGLU

A gated feed-forward layer, 832 wide in and 2,496 in the middle, with no bias terms.

Stability and position

RMSNorm and RoPE

Pre-norm blocks with RMSNorm, and rotary positions with a base of 100,000 across a 2,048-token window.

Languages

Built for Indic Scripts From the First Token

A tokenizer decides how much of your context window a sentence uses. A vocabulary trained mostly on English breaks Indic scripts into many small fragments, so the same Telugu word that costs one or two tokens in a purpose-built vocabulary can cost a dozen or more elsewhere. Every extra token is slower, costlier and takes room from a context window that, at 2,048 tokens, is already short.

Nandi-Mini's tokenizer was built for English and ten Indic languages together. Measured as tokens per word, Qwen3-0.6B-Base needs between 3.9× (Hindi) and 7.6× (Telugu) as many tokens as Nandi-Mini across the Indic languages we measured.

Figure 4 · Tokens Per Word, 12 Languages

Qwen3-0.6B-BaseNandi-Mini-150MTokens per word · lower is betterOdia15.752.68Malayalam14.562.05Telugu13.381.77Kannada12.961.90Tamil10.932.05Gujarati9.371.53Punjabi8.661.42Assamese8.131.51Bengali7.511.44Marathi6.701.55Hindi5.141.32English1.161.18
Tokenization fertility, tokens per word. Lower means shorter sequences for the same text. Full comparison with SmolLM3-3B and Sarvam-1 in the table below.

In practical terms, 2,048 tokens hold about 153 Telugu words under Qwen3's tokenizer and about 1,157 under Nandi-Mini's.

Against Sarvam-1, a tokenizer also built for Indic languages, Nandi-Mini is ahead on nine of twelve languages including English, level on Marathi, and behind on Hindi (1.32 against 1.25) and Odia (2.68 against 2.18). Assamese, at 1.51, is the widest gap in our favor.

Tokens per word by language and tokenizer
LanguageSmolLM3-3BQwen3-0.6B-BaseSarvam-1Nandi-Mini-150M
English1.171.161.321.18
Hindi2.715.141.251.32
Bengali8.667.511.551.44
Gujarati10.479.371.551.53
Kannada16.4312.962.101.90
Malayalam17.7714.562.492.05
Marathi3.736.701.551.55
Odia19.0715.752.182.68
Punjabi9.238.661.471.42
Tamil13.5610.932.062.05
Telugu15.4013.382.091.77
Assamese9.268.134.311.51

Tokens per word, lower is better. Best in each row in bold. Source: the Nandi-Mini-150M model card.

Results

What 500 Billion Tokens Buy

We compared Nandi-Mini-150M with the models closest to it in size, using the same lm-eval setup for every row. Mobile-LLM figures come from its paper, because those checkpoints are not public, so it appears only in the full table. GSM8K and HumanEval use greedy decoding. No benchmark-specific tricks went into these numbers.

Figure · The 150M Class, Benchmark by Benchmark

SmolLM-135MSmolLM2-135MNandi-Mini-150MHellaSwag42.6643.1337.20Winogrande53.0353.2752.32GPQA25.4422.0928.57MMLU25.3024.0928.86GSM8K1.361.742.58HumanEval0.000.004.27Average24.6324.0525.63
Benchmark scores for the 150M class, one panel per benchmark. Each panel has its own scale, so bars are comparable within a panel, not across panels. Best score in each panel in bold.
Show the full table
Benchmarks for the 150M class
ModelTokens (B)HellaSwagWinograndeGPQAMMLUGSM8KHumanEvalAvg.
Mobile-LLM-125M1,00038.9053.10—————
SmolLM-135M-Base60042.6653.0325.4425.301.360.0024.63
SmolLM2-135M-Base2,00043.1353.2722.0924.091.740.0024.05
Nandi-Mini-150M-Base50037.2052.3228.5728.862.584.2725.63

Nandi-Mini-150M leads its class on average (25.63, against 24.63 and 24.05) and on GPQA, MMLU, GSM8K and HumanEval, using 500B tokens where SmolLM2-135M saw 2 trillion. The commonsense tasks go the other way: SmolLM-135M and SmolLM2-135M score about 5 points higher on HellaSwag. And at this size math and code are barely awake, with GSM8K at 2.58 and HumanEval at 4.27. These are base-model numbers, a starting point for fine-tuning rather than a finished assistant.

Fine-Tuned for Hindi

A base model earns its keep when you adapt it. We fine-tuned each base model on CrossSum-Hindi, a summarization task from IndicGenBench, and scored it with chrF. Nandi-Mini-150M comes out on top, ahead of two models more than three times its size.

Figure · Hindi Summarization After Fine-Tuning

Nandi-Mini-150M150M parameters4.37Qwen-2-0.5B-Base500M parameters · 12T tokens4.22Qwen2.5-0.5B-Base500M parameters · 18T tokens4.18SmolLM2-360M-Base360M parameters3.51SmolLM-360M-Base360M parameters2.99SmolLM2-135M-Base135M parameters2.67SmolLM-135M-Base135M parameters2.55chrF after fine-tuning · higher is better
chrF after fine-tuning on CrossSum-Hindi (IndicGenBench). Absolute values are low for every model of this size on this task; the ranking is the signal. One fine-tuning task is not a full evaluation.

For Perspective

Larger models trained on far more data score higher on general benchmarks, and we show them here for the same reason we show the rest: so you can choose with the whole picture.

Figure · Against Larger Models

Qwen3-0.6B-Base600M parameters · 36T tokens39.58Qwen2.5-0.5B-Base500M parameters · 18T tokens35.86SmolLM2-360M-Base360M parameters · 4T tokens28.19Nandi-Mini-150M150M parameters · 0.5T tokens25.63Average of six benchmarks · higher is better
Average over the six benchmarks in the first chart. Source: the Nandi-Mini-150M model card.
Show the full table
Benchmarks against larger models
ModelParams (M)Tokens (B)MMLUGSM8KHumanEvalAvg.
SmolLM2-360M-Base3604,00025.552.880.0028.19
Qwen2.5-0.5B-Base50018,00047.414.7729.8735.86
Qwen3-0.6B-Base60036,00050.3415.3128.0439.58
Nandi-Mini-150M-Base15050028.862.584.2725.63

Family

The Nandi-Mini Family

Nandi-Mini-150M is the base of a growing family. Every model is on Hugging Face with open weights.

Base

Nandi-Mini-150M

The pre-trained foundation model described in this post.

In training

Nandi-Mini-600M

Early checkpoints of the 600M model are public while pre-training continues.

Roadmap

Nandi-Mini-500M and 1B

Base and Instruct versions of both are in pre-training.

The whole collection lives in the Nandi-Mini collection.

Run

Run It Yourself

The architecture is custom, so loading it needs trust_remote_code=True. Everything else is standard Hugging Face.

# pip install transformers==5.4.0
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_name = "FrontiersMind/Nandi-Mini-150M"
device = "cuda" if torch.cuda.is_available() else "cpu"

tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
    model_name, trust_remote_code=True, dtype=torch.bfloat16
).to(device).eval()

inputs = tokenizer(["The night was quiet and the streets were empty."],
                   return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True,
                         temperature=0.3, top_k=20, top_p=0.95,
                         repetition_penalty=1.1)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

For serving, Nandi-Mini-150M runs on vLLM and SGLang with OpenAI-compatible endpoints, and on Docker Model Runner with one command:

docker model run hf.co/FrontiersMind/Nandi-Mini-150M

The exact serving commands are on the model card.

Fit

Where Nandi-Mini Fits

Reach for Nandi-Mini-150M when the constraint is the hardware: an edge device, an on-premises server, a latency budget measured in milliseconds, or a workload in an Indic language where a larger model's tokenizer wastes most of your context. It is a strong place to start a fine-tune, because the base is small enough to adapt quickly and cheaply, and the data and the weights never have to leave your infrastructure.

Know its edges. It is a base model, so it continues text rather than following instructions; use the Instruct or Tool-Calling releases, or fine-tune. Its context window is 2,048 tokens. Its math and code scores are low, as expected at 150 million parameters. And on general benchmarks, models many times its size trained on far more data are ahead.

The Takeaway

Nandi-Mini-150M is a small model with a design behind it: layers that run twice, an embedding table that does double duty, and a tokenizer that treats Indic languages as first-class. It was trained from scratch, it is open, and you can run it on hardware you own. That is where Sovereign Superintelligence starts.