Tensor Flow 📂 Variables and Automatic Gradients · 2 of 5 35 min read

tf.GradientTape Explained: Your First Gradient in TensorFlow

Understand gradients as slopes and compute your first one with tf.GradientTape in three lines. See how the tape records the forward pass and replays it backwards with the chain rule. Type any function into the Slope Explorer, then test yourself on why tape.gradient sometimes returns None.

Section 01

The Story — A Video Camera in the Kitchen

Record Forward, Replay Backward
A chef puts a video camera in the kitchen. He cooks: chops, mixes, bakes. The camera records every step.

The cake tastes too sweet. How much did each step add to the sweetness? The chef plays the video backwards, from the cake to the first ingredient, and works out the effect of each step.

tf.GradientTape is that camera. It records your maths. Then tape.gradient() plays it backwards to find out how much each input changed the output. That number is the gradient.

Training a neural network means asking one question again and again: "If I change this weight a little, does the loss go up or down, and by how much?" The answer is the gradient. TensorFlow computes it for you automatically. This is called automatic differentiation.


Section 02

What Is a Gradient? (No Heavy Maths)

A gradient is a slope. It tells you how fast the output changes when you push the input a tiny bit. For one input, the gradient is the same as the derivative you may know from school.

Function
y = x²
At x = 3, y = 9.
Gradient
dy/dx = 2x = 6
At x = 3, a small push of +0.01 on x moves y by about +0.06.
⬆️
Positive gradient
grad > 0
Increase x → y goes up.
⬇️
Negative gradient
grad < 0
Increase x → y goes down.
⚪
Zero gradient
grad = 0
Flat spot. Maybe a minimum or maximum.

Section 03

Your First Gradient in Three Lines

import tensorflow as tf

x = tf.Variable(3.0)

with tf.GradientTape() as tape:     # 1. start recording
    y = x ** 2                      # 2. do the maths inside the block

dy_dx = tape.gradient(y, x)         # 3. play it backwards
print("y     =", y.numpy())
print("dy/dx =", dy_dx.numpy())
OUTPUT
y = 9.0 dy/dx = 6.0
🎥 The Three Steps
Record
with tf.GradientTape() as tape: — every op inside the block is written to the tape.
Compute
Calculate the output (later: the loss) from your variables.
Replay
tape.gradient(target, source) — "how does target change when source changes?"
Animated Diagram — Forward Pass Is Recorded, Backward Pass Uses the Recording
x3.0 squarex ** 2 y9.0 FORWARD → recorded on the tape dy/dx6.0 × 2xlocal slope dy/dy1.0 ← BACKWARD: tape.gradient(y, x)

Blue dot: the forward pass computes y = 9. Red dot: the backward pass starts at 1.0 and multiplies by each op's local slope (2x = 6).


Section 04

Try It — Slope Explorer

📈 Type Any Function, Drag x, See the Gradient Interactive

Pick a function or type your own using x, + - * / ** and sin cos exp log sqrt abs relu sigmoid tanh. Move the slider or click the chart. The orange line is the tangent. Its slope is the gradient.

🔬
Things to Try

Find where the gradient of x**3 - 3*x is zero (at x = ±1). Look at relu(x): the gradient is 0 on the left and 1 on the right. Look at sigmoid(x) far from 0: the gradient becomes tiny. This is the famous "vanishing gradient".


Section 05

The Chain Rule Happens for You

Real models chain many ops together. The gradient of a chain is the product of each step's local slope. This is the chain rule. The tape applies it automatically, step by step, backwards.

x = tf.Variable(2.0)

with tf.GradientTape() as tape:
    a = 3 * x + 1        # a = 7
    y = a ** 2           # y = 49

print("tape says :", tape.gradient(y, x).numpy())
print("by hand   :", 2 * (3 * 2.0 + 1) * 3)     # dy/da * da/dx = 2a * 3
OUTPUT
tape says : 42.0 by hand : 42.0
Step (backwards)Local slopeRunning product
Start at ydy/dy = 11
y = a²dy/da = 2a = 141 × 14 = 14
a = 3x + 1da/dx = 314 × 3 = 42

Section 06

What Does the Tape Watch?

The tape automatically watches every trainable float tf.Variable. It does not watch plain tensors. If the tape did not watch the source, tape.gradient returns None — no error, just None.

c = tf.constant(3.0)

with tf.GradientTape() as tape:
    y = c ** 2
print("constant, not watched :", tape.gradient(y, c))

with tf.GradientTape() as tape:
    tape.watch(c)                     # ask the tape to watch it
    y = c ** 2
print("constant, watched     :", tape.gradient(y, c).numpy())
OUTPUT
constant, not watched : None constant, watched : 6.0

Common Reasons for a None Gradient

def grad_of(x, fn):
    with tf.GradientTape() as tape:
        y = fn(x)
    return tape.gradient(y, x)

print("int variable     :", grad_of(tf.Variable(3), lambda v: v * v))
print("trainable=False  :", grad_of(tf.Variable(3.0, trainable=False), lambda v: v * v))
print("left TF (.numpy) :", grad_of(tf.Variable(3.0), lambda v: tf.constant(v.numpy() ** 2)))
print("no-gradient op   :", grad_of(tf.Variable(3.0), lambda v: tf.round(v)))
OUTPUT
int variable : None trainable=False : None left TF (.numpy) : None no-gradient op : None

Section 07

Try It — Will I Get a Gradient?

❓ Predict, Then Check Interactive

Pick a setup. First guess the answer with a button, then see what TensorFlow really returns and why.

Your guess:

Section 08

Python Control Flow Is Fine

The tape records the ops that actually ran. So if, for and while all work.

x = tf.Variable(2.0)

with tf.GradientTape() as tape:
    y = x
    for _ in range(3):        # y = x ** 8 after three squarings
        y = y * y

print("y     :", y.numpy())
print("dy/dx :", tape.gradient(y, x).numpy(), "(= 8 * 2**7)")
OUTPUT
y : 256.0 dy/dx : 1024.0 (= 8 * 2**7)

Section 09

Golden Rules

🎥 GradientTape — Rules to Remember
1
Do the forward maths inside the with tf.GradientTape() block. Call tape.gradient after it.
2
The tape watches trainable float Variables by itself. Use tape.watch(t) for tensors.
3
A None gradient means the path from source to target is broken. Check: int dtype, not watched, .numpy(), or a no-gradient op.
4
The gradient has the same shape as the source variable.
5
The chain rule is automatic. Any mix of TF ops and Python control flow works.