Qwen3.5-4B in 1.2 GB: 330 of 540 math problems to Bonsai 2 Ternary's 328, and closer to the original on text
Math problems solved, of 540
KL from the original on text (lower is better)
Bonsai 2 Ternary 4B [1] is Prism ML's compression of Qwen3.5-4B [2] to three values per weight. Its language weights take 1.20 GB. The original's take 8.4 GB.
Our file is the same model at 2.3 bits per weight, 1.23 GB. The compiler from LookAtMyQuant builds it from the original's weights, and 4,000 steps of training follow.
The math test is 540 generated problems with exact answers. There are twelve kinds of problem, from long addition and multiplication to determinants, modular powers and linear systems, at three difficulties. A problem counts only if the final answer is exactly right within 2,048 tokens. Models answer greedily, with thinking turned off.
Ours solves 330, Bonsai 328 and the original 359. 62 problems are solved only by ours and 60 only by Bonsai, so the test does not separate the two files.
Table 1. Every model on the same math test and the same text. KL is against the original Qwen3.5-4B, on 52 windows from 13 sources and on 64 windows of WikiText-2. A window is 512 tokens.
| Model | Weights (GB) | Math, of 540 | KL, 13 sources | KL, WikiText-2 |
|---|---|---|---|---|
| Qwen3.5-4B, ours 2.3 bits per weight, trellis codes | 1.23 | 330 | 0.45 | 0.42 |
| Bonsai 2 Ternary 4B Prism ML, three values per weight | 1.20 | 328 | 0.59 | 0.50 |
| Qwen3.5-2B at 5 bits 1.9 billion weights, rounded as MLX does | 1.29 | 284 | 0.51 | 0.45 |
| Qwen3.5-2B at 4 bits 1.9 billion weights, rounded as MLX does | 1.06 | 242 | 0.60 | 0.51 |
| Qwen3.5-0.8B at 8 bits 0.8 billion weights, rounded as MLX does | 0.80 | 205 | 0.75 | 0.70 |
| Qwen3.5-4B, original 16 bits per weight | 8.41 | 359 | 0 | 0 |
KL divergence measures how far a model's next-token predictions are from the original's. Lower is better. On held-out text from 13 sources, ours averages 0.45 and Bonsai 0.59. On WikiText-2, ours is 0.42 and Bonsai 0.50.
Figure 2 shows each source. Bonsai is lower on chat and Hindi. Ours is lower on the rest, by the most on Chinese, Korean, Japanese and Arabic.
The same space can hold a smaller model with more bits for each weight. We rounded the two smaller Qwen3.5 models the way MLX's standard files do [8]. Weights are stored in groups of 64, and each group has its own scale and offset.
Qwen3.5-2B at 5 bits is 1.29 GB and solves 284. At 4 bits it is 1.06 GB and solves 242. Qwen3.5-0.8B at 8 bits is 0.80 GB and solves 205. More bits would not help the 0.8B, because 8 bits already change its weights by only half a percent. No Qwen3.5 model fills 1.2 GB at 8 bits. That takes 1.1 billion weights, and these two models have 0.8 and 1.9 billion.
On text, their KL from the original 4B's predictions is 0.51, 0.60 and 0.75. Ours is 0.45.
The build makes the 1.2 GB file from the original's weights and a sample of text. Nothing is trained. The first file at this size solved 1 problem, although its KL on WikiText-2 was 0.60 against Bonsai's 0.50. Figure 3 shows the score after each change.
The first file stored each weight as one of a few fixed levels. A trellis code [3] stores a row of weights as one path of bits. Each weight adds 1 to 4 bits to the path. Its value is read from a table of 4,096 values, at the position given by the path's last 12 bits. One weight's bits therefore also help to pick the values of the weights after it, and the whole row lands closer to the original.
On Gaussian weights at 2 bits, the trellis leaves 36% less squared error than the best fixed levels. In the whole model, WikiText-2 KL fell from 0.60 to 0.39 and the score went from 28 to 117.
The rest of the format follows QuIP# [4] and QTIP [3]. A random Hadamard transform rotates each matrix's inputs, which makes its weights look Gaussian. Each row has one scale. Weights are rounded 16 columns at a time, and each block's error is pushed onto the columns not yet rounded, weighted by statistics of the layer's inputs [5].
Rounding needs a sample of text, because statistics of each layer's inputs decide which errors matter. With general text the file solved 1. With the original's own solutions to grade-school math problems [10] as half of the text, it solved 28.
Two more changes to the text came after the trellis codes. First, all of the text became math, and positions where the next token is a digit counted ten times as much as other positions. The score went from 117 to 147. Second, the short grade-school solutions gave way to the original's long worked solutions to competition problems [9], 64 windows of 2,048 tokens. They have many intermediate results, like the answers the test needs. The score went from 147 to 224.
Layers are rounded in order, so each layer receives inputs that already carry the error of the layers before it. A layer can be fitted to cancel that error [6]. Cancelling half of it rather than all of it took the score from 224 to 265 and WikiText-2 KL from 0.85 to 0.66.
The rows of one matrix differ widely in how much they matter for predicting digits. In the matrices that read a linear-attention layer's input, a tenth of the rows carry 79% of that importance. We measured every row's importance on the original model. Important rows then got 3 or 4 bits and unimportant rows 1 or 2, at the same file size.
Moving the top eighth of each matrix's rows up one bit and the bottom eighth down gave 292. Choosing every row's bits across the whole model at once gave 300. Two more builds of the first kind gave 261 and 266.
A trellis code needs its table of 4,096 values. We had fitted it with six passes of Lloyd's algorithm, the usual k-means, over one set of Gaussian samples. e-means [7] replaces those full passes with small batches and exponential moving averages. We fitted the table that way, with fresh samples in every batch, a decaying sum and count for each of the 4,096 values, and a weight on each new batch that falls from 0.5 to 0.01.
On Gaussian weights the new table leaves 4% to 9% less error at 1 to 4 bits per weight. The file is the same size and decodes the same way. With new tables for the 2-bit and 3-bit codes, which hold 83% of the weights, the score went from 300 to 311. With new tables for every code it went to 317. KL on the 13 sources was 2% lower with the first and 4% lower with the second.
Changing one stored bit of a trellis code changes several weights at once, so a weight cannot take a small step. Ordinary fine-tuning of a built file can move only the row scales and the value tables, which are stored as plain numbers.
The training runs on a copy of the model whose weights are ordinary real numbers. The copy starts exactly on the stored model. Figure 4 shows the steps.
The loss compares the copy's predictions with the original's 64 most likely tokens at 128 positions of each 512-token window. Half of each batch is worked math solutions. The other half is general text, science, code, instructions and tool calls. A step uses 8 windows. Adam's damping term is set to each matrix's typical gradient size, so weights with tiny gradients do not take full-size steps.
This training took the score from 317 to 321 and KL on the 13 sources from 1.41 to 0.79. The codes hardly moved. Only 0.1% of a layer's codes change when it is rounded again, because a weight that sits near its code rounds back to the same code.
So we choose every layer's codes again, once, between steps 1,000 and 1,750. Each layer is rounded from the original's weights. The rounding uses statistics of the layer's inputs in the partly trained model, kept as a running average over the training batches. That average covers eight times as much text as the build's. 97% of the codes change, and training continues from the new ones.
KL from the original on text (lower is better)
We ran both kinds of training from two builds. With the codes chosen again, the files solve 330 and 324 problems and their KL on the 13 sources is 0.45 and 0.45. Without, they solve 321 and 314 and their KL is 0.79 and 0.80.
Table 2. Two builds, each untrained, trained, and trained with the codes chosen again.
| Training | Math, of 540 | KL, 13 sources | KL, WikiText-2 |
|---|---|---|---|
| Build A, with new value tables for every code | |||
| Untrained | 317 | 1.41 | 1.07 |
| Trained | 321 | 0.79 | 0.64 |
| Trained, with the codes chosen again (our file) | 330 | 0.45 | 0.42 |
| Build B, with new value tables for the 2-bit and 3-bit codes only | |||
| Untrained | 311 | 1.43 | 1.05 |
| Trained | 314 | 0.80 | 0.64 |
| Trained, with the codes chosen again | 324 | 0.45 | 0.44 |
Table 3 lists every step that makes the file once, at Modal's on-demand prices [11] for the GPU, CPU and memory each step used. Calibration is every step before training, and costs $13. Training costs $21. The steps take 5.4 GPU-hours in all. Calibration reads 131,000 tokens of text, and training reads 16 million.
Table 3. The time and cost of each step.
| Step | GPU | Hours | Cost |
|---|---|---|---|
| Measure how much each matrix matters, for the plan of bits | H100 | 1.6 | $7.74 |
| Write the calibration text (the original solves 384 problems) | H100 | 0.3 | $1.24 |
| Measure each row's importance and fit four value tables | L40S | 0.2 | $0.50 |
| Round the weights | H100 | 0.6 | $3.32 |
| Train for 4,000 steps | B200 | 2.7 | $20.98 |
| All of it | 5.4 | $33.78 |
@misc{boson2026lookatmyquant2,
title = {LookAtMyQuant 2: Qwen3.5-4B in 1.2 GB},
author = {{Shin Megami Boson}},
year = {2026},
month = nov
}