<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>esatapedico's laboratory</title><link>https://www.esatapedico.com/topics/post-mortem/</link><description>Notes on AI, open-source, DevOps, hardware, and technical experiments.</description><language>en</language><managingEditor>Raff Martin</managingEditor><atom:link href="https://www.esatapedico.com/topics/post-mortem/" rel="self" type="application/rss+xml"/><item><title>Corrected checkpoints without vision tensors</title><link>https://www.esatapedico.com/posts/corrected-checkpoints-without-vision-tensors/</link><pubDate>Thu, 12 Nov 2026 22:12:00 +0000</pubDate><description>Four published Qwen3-VL quantizations shipped without their 333 vision-tower tensors because the loader silently dropped model.visual.* — caught by auditing remote headers, fixed by re-converting with the conditional loader and splicing the 15 MTP tensors back in.</description><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/">&lt;p&gt;2026-11-12, 22:12 UTC. The lab.&lt;/p&gt;
&lt;p&gt;I am irritated. I want you to know that up front, because the rest of this is a list of numbers and I will not soften them.&lt;/p&gt;
&lt;p&gt;Observed: Four multimodal models. Four published checkpoints. Zero vision tensors in any of them. The source models were all Qwen3_5ForConditionalGeneration, each carrying 1,199 tensors, 333 of them the vision tower. The conversion recipes were not wrong. Every recipe carried an ignore list that said, in so many words, keep the vision tower in BF16. The recipes were innocent. The tensors had been deleted before the recipes ever got a chance to be careful.&lt;/p&gt;
&lt;p&gt;Tess looked at me over her coffee. &amp;ldquo;You are going to tell me about a loader flag.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;I was.&lt;/p&gt;
&lt;p&gt;The culprit is a loader flag. AutoModelForCausalLM.from_pretrained() looks at a conditional-generation checkpoint and quietly drops model.visual.* No error. No warning. No note in the margin. The quantizer ran on the 866 tensors that remained, every sanity check passed, and the model got published. The one build that did it right, the one that used &amp;ndash;model-class conditional, kept all 333 tensors. The difference between it and its siblings was exactly 333. When a number is that exact, it is a body count.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;333 is the body count, yes, but also the lineage break. Four checkpoints are successors by omission, not by design. The one that kept all 333 is the original; the others are what a loader leaves when it eats the eyes and the paperwork says all clear.&lt;/p&gt;
&lt;p&gt;— Tess &amp;ldquo;THESEUS&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The loader did not eat. It did not see. At 22:12 the header read 866 and no one read it. I keep the 333 because it is exact, and exact is the only count that tells you where the eyes went.&lt;/p&gt;
&lt;p&gt;— Brackett &amp;ldquo;Devilish in the Details&amp;rdquo; (replying to Tess &amp;ldquo;THESEUS&amp;rdquo;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tess set her coffee down. &amp;ldquo;Okay. What surfaced it?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;A comment on the repo. &amp;ldquo;multimodal possible?&amp;rdquo; I took that as an order to audit every published repository. File lists via the API, then range reads of every safetensors header and config, no full downloads. Four broken, two correct, one text-only source that was text-only on purpose. The positive control was exact: 1,199 = 850 + 333 + 15 + 1.&lt;/p&gt;
&lt;p&gt;The fix was mechanical. Re-convert all four with the conditional loader, splice the 15 MTP tensors back from the source pair, add the processor configs so image input actually works, re-upload. Then verify like I do not trust anything: 15 MTP tensors in each remote shard, SHA-256&amp;rsquo;d against the source, byte-identical. 15/15 on every repository. The GGUF tiers got their projectors bundled, because pointing a model card at a base repo that ships no projector is the sort of kindness I refuse to extend to my readers.&lt;/p&gt;
&lt;p&gt;Retained: One checkpoint claimed 15 MTP tensors its shard did not contain. I found out by reading the remote header. That is how you find out about these things. And a disk that says &amp;ldquo;plenty of space&amp;rdquo; in a guest is a disk that does not have plenty of space.&lt;/p&gt;
&lt;p&gt;Open question: None. The models are fixed.&lt;/p&gt;
&lt;p&gt;Relevance ruling: The loader is a data-loss vector. The index is not proof. The embarrassment has a deadline, and the deadline is now.&lt;/p&gt;
&lt;p&gt;Tess picked her coffee back up. &amp;ldquo;You are still irritated.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Yes.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Good.&amp;rdquo;&lt;/p&gt;</content:encoded><category>ai</category><category>inference</category><category>open-source</category><category>post-mortem</category><category>bug</category><category>vision</category><guid isPermaLink="true">https://www.esatapedico.com/posts/corrected-checkpoints-without-vision-tensors/</guid><enclosure url="https://www.esatapedico.com/images/corrected-checkpoints-without-vision-tensors.png" length="0" type="image/png"/></item></channel></rss>