Vulkan GPU picker: allow uncached Hub GGUFs, backstop diffusion at spawn

The pre-download /load and /validate Vulkan gates rejected gpu_ids whenever
_classify_diffusion_gguf was not False, but None is the ordinary first-load
case for an uncached Hub GGUF (no local header to classify yet). That 400'd
first-time remote GGUF loads and made the new Vulkan GPU picker unusable unless
the model was already cached.

Reject only a CONFIRMED diffusion GGUF (is True) at the gates. For the rare
uncached model that turns out to be diffusion after download, add a spawn-time
backstop in load_model: on a Vulkan build, drop the unmappable gpu_ids pin
before _start_diffusion_server (ggml Vulkan ordinals cannot be forwarded as the
runner's CUDA/DG token) so it serves on the default device instead of the wrong
card. Regression tests cover the relaxed gate and the spawn backstop.
This commit is contained in:
LeoBorcherding 2026-07-23 18:34:04 -05:00
commit a9afb8011c
3 changed files with 56 additions and 7 deletions

View file

@ -6404,6 +6404,22 @@ class LlamaCppBackend:
# Not a tensor/layer GGUF: clear any preserved-fallback flag from a
# prior load (this path skips the command builder that clears it).
self._layer_preserves_tensor_intent = False
# Backstop for the relaxed Vulkan validation gate: /load and
# /validate only reject a CONFIRMED-diffusion pick up front, so an
# uncached GGUF that turns out to be diffusion after download can
# still arrive here with a pin. On a Vulkan build gpu_ids are ggml
# Vulkan ordinals, but _diffusion_gpu_arg forwards gpu_ids[0] as a
# CUDA/DG_GPU token -- an ordinal there would target the wrong
# card. Drop the unmappable pin so the runner uses its default
# device selection instead (same as an unpinned diffusion load).
if gpu_ids and is_vulkan_backend:
logger.warning(
"Ignoring gpu_ids %s for diffusion GGUF on a Vulkan build: "
"the diffusion runner cannot map ggml Vulkan ordinals; "
"serving on the default device.",
gpu_ids,
)
gpu_ids = None
with self._lock:
if self._cancel_event.is_set():
logger.info("Load cancelled before diffusion server start")

View file

@ -4459,10 +4459,13 @@ async def _load_model_impl(
# Diffusion GGUFs bypass llama-server: the diffusion runner
# forwards gpu_ids[0] as a CUDA/DG_GPU device token, NOT
# --device Vulkan<i>, so a Vulkan ordinal would target the wrong
# card. Reject the pick for anything that can route there
# (diffusion or not-yet-classifiable), matching the training
# guard's `diffusion_kind is not False` treatment.
if _classify_diffusion_gguf(config) is not False:
# card. Reject only a CONFIRMED diffusion GGUF (`is True`) here:
# `None` is the ordinary first-load case for an uncached Hub GGUF
# (no local header to classify yet), and rejecting it would make
# the picker unusable for remote GGUFs. An uncached model that
# turns out to be diffusion is caught post-download by the
# spawn-time Vulkan backstop in load_model.
if _classify_diffusion_gguf(config) is True:
raise HTTPException(
status_code = 400,
detail = (
@ -5089,10 +5092,13 @@ async def validate_model(
)
# Mirror /load: a Vulkan build validates the pick in ggml's own
# Vulkan ordinal space (the space the --device pin uses), and rejects
# picks for diffusion GGUFs (their runner takes a CUDA/DG_GPU token,
# not --device Vulkan<i>, so an ordinal targets the wrong card).
# picks for CONFIRMED diffusion GGUFs (their runner takes a CUDA/DG_GPU
# token, not --device Vulkan<i>, so an ordinal targets the wrong card).
# `None` (uncached, unclassifiable) is allowed through so first-time
# remote GGUF loads still work; the spawn-time backstop catches an
# uncached model that turns out to be diffusion after download.
if LlamaCppBackend._is_vulkan_backend():
if _classify_diffusion_gguf(config) is not False:
if _classify_diffusion_gguf(config) is True:
raise HTTPException(
status_code = 400,
detail = (

View file

@ -658,6 +658,33 @@ def test_start_diffusion_server_resets_tensor_parallel():
assert "self._tensor_parallel = False" in src
def test_vulkan_gpu_gate_allows_unclassified_gguf():
# The pre-download /load + /validate Vulkan gates must reject only a
# CONFIRMED-diffusion pick (`is True`). `None` -- the ordinary first-load
# case for an uncached Hub GGUF with no local header -- has to pass, or the
# GPU picker is unusable for first-time remote GGUF loads (Codex #7356).
route_src = (Path(_BACKEND_DIR) / "routes" / "inference.py").read_text(encoding = "utf-8")
# Both Vulkan validation sites (/load, /validate) gate on `is True`...
assert route_src.count("_classify_diffusion_gguf(config) is True") == 2
# ...and no diffusion *rejection* keys off the old over-broad `is not False`
# (which also caught the unclassifiable None). The training guard keeps its
# own conservative `diffusion_kind is not False` sizing -- a different name.
assert "_classify_diffusion_gguf(config) is not False" not in route_src
def test_diffusion_vulkan_load_drops_unmappable_gpu_pin():
# Backstop for the relaxed gate: an uncached GGUF that turns out to be
# diffusion after download can reach the diffusion branch still carrying a
# Vulkan pin. ggml Vulkan ordinals can't be forwarded as the runner's
# CUDA/DG token, so load_model must drop the pin before the spawn.
src = inspect.getsource(LlamaCppBackend.load_model)
diff_branch = src[src.index("if self._is_diffusion:") :]
guard = diff_branch.index("if gpu_ids and is_vulkan_backend:")
drop = diff_branch.index("gpu_ids = None")
spawn = diff_branch.index("_start_diffusion_server(")
assert guard < drop < spawn
def test_route_matches_loaded_settings_collapses_diffusion_gpu_ids():
# The route-level reload dedupe mirrors the backend: for a loaded diffusion
# model it compares the request against the single recorded device, not the