Skip to main content

TorchTangents

PyPI version Python Versions PyTorch 2.2+ License

TorchTangents (torchtangents) is a PyTorch-native port of Google's JAX-native Neural Tangents library. It lets you build, lift, and analyze deep neural networks in standard PyTorch while extracting their exact infinite-width Neural Network Gaussian Process (NNGP) and Neural Tangent Kernel (NTK) in closed form.

Novak et al., "Fast and Easy Infinite Neural Networks in Python" (ICLR 2020) introduced the original Neural Tangents library for JAX. With the original JAX repository archived in May 2025, torchtangents brings this mathematical framework natively to PyTorch — adding stateful torch.nn.Module wrappers, torch.fx model lifting, torch.func input Jacobians/Hessians, and torch.compile acceleration.


Installation

From PyPI

pip install torchtangents

Editable / Developer Installation

git clone https://github.com/deoliveirajoshua/torchtangents.git
cd torchtangents
pip install -e .

For running PyTorch-vs-JAX parity tests or benchmarks, see the Developer & Benchmark Installation Guide.

Requirements: Python >= 3.9, PyTorch >= 2.2.


30-Second Quickstart

import torch
import torch.nn as nn
import torchtangents as tt

x_train = torch.randn(16, 10)
y_train = torch.randn(16, 2).to(torch.float64)
x_test  = torch.randn(4, 10)

# 1. Build a dual-mode TorchTangents model (drop-in replacement for torch.nn)
model = tt.nn.Sequential(
    tt.nn.Linear(10, 128),
    tt.nn.ReLU(),
    tt.nn.Linear(128, 2),
)
out   = model(x_test)                              # Finite-width forward pass: (4, 2)
k_inf = model.inf_kernel(x_train, x_test)          # Infinite-width NNGP & NTK: (16, 4)
k_emp = model.empirical_ntk(x_train, x_test)       # Finite-width empirical NTK: (16, 4, 2, 2)

# 2. Or lift ANY existing vanilla PyTorch model in one line via torch.fx
vanilla_model = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 2))
lifted_model  = tt.convert.lift(vanilla_model)
k_lifted      = lifted_model.inf_kernel(x_train, x_test, get="ntk")  # Shape: (16, 4)

# 3. Train an infinitely wide network in closed form (zero training loop!)
k_tr_tr = model.inf_kernel(x_train, None, get=("nngp", "ntk"))
k_te_tr = model.inf_kernel(x_test, x_train, get=("nngp", "ntk"))
gp_pred = tt.predict.gp_inference(k_tr_tr, y_train, diag_reg=1e-4)
y_pred  = gp_pred(get="ntk", k_test_train=k_te_tr).mean              # Shape: (4, 2)

Package Architecture

torchtangents is organized into four core submodules:

Submodule Role When to Use
torchtangents.nn Stateful torch.nn.Module drop-in layers (Linear, Conv2d, ReLU, Sequential, etc.) When you want both standard finite-width forward passes (model(x)), .empirical_ntk(), and exact infinite-width kernels (model.inf_kernel(x1, x2)).
torchtangents.stax Stateless functional kernel layers (mirrors neural_tangents.stax) When you only need analytical infinite-width kernels (kernel_fn(x1, x2)) without allocating finite-width layer weights.
torchtangents.convert Automatic PyTorch-to-TorchTangents conversion (lift, make_tangential, infinite_analog, inject, optimize_model) When you already have a vanilla torch.nn.Module (including residual/branched graphs) and want its infinite-width or empirical NTK without rewriting it.
torchtangents.predict Closed-form infinite-width training & Bayesian GP inference (gp_inference, gradient_descent_mse, gradient_descent) When you want exact infinite-width test predictions at $t = \infty$ or any continuous training time $t$ without running an optimizer loop.

Theory at a Glance

1. Finite-Width (Empirical) NTK: Dot Product in Gradient Space

