Keep AD variables whose derivative evaluates to zero - #533
Draft
mohitt31 wants to merge 1 commit into
Draft
Conversation
mohitt31
force-pushed
the
ad-zero-weight-prune
branch
from
August 21, 2026 18:50
a99c0ab to
7a77b95
Compare
`ad_var_new()` skips an edge when its weight is a zero literal. If every edge of an operation gets skipped, the AD variable was thrown away, and the result then looked the same as a variable where gradients were never enabled. You can see this through `drjit.backward()`, which complains that the argument "does not depend on the input variable(s) being differentiated" for a program that is fine and whose gradient is simply zero. It depends on the values at runtime, so the same code fails for one input and works for another. Only throw the variable away if the operation had no differentiable input to begin with. The edge pruning itself is unchanged, so an operation whose derivative is zero stays in the graph and just does not propagate anything.
mohitt31
force-pushed
the
ad-zero-weight-prune
branch
from
August 21, 2026 19:00
7a77b95 to
aae0a2d
Compare
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.
Follow-up to my NEON PR #531.
I was looking at #517. The error turned out to have nothing to do with
dr.square, and nothing to do with symbolic calls. It comes from the AD layer.What happens
ad_var_new()skips an edge when its weight is a zero literal. If all the edges of an operation get skipped, the AD variable is thrown away:After that the result has no AD index at all, so it looks the same as a variable where nobody called
dr.enable_grad().check_grad_enabled()then seesgrad_enabled() == falseand raises "the argument does not depend on the input variable(s) being differentiated", even though the program is fine and the gradient is simply zero.The annoying part is that this depends on the values at runtime, so the same code fails for one input and works for another:
With
Float(1.0), Float(3.0)the same code runs fine.This also explains the
SymbolicCallspart of the issue. That flag only decides whether the check insidecheck_grad_enabled()runs at all (it was added in 4fbd8d0). It does not change the AD graph.grad_enabled(loss)isFalseeither way.The change
Throw the variable away only if the operation had no differentiable input to begin with. I did not touch the edge pruning itself, so an operation whose derivative is zero stays in the graph and just does not propagate anything.
What I tested
Float,Float16andFloat64. I checked CUDA separately on a T4, where the unpatched build fails all threedrjit.cuda.advariants.dr.square(a - b)with literal operands keeps 2 AD nodes per iteration instead of 0.The CI failure at the moment is the nanobind dev4 / dev5 ABI mismatch that is also hitting other PRs. The build stops before any test runs.
Why I left it as a draft
I am not sure this is the trade off you want. Keeping these nodes costs memory in exactly the places the pruning was written for. The other option is to leave the AD layer alone and make the check in
check_grad_enabled()less strict instead. I am happy to redo it that way if you prefer, or to add a changelog entry.I mostly work on C++ and SIMD performance and I am still learning the JIT and autodiff internals, so I may be missing something here.