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:
parent
4136d2f285
commit
a9afb8011c
3 changed files with 56 additions and 7 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 = (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue