Expand description
Host preprocessor for vision input (lane/vision): bytes -> ViT patch rows.
Qwen2VLImageProcessorFast semantics: smart_resize to multiples of
factor = patch(16) * merge(2) = 32 with the pixel-area budget, rescale 1/255,
normalize mean/std 0.5 -> [-1, 1], patchify to [ghgw, 321616 = 1536] rows in
row-major grid order with (c, t, ph, pw) inner order — the flatten of the conv
weight [1152, 3, 2, 16, 16], so VisionTower::forward consumes rows directly.
Images duplicate their frame across temporal_patch 2; videos fill the pair with
consecutive sampled frames.
Resize filter: CatmullRom (Keys bicubic a=-0.5, PIL-BICUBIC family). The HF fast processor runs torch bicubic (a=-0.75) antialias — close but not bit-equal; the merger-cosine parity gate arbitrates whether the difference matters.
Structs§
- Prepped
Image - Prepped
Video - One prepared VIDEO: temporal groups as PreppedImage units (each = one pad run of
gh*gw/4tokens) + per-group timestamps for the HF placeholder format (<t.t seconds>before each group’s pad run). Groups forward TOGETHER throughVisionTower::forward_seq— one attention span per video, the HF cu_seqlens law. - Vision
Unit - One pad-run unit crossing the API boundary: a standalone image, or one temporal
group of a video. Units with the same
videoindex are consecutive and forward TOGETHER throughforward_seq(one attention span per video).
Constants§
- GIF_
MAX_ FRAMES - Decode ceilings for
prep_video_gif(hermes finding, fixed 2026-08-19): the loop used to expand EVERY frame to full-canvas RGB in host RAM before theVID_MAX_FRAMESsample — and it runs in the HTTP handler pre-admission, so a small crafted GIF (big canvas x many frames; LZW expands ~1000x) allocated GBs per request. The canvas dimensions come from the GIF header, soframes x canvas pixelsis checked against the pixel ceiling AS DECODE PROCEEDS and the request is refused (clean 4xx at the handler) the moment the budget would cross — retained RAM is bounded byGIF_MAX_TOTAL_PIXELSRGB (192 MiB) plus at most one transient canvas, no matter what the stream claims. 512 frames / 67.1M px comfortably cover legitimate clips (a 480p GIF may run ~370 frames, ~12 s at 30 fps) — the serve path samples down to 32 frames and ~2M px right after this anyway. - GIF_
MAX_ TOTAL_ PIXELS - MAX_
PIXELS - MIN_
PIXELS - Area budget (pixels) from preprocessor_config: shortest_edge / longest_edge.
- VID_
MAX_ FRAMES - Sampled frame cap (2 frames per temporal group).
- VID_
MIN_ PIXELS
Functions§
- decode_
data_ uri - Parse a base64 data URI into raw bytes (any
data:*;base64,media type). - prep_
data_ uri data:image/...;base64,<payload>-> patch rows.- prep_
image_ bytes - Image bytes (png/jpeg/webp/gif/bmp) -> patch rows. The single frame fills both temporal slots (HF: images are tiled to temporal_patch_size).
- prep_
video_ gif - Animated GIF -> prepared video: decode frames + delays, uniform-sample to an even
count <= VID_MAX_FRAMES, resize on the total-pixel budget, patchify CONSECUTIVE
frame pairs into temporal groups (frame 2g fills t=0, 2g+1 fills t=1). Timestamps
come from the GIF’s own delays at the sampled indices (HF
_calculate_timestamps). - smart_
resize - smart_resize (HF): round each side to a multiple of 32 preserving aspect ratio, then scale into the [MIN_PIXELS, MAX_PIXELS] area budget.
- video_
max_ pixels - Serving cap on total video patches (groupsghgw): sdpa_naive keys the whole span in shared memory, so the pixel budget stays well under the HF default. Env-tunable.