Skip to content

[Bug] Incorrect error thrown by dr.backward #517

Description

@Microno95

I have found a strange edge-case where dr.backward incorrectly throws the following RuntimeError:
RuntimeError: drjit.backward_from(): the argument does not depend on the input variable(s) being differentiated. Raising an exception since this is usually indicative of a bug (for example, you may have forgotten to call dr.enable_grad(..)). If this is expected behavior, provide the drjit.ADFlag.AllowNoGrad flag to the function (e.g., by specifying flags=dr.ADFlag.Default | dr.ADFlag.AllowNoGrad).

My current setup is on Windows in a Python 3.12.4 environment with the following drjit and mitsuba version:
(mi.__version__, dr.__version__) = ('3.8.0', '1.3.1')

I have the Windows LLVM/Clang 22.1.8 toolchain installed.

This bug existed in the following versions as well by my tests: ('3.6.4', '1.0.5').

The runtime error can be elicited by the following script:

import mitsuba as mi
import drjit as dr

mi.set_variant('llvm_ad_rgb')  # I also tried 'cuda_ad_rgb' with the same result

dr.set_flag(dr.JitFlag.VCallRecord, False)
test_point = mi.Point2f([0.0, 1.0])
test_point_3 = mi.Point3f([0.0, 1.0, 2.0])

dr.enable_grad(test_point_3)
p3x = test_point_3.x
p3y = test_point_3.y

diff = test_point - mi.Point2f(test_point_3.x, test_point_3.y)
loss = dr.square(diff)  # or diff * diff
dr.backward(loss)
print(dr.grad(test_point_3))  # <- works fine, outputs correct gradient

dr.set_flag(dr.JitFlag.VCallRecord, True)
test_point = mi.Point2f([0.0, 2.0])
test_point_3 = mi.Point3f([0.0, 1.0, 2.0])

dr.enable_grad(test_point_3)
p3x = test_point_3.x
p3y = test_point_3.y

diff = test_point - mi.Point2f(test_point_3.x, test_point_3.y)
loss = dr.square(diff)  # or diff * diff
dr.backward(loss)
print(dr.grad(test_point_3))  # <- works fine, outputs correct gradient

test_point = mi.Point2f([0.0, 1.0])
test_point_3 = mi.Point3f([0.0, 1.0, 2.0])

dr.enable_grad(test_point_3)
p3x = test_point_3.x
p3y = test_point_3.y

diff = test_point - mi.Point2f(test_point_3.x, test_point_3.y)
loss = dr.square(diff)  # or diff * diff
dr.backward(loss)
print(dr.grad(test_point_3))  # <- throws RuntimeError, only difference being whether VCallRecord is True or False

The first call to dr.backward(loss) raises no RuntimeError despite being an identical operation to the subsequent call. It is surprising since the gradient computed by dr.grad(test_point_3) is correct with VCallRecord = False and, from what I can see, the RuntimeError depends on whether the diff variable has a value of [0.0, 0.0] or not. This happens only with calls to dr.square and not with any other operation (which is likely why using diff * diff also raises the issue).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions