tch-rs
Library Featured
Rust wrappers for the PyTorch C++ api (libtorch).
- Downloads
- 1,190,464
- Dependents
- 124
- Stars
- 5,518
- Forks
- 463
- Contributors
- 78
- Commits
- 960
- Latest release
- 0.26.0 ·
About
Rust bindings for the C++ api of PyTorch. The goal of the tch crate is to
provide some thin wrappers around the C++ PyTorch api (a.k.a. libtorch). It
aims at staying as close as possible to the original C++ api. More idiomatic
rust bindings could then be developed on top of this. The
documentation can be found on docs.rs.
The code generation part for the C api on top of libtorch comes from ocaml-torch.
Getting Started
This crate requires the C++ PyTorch library (libtorch) in version v2.13.0 to be available on your system. You can either:
- Use the system-wide libtorch installation (default).
- Install libtorch manually and let the build script know about it via the
LIBTORCHenvironment variable. - Use a Python PyTorch install, to do this set
LIBTORCH_USE_PYTORCH=1. - When a system-wide libtorch can't be found and
LIBTORCHis not set, the build script can download a pre-built binary version of libtorch by using thedownload-libtorchfeature. By default a CPU version is used. TheTORCH_CUDA_VERSIONenvironment variable can be set tocu117in order to get a pre-built binary using CUDA 11.7.
Read the full README
System-wide Libtorch
On linux platforms, the build script will look for a system-wide libtorch
library in /usr/lib/libtorch.so.
Python PyTorch Install
If the LIBTORCH_USE_PYTORCH environment variable is set, the active python
interpreter is called to retrieve information about the torch python package.
This version is then linked against.
Libtorch Manual Install
- Get
libtorchfrom the PyTorch website download section and extract the content of the zip file. - For Linux and macOS users, add the following to your
.bashrcor equivalent, where/path/to/libtorchis the path to the directory that was created when unzipping the file.
export LIBTORCH=/path/to/libtorch
The header files location can also be specified separately from the shared library via the following:
# LIBTORCH_INCLUDE must contain `include` directory.
export LIBTORCH_INCLUDE=/path/to/libtorch/
# LIBTORCH_LIB must contain `lib` directory.
export LIBTORCH_LIB=/path/to/libtorch/
For Windows users, assuming that
X:\path\to\libtorchis the unzipped libtorch directory.- Navigate to Control Panel -> View advanced system settings -> Environment variables.
- Create the
LIBTORCHvariable and set it toX:\path\to\libtorch. - Append
X:\path\to\libtorch\libto thePathvariable.
If you prefer to temporarily set environment variables, in PowerShell you can run
$Env:LIBTORCH = "X:\path\to\libtorch"
$Env:Path += ";X:\path\to\libtorch\lib"
- You should now be able to run some examples, e.g.
cargo run --example basics.
Windows Specific Notes
As per the pytorch docs the Windows debug and release builds are not ABI-compatible. This could lead to some segfaults if the incorrect version of libtorch is used.
It is recommended to use the MSVC Rust toolchain (e.g. by installing stable-x86_64-pc-windows-msvc via rustup) rather than a MinGW based one as PyTorch has compatibilities issues with MinGW.
Static Linking
When setting environment variable LIBTORCH_STATIC=1, libtorch is statically
linked rather than using the dynamic libraries. The pre-compiled artifacts don't
seem to include libtorch.a by default so this would have to be compiled
manually, e.g. via the following:
git clone -b v2.13.0 --recurse-submodule https://github.com/pytorch/pytorch.git pytorch-static --depth 1
cd pytorch-static
USE_CUDA=OFF BUILD_SHARED_LIBS=OFF python setup.py build
# export LIBTORCH to point at the build directory in pytorch-static.
Examples
Basic Tensor Operations
This crate provides a tensor type which wraps PyTorch tensors. Here is a minimal example of how to perform some tensor operations.
use tch::Tensor;
fn main() {
let t = Tensor::from_slice(&[3, 1, 4, 1, 5]);
let t = t * 2;
t.print();
}
Training a Model via Gradient Descent
PyTorch provides automatic differentiation for most tensor operations
it supports. This is commonly used to train models using gradient
descent. The optimization is performed over variables which are created
via a nn::VarStore by defining their shapes and initializations.
In the example below my_module uses two variables x1 and x2
which initial values are 0. The forward pass applied to tensor xs
returns xs * x1 + exp(xs) * x2.
Once the model has been generated, a nn::Sgd optimizer is created.
Then on each step of the training loop:
- The forward pass is applied to a mini-batch of data.
- A loss is computed as the mean square error between the model output and the mini-batch ground truth.
- Finally an optimization step is performed: gradients are computed and variables from the
VarStoreare modified accordingly.
use tch::nn::{Module, OptimizerConfig};
use tch::{kind, nn, Device, Tensor};
fn my_module(p: nn::Path, dim: i64) -> impl nn::Module {
let x1 = p.zeros("x1", &[dim]);
let x2 = p.zeros("x2", &[dim]);
nn::func(move |xs| xs * &x1 + xs.exp() * &x2)
}
fn gradient_descent() {
let vs = nn::VarStore::new(Device::Cpu);
let my_module = my_module(vs.root(), 7);
let mut opt = nn::Sgd::default().build(&vs, 1e-2).unwrap();
for _idx in 1..50 {
// Dummy mini-batches made of zeros.
let xs = Tensor::zeros(&[7], kind::FLOAT_CPU);
let ys = Tensor::zeros(&[7], kind::FLOAT_CPU);
let loss = (my_module.forward(&xs) - ys).pow_tensor_scalar(2).sum(kind::Kind::Float);
opt.backward_step(&loss);
}
}
Writing a Simple Neural Network
The nn api can be used to create neural network architectures, e.g. the following code defines
a simple model with one hidden layer and trains it on the MNIST dataset using the Adam optimizer.
use anyhow::Result;
use tch::{nn, nn::Module, nn::OptimizerConfig, Device};
const IMAGE_DIM: i64 = 784;
const HIDDEN_NODES: i64 = 128;
const LABELS: i64 = 10;
fn net(vs: &nn::Path) -> impl Module {
nn::seq()
.add(nn::linear(
vs / "layer1",
IMAGE_DIM,
HIDDEN_NODES,
Default::default(),
))
.add_fn(|xs| xs.relu())
.add(nn::linear(vs, HIDDEN_NODES, LABELS, Default::default()))
}
pub fn run() -> Result<()> {
let m = tch::vision::mnist::load_dir("data")?;
let vs = nn::VarStore::new(Device::Cpu);
let net = net(&vs.root());
let mut opt = nn::Adam::default().build(&vs, 1e-3)?;
for epoch in 1..200 {
let loss = net
.forward(&m.train_images)
.cross_entropy_for_logits(&m.train_labels);
opt.backward_step(&loss);
let test_accuracy = net
.forward(&m.test_images)
.accuracy_for_logits(&m.test_labels);
println!(
"epoch: {:4} train loss: {:8.5} test acc: {:5.2}%",
epoch,
f64::from(&loss),
100. * f64::from(&test_accuracy),
);
}
Ok(())
}
More details on the training loop can be found in the detailed tutorial.
Using some Pre-Trained Model
The pretrained-models example illustrates how to use some pre-trained computer vision model on an image. The weights - which have been extracted from the PyTorch implementation - can be downloaded here resnet18.ot and here resnet34.ot.
The example can then be run via the following command:
cargo run --example pretrained-models -- resnet18.ot tiger.jpg
This should print the top 5 imagenet categories for the image. The code for this example is pretty simple.
// First the image is loaded and resized to 224x224.
let image = imagenet::load_image_and_resize(image_file)?;
// A variable store is created to hold the model parameters.
let vs = tch::nn::VarStore::new(tch::Device::Cpu);
// Then the model is built on this variable store, and the weights are loaded.
let resnet18 = tch::vision::resnet::resnet18(vs.root(), imagenet::CLASS_COUNT);
vs.load(weight_file)?;
// Apply the forward pass of the model to get the logits and convert them
// to probabilities via a softmax.
let output = resnet18
.forward_t(&image.unsqueeze(0), /*train=*/ false)
.softmax(-1);
// Finally print the top 5 categories and their associated probabilities.
for (probability, class) in imagenet::top(&output, 5).iter() {
println!("{:50} {:5.2}%", class, 100.0 * probability)
}
Importing Pre-Trained Weights from PyTorch Using SafeTensors
safetensors is a new simple format by HuggingFace for storing tensors. It does not rely on Python's pickle module, and therefore the tensors are not bound to the specific classes and the exact directory structure used when the model is saved. It is also zero-copy, which means that reading the file will require no more memory than the original file.
For more information on safetensors, please check out https://github.com/huggingface/safetensors
Installing safetensors
You can install safetensors via the pip manager:
pip install safetensors
Exporting weights in PyTorch
import torchvision
from safetensors import torch as stt
model = torchvision.models.resnet18(pretrained=True)
stt.save_file(model.state_dict(), 'resnet18.safetensors')
Note: the filename of the export must be named with a .safetensors suffix for it to be properly decoded by tch.
Importing weights in tch
use anyhow::Result;
use tch::{
Device,
Kind,
nn::VarStore,
vision::{
imagenet,
resnet::resnet18,
}
};
fn main() -> Result<()> {
// Create the model and load the pre-trained weights
let mut vs = VarStore::new(Device::cuda_if_available());
let model = resnet18(&vs.root(), 1000);
vs.load("resnet18.safetensors")?;
// Load the image file and resize it to the usual imagenet dimension of 224x224.
let image = imagenet::load_image_and_resize224("dog.jpg")?
.to_device(vs.device());
// Apply the forward pass of the model to get the logits
let output = image
.unsqueeze(0)
.apply_t(&model, false)
.softmax(-1, Kind::Float);
// Print the top 5 categories for this image.
for (probability, class) in imagenet::top(&output, 5).iter() {
println!("{:50} {:5.2}%", class, 100.0 * probability)
}
Ok(())
}
Further examples include:
- A simplified version of char-rnn illustrating character level language modeling using Recurrent Neural Networks.
- Neural style transfer uses a pre-trained VGG-16 model to compose an image in the style of another image (pre-trained weights: vgg16.ot).
- Some ResNet examples on CIFAR-10.
- A tutorial showing how to deploy/run some Python trained models using TorchScript JIT.
- Some Reinforcement Learning examples using the OpenAI Gym environment. This includes a policy gradient example as well as an A2C implementation that can run on Atari games.
- A Transfer Learning Tutorial shows how to finetune a pre-trained ResNet model on a very small dataset.
- A simplified version of GPT similar to minGPT.
- A Stable Diffusion implementation following the lines of hugginface's diffusers library.
External material:
- A tutorial showing how to use Torch to compute option prices and greeks.
- tchrs-opencv-webcam-inference uses
tch-rsandopencvto run inference on a webcam feed for some Python trained model based on mobilenet v3.
FAQ
What are the best practices for Python to Rust model translations?
See some details in this thread.
How to get this to work on a M1/M2 mac?
Check this issue.
Compilation is slow, torch-sys seems to be rebuilt every time cargo gets run.
See this issue, this could
be caused by rust-analyzer not knowing about the proper environment variables
like LIBTORCH and LD_LIBRARY_PATH.
Using Rust/tch code from Python.
It is possible to call Rust/tch code from Python via PyO3, tch-ext provides an example of such a Python extension.
Error loading shared libraries.
If you get an error about not finding some shared libraries when running the generated binaries
(e.g.
error while loading shared libraries: libtorch_cpu.so: cannot open shared object file: No such file or directory).
You can try adding the following to your .bashrc where /path/to/libtorch is the path to your
libtorch install.
# For Linux
export LD_LIBRARY_PATH=/path/to/libtorch/lib:$LD_LIBRARY_PATH
# For macOS
export DYLD_LIBRARY_PATH=/path/to/libtorch/lib:$DYLD_LIBRARY_PATH
License
tch-rs is distributed under the terms of both the MIT license
and the Apache license (version 2.0), at your option.
See LICENSE-APACHE, LICENSE-MIT for more details.
Compatibility
- Runs on
- CUDA
What shows it
- CUDA: tch itself, pyo3-tch dependency tch, tch-ext dependency tch, torch-sys itself
- Native code
- Required
- Binds native code: tch, torch-sys
- Build uses a native toolchain: cc
- Python bindings
- Has Python bindings
- pyo3-tch needs Python
- tch-ext needs Python
- License
- Apache-2.0 OR MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Rust wrappers for the PyTorch C++ api (libtorch). Python bindings |
1,190,464 downloads over 30 days | 124 | 5,518 | 0.26.0 | CUDA | Binds native code: tch, torch-sys. Build uses a native toolchain: cc | Apache-2.0 OR MIT |
|
burn Featured
Flexible and Comprehensive Deep Learning Framework in Rust Also in Run and serve models. |
521,465 downloads over 30 days | 391 | 16,257 | 0.22.1 | CUDA, WebGPU, Metal, ROCm, Vulkan | Binds native code: netlink-sys (feature iroh), nvml-wrapper-sys (feature sys-metrics), torch-sys (feature tch) | Apache-2.0 OR MIT |
|
mlx-rs Featured
Unofficial rust wrapper for Apple's mlx machine learning library. Also in Run and serve models. |
33,398 downloads over 30 days | 36 | 389 | 0.34.0 | Metal | Binds native code: mach-sys, mlx, mlx-sys. Build uses a native toolchain: bindgen, cc, cmake | Apache-2.0 OR MIT |
|
aprender Listed
Next-generation ML framework in pure Rust — `cargo install aprender` for the `apr` CLI Also in Train models. |
15,442 downloads over 30 days | 31 | 140 | 0.72.3 | CUDA, WebGPU | Binds native code: libsqlite3-sys, zstd-sys, tree-sitter (feature full), alsa-sys (feature audio-alsa), nvml-wrapper-sys (feature nvml) and 1 more. Build uses a native toolchain: bindgen (feature bindgen) | MIT |
|
boostr Listed
ML framework on numr for training and inference on CPU, CUDA and WebGPU: attention, quantization, inference scheduling and distributed execution. Models include LLaMA, Mamba2, Qwen3.5, Whisper, Kokoro, VITS, VoxCPM2, Silero VAD, CLAP and super-resolution. Loads SafeTensors and GGUF. Also in Run and serve models. |
1,265 downloads over 30 days | 7 | 20 | 0.11.2 | CUDA, WebGPU | Binds native code: ring (feature distributed) | Apache-2.0 |
|
Deep Learning in Rust with the PyTorch API Also in Train models. |
Not measured | Not applicable | 77 | Not measured | Not measured | Not measured | BSD-2-Clause |
All projects in Run and serve modelsAll projects in Train models
Why FeaturedIt passes every Featured gate.
What it meets
- It has 28 active dependents and 20 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days.
- Active dependents are at 95% of their peak. Featured needs at least 50%.
- Docs are present. The release commit or a manifest ties the crate to the repository.
- No vulnerability advisory stays unpatched past the grace window. At least one version is neither a prerelease nor 0.0.x.
- The last activity is on 23 Aug 2026, 78 days ago. The rules expect an update within 560 days. Dormancy rule
What else the check found
- The oldest outside issue waits 440 days for a reply, past the limit of 270. No maintainer replied in 365 days. Rot signals rule
- The latest release requires the deprecated dependency cpython. RUSTSEC-2023-0076 Rot signals rule
Exact rules: Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.26.0 base 140, doubled for 1190464 downloads per month, doubled for 28 active users: E = 560 daysdormancy: last activity 2026-08-23, 78 days ago, E = 560: activerot: oldest unanswered issue 440 days (limit 270), no maintainer reply in 365 daysrot: deprecated requirement `cpython (RUSTSEC-2023-0076, https://rustsec.org/advisories/RUSTSEC-2023-0076.html)`featured: featured: active_users 28, new_adopters 20, former_glory 0.95
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption28 active dependents, 20 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 28 | crates.io database dump | Yes | |
| New dependents (365 days) | 20 | crates.io database dump | Yes | |
| Peak active dependents | 31 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 0.9512 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 2 months ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-08-23 | GitHub repository | Yes | |
| Latest release | 2026-08-23 | crates.io database dump | Yes | |
| First release | 2019-02-27 | crates.io database dump | Yes | |
| Latest version | 0.26.0 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 440 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 0 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | cpython (RUSTSEC-2023-0076, https://rustsec.org/advisories/RUSTSEC-2023-0076.html) | crates.io database dump | Yes |
Distribution48 releases, 1,190,464 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 48 | crates.io database dump | Yes | |
| Downloads over 30 days | 1190464 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository5,518 stars, 463 forks, 78 contributors, 960 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 5518 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 463 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 78 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 960 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 OR MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | CUDA | crates.io database dump | No | |
| What shows each backend | CUDA: tch itself, pyo3-tch dependency tch, tch-ext dependency tch, torch-sys itself | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | Binds native code: tch, torch-sys. Build uses a native toolchain: cc | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | Has Python bindings: pyo3-tch needs Python, tch-ext needs Python | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 124 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.