`tf$GradientTape()` records TensorFlow operations so you can ask how a result changes with respect to an input. It supplies automatic differentiation for computations such as neural-network training, avoiding hand-written backpropagation through operations like softmax and cross-entropy. section 2.5.2
Differentiate a square
In R, create a variable and compute its square inside the tape scope: ```r library(tensorflow) input_var <- tf$Variable(initial_value = 3) with(tf$GradientTape() %as% tape, { result <- tf$square(input_var) }) gradient <- tape$gradient(result, input_var) ``` The first argument to `tape$gradient()` is the result; the second is what you want to differentiate with respect to. Put the calculation of the result inside the scope, then request its gradient from the tape. section 3.3.1
library(tensorflow, exclude = c("set_random_seed", "shape"))
library(keras3)
use_backend("tensorflow")get_mnist_model <- function() {
inputs <- keras_input(shape = c(28 * 28))
outputs <- inputs |>
layer_dense(512, activation = "relu") |>
layer_dropout(0.5) |>
layer_dense(10, activation = "softmax")
keras_model(inputs, outputs)
}model <- get_mnist_model()
loss_fn <- loss_sparse_categorical_crossentropy()
optimizer <- optimizer_adam()
train_step <- function(inputs, targets) {
with(tf$GradientTape() %as% tape, { #1
predictions <- model(inputs, training = TRUE) #2
loss <- loss_fn(targets, predictions) #2
}) #2
gradients <- tape$gradient(loss, model$trainable_weights) #3
optimizer$apply(gradients, model$trainable_weights) #4
loss
}
A complete TensorFlow training-step listing puts the model’s forward pass and loss calculation inside the tape scope. Afterward, it requests gradients with respect to the model’s trainable weights and passes them to an optimizer. Gradient calculation and weight updates are separate steps. section 7.4.2
Two useful variations:
- To differentiate with respect to a constant tensor, call `tape$watch(input_const)` inside the scope before computing the result. The variable example needs no explicit watch call. section 3.3.1
- For a second derivative, nest two tape scopes: use the inner tape to compute the first gradient and the outer tape to differentiate that gradient. section 3.3.1
Listing 10.9 Stochastic gradient ascent in TensorFlow
library(tensorflow, exclude = c("set_random_seed", "shape"))
gradient_ascent_step <- tf_function(\(image, filter_index, learning_rate) {
with(tf$GradientTape() %as% tape, {
tape$watch(image) #1
loss <- compute_loss(image, filter_index) #2
})
grads <- tape$gradient(loss, image) #3
grads <- op_normalize(grads) #4
image + (learning_rate * grads) #5
})
Gradients need not be taken with respect to model weights. This gradient-ascent step explicitly watches an image, differentiates a filter-related loss with respect to that image, normalizes the gradient, and uses it to update the image. section 10.2.1

