Sometimes, you want to control exactly how your model learns. A custom training step lets you do that by writing your own code for one round of learning.
Custom training step in TensorFlow
def train_step(data): with tf.GradientTape() as tape: predictions = model(data[0], training=True) loss = loss_function(data[1], predictions) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) train_loss.update_state(loss) train_accuracy.update_state(data[1], predictions) return {"loss": train_loss.result(), "accuracy": train_accuracy.result()}
The train_step function takes a batch of data and runs one learning round.
Use tf.GradientTape() to record operations for automatic differentiation.
def train_step(data): x, y = data with tf.GradientTape() as tape: y_pred = model(x, training=True) loss = loss_fn(y, y_pred) grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) return loss
def train_step(data): x, y = data with tf.GradientTape() as tape: y_pred = model(x, training=True) loss = loss_fn(y, y_pred) grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) train_loss_metric.update_state(loss) train_acc_metric.update_state(y, y_pred) return {"loss": train_loss_metric.result(), "accuracy": train_acc_metric.result()}
This code loads a small part of MNIST, builds a simple CNN, and runs one epoch using a custom training step. It prints the loss and accuracy after training.
import tensorflow as tf # Prepare simple data (x_train, y_train), _ = tf.keras.datasets.mnist.load_data() x_train = x_train[:1000].astype('float32') / 255.0 x_train = x_train[..., tf.newaxis] y_train = y_train[:1000] train_ds = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32) # Build a simple model model = tf.keras.Sequential([ tf.keras.layers.Conv2D(16, 3, activation='relu'), tf.keras.layers.Flatten(), tf.keras.layers.Dense(10) ]) loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) optimizer = tf.keras.optimizers.Adam() train_loss = tf.keras.metrics.Mean(name='train_loss') train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy') @tf.function def train_step(data): x, y = data with tf.GradientTape() as tape: predictions = model(x, training=True) loss = loss_fn(y, predictions) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) train_loss.update_state(loss) train_accuracy.update_state(y, predictions) return {"loss": train_loss.result(), "accuracy": train_accuracy.result()} # Run one epoch for batch in train_ds: metrics = train_step(batch) print(f"Loss: {metrics['loss']:.4f}, Accuracy: {metrics['accuracy']:.4f}")
Use @tf.function to speed up the training step by compiling it.
Reset metrics if you run multiple epochs to avoid mixing results.
Custom training steps give full control but require careful coding to avoid mistakes.
Custom training steps let you write exactly how your model learns each batch.
They use tf.GradientTape to calculate gradients and update weights.
You can track and return any metrics you want during training.
Practice
What is the main purpose of a custom training step in TensorFlow?
Solution
Step 1: Understand the role of a training step
A training step controls how the model updates its weights using data batches.Step 2: Identify what custom training step changes
Custom training steps let you write your own logic for learning, including gradient calculation and weight updates.Final Answer:
To define exactly how the model learns from each batch of data -> Option DQuick Check:
Custom training step = control learning process [OK]
- Thinking it builds model architecture
- Confusing with data loading
- Assuming it only visualizes outputs
Which of the following is the correct way to start recording operations for gradient calculation in a custom training step?
def train_step(inputs):
# What goes here?
...
Solution
Step 1: Recall TensorFlow's gradient recording method
TensorFlow usestf.GradientTape()to record operations for automatic differentiation.Step 2: Match correct syntax for gradient recording
The correct syntax to start recording iswith tf.GradientTape() as tape:.Final Answer:
with tf.GradientTape() as tape: -> Option BQuick Check:
Gradient recording uses tf.GradientTape [OK]
- Using tf.Session() which is for old TF versions
- Confusing tf.Variable() with gradient recording
- Using tf.data.Dataset() incorrectly here
What will be the output of the following custom training step code snippet?
import tensorflow as tf
model = tf.keras.Sequential([tf.keras.layers.Dense(1)])
optimizer = tf.keras.optimizers.SGD(learning_rate=0.1)
@tf.function
def train_step(x, y):
with tf.GradientTape() as tape:
predictions = model(x, training=True)
loss = tf.reduce_mean(tf.square(y - predictions))
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
x = tf.constant([[1.0], [2.0]])
y = tf.constant([[3.0], [5.0]])
loss_value = train_step(x, y).numpy()
print(round(loss_value, 2))
Solution
Step 1: Calculate initial predictions and loss
Model starts with random weights near zero, so predictions ~0. Loss = mean squared error between y and predictions = mean of [9, 25] = 17.Step 2: After one gradient update with learning rate 0.1, loss reduces
One step reduces loss roughly to around 4.0 (not zero yet).Final Answer:
4.0 -> Option CQuick Check:
One step reduces loss from ~17 to ~4 [OK]
- Assuming loss becomes zero immediately
- Ignoring initial random weights
- Confusing loss with prediction values
Identify the error in this custom training step code and select the fix:
def train_step(x, y):
with tf.GradientTape() as tape:
predictions = model(x)
loss = tf.reduce_mean(tf.square(y - predictions))
gradients = tape.gradient(loss)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
Solution
Step 1: Check tape.gradient usage
tape.gradient requires two arguments: loss and variables to differentiate with respect to.Step 2: Identify missing argument
Code misses the second argument (model.trainable_variables), causing error.Final Answer:
Pass model.trainable_variables as second argument to tape.gradient -> Option AQuick Check:
tape.gradient(loss, variables) needs variables [OK]
- Forgetting second argument in tape.gradient
- Removing GradientTape context
- Changing loss function unnecessarily
You want to track both loss and accuracy in a custom training step for a classification model. Which code snippet correctly updates and returns these metrics?
loss_metric = tf.keras.metrics.Mean()
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy()
@tf.function
def train_step(x, y):
with tf.GradientTape() as tape:
logits = model(x, training=True)
loss = loss_fn(y, logits)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
# What goes here?
...
Solution
Step 1: Understand metric update methods
TensorFlow metrics useupdate_state()to add new values for tracking.Step 2: Correctly update and return metric results
Useloss_metric.update_state(loss)andaccuracy_metric.update_state(y, logits), then return theirresult().Final Answer:
loss_metric.update_state(loss); accuracy_metric.update_state(y, logits); return loss_metric.result(), accuracy_metric.result() -> Option AQuick Check:
Use update_state() and result() for metrics [OK]
- Assigning metric variables instead of updating
- Using non-existent add() method
- Resetting metrics inside training step
Ready to prove it?
Pass the test and this pattern moves unknown
