PyTorch is a Python-based, open-source framework for tensor computation and automatic differentiation. It provides the low-level operations needed to train neural networks. You can use those operations directly or choose PyTorch as the backend that runs a Keras model. section 3.4 section 3.2
library(keras3)
use_backend("torch")
torch <- import("torch")
In R, select the Keras torch backend, then import Python’s torch module. The Python package is named torch; it is distinct from the R package of the same name. section 3.4.1
A first gradient
Create a tensor whose gradient should be tracked, square it, and call backward() on the result: input_var <- torch$tensor(3.0, requires_grad = TRUE) result <- torch$square(input_var) result$backward() input_var$grad The gradient is tensor(6.). This small example contains the essential training mechanism: compute a result, run backpropagation, and read a gradient. Clear a tensor’s grad before repeating the calculation; otherwise gradients accumulate. section 3.4.1
Tensors also support familiar numerical work: create arrays of zeros or ones, generate random values, and combine tensors with operations such as addition and matrix multiplication. Parameters hold model state; tensors marked requires_grad = TRUE can receive gradients during backpropagation. section 3.4.1 section 3.4.2
learning_rate <- 0.1
training_step <- function(inputs, targets, W, b) {
predictions <- model(inputs, W, b) #1
loss <- mean_squared_error(targets, predictions) #1
loss$backward() #2
grad_loss_wrt_W <- W$grad #3
grad_loss_wrt_b <- b$grad #3
with(torch$no_grad(), { #3
W$sub_(grad_loss_wrt_W * learning_rate) #4
b$sub_(grad_loss_wrt_b * learning_rate) #4
}) #4
W$grad <- b$grad <- NULL #5
loss
}
This linear-classifier training step makes the gradient workflow concrete. A model computes predictions, mean squared error supplies a loss, and loss$backward() fills W$grad and b$grad. Update the weights inside torch$no_grad() so the update itself is not tracked, then clear both gradients before the next step. section 3.4.2
For a less manual version, a torch$nn$Module can hold Parameters and define a forward pass; torch$optim$SGD then updates its parameters. torch$compile() can compile a model or function, though eager execution is the usual PyTorch approach and keeps debugging straightforward. section 3.4.2 section 3.4.3
library(reticulate)
library(keras3)
use_backend("torch")
torch <- import("torch")loss_fn <- loss_sparse_categorical_crossentropy()
optimizer <- optimizer_adam()
model <- get_mnist_model()
train_step <- function(inputs, targets) {
predictions <- model(inputs, training = TRUE) #1
loss <- loss_fn(targets, predictions) #1
loss$backward() #2
gradients <- model$trainable_weights |>
lapply(\(weight) weight$value$grad) #3
with(torch$no_grad(), {
optimizer$apply(gradients, model$trainable_weights)
}) #4
model$zero_grad() #5
loss
}
A custom Keras training step can also use PyTorch gradients. With the torch backend, call backward() on the loss, read gradients from the model’s trainable weights, apply the Keras optimizer inside torch$no_grad(), and call model$zero_grad(). section 7.4.2
Choose PyTorch when eager debugging or access to its pretrained-model ecosystem matters. Weigh that against the reported performance advantage of JAX for some models and PyTorch API differences from NumPy, including inconsistent argument names. section 3.4.3










