mirror of
https://github.com/Niko1221/Strata.git
synced 2026-11-07 14:21:06 -10:00
AMD: the Qwen on-demand picture reader works on HIP (reader with its CPU reader beside it, one GPU) and releases its VRAM when idle, but is off by default (VISION_ON_DEMAND_AMD_BY_DEFAULT): no shrinking expert cache on HIP, so 7,959 slots against 7,943 for +5.4 s on the first picture; docs
This commit is contained in:
1 parent
e04ee998f2
commit
e5de74282e
3 files changed
+28
-5
No files matched your search
@@ -114,7 +114,10 @@ it, so between pictures it holds no VRAM. Its room comes from the reserve (`--vr
|
||||
number the person or the app chose is kept). A start that finds no room (the reserve used by another program, the card busy, the reader not
|
||||
starting) is read by the CPU reader, which is the same program without `--gpu`, with the same picture tokens; the next start tries the card again.
|
||||
`"elastic": false` in the config's `"vision"` section keeps the reader on the card as before; `"elastic": true` asks for it on any card the
|
||||
reader runs on. AMD, Intel and a Mac keep their readers as they were (not measured there). Not by default with a layer split, batch slots,
|
||||
reader runs on. Intel and a Mac keep their readers as they were (not measured there). AMD works the same way (the HIP reader, with the CPU reader beside it) but is
|
||||
off by default: there is no shrinking expert cache on HIP, so the reader's room stays in the reserve and the experts get nothing back (Radeon AI PRO R9700, Qwen
|
||||
UD-Q4_K_XL: 7,959 slots on demand, 7,943 with the reader on the card, 8,411 with the CPU reader), and the first picture after a start takes 5 s longer (the HIP reader starts
|
||||
in 4.9 s, 1,480 MiB). It releases its VRAM when idle (30,585 to 32,098 MiB while it runs, back to 30,618 after 120 s). `"elastic": true` in the vision section asks for it. Not by default with a layer split, batch slots,
|
||||
`--kv-grow` or `--peer-device`.
|
||||
|
||||
With `"vram_elastic": true` as well (opt-in) the expert cache gives the room instead of the reserve:
|
||||
|
||||
+10
-3
@@ -9204,6 +9204,10 @@ READER_NEEDS_MIB = 1536 # what the GPU picture reader takes from the card (1
|
||||
#: the reader on the card, 1.3 GB less VRAM in use between pictures. The expert cache that gives its room (vram_elastic) held 8.5% more slots
|
||||
#: and was 2.2% slower in text (4 pairs of 5), so it stays opt-in.
|
||||
VISION_ON_DEMAND_BY_DEFAULT = True
|
||||
#: AMD (HIP): the rule works there (the HIP reader starts on the first picture, +5.4 s on an R9700, and stops when idle) but is OFF by default: with no shrinking
|
||||
#: expert cache on HIP the room has to stay in the reserve, so the engine gets no more slots (R9700, Qwen UD-Q4_K_XL: 7,959 against 7,943 with the reader on the card).
|
||||
#: "elastic": true in the vision section asks for it. Set True if the expert cache can give its room on HIP.
|
||||
VISION_ON_DEMAND_AMD_BY_DEFAULT = False
|
||||
VISION_RESERVE_MIB = 2048
|
||||
_ON_DEMAND_NOT_WITH = ("--kv-grow", "--batch", "--slots", "--peer-device", "--expert-cache-device1", "--expert-cache-device2",
|
||||
"--expert-cache-device3")
|
||||
@@ -9211,19 +9215,22 @@ _ON_DEMAND_NOT_WITH = ("--kv-grow", "--batch", "--slots", "--peer-device", "--ex
|
||||
|
||||
def vision_on_demand_by_default(cfg: dict) -> bool:
|
||||
"""True when this config's GPU reader should start on demand without the config saying so: a GPU reader (vision.gpu) of the NVIDIA
|
||||
kind on one GPU, no batch slots, no --kv-grow, no helper caches, and nothing in the vision section that says otherwise. Not DeepSeek
|
||||
(its own tower), not AMD, Intel or a Mac (not measured there), not a reader pinned to another card (vision.cuda_device)."""
|
||||
kind (or AMD's, with its CPU reader) on one GPU, no batch slots, no --kv-grow, no helper caches, and nothing in the vision section that says otherwise. Not DeepSeek
|
||||
(its own tower), not Intel or a Mac (not measured there), not a reader pinned to another card (vision.cuda_device)."""
|
||||
vis = cfg.get("vision")
|
||||
if not VISION_ON_DEMAND_BY_DEFAULT or not isinstance(vis, dict) or vis.get("gpu") is not True or "elastic" in vis:
|
||||
return False
|
||||
if vis.get("cuda_device") is not None or sys.platform == "darwin":
|
||||
return False
|
||||
if (cfg.get("arch") or "") == "deepseek41" or cfg.get("backend") not in (None, "cuda"):
|
||||
backend = cfg.get("backend")
|
||||
if (cfg.get("arch") or "") == "deepseek41" or backend not in (None, "cuda", "hip"):
|
||||
return False
|
||||
args = [str(a) for a in (cfg.get("args") or [])]
|
||||
if len(gpu_list(cfg)) > 1 or parallel_slots(cfg) or any(a in args for a in _ON_DEMAND_NOT_WITH):
|
||||
return False
|
||||
name = re.split(r"[\\/:]", str(vis.get("exe") or ""))[-1].lower() # a path or a "component:..." reference
|
||||
if backend == "hip": # AMD: the HIP reader, with the CPU reader setup wrote beside it to read when the card has no room
|
||||
return VISION_ON_DEMAND_AMD_BY_DEFAULT and name in (vision_reader.GPU_READER, vision_reader.GPU_READER + ".exe") and bool(vis.get("cpu_exe"))
|
||||
return name in (vision_reader.CPU_READER, vision_reader.CPU_READER + ".exe")
|
||||
|
||||
|
||||
|
||||
@@ -270,12 +270,25 @@ class OnDemandByDefault(unittest.TestCase):
|
||||
bs = chr(92)
|
||||
self.assertTrue(vision_on_demand_by_default(self.cfg(vision={"exe": "C:" + bs + "e" + bs + "strata-vision.exe"})))
|
||||
|
||||
def test_the_amd_reader_with_its_cpu_reader_is_on_demand_when_asked(self):
|
||||
import serve.server as S
|
||||
f = S.vision_on_demand_by_default
|
||||
amd = self.cfg(vision={"exe": "/e/strata-vision-hip", "cpu_exe": "/e/strata-vision"}, backend="hip")
|
||||
self.assertFalse(f(amd)) # off by default on AMD (no slots gained: see the constant's note)
|
||||
with mock.patch.object(S, "VISION_ON_DEMAND_AMD_BY_DEFAULT", True):
|
||||
self.assertTrue(f(amd))
|
||||
self.assertTrue(S.apply_vision_defaults(amd)["vision"]["elastic"])
|
||||
with mock.patch.object(__import__("serve.server").server, "VISION_ON_DEMAND_AMD_BY_DEFAULT", True):
|
||||
self.assertFalse(f(self.cfg(vision={"exe": "/e/strata-vision-hip", "cpu_exe": "/e/strata-vision"}, backend="hip", gpu=[0, 1])))
|
||||
self.assertFalse(f(self.cfg(vision={"exe": "/e/strata-vision-sycl", "cpu_exe": "/e/strata-vision"}, backend="sycl")))
|
||||
|
||||
def test_what_stays_as_it_was(self):
|
||||
from serve.server import vision_on_demand_by_default as f
|
||||
self.assertFalse(f(self.cfg(vision={"gpu": False}))) # the CPU reader
|
||||
self.assertFalse(f(self.cfg(vision={"elastic": False}))) # the person said no
|
||||
self.assertFalse(f(self.cfg(vision={"cuda_device": 1}))) # a reader on its own card
|
||||
self.assertFalse(f(self.cfg(vision={"exe": "/e/strata-vision-hip"}, backend="hip")))
|
||||
self.assertFalse(f(self.cfg(vision={"exe": "/e/strata-vision-hip"}, backend="hip"))) # AMD without its CPU reader
|
||||
self.assertFalse(f(self.cfg(vision={"exe": "/e/strata-vision"}, backend="hip")))
|
||||
self.assertFalse(f(self.cfg(backend="sycl", vision={"exe": "/e/strata-vision-sycl"})))
|
||||
self.assertFalse(f(self.cfg(gpu=[0, 1]))) # a layer split
|
||||
self.assertFalse(f(self.cfg(args=["--vision", "--kv-grow"])))
|
||||
|
||||
Reference in new issue
Block a user