Views
No views yet
lfm2_5_vl_450m_xnnpack_8da4w.pte (369 MB)[1, 1024, 768] patches plus [1, 1024] attention mask,
and token ids for the words around it| method | in | out |
|---|---|---|
vision_encoder | patches, mask | [1, 256, 1024] rows in the decoder's embedding space |
token_embeddings | token ids | embeddings |
text_model | embeddings, positions | logits, and its own cache |
.pte and a text .pte runs aground there;
MultimodalPrefiller::load asks one module for token_embeddings and text_model and uses
vision_encoder if it finds it.convert/calib_images:| picture | answer |
|---|---|
| a London street | "A bustling street scene with people walking, outdoor seating, and various storefronts, including a prominent Pizza Express." |
| a man with a dog | "A man in a hat and overalls stands next to a wagon loaded with logs, with a water tower in the background." |
| a studio portrait | "A man in a gray long-sleeve shirt poses against a white background…" |
python convert/run_vl.py <image> "What is in this picture?"convert/export_vl_bundle.py. Four things needed re-authoring:torch.export cannot follow. The grid is fixed here, so the resize is computed once and
the constant handed to a replacement forward.text_model. ExecuTorch copies a mutable buffer into each
method that names it (Program::load_mutable_subsegment_into writes into the method's own
memory), so a prefill method and a decode method would each get their own and neither
would see the other's writes. One graph has to serve both, which rules out the two code
paths transformers keeps for LFM2's short convolution — a windowed convolution for a
prompt, a fused single-step update for a token, chosen in Python and therefore baked in by
tracing. Carrying the last kernel - 1 columns and putting them in front of whatever
arrives is the same arithmetic in one branch-free path.CONTEXT, the upper bound on the dynamic sequence dimension. The memory planner sizes its
arena for the bound, not for what a picture costs: at 4096 that arena is 3.7 GB and iOS
kills the process with signal 9 before the first method has finished loading. One square
photograph is 1024 patches, which the projector unshuffles to 256 rows, so 512 leaves room
for a long question and a long answer and brings the arena to 164 MB.nn.Embedding, and the quantisation filter in convert/export_vl_bundle.py
was written as isinstance(module, nn.Linear), so it went out in fp32 — 268 MB of a
566 MB file. tie_word_embeddings does not save it either: quantize_ swaps
lm_head.weight for a new tensor and the embedding keeps pointing at the old fp32 one.
(LFM2.5-VL ties and SmolVLM2 does not; both leaked.)IntxWeightOnlyConfig reaches an nn.Embedding but will not lower
(Missing out variants: {'torchao::dequantize_affine'}). On this model it is free: the first-step logits read corr 0.98109 against 0.98147 for the fp32 table, the greedy token sequence is identical, and the file drops from 566 MB to 369 MB.