Repository navigation
serve: let the image encoder run on its own GPU (vision.cuda_device) #408
Description
Request: let the image encoder run on its own GPU, chosen in the config, separate from the cards the engine uses.
Why: I have three cards: two RTX 5060 Ti 16 GB that hold the IQ3_S layer split ("gpu": [0, 1]) and a spare RTX 3060 12 GB. With --vision gpu, strata-vision starts with the engine's environment (child_env(cfg), so CUDA_VISIBLE_DEVICES=0,1) and lands on card 0. It takes room the expert cache could use (the "few % slower" in the docs) while the 3060 sits idle. I couldn't find a setting for this; the env is shared at server.py where Vision(cfg["vision"], ..., env=env) is built.
What I run locally (0.1.30): an optional "cuda_device" in the config's vision section. When it is set, the encoder gets a copy of the env with CUDA_DEVICE_ORDER=PCI_BUS_ID and CUDA_VISIBLE_DEVICES=<n> (numbered like nvidia-smi, as in #51). When it is absent, nothing changes.
"vision": { "exe": "...\strata-vision.exe", "mmproj": "...", "model": "...",
"gpu": true, "max_tokens": 1024, "cuda_device": 2 }diff --git a/serve/server.py b/serve/server.py
index e03379e..e008b16 100644
--- a/serve/server.py
+++ b/serve/server.py
@@ -565,6 +565,19 @@ def child_env(cfg: dict) -> dict:
return env
+def vision_env(cfg: dict, env: dict) -> dict:
+ """The image encoder's environment: the engine's, unless the config's vision section names its own
+ "cuda_device" (numbered like nvidia-smi) - then the encoder runs on that card alone, so a spare GPU can hold it
+ while the engine keeps every byte of its own cards."""
+ dev = (cfg.get("vision") or {}).get("cuda_device")
+ if dev is None:
+ return env
+ env = dict(env)
+ env["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
+ env["CUDA_VISIBLE_DEVICES"] = str(dev)
+ return env
+
+
class ByteTokenizer:
"""Tiny stand-in tokenizer for tests without the pack: one id per UTF-8 byte, specials as ids >= 256."""
SPECIALS = ["<|im_start|>", "<|im_end|>", "<|endoftext|>", "<|vision_start|>", "<|image_pad|>", "<|vision_end|>"]
@@ -1917,7 +1930,7 @@ def main() -> int:
if cfg.get("vision"):
print("loading the vision encoder ...", flush=True)
vision = Vision(cfg["vision"], log=open(cfg["log"], "a", encoding="utf-8") if cfg.get("log") else None,
- env=env)
+ env=vision_env(cfg, env))
print("loading the model (the first start takes a minute or two) ...", flush=True)
if len(gpu_list(cfg)) > 1:
print(f"[strata] layer split across GPUs {gpu_list(cfg)} ({cfg.get('layer_split') or 'auto'})", flush=True)Plus a unit test next to GpuChoice.test_env: the encoder env gets "2", the engine env stays "0,1", and without cuda_device the engine's env is returned unchanged.
Measured (Windows 10, driver CUDA 13.0, engine 0.1.30, prebuilt strata-vision.exe with sm_86):
nvidia-smishowsstrata-vision.exeon the 3060 only. The 3060 went from about 0.9 to 2.3 GB, and the two 5060 Tis stayed at about 14.9 / 15.0 GB./v1/statusreports"vision": {"enabled": true, "available": true}.- A 1328×1328 PNG through
/v1/chat/completions(image_urldata URL) was described correctly, with 1,073 prompt tokens and 11.5 s for the full request including 151 output tokens.
Open points for you:
- setup.py could offer this when it finds a card outside the engine's set. I only edited the config by hand. I appended
--visiontoargsbut left out--vram-reserve-mib, since 700 is already the engine default. - The encoder's card has to be in
vision_archs(86/89/120 in the prebuilt). This patch does not check that.
Happy to open a PR if this shape works for you.
Activity
Niko1221 commentedon Oct 1, 2026
Thanks, taken as you described for the next release:
"cuda_device"in the config'svisionsection runs the encoder on that card alone (numbered likenvidia-smi); without it nothing changes. Documented in DETAILS.md (Images), with a note to lower--vram-reserve-mibto 700 in that case. Credited to you. This issue closes with the release.serve: the image encoder on its own GPU, "cuda_device" in the vision …
Engine 0.1.33: a portable image encoder again (#411 #412), setup reco…
Niko1221 commentedon Oct 1, 2026
Released in 0.1.33:
"cuda_device"in the vision section. Thanks!serve: the image encoder on its own GPU, "cuda_device" in the vision …
Engine 0.1.33: a portable image encoder again (#411 #412), setup reco…
serve: the image encoder on its own GPU, "cuda_device" in the vision …
Engine 0.1.33: a portable image encoder again (Niko1221#411 Niko1221#412
serve: the image encoder on its own GPU, "cuda_device" in the vision …
Engine 0.1.33: a portable image encoder again (Niko1221#411 Niko1221#412