# ZDTaichu5.0-9B: the release contradicts itself on its own best benchmark

> Satyajit Ghana — Head of Engineering @ Inkers Technology
> canonical: https://ai.thesatyajit.com/articles/zdtaichu-5-9b
> date: 2026-09-18
> tags: multimodal, vision-language-models, benchmarks, quantization, inference-optimization, explainer
On 15 September 2026 the Taichu lab (紫东太初) open-sourced **ZDTaichu5.0-9B**: a Qwen3.5-9B
decoder with an NVIDIA C-RADIOv4-H vision tower bolted on, pitched at spatial reasoning and
embodied AI. There is no arXiv preprint and no tech report — the entire technical record is a
[model card](https://huggingface.co/TaichuAI/ZDTaichu5.0-9B), a [GitHub
README](https://github.com/Taichu-AI/ZDTaichu5.0-9B), and one subdirectory called
`recurrent_reasoning/`. I read all of it, in both languages, and pulled every safetensors
header over HTTP range requests without downloading a single weight.

The artifact is in good shape. The bytes reconcile exactly, the config matches the tensor
shapes, and the vision tower is really there. The *documentation* is where this release
falls over — and it falls over hardest on exactly the benchmarks where it beats a frontier
closed model.

<ModelCard
  repo="TaichuAI/ZDTaichu5.0-9B"
  claimed="9B, Qwen3.5-9B + C-RADIOv4-H, 128K context"
  note="Measured from the safetensors headers: 9,794,197,512 parameters in 820 tensors — 8.95B language model, 651.6M vision tower, 188.7M projector. config.json sets max_position_embeddings to 262,144 and the README's own recommended vLLM command asks for --max-model-len 220000, neither of which is 128K."
/>

## The two READMEs

The model card has one table for spatial and embodied reasoning. `recurrent_reasoning/README.md`
in the GitHub repo has another, for the same model on four of the same benchmarks. They do
not agree, and nothing in either document reconciles them:

| Benchmark | Model card | `recurrent_reasoning/README.md` | Difference |
|---|---:|---:|---:|
| ViewSpatial | 62.50 | 54.10 | **+8.40** |
| MMSI-Bench | 47.20 | 36.80 | **+10.40** |
| MindCube-tiny | 78.27 | 74.04 | **+4.23** |
| RoboSpatial | 56.00 | 68.00 | **−12.00** |

The first three have an explanation, buried in a `<sub>` footnote under the model card's
tables. For ViewSpatial, MMSI-Bench, MindCube-tiny and VSI-Bench, an output-format
instruction was appended to the evaluation prompt:

> You FIRST think about the reasoning process as an internal monologue and then provide the
> final answer. The reasoning process MUST BE enclosed within `<think>` `</think>` tags. The
> final answer MUST BE put in `\boxed{}`.

The EARR README's footnote says its numbers were taken *without* that instruction, through
plain Transformers at `batch_size=1`. So the delta between the two tables is the price of
that one paragraph of prompt. On MMSI-Bench it is worth 10.4 points.

MMSI-Bench is a fixed set of **1,000 multiple-choice questions**
([arXiv:2505.23764](https://arxiv.org/abs/2505.23764)), which makes the denominator easy:
47.20 is 472 questions, 36.80 is 368. The `<think>`/`\boxed{}` wrapper is worth **104
questions out of 1,000**.

<Callout type="warn">
That matters because of where those three benchmarks sit. Of the 25 rows in the model card
that carry a Gemini 3 Pro score, ZDTaichu5.0-9B is ahead on seven — and four of those seven
are ViewSpatial, MMSI-Bench, MindCube-tiny and VSI-Bench, exactly the four benchmarks the
footnote says got the format instruction. On MMSI-Bench the card puts ZDTaichu5.0-9B at
47.20 against Gemini 3 Pro's 45.20, a 2.0-point lead; the lab's own ungated measurement of
the same model is 36.80, which is 8.4 points the other way. Whether the lead survives
depends entirely on whether the baselines got the same prompt addendum, and the model card
never says.
</Callout>

RoboSpatial is worse, because it has no explanation at all. It is not in the list of
benchmarks that received the format instruction, yet the same model is reported at 56.00
in one file and 68.00 in the other. One of those two numbers came from a different harness,
a different split, or a different checkpoint, and the release does not say which. The
Highlights section leads with "Scores of 48 on ERQA and 56 on RoboSpatial" — the lower of
the two, which is at least not the flattering direction.

I checked the Chinese `README_zh.md` files on the assumption that the more candid document
might be the untranslated one. It is not: both EARR READMEs are faithful translations of
each other, same numbers, same footnote, and — a small tell about how carefully this was
proofread — the same broken install line in both.

## What the release figure shows, and what its own tables print

The headline figure is twelve bar-chart panels. The tables above it have twenty-seven rows.

<Figure
  src="/articles/zdtaichu-5-9b/fig1.png"
  alt="A twelve-panel bar chart titled 'ZDTaichu5.0-9B: Comparison with Open Models', grouped into General Visual Understanding, Spatial and Embodied Capabilities, and Text and Agent Capabilities, comparing ZDTaichu5.0-9B against Qwen3.5-9B, STEP3-VL-10B and gemma4-8B-E4B."
  caption="The release's open-model comparison. Twelve of the twenty-seven benchmark rows in the tables directly above it made the cut (ZDTaichu5.0-9B release, docs/assets/, file taichu-release-benchmark-comparison.svg)."
/>

I parsed all three HTML tables out of the model card and scored every row against the best
of the three open baselines the release itself chose. Toggle between the figure's twelve
panels and the full twenty-seven:

<PanelPick />

Across the full tables ZDTaichu5.0-9B leads the open field on 17 of 27 rows — 63.0%. Across
the twelve panels promoted into the figure, 10 of 12 — 83.3%. Choosing a subset for a
release graphic is normal, and every one of these losses is printed in the tables the figure
sits under. The number worth carrying away is the one the graphic cannot show you: **eight
of the ten losses are to Qwen3.5-9B**, the model's own language backbone. Both MMLU rows,
OCRBench, MMStar, RealWorldQA, MathVista and MathVerse all go backwards relative to the text
model this was built from. That is the visual-instruction-tuning tax, it is substantial
(MathVerse Mini drops 7.74 points), and it is the honest cost of the spatial gains.

One more thing about the figure: in it, ZDTaichu's value label is bold in all twelve panels,
including MMStar and RealWorldQA where it loses. In the tables, bold means *best score among
open models*. Two conventions, one document.

## Measuring the artifact

None of the above touches the weights, so I measured those separately. A safetensors file
opens with an 8-byte little-endian header length followed by a JSON header listing every
tensor's name, dtype and byte offsets — two range requests per file recover the complete
tensor manifest for free.

```bash
# first 8 bytes -> header length n
curl -sSL -H 'Range: bytes=0-7' \
  https://huggingface.co/TaichuAI/ZDTaichu5.0-9B/resolve/main/model-1-of-5.safetensors \
  | xxd -e -g8
# then bytes 8..8+n-1 -> the JSON header
```

**Receipts.** ZDTaichu5.0-9B ships 9,794,197,512 parameters in 19,588,395,036 tensor bytes across five safetensors shards. Every shard's real size, tensor list and parameter count was recovered by HTTP range read without downloading any weights, and the three totals reconcile exactly: 8 length bytes per file, plus 106,344 bytes of JSON headers, plus tensor bytes, equals the sum of the CDN's Content-Length values to the byte.

| file | CDN Content-Length (B) | git-lfs pointer size (B) | safetensors header (B) | tensors | parameters |
| :--- | ---: | ---: | ---: | ---: | ---: |
| model-1-of-5.safetensors | 4,268,658,872 | 4,268,658,872 | 9,776 | 75 | 2,134,324,544 |
| model-2-of-5.safetensors | 4,265,727,128 | 4,265,727,128 | 16,656 | 128 | 2,132,855,232 |
| model-3-of-5.safetensors | 4,215,379,968 | 4,215,379,968 | 16,760 | 128 | 2,107,681,600 |
| model-4-of-5.safetensors | 3,123,658,752 | 3,123,658,752 | 12,408 | 95 | 1,561,823,168 |
| model-5-of-5.safetensors | 3,715,076,700 | 3,715,076,700 | 50,744 | 394 | 1,857,512,968 |
| — total — | 19,588,501,420 | 19,588,501,420 | 106,344 | 820 | 9,794,197,512 |

The index file's declared metadata.total_size is 19,588,395,036, which is tensor bytes only and excludes headers — it matches the summed data_offsets exactly, so nothing is missing or double-counted. The parameter total splits into 8,953,803,264 in the language model, 651,645,448 in the C-RADIOv4-H vision tower (390 tensors, one of them an int64 index buffer) and 188,748,800 in the mlp1 projector. config.json labels the release "9B" via _model_size_label; the shipped artifact is 9.79B, of which 2,034,237,440 (20.8%) is the untied input embedding plus LM head over a 248,320-token vocabulary.

> method: For each shard: curl -sSL -I <resolve URL> to follow the xet CDN redirect and read Content-Length; then Range: bytes=0-7 for the little-endian u64 header length, then Range: bytes=8-(8+n-1) for the JSON header. Parameter counts are the product of each tensor's shape; byte counts are data_offsets[1]-data_offsets[0].
> source: https://huggingface.co/TaichuAI/ZDTaichu5.0-9B
> captured: 2026-09-18
> data: https://ai.thesatyajit.com/articles/zdtaichu-5-9b/data/checkpoint-ledger.json (6 rows)

Everything closes. 40 bytes of length prefixes plus 106,344 bytes of headers plus
19,588,395,036 tensor bytes equals 19,588,501,420, which is the sum of the five CDN
`Content-Length` values to the byte. The `model.safetensors.index.json` declares
`total_size: 19588395036` — tensor bytes only, which is correct and not a discrepancy. The
git-lfs pointer sizes match the post-redirect `Content-Length` exactly. No missing gigabytes.

The config matches too, including the two places where it looks like it shouldn't. `q_proj`
ships as `[8192, 4096]` while `num_attention_heads` is 16 and `head_dim` is 256, which
multiplies out to 4096 — but `configuration.py`'s own header comment gives the reason:
*"Attention output gating (sigmoid gate on q_proj)"*, so the projection is 16 × 256 × 2.
The DSpark draft model confirms it from the other side: its config is plain `qwen3` with the
same 16 heads and 256 head_dim, and its `q_proj` really is `[4096, 4096]`.
The Gated DeltaNet layers line up the same way: `in_proj_qkv` is `[8192, 4096]` = 16×128
keys + 16×128 queries + 32×128 values, and `in_proj_z` is the 32×128 gate. The projector is
exactly what `mlp1` claims: `[5120]` RMSNorm → `[20480, 5120]` → `[4096, 20480]`, where 5120
is the 1280-wide ViT output after a 0.5 pixel-shuffle. **The vision tower is real** — 390
tensors, 32 ViT-H/16 blocks, 651,645,448 parameters — not a config entry pointing at nothing.

Two things the config advertises that the checkpoint does not carry:

- `mtp_num_layers: 1` and `mtp_loss_scaling_factor: 0.1` describe a multi-token-prediction
  head. There are **zero** tensors matching `mtp.*` in the index, and `modeling.py` explicitly
  lists `r"^mtp\..*"` in `_keys_to_ignore_on_load_unexpected`. The MTP head was stripped
  before release; the config was not updated.
- `llm_config.use_cache: false`, alongside `mtp_loss_scaling_factor` and a
  `vision_config.args` blob containing the entire RADIO training argparse namespace
  (`world_size: 256`, `epoch: 299`, `wandb_project`, and the teacher list — `siglip2-g-384`,
  `dinov3_vit7b16`, `sam3`). This config.json is a training-run export shipped as-is. It is
  harmless, but it is not a release artifact.

### What "9B" is made of

Of the 9,794,197,512 parameters, **2,034,237,440 — 20.8% — is the untied input embedding plus
LM head** over a 248,320-token vocabulary. The non-embedding model is 7.76B. That framing
matters as soon as you look at the quantized builds, because nobody quantized those two
matrices.

<PrecisionMap />

Read the bits/weight figure. The FP8 build lands at **10.35 bits/weight**, not 8, because
45.4% of it is still BF16: the embedding, the LM head, the entire C-RADIOv4-H tower and the
projector. The NVFP4 build lands at **8.01 bits/weight**, not 4, because only the MLP
projections in layers 0 through 27 are actually 4-bit — 2.11 GB of `U8`-packed weights with
E4M3 block scales at block size 16. Layers 28–31 keep FP8 MLPs, every attention and
linear-attention projection stays FP8, the LM head is FP8, and `embed_tokens` is still BF16.
Measured in parameters, 43.2% of the model is 4-bit in the "NVFP4" checkpoint.

The 1.68 GB vision tower and projector are byte-for-byte identical across all three
checkpoints. For a model whose pitch is embodied and spatial deployment, the visual encoder
is the one component that never gets quantized.

<Callout type="note">
None of this is wrong — leaving embeddings and the vision encoder in BF16 is standard and
usually correct. It is just not what "FP8" and "NVFP4" imply on a download page that lists no
file sizes, and the gap between 4 bits/weight and 8.01 bits/weight is the gap between fitting
on a 16 GB card and not.
</Callout>

The fourth entry in that download table is `ZDTaichu5.0-9B-DSpark`, which is not a
quantization at all and is never mentioned again anywhere in the README. Its header says
3,210,004,992 parameters in 62 tensors: `embed_tokens`, five Qwen3 decoder layers, an `fc` of
`[4096, 20480]` that fuses five auxiliary hidden states, a `markov_head` of 2 × `[248320, 256]`,
and `lm_head`. It is an EAGLE-3-style speculative-decoding draft model, and its own card
reports 2.46×–3.17× speedups on a **single H800 at concurrency 1** with
`num_speculative_tokens: 7` — best-case conditions for speculative decoding, and a number that
will not survive real batching. Two-thirds of its 6.42 GB (63.4%) is the two vocabulary
matrices. It is tagged `pipeline_tag: image-text-to-text` on Hugging Face and contains no
vision tensors, which is correct by design for a draft model and wrong as metadata.

## The headline feature ships in neither place you would look for it

The fourth bullet in Highlights is **Entropy-Gated Adaptive Recurrent Reasoning**:
"dynamically allocates additional recurrent refinement steps in latent space to more
challenging tokens." It is the only architectural novelty claimed over stock Qwen3.5 + RADIO.

<Figure
  src="/articles/zdtaichu-5-9b/fig2.png"
  alt="A flow diagram: Standard Forward produces logits and hidden states, feeding Entropy Gating which tests the entropy of the logits against a threshold; high entropy loops into Latent-Space Recurrent refinement, low entropy goes straight to Trajectory Readout. Below, five labelled boxes read Trigger — normalized entropy / margin, Termination — KL + hidden residual, Stability — damping + anchor, Deployment — KV-cache policy, Safety — best-state rollback."
  caption="The mechanism as the release draws it, including the five 'Key Design Points' along the bottom (ZDTaichu5.0-9B repo, recurrent_reasoning/, file EARR.png)."
/>

It is not in the Hugging Face repo. `modeling.py` there has no entropy gate at all. To get
EARR you clone GitHub and copy two files over the downloaded checkpoint:

```bash
# recurrent_reasoning/README.md, verbatim
cp ./modeling.py /path/to/ZDTaichu5.0-9B/
cp ./recurrent_reasoning.py /path/to/ZDTaichu5.0-9B/
```

Diffing the two `modeling.py` files shows how thin the seam is — 22 changed lines, all of
them plumbing, and the one that matters is the class declaration:

```python
-class ZDTaichu5_0_ForConditionalGeneration(PreTrainedModel, GenerationMixin):
+class ZDTaichu5_0_ForConditionalGeneration(RecurrentReasoningMixin, PreTrainedModel, GenerationMixin):
```

It is also absent from the deployment path the README actually recommends. The Online Serving
section serves the model with a forked vLLM, and vLLM does not run the repo's `modeling.py`.
So the headline mechanism is available only through `AutoModel`, only at `batch_size=1` (the
code says so: *"Batch size is always 1, so entropy is handled as one scalar"*), and only if
you configure it through process-level environment variables — `recurrent_reasoning.py` reads
them with `os.getenv` at **import** time, and the README is explicit that they "are not passed
as arguments to `model.generate(...)` and are not read from `config.json`."

### What the mechanism actually does

Strip the prose and the loop is short. One ordinary forward pass produces logits; the entropy
of the last position's distribution is compared against a threshold; if it is exceeded, the
block of layers named by `RECURRENT_REASONING_LAYER_INDICES` (default `"12,13,14,15"`) is
re-run on a damped blend of its own input and output, and the new logits are kept only if
entropy went down.

<EntropyGate />

Two things fall out of that. The "damped update" is not a tuned constant — it is
`1.0 / (RECURRENT_REASONING_MAX_ITERS + 1)`, so at the shipped default of `MAX_ITERS=1` it is
a flat 50/50 average, and the re-blend line inside the loop (guarded by
`if reasoning_iter < RECURRENT_REASONING_MAX_ITERS`) never executes at all. And the "greater
computational depth" the Highlights promise is, at default settings, **one extra pass over
four of thirty-two layers**, on gated tokens only: 12.5% more decoder depth, once.

Raising `MAX_ITERS` does not simply buy more depth, either, because it shrinks the step: at
`MAX_ITERS=3` the damping weight drops to 0.25, so each of the three iterations moves the
hidden state a quarter of the way instead of half.

### Five of the diagram's terms return zero grep hits

The figure's bottom row lists five mechanisms. I grepped the released
`recurrent_reasoning.py` — all 45 KB of it — for the term behind each. Five of those terms
(`margin`, `normaliz`, `residual`, `anchor`, `rollback`) return zero hits, case-insensitive;
one design point survives intact, and it is the one with the least marketing attached:

| Claim in the figure / README | In `recurrent_reasoning.py` |
|---|---|
| Trigger: "normalized entropy / margin" | Raw entropy in nats against a constant. `margin` and `normaliz` appear **0 times**. |
| Termination: "KL + hidden residual" | KL early-stop is there. `residual` appears **0 times**; the second stop rule is "entropy went up". |
| Stability: "damping + anchor" | Damping is there. `anchor` appears **0 times** — the blend at iteration *k* is against iteration *k*'s own input, not the initial representation. |
| Safety: "best-state rollback" | `rollback` appears **0 times**. The loop keeps the last accepted candidate and breaks on the first entropy rise — greedy, not best-of-trajectory. |
| Deployment: "KV-cache policy" | Genuinely implemented, and the most substantial part of the file: cache forking, frozen history rebuild, DeltaNet recurrent-state snapshots. |

The one the README under-sells is the one that is real. Re-running four layers over cached
decode state without corrupting a hybrid KV/DeltaNet cache is fiddly, and
`_build_recurrent_reasoning_history_cache`, `_fork_recurrent_reasoning_cache` and
`_snapshot_recurrent_reasoning_linear_states` are where the engineering went. During prefill
there is no such luck — the comment in the code is blunt: *"Prefill reasoning recomputes the
current input tokens without a KV/recurrent cache"*, which for a long multi-image prompt means
those four layers get re-run over the entire sequence.

### And the gains it buys

| Benchmark | ungated | with EARR | Δ |
|---|---:|---:|---:|
| ViewSpatial | 54.10 | 54.27 | +0.17 |
| MMSI-Bench | 36.80 | 37.40 | +0.60 |
| MindCube-tiny | 74.04 | 75.00 | +0.96 |
| RoboSpatial | 68.00 | 70.00 | +2.00 |

Four benchmarks, one run each, no seeds, no item counts, no error bars. On MMSI-Bench's 1,000
questions, +0.60 is **6 questions**. The release bolds all four as wins. To its credit, the
README states the limitation itself, and states it well:

> Output entropy reflects the model's own uncertainty and does not establish whether an answer
> is correct.

That is exactly right, and it is the reason a gate that accepts whichever candidate has lower
entropy is selecting for confidence, not accuracy. A more confident wrong answer passes this
filter.

## The install line does not work

Three files — the Hugging Face model card, `recurrent_reasoning/README.md`, and
`recurrent_reasoning/README_zh.md` — give the same installation command:

```bash
pip install tranformer==5.3.0 torch==2.10.0 torchvision==0.25.0 accelerate timm
```

`tranformer` is a typo for `transformers`, and there is no PyPI project by that name:
`https://pypi.org/pypi/tranformer/json` returns 404, as does `transformer` without the
trailing *s*. Nobody who copy-pasted the quickstart got past line one. (No typosquat exists on
either name today, which is luck rather than design.) Everything else in the quickstart checks
out — `processor.from_messages(...)` really is defined, at `processing.py:424`.

The context length is muddled the same way. The model card's spec table and prose both say
128K. `config.json` sets `max_position_embeddings: 262144`. The vLLM command the README tells
you to run asks for `--max-model-len 220000`. Three numbers, no reconciliation — and unusually,
the marketing figure is the *smallest* of the three.

## The demo

The GitHub repo ships agent demo recordings. This is the one for a damped-harmonic-oscillator
task — solve it analytically with Wolfram, then numerically in Python, then compare the phase
portraits — driven through an agent harness called ScienceClaw, which is presumably the source
of the release's Claw-Eval numbers.

<Video
  src="/articles/zdtaichu-5-9b/agent-demo"
  poster="/articles/zdtaichu-5-9b/agent-demo.jpg"
  alt="A screen recording of an agent session replay: a Chinese-language prompt describing a damped harmonic oscillator, with a tool-call trace on the right showing Wolfram output, a bash_exec listing files in /workspace/output, and a sandbox_patch editing solution_report.md."
  caption="Official demo, uncropped and untrimmed; downscaled to 1,280px and stripped of audio, nothing else. The vendor's replay toolbar is visible top right: playback speed is set to 2x, 49% through a session the header timestamps at 34 minutes (ZDTaichu5.0-9B repo, docs/assets/agents/, file zdtaichu5_agent_damped_oscillator.mp4)."
/>

Worth noting what the toolbar tells you that the README doesn't: this is a session replay, not
real time, and its own speed selector is set to **2x**. The 16-second clip is a sped-up
excerpt of a session the header labels 34 minutes old. That is a normal thing for a product
viewer to do and an easy thing to forget when you are watching an agent look fast.

## What I would actually do with this

Set the documentation aside and there is a real model here. But which model depends on a
number the release does not publish.

At the model card's gated scores, ZDTaichu5.0-9B is 8.5 to 15.5 points clear of the best open
baseline on the three complex-spatial rows. At the lab's own ungated scores it is 36.80 on
MMSI-Bench, and the model card's number for its own backbone, Qwen3.5-9B, is 38.70. Those two
are not directly comparable — the card never says whether Qwen was given the format
instruction — and that is precisely the problem. Depending on the answer, ZDTaichu5.0-9B is
either 8.5 points ahead of Qwen3.5-9B on MMSI-Bench or 1.9 points behind it.

That is one missing sentence away from resolved: were the baselines in the spatial table
evaluated with the same `<think>`/`\boxed{}` addendum? If they were, the lead is real and
`recurrent_reasoning/README.md` is just an ablation at different settings. If they were not,
the four marquee spatial results compare a prompted model against unprompted baselines. Until
that is stated, the defensible claim is narrower than the one on the front page:
ZDTaichu5.0-9B is a 9.79B multimodal model that responds unusually well to an explicit
reasoning-format instruction on multi-image spatial tasks — worth 10.4 points on MMSI-Bench
alone. That is a useful thing to know, and you can get it from the release's own two tables —
just not from either one alone.

<ChangeMyMind>
  <Falsifier claim="The model card's spatial scores and recurrent_reasoning/README.md's scores were produced under different prompts, and the gap is the prompt.">
    The model card's own footnote says the format instruction was added for ViewSpatial,
    MMSI-Bench, MindCube-tiny and VSI-Bench; the EARR footnote says it was not used. If the
    lab publishes an eval log showing the two tables differ for some other reason — a
    checkpoint revision, a different harness — the attribution is wrong, though the
    10.4-point contradiction on MMSI-Bench stands either way. RoboSpatial's 12-point gap has
    no such explanation at all.
  </Falsifier>
  <Falsifier claim="ZDTaichu5.0-9B's MMSI-Bench lead over Gemini 3 Pro depends on the prompt addendum.">
    Run MMSI-Bench's 1,000 questions against Gemini 3 Pro with the identical
    `<think>`/`\boxed{}` instruction. If Gemini stays at 45.20 with the addendum, the
    2.0-point lead is real and this reservation is unfounded.
  </Falsifier>
  <Falsifier claim="Most of the 'Key Design Points' in EARR.png have no implementation in the released code.">
    A grep of `recurrent_reasoning.py` (github.com/Taichu-AI/ZDTaichu5.0-9B, read 2026-09-18)
    returns zero hits for `margin`, `normaliz`, `residual`, `anchor` and `rollback`. If a
    later commit adds them, or if they live in unreleased training code and the diagram
    describes the trained model rather than the shipped inference path, this reads as a
    labelling problem rather than a missing feature.
  </Falsifier>
  <Falsifier claim="The NVFP4 checkpoint is 8.01 bits/weight, not 4.">
    Read the header: 2,113,929,216 bytes of `U8` packed weights against a 9,811,117,776-byte
    total and 9,794,197,512 parameters. If TaichuAI reuploads with the embedding, the vision
    tower and layers 28–31 quantized, the number moves. As shipped on 2026-09-18, it does not.
  </Falsifier>
  <Falsifier claim="The parameter count, shard sizes and config all agree with the artifact.">
    Every shard's post-redirect `Content-Length` equals its git-lfs pointer size, and
    8×5 + 106,344 + 19,588,395,036 = 19,588,501,420 = their sum. A mismatch on any shard, or a
    tensor shape contradicting `config.json` beyond the documented `q_proj` output gate, would
    break this.
  </Falsifier>
</ChangeMyMind>

<Figure
  src="/articles/zdtaichu-5-9b/fig3.png"
  alt="A twelve-panel bar chart titled 'ZDTaichu5.0-9B: Comparison with Closed Models', comparing ZDTaichu5.0-9B against Gemini 3 Pro, Grok 4 and GPT-5.2 across general visual understanding, spatial and embodied capabilities, and text and agent capabilities."
  caption="The closed-model comparison. The four spatial panels — MindCube-tiny, ViewSpatial, MMSI-Bench, VSI-Bench — are exactly the benchmarks whose ZDTaichu scores were measured with the added output-format instruction (ZDTaichu5.0-9B release, docs/assets/, file taichu-vs-closed-models.svg)."
/>

**Sources.** [TaichuAI/ZDTaichu5.0-9B](https://huggingface.co/TaichuAI/ZDTaichu5.0-9B) ·
[Taichu-AI/ZDTaichu5.0-9B](https://github.com/Taichu-AI/ZDTaichu5.0-9B) ·
[FP8](https://huggingface.co/TaichuAI/ZDTaichu5.0-9B-FP8) ·
[NVFP4](https://huggingface.co/TaichuAI/ZDTaichu5.0-9B-NVFP4) ·
[DSpark](https://huggingface.co/TaichuAI/ZDTaichu5.0-9B-DSpark) ·
[MMSI-Bench](https://arxiv.org/abs/2505.23764). All headers read 2026-09-18; weights under
the NVIDIA Open Model License, upstream Qwen3.5 under Apache-2.0.
