Intelegentny_Pszczelarz/.venv/Lib/site-packages/jax/experimental/jax2tf/tests/control_flow_ops_test.py
2023-06-19 00:49:18 +02:00

306 lines
9.9 KiB
Python

# Copyright 2020 The JAX Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for the jax2tf conversion for control-flow primitives."""
from absl.testing import absltest
import jax
import jax.lax as lax
import jax.numpy as jnp
from jax._src import test_util as jtu
import numpy as np
from jax.experimental.jax2tf.tests import tf_test_util
from jax import config
config.parse_flags_with_absl()
class ControlFlowOpsTest(tf_test_util.JaxToTfTestCase):
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond(self):
def f_jax(pred, x):
return lax.cond(pred, lambda t: t + 1., lambda f: f, x)
self.ConvertAndCompare(f_jax, jnp.bool_(True), 1.)
self.ConvertAndCompare(f_jax, jnp.bool_(False), 1.)
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond_multiple_results(self):
def f_jax(pred, x):
return lax.cond(pred, lambda t: (t + 1., 1.), lambda f: (f + 2., 2.), x)
self.ConvertAndCompare(f_jax, jnp.bool_(True), 1.)
self.ConvertAndCompare(f_jax, jnp.bool_(False), 1.)
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond_partial_eval(self):
def f(x):
res = lax.cond(True, lambda op: op * x, lambda op: op + x, x)
return res
self.ConvertAndCompare(jax.grad(f), 1.)
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond_units(self):
def g(x):
return lax.cond(True, lambda x: x, lambda y: y, x)
self.ConvertAndCompare(g, 0.7)
self.ConvertAndCompare(jax.grad(g), 0.7)
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond_custom_jvp(self):
"""Conversion of function with custom JVP, inside cond.
This exercises the custom_jvp_call_jaxpr primitives."""
@jax.custom_jvp
def f(x):
return x * x
@f.defjvp
def f_jvp(primals, tangents):
x, = primals
x_dot, = tangents
primal_out = f(x)
tangent_out = 3. * x * x_dot
return primal_out, tangent_out
def g(x):
return lax.cond(True, f, lambda y: y, x)
arg = 0.7
self.TransformConvertAndCompare(g, arg, None)
self.TransformConvertAndCompare(g, arg, "jvp")
self.TransformConvertAndCompare(g, arg, "vmap")
self.TransformConvertAndCompare(g, arg, "jvp_vmap")
self.TransformConvertAndCompare(g, arg, "grad")
self.TransformConvertAndCompare(g, arg, "grad_vmap")
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_cond_custom_vjp(self):
"""Conversion of function with custom VJP, inside cond.
This exercises the custom_vjp_call_jaxpr primitives."""
@jax.custom_vjp
def f(x):
return x * x
# f_fwd: a -> (b, residual)
def f_fwd(x):
return f(x), 3. * x
# f_bwd: (residual, CT b) -> [CT a]
def f_bwd(residual, ct_b):
return residual * ct_b,
f.defvjp(f_fwd, f_bwd)
def g(x):
return lax.cond(True, f, lambda y: y, x)
arg = 0.7
self.TransformConvertAndCompare(g, arg, None)
self.TransformConvertAndCompare(g, arg, "vmap")
self.TransformConvertAndCompare(g, arg, "grad_vmap")
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_while_single_carry(self):
"""A while with a single carry"""
def func(x):
# Equivalent to:
# for(i=x; i < 4; i++);
return lax.while_loop(lambda c: c < 4, lambda c: c + 1, x)
self.ConvertAndCompare(func, 0)
def test_while(self):
# Some constants to capture in the conditional branches
cond_const = np.ones(3, dtype=np.float32)
body_const1 = np.full_like(cond_const, 1.)
body_const2 = np.full_like(cond_const, 2.)
def func(x):
# Equivalent to:
# c = [1, 1, 1]
# for(i=0; i < 3; i++)
# c += [1, 1, 1] + [2, 2, 2]
#
# The function is set-up so that it captures constants in the
# body of the functionals. This covers some cases in the representation
# of the lax.while primitive.
def cond(idx_carry):
i, c = idx_carry
return i < jnp.sum(lax.tie_in(i, cond_const)) # Capture cond_const
def body(idx_carry):
i, c = idx_carry
return (i + 1, c + body_const1 + body_const2)
return lax.while_loop(cond, body, (0, x))
self.ConvertAndCompare(func, cond_const)
def test_while_batched_cond(self):
"""A while with a single carry"""
def product(x, y):
# Equivalent to "x * y" implemented as:
# res = 0.
# for(i=0; i < y; i++)
# res += x
return lax.while_loop(lambda idx_carry: idx_carry[0] < y,
lambda idx_carry: (idx_carry[0] + 1,
idx_carry[1] + x),
(0, 0.))
# We use vmap to compute result[i, j] = i * j
xs = np.arange(4, dtype=np.int32)
ys = np.arange(5, dtype=np.int32)
def product_xs_y(xs, y):
return jax.vmap(product, in_axes=(0, None))(xs, y)
def product_xs_ys(xs, ys):
return jax.vmap(product_xs_y, in_axes=(None, 0))(xs, ys)
self.ConvertAndCompare(product_xs_ys, xs, ys)
@jtu.ignore_warning(category=UserWarning,
message="Explicitly requested dtype .* requested in array is not available")
def test_while_custom_jvp(self):
"""Conversion of function with custom JVP, inside while.
This exercises the custom_jvp_call_jaxpr primitives."""
@jax.custom_jvp
def f(x):
return x * x
@f.defjvp
def f_jvp(primals, tangents):
x, = primals
x_dot, = tangents
primal_out = f(x)
tangent_out = 3. * x * x_dot
return primal_out, tangent_out
def g(x):
return lax.while_loop(lambda carry: carry[0] < 10,
lambda carry: (carry[0] + 1., f(carry[1])),
(0., x))
arg = 0.7
self.TransformConvertAndCompare(g, arg, None)
self.TransformConvertAndCompare(g, arg, "jvp")
self.TransformConvertAndCompare(g, arg, "vmap")
self.TransformConvertAndCompare(g, arg, "jvp_vmap")
def test_scan(self):
def f_jax(xs, ys):
body_const = np.ones((2, ), dtype=np.float32) # Test constant capture
def body(res0, inputs):
x, y = inputs
return res0 + x * y, body_const
return lax.scan(body, 0., (xs, ys))
arg = np.arange(10, dtype=np.float32)
self.ConvertAndCompare(f_jax, arg, arg)
def test_scan_partial_eval(self):
def f_jax(xs, ys):
body_const = np.ones((2, ), dtype=np.float32) # Test constant capture
def body(res0, inputs):
x, y = inputs
return res0 + x * y, body_const
c_out, _ = lax.scan(body, 0., (xs, ys))
return c_out
arg = np.arange(10, dtype=np.float32)
self.ConvertAndCompare(jax.grad(f_jax), arg, arg)
def test_scan_custom_jvp(self):
"""Conversion of function with custom JVP, inside scan.
This exercises the custom_jvp_call_jaxpr primitives."""
@jax.custom_jvp
def f(x):
return x * x
@f.defjvp
def f_jvp(primals, tangents):
x, = primals
x_dot, = tangents
primal_out = f(x)
tangent_out = 3. * x * x_dot
return primal_out, tangent_out
def g(x):
return lax.scan(lambda carry, inp: (carry + f(inp), 0.),
np.full(x.shape[1:], 0.), # Like x w/o leading dim
x)[0]
arg = np.full((5,), 0.7)
self.TransformConvertAndCompare(g, arg, None)
self.TransformConvertAndCompare(g, arg, "jvp")
self.TransformConvertAndCompare(g, arg, "vmap")
self.TransformConvertAndCompare(g, arg, "jvp_vmap")
self.TransformConvertAndCompare(g, arg, "grad")
self.TransformConvertAndCompare(g, arg, "grad_vmap")
def test_scan_custom_vjp(self):
"""Conversion of function with custom VJP, inside scan.
This exercises the custom_vjp_call_jaxpr primitives."""
@jax.custom_vjp
def f(x):
return x * x
# f_fwd: a -> (b, residual)
def f_fwd(x):
return f(x), 3. * x
# f_bwd: (residual, CT b) -> [CT a]
def f_bwd(residual, ct_b):
return residual * ct_b,
f.defvjp(f_fwd, f_bwd)
def g(x):
return lax.scan(lambda carry, inp: (carry + f(inp), 0.),
np.full(x.shape[1:], 0.), # Like x w/o leading dim
x)[0]
arg = np.full((5,), 0.7)
self.TransformConvertAndCompare(g, arg, None)
self.TransformConvertAndCompare(g, arg, "vmap")
self.TransformConvertAndCompare(g, arg, "grad")
self.TransformConvertAndCompare(g, arg, "grad_vmap")
def test_scan_remat(self):
def f_jax(xs):
@jax.remat
def body_fun(carry, x):
return carry * x, xs # capture xs from the environment
res1, res2 = lax.scan(body_fun, 0., xs + 1.)
return jnp.sum(res1) + jnp.sum(res2)
arg = np.arange(10, dtype=np.float32) + 1.
self.TransformConvertAndCompare(f_jax, arg, None)
self.TransformConvertAndCompare(f_jax, arg, "grad")
if __name__ == "__main__":
absltest.main(testLoader=jtu.JaxTestLoader())