In Mooncake.jl, a reverse-mode rule for a function is designed to perform a forward pass and return an adjoint function (the reverse pass). For a function $f(x, y)$, a Mooncake-style rule rr(f, x, y) typically returns a tuple containing the function result and an adjoint function adj_f(db). This adjoint function takes the gradient of the output (db) and returns the gradients for all inputs (e.g., dx, dy) along with any necessary reverse-mode data (rdata).
Key components of the rule execution:
- Forward-pass: The rule replaces calls to functions with calls to their respective rules.
- Reverse-pass: The adjoints are run in reverse order of the forward pass. If a variable is used multiple times, its adjoint contributions are added together.
function f(x, y)
a = g(x)
b = h(a, y)
return b
end
# A correct reverse-mode rule implementation:
function rr(f, x, y)
a, adj_g = rr(g, x)
b, adj_h = rr(h, a, y)
function adj_f(db)
_, da, dy = adj_h(db)
_, dx = adj_g(da)
return NoRData(), dx, dy
end
return b, adj_f
end