~/satyajit

Nemotron 3.5 Bolt E4B: Gemma 4 E4B, retrained for talking robots, in a 4GB file that weighs 6.18 GB

mdjsonmcp

2026-10-24 · 22 min · small-models · on-device · tool-calling · voice-agents · gguf · quantization · nvidia

A 1:45 narrated explainer, drawn in code. Every number and picture in it is this article's own; the sources are below.

› transcript

Hi, I'm Jib! NVIDIA's new small model talks, calls tools and drives a robot. Why does a four gig model ship as a six gig file? Bolt keeps Gemma's architecture and retrains the text weights with reinforcement learning. Its biggest table is only looked up, so it can stay out of graphics memory. No supervised stage at all. Start from Google's Gemma, unchanged. Train every prompt with thinking on and off, mostly off. Penalise long answers, in cycles, so the voice stays short. Then quantize to four bits. A token becomes an embedding and climbs forty two decoder layers. Gemma's small models add a second table: a small vector per token, for every layer. The token id just picks one row. A lookup, not a matrix multiply. Each layer gates its slice and adds it in. So the table can live in ordinary memory. In the four bit file, the computing parts come to about three point one seven gigabytes. The lookup table is another three, kept on the CPU. Every sixth layer attends to the whole context. Those are the layers whose cache grows. The last eighteen layers borrow keys and values from earlier ones, so only twenty four keep a cache. Bolt gains a lot on instructions and personas. On long multi turn tool tasks, Qwen still leads by twenty points. So the four gigabytes is graphics memory. The lookup table is the other half of the file. Gemma's skeleton, retrained. A table on the CPU. A cache only twenty four layers deep. Every source is in the full article. I'm Jib. Bye!

Why read this

Notabletop 60%

Headers show Bolt is Gemma 4 E4B with new text weights; a CPU run measures where the '4GB' file's bytes go and shows real outputs.

  • Original analysis
  • Runs on a consumer GPU
  • Widely used

LLM architectureOpenMDW-1.1Practitioner model

How this was scored
Is it new?
1 of 3: An incremental tweak
Can I trust it?
2 of 3: Measures key facts from files, code or configs
Can I run it?
2 of 3: Open code or weights with real limits
Will I understand it?
2 of 3: Mechanism from first principles with figures
Can I act on it?
2 of 3: A concrete recipe, numbers or comparison
Will it last?
1 of 3: Relevant for months
Does it affect many?
2 of 3: A widely used model, tool or lab release
Only here?
2 of 3: A teardown or measurement few others did

Score 63 of 100, ranked 282 of 607 rated articles. Each question is answered 0–3 by hand, and a 3 is rare. How articles are scored

On 2026-10-23 NVIDIA posted: "Available now: NVIDIA Nemotron 3.5 Bolt E4B 4GB. Our newest small open model is built for local assistants, interactive characters and robots that can carry on a conversation and use tools to get things done." The clip shows a Reachy Mini robot chatting and moving, "with Bolt handling conversation and NVIDIA Cosmos handling vision. Both models run locally on Jetson Orin Nano 8GB."

Unsloth reposted it with three claims of its own: the model "runs locally on 6GB RAM", it was "Trained on Gemma 4", and "it supports vision".

Each is half right. I read the primary sources: NVIDIA's blog post, the 18-page technical report, both model cards, and the files themselves. I read the safetensors and GGUF headers by HTTP range request (a few MB instead of 22 GB), compared byte ranges of individual tensors against Google's Gemma-4-E4B-it, and rendered NVIDIA's chat template to see the exact tool-call wire format. Then I ran one quant on a CPU, with llama.cpp, to check the memory claims and to see what the model actually says.

Numbers are labelled measured (I counted or read it from a file), reported (NVIDIA or Unsloth says so; I did not re-run it) or reasoned (my arithmetic on the other two).

A white Reachy Mini robot with two round camera eyes on a table, with an inset showing the robot's camera view and a caption reading: NVIDIA Cosmos supplies real-time vision, Bolt E4B triggers animations and responds.
Reachy Mini on a Jetson Orin Nano 8GB: Cosmos 3 Edge watches, Bolt E4B talks and calls the robot's animation scripts. A single frame of NVIDIA's demo GIF (NVIDIA Nemotron 3.5 Bolt E4B 4GB blog, demo animation).

What I ran, and what I still could not

I ran Unsloth's UD-Q4_K_XL GGUF (4,758,125,760 bytes, SHA-256 checked against the Hub) with its mmproj-Q8_0 vision projector. I used llama.cpp built from source at commit 7894e8b, CPU only. The machine is a shared cloud VM with 4 vCPUs (Intel Xeon @ 2.10GHz) and no GPU. I used 2 threads at the lowest scheduling priority, while other jobs kept the load average between 6 and 12. Every speed below is therefore a floor, not a benchmark of the model. The results are in "What it does on a CPU" below.

What I still could not do:

nvidia/NVIDIA-Nemotron-3.5-Bolt-E4B-BF16@49843ee · snapshot 2026-10-24
announced
8B (4B effective)
measured
7,996,156,490
parameters
8.00B
repo size
16.06 GB
architecture
Gemma4ForConditionalGeneration
task
text-generation
library
transformers
license
other
safetensors
2 shards
largest file
15.88 GB
files
18
downloads
249
likes
24
languages
en, ar, bg, cs, da, de
parameters by dtype
BF168.00B
nvidiapytorchnemotron-3.5

Gemma4ForConditionalGeneration, unchanged from Gemma-4-E4B-it except a 65,536-token position limit. Text weights retrained with RL; vision and audio towers carried over. Licence OpenMDW-1.1.

repo last modified 2026-10-23

"Trained on Gemma 4" means: the same model, with new text weights

Distilled from Gemma 4 into a new architecture, fine-tuned from it, or trained on its outputs? The files answer this.

The report fills in the rest. Bolt is "further post-trained from Gemma4-E4B-it with multi-environment RLVR and RLHF" (reported), on NeMo-RL and NeMo-Gym, with 256 prompts per batch and 8 rollouts each. The environments cover tool calling, instruction following and hierarchy, structured outputs and a generative reward model.

There was deliberately no SFT stage. NVIDIA tried SFT on its own post-training data first. Tool calling improved, but "SFT on data from diverse teachers resulted in a regression on conversational qualities and verbosity" (reported). So: a Gemma 4 E4B, retrained with RL, text side only.

Two choices fit the use case. Every prompt was trained with thinking on and off, at a "deliberate 2 : 1" non-reasoning to reasoning ratio. And because RL made answers longer, NVIDIA added length penalties and cycled them tighter and looser "as the training progressed" (reported).

What "E4B" means: per-layer embeddings

Gemma's card defines it: "The 'E' in E2B and E4B stands for 'effective' parameters." The small Gemmas use per-layer embeddings (PLE). An ordinary model gives each token one embedding vector at the bottom of the stack. PLE also gives each token a small extra vector for every layer, fetched from a separate table and fed into that layer.

Here are the shapes, from Bolt's config.json and safetensors header (measured):

Why this is cheap at run time: the table is only ever indexed. A forward pass reads one 10,752-number row per token, never the whole 2.8B-parameter table. It can sit in slow memory, or on flash.

Summing the BF16 header (measured):

PartParameters
Decoder layers (attention, MLP, per-layer gates)3.946B
Per-layer embedding table2.819B
Token embedding (tied to the LM head)0.671B
Audio tower0.309B
Vision tower0.169B
Per-layer model projection0.028B
Main file total7.941B
Frozen shared-KV side file0.055B

Remove the PLE table and the two encoders and 4.64B remain. Remove the token embedding too and 3.97B remain (reasoned). Google's card calls E4B "4.5B effective (8B with embeddings)", and Bolt's card says "8B (4B effective)". Both are rounding the same thing: the parameters that do arithmetic for every token. The 4 in "E4B" is not a quantization level, and it is not the "4GB".

The "4GB" file is 6.18 GB, and both numbers are honest

NVIDIA's GGUF repo is called NVIDIA-Nemotron-3.5-Bolt-E4B-4GB. Its one model file, Nemotron-3.5-Bolt-E4B-Q4_K_M.gguf, is 6,180,446,208 bytes (measured). I parsed its header (measured):

So the parts that compute come to about 3.17 GB, and the part that is only looked up is another 3.0 GB (reasoned). The lookup part is what llama.cpp moves aside. In llama.cpp's src/llama-arch.cpp, LLM_TENSOR_PER_LAYER_TOKEN_EMBD is registered as LLM_TENSOR_LAYER_INPUT with op GGML_OP_GET_ROWS. In src/llama-model.cpp, input-layer tensors go to dev_input = { cpu_dev, … } (measured, read from llama.cpp master on 2026-10-24). With every layer offloaded to a GPU, the table stays in host memory and only the rows the batch needs are gathered.

That reconciles the claims:

The widget below adds up the same numbers. Switch between GPU offload and CPU-only, drag the context, and turn off KV sharing to see what the 18 shared layers save.

