Skip to content

fix: GGUF local model GPU crashes and rough edges - #3

Open
Dak0verflow wants to merge 1 commit into
am-will:mainfrom
Dak0verflow:local-model-gpu-fixes
Open

fix: GGUF local model GPU crashes and rough edges#3
Dak0verflow wants to merge 1 commit into
am-will:mainfrom
Dak0verflow:local-model-gpu-fixes

Conversation

@Dak0verflow

Copy link
Copy Markdown

Summary

  • Enable flash attention (and quantized KV cache) for GGUF GPU inference instead of forcing it off.
  • Add a repetition penalty to the GGUF sampler chain.
  • Add a local model picker with live import progress and friendly display names.
  • Raise the GGUF import cap from 3 blobs to 8.
  • Simplify the system prompt for local models under ~2B parameters.

Why

  • GPU crash: Standard (non-flash) attention's Vulkan matmul dispatch hits a ggml-vulkan descriptor-set accounting bug on some GPUs (reproduced on a Mali-G715 / Tensor G4, no coopmat/int-dot support) — a hard GGML_ASSERT abort that kills the process outright. Because it's a signal, not a C++ exception, the existing Vulkan-error-to-CPU fallback (built to handle things like VK_ERROR_DEVICE_LOST) never sees it and can't recover. Flash attention routes through a different kernel path that avoids the bug entirely. llama.cpp requires quantized KV cache whenever flash attention is enabled, so both changed together.
  • Repetition penalty: the sampler chain had no repetition/frequency penalty at all (top_k -> top_p -> temp -> dist). Small local models (sub-2B) would reliably degenerate into repetitive or self-referential loops without one.
  • Model picker + import progress: the "Model file" field showed the raw internal blob path (blob_<uuid>.gguf) instead of the imported file's name, and importing a multi-GB model gave zero visible feedback during the copy — it looked hung. Switching models required re-importing every time since there was no way to pick from what was already imported.
  • Import cap: maxBlobCount was hardcoded to 3 regardless of the actual 24GB aggregate storage budget, an arbitrary extra ceiling that got in the way of trying more than 3 models.
  • Tiny-model system prompt: the local-mode system prompt includes a detailed JSON tool-call protocol (control markers, schemas, an approval-capability workflow) on top of the base prompt. Models under ~2B parameters (tested: Qwen3-0.6B, Qwen3-1.7B) reliably lose the thread on this and degenerate into one-word non-answers (e.g. a bare "Done") instead of answering or calling a tool correctly. They're not capable enough to use the protocol reliably in the first place, so skipping straight to a plain conversational prompt below that size loses nothing.

Test Plan

  • Reproduced the GPU crash on-device (Pixel 9 Pro XL / Tensor G4) with both a standard-quant model and a ternary-quant model; confirmed the exact GGML_ASSERT failure via llvm-addr2line/llvm-objdump against the built .so, then confirmed the fix resolves it for both on GPU.
  • Verified the repetition penalty change against a sub-1B model that reliably looped without it.
  • Manually exercised the model picker: imported multiple models, confirmed friendly names and live progress, confirmed switching between already-imported models without re-importing.
  • Verified the tiny-model prompt path against two sub-2B models; confirmed two larger models (4B and 8B) are unaffected.

Standard attention's Vulkan dispatch hits a descriptor-set accounting
bug on some devices (Mali GPUs without coopmat/int-dot support) that
hard-aborts the process, so the existing Vulkan-error-to-CPU fallback
never sees it - it's a signal, not a catchable exception. Flash
attention avoids the buggy path; quantized KV cache is required
whenever flash attention is on, so both change together.

No repetition penalty existed in the sampler chain, so small models
would degenerate into repetitive loops.

The local model UI showed raw internal blob paths instead of names,
gave no feedback during multi-GB imports, and capped imports at 3
regardless of the actual 24GB storage budget - all friction against
just trying more models.

Sub-2B models reliably lose the thread on the full tool-call JSON
protocol and degenerate into one-word non-answers; they're not capable
enough to use it correctly anyway, so skip straight to a plain
conversational prompt below that size.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant