Derivatives: ppy.grad¶
ppy.grad and ppy.value_and_grad differentiate a scalar function. This
page covers how to call them, what the function body may contain, and how the
derivative is built on each path.
Example¶
import math
import ppy
def f(x: float, y: float) -> float:
return math.sin(x) * y + x * x
df = ppy.grad(f)
both = ppy.value_and_grad(f, argnums=1)
def slope(x: float, y: float) -> float:
return df(x, y)
Calling grad and value_and_grad¶
ppy.grad(f)is the gradient offwith respect to its first parameter.argnumsnames another parameter, or a tuple of them. With a tuple, the gradient is a tuple.ppy.value_and_grad(f)givesf's value and the gradient as a pair.
Rules for the function¶
f returns a float, and the parameters differentiated are floats. f's
body is assignments and a return over:
- arithmetic
- the
mathfunctions abs- under CPython, over NumPy arrays:
+ - * / ** @,sum,mean,.T,reshape,broadcast_to
A branch, a loop, a call into anything else, or an effect no derivative follows (I/O, a write, a thread) is refused.
Diagnostics¶
| code | meaning |
|---|---|
E1660 |
a misuse of ppy.grad itself |
E1661 |
the types |
E1662 |
an effect |
How the derivative is built¶
Under CPython the derivative is made from f's source the first time it is
called: the body restated one operation at a time, then each operation's
adjoint in reverse.
Natively the compiler differentiates f's IR by the same rules in the same
order. This is the autodiff transform, reverse mode over the canonical and
tensor dialects. df(x, y) in a native function is a call to the derived
function.
Both follow one rule table, with one order of accumulation, so the three paths agree bit for bit.
Examples: Autodiff.