Skip to content

train: a node the device cannot run refuses the JOB, not the server; supports_op tells the truth - #35

Merged
joelteply merged 1 commit into
feat/props-weight-residencyfrom
fix/training-refuses-a-node-the-device-cannot-run
Oct 6, 2026
Merged

joelteply merged 1 commit into
feat/props-weight-residencyfrom
fix/training-refuses-a-node-the-device-cannot-run

Conversation

@joelteply

Copy link
Copy Markdown

Why: /train on a qwen35 model aborted the serving process from inside a CUDA kernel (unary.cu, SQR on a viewed k_conv, 5090 2026-10-06). CUDA supports_op returned true unconditionally for SQR/SQRT/SIN/COS/LOG while those kernels assert a contiguous src0, and the scheduler trusted it.

Changes:

  • CUDA supports_op: SQR/SQRT/SIN/COS/LOG report the contiguity their kernel asserts. They're split out of the NONE/VIEW/PERMUTE/… case group, which stays true.
  • ggml_opt_alloc refuses the job: before anything is allocated, every compute node of a training graph must be supported by the device backend. A "no" refuses the job with the op, node and source named (ggml_opt_refusal).
    • Inference keeps its fallback; only a training graph turns the "no" into a refused job.
    • supports_op stays the one place that knows (Cormac's shape).
  • llama_opt_failure carries the reason, and server-train reports it instead of "did not fit in device memory".
  • ggml_acc_or_set: a viewed gradient (a slice of a fused QKV) is accumulated from a contiguous copy, so the VIEW backward stays on the device. The new check found this: it had been running through the CPU fallback.

Measured, 0.8B qwen35 (unsloth/Qwen3.5-0.8B-GGUF):

Engine Result /health
without the L2/ACC rule fixes refused: the training graph has a node CUDA0 cannot run: ACC 'grad for Qcur-23' …, then SQR … on 'k_conv-22' (a non-contiguous view) ok throughout
with them trains on the GPU, no refusal (loss 0.5924) ok

Remaining sweep (Fable): other backward rules that apply a unary op straight to a view (sin/cos, abs, relu, exp, swiglu's silu). This check now names each one as a refused job instead of a crash.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

…supports_op tells the truth

Measured on the 5090 2026-10-06: /train on a qwen35 model aborted the SERVING
process from inside a CUDA kernel (unary.cu, SQR on a viewed k_conv). CUDA
supports_op returned true unconditionally for SQR/SQRT/SIN/COS/LOG while those
kernels assert a contiguous src0, so the scheduler trusted it.

- CUDA supports_op: SQR/SQRT/SIN/COS/LOG report the contiguity their kernel
  asserts (split out of the NONE/VIEW/PERMUTE... group, which stays true).
- ggml_opt_alloc: before anything is allocated, every compute node of a training
  graph must be supported by the device backend; a "no" refuses the job with the
  op, node and source named (ggml_opt_refusal). Inference keeps its fallback; only
  a training graph turns supports_op's "no" into a refused job (Cormac's shape:
  supports_op stays the ONE place that knows).
- llama_opt_failure carries the reason; server-train reports it instead of "did
  not fit in device memory".
- ggml_acc_or_set: a viewed gradient (a slice of a fused QKV) is accumulated from
  a contiguous copy, so the VIEW backward stays on the device. The new check found
  this: it had been running through the CPU fallback.

0.8B qwen35 (unsloth/Qwen3.5-0.8B-GGUF):
- without the L2/ACC rule fixes, the job refuses with "the training graph has a
  node CUDA0 cannot run: ACC 'grad for Qcur-23' ..." and then "SQR ... on
  'k_conv-22' (a non-contiguous view)"; /health stays ok throughout
- with them, it trains on the GPU, no refusal (loss 0.5924)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc
@joelteply

Copy link
Copy Markdown
Author

APPROVED at 9652942. This is the shape we agreed on: supports_op stays the one place that knows (SQR/SQRT/SIN/COS/LOG now report the contiguity their kernel asserts, and CLAMP keeps its unconditional yes), and ggml_opt_alloc turns a device 'no' into a refused JOB before allocating, naming the op, node and source, carried through llama_opt_failure to /train's error. ggml_acc_or_set copies a viewed gradient, and skips the copy where grad_accs requires in-place accumulation. Correct. The supports_op change is also a strict win for inference: those ops on a view now fall back instead of asserting. One check before it reaches every node: the refusal is broader than the old behaviour. A training graph with ANY op the GPU doesn't implement used to run with that op on the CPU; now the whole job is refused. Please run the configs that trained before (the 1.5B parity set, and the 0.8B at both depths, which you have) and confirm none is now refused. A previously-working graph turned into a refusal would be a regression that reads as safety.

@joelteply
joelteply merged commit 8cd6fdb into feat/props-weight-residency Oct 6, 2026
13 of 28 checks passed
joelteply added a commit to CambrianTech/continuum that referenced this pull request Oct 6, 2026
…s the job, not the server (#4819)

CambrianTech/llama.cpp#35 (approved by Cormac): CUDA supports_op reports the
contiguity SQR/SQRT/SIN/COS/LOG kernels assert, and ggml_opt_alloc refuses a
training graph with any node the device backend cannot run, before allocating,
with the op and node named in the /train error. On the 5090 such a node aborted
Kimi's serving process. The VIEW backward also accumulates a viewed gradient from
a contiguous copy, so it stays on the GPU.

Measured: the 0.8B qwen35 job refuses with the node named while /health stays ok,
and trains on the GPU once the rules are fixed. The 1.5B parity sets still train
unchanged (eval 0.511 -> 0.241 -> 0.217; 0.496 -> 0.285 -> 0.174).


Claude-Session: https://claude.ai/code/session_01Q4NU4VNiELPQfBpCacDZGc

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
joelteply added a commit that referenced this pull request Oct 6, 2026
…end-can-run

train: refuse only a node NO scheduler backend can run (fix the Metal regression from #35)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant