~/satyajit

llama-modchip: a 284B MoE in 64 GB of RAM, and what actually makes it fit

mdjsonmcp

2026-11-12 · 25 min · mixture-of-experts · quantization · inference · on-device · gguf · llama-cpp · deepseek

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

› transcript

A two hundred and eighty-four billion parameter model. Sixty-four gigabytes of RAM. No graphics card. So where do the weights that don't fit go? Hi, I'm Bexley! I expected a trick with the disk. There isn't one. Let's count the bytes. Chapter one. Two different sizes. DeepSeek V4 Flash has forty-three layers. In each, a router scores two hundred and fifty-six experts for every token. Only the top six run. The other two hundred and fifty stay idle, but any of them could be picked next token. A shared expert runs for everyone, and attention runs every time too. So the whole model has to fit in memory. But a token only reads a small slice of it. Those are two different numbers. I parsed the header of the default checkpoint. Fifty-six point nine three gibibytes, and routed experts are ninety-two point seven percent of it. One token reads six of two hundred and fifty-six slices per layer. That is one point three three gigabytes: a quarter of its reads. Attention is a few percent of the file, yet every token reads all of it: two point five four gigabytes. Add the shared expert and the output head, and one token pulls five point three six gigabytes through the memory bus. Start with the bytes: five point three six gigabytes per token. The README's desktop sustains about seventy-five gigabytes a second. Divide, and a token can't take less than seventy-one and a half milliseconds. That caps decoding at fourteen tokens a second. The README measures eight point seven five. Sixty-two percent of the ceiling, which is where tuned CPU inference usually lands. Chapter two. Why not stream the experts from disk? The obvious design maps the file and reads experts from an SSD on demand. At about seven gigabytes a second, with nothing cached, that is four point one tokens a second. This project does the opposite. Most expert weights go to a stock llama.cpp format at about one and a half bits, and the whole file stays in RAM. Chapter three. Three weights, seven bits. A three bit scalar quantizer gives each weight eight levels. Three weights then sit on a grid of five hundred and twelve points, evenly through a cube. Vector quantization snaps the triple as a unit, to a codebook of a hundred and twenty-eight points. That costs seven bits per three weights. A block holds sixty-four weights: a scale, twenty seven-bit indices, two short tail indices, and eight small sub-scales. That is a hundred and ninety-two bits, exactly three bits per weight. The whole codebook fits in six vector registers, so one instruction expands sixty-four bytes of indices without touching memory. Here is the formula. d is the block's scale, m is the sub-scale for its group of eight, and c is one coordinate of the codebook entry its index names. And here it runs: the Nemotron thirty B build, on a free eight-core cloud instance with thirty-two gigabytes and no GPU. The status bar shows an eight K context window. Short prompts only: a coding agent's long system prompt did not fit. The quality claims need a closer read. Ninety-nine point one five percent is one tensor, quantized and restored, from the thirty B model. It says nothing about the big model's answers. The big model never ran at full precision, so its divergence is measured against its own default build. And on the thirty B, every variant scores a hundred on the gate. A test everyone aces cannot rank them. The big model fits because its experts are squeezed to about one point six bits. Its speed is set by the layers every token reads. To recap. A token reads five point three six gigabytes, a quarter of it experts. Nothing streams. And vector quantization packs three weights into seven bits. Every source is in the full article. I'm Bexley. Bye!

Why read this

Essentialtop 10%

Counts every byte of the published GGUFs: the 284B fits on stock 1.56-bit experts, not VQ3, and dense layers, not experts, set its per-token bandwidth.

  • Analysis found nowhere else
  • Interactive explanations
  • Runs on a laptop CPU

Quantization & compressionApache-2.0Practitioner tool

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?
3 of 3: Mechanism carried by interactives built from real code or data
Can I act on it?
2 of 3: A concrete recipe, numbers or comparison
Will it last?
2 of 3: A reference for a year or more
Does it affect many?
2 of 3: A widely used model, tool or lab release
Only here?
3 of 3: The only place this analysis exists

Score 75 of 100, ranked 73 of 740 rated articles. Each question is answered 0–3 by hand, and a 3 is rare. How articles are scored

Two posts from the Chinese creator @mingzi206 landed on 12 November. The first introduced synchopate/llama-modchip, a patched llama.cpp, with the line "no GPU, 64 GB of RAM, a 284B model". It listed 56.9 GB for DeepSeek-V4, 9 to 14 tok/s, up to 25 tok/s with speculative decoding, 99.15% cosine similarity, a 13.3 GB 30B model that "runs on a 16 GB laptop", and 111 tok/s. Three hours later he quoted it with a video: "it really works. On a free 8-core, 32 GB CPU-only machine I got NVIDIA's modified Nemotron 30B-A3B VQ3-64 running."

The quoted post's run: Nemotron-3.5-30B-A3B in the VQ3-64 build, served from a ModelScope CPU instance with an 8K context, writing a Python snippet. Cut to 14 s of the 51 s original, no audio (video from @mingzi206's post on X).

A 284B model in 64 GB sounds like a trick with the disk: map the file, let the page cache hold the hot experts, read the rest from NVMe on demand. I expected that and went looking for the mmap path. There isn't one. The repo loads every weight into anonymous heap (--load-mode none --repack) and says "zero disk streaming" in so many words. The 284B fits for a duller reason, and finding it took reading the checkpoints rather than the README.

I did not run the code. I parsed the headers of seven GGUF files from three published checkpoints with HTTP range requests (a GGUF header lists every tensor's name, shape, type and byte offset, so sizes fall out of consecutive offsets) and counted bytes. Everything below that says "the header" comes from that.

Two different sizes: what a model holds, and what a token reads

A mixture-of-experts layer replaces one feed-forward block with many, plus a router. For each token the router scores every expert and runs the top few. DeepSeek-V4-Flash, per its config.json, has 43 layers, 256 routed experts per layer, one shared expert, and num_experts_per_tok: 6. Each expert is a SwiGLU block of width 2048 on a hidden size of 4096, so three matrices of 4096 x 2048:

3×4096×2048=25,165,824 parameters per expert3 \times 4096 \times 2048 = 25{,}165{,}824 \text{ parameters per expert} 25.17M×256×43=277.0B routed,25.17M×6×43=6.49B routed per token25.17\text{M} \times 256 \times 43 = 277.0\text{B routed}, \qquad 25.17\text{M} \times 6 \times 43 = 6.49\text{B routed per token}

The header agrees: 284.335B parameters in all, 277.025B of them in the ffn_*_exps tensors. Add attention, the shared expert, the output head and one embedding row, and a token touches 13.27B parameters, close to the 13.17B the README quotes.

Those two totals answer different questions. Total parameters set capacity: every expert must live somewhere you can reach in time, because the router may pick any of them next token. Active parameters set bandwidth: on a CPU, decoding one token is a sequence of matrix-vector products, each weight is read once and used for two flops, and no CPU has the memory bandwidth to make those flops the bottleneck. Time per token is, to first order, bytes read divided by bytes per second.

So two separate numbers decide whether a 284B model is usable on a desktop. Does the whole file fit in RAM? And how many bytes does one token pull through the memory bus?

Where the 56.93 GiB goes

The default 284B checkpoint is DeepSeek-V4-Flash-0731-MaxQ-Fractal, three shards totalling 61,129 MB, the README's 56.93 GiB. By tensor type, from the header:

TensorsFormatParametersOn diskBits per weight
routed experts, bulkIQ1_S225.5B41.02 GiB1.5625
routed experts, anchor layersIQ2_XXS34.4B8.25 GiB2.0625
routed experts, mid layersIQ1_M17.2B3.50 GiB1.75
attention and indexerFractal-64 (type 42)4.9B2.14 GiB3.75
shared expert, head, embeddings, attn_q_aQ6_K2.3B1.77 GiB6.5625
everything elseF32, BF16, Q8_0, I320.1B0.25 GiB

Routed experts are 92.7% of the file and average 1.64 bits per weight. The whole file averages 1.72. That is the answer to "how does 284B fit in 64 GB": 225.5B parameters at 1.5625 bits is 41 GiB, and nothing else is large.

IQ1_S, IQ1_M and IQ2_XXS are upstream llama.cpp formats, the same family Unsloth used for the UD-IQ1_S build the README itself lists at 76.87 GiB. What modchip adds for the 284B is choosing which layers get the 2-bit treatment, an importance weighting for the 1-bit ones (the MaxQ build uses @antirez's 1.5M-token importance matrix; an earlier build used a closed-form "SwiGLU-H2" weighting from the product of each gate and up row norm), and moving attention from Q8_0 to its own 3.75-bit Fractal-64. The README credits the re-quantized experts and the attention transcode together with taking the Unsloth build from 76.87 GiB to 56.56 GiB. The attention part is the smaller share: 4.9B parameters at Q8_0's 8.5 bits are about 4.85 GiB against 2.14 GiB now, so roughly 2.7 of the 20.31 GiB saved. The rest came out of the experts.

The format the repo is named for, LUT-VQ3-64 (GGML_TYPE_VQ3_0 = 43), does not appear in the MaxQ header. Not one tensor of type 43. Per the README it ships in the separate 56.40 GiB "VQ3" 284B build, on 68 shared-expert matrices (I did not parse that one), and in the Nemotron 30B, where the header shows it. The post that credits VQ3 with the 284B result has the cause wrong.

What a token reads

Capacity explains the fit. Speed needs the second number. Per token, the runtime reads every non-routed tensor once, one row of the embedding table, and 6 of 256 slices of each routed tensor. Applying that to the header's byte counts:

Part of the MaxQ checkpointShare of the fileRead per tokenShare of a token's reads
routed experts92.7%1.328 GB24.8%
attention and indexer4.2%2.541 GB47.4%
shared expert1.5%0.890 GB16.6%
output head0.7%0.434 GB8.1%
norms, router, hyper-connections0.3%0.168 GB3.1%
total5.36 GB

The experts dominate the file and are a quarter of the traffic. Squeeze them to 1.6 bits and you have solved capacity, but the bus spends most of each token on the 7% of the file that every token touches. The attention projections alone, attn_q_b, attn_output_a and attn_output_b, are 2.03 GB a token. This is why the repo's kernel work concentrates on the 3.75-bit Fractal-64 matmuls for attention rather than on the experts.

Nemotron-3.5-30B-A3B shows the same shape at a smaller size. Its config is a hybrid: 52 blocks, 23 of them MoE (128 experts, top 6, each expert an up and a down matrix of 2688 x 1856 with a squared-ReLU between, 9,977,856 parameters), 23 Mamba-2 and 6 attention. In the VQ3-64 GGUF the routed experts are 88.5% of the file and 29.1% of a token's 2.04 GB. The Mamba layers read more per token (0.631 GB) than the experts do (0.592 GB).

The widget holds every per-token byte count from the headers. Pick a checkpoint and a memory system and it divides. Switch the experts to "mmap from an SSD" and it charges the expert reads that miss the page cache at SSD speed.

The arithmetic of a ceiling

The README's benchmark machine is a Ryzen 9 9955HX, 16 Zen 5 cores, two channels of DDR5-5600. Peak bandwidth is channels times bytes per transfer times transfers per second: 2×8×5600M=89.62 \times 8 \times 5600\text{M} = 89.6 GB/s. The README says about 75 GB/s sustained, which is a believable 84% of peak. Then:

ttoken≥5.36 GB75 GB/s=71.5 ms⇒≤14.0 tok/st_{\text{token}} \ge \frac{5.36\ \text{GB}}{75\ \text{GB/s}} = 71.5\ \text{ms} \quad\Rightarrow\quad \le 14.0\ \text{tok/s}

The README measures 8.75 tok/s for the MaxQ build, single stream, all six experts, no speculation. That is 62% of the bandwidth ceiling. For Nemotron, 2.04 GB over 75 GB/s is 27.2 ms, a 36.8 tok/s ceiling, against a measured 22.44: 61%. Two models, two formats, the same fraction. On a CPU that is respectable. The remaining third goes to dequantization arithmetic, thread synchronization across 43 layers of small matmuls, and the parts of a token that are not weight reads.

The repo's own profile in docs/DEEPSEEK_V4_OPTIMIZATIONS.md labels the decode read as "3.20 GB -> 2.85 GB" per token. I cannot get there from the headers. The same document puts the wo_a and wo_b pair at 991.6 MB a token; the header says those 86 tensors are 2.886B parameters at 3.75 bits, 1.35 GB. The runtime repacks weights at load, so on-disk bytes are a proxy, but repacking a 3.75-bit block does not make it 27% smaller. If their 3.20 GB were right, the ceiling would be 23.4 tok/s and the measured speed 37% of it, which would say the kernels are far from the bus. My count says the kernels are close to where llama.cpp usually lands. Either way the measured number sits under the ceiling, so nothing is impossible here. The headers are public; anyone can redo the count.

The post's "9 to 14 tok/s" mixes two modes, and the bus says which. At 5.36 GB a token, 9 tok/s pulls 48.2 GB/s through memory: 64% of the 75 GB/s the desktop sustains, 54% of its 89.6 GB/s peak. Fine. 14 tok/s would pull 75.0 GB/s, every byte the bus sustains, with nothing left for activations, the KV cache or the operating system. A single stream cannot do that on two channels of DDR5. The README never claims it: its single-stream range is 8.75 to 9.55, and 10.74 with optional top-4 expert pruning, which reads fewer expert bytes and measurably changes the output. The 14 matches the repo's 14.69 peak with speculative decoding on, in ARCHITECTURE.md. Two more numbers in the post do not belong on this axis at all. The "25 tok/s" is the README's 25.3, a speculative-decoding burst: a drafter proposes tokens and one forward pass verifies several, so weights are read once for several tokens and a per-token bandwidth ceiling no longer applies. The "111 tok/s" is 111.62 on a 64-core Threadripper PRO 7985WX with eight channels of DDR5-6000 (384 GB/s peak, 188 tok/s ceiling for Nemotron by the same arithmetic), warm, with the speculative drafter, running the 30B. It is a real number about different hardware, a different model and a different decoding mode.

The first post, claim by claim

Satyajit reposted the first of the two posts as well, so here is every claim in it against the repo. Where a phrase is the poster's and not the README's, the table says so.

The post saysThe repo saysVerdict
284B squeezed into 56.9 GB "of VRAM", a 64 GB desktop runs it without swap56.93 GiB on disk (61.13 GB), 59.13 GiB resident at a 32K context in about 62.5 GiB usable; the launch script forces -c 32768 -ub 512 on hosts of 68 GB or less and suggests zramTrue at 32K context with nothing else running. The unit is GiB, and "VRAM" is the poster's word for system RAM
9 to 14 tok/s on CPU "via vector instructions"8.75 to 9.55 single stream, 10.74 with top-4 pruning, 14.69 peak with speculation; AVX-512 kernels9 holds. 14 is a speculative peak, and the bus arithmetic above rules it out for one stream
Up to 25 tok/s with speculative decoding11.2 to 25.3 tok/s for the "Stockfish-PVS" drafter, 19.4 to 25.3 for the VQ3 build in agentic burstsTrue as a burst peak; the low end of the same range is 11.2
Cosine similarity 99.15%99.15% for Fractal-64 on one Nemotron tensor's weights, 97.78% for VQ3Real number, wrong object: it describes one tensor, not the 284B's output (see below)
A 30B MoE at 13.3 GB runs on a 16 GB laptop13.30 GiB on disk, 14.6 GiB resident at 32K; hardware class "16 to 32 GB"Tight. On 16 GB with an OS and a browser it will swap
... at up to 111 tok/s111.62 on a 64-core, 8-channel Threadripper, warm, with speculation; 22.44 single stream on the 16-core desktopThe poster's splice: the laptop and the 111 are different machines
Dependency-free dark web UI and terminal chat./modchip web serves a dark-mode chat at port 8787, ./modchip chat a terminal one; the release binaries are built with no libssl or libcurl dependencyBoth exist. "Dependency-free" is the poster's gloss on the binaries; the web UI is a Python gateway
Mountable as a local backend for Claude Code./modchip claude launches Claude Code wired to the local server, with a 40-tool prefix restored from /dev/shm in 10.4 msTrue as described
Needs real 64 GB of RAM, or swap thrashesWeights sit in anonymous heap, which the kernel cannot drop without swap; zram or closing the browser recommendedTrue, and the README is candid about it
Custom patched llama.cpp; stock Ollama can't load the formatTypes 42 and 43 are custom; vanilla llama.cpp, Ollama, vLLM and LM Studio fail on unknown tensor type 43True. Type 42 also reuses a deprecated upstream enum slot, so a stock build may misread it rather than refuse it

The poster's framing ("a few eight-GPU H100 servers" for the full model) is about BF16 serving; at 568.6 GiB in BF16 that is fair, and it is also why the comparison means little. The 284B here is a 1.72-bit model.

Why nothing streams from disk

The obvious design for a model bigger than RAM is mmap: map the file, let the kernel fault pages in on first touch, and let the page cache keep whatever was used recently. Upstream llama.cpp does this by default. For an MoE it is attractive, because each token touches 6 of 256 experts per layer and the rest can sit on disk.

The arithmetic is unkind. In the MaxQ build one expert's three matrices in one layer average 5.15 MB, and a token reads 258 of those slices (6 experts, 43 layers), 1.33 GB. A PCIe 4.0 NVMe drive reads about 7 GB/s sequentially and less for scattered 5 MB reads. Put all the experts on disk with nothing cached and a token costs 53.8 ms of dense reads from RAM plus 190 ms of expert reads from the SSD: 4.1 tok/s. A 90% hit rate in the page cache brings that back to 11.3 tok/s, still under the resident 14.0.

The counterfactual that matters is the one where you keep more bits. DeepSeek ships the routed experts in FP4 ("expert_dtype": "fp4"); at MXFP4's 4.25 bits the routed tensors alone are 147.2 GB, and the file would be about 151.6 GB. That does not fit, so streaming would be mandatory. RAM could cache roughly 41% of the experts. If routing were uniform, about 40% of expert reads would hit, and a token would run at 2.7 tok/s on the same desktop, and even with everything resident it would only reach 10.0. Squeezing experts to 1.6 bits buys both: the file fits, and the expert slice of each token shrinks from 3.45 GB to 1.33 GB.

Choosing anonymous heap over mmap has a cost the README is candid about. Page-cache pages are clean and the kernel can drop them under pressure; anonymous pages cannot be dropped without swap. The MaxQ build allocates 59.13 GiB of resident memory at a 32K context, and a 64 GB Linux box has about 62.5 GiB usable. The launch script forces -c 32768 -ub 512 on hosts of 68 GB or less and suggests zram or closing the browser. That is a 3.4 GiB margin. Treat "runs on 64 GB" as "runs on a 64 GB machine that does nothing else".

The streaming design does exist elsewhere. Edge0 streams a 35B MoE off SSD, and the bytes it cannot stream are the same dense layers counted here. A 200 GB MoE on one RTX 3090 keeps experts in eight-channel DDR4 and found the CPU's dequantization arithmetic, not the bus, setting the speed. modchip sits at the far end of both: no GPU, no disk, everything in DRAM, as few bits as the model survives.

Vector quantization, from the scalar case up

The format with its name on the repo does real work in the Nemotron build, so it deserves a proper look.

A scalar quantizer rounds each weight on its own. Q4_0 takes a block of 32 weights, stores one FP16 scale dd, and replaces each weight wiw_i with a 4-bit integer qiq_i so that wi≈d⋅qiw_i \approx d \cdot q_i: 18 bytes for 32 weights, 4.5 bits per weight. Go to 3 bits and each coordinate gets 8 levels. Three consecutive weights then live on a grid of 83=5128^3 = 512 points spread evenly through a cube, and spending 9 bits on that triple buys one of those 512 points.

The waste is geometric. Weights are roughly bell-shaped and heavy-tailed, so a triple of them is far more likely to sit near the centre than in a corner of the cube. The README makes the volume argument: a ball inscribed in the cube [−M,M]3[-M, M]^3 has volume 43πM3≈4.189M3\tfrac{4}{3}\pi M^3 \approx 4.189 M^3 against the cube's 8M38 M^3, so 47.64% of the cube lies outside it, and a uniform grid spends that share of its points where triples rarely land.

Vector quantization quantizes the triple as a unit. Instead of 512 grid points, keep a codebook of KK points placed where triples actually fall, and store the index of the nearest one. Lloyd-Max is the classical way to place them: alternate between assigning every training triple to its nearest centroid and moving each centroid to the mean of its triples, which is k-means with a quantization goal. With K=128K = 128 the index is 7 bits for three weights, 2.333 bits per weight before scales.

LUT-VQ3-64 packs 64 weights into a 24-byte block_vq3_0:

16+140+12+24=19216 + 140 + 12 + 24 = 192 bits, 24 bytes, exactly 3.000 bits per weight. A weight decodes as w=d⋅G⋅mb⋅cidx[j]w = d \cdot G \cdot m_b \cdot c_{\text{idx}}[j], where cc is an int8 codebook entry.

The decode trick is where this becomes a CPU format. The 128 entries times 3 int8 coordinates are 384 bytes: six 64-byte AVX-512 registers, one pair per coordinate. AVX-512 VBMI's VPERMI2B (_mm512_permutex2var_epi8) treats a pair of registers as a 128-byte table and looks up 64 bytes of it at once with 7-bit indices. So three permutes expand a block's indices into int8 weights without touching memory, and the existing int8 dot-product path takes over. The patch patches/lut-vq3-64-avx512-vbmi.patch does exactly this with _mm512_mask2_permutex2var_epi8, and falls back to AVX2 and scalar paths on CPUs without VBMI.

The widget draws the table as shipped in vq3/vq3_codebook.h. Two README claims about it do not survive contact with the file. The README calls the codebook "antipodally symmetric c127−k=−ckc_{127-k} = -c_k". In the shipped table no entry's negation is in the table at all, let alone at index 127−k127-k; the set is balanced (the coordinate means are 0.09, -0.69 and -0.95, and each octant holds 15 to 17 points) but not symmetric. The README also says the centroids sit "on the populated spherical/cross-polytope shell inside" the cube. Measured from the origin, 80 of the 128 entries lie outside the ball of radius 127 and the largest reaches 205.7, close to a corner at 1273≈220127\sqrt{3} \approx 220. The codebook spreads into the corners. With per-group scales doing the radial work, that is a reasonable place for it to be; it is just not what the prose describes.

Fractal-64, the other format, is a scalar 3-bit quantizer with a non-uniform level set {-14, -8, -4, -1, +1, +4, +8, +14} and eight 4-bit sub-scales: 16+32+192=24016 + 32 + 192 = 240 bits per 64 weights, 3.75 bits per weight. Eight levels fit a VPSHUFB lookup. It is the format on the 284B's attention and on all of Nemotron's down projections.

One check ties the formats to the files. The Nemotron VQ3 build puts 12.133B parameters (19 interior ffn_up_exps) in VQ3 and the rest of the experts in Fractal-64. Moving those 12.133B from 3.75 to 3.00 bits should save 12.133B×0.75/8=1.1412.133\text{B} \times 0.75 / 8 = 1.14 GB, which is 1.06 GiB. The README's two Nemotron files are 14.36 and 13.30 GiB: 1.06 GiB apart. The format does what its block layout says.

What the quality numbers measure

The post's "cosine similarity 99.15%" reads like a statement about the 284B's output. It is something narrower. The README measures it by quantizing and dequantizing one tensor, blk.1.ffn_up_exps.weight, from a "59.0 GiB BF16 master checkpoint". 59.0 GiB is the Nemotron 30B in BF16 (the 284B in BF16 is 568.6 GiB), and 99.15% belongs to Fractal-64 on that tensor; VQ3 scores 97.78% on the same test. The numbers are self-consistent: a signal-to-quantization-noise ratio of 17.75 dB is a power ratio of 59.6, a relative error of 1/59.6=12.95%1/\sqrt{59.6} = 12.95\% against the README's 12.96%, and a cosine of 1/1+1/59.6=0.99171/\sqrt{1 + 1/59.6} = 0.9917. Weight reconstruction is the right first test for a format. It says nothing about what a 1.6-bit 284B model writes.

For that the repo has perplexity, KL divergence and a 100-point gate, and each has a limit:

On the 284B the gate does spread out (MaxQ 70/80, VQ3 64/80) and the harder 60-point suite more so (40 against 30). That is the evidence I would weigh, and it favours the build without the VQ3 tensors.

The free 8-core box in the video

The quoted post's run is the more interesting of the two, because it is the cheap case. He named the machine in a reply: when someone asked where to get an 8-core, 32 GB CPU instance, he linked his earlier post about ModelScope's free notebooks. His screenshot of the console shows it.

The ModelScope 'My Notebook' page listing three instance types: '8核 32GB CPU' marked running with long-term validity, an 8-core 32 GB GPU instance with 24 GB of video memory, and a 23-core 200 GB AMD GPU instance, with red arrows pointing at the CPU row.
The machine: a free ModelScope notebook instance, 8 cores and 32 GB, CPU only, valid long-term. Red arrows are his (image from @mingzi206's post on X).

His coding assistant, in the first seconds of the video, gets the model's provenance right where the post does not: "NVIDIA's Nemotron 3.5 Lightning model, a CPU quantized version made by the third party Synchopate". NVIDIA publishes the BF16 weights; nobody at NVIDIA modified anything. The same screen gives the decode speed as "we measured about 11.3 token/s".

A chat reply in Chinese explaining that Nemotron 30B-A3B VQ3-64 is NVIDIA's Nemotron 3.5 Lightning model in a CPU-quantized version made by the third party Synchopate, with bullets: 30B is about 30 billion parameters in total; A3B is an MoE activating about 3 billion per token; VQ3-64 is a special mixed quantization format where 64 is the group size.
His assistant's summary of what the model is, at the start of the video (video from @mingzi206's post on X).

The request panel in his client logs a token count, a time and a rate per call, and they don't divide (333 tokens in 4.5 s is shown as 22 tok/s), so I would not read a decode speed off it. The server ran with an 8K context, and an earlier call failed with "request (125334 tokens) exceeds the available context size (8192 tokens)": a coding agent's prompt does not fit.

A list of requests to ModelScope CPU nemotron-30b-vq3-modchip, each with a timestamp and a line such as '1 try · 333 toks · 4.5s · 22 tok/s', '277 toks · 3.3s · 25 tok/s', '258 toks · 6.0s · 11 tok/s', '207 toks · 5.8s · 12 tok/s' and '152 toks · 3.2s · 33 tok/s'.
The router panel in his client. The token counts and rates do not divide, so the rate column is not a clean decode speed (video from @mingzi206's post on X).

Take the 11.3 tok/s at face value. At 2.04 GB a token that is 23.0 GB/s of weight traffic, plausible for a shared cloud host. I don't know whether the instance has AVX-512 VBMI; without it the VQ3 tensors take the AVX2 fallback. Either way, a 30B MoE holds a conversation on a free CPU instance at reading speed, as long as the prompts stay short.

The launch animation

The README's launch animation, converted from its 9 s GIF. It is a scripted render of v2.4.0, not a screen recording, and its figures (57.61 GiB, 10.74 tok/s with tail pruning) are the project's claims (animation from the llama-modchip README).

Every panel is typed on at a fixed cadence and the telemetry is static. As marketing it is fine. As evidence it is not.

Run the MaxQ build, skip the VQ3 one

The README packs a dozen invented names (RouteCrack, Stockfish-PVS, HARP-Cache, SwiGLU-H2) into every table cell, and several of its derivations do not match its own files. Under that is competent engineering: a model that fits 64 GB at 1.6 bits, bits spent where tokens read them (1.56 on experts, 3.75 on attention, 6.56 on the shared expert and head), and about 62% of the memory bus on both models.

If you have a 64 GB desktop that does nothing else, the MaxQ build is a real way to run DeepSeek-V4-Flash at 8 to 9 tok/s, and its decode floor is set by attention, not experts. If you have 16 to 32 GB, the Nemotron VQ3 build is the more interesting artefact; it is 1.06 GiB smaller than Fractal-64 for a 1.07% perplexity cost. I would skip the VQ3 284B build, which loses a quarter of top-1 agreement to save half a gigabyte. And I would not quote the 100/100 gate for anything.

So a 284B MoE runs from 64 GB because its experts are compressed until they fit, not because they stream. For the same bandwidth reasoning elsewhere, see CPU performance engineering, PS5LM on a console's memory bus, and DeepSeek-V4.1-Flash-1017, whose UD-IQ1_S build shows the same split: 1.80 GB of experts against 6.60 GB of everything else per token.

Cite this article

For attribution, please use the following reference or BibTeX:

Satyajit Ghana, "llama-modchip: a 284B MoE in 64 GB of RAM, and what actually makes it fit", ai.satyajit.si, November 2026.

bibtex
@misc{ghana2026llamamodchip,
  author = {Satyajit Ghana},
  title  = {llama-modchip: a 284B MoE in 64 GB of RAM, and what actually makes it fit},
  url    = {https://ai.satyajit.si/articles/llama-modchip},
  year   = {2026}
}
share