The 8 GB Lab Book · Chapter 19
Vision tokens are context tokens
- Board
- Jetson Orin Nano Super
- Mode
- 15W
- Setup
- llama-server + mmproj
- Summary
- For Qwen2.5-VL-3B, 4.4x the vision tokens gave 2.9x the wait. Peak RAM did not rise with the tokens: the KV was allocated at start, at -c 4096.
What I expected
My model was simple: the tokens follow the pixels. Twice the side would give four times the tokens and four times the wait. I expected one straight ratio with no fixed part. I expected that both models would obey this ratio.
I also expected that the peak RAM counter would increase with the KV of the extra tokens. One of the three expectations was correct.
The theory
The tiler is a grid, so N_v is a patch count
QWEN2.5-VL-3B AT 640x360 (arithmetic)
28 px per token: 14 px patch, 2x2 merge (model card) 640 / 28 = 22.9 -> 23 across 360 / 28 = 12.9 -> 13 down 23 x 13 = 299 tokens = +2 markers = 301 server says 301
SAME MODEL AT 320x180
320 / 28 = 11.4 -> 11 across 180 / 28 = 6.4 -> 6 down 11 x 6 = 66 tokens 299 / 66 = 4.5, not 4: the grid snaps to 28 px, the image does not = +2 markers = 68 server says 68
Both counts match exactly. I read the 2 as the image start marker and the image end marker. On that reading, a 28x28 image costs 3 tokens.
TTFT as a line through the two QWEN points (arithmetic)
- slope
- 5.5 ms/tok
- intercept
- 112 ms
- prefill rate
- 182 tok/s
Prefill: what the counters allow (arithmetic)
3B weights by name x 2 flop = 6 GFLOP / token 332 tokens = 2.0 TFLOP 2.0 TFLOP / 1.935 s = 1.0 TFLOP/s if prefill took all of it Day 14 text prefill: 3.3 to 3.75 TF/s on this board at 3.3 TF/s, 332 tokens = 0.6 s = 1.3 s or more is encoder + launches (not split)
Decode, same model, one token
AI = 1 tok x 2 flop / 0.62 B per weight = 3 flop per byte far below any ridge on this board: memory-bound 1 / 15 tok/s = 67 ms per token Q4_K_M, 4.96 bits per weight (Day 14): 3B x 0.62 B = 1.9 GB 1.9 GB / 67 ms = 28 GB/s = Day 2's 28 GB/s SLM pull
The image adds tokens to prefillThe first phase of language-model inference, where the whole prompt is processed in one parallel pass to fill the KV cache; it is usually limited by compute. and work to the encoder. It does not change decodeThe phase after prefill where a language model generates one token at a time and re-reads its weights for each one; it is usually limited by memory bandwidth.. The 15 tok/sTokens per second: how fast a language model reads a prompt (prefill) or writes output (decode); the two rates are different numbers. at both sizes agrees with a weight stream near Chapter 2's 28 GB/s. Which side of the ridge prefill sits on, this run cannot say: prompt_ms holds the encoder and the LLM prefill together, and t_vit_ms is empty in results.json.
The setup
python3 ~/day19_vtokens.py
cat ~/day19/results.json | head -40"script": "day19_vtokens (llama-server)"
"prompt": "Describe what is in front of the robot in one sentence."
"res": { "hi": "640x360", "lo": "320x180" }
"rows": [ ... ]The measurement
| What | Expected | Measured | Note |
|---|---|---|---|
| SmolVLM-500M @ 640x360: N_v / TTFT / decode / peak | - | 134 / 403 ms / 75 tok/s / 1914 MB | The image shows two rectangles placed s |
| SmolVLM-500M @ 320x180: N_v / TTFT / decode / peak | - | 134 / 400 ms / 75 tok/s / 1942 MB | The image shows two rectangles placed s |
| Qwen2.5-VL-3B @ 640x360: N_v / TTFT / decode / peak | - | 301 / 1935 ms / 15 tok/s / 5255 MB | The robot is in front of a green square |
| Qwen2.5-VL-3B @ 320x180: N_v / TTFT / decode / peak | - | 68 / 656 ms / 15 tok/s / 5269 MB | In front of the robot, there is a red cu |
| robot default resolution | - | 320x180 (Qwen2.5-VL-3B) (estimate) | re-decided on real frames |

Image to grid to tokens to wait
- Image320 x 180
- Snap to 28 px308 x 168
- Grid 11 x 666 + 2 tokens
- Prefill656 ms
| model | res | N_v | TTFT ms | tok/s | peak MB |
|---|---|---|---|---|---|
| SmolVLM-500M | 640x360 | 134 | 403 | 75 | 1914 |
| SmolVLM-500M | 320x180 | 134 | 400 | 75 | 1942 |
| Qwen2.5-VL-3B | 640x360 | 301 | 1935 | 15 | 5255 |
| Qwen2.5-VL-3B | 320x180 | 68 | 656 | 15 | 5269 |
Where it broke
The ratio came from the grid, not from the pixels. 320 rounds down to 11 columns and 640 rounds up to 23. The ratio is 4.5x by the count and 4.4x by the server. The wait increased only 2.9x, because 112 ms of the wait is fixed.
Peak RAM never showed the extra 233 tokens, and it could not. llama-server ran with -c 4096, which allocates the whole KV at start. At Chapter 3's 144 KiB per token, which is Qwen3-4B's figure and not this model's, 233 tokens would be 34 MiB vs MBA mebibyte (MiB) is 2^20 bytes and a megabyte (MB) is 10^6 bytes; some tools label MiB as "MB", so check which one a tool actually counts.; this model's own per-token KV was not read from its log. Both models had a higher peak on the SMALL image, by 14 and 28 MB. That is counter noise.
My prior was a ratio with no intercept. Each prefill pays the cost of the encoder and the launch one time. A line was the correct prior.
I set 320x180 as the default because its caption still named the object. But the synthetic image has the words 'cup on table' drawn on it (day19_vtokens.py, cv2.putText), and the 320x180 caption said 'a red cup on a table' while the 640x360 caption described squares. Most likely the model read the label, not the shapes. The default is a placeholder until real frames.
The 134 of SmolVLM is a floor, and no camera mode decreases it. Vision that costs less than this floor needs a different model. The number that affects the robot is 2.9x, not 4.4x.
Summary
- N_v is the prompt token count of the server with the image, minus the count without the image. It is the number of prefill tokens that the image costs. The KB-per-token of the model, read from its log, changes it into KV bytes.
- Not every VLMVision-language model: a language model that also accepts images, turning them into tokens it reads alongside the text. scales. SmolVLM-500M resizes the image onto its fixed grid and costs 134 tokens at both sizes. Qwen2.5-VL-3B tiles the real pixels, and its count follows the image. Find which kind you have before you select a camera mode.
- Here, TTFTTime to first token: the delay between sending a request and receiving the first generated token, mostly spent in prefill. includes the image encoder. A language benchmark never shows this part. It is the time that the robot waits before the first word.
- The embeddingA fixed-length vector a model produces for an input, arranged so that similar inputs land close together and can be compared with simple distance math. of Chapter 17 answered at 68 fps. At 640x360, the VLM waits 1.9 s for its first token.
Sources
These sources are not mine. Measured numbers came off my own board; specs, estimates and paper figures are labeled as such.
- Qwen-VL / Gemma 4 multimodal cards (token / tile behavior)
- TensorRT Edge-LLM VLM benches (ViT time column on Nano)
- Your Day 3 KV math