Package: torch2jax
torch2jaxRun PyTorch in JAX. 🤝Mix-and-match PyTorch and JAX code with seamless, end-to-end autodiff, use JAX classics likejit,grad, andvmapon PyTorch code, and run PyTorch models on TPUs.torch2jax uses abstract interpretation (aka tracing) to move JAX values through PyTorch code. As a result, you get a JAX-native computation graph that followsexactlyyour PyTorch code, down to the last epsilon.fromtorch2jaximportj2t,t2jvit=torchvision.models.vit_b_16().eval()batch=torch.randn(1,3,224,224)vit(x)# => [-5.3352e-01, ..., 2.0390e-01]jax_vit=t2j(vit)jax_batch=t2j(batch)params={k:t2j(v)fork,vinvit.named_parameters()}jit(jax_vit)(jax_batch,state_dict=params)# => [-5.3125e-01, ..., 2.0735e-01]torch2jax even works with in-place PyTorch operations:deff(x):x.add_(1)x.mul_(2)returnxf(torch.Tensor([3]))# => torch.Tensor([8])jax_f=t2j(f)jax_f(jnp.array([3]))# => jnp.array([8])vmap(jax_f)(jnp.array([1,2,3]))# => jnp.array([[4], [6], [8]])grad(jax_f)(jnp.array([2.0]))# => jnp.array([2.0])torch2jax offers a simple API with two functions:j2t: Convert a JAXjax.numpy.ndarrayto atorch.Tensor.t2j: Convert a PyTorch function,torch.nn.Module, ortorch.Tensorto their JAX equivalent.Internally, the core of torch2jax isTorchish, a class that mimicstorch.Tensorvia__torch_function__. ATorchishobject is backed by a JAXjax.numpy.ndarray, and proxies PyTorch operations onto the underlyingjax.numpy.ndarray. As a result, you get a JAX-native computation graph that exactly follows your PyTorch code.InstallationPyPIpip install torch2jaxNix flaketorch2jax is available as aNixflake.$ nix shell github:samuela/torch2jax
(shell) $ python -c "from torch2jax import j2t, t2j"FAQHelp! I've encountered a PyTorch operation that isn't implemented yet.torch2jax is an implementation of the PyTorch standard library written in JAX. If you come across an operation that isn't implemented yet, please file an issue and/or PR!Adding new PyTorch operations is straightforward. Check the source for functions decorated with@implementsto get started.My PyTorch model includes dropout (or some other random operation), and does not work in training mode. Why?JAX mandatesdeterministic randomness, while PyTorch does not. This leads to some API friction. torch2jax does not currently offer a means to bridge this gap. I have an idea for how to accomplish it. If this is important to you, please open an issue.In the meantime, make sure to call.eval()on yourtorch.nn.Modulebefore conversion.My PyTorch model includes batch norm (or some othertorch.nn.Moduleutilizing buffers), and does not work in training mode. What can I do?Similar to the randomness story, PyTorch and JAX have different approaches to maintaining state. Operations like batch norm require maintaining running statistics. In PyTorch, this is accomplished viabuffers.torch2jax supports running batch norm models ineval()-mode. Just don't forget that you should avoid taking gradients w.r.t. buffers. For example,rn18=torchvision.models.resnet18(weights="DEFAULT").eval()loss=lambdax:torch.sum(x**2)batch=torch.randn(1,3,224,224)loss(rn18(batch)).backward()parameters={k:t2j(v)fork,vinrn18.named_parameters()}buffers={k:t2j(v)fork,vinrn18.named_buffers()}jax_rn18=t2j(rn18)grad(lambdaparams,x:loss(jax_rn18(x,state_dict={**params,**buffers})))(parameters,t2j(batch))I have an idea for how to implement buffers, including in training mode. If this is important to you, please open an issue.I'm seeing slightly different numerical results between PyTorch and JAX. Is it a bug?Floating point arithmetic is hard. There are a number of sources of divergence preventing bit-for-bit equivalence:torch2jax guarantees equivalence with PyTorch standard library functions in the mathematical sense, but not necessarily in their operational execution. This can lead to slight differences in results.The JAX/XLA and PyTorch compilers apply different optimizations and should be expected to rewrite computation graphs in exciting and unpredictable ways, potentially invoking different CUDA kernels.CUDA kernels can be non-deterministic, for example as a result of floating point addition being non-associative.Also bear in mind that floating point errors compound, so larger models will experience increased divergence.What about going the other way around? Running JAX code in PyTorch?Check outjax2torch.ContributingPyTorch has a non-trivial API surface to cover. Contributions are welcome!Run the test suite withpytestrunning innix shell. Format imports withisort --dont-follow-links ..