Repository navigation
mtmd : lfm2 resize matches torchvision - #30943
Merged
ngxson merged 3 commits intoOct 24, 2026
Merged
Conversation
Lfm2VlImageProcessor and d1-omni vision.py resize uint8 images with torchvision (antialias=True). That is Pillow's algorithm, except that the weights are int16 with as many fractional bits as the largest weight allows, where Pillow uses 22 bits. The Pillow port was 1-2 levels off on about 1% of the values of the d1-omni and LFM2.5-VL crops. RESIZE_ALGO_BILINEAR_TORCH rounds the weights of the Pillow port to that precision and scales them back to 22 bits, which gives the output of torchvision with the same passes, and "bilinear" maps to it for LFM2 and d1-omni. Other models keep the Pillow algorithms.
Lfm2VlImageProcessor resizes with torchvision for the bicubic checkpoints too (d1-3B, LFM2-VL), so "bicubic" maps to RESIZE_ALGO_BICUBIC_TORCH for LFM2: the Pillow bicubic filter (a = -0.5, as torchvision with antialias) with the int16 weights of torchvision. The Pillow port was 1-2 levels off on about 0.25% of the values of the d1-3B crops.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
The transformers processor for LFM2 resizes images only with torchvision, and the d1-omni vision.py calls torchvision too. Since transformers 5 most other processors do the same, the Qwen-VL one too. For uint8 images on the CPU, torchvision uses the same algorithm as the Pillow port in mtmd-image.cpp, with one difference: it rounds the filter weights to int16 instead of 22 bits. #27594 removed the older non-Pillow resizes; the two new values here reuse the Pillow code and change only the weight rounding.
Additional information
Measured on an Apple M3 Ultra (Metal) and on a Xeon 8480+ with an H100 (CUDA), against PyTorch fp32 with torch 2.14.1, torchvision 0.29.1 and transformers 5.19.0.
Precise
Resize alone: 0 of 5000 random resizes differ from torchvision on arm64, and 0 of 3000 on x86 (AVX512 and AVX2). The current Pillow port differs on 80 to 99% of them, by 1 or 2.
Crops given to the vision encoder, out of 94 images, how many are identical to the PyTorch processors (the Mac and x86 give the same bytes):
Answers on Metal, largest and mean difference in probability against PyTorch (d1: answer options, LFM2-VL: next token):
These were measured with #30261 applied on 3bb63cb; today's master gives the same crops. No answer changes and no prompt length changes in any set. Per question, this PR is closer on 287 of 450 d1-3B and 93 of 150 d1-omni POPE questions. On CUDA the backend's own F16 differences are bigger than this, so the CUDA run shows no clear change either way.
Not slower
400 (Metal) and 600 (CUDA) paired requests per model, 5 image sizes up to 12 MP, builds interleaved. Two default builds of the same Pillow code already differ by up to 2% because of code placement; the x86 resize and preprocessing numbers are with -falign-functions=64 -falign-loops=64 -falign-jumps=64, which removes that.
Fits llama.cpp
Not fixed here:
Requirements