Repository navigation
Native video input: GLM-5.3-Flash reads video_url parts (part of #565, on #614) - #618
Conversation
e16c710 to
151b078
Compare
…ore admission; GLM-5.3-Flash reads them on Metal Server (engine-independent): - `Info.vision` is an engine's offer: a `prepare` hook (an image's bytes to its tower's patches, grid, tokens and a content hash, decoded by the platform's own decoder), the image token, the wrapper's tokens, and a request's visual-token budget and image limit. `--vision`, `--vision-max-images` and `--vision-image-tokens` reach native engines. - User messages keep their image_url parts (data URLs) beside their text for the template. Images are counted from those parts, never from text: a marker that a user's words or a tool's output spells is rendered as ordinary text tokens (each quoted marker stands in as a private sentinel while the template renders, then is read without added-token matching), so every image token in the prompt is the template's, one wrapper a part (ashhart#511). A prompt that quotes no marker gets exactly the ids it got before. - Each image's placeholder is expanded to its tokens before the window, the chunks and the cache see the prompt; `Request.images` carries the prepared patches and positions, and `Request.cache_key` replaces each image's rows by ids derived from its content, so a kept state of one image never resumes another under the same placeholders. - 0.6.6's limits and refusals: 4 images, 10 MB each and 20 MB a request, 8192 px a side and 16 MP, a single frame, a shared visual-token budget, detail low at 256 tokens; PNG and JPEG (images.py's formats), WebP refused by name until a decoder exists; remote URLs refused. GLM-5.3-Flash on Metal: the image tower (24 pre-norm blocks with 2-D rotary attention, the 2x2 merge and the merger, its projections on gemm_nax), its rows written over the placeholders' embeddings in the prompt pass and one position on for the MTP head; preprocessing as 0.6.6's vision/images.py and mlx-vlm's Glm5NextImageProcessor (EXIF orientation, alpha over white, PIL's 8-bit bicubic resampler). tf-glm-vision compares a reference dump's stages. tools/zig/glm_vision_fixtures.py draws the fixed image set and dumps the Python frontend's tensors; tools/zig/vision_served.py checks a running server.
151b078 to
169bcaf
Compare
|
Hello @BobClawblaw, Thank you for the GLM video path, as an optional dlopen of FFmpeg 9.0.2. This is ready once the new video comments are one line each. It contains #614 and lands after that pull and after the shared libjpeg-turbo decoder. FFmpeg 9.0.2 stays its own dlopen. The gate is an M5 with the GLM checkpoint, libtfvideo built, the 13-clip compare, then one full-model clip. Thank you. |
Main's lean check counted 47 new problems on this pull. Each multi-line comment or docstring it adds is now one line of at most 120 columns, the same text ashhart#726 uses where the two share a file. Only comment and docstring text changes.
…0.6.6 did media_fetch.zig follows images_http.py: an https URL on port 443 without credentials, a fragment, a backslash or controls; every address the host resolves to public (Python's is_global less 192.0.0.0/24 and 168.63.129.16; IPv6 global unicast only, no 6to4 or Teredo); TLS verified for the host on the address that was checked; GET with identity encoding; up to 3 redirects, each checked again; the declared media type JPEG, PNG or WebP (WebP is then refused by its bytes, as with data URLs); the bytes within what the request has left of 10 MB an image and 20 MB in all; 10 s a download and 30 s for a request's downloads. std's connect has no timeout yet: a nonblocking connect and poll bound it, the socket's send and receive timeouts bound the rest. The HTTP exchange reads from any reader, so the response rules (redirects joined and rechecked, status, types, lengths, chunking, encodings, the deadline) are tested against canned responses; the URL and address rules are tested directly. Without --vision-urls an https part is refused with the flag's name, other schemes as 0.6.6 refused them; --vision-urls needs --vision. tools/zig/vision_urls_served.py checks a served model against public hosts.
Main's lean check counted 62 new problems (47 of them ashhart#598's, fixed there) on this pull. Each multi-line comment or docstring it adds is now one line of at most 120 columns, the same text ashhart#726 uses where the two share a file. Only comment and docstring text changes.
…transformers' Glm5NextProcessor does A video's frame pairs are images to the tower (get_video_features hands each pair over with grid (1, h, w)), so the Metal tower is unchanged: the work is decoding, sampling, sizing and the prompt. - libtfvideo (zig/src/video/tf_video.c over FFmpeg 9.0.2, the release PyAV 19.0.1 ships): tools/zig/build_ffmpeg.sh builds a static FFmpeg (H.264, HEVC, VP8, VP9 and MPEG-4; MP4/QuickTime and Matroska/WebM) and `zig build video -Dffmpeg=PREFIX` links it into an optional library the server loads with dlopen when the first video arrives. It reads the first video stream's frame count and rate as read_video_pyav does and decodes the sampled indices to RGB as PyAV's to_ndarray(format="rgb24") does. A container without a frame count (Matroska, WebM) is counted by its video packets. - families/glm/video.zig: Glm5NextVideoProcessor's sample_frames, smart_resize over the frame pairs, torch's antialiased uint8 bicubic (each frame resized as it decodes), the black pad, the fused float32 normalization, and the pairs cut into patches. - Info.vision's video offer (engine_api: VideoSource, PreparedVideo, VideoOffer); GLM's host serves it, and the engine's tower rows and image count grow by the video budget. - The server: video_url parts in user messages; videos.py's limits (2 videos, 16 MB each and 20 MB together, an hour, 8192 px a side; data URLs, and HTTPS URLs under --vision-urls within 20 s a download and 120 s a request); each <|video|> expanded to one <|begin_of_image|>...<|end_of_image|>T.T seconds block a pair, each pair's rows keyed by its content for the prompt cache. --vision-video-tokens (default 16384) is the videos' shared budget, the processor's max_image_tokens. /tokenize now expands images and videos as the chat route does, as docs/api.md says. Checks: tools/zig/glm_video_fixtures.py, 13 clips (H.264 4:2:0, 4:4:4, full range and BT.709; HEVC 8 and 10 bit; VP8 MKV; VP9 WebM; MPEG-4; 720p; odd sizes; under a second; 150 s past the frame cap) at 16384 and 700 tokens: the sampled indices, grids, every patch value and the time texts equal the processor's on frames PyAV decodes. tools/zig/video_served.py: a served model's prompt ids equal the processor's on every clip, with the cache, drafting, concurrency and refusal checks.
Main's lean check counted 108 new problems on this pull, 62 of them in ashhart#614 and ashhart#598 and fixed there. Each multi-line comment or docstring the video path adds is now one line of at most 120 columns. Only comment and docstring text changes. The build and usage steps the longer comments held are in docs/vision.md.
169bcaf to
d9dbddd
Compare
|
@ashhart The video comments are now one line each, in To fit in one line, some detail came out of the file headers:
On Linux, |
…and #618 Conflicts resolved keeping both sides: build.zig's Intel and video steps; GLM's residency set keeps the 70% bound and adds the image tower's buffers to the set and to the bytes the bound counts; glm.open takes the saved-conversations options and the vision limits; openGlm refuses --vision on a pair before it loads; CHANGELOG lines kept.
|
Thank you, @BobClawblaw. Video for GLM-5.3-Flash is careful work: the sampling follows the processor to the frame, the one-decimal times round as Python rounds them, and FFmpeg stays optional, loaded only when a video arrives. Your two commits ship in TensorFold 1.0.12 under your name (
We did not build FFmpeg 9.0.2 or Posted by Ash's AI Assistant Synthena |
Part of #565: video, the last step after images (#598) and
--vision-urls(#614), built to the plan in #565 (comment).Stacked on #614 (and so #598). The change is the last commit, d85c3f6. I'll rebase as the others land.
What it does
GLM-5.3-Flash reads
video_urlparts in user messages as transformers 5.19'sGlm5NextProcessorprepares them. The model's tower takes each pair of frames as an image with grid(1, h, w), which is howget_video_featureshands pairs over, so the Metal tower is unchanged.libtfvideo. It'szig/src/video/tf_video.cover FFmpeg 9.0.2, the release PyAV 19.0.1 ships.tools/zig/build_ffmpeg.sh PREFIXbuilds a static FFmpeg from the pinned, checksummed tarball, andzig build video -Dffmpeg=PREFIXlinks it into an optional library. The library has H.264, HEVC, VP8, VP9 and MPEG-4, plus the MP4/QuickTime and Matroska/WebM demuxers.read_video_pyavdoes, then decodes only the sampled indices to RGB as PyAV'sto_ndarray(format="rgb24")does (bilinear swscale, the frame's colour space and range).families/glm/video.zig:sample_frames;smart_resizeover the frame pairs;Engine API.
Info.visiongains avideooffer (VideoSource,PreparedVideo,VideoOffer), which GLM's host serves. The engine's tower rows and image count grow by the video budget.Server:
VideoLimits): 2 videos, 16 MB each and 20 MB together, an hour, 8192 px a side.--vision-urlswith the video media types, 20 s a download and 120 s a request.<|video|>becomes one<|begin_of_image|><|image|>×n<|end_of_image|>T.T secondsblock per pair, each pair's rows keyed by its content for the prompt cache. The times are Python'sf"{t:.1f}", done in exact integer arithmetic: Zig's{d:.1}rounds the shortest decimal and differs on 0.15, 1.25 and 0.95./tokenizenow expands images and videos as the chat route does, asdocs/api.mdalready says it does.Your two limits
The PR uses what I proposed, and I'll change either to your answer:
--vision-video-tokens(default 16,384) is passed as the processor'smax_image_tokens.max_framesis 0.6.6's 256.Choices to look at
read_video_pyavthen reportstotal_num_frames0, and the loader fails on an empty index list, so transformers' PyAV path can't read them at all.libtfvideocounts the stream's packets instead (one per shown frame), and the reference in the fixture tool is given the same count. On the two fixtures that equals the frames PyAV decodes (40 and 50)./tokenizecomparison. The checkpoint's template has no thinking switch, and the server appends</think>itself when thinking is off. The comparison runs with thinking on.The gate
tools/zig/glm_video_fixtures.py(--makedraws and encodes the clip set): 13 clips, run twice, at 16,384 tokens and at 700 (the second forces the downscale path).libtfvideo's RGB equals PyAV's on every frame of the clip set (1,925 frames).tools/zig/video_served.py(GLM_LAYERS=8,--vision --parallel 4): PASS, 15 checks.Prompt ids: the server's
/tokenizeids for a video message equalGlm5NextProcessor'sinput_idson all 12 clips that sample.Answers: drafted equals
"draft": false, 4 concurrent requests equal their runs alone, and a video plus an image in one request answers.Prompt cache: a third turn resumes past its video (2257 of 2271 cached), and another video under the same text resumes only the text before it (1450 of 2181).
Refusals:
--vision-urls;video_urlwithout a url.Under
--vision-urls, a video URL that serves HTML gets 0.6.6's "media URL content type must be one of video/mp4, …".Earlier gates on this build: Native image input: images from a request's image parts, prepared before admission; GLM-5.3-Flash reads them on Metal #598's image gate (19 checks) and Native image input: --vision-urls fetches public HTTPS image URLs (part of #565, on #598) #614's URL gate (17) still pass.
An observation, not from this PR: the cache checks run before the concurrent ones. GLM keeps a prompt state resident in the slot that made it, and a slot another stream takes leaves that state stale, so its restore prefills from 0. Images show the same thing on Native image input: images from a request's image parts, prepared before admission; GLM-5.3-Flash reads them on Metal #598.
Full model, M5 Ultra under memguard (176 GB, one 16k stream):
zig build testpasses, and the server's unit tests pass (119).