




import jax
import jax.numpy as jnp
def f(x):
y = jnp.sin(x) ** 2
return jnp.sum(y)
jax.grad(f)(x)
jax.vmap(jax.grad(f))(xs)
jax.jit(jax.vmap(jax.grad(f)))(xs)

def f(x):
y = jnp.sin(x)
y = y ** 2
return y
jax.make_jaxpr(f)(x)
{ lambda ; a:f32[5]. let
b:f32[5] = sin a
c:f32[5] = integer_pow[y=2] b
in (c,) }
jax.jvp
jax.vmap
{ lambda ; a:f32[5] b:f32[5]. let
c:f32[5] = sin a
d:f32[5] = cos a
e:f32[5] = mul b d
f:f32[5] = integer_pow[y=2] c
g:f32[5] = mul 2.0:f32[] c
h:f32[5] = mul e g
in (f, h) }
{ lambda ; a:f32[3,5]. let
b:f32[3,5] = sin a
c:f32[3,5] = integer_pow[y=2] b
in (c,) }
jax.jvp
partial eval
jax.linearize
transpose
jax.vjp
seed 1.0
jax.grad
jax.jacfwd
jax.jacrev= jax.jacobian
import asdex
import jax.numpy as jnp
def f(x):
y = jnp.sin(x) ** 2
return y[1:] - y[:-1]
x = jnp.arange(5.0)
print(asdex.jacobian_sparsity(f, x))
SparsityPattern(4×5, nnz=8, sparsity=60.0%)
● ● ⋅ ⋅ ⋅
⋅ ● ● ⋅ ⋅
⋅ ⋅ ● ● ⋅
⋅ ⋅ ⋅ ● ●
def hessian_sparsity(f, x):
grad_f = jax.grad(f)
return jacobian_sparsity(grad_f, x)
For free!
make_jaxpr(jax.jacfwd(f))(x)
{ lambda ; a:f32[1000]. let
b:i32[1000,1000] = iota[dimension=0]
c:i32[1000,1000] = iota[dimension=1]
d:i32[1000,1000] = add b 0:i32[]
e:bool[1000,1000] = eq d c
f:f32[1000,1000] = convert_element_type e
g:f32[1000,1000] = split f
h:f32[1000] = sin a
i:f32[1000] = cos a
j:f32[1,1000] = broadcast_in_dim i
k:f32[1000,1000] = mul g j
l:f32[1000] = integer_pow[y=2] h
m:f32[1000] = mul 2.0:f32[] h
n:f32[1,1000] = broadcast_in_dim m
o:f32[1000,1000] = mul k n
p:f32[999] = slice[1:1000] l
q:f32[1000,999] = slice[:,1:1000] o
r:f32[999] = slice[0:999] l
s:f32[1000,999] = slice[:,0:999] o
_:f32[999] = sub p r
t:f32[1000,999] = sub q s
u:f32[999,1000] = transpose t
v:f32[999,1000] = split u
in (v,) }
make_jaxpr(asdex.jacobian(f, x))(x)
{ lambda a:f32[2,1000] b:i32[1998,2]
c:i32[1998,2]; d:f32[1000]. let
e:f32[1000] = sin d
f:f32[1000] = cos d
g:f32[1000] = integer_pow[y=2] e
h:f32[1000] = mul 2.0:f32[] e
i:f32[999] = slice[1:1000] g
j:f32[999] = slice[0:999] g
_:f32[999] = sub i j
k:f32[1,1000] = broadcast_in_dim f
l:f32[2,1000] = mul a k
m:f32[1,1000] = broadcast_in_dim h
n:f32[2,1000] = mul l m
o:f32[2,999] = slice[:,1:1000] n
p:f32[2,999] = slice[:,0:999] n
q:f32[2,999] = sub o p
r:f32[1998] = gather q b
in (r, c) }
jit, vmap, grad
def f(x):
u, p = x["u"], x["p"]
return {"a": p[0] * u + p[1], "b": jnp.diff(u)}
x = {"u": jnp.array([1.0, 2.0, 3.0]), "p": jnp.array([2.0, 5.0])}
jax.jacobian(f)(x)
{'a': {'p': Array([[1., 1.],
[2., 1.],
[3., 1.]], dtype=float32),
'u': Array([[2., 0., 0.],
[0., 2., 0.],
[0., 0., 2.]], dtype=float32)},
'b': {'p': Array([[0., 0.],
[0., 0.]], dtype=float32),
'u': Array([[-1., 1., 0.],
[ 0., -1., 1.]], dtype=float32)}}
asdex.jacobian(f, x)(x)
{'a': {'p': BCOO(float32[3, 2], nse=6),
'u': BCOO(float32[3, 3], nse=3)},
'b': {'p': BCOO(float32[2, 2], nse=0),
'u': BCOO(float32[2, 3], nse=4)}}
cond, scan, while_loopchunk_size bounds the memory of the batched AD passesargnums, has_aux, value_and_jacobianspy plots of patterns

