Repository navigation
glm cuda: TF_GLM_VISION_HOST keeps the vision tower's weights in pinned host memory - #1760
Merged
Merged
Conversation
…ed host memory With TF_GLM_VISION_HOST=1, the tower's bf16 weights load into pinned host memory mapped into the device's address space, and an encode copies each unit of the pass (the patch embedding, each block, the post-norm and downsample, the merger's projection, its MLP) into one device slot just before the work that reads it, on the same stream. The device keeps the slot, the size of the largest unit, instead of the whole tower. Quantized towers are refused in this mode.
ashhart
force-pushed
the
glm-vision-host
branch
from
October 31, 2026 21:02
aa9485e to
faa0920
Compare
Owner
|
Thank you @russellmm. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
Contributor
Author
|
I have the final piece that should be done soon which is to allow most of the KV Cache to sit pinned in system memory. This will allow the full 1M context of the GLM5.3-Flash model on a Dual RTX-6000. Without the final piece, we can get up to 512K KV with a 1.5GB VRAM reserve. |
This was referenced Nov 1, 2026
Closed
Owner
|
Thanks @russellmm! |
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.
What this changes
With
--vision, GLM-5.3-Flash on CUDA keeps its whole vision tower on rank 0: 1.05 GiB of bf16 weights that are idleexcept while an image is encoded. Rank 0's room bounds every rank's KV pages and prompt cache.
With
TF_GLM_VISION_HOST=1:the patch embedding, each block, the post-norm and downsample, the merger's projection, and its MLP.
Fixes #1759. Follows #1736 (prompt states in host memory, merged); the two touch different files.
Modules:
cuda_vision_weights.zig(new): where the tower's tensors live, plus the name lookups moved out ofcuda_vision.zig, which stays under 600 lines.cuda_vision_stage.zig(new): the units, the slot and the copies.cuda_vision.zig: load places the weights, and the encode brings each unit in turn.No kernel, scheduler or arithmetic change.
Why
This is the second step toward serving GLM-5.3-Flash on two 96 GB cards with system memory relieving the KV window.
The checkpoint's weights take 86.2 GiB of each card, which leaves rank 0 about 4-5 GiB for KV pages and the prompt
cache. The first step, #1736 (merged), moved kept prompt states to host memory. This one moves the idle vision tower.
Why staged copies and not zero-copy. Letting the kernels read the weights from host memory directly saved a little
more device memory, but cost about 5x per image:
The GEMMs read each weight many times. Staging copies each byte across PCIe once a pass (~1.05 GiB, about 19 ms at
~57 GB/s).
Receipt
Environment.
main94b90c9 with and without this commit, built with Zig 0.17.0 and nvcc 13.4.92 (-Dsm=120).cuBLASLt 13.4, driver 615.71.09, Linux 7.3.
Mia-AiLab/GLM-5.3-Flash-EXL3-4bpw-TensorFold@ 76c0b517.--vision --context 327680 --kv-cache bf16 --parallel 2,TENSORFOLD_MEMORY_RESERVE_GIB=2.6.--chat-template: the checkpoint's own template with its media branch taken from zai-org/GLM-5.3-Flash. Thecheckpoint's template is text-only: it replaces images with a refusal, and the server warns so.
Exactness.
tools/bench_concurrent.py --levels 1,2 --tokens 256 --temperatures 0 --alone --serial, code and chat. Baselineand candidate: alone 3/3 and 6/6 equal, serial 1/1 equal in every cell; 0 unequal, 0 failed.
are identical between baseline and candidate.
Memory (rank 0's startup line):
--context 393216, same flagsImage speed. First token of a 1-token reply; each request is salted so nothing is reused; median of 3, two
alternating server starts each:
Decode speed (
tools/bench_openai.py --tokens 256 --reps 3 --temperatures 0), median tok/s; identicaltoken_shain every cell.bench_concurrent.pyaggregate at 2 streams: code 378.7 vs 378.1, chat 241.6 vs 241.3.Prompt speed (
tools/bench_cache.py --require-cold --tokens 64), fixed token arrays from the repository's docs,fresh server each run, alternating. Cold
ttft_s, with the sametoken_shaandcached_tokens0:Tests run.
zig build test --test-timeout 10m: 5,753 passed (main's 5,752 plus the new unit test incuda_vision_stage.zig), 27 skipped, 0 failed.test-kernel-contract: 141/141.test-golden: pass.test-server-security test-pull-security: 26/26.fuzz-cortheon: 17/17.zig build: pass.build_options_test.py: pass.git diff --check: clean.lean_new.pyagainstmain: 424 on the base, 424 on the head, 0 new.Not run, and why.
libtfvideo, not built here. It uses the same encode path, so it is expected to behave thesame, but it was not measured.
Checklist
changes.
"draft": false, and concurrent equals solo (resumed prompts are untouched by this change).main(cold 32K/64K above; image encodes 10-15 ms slower).