When one tape isn't enough
By default, a GradientTape releases its resources after the first tape.gradient() call. Two situations require special patterns: multiple gradient computations from the same forward pass, and second-order (or higher) gradients.
Persistent tapes (tf.GradientTape(persistent=True)) allow multiple gradient() calls. The tradeoff: the tape holds references to all intermediate tensors, blocking garbage collection. Always del tape when you're done — especially in tight training loops.
Higher-order gradients use nested tapes. The outer tape records the inner tape's gradient computation, so calling outer.gradient(inner_grad, x) returns the second derivative.
For Jacobians (gradient of vector-valued functions), tape.jacobian(y, x) returns shape output_shape + input_shape.