Why the cache stays small: 18 layers borrow their keys

The 54 tensors moved to the side file are the KV projections of layers 24 to 41. num_kv_shared_layers is 18, so the last 18 layers do not compute keys and values. They reuse the cache of the last earlier layer of the same attention type. The weights exist in Google's checkpoint, but they are never used, and NVIDIA marked them "frozen" and set them apart. Only 24 layers own a cache.

Of those 24, every sixth is full attention: layers 5, 11, 17 and 23. Their KV uses 2 heads of dimension 512, so 4,096 bytes per token per layer in F16. The other 20 are sliding-window layers with a 512-token window and 2 heads of dimension 256. Their cache stops growing at 512 tokens, at about 21 MB in total. At the full 65,536-token context that comes to 1.09 GB of KV. Without sharing (7 full and 35 sliding layers) it would be 1.92 GB, about 43% more (reasoned from config.json).

The tool-call format is not JSON

Bolt keeps Gemma 4's chat format and adds two things to the template. I rendered NVIDIA's chat_template.jinja with a sandboxed Jinja for one tool turn, with conversational_mode on and thinking off (measured: this is the template's output, not the model's):

<bos><|turn>system
You are Jib, a desk robot.
 
You are having a spoken conversation with the user. Respond as briefly as possible while still addressing their questions fully.<|tool>declaration:set_light{description:<|"|>Turn a room light on or off<|"|>,parameters:{properties:{on:{type:<|"|>BOOLEAN<|"|>},room:{type:<|"|>STRING<|"|>}},required:[<|"|>room<|"|>,<|"|>on<|"|>],type:<|"|>OBJECT<|"|>}}<tool|><turn|>
<|turn>user
Kitchen lights off, please.<turn|>
<|turn>model
<|tool_call>call:set_light{on:false,room:<|"|>kitchen<|"|>}<tool_call|><|tool_response>response:set_light{value:<|"|>{"ok": true}<|"|>}<tool_response|>

Three things to notice:

What it does on a CPU

Everything in this section is measured by me on the machine described above, using Unsloth's UD-Q4_K_XL file. The model outputs are quoted verbatim and trimmed only where marked. They were generated on a CPU VM at the card's recommended sampling (temperature 1.0, top-p 0.95) with seed 7. They are single samples, not curated ones.

What is in the file

Unsloth's layout differs from NVIDIA's. I read it with llama.cpp's gguf-py. The per-layer table per_layer_token_embd is IQ4_NL at 1.585 GB, where NVIDIA uses Q8_0. token_embd is Q4_K at 0.377 GB, and everything else comes to 2.779 GB. The parts that compute therefore total 3.156 GB, almost the same as in NVIDIA's file. Unsloth saved its 1.4 GB on the lookup table.

Speed

llama-bench with 2 threads gave 30.77 ± 12.21 tokens/s for a 512-token prompt and 2.46 ± 0.37 tokens/s for generation. The wide error bars come from the other tenants on the machine. Through llama-server, short prompts were processed at 10 to 22 tokens/s and generation ran at 1.5 to 3.1 tokens/s. A 15,520-token prompt took 539.2 s to process (28.79 tokens/s), so a 16K-context question costs about nine minutes before the first word. On two shared vCPUs you can talk to it, slowly.

Memory: three different numbers

ConfigurationPeak RSSFile-backedAnonymousActually touched
Defaults, 4K context, after 3 chats8.20 GB4.76 GB3.41 GBn/a
Defaults, 16K context, after a 15,520-token prompt8.54 GB4.76 GB3.78 GB3.61 GB anon + 0.06 GB of file
--no-repack, 4K context, after 3 chats5.03 GB4.76 GB0.27 GB3.14 GB of file
--no-repack + mmproj, 4K, after an image6.13 GB4.76 GB1.37 GBn/a

RSS comes from /proc/<pid>/status. "Actually touched" is the Referenced total from /proc/<pid>/smaps, after clearing the bits with /proc/<pid>/clear_refs before the run.

What the table shows:

So "runs on 6GB RAM" holds for the working set, and for RSS with --no-repack (5.03 GB). It does not hold for llama.cpp's default RSS. A phone OS that kills an app by its resident size will see the larger number. --no-repack did not slow generation here: the same three chats ran at 2.3 to 3.1 tokens/s without it and 1.5 to 2.0 with it, but the load noise on this VM is larger than any difference repacking makes.

Three chats

With conversational_mode on and thinking off, system prompt "You are Jib, a small desk robot that talks with people in an office.", I asked: "Hey Jib, I have a meeting in ten minutes and I haven't eaten. Quick idea?"

