| name | torch-r |
| description | Master torch (PyTorch for R) deep learning with maximum flexibility and control. Use when mentions "torch", "torch em R", "torch for R", "torch in R", "PyTorch R", "pt", "nn_module", "nn_linear", "nn_conv", "nn_sequential", "torch_tensor", "autograd", "automatic differentiation", "custom training loop", "manual training", "backpropagation", "gradient manipulation", "research model", "custom loss function", "custom layer", "torch dataset", "dataloader", "GPU torch", "CUDA torch", "treinar com torch", "rede neural torch", "CNN torch", "RNN torch", "LSTM torch", "GRU torch", "attention mechanism", "transformer torch", "audio torch", "NLP torch", "vision torch", "time series torch", "torch flexibility", "torch control", "low-level training", "research deep learning", "experimental models", "dynamic computation graph", "when use torch", "torch vs keras", "torch or keras3", "torch benefits", "LibTorch", "mlverse torch", "torch for research", "torch for production", or working with torch R package for deep learning, neural networks, and scientific computing with explicit control. |
| version | 1.0.0 |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
torch (PyTorch for R) - Maximum Flexibility Deep Learning
Expert guidance for deep learning in R using torch, the R interface to LibTorch (PyTorch C++ backend), providing maximum flexibility and explicit control over neural network design, training, and experimentation.
Overview
What is torch?
torch is an R package that provides a native R interface to LibTorch, the C++ backend of PyTorch. It offers:
- Tensors: Multidimensional arrays with GPU acceleration
- Autograd: Automatic differentiation for gradient-based optimization
- Neural network modules: Building blocks for custom architectures (
nn_module, nn_* layers)
- Optimizers: SGD, Adam, RMSprop, and more
- Full control: Custom training loops, loss functions, layers, and gradient manipulation
torch is currently the most modern and flexible framework in the R ecosystem for deep learning, especially suited for:
- Research and experimentation
- Custom architectures and training procedures
- Low-level control over gradient computation
- Models requiring dynamic computation graphs
- Integration with PyTorch ecosystem (transfer learning, pretrained models)
Key Documentation Resources
When to Use torch
Use torch when you need:
✅ Maximum flexibility and control
- Custom training loops with explicit forward/backward passes
- Non-standard loss functions or gradient manipulation
- Dynamic network architectures that change during training
- Research experiments requiring low-level access
✅ PyTorch ecosystem integration
- Transfer learning from PyTorch pretrained models
- Reproducing PyTorch research papers in R
- Sharing models between Python PyTorch and R torch
✅ Explicit gradient control
- Custom gradient clipping or modification
- Multi-task learning with weighted gradients
- Debugging gradient flow in complex architectures
✅ Scientific computing beyond ML
- Differentiable simulations
- Physics-informed neural networks
- Optimization problems with custom constraints
Use keras3 instead when:
⚠️ High-level API preferred
- Rapid prototyping with minimal code
- Standard architectures (ResNet, EfficientNet, etc.)
- Built-in
fit() workflow with callbacks
- Preprocessing layers in model graph
Use r-tensorflow instead when:
⚠️ Deployment and infrastructure focus
- TensorFlow Serving deployment
- SavedModel format required
- Integration with existing TensorFlow pipelines
Decision matrix: See references/torch-vs-keras-comparison.md
Core Concepts
1. Tensors - Fundamental Data Structure
Tensors are multidimensional arrays, the building blocks of all torch operations.
library(torch)
x <- torch_tensor(c(1, 2, 3, 4, 5, 6))
print(x)
x <- x$view(c(2, 3))
print(x)
zeros <- torch_zeros(c(3, 4))
ones <- torch_ones(c(2, 2))
random <- torch_randn(c(5, 5))
arange <- torch_arange(0, 10, 0.5)
result <- torch_randn(c(3, 3))$
abs()$
sqrt()$
mean()
print(result)
Key R-specific patterns:
- Access tensor methods with
$ (e.g., tensor$view(), tensor$mean())
- torch uses R6 objects, not S3/S4
- Indexing is 1-based in R, unlike Python (0-based)
2. Device Management (CPU/GPU)
torch supports GPU acceleration via CUDA.
if (cuda_is_available()) {
cat("CUDA is available!\n")
cat("Device count:", cuda_device_count(), "\n")
} else {
cat("CUDA not available, using CPU\n")
}
device <- if (cuda_is_available()) torch_device("cuda") else torch_device("cpu")
x <- torch_randn(c(100, 100))
x_gpu <- x$to(device = device)
y_gpu <- x_gpu$matmul(x_gpu$t())
y_cpu <- y_gpu$cpu()
y_r <- as_array(y_cpu)
Best practice: Set device once and reuse throughout training:
device <- if (cuda_is_available()) "cuda" else "cpu"
3. Autograd - Automatic Differentiation
torch automatically tracks operations for gradient computation.
x <- torch_tensor(2.0, requires_grad = TRUE)
y <- x^2 + 3*x + 1
y$backward()
print(x$grad)
x <- torch_tensor(1.0, requires_grad = TRUE)
y1 <- x^2
y1$backward()
print(x$grad)
y2 <- x^3
y2$backward()
print(x$grad)
x$grad$zero_()
y3 <- x^2
y3$backward()
print(x$grad)
Critical pattern: Always zero gradients in training loops!
optimizer$zero_grad()
loss$backward()
optimizer$step()
4. nn_module - Neural Network Building Blocks
nn_module is the base class for all neural networks in torch.
library(torch)
simple_net <- nn_module(
"SimpleNet",
initialize = function(input_size, hidden_size, output_size) {
self$fc1 <- nn_linear(input_size, hidden_size)
self$fc2 <- nn_linear(hidden_size, output_size)
self$relu <- nn_relu()
},
forward = function(x) {
x |>
self$fc1() |>
self$relu() |>
self$fc2()
}
)
model <- simple_net(input_size = 10, hidden_size = 64, output_size = 3)
input <- torch_randn(c(32, 10))
output <- model(input)
print(output$shape)
print(length(model$parameters))
model$to(device = device)
nn_module patterns:
initialize() = constructor (like __init__ in PyTorch)
forward() = forward pass (like forward() in PyTorch)
- Access layers with
self$layer_name
- Use
|> (pipe) for sequential operations
5. nn_sequential - Quick Layer Stacking
For simple sequential models, use nn_sequential():
model <- nn_sequential(
nn_linear(784, 128),
nn_relu(),
nn_dropout(0.2),
nn_linear(128, 64),
nn_relu(),
nn_linear(64, 10)
)
output <- model(torch_randn(c(16, 784)))
print(output$shape)
When to use:
- ✅ Simple feedforward architectures
- ✅ No custom logic in forward pass
- ❌ Skip connections, branching, or conditional logic → use
nn_module
6. Loss Functions
torch provides standard loss functions as nn_* modules:
ce_loss <- nn_cross_entropy_loss()
bce_loss <- nn_bce_loss()
bce_logits <- nn_bce_with_logits_loss()
mse_loss <- nn_mse_loss()
mae_loss <- nn_l1_loss()
smooth_l1 <- nn_smooth_l1_loss()
predictions <- torch_randn(c(32, 10))
targets <- torch_randint(1, 10, c(32))
loss <- ce_loss(predictions, targets)
print(loss)
Important: nn_cross_entropy_loss() expects:
- Predictions: raw logits (no softmax)
- Targets: class indices (1-based in R, unlike Python!)
7. Optimizers
Optimizers update model parameters based on computed gradients.
optimizer <- optim_adam(model$parameters, lr = 0.001)
optimizer <- optim_sgd(model$parameters, lr = 0.01, momentum = 0.9)
optimizer <- optim_rmsprop(model$parameters, lr = 0.001)
optimizer$zero_grad()
output <- model(input)
loss <- loss_fn(output, target)
loss$backward()
optimizer$step()
scheduler <- lr_step(optimizer, step_size = 10, gamma = 0.1)
scheduler$step()
8. Datasets and DataLoaders
torch provides dataset and dataloader for efficient data handling.
my_dataset <- dataset(
"MyDataset",
initialize = function(x, y) {
self$x <- x
self$y <- y
},
.getitem = function(i) {
list(
x = self$x[i, ],
y = self$y[i]
)
},
.length = function() {
nrow(self$x)
}
)
x_data <- torch_randn(c(1000, 10))
y_data <- torch_randint(1, 3, c(1000))
ds <- my_dataset(x_data, y_data)
dl <- dataloader(
ds,
batch_size = 32,
shuffle = TRUE,
num_workers = 0
)
coro::loop(for (batch in dl) {
x <- batch$x
y <- batch$y
optimizer$zero_grad()
output <- model(x)
loss <- loss_fn(output, y)
loss$backward()
optimizer$step()
})
Key pattern: Use coro::loop() for dataloader iteration in R.
Training Patterns
Basic Training Loop
library(torch)
library(coro)
model <- simple_net(10, 64, 3)
model$to(device = device)
optimizer <- optim_adam(model$parameters, lr = 0.001)
loss_fn <- nn_cross_entropy_loss()
num_epochs <- 10
for (epoch in 1:num_epochs) {
model$train()
train_loss <- 0
batch_count <- 0
coro::loop(for (batch in train_dl) {
x <- batch$x$to(device = device)
y <- batch$y$to(device = device)
optimizer$zero_grad()
output <- model(x)
loss <- loss_fn(output, y)
loss$backward()
optimizer$step()
train_loss <- train_loss + loss$item()
batch_count <- batch_count + 1
})
avg_loss <- train_loss / batch_count
cat(sprintf("Epoch %d: Loss = %.4f\n", epoch, avg_loss))
}
Evaluation Loop
model$eval()
test_loss <- 0
correct <- 0
total <- 0
with_no_grad({
coro::loop(for (batch in test_dl) {
x <- batch$x$to(device = device)
y <- batch$y$to(device = device)
output <- model(x)
loss <- loss_fn(output, y)
predictions <- output$argmax(dim = 2)
correct <- correct + (predictions == y)$sum()$item()
total <- total + y$size(1)
test_loss <- test_loss + loss$item()
})
})
accuracy <- correct / total
cat(sprintf("Test Accuracy: %.2f%%\n", accuracy * 100))
Critical patterns:
model$train() before training (enables dropout, batch norm training mode)
model$eval() before evaluation (disables dropout, batch norm eval mode)
with_no_grad({...}) during evaluation (disables autograd for efficiency)
Domain-Specific Applications
Computer Vision - CNN Architecture
library(torch)
cnn_model <- nn_module(
"CNNClassifier",
initialize = function(num_classes = 10) {
self$conv1 <- nn_conv2d(3, 32, kernel_size = 3, padding = 1)
self$conv2 <- nn_conv2d(32, 64, kernel_size = 3, padding = 1)
self$conv3 <- nn_conv2d(64, 128, kernel_size = 3, padding = 1)
self$pool <- nn_max_pool2d(kernel_size = 2, stride = 2)
self$relu <- nn_relu()
self$dropout <- nn_dropout(0.25)
self$fc1 <- nn_linear(128 * 4 * 4, 512)
self$fc2 <- nn_linear(512, num_classes)
},
forward = function(x) {
x <- x |>
self$conv1() |> self$relu() |> self$pool() |>
self$conv2() |> self$relu() |> self$pool() |>
self$conv3() |> self$relu() |> self$pool()
x <- x$view(c(x$size(1), -1))
x <- x |>
self$fc1() |> self$relu() |> self$dropout() |>
self$fc2()
return(x)
}
)
model <- cnn_model(num_classes = 10)
input <- torch_randn(c(16, 3, 32, 32))
output <- model(input)
print(output$shape)
CNN patterns:
- Input format:
[batch, channels, height, width]
- Use
nn_conv2d() for 2D convolutions
nn_max_pool2d() or nn_avg_pool2d() for downsampling
view() to flatten before fully connected layers
NLP - LSTM for Text Classification
library(torch)
lstm_model <- nn_module(
"LSTMClassifier",
initialize = function(vocab_size, embedding_dim, hidden_dim, output_dim,
n_layers = 1, bidirectional = FALSE, dropout = 0.5) {
self$embedding <- nn_embedding(vocab_size, embedding_dim)
self$lstm <- nn_lstm(
embedding_dim,
hidden_dim,
num_layers = n_layers,
bidirectional = bidirectional,
dropout = if (n_layers > 1) dropout else 0,
batch_first = TRUE
)
self$fc <- nn_linear(
hidden_dim * (if (bidirectional) 2 else 1),
output_dim
)
self$dropout <- nn_dropout(dropout)
},
forward = function(text) {
embedded <- self$embedding(text)
embedded <- self$dropout(embedded)
lstm_out <- self$lstm(embedded)
output <- lstm_out[[1]]
final_output <- output[, -1, ]
logits <- self$fc(self$dropout(final_output))
return(logits)
}
)
model <- lstm_model(
vocab_size = 10000,
embedding_dim = 128,
hidden_dim = 256,
output_dim = 5,
n_layers = 2,
bidirectional = TRUE,
dropout = 0.5
)
input <- torch_randint(1, 10000, c(32, 50))
output <- model(input)
print(output$shape)
LSTM patterns:
nn_embedding() for token → vector conversion
nn_lstm() returns list: [[1]] = outputs, [[2]] = hidden state
- Set
batch_first = TRUE for [batch, seq, features] format
- Bidirectional LSTM doubles hidden dimension
Time Series - Forecasting with RNN
library(torch)
rnn_forecaster <- nn_module(
"RNNForecaster",
initialize = function(input_size, hidden_size, num_layers, output_size, dropout = 0.2) {
self$rnn <- nn_gru(
input_size,
hidden_size,
num_layers = num_layers,
dropout = dropout,
batch_first = TRUE
)
self$fc <- nn_linear(hidden_size, output_size)
},
forward = function(x) {
rnn_out <- self$rnn(x)
output <- rnn_out[[1]]
last_output <- output[, -1, ]
forecast <- self$fc(last_output)
return(forecast)
}
)
model <- rnn_forecaster(
input_size = 5,
hidden_size = 128,
num_layers = 2,
output_size = 10
)
input <- torch_randn(c(16, 50, 5))
output <- model(input)
print(output$shape)
Time series patterns:
- Use
nn_gru() or nn_lstm() for sequential data
- Input format:
[batch, sequence_length, features]
- Output last timestep for many-to-one forecasting
- Output all timesteps for sequence-to-sequence
Audio - Spectrogram CNN
See complete example: examples/audio-classification-torch.md
Key patterns:
- Convert waveform to mel-spectrogram
- Treat spectrogram as 2D image (time × frequency)
- Use CNN architecture (similar to computer vision)
- Handle variable-length audio with padding or cropping
Advanced Topics
Custom Loss Functions
focal_loss <- nn_module(
"FocalLoss",
initialize = function(alpha = 1, gamma = 2) {
self$alpha <- alpha
self$gamma <- gamma
self$ce_loss <- nn_cross_entropy_loss(reduction = "none")
},
forward = function(inputs, targets) {
ce <- self$ce_loss(inputs, targets)
probs <- nnf_softmax(inputs, dim = 2)
targets_one_hot <- nnf_one_hot(targets, num_classes = inputs$size(2))
pt <- (probs * targets_one_hot)$sum(dim = 2)
focal_weight <- (1 - pt)^self$gamma
loss <- self$alpha * focal_weight * ce
return(loss$mean())
}
)
loss_fn <- focal_loss(alpha = 1, gamma = 2)
loss <- loss_fn(predictions, targets)
Custom Layers
attention_layer <- nn_module(
"AttentionLayer",
initialize = function(hidden_dim) {
self$attention_weights <- nn_linear(hidden_dim, 1)
},
forward = function(x) {
scores <- self$attention_weights(x)
scores <- scores$squeeze(3)
weights <- nnf_softmax(scores, dim = 2)
weights_expanded <- weights$unsqueeze(3)
weighted <- x * weights_expanded
output <- weighted$sum(dim = 2)
return(output)
}
)
Custom Training Loop with Gradient Manipulation
train_advanced <- function(model, train_dl, num_epochs = 10) {
optimizer <- optim_adam(model$parameters, lr = 0.001)
loss_fn <- nn_cross_entropy_loss()
for (epoch in 1:num_epochs) {
model$train()
coro::loop(for (batch in train_dl) {
x <- batch$x$to(device = device)
y <- batch$y$to(device = device)
optimizer$zero_grad()
output <- model(x)
loss <- loss_fn(output, y)
loss$backward()
nn_utils_clip_grad_norm_(model$parameters, max_norm = 1.0)
optimizer$step()
})
cat(sprintf("Epoch %d completed\n", epoch))
}
}
Multi-GPU Training
library(torch)
if (cuda_device_count() > 1) {
cat(sprintf("Using %d GPUs\n", cuda_device_count()))
model <- nn_data_parallel(model)
}
model$to(device = "cuda")
dl <- dataloader(dataset, batch_size = 32 * cuda_device_count(), shuffle = TRUE)
Transfer Learning
pretrained_model <- my_pretrained_net()
for (param in pretrained_model$conv1$parameters) {
param$requires_grad_(FALSE)
}
for (param in pretrained_model$conv2$parameters) {
param$requires_grad_(FALSE)
}
pretrained_model$fc <- nn_linear(512, num_classes)
trainable_params <- purrr::keep(
pretrained_model$parameters,
~.x$requires_grad
)
optimizer <- optim_adam(trainable_params, lr = 0.001)
Transfer learning patterns:
- Freeze layers with
param$requires_grad_(FALSE)
- Replace final layer for new task
- Only pass trainable parameters to optimizer
- Use lower learning rate for fine-tuning
Integration with Other Skills
r-deeplearning Skill
When to use r-deeplearning:
- Framework comparison guidance (torch vs keras3 vs tensorflow)
- Decision matrix for selecting framework
- General deep learning concepts independent of framework
- Multi-framework projects
Pattern: Use r-deeplearning for strategic decisions, then torch-r for implementation.
keras3 Skill
When to use keras3:
- Rapid prototyping with minimal code
- Standard architectures (ResNet, EfficientNet, etc.)
- Built-in
fit() workflow with callbacks sufficient
- Preprocessing layers in model graph
- Multi-backend flexibility (TensorFlow/JAX/PyTorch)
Pattern: Start with keras3 for baseline, migrate to torch for custom experiments.
r-tensorflow Skill
When to use r-tensorflow:
- TensorFlow-specific deployment (SavedModel, TF Serving)
- Infrastructure and production pipeline setup
- GPU configuration and optimization
- Integration with TensorFlow ecosystem
Pattern: Use torch for model development, r-tensorflow for deployment if TensorFlow required.
learning-paradigms Skill
When to use learning-paradigms:
- Choosing between supervised, self-supervised, few-shot learning
- Data scarcity strategies
- Meta-learning approaches
Pattern: Use learning-paradigms for conceptual guidance, implement with torch.
Performance Optimization
GPU Best Practices
model$to(device = "cuda")
coro::loop(for (batch in train_dl) {
x <- batch$x$to(device = "cuda")
y <- batch$y$to(device = "cuda")
})
dl <- dataloader(dataset, batch_size = 32, pin_memory = TRUE)
torch_backends_cudnn_benchmark_set(TRUE)
Memory Management
if (cuda_is_available()) {
cuda_empty_cache()
}
predictions <- model(x)$detach()
with_no_grad({
predictions <- model(x)
})
rm(large_tensor)
gc()
DataLoader Optimization
if (.Platform$OS.type != "windows") {
dl <- dataloader(
dataset,
batch_size = 32,
shuffle = TRUE,
num_workers = 4,
pin_memory = TRUE
)
} else {
dl <- dataloader(dataset, batch_size = 32, shuffle = TRUE, num_workers = 0)
}
Troubleshooting
Common Issues
1. CUDA out of memory
2. Gradient explosion/vanishing
3. DataLoader iteration errors
library(coro)
coro::loop(for (batch in dl) {
})
4. Indexing confusion (R vs Python)
x[1, ]
x[[1]]
tensor[1, ]
5. Device mismatch errors
model$to(device = device)
x <- x$to(device = device)
y <- y$to(device = device)
Supporting Files
Examples
Complete working examples demonstrating torch patterns:
References
Deep-dive technical documentation:
Templates
Ready-to-use code templates:
Best Practices Summary
✅ DO:
- Always zero gradients:
optimizer$zero_grad()
- Use
model$train() before training, model$eval() before evaluation
- Use
with_no_grad({...}) during evaluation
- Set device once and reuse
- Use
coro::loop() for dataloader iteration
- Clip gradients for RNN/LSTM training
- Use
requires_grad_(FALSE) to freeze layers
- Clear GPU cache periodically with
cuda_empty_cache()
❌ DON'T:
- Forget to zero gradients (they accumulate!)
- Apply softmax before
nn_cross_entropy_loss() (it's built-in)
- Use Python-style 0-based indexing (R is 1-based)
- Ignore device mismatches between model and data
- Use large batch sizes without gradient accumulation
- Mix training and evaluation without
model$train()/model$eval()
Resources
Quick Reference Card
x <- torch_tensor(data)
x$to(device = "cuda")
x$view(c(batch, -1))
model <- nn_module("MyNet", initialize = ..., forward = ...)
model$train()
model$eval()
optimizer$zero_grad()
loss$backward()
optimizer$step()
with_no_grad({...})
param$requires_grad_(FALSE)
nn_utils_clip_grad_norm_(params, max_norm)
dl <- dataloader(dataset, batch_size, shuffle = TRUE)
coro::loop(for (batch in dl) {...})
device <- if (cuda_is_available()) "cuda" else "cpu"