Return a new function that computes the gradient of f via reverse-mode
automatic differentiation. f must return a single float scalar. The
returned function has the same signature as f.
gradient()returns only the gradients, structured like the inputs (or the subset selected bywrt).value_and_gradient()returns both the output offand its gradients, computed in a single forward and reverse pass.
Arguments
- f
(
function)
Function to differentiate. Must return a single scalar float array.- wrt
(
character|integer|NULL)
Names or positions of the arguments to compute the gradient with respect to. Only float arrays can be included; static arguments must not appear inwrt. At call time, an argument inwrtmust be an array with a data type, not an R value such as3, since the data type of its gradient would otherwise be undetermined. IfNULL(the default), the gradient is computed with respect to all arguments (which must all be arrayish in that case).
Value
(function)
Has the same formals as f and must be called inside jit().
For gradient(), it returns a named list of gradients, one per
argument of f (or per wrt entry), each structured like that argument.
For value_and_gradient(), it returns list(value = , grad = ): the
return value of f, and that same list of gradients.
See also
the Automatic Differentiation article, transform_gradient() for the
low-level graph transformation.
Examples
f <- function(x, y) sum(x * y)
g <- jit(gradient(f))
g(nv_array(c(1, 2), dtype = "f32"), nv_array(c(3, 4), dtype = "f32"))
#> $x
#> AnvlArray
#> 3
#> 4
#> [ CPUf32{2} ]
#>
#> $y
#> AnvlArray
#> 1
#> 2
#> [ CPUf32{2} ]
#>
# differentiate with respect to a single argument
g_x <- jit(gradient(f, wrt = "x"))
g_x(nv_array(c(1, 2), dtype = "f32"), nv_array(c(3, 4), dtype = "f32"))
#> $x
#> AnvlArray
#> 3
#> 4
#> [ CPUf32{2} ]
#>
# static (non-array) arguments are passed through but cannot be in wrt
f2 <- function(x, power) sum(x^power)
g2 <- jit(gradient(f2, wrt = "x"), static = "power")
g2(nv_array(c(1, 2, 3), dtype = "f32"), power = 2L)
#> $x
#> AnvlArray
#> 2
#> 4
#> 6
#> [ CPUf32{3} ]
#>
# an argument in `wrt` must be passed as an array, not as an R value
g3 <- jit(gradient(function(x) x^2L))
g3(nv_scalar(3))
#> $x
#> AnvlArray
#> 6
#> [ CPUf32{} ]
#>
try(g3(3))
#> Error in check_wrt_arrayish(args_flat, is_wrt_flat) :
#> Cannot compute gradient with respect to a value that has no data type.
#> ✖ It is an R double, which takes its data type from the way the function body
#> uses it (see `?RData`).
#> ℹ Give it one first, e.g. `nv_array(x, dtype = "f32")` or an explicit
#> `nv_array(x, dtype = "f64")`, so the gradient's data type is the caller's
#> choice.
# the value of `f` together with its gradient
loss_fn <- function(x) sum(x^2L)
vg <- jit(value_and_gradient(loss_fn))
result <- vg(nv_array(c(3, 4), dtype = "f32"))
result$value
#> AnvlArray
#> 25
#> [ CPUf32{} ]
result$grad
#> $x
#> AnvlArray
#> 6
#> 8
#> [ CPUf32{2} ]
#>