| Crates.io | torsh-autograd |
| lib.rs | torsh-autograd |
| version | 0.1.0-alpha.2 |
| created_at | 2025-09-29 23:47:42.57939+00 |
| updated_at | 2025-12-22 04:39:22.739159+00 |
| description | Automatic differentiation engine for ToRSh with PyTorch-compatible API |
| homepage | https://github.com/cool-japan/torsh/ |
| repository | https://github.com/cool-japan/torsh/ |
| max_upload_size | |
| id | 1860403 |
| size | 4,149,151 |
Automatic differentiation engine for ToRSh, providing PyTorch-compatible autograd functionality powered by scirs2.
This crate leverages scirs2's powerful automatic differentiation capabilities to provide:
use torsh_autograd::prelude::*;
use torsh_tensor::prelude::*;
// Enable gradient computation
let x = tensor![2.0].requires_grad_(true);
let y = x.pow(2.0)?;
// Compute gradients
backward(&y, None, false)?;
// Access gradient
let grad = x.grad().unwrap();
assert_eq!(grad.item(), 4.0); // dy/dx = 2x = 4
// Disable gradient computation
{
let _guard = no_grad();
// Operations here won't track gradients
let z = x.mul(&y)?;
}
// Inference mode for maximum performance
{
let _guard = inference_mode();
// No graph building, pure computation
let output = model.forward(&input)?;
}
// Anomaly detection for debugging
{
let _guard = detect_anomaly();
// Will detect NaN/Inf in gradients
backward(&loss, None, false)?;
}
// Compute Jacobian matrix
let jacobian = jacobian(|x| x.pow(2.0), &input, true)?;
// Compute Hessian matrix
let hessian = hessian(|x| x.sum(), &input, true)?;
// Vector-Jacobian product
let (output, vjp) = vjp(|x| model.forward(x), &input, &v, true)?;
// Jacobian-vector product
let (output, jvp) = jvp(|x| model.forward(x), &input, &v, true)?;
use torsh_autograd::function::{Function, FunctionContext, apply_function};
struct MyReLU;
impl Function for MyReLU {
fn forward<T>(&self, ctx: &mut FunctionContext, inputs: &[&Tensor<T>]) -> Result<Vec<Tensor<T>>>
where
T: TensorElement,
{
// Save input for backward
ctx.save_for_backward(inputs);
// Compute ReLU: max(0, x)
let output = inputs[0].clamp_min(0.0)?;
Ok(vec![output])
}
fn backward<T>(&self, ctx: &mut FunctionContext, grad_outputs: &[&Tensor<T>]) -> Result<Vec<Option<Tensor<T>>>>
where
T: TensorElement,
{
let saved = ctx.saved_tensors::<T>()?;
let input = &saved[0];
// Gradient is 1 where input > 0, else 0
let grad_input = grad_outputs[0].mul(&input.gt(&zeros_like(input))?)?;
Ok(vec![Some(grad_input)])
}
}
// Apply custom function
let output = apply_function(MyReLU, &[&input])?;
use torsh_autograd::accumulate::GradientAccumulator;
let mut accumulator = GradientAccumulator::new();
// Accumulate gradients over multiple batches
for batch in batches {
let loss = model.forward(&batch)?;
backward(&loss, None, true)?;
accumulator.accumulate();
}
// Get averaged gradients
let avg_grads = accumulator.average();
use torsh_autograd::checkpoint::checkpoint;
// Checkpoint a function to save memory
let outputs = checkpoint(
|inputs| {
// Memory-intensive computation
let x = expensive_layer1(&inputs[0])?;
let y = expensive_layer2(&x)?;
Ok(vec![y])
},
&[input],
)?;
use torsh_autograd::grad_mode::clip::{clip_grad_norm, clip_grad_value};
// Clip gradients by global norm
let total_norm = clip_grad_norm(&mut model.parameters(), 1.0, 2.0);
// Clip gradients by value
clip_grad_value(&mut model.parameters(), 0.5);
This crate fully leverages scirs2-autograd's capabilities:
Licensed under either of
at your option.