For a parameterized neural network $f(x; \theta) \in \mathbb{R}^K$ with finite width and parameters $\theta \in \mathbb{R}^P$, the Empirical Neural Tangent Kernel (model.empirical_ntk(x1, x2)) measures how a gradient step at input $x'$ changes the network's output at $x$. Mathematically, it is the inner product of the per-sample parameter Jacobians in gradient space:

$$\hat{\Theta}(x, x') = \left\langle \nabla_\theta f(x; \theta),, \nabla_\theta f(x'; \theta) \right\rangle = \sum_{p=1}^{P} \frac{\partial f(x; \theta)}{\partial \theta_p} \left(\frac{\partial f(x'; \theta)}{\partial \theta_p}\right)^\top \in \mathbb{R}^{K \times K}$$

At finite width, $\hat{\Theta}(x, x')$ depends on the random initialization of $\theta$ and evolves non-linearly during training.

2. Infinite-Width Limit: Layer-Wise Recursive NNGP & NTK

As the hidden layer widths approach infinity ($n_1, \dots, n_{L-1} \to \infty$) under NTK parameterization, two remarkable simplifications occur:

  1. At Initialization (NNGP): Pre-activations at each layer $\ell$ converge by the Central Limit Theorem to an exact zero-mean Gaussian Process with covariance kernel $\Sigma^{(\ell)}(x, x')$.
  2. During Training (NTK): The empirical kernel $\hat{\Theta}(x, x')$ converges deterministically to a scalar-output multiple $\Theta^{(L)}(x, x') \otimes I_K$ that remains constant (frozen) throughout gradient descent.

Both $\Sigma^{(L)}$ and $\Theta^{(L)}$ are computed analytically (model.inf_kernel(x1, x2)) via a closed-form layer-by-layer recursion:

  • Base Case (First Linear Layer): $$\Sigma^{(1)}(x, x') = \frac{\sigma_w^2}{d_{\text{in}}} \langle x, x' \rangle + \sigma_b^2, \qquad \Theta^{(1)}(x, x') = \Sigma^{(1)}(x, x')$$

  • Recursive Step (Layer $\ell \to \ell + 1$ with nonlinearity $\phi$): $$\Sigma^{(\ell+1)}(x, x') = \sigma_w^2 , \mathbb{E}_{(u, v) \sim \mathcal{N}\left(0,, \Lambda^{(\ell)}(x, x')\right)} \Big[\phi(u),\phi(v)\Big] + \sigma_b^2$$ $$\Theta^{(\ell+1)}(x, x') = \Sigma^{(\ell+1)}(x, x') + \sigma_w^2 , \dot{\Sigma}^{(\ell+1)}(x, x') , \Theta^{(\ell)}(x, x')$$

where the derivative covariance is

$$\dot{\Sigma}^{(\ell+1)}(x, x') = \mathbb{E}_{(u, v) \sim \mathcal{N}\left(0,, \Lambda^{(\ell)}(x, x')\right)} \Big[\dot{\phi}(u),\dot{\phi}(v)\Big], \qquad \Lambda^{(\ell)}(x, x') = \begin{pmatrix} \Sigma^{(\ell)}(x, x) & \Sigma^{(\ell)}(x, x') \ \Sigma^{(\ell)}(x', x) & \Sigma^{(\ell)}(x', x') \end{pmatrix}$$

3. Closed-Form Infinite-Width Training

Because $\Theta^{(L)}$ is constant during training in the infinite-width limit, training a deep network with continuous-time gradient descent under MSE loss reduces to linear ODE dynamics with an exact closed-form solution at $t \to \infty$:

$$\mu(x^{\star}) = \Theta^{(L)}(x^{\star}, X) \Big(\Theta^{(L)}(X, X) + \lambda I\Big)^{-1} Y$$

where $(X, Y)$ is the training dataset, $x^{\star}$ is the test input, and $\lambda$ is ridge regularization.


Core Usage Recipes

All examples below have standalone runnable scripts in examples/.

1. Stateful (tt.nn) vs. Stateless (tt.stax) Construction

See examples/1_model_construction.py:

import torch
import torchtangents as tt

x1, x2 = torch.randn(4, 10), torch.randn(2, 10)

# Option A: Stateful PyTorch-style module (finite forward + infinite kernel)
model = tt.nn.Sequential(tt.nn.Linear(10, 128), tt.nn.ReLU(), tt.nn.Linear(128, 5))
out  = model(x1)                   # Finite-width forward pass: (4, 5)
k_nn = model.inf_kernel(x1, x2)    # Infinite-width NNGP & NTK: (4, 2)

# Option B: Stateless functional stax (infinite kernel only, zero weights allocated)
kernel_fn = tt.stax.Sequential(tt.stax.Linear(128), tt.stax.ReLU(), tt.stax.Linear(5))
k_stax    = kernel_fn(x1, x2)      # Identical NNGP & NTK:      (4, 2)

2. Kernel Utilities: Empirical NTK, Input Gradients & Hessians

See examples/2_kernel_utilities.py:

x1 = torch.randn(2, 10, requires_grad=True)
x2 = torch.randn(3, 10)

# Analytical infinite-width kernel vs. finite-width empirical NTK
k_inf = model.inf_kernel(x1, x2)     # k_inf.nngp: (2, 3), k_inf.ntk: (2, 3)
k_emp = model.empirical_ntk(x1, x2)  # Shape: (2, 3, 5, 5) -> (N1, N2, Out, Out)

# First-order Jacobians and second-order Hessians of the infinite-width NTK w.r.t. x1
grad_pairs = model.ntk_gradient(x1, x2, mode="all_pairs")  # Shape: (2, 3, 10)
grad_gram  = model.ntk_gradient(x1, x2, mode="gram")       # Shape: (2, 10)
hess_pairs = model.ntk_hessian(x1, x2, mode="all_pairs")   # Shape: (2, 3, 10, 10)
hess_gram  = model.ntk_hessian(x1, x2, mode="gram")        # Shape: (2, 10, 2, 10)

3. Lifting Existing Vanilla PyTorch Models

See examples/3_model_lifting.py and examples/example_auto_converter.py:

import torch.nn as nn

class ResMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1  = nn.Linear(10, 16)
        self.fc2  = nn.Linear(16, 16)
        self.head = nn.Linear(16, 2)

    def forward(self, x):
        h = torch.relu(self.fc1(x))
        h = torch.relu(self.fc2(h)) + h  # Residual skip connection traces automatically
        return self.head(h)

# Lift into a dual-mode StaxModule
lifted = tt.convert.lift(ResMLP())
ntk    = lifted.inf_kernel(x1, x2, get="ntk")  # Shape: (2, 3)

# Or extract a lightweight stateless kernel function
kernel_fn = tt.convert.infinite_analog(ResMLP())
ntk       = kernel_fn(x1, x2, get="ntk")       # Shape: (2, 3)

4. Closed-Form Infinite-Width Training & GP Inference

See examples/5_infinite_width_prediction.py:

x_train = torch.randn(16, 8)
y_train = torch.sin(x_train[:, :1]).to(torch.float64)
x_test  = torch.randn(4, 8)

kernel_fn     = tt.stax.Sequential(tt.stax.Linear(256), tt.stax.ReLU(), tt.stax.Linear(1))
k_train_train = kernel_fn(x_train, None, get=("nngp", "ntk"))
k_test_train  = kernel_fn(x_test, x_train, get=("nngp", "ntk"))

# Exact Bayesian NNGP & NTK posterior mean
gp_predict = tt.predict.gp_inference(k_train_train, y_train, diag_reg=1e-4)
ntk_mean   = gp_predict(get="ntk", k_test_train=k_test_train).mean   # Shape: (4, 1)

# Exact continuous-time gradient descent trajectory at finite time t=1.0
gd_predict = tt.predict.gradient_descent_mse(k_train_train, y_train, diag_reg=1e-4)
fx_tr, fx_te = gd_predict(
    t=1.0,
    fx_train_0=torch.zeros_like(y_train),
    fx_test_0=torch.zeros(len(x_test), 1, dtype=torch.float64),
    k_test_train=k_test_train,
)

5. Mini-Batching & torch.compile Acceleration

See examples/6_batched_and_compiled_kernels.py:

# Compute exact kernels in mini-batches to fit large datasets in GPU memory
batched_kernel_fn = tt.stax.batch(kernel_fn, batch_size=8)
k_batched         = batched_kernel_fn(x_train, x_test, get=("nngp", "ntk"))

# Fuse and accelerate kernel evaluation with torch.compile (Linux / WSL2)
compiled_kernel_fn = tt.convert.optimize_model(kernel_fn)
k_compiled         = compiled_kernel_fn(x_train, x_test, get=("nngp", "ntk"))

Platform Support

  • OS: Windows, Windows + WSL2, Linux
  • Hardware: CPU, or CPU + NVIDIA GPUs (CUDA 12.x or later)
  • Note: torch.compile (inductor backend) is supported on Linux and Windows + WSL2.

Performance

TorchTangents vs. Neural Tangents (JAX): time to calculate the infinite-width NTK of a WideResNet model.

import torchtangents.stax as tt_stax

def WideResnetBlock_tt(channels, strides=(1, 1), channel_mismatch=False):
    Main = tt_stax.serial(
        tt_stax.ReLU(), tt_stax.Conv(channels, (3, 3), strides, padding='SAME'),
        tt_stax.ReLU(), tt_stax.Conv(channels, (3, 3), padding='SAME'))
    Shortcut = tt_stax.Identity() if not channel_mismatch else tt_stax.Conv(
        channels, (3, 3), strides, padding='SAME')
    return tt_stax.serial(
        tt_stax.FanOut(2),
        tt_stax.parallel(Main, Shortcut),
        tt_stax.FanInSum())

def WideResnetGroup_tt(n, channels, strides=(1, 1)):
    blocks = [WideResnetBlock_tt(channels, strides, channel_mismatch=True)]
    for _ in range(n - 1):
        blocks.append(WideResnetBlock_tt(channels, (1, 1)))
    return tt_stax.serial(*blocks)

def WideResnet_tt(block_size, k, num_classes):
    return tt_stax.serial(
        tt_stax.Conv(16, (3, 3), padding='SAME'),
        WideResnetGroup_tt(block_size, int(16 * k)),
        WideResnetGroup_tt(block_size, int(32 * k), (2, 2)),
        WideResnetGroup_tt(block_size, int(64 * k), (2, 2)),
        tt_stax.AvgPool((8, 8)),
        tt_stax.Flatten(),
        tt_stax.Dense(num_classes, 1., 0.))

The speed % column is the proportion faster or slower torchtangents is compared to neural-tangents (higher is better). E.g., 1.0 = same speed, 1.2 = torchtangents is 20% faster.

Platform Precision ms / NTK entry Speed % of neural-tangents Max Batch Size ($N \times N$)
CPU FP 32
FP 64
NVIDIA P100 FP 16
FP 32
FP 64
NVIDIA V100 FP 16
FP 32
FP 64
NVIDIA L40S TF 16
FP 16
TF 32
FP 32
TF 64
FP 64
NVIDIA A100 TF 16
FP 16
TF 32
FP 32
TF 64
FP 64
NVIDIA H100 TF 16
FP 16
TF 32
FP 32
TF 64
FP 64
NVIDIA H200 TF 16
FP 16
TF 32
FP 32
TF 64
FP 64

Citation

If you use torchtangents in academic work, please cite:

@software{torchtangents2025,
  title        = {torchtangents: Infinite-width neural networks and NTKs in PyTorch},
  author       = {Joshua DeOliveira},
  year         = {2025},
  url          = {https://github.com/deoliveirajoshua/torchtangents}
}

Additionally, cite when appropriate these foundational works that torchtangents mirrors in PyTorch:

# Infinite width NTK/NNGP:
@inproceedings{neuraltangents2020,
    title={Neural Tangents: Fast and Easy Infinite Neural Networks in Python},
    author={Roman Novak and Lechao Xiao and Jiri Hron and Jaehoon Lee and Alexander A. Alemi and Jascha Sohl-Dickstein and Samuel S. Schoenholz},
    booktitle={International Conference on Learning Representations},
    year={2020},
    pdf={https://arxiv.org/abs/1912.02803},
    url={https://github.com/google/neural-tangents}
}
# Finite width, empirical NTK/NNGP:
@inproceedings{novak2022fast,
    title={Fast Finite Width Neural Tangent Kernel},
    author={Roman Novak and Jascha Sohl-Dickstein and Samuel S. Schoenholz},
    booktitle={International Conference on Machine Learning},
    year={2022},
    pdf={https://arxiv.org/abs/2206.08720},
    url={https://github.com/google/neural-tangents}
}
# Attention and variable-length inputs:
@inproceedings{hron2020infinite,
    title={Infinite attention: NNGP and NTK for deep attention networks},
    author={Jiri Hron and Yasaman Bahri and Jascha Sohl-Dickstein and Roman Novak},
    booktitle={International Conference on Machine Learning},
    year={2020},
    pdf={https://arxiv.org/abs/2006.10540},
    url={https://github.com/google/neural-tangents}
}
# Infinite-width "standard" parameterization:
@misc{sohl2020on,
    title={On the infinite width limit of neural networks with a standard parameterization},
    author={Jascha Sohl-Dickstein and Roman Novak and Samuel S. Schoenholz and Jaehoon Lee},
    publisher = {arXiv},
    year={2020},
    pdf={https://arxiv.org/abs/2001.07301},
    url={https://github.com/google/neural-tangents}
}
# Elementwise nonlinearities and sketching:
@inproceedings{han2022fast,
    title={Fast Neural Kernel Embeddings for General Activations},
    author={Insu Han and Amir Zandieh and Jaehoon Lee and Roman Novak and Lechao Xiao and Amin Karbasi},
    booktitle = {Advances in Neural Information Processing Systems},
    year={2022},
    pdf={https://arxiv.org/abs/2209.04121},
    url={https://github.com/google/neural-tangents}
}

License & Acknowledgments

TorchTangents operates under the open-source Apache License 2.0.

Because TorchTangents' stax sub-module (torchtangents.stax) mirrors and ports the core mathematical abstractions of Google's original Neural Tangents (JAX), we proudly acknowledge and extend the original computational logic developed by the Google team. For legal attributions, see the NOTICE and LICENSE files.

Metadata

Release files for torchtangents 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for torchtangents 0.1.1
File Size Uploaded Provenance Actions
torchtangents-0.1.1.tar.gz 81.6 kB With provenance Details for torchtangents-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for torchtangents 0.1.1
File Interpreter ABI Platform Actions
torchtangents-0.1.1-py3-none-any.whl Python 3 none any Details for torchtangents-0.1.1-py3-none-any.whl

Total release size: 165.5 kB

Release files / torchtangents-0.1.1.tar.gz

Download URL torchtangents-0.1.1.tar.gz
Size 81.6 kB
Tags Source
SHA-256 checksum
How to use checksums
408d85743b4ec2d7a830f8da3c3039d3b54f810787a1e4e0a23159546e8c6ecc
BLAKE2b-256 checksum
How to use checksums
69efd551fa68f248afd0d00b610538e76f2c01525a9a862f71d23a54a4333cb0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Release files / torchtangents-0.1.1-py3-none-any.whl

Download URL torchtangents-0.1.1-py3-none-any.whl
Size 83.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f84913bd178f90e045cd1dded604a1fa149795823bd9398a33734bb7c5fbbd97
BLAKE2b-256 checksum
How to use checksums
b51f42d884a0482df98ad31e96e983ec7daf9d171ac60806f2bb12a6b20ffae7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Security for torchtangents 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for torchtangents-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page