Repository navigation
Add the exact same-step gradient for outputs that bypass new hidden values (#185) - #192
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #185.
Problem
Under
vjp_method='single-step'(the default), a step output computed from a value that is not a new hidden state got no online credit along that path, and nothing warned about it. Examples: a spike read from the pre-reset membrane potential, or a readout weight applied inside the step. Two terms were missing:dL^t/dh^{t-1}of a previous hidden value, paired with the previous tracee^{t-1}.Fix
_compiler/output_bypass.py(new): finds the forward cone of every parameter leaf and hidden invar that reaches a model output or a non-hidden state output without crossing a new hidden value or astop_gradient. It duplicates that cone on differentiable copies, with every other input detached, and attaches the duplicate as a pure tangent:select_n(is_finite(d), o, o + (d - sg(d))). Forward values are unchanged, and an overflowing output staysinf. A cone that crosses awhileor an equation with effects is cut, with a WARNING (OUTPUT_BYPASS_DROPPED). The bypasses that are found get an INFO (OUTPUT_BYPASSES_HIDDEN). With no bypass, the perturbed jaxpr is exactly as before.dl_to_etws_at_t. The single-step guard still rejects any other parameter gradient._compute_learning_signaland is contracted withe^{t-1}by a new pure hook,_solve_previous_trace_gradients. It is implemented for the ParamDim, IO-dim and random-projection engines. ParamDim uses the previous filtered trace, and IO-dim uses the bias correction one step younger.learning_signal='modulatory'replacesdL/dh, so it compiles without the rewrite. Multi-step mode builds no perturbation and is unchanged; it already differentiated both terms.Before / after (issue repro,
etrace_grad, |grad w| summed)tanh(V) @ w_out,w_outSide effects (both now exact)
h2^t = h1^{t-1}, from KeyError in HiddenGroup.transition when a HiddenState depends only on inputs (no hidden-to-hidden path) #184) is credited as the hidden bypass ofh1^{t-1}. D-RTRL now equals BPTT, so theHIDDEN_COPY_SAME_STEP_READwarning added in Fix KeyError for input-only hidden states and dropped pure-copy edges (#184) #190 (unreleased) is removed.woutinplain_and_etp_rnnnow equals BPTT. A plain parameter that only feeds a hidden state (win) is still zero, and the pin and the doc say so.scan_descent_support_test.pynow asserts that equality.Edge cases covered by tests
Linearreadout (pytree param);stop_gradientcuts;infoutputs;whileon the bypass (warning);Spec:
docs/specs/2026-10-24-issue-185-output-bypass-gradient.md. Docs: a new "Outputs That Bypass New Hidden States" section indocs/advanced/limitations.ipynb.