Grab a protein bar. Quick energy.

That is nine tokens, which is the brevity training doing its job. The same prompt without repacking (a different run, same seed) gave "Grab a protein bar or some nuts. Quick energy."

With thinking off, I asked about the topic of this article: "In two sentences: why does a GPU need less memory for a model whose embedding table stays on the CPU?"

The GPU does not need to store the entire embedding table because it only needs memory for the active parts of the model and intermediate computations. The CPU handles the larger embedding table, transferring only the necessary lookups to the GPU as needed for forward and backward passes.

Right in outline; "backward passes" is wrong for inference.

With thinking on, I asked: "A shop sells pens at 3 for $2. How much do 15 pens cost? Answer with the number only." The reasoning (trimmed):

2.  **Find how many groups of 3 are in 15 pens:** $15 / 3 = 5$ groups.
3.  **Calculate the total cost:** 5 groups * $2/group = $10.
 
The answer should be the number only.

The answer: 10. That took 116 tokens in total, reasoning included.

One tool call

I sent the set_light tool from the template section through llama-server's OpenAI endpoint (--jinja), with conversational mode on and thinking off. The system prompt was "You are Jib, a desk robot that controls the office lights." and the user said "Kitchen lights off, please." The raw text the model generated, read from /completion on the same rendered prompt:

<|tool_call>call:set_light{on:false,room:<|"|>Kitchen<|"|>}<tool_call|>

That is exactly the Gemma 4 format, followed by end-of-turn. llama.cpp parsed it into a standard OpenAI tool call:

[{"type": "function", "function": {"name": "set_light", "arguments": "{\"on\":false,\"room\":\"Kitchen\"}"}, "id": "HV2BrvJuN00EiOvSAeD4WGVeSwQ9Cjwj"}]

The call parses. The arguments are valid JSON, both required keys are present, and on is a real boolean. The model capitalised "Kitchen", which a strict enum would reject.

The second turn surprised me. After I sent back the tool result {"ok": true}, the model ended its turn with no text in 3 of 4 samples (seeds 7, 2 and 3). Seed 1 said Done.. For a voice robot, silence after an action may be fine. For a chat UI, plan to say "done" yourself.

One image

With Unsloth's Q8_0 projector, I sent NASA's public-domain Apollo 17 "Blue Marble" photograph (AS17-148-22727, 1280 × 1280) with thinking off and the prompt "What is in this image? Two sentences." The image and prompt came to 749 prompt tokens, processed in 65.6 s. The reply:

This image is a view of the Earth from space, centered over Africa and parts of Eurasia. It shows landmasses like the Sahara Desert and the African continent surrounded by oceans and white clouds.

That is correct: the photograph shows Africa, Arabia and Madagascar under cloud. The retrained language model still reads Google's unchanged vision encoder well enough for a caption. The report's MMMU-Pro drop is about harder questions than this. With the projector loaded and repacking off, peak RSS was 6.13 GB.

Vision: in the checkpoint, not in the training

Is Unsloth's "it supports vision" true? It depends on which file you download.

NVIDIA measured what that costs. "Although the model was trained text-only", the report says, audio got better and vision got worse (reported, Table 8, reasoning mode): VoiceBench 80.30 against Gemma's 78.20, but MMMU-Pro Vision 42.02 against 47.63, and OmniDocBench 1.5 error 0.42 against 0.21. NVIDIA blames "misalignment between the vision encoder and the language model introduced by text-only training". It tried retraining the encoder alone and "observed no meaningful improvements". The Reachy demo does not use Bolt's eyes at all: Cosmos 3 Edge does the seeing.

Benchmarks: a clear win on instruction and persona, not on agents

NVIDIA picked 21 benchmarks in five groups and ran them all in its own NeMo Gym harness, with Gemma 4 E4B, Qwen3.5-4B and its own Nemotron 3 Nano 4B as baselines. Here are the BF16 rows that move the most (reported, card and report Table 3):

BenchmarkBolt E4BGemma 4 E4BQwen3.5 4B
IFBench63.7942.8458.91
IHEval (instruction hierarchy)84.7967.0460.57
RoleBench (custom win %)67.0549.9553.66
MultiChallenge53.1042.0851.76
GaRAGe42.6134.7324.66
Tau2-Bench55.1038.5075.06
LongBench v2 (48K)50.5049.3459.93
RULER (64K)86.9986.5595.15
EQ-Bench v339.4041.1732.92

My arithmetic on the full 21-row table (reasoned):

A thread in the replies credited Bolt with "MultiChallenge: 56.03%" and "Instruction retention: 76.8%". Neither number is on the card or in the report, so I cannot check them.

Scatter of benchmark average against time to first token. Nemotron 3.5 Bolt E4B 4GB sits at 70.2 near 290 ms, above Gemma 4 E4B at 63.2 and Qwen 3.5 4B at 59.1, with larger models Gemma 4 26B-A4B at 72.8 and Qwen 3.8 27B at 67.0 further right.
NVIDIA's headline chart: a six-benchmark average against time to first token, Q4_K_M on an RTX 5090 at about 3,000 input and 50 output tokens. The six benchmarks are a subset that suits Bolt; the full 21-row average is closer (NVIDIA Nemotron 3.5 Bolt E4B 4GB technical report, Figure 1).

That chart averages only MultiChallenge, RoleMRC, BFCL-v3, IHEval, SysBench and RelyToolBench, so Bolt scores 70.2 against Gemma's 63.2. It leaves out Tau2-Bench and the long-context rows, where Qwen leads. The second chart is the one I find more useful. It shows the length penalties working:

Scatter of average accuracy against mean output tokens on a log scale. Bolt reasoning at 63.9% with 672 tokens, Bolt non-reasoning at 57.3% with 210 tokens, Gemma4-E4B-it 58.1% at 782 tokens, Qwen3.5-4B 57.8% at 3,604 tokens.
Average over all 21 benchmarks against mean output tokens. Qwen3.5-4B with reasoning averages 3,604 tokens; Bolt averages 672 (NVIDIA Nemotron 3.5 Bolt E4B 4GB technical report, Figure 2).

Bolt with thinking off (57.3% at 210 tokens) is about level with Gemma 4 E4B with thinking on (58.1% at 782 tokens). The "up to ~80% fewer tokens" claim is 672 against Qwen's 3,604, which is 81% fewer (reasoned). For a voice agent, those are the tokens the user sits through.

Speed numbers, all NVIDIA's

On a Jetson Orin Nano 8GB, NVIDIA reports 4.2 GB of VRAM, a 5,785 ms time to first token and 15.5 tokens/s for a 3K-token prompt. With 32K cached and 2K new tokens it reports 4.9 GB, 6,259 ms and 13.0 tokens/s (reported, llama.cpp CUDA, Q4_K_M). Nearly six seconds before the first token is long for a robot that is supposed to chat. The report does not say how the Reachy demo hides it.

The release also ships a five-layer, 360M-parameter DFlash drafter (see DFlash2). NVIDIA reports 1.21× the throughput of Gemma's own MTP drafter on an RTX 5070 (reported).

Licence: OpenMDW, over an Apache base

Bolt's weights are under the OpenMDW License 1.1, not the NVIDIA Open Model License. OpenMDW is permissive: keep the notices, lose your rights if you sue over patents or copyright, and there are no conditions on outputs. Gemma 4, which Bolt was "post-trained on", is Apache 2.0. Its vision and audio towers ship unchanged, so if you redistribute Unsloth's mmproj you are redistributing Apache-2.0 weights. That is my reading, not legal advice.

Where it fits

If you were going to run Gemma 4 E4B for an assistant, character or robot, Bolt is a drop-in swap. It has the same architecture, the same runtime support and the same memory. In NVIDIA's own harness it follows system prompts and personas much better and says less. If your agent mostly runs long multi-step tool tasks, the card's Tau2 and ToolSandbox rows say Qwen3.5-4B is still the better 4B. If you need the model to see, keep Gemma 4 E4B, or give the eyes to a separate model, as the Reachy demo does.

For background, see the parent's KV-cache design in Gemma 4, NVIDIA's large sibling in Nemotron 3.5 Super VL, and the voice-agent plumbing that already runs on Reachy Mini in speech-to-speech. On a CPU it works, slowly. It answers briefly, calls tools in clean Gemma format, finds a needle at 15K tokens and captions a photo. Pass --no-repack if resident memory is your budget: the lookup table costs almost nothing to run, but the default loader still holds every byte of it.

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "Nemotron 3.5 Bolt E4B: Gemma 4 E4B, retrained for talking robots, in a 4GB file that weighs 6.18 GB", ai.thesatyajit.com, October 2026.

bibtex
@misc{ghana2026nemotron35bolt,
  author = {Satyajit Ghana},
  title  = {Nemotron 3.5 Bolt E4B: Gemma 4 E4B, retrained for talking robots, in a 4GB file that weighs 6.18 GB},
  url    = {https://ai.thesatyajit.com/articles/nemotron-3-5-bolt},
  year   = {2026}
}
share