Skip to content

S1-29b: the SSM backward wiring S1-29 never landed#23

Open
dillon-blake wants to merge 1 commit into
ticket/S1-28-glu-backwardfrom
ticket/S1-29b-ssm-back-ops
Open

S1-29b: the SSM backward wiring S1-29 never landed#23
dillon-blake wants to merge 1 commit into
ticket/S1-28-glu-backwardfrom
ticket/S1-29b-ssm-back-ops

Conversation

@dillon-blake

Copy link
Copy Markdown
Owner

Stacked on #22 (S1-28).

S1-29 is marked done and delivered only the CONCAT VJP. The SSM_CONV_BACK / SSM_SCAN_BACK enums, constructors and backward-switch cases its own ticket also promised were never written — SSM_CONV_BACK appeared zero times in ggml.h. So S1-30 and S1-31 were both written against a dependency that did not exist.

Two ops at the enum tail, their constructors, and the two backward cases that emit them. No kernels — CPU supports_op returns false explicitly for both, which is not redundant: the default returns true, so a new op with no dispatch case is reported supported, gets scheduled, and hits ggml_compute_forward's default: GGML_ABORT. Same trap S1-25 hit.

The packed-gradient decision, made here so S1-31 cannot get it wrong

SSM_SCAN has seven sources and five take a gradient, so ggml_ssm_scan_back returns a packed 1-D tensor — [d_s | d_x | d_dt | d_B | d_C] — exactly as ggml_ssm_scan itself packs y with the final states.

grad is the whole packed gradient of the forward's dst, state region included. MODE_GRAD's objective sums over it, so it is not zero there — a kernel that assumed otherwise would disagree with the finite difference and be right to. That region seeds the reverse recurrence at t = n_t.

The tests called ggml_set_param zero times

So grad -o SSM_CONV and grad -o SSM_SCAN requested no gradients, compared nothing, and printed Backend CPU: OK — while neither op had a backward case at all and both would have aborted the moment one was asked for.

And every existing shape is far above grad_nmax() (10000), so they'd have been silently skipped even with a param. Tiny shapes added — and for SSM_SCAN in both the Mamba-1 (head_dim == 1, per-state A) and Mamba-2 (head_dim > 1, scalar A) branches, which are different code in the kernel.

The xbc_overlap variants make x, B and C views of one tensor, and ggml_set_param asserts op == GGML_OP_NONE, so those stay eval-only. Stated in the code rather than hidden — it is a real llama.cpp layout and its backward aliasing is exactly what goes wrong quietly. S1-31 owns it.

Backward graphs now build for both ops and report not-supported instead of aborting. Full 21-op grad sweep 0/8 failing; SSM forwards unregressed.

S1-29 is marked done and delivered ONLY the CONCAT VJP. The SSM_CONV_BACK /
SSM_SCAN_BACK enums, constructors and backward-switch cases its own ticket also
promised were never written -- SSM_CONV_BACK appeared zero times in ggml.h. So S1-30 and
S1-31 were both written against a dependency that did not exist.

Two ops at the enum tail, their constructors, and the two backward cases that emit them.
No kernels: CPU supports_op returns FALSE explicitly for both, which is not redundant --
the default returns TRUE, so a new op with no dispatch case is reported *supported*, gets
scheduled, and hits ggml_compute_forward's `default: GGML_ABORT`. It would look
implemented right up until it killed the process. Same trap S1-25 hit.

SSM_CONV's backward is the convolution run backwards; only sx takes a gradient, since the
conv weight is a frozen base weight on the LoRA path.

SSM_SCAN has SEVEN sources and five of them take a gradient, so ggml_ssm_scan_back returns
a PACKED 1-D tensor -- [d_s | d_x | d_dt | d_B | d_C] -- exactly as ggml_ssm_scan itself
packs y with the final states, and the backward case views each region back onto its
source. `grad` is the WHOLE packed gradient of the forward's dst, state region included:
MODE_GRAD's objective sums over it, so it is NOT zero there, and a kernel that assumed
otherwise would disagree with the finite difference and be wrong to. That region seeds the
reverse recurrence at t = n_t. Decided here so S1-31 cannot get it wrong.

THE TESTS CALLED ggml_set_param ZERO TIMES.

So `grad -o SSM_CONV` and `grad -o SSM_SCAN` requested no gradients, compared nothing, and
printed `Backend CPU: OK` -- while neither op had a backward case at all and both would
have aborted the moment one was asked for. Both now ask.

And every existing shape is far above grad_nmax() (10000), so they would have been
SILENTLY SKIPPED even with a param. Tiny shapes added for both, and for SSM_SCAN in both
the Mamba-1 (head_dim == 1, per-state A) and Mamba-2 (head_dim > 1, scalar A) branches --
they are different code in the kernel.

The xbc_overlap variants make x, B and C views of one tensor, and ggml_set_param asserts
op == GGML_OP_NONE, so those stay eval-only. Stated in the code rather than hidden: it is
a real llama.cpp layout and its backward aliasing is exactly what goes wrong quietly.
S1-31 owns it.

Backward graphs now BUILD for both ops and report not-supported instead of aborting. Full
21-op grad sweep 0/8 failing; SSM forwards unregressed.
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