Train a Clothing Image Classifier
Train and audit a TensorFlow model that classifies Fashion MNIST clothing.
Introduction
30 Second Summary
Small clothing images can be surprisingly ambiguous. A shirt, coat, or pullover can share the same outline when detail disappears.
In this project, you will train a neural network in Google Colab with TensorFlow to classify ten types of clothing. You will compare a deliberately biased training run with a complete one to see how missing categories damage performance on unseen images.
What You'll Build
Your finished notebook will show a clothing classifier learning in the browser before exposing its wrong answers in a visual gallery.
By the end of this project, you'll have:
- A 3 by 3 preview of labeled data that connects numeric labels to recognizable clothing categories.
- A before-and-after accuracy comparison that shows why a model trained on two categories fails across ten.
- A twenty-five-image mistake gallery that pairs each wrong prediction with its true label and confidence score.
- Secret Mission: Turn the mistake gallery into an evidence-based model audit that links recurring errors to follow-up experiments.
Are there any prerequisites?
You need a Google account, Google Chrome, and basic Python knowledge covering variables, functions, lists, and loops. The browser-based notebook requires no local Python or machine learning installation.
Before We Start
Before the hands-on work begins, this is your moment to commit to the clothing image classifier you are building and why evidence from unseen images matters.
Set Up the Colab Notebook
Your plan for testing unseen clothing images now needs a place where the classifier code can run.
Google Colab runs notebooks in your browser. It removes local installation work so you can focus on training and evaluating the model.
In this step, get ready to:
- Create a blank Colab notebook named clothing_classifier.ipynb.
- Add the TensorFlow imports plus the Matplotlib imports.
- Confirm the setup cell reports the expected library versions.
Create the Colab notebook
Colab stores notebooks in Google Drive. Your work stays attached to your Google account.
Signing in uses Google's account flow. You never paste account credentials into the notebook code.
- Visit Google Colab in Chrome.
- Select Sign in if Colab asks you to authenticate.
- Choose the Google account confirmed for this project.
- Click New notebook on the Colab landing page.
- Click the current notebook name in the top-left corner.
- Enter clothing_classifier.ipynb as the new name.
- Press Enter to apply the name.
You should see a blank notebook with clothing_classifier.ipynb at the top.
Notebook did not open?
- Check that you completed Google sign-in in the same Chrome profile.
- Reload the Colab landing page after sign-in completes.
Help me fix a Google Colab notebook that does not open after sign-in.
Add the setup code
The setup cell imports the two libraries used throughout the project. Its print statements record the versions supplied by the hosted environment.
- Click the empty code cell beneath the notebook toolbar.
- Add the imports plus the version checks by pasting this code:
import tensorflow as tf
import matplotlib
import matplotlib.pyplot as plt
print(f"TensorFlow: {tf.__version__}")
print(f"Matplotlib: {matplotlib.__version__}")
What does this code do?
- tensorflow as tf gives the notebook a short name for accessing TensorFlow features.
- matplotlib exposes the installed Matplotlib version.
- matplotlib.pyplot as plt imports the plotting interface used for clothing image galleries.
- The two print statements record the library versions available in the current runtime.
- Confirm Colab reports that the notebook is saved to Google Drive.
- Check that the code cell contains three import lines above two print statements.
Cell does not match?
- Check that the three import lines appear above the two print statements.
- Replace any smart quotation marks with the straight quotation marks shown in the snippet.
Help me compare my Colab setup cell with the supplied TensorFlow and Matplotlib code.
Run the setup cell
A Colab runtime executes the code behind your notebook. This check proves both libraries are available before you load any training data.
The first execution can pause briefly while Colab connects to the runtime. That short wait is expected.
Before you run the cell, do you expect both libraries to import without errors?
- Run the setup cell by clicking the play button on its left.
Under the cell, you should see TensorFlow: 2.21.0 on one line. You should see Matplotlib: 3.10.0 on the next line without an import error.
Your setup is working. The hosted notebook now records successful imports for both libraries.
Seeing an import problem?
- Reconnect to a fresh standard hosted runtime from Colab's runtime controls.
- Run the unchanged setup cell again after the runtime connects.
Help me diagnose an import problem in my Colab setup cell.
The tabs below provide a quick confirmation or the exact notebook structure for comparison.
✔️ Awesome, I've got everything!
Your setup cell is complete. Colab stores the notebook in Google Drive.
ⓧ I'd like to double check the full code
{"cells":[{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"import tensorflow as tf\nimport matplotlib\nimport matplotlib.pyplot as plt\n\nprint(f\"TensorFlow: {tf.__version__}\")\nprint(f\"Matplotlib: {matplotlib.__version__}\")\n"}],"metadata":{},"nbformat":4,"nbformat_minor":5}
Your hosted notebook is ready for model work. Next, you will load Fashion MNIST and inspect the images your classifier learns from.
Inspect the Training Data
Your TensorFlow runtime in Google Colab is ready. Now you need to understand the examples that will teach your classifier.
Fashion MNIST uses labeled data to connect each image with its clothing category. Image normalization puts every pixel on a consistent scale before training.
In this step, get ready to:
- Prepare the Fashion MNIST images with their ordered class names.
- Confirm the dataset dimensions before scaling every pixel to a consistent range.
- Display the first nine training images with their panel labels.
Prepare the image arrays
A labeled dataset pairs each input with the answer a model should learn. Fashion MNIST provides 60,000 training images plus 10,000 separate test images.
- Add a new code cell directly beneath the setup cell using Colab's code-cell control.
- Prepare the labeled dataset by pasting this code into the new cell:
(train_images, train_labels), (test_images, test_labels) = (
tf.keras.datasets.fashion_mnist.load_data()
)
class_names = (
"T-shirt/top",
"Trouser",
"Pullover",
"Dress",
"Coat",
"Sandal",
"Shirt",
"Sneaker",
"Bag",
"Ankle boot",
)
print("Training shape:", train_images.shape)
print("Test shape:", test_images.shape)
print("Original pixel range:", train_images.min(), train_images.max())
train_images = train_images / 255.0
test_images = test_images / 255.0
What does this code do?
- The load_data() call returns separate arrays for training images, training labels, test images, plus test labels.
- The class_names tuple maps each numeric label to its clothing category.
- The three print statements record the dataset dimensions plus the original pixel range.
- Dividing by 255.0 changes the pixel scale from 0 through 255 to 0 through 1.
- Run the data cell using the play control beside it.
You'll see Training shape: (60000, 28, 28). The next line shows Test shape: (10000, 28, 28).
You'll also see Original pixel range: 0 255. This confirms the values were inspected before normalization.
That is the data foundation in place: your notebook now holds normalized arrays for both dataset splits.
Shapes not printing?
Confirm that the notebook runtime is still connected. Rerun the setup cell before running the data cell again.
If loading stops partway through, check your internet connection before retrying the cell.
Help me diagnose why my Fashion MNIST data cell is not completing in Google Colab.
Display the labeled sample grid
A shape tells you how much data exists. A visual sample lets you confirm what those pixel arrays represent before the model learns from them.
Matplotlib provides a grid of axes for displaying several images in one figure. The panel output links each position to its class name.
- Append the visualization code below to the end of the same data cell:
figure, axes = plt.subplots(3, 3, figsize=(7, 7))
for panel in range(9):
row = panel // 3
column = panel % 3
axes[row, column].imshow(train_images[panel], cmap="gray")
print(f"Panel {panel + 1}: {class_names[train_labels[panel]]}")
plt.show()
How does the grid work?
- The plt.subplots(3, 3) call creates nine axes arranged across three rows.
- The loop calculates a row position from each panel number.
- The loop also calculates the matching column position.
- The imshow call displays each normalized image in grayscale.
- The print statement connects each panel number to the matching entry in class_names.
Before you run the completed cell, do you expect the printed panel order to match the grid's row-by-row reading order?
- Run the completed data cell using the play control beside it.
You'll see a 3 by 3 grid containing the first nine normalized training images. You'll also see lines beginning with Panel 1 through Panel 9.
You have turned the image arrays into evidence you can inspect. Each numbered panel now has a visible category label.
Grid missing or incomplete?
Confirm that the visualization code sits at the end of the same cell as the data-loading code.
Check that every line inside the for loop has the same four-space indentation.
Help me fix my 3 by 3 Fashion MNIST image grid in Google Colab.
✔️ Awesome, I've got everything!
Your notebook now contains the complete data-loading, normalization, inspection, plus visualization cell.
ⓧ I'd like to double check the full code
{"cells":[{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"import tensorflow as tf\nimport matplotlib\nimport matplotlib.pyplot as plt\n\nprint(f\"TensorFlow: {tf.__version__}\")\nprint(f\"Matplotlib: {matplotlib.__version__}\")\n"},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":"(train_images, train_labels), (test_images, test_labels) = (\n tf.keras.datasets.fashion_mnist.load_data()\n)\n\nclass_names = (\n \"T-shirt/top\",\n \"Trouser\",\n \"Pullover\",\n \"Dress\",\n \"Coat\",\n \"Sandal\",\n \"Shirt\",\n \"Sneaker\",\n \"Bag\",\n \"Ankle boot\",\n)\n\nprint(\"Training shape:\", train_images.shape)\nprint(\"Test shape:\", test_images.shape)\nprint(\"Original pixel range:\", train_images.min(), train_images.max())\n\ntrain_images = train_images / 255.0\ntest_images = test_images / 255.0\n\nfigure, axes = plt.subplots(3, 3, figsize=(7, 7))\nfor panel in range(9):\n row = panel // 3\n column = panel % 3\n axes[row, column].imshow(train_images[panel], cmap=\"gray\")\n print(f\"Panel {panel + 1}: {class_names[train_labels[panel]]}\")\nplt.show()\n"}],"metadata":{},"nbformat":4,"nbformat_minor":5}
Your training data is loaded, scaled, plus visible. Next, you'll use those labeled examples to expose what happens when a classifier learns from incomplete category coverage.
Train a Model with a Blind Spot
Your normalized Fashion MNIST images are ready for training. You can now use TensorFlow to build a neural network that learns from those examples.
Dataset coverage determines which categories a model can learn. This step deliberately trains on only T-shirt/top and Trouser images before testing against all ten categories.
In this step, get ready to:
- Define a reusable classifier architecture.
- Restrict its training examples to two clothing categories.
- Measure its performance across the complete test set.
Define the model builder
A model builder keeps the architecture in one function. Calling build_model() creates a fresh classifier with the same layers each time.
- Insert a code cell below the data-inspection cell using Google Colab's code-cell control.
- Add the model builder to that code cell by pasting this code:
def build_model(hidden_units=128):
model = tf.keras.Sequential([
tf.keras.Input(shape=(28, 28)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(
hidden_units, activation=tf.keras.activations.relu
),
tf.keras.layers.Dense(
10, activation=tf.keras.activations.softmax
),
])
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[
tf.keras.metrics.SparseCategoricalAccuracy(name="accuracy")
],
)
return model
What does this model builder do?
- The Input layer expects images with a height of 28 pixels and a width of 28 pixels.
- The Flatten layer turns each image into a single sequence of pixel values.
- The hidden Dense layer learns combinations of pixels using the ReLU activation.
- The output Dense layer produces ten softmax scores that sum to 1.
- The compile settings tell Keras how to update the model and calculate its accuracy.
- Run the code cell using its play control.
- Confirm the cell reaches a completed execution state without an exception.
Seeing an exception in the model cell?
- Confirm the setup cell has already imported tf.
- Check that each opening parenthesis and bracket has a matching closing character.
- Rerun the model cell after correcting any indentation that changed during pasting.
Help me fix the model builder in my Colab notebook.
Limit the training labels
A Boolean mask can select rows whose labels satisfy a condition. Here, labels below 2 keep only the first two categories in class_names.
- Append the biased dataset selection to the same code cell:
biased_mask = train_labels < 2
biased_images = train_images[biased_mask][:1000]
biased_labels = train_labels[biased_mask][:1000]
How does the biased dataset work?
- The biased_mask array identifies every training example labeled 0 or 1.
- The biased_images array keeps the first 1,000 matching images.
- The biased_labels array keeps the corresponding labels in the same order.
- Run the combined code cell using its play control.
- Confirm the cell's execution count updates without an exception.
Does the biased dataset selection fail?
- Confirm the earlier data cell created train_images and train_labels.
- Check that biased_mask uses the less-than symbol before 2.
- Check that both filtered arrays end with [:1000].
Help me debug the biased Fashion MNIST selection.
Measure the biased model
An epoch is one complete pass through the selected training examples. After that pass, the model faces every image in the ten-category test set to measure its generalization.
- Append the training and evaluation logic to the end of the same code cell:
biased_model = build_model()
biased_model.fit(biased_images, biased_labels, epochs=1, verbose=2)
_, biased_test_accuracy = biased_model.evaluate(
test_images, test_labels, verbose=0
)
print(f"Biased-model test accuracy: {biased_test_accuracy:.3f}")
What happens during this run?
- The build_model() call creates a fresh classifier.
- The fit call trains it once on the 1,000 biased examples.
- The evaluate call tests the trained model against every test image.
- The final line records the resulting test score to three decimal places.
Before you run the complete cell, do you expect training on two categories to produce strong performance across ten categories?
- Run the complete code cell using its play control.
You'll see one epoch complete. A line beginning Biased-model test accuracy: follows.
That's the blind spot made measurable. The score exposes the intended shortfall caused by training with only two of the ten labels.
Missing the accuracy line?
- Rerun the entire combined cell from its first line.
- Check that biased_model.fit receives biased_images and biased_labels.
- Check that biased_model.evaluate receives test_images and test_labels.
Help me find why the biased-model accuracy is missing.
✔️ Awesome, I've got everything!
Great work. Your third notebook cell now defines the model and records how it performs with incomplete class coverage.
ⓧ I'd like to double check the full code
def build_model(hidden_units=128):
model = tf.keras.Sequential([
tf.keras.Input(shape=(28, 28)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(
hidden_units, activation=tf.keras.activations.relu
),
tf.keras.layers.Dense(
10, activation=tf.keras.activations.softmax
),
])
model.compile(
optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[
tf.keras.metrics.SparseCategoricalAccuracy(name="accuracy")
],
)
return model
biased_mask = train_labels < 2
biased_images = train_images[biased_mask][:1000]
biased_labels = train_labels[biased_mask][:1000]
biased_model = build_model()
biased_model.fit(biased_images, biased_labels, epochs=1, verbose=2)
_, biased_test_accuracy = biased_model.evaluate(
test_images, test_labels, verbose=0
)
print(f"Biased-model test accuracy: {biased_test_accuracy:.3f}")
You now have evidence that incomplete training coverage creates a measurable blind spot. Next, you'll keep the architecture constant while expanding the training data to all ten categories.
Retrain on Complete Data
Your biased TensorFlow classifier has now faced images from all ten clothing categories. Its result exposed the blind spot caused by training on only two categories.
Eight categories were absent from its training examples. In Google Colab, you will now train the same architecture on the complete labeled dataset.
In this step, get ready to:
- Create a fresh model with the existing build_model() function.
- Train the model on all 60,000 normalized training images for five epochs.
- Compare the biased result with the full model's training and test accuracy.
Keep the architecture fixed
A controlled comparison holds the model architecture constant. Complete dataset coverage becomes the deliberate change in this experiment.
- Return to the biased-model output at the bottom of clothing_classifier.ipynb.
- Confirm that its final line begins with Biased-model test accuracy:.
Why Use a Fresh Model?
Calling build_model() creates a classifier with fresh randomized weights. It keeps the same layer design as the biased model.
The architecture stays fixed throughout the comparison. Training data coverage becomes the factor you are testing.
Add the full-data training cell
An epoch is one complete pass through the training data. Five epochs give the fresh model repeated exposure to examples from all ten categories.
- Select the biased-model cell that ends with the printed test accuracy.
- Insert a new code cell directly beneath it with the notebook's add-code control.
- Paste the full-data experiment below into the new cell.
model = build_model()
full_history = model.fit(
train_images, train_labels, epochs=5, verbose=2
)
_, full_test_accuracy = model.evaluate(test_images, test_labels, verbose=0)
full_train_accuracy = full_history.history["accuracy"][-1]
print(f"Biased-model test accuracy: {biased_test_accuracy:.3f}")
print(f"Full-model training accuracy: {full_train_accuracy:.3f}")
print(f"Full-model test accuracy: {full_test_accuracy:.3f}")
What Does This Code Do?
- The model variable holds a fresh classifier created by build_model().
- The full_history variable stores the accuracy recorded during each training epoch.
- The full_test_accuracy variable stores the model's accuracy across all 10,000 test images.
- The full_train_accuracy variable extracts the final epoch's training accuracy.
- The print statements place the biased result beside the two full-model results.
Run and compare the results
Training accuracy measures performance on examples used to adjust the model. Test accuracy measures generalization across separate images.
This run processes all 60,000 images during each of five passes. Expect a longer wait than the biased run while one epoch line arrives at a time.
Before you run the cell, consider which model you expect to have the higher test accuracy.
- Run the new cell with the run control on its left.
You will see five epoch records. Each record includes the loss and accuracy measured during that pass.
After the fifth epoch, you will see lines beginning with Biased-model test accuracy:, Full-model training accuracy:, and Full-model test accuracy:.
- Compare the value after Full-model test accuracy: with the value after Biased-model test accuracy:.
- Confirm that the full-model test accuracy is higher than the biased-model test accuracy.
The exact decimal values can vary because the fresh model begins with randomized weights. The higher full-model result shows how complete class coverage fixes the deliberate blind spot.
Training Cell Not Completing?
- Run the earlier notebook cells from top to bottom if the current runtime no longer has train_images or build_model().
- Check that the training call uses train_images if the full model still performs like the biased model.
- Check that the training call contains epochs=5 if only one epoch appears.
Help me troubleshoot my full-data training cell in Google Colab.
Strong result. Your classifier now learns from examples across all ten clothing categories.
✔️ Awesome, I've got everything!
Your fourth code cell trains the full-data model for five epochs. It prints all three accuracy values for comparison.
ⓧ I'd like to double check the full code
model = build_model()
full_history = model.fit(
train_images, train_labels, epochs=5, verbose=2
)
_, full_test_accuracy = model.evaluate(test_images, test_labels, verbose=0)
full_train_accuracy = full_history.history["accuracy"][-1]
print(f"Biased-model test accuracy: {biased_test_accuracy:.3f}")
print(f"Full-model training accuracy: {full_train_accuracy:.3f}")
print(f"Full-model test accuracy: {full_test_accuracy:.3f}")
Your full-data model now outperforms the classifier with missing classes. Next up, you will inspect individual mistakes to uncover what the overall score still hides.
Investigate the Model's Mistakes
Your full-data model now performs better across all ten clothing classes. Its accuracy still compresses 10,000 test decisions into one number.
Error analysis opens those individual decisions back up. A mistake gallery shows the model's confidence beside each failure.
Confident mistakes reveal gaps that the overall score can hide. These examples show where the model still struggles with unseen images.
In this step, get ready to:
- Generate predictions for every normalized test image.
- Locate every misclassified test image.
- Create panel evidence for the first twenty-five mistakes.
Create the mistake evidence
A softmax prediction gives one score to each clothing class. The largest score becomes the predicted label.
Comparing that label with the true label isolates the mistakes. The corresponding maximum score records how confident the model was.
- Use the code-cell control in Google Colab to insert a new cell directly beneath the full-model cell.
- Paste the following code into the new cell:
predictions = model.predict(test_images, verbose=0)
predicted_labels = predictions.argmax(axis=1)
confidence_scores = predictions.max(axis=1)
mistake_indices = (predicted_labels != test_labels).nonzero()[0]
figure, axes = plt.subplots(5, 5, figsize=(10, 10))
for panel, index in enumerate(mistake_indices[:25]):
row = panel // 5
column = panel % 5
axes[row, column].imshow(test_images[index], cmap="gray")
print(
f"Panel {panel + 1}: "
f"predicted={class_names[predicted_labels[index]]}, "
f"true={class_names[test_labels[index]]}, "
f"confidence={confidence_scores[index]:.1%}"
)
plt.show()
What does this code do?
- The predictions array stores one class-score vector for every image in test_images.
- The predicted_labels array stores the highest-scoring class index for each image.
- The confidence_scores array stores the largest score from each prediction.
- The mistake_indices array stores the positions where a prediction differs from the true label.
- The plt.subplots(5, 5) call creates the twenty-five-panel Matplotlib gallery.
- The row value places each image in its correct horizontal band.
- The column value places each image in its correct vertical position.
- The loop prints one evidence record for each displayed mistake.
Before you run the cell, do you expect every wrong prediction to have low confidence?
- Run the fifth code cell using the play button on its left.
You'll see twenty-five printed lines followed by a 5 by 5 gallery. The lines begin with Panel 1 through Panel 25.
Each line names its predicted class. The same line identifies its true class.
A confidence percentage completes each record. The gallery shows the corresponding misclassified images.
Cell not producing the gallery?
- Confirm the fifth cell sits below the full-training cell.
- Rerun the earlier notebook cells in order if Colab lost the prior variables.
Ask for help with the missing output:
✔️ Awesome, I've got everything!
Your fifth code cell now generates predictions and turns the first twenty-five mistakes into visible evidence.
ⓧ I'd like to double check the full code
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"import matplotlib\n",
"import matplotlib.pyplot as plt\n",
"\n",
"print(f\"TensorFlow: {tf.__version__}\")\n",
"print(f\"Matplotlib: {matplotlib.__version__}\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"(train_images, train_labels), (test_images, test_labels) = (\n",
" tf.keras.datasets.fashion_mnist.load_data()\n",
")\n",
"\n",
"class_names = (\n",
" \"T-shirt/top\",\n",
" \"Trouser\",\n",
" \"Pullover\",\n",
" \"Dress\",\n",
" \"Coat\",\n",
" \"Sandal\",\n",
" \"Shirt\",\n",
" \"Sneaker\",\n",
" \"Bag\",\n",
" \"Ankle boot\",\n",
")\n",
"\n",
"print(\"Training shape:\", train_images.shape)\n",
"print(\"Test shape:\", test_images.shape)\n",
"print(\"Original pixel range:\", train_images.min(), train_images.max())\n",
"\n",
"train_images = train_images / 255.0\n",
"test_images = test_images / 255.0\n",
"\n",
"figure, axes = plt.subplots(3, 3, figsize=(7, 7))\n",
"for panel in range(9):\n",
" row = panel // 3\n",
" column = panel % 3\n",
" axes[row, column].imshow(train_images[panel], cmap=\"gray\")\n",
" print(f\"Panel {panel + 1}: {class_names[train_labels[panel]]}\")\n",
"plt.show()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def build_model(hidden_units=128):\n",
" model = tf.keras.Sequential([\n",
" tf.keras.Input(shape=(28, 28)),\n",
" tf.keras.layers.Flatten(),\n",
" tf.keras.layers.Dense(\n",
" hidden_units, activation=tf.keras.activations.relu\n",
" ),\n",
" tf.keras.layers.Dense(\n",
" 10, activation=tf.keras.activations.softmax\n",
" ),\n",
" ])\n",
" model.compile(\n",
" optimizer=tf.keras.optimizers.Adam(),\n",
" loss=tf.keras.losses.SparseCategoricalCrossentropy(),\n",
" metrics=[\n",
" tf.keras.metrics.SparseCategoricalAccuracy(name=\"accuracy\")\n",
" ],\n",
" )\n",
" return model\n",
"\n",
"biased_mask = train_labels < 2\n",
"biased_images = train_images[biased_mask][:1000]\n",
"biased_labels = train_labels[biased_mask][:1000]\n",
"\n",
"biased_model = build_model()\n",
"biased_model.fit(biased_images, biased_labels, epochs=1, verbose=2)\n",
"_, biased_test_accuracy = biased_model.evaluate(\n",
" test_images, test_labels, verbose=0\n",
")\n",
"print(f\"Biased-model test accuracy: {biased_test_accuracy:.3f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"model = build_model()\n",
"full_history = model.fit(\n",
" train_images, train_labels, epochs=5, verbose=2\n",
")\n",
"_, full_test_accuracy = model.evaluate(test_images, test_labels, verbose=0)\n",
"full_train_accuracy = full_history.history[\"accuracy\"][-1]\n",
"\n",
"print(f\"Biased-model test accuracy: {biased_test_accuracy:.3f}\")\n",
"print(f\"Full-model training accuracy: {full_train_accuracy:.3f}\")\n",
"print(f\"Full-model test accuracy: {full_test_accuracy:.3f}\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"predictions = model.predict(test_images, verbose=0)\n",
"predicted_labels = predictions.argmax(axis=1)\n",
"confidence_scores = predictions.max(axis=1)\n",
"mistake_indices = (predicted_labels != test_labels).nonzero()[0]\n",
"\n",
"figure, axes = plt.subplots(5, 5, figsize=(10, 10))\n",
"for panel, index in enumerate(mistake_indices[:25]):\n",
" row = panel // 5\n",
" column = panel % 5\n",
" axes[row, column].imshow(test_images[index], cmap=\"gray\")\n",
" print(\n",
" f\"Panel {panel + 1}: \"\n",
" f\"predicted={class_names[predicted_labels[index]]}, \"\n",
" f\"true={class_names[test_labels[index]]}, \"\n",
" f\"confidence={confidence_scores[index]:.1%}\"\n",
" )\n",
"plt.show()\n"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
Verify the panel evidence
The printed evidence follows the same row-major order as the gallery. This keeps every text record tied to one visible image.
- Read the printed panel records from top to bottom.
- Match each printed record to the image in the same numbered gallery position.
You'll count exactly twenty-five panel records. You'll also see twenty-five misclassified images arranged across five rows.
You have turned one accuracy score into inspectable evidence. Your notebook now exposes the specific test images that the model gets wrong.
Secret mission
Audit the Error Patterns
Turn the twenty-five mistakes into a three-row model audit. You will cite actual panels for recurring confusions. Each pattern ends with a controlled next experiment.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to keep the notebook, release its temporary runtime, or delete the saved file. Google Colab's free-of-charge tier keeps this project at $0 while Google Drive stores the notebook.
Resources you used:
- The clothing_classifier.ipynb notebook stored in Google Drive.
- The temporary virtual machine that holds the current Colab session.
Keep everything running
No action needed. Choose this if you want to reopen the classifier notebook or share your results later.
- Leave clothing_classifier.ipynb in Google Drive.
- Reopen the notebook from Google Drive when you want to continue.
- Rerun all notebook cells after Colab assigns a new runtime.
Free Colab resources are not guaranteed or unlimited. A future session may start with a fresh runtime.
Pause - I'll come back to this later
Release the temporary virtual machine while keeping your notebook in Google Drive. Choose this option when you want to free the current Colab resources without losing your work.
- In the Colab notebook from earlier, select Runtime in the top menu.
- Select Disconnect and delete runtime.
Your temporary runtime is now released. Your classifier code and model audit remain saved in clothing_classifier.ipynb.
Delete - I don't want to use this again
Remove the temporary runtime and the saved notebook. Choose this option when you no longer need the classifier or its model audit.
Deletion Removes Your Saved Work
Deleting your work is the irreversible option here. Emptying Google Drive Trash permanently removes the saved notebook.
- In clothing_classifier.ipynb, select Runtime in the top menu.
- Select Disconnect and delete runtime.
- Open Google Drive in a new Chrome tab.
- Locate clothing_classifier.ipynb in Google Drive.
- Move clothing_classifier.ipynb to Trash.
- Open Trash in Google Drive.
- Empty Trash to permanently remove the notebook.
The temporary virtual machine is released. After Trash is empty, clothing_classifier.ipynb no longer appears there.
Nice Work!
Nice Work!
You did it! You built a clothing classifier with TensorFlow in Google Colab.
You've learned how to:
- Train a deliberately biased neural network on two clothing classes. Its ten-class test result exposes the cost of incomplete dataset coverage.
- Retrain the same architecture on all ten classes. The stronger test accuracy measures improved generalization on unseen images.
- Perform error analysis with a twenty-five-image gallery of misclassified test examples. Each panel records a prediction beside the true label. The confidence score reveals how strongly the model backed its mistake.
- Secret Mission: Turn recurring confusion patterns into an evidence-based model audit. The audit cites real panel evidence. It proposes controlled follow-up experiments.
Ready to quiz yourself?