Neural Networks with Fashion MNIST
This page explains a basic dense neural network workflow with Fashion MNIST: loading images, preparing labels, building a Sequential model, training, predicting, and evaluating classification quality.
- Load and inspect Fashion MNIST image and label arrays.
- Normalize pixel values and create a validation split.
- Build a dense neural network with Flatten, Dense, ReLU, and softmax layers.
- Train, evaluate, predict classes, and read a classification report and confusion matrix.
- Neural network inputs should be scaled; image pixels are commonly divided by 255.
- A softmax output layer returns one probability per class.
- np.argmax converts class probabilities into the predicted class index.
Setup and Dataset
Listing 1. Import TensorFlow and Keras
This step supports the workflow shown in the surrounding listings.
import tensorflow as tf
from tensorflow import kerasListing 2. Check the TensorFlow version
This step supports the workflow shown in the surrounding listings.
tf.__version__Expected text output or note
'2.15.0'Listing 3. Load Fashion MNIST from Keras datasets
This prepares the data or pretrained resource used by the following examples.
dataset = keras.datasets.fashion_mnist
(X_train,y_train), (X_test,y_test)=dataset.load_data()Expected text output or note
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
29515/29515 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26421880/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
5148/5148 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4422102/4422102 [==============================] - 0s 0us/stepListing 4. Check the training image array shape
Training updates model weights and stores the learning history for later inspection.
X_train.shapeExpected text output or note
(60000, 28, 28)Listing 5. Inspect the raw training labels
Training updates model weights and stores the learning history for later inspection.
y_trainExpected text output or note
array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)Listing 6. Define readable Fashion MNIST class names
This step supports the workflow shown in the surrounding listings.
class_names=["T-shirt/top", "Trouser", "Pullover","Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]Listing 7. Inspect the first training label
Training updates model weights and stores the learning history for later inspection.
y_train[0]Expected text output or note
9Listing 8. Convert the first training label to its class name
Training updates model weights and stores the learning history for later inspection.
class_names[y_train[0]]Expected text output or note
'Ankle boot'Listing 9. Check one image shape
This step supports the workflow shown in the surrounding listings.
X_train[0].shapeExpected text output or note
(28, 28)Listing 10. Display one grayscale Fashion MNIST image
This visualization step helps verify what the data or model output looks like.
import matplotlib.pyplot as plt
plt.imshow(X_train[0], cmap='gray')Expected text output or note
<matplotlib.image.AxesImage at 0x7a15769d0910>
<Figure size 640x480 with 1 Axes>
[visual output omitted; run the code to display the image or chart]Listing 11. Normalize pixel values to the 0 to 1 range
This transforms the raw input into the numeric scale or shape expected by the model.
X_train=X_train/255Listing 12. Create validation data from the first 5,000 training examples
Training updates model weights and stores the learning history for later inspection.
X_valid=X_train[:5000]
X_train=X_train[5000:]
y_valid=y_train[:5000]
y_train=y_train[5000:]Listing 13. Preview validation images with their class names
This step supports the workflow shown in the surrounding listings.
for i in range(0,5):
plt.subplot(151+i)
plt.imshow(X_valid[i], cmap='gray')
plt.title(class_names[y_valid[i]])
plt.show()Expected text output or note
<Figure size 640x480 with 5 Axes>
[visual output omitted; run the code to display the image or chart]Model Architecture
Listing 14. Create an empty Sequential model
This defines or inspects part of the neural network architecture.
model=keras.models.Sequential()Listing 15. Flatten 28 by 28 images into vectors
This step supports the workflow shown in the surrounding listings.
model.add(keras.layers.Flatten(input_shape=[28,28]))Listing 16. Add the first hidden dense layer
This defines or inspects part of the neural network architecture.
model.add(keras.layers.Dense(300, activation="relu"))Listing 17. Add the second hidden dense layer
This defines or inspects part of the neural network architecture.
model.add(keras.layers.Dense(100, activation="relu"))Listing 18. Add the softmax output layer for 10 classes
This defines or inspects part of the neural network architecture.
model.add(keras.layers.Dense(10, activation="softmax"))Listing 19. List the model layers
This defines or inspects part of the neural network architecture.
model.layersExpected text output or note
[<keras.src.layers.reshaping.flatten.Flatten at 0x7a1576856290>,
<keras.src.layers.core.dense.Dense at 0x7a1576857a00>,
<keras.src.layers.core.dense.Dense at 0x7a1576798580>,
<keras.src.layers.core.dense.Dense at 0x7a1576798be0>]Listing 20. Print the model architecture summary
This defines or inspects part of the neural network architecture.
model.summary()Expected text output or note
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
dense (Dense) (None, 300) 235500
dense_1 (Dense) (None, 100) 30100
dense_2 (Dense) (None, 10) 1010
=================================================================
Total params: 266610 (1.02 MB)
Trainable params: 266610 (1.02 MB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________Listing 21. Draw the model graph with tensor shapes
This defines or inspects part of the neural network architecture.
keras.utils.plot_model(model, show_shapes=True)Expected text output or note
<IPython.core.display.Image object>
[visual output omitted; run the code to display the image or chart]Listing 22. Select the first hidden layer
This defines or inspects part of the neural network architecture.
hidden1=model.layers[1]Listing 23. Read weights and bias values from the hidden layer
This defines or inspects part of the neural network architecture.
weights, bias= hidden1.get_weights()Listing 24. Inspect the hidden-layer weight matrix
This defines or inspects part of the neural network architecture.
weightsExpected text output or note
array([[-0.06094005, 0.02962055, -0.02309486, ..., -0.06288422,
-0.01324312, -0.0500589 ],
[ 0.070352 , -0.03515274, -0.04809655, ..., -0.04971475,
0.04923429, 0.01798429],
[-0.05490538, 0.02042819, -0.02559312, ..., -0.01840512,
0.0332567 , -0.0607585 ],
...,
[ 0.06727193, 0.05644499, -0.03700116, ..., 0.02343841,
0.07261452, 0.03050473],
[-0.05256438, -0.06475436, -0.03320796, ..., 0.017466 ,
-0.05396302, 0.07283223],
[ 0.017487 , -0.02869108, 0.05089015, ..., 0.04649328,
-0.06772804, 0.01935725]], dtype=float32)Training
Listing 25. Compile the classifier with sparse categorical crossentropy
Compilation chooses the loss function, optimizer, and metrics used during training.
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"]) # more metrics can be listed hereListing 26. Train the dense neural network
Training updates model weights and stores the learning history for later inspection.
history=model.fit(X_train,y_train,batch_size=32, epochs=20, validation_data=(X_valid, y_valid))
#history=model.fit(X_train,y_train,batch_size=256, epochs=20, validation_split=0.2)Expected text output or note
Epoch 1/20
1719/1719 [==============================] - 14s 6ms/step - loss: 0.7172 - accuracy: 0.7635 - val_loss: 0.5121 - val_accuracy: 0.8246
Epoch 2/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.4911 - accuracy: 0.8294 - val_loss: 0.4867 - val_accuracy: 0.8204
Epoch 3/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.4473 - accuracy: 0.8433 - val_loss: 0.4261 - val_accuracy: 0.8530
Epoch 4/20
1719/1719 [==============================] - 6s 4ms/step - loss: 0.4184 - accuracy: 0.8545 - val_loss: 0.4224 - val_accuracy: 0.8552
Epoch 5/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.3992 - accuracy: 0.8588 - val_loss: 0.3741 - val_accuracy: 0.8718
Epoch 6/20
1719/1719 [==============================] - 6s 4ms/step - loss: 0.3831 - accuracy: 0.8651 - val_loss: 0.3749 - val_accuracy: 0.8678
Epoch 7/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.3689 - accuracy: 0.8702 - val_loss: 0.3631 - val_accuracy: 0.8756
Epoch 8/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.3556 - accuracy: 0.8747 - val_loss: 0.3483 - val_accuracy: 0.8800
Epoch 9/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.3452 - accuracy: 0.8786 - val_loss: 0.3641 - val_accuracy: 0.8728
Epoch 10/20
1719/1719 [==============================] - 6s 4ms/step - loss: 0.3358 - accuracy: 0.8797 - val_loss: 0.3379 - val_accuracy: 0.8818
Epoch 11/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.3273 - accuracy: 0.8831 - val_loss: 0.3397 - val_accuracy: 0.8794
Epoch 12/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.3194 - accuracy: 0.8855 - val_loss: 0.3276 - val_accuracy: 0.8862
Epoch 13/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.3104 - accuracy: 0.8887 - val_loss: 0.3331 - val_accuracy: 0.8804
Epoch 14/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.3039 - accuracy: 0.8912 - val_loss: 0.3253 - val_accuracy: 0.8876
Epoch 15/20
1719/1719 [==============================] - 6s 3ms/step - loss: 0.2979 - accuracy: 0.8927 - val_loss: 0.3202 - val_accuracy: 0.8870
Epoch 16/20
1719/1719 [==============================] - 5s 3ms/step - loss: 0.2911 - accuracy: 0.8947 - val_loss: 0.3279 - val_accuracy: 0.8842
Epoch 17/20
1719/1719 [==============================] - 6s 4ms/step - loss: 0.2858 - ac
[output shortened for documentation readability]Listing 27. Inspect the metrics stored in the training history
Training updates model weights and stores the learning history for later inspection.
history.history.keys()Expected text output or note
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])Listing 28. Plot training and validation curves
Training updates model weights and stores the learning history for later inspection.
import pandas as pd
pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.ylim(0,1)
plt.show()Expected text output or note
<Figure size 800x500 with 1 Axes>
[visual output omitted; run the code to display the image or chart]Evaluation and Predictions
Listing 29. Evaluate the model on the test set
This defines or inspects part of the neural network architecture.
model.evaluate(X_test,y_test)Expected text output or note
313/313 [==============================] - 1s 2ms/step - loss: 69.8466 - accuracy: 0.8355
[69.84664154052734, 0.8355000019073486]Listing 30. Predict class probabilities for test images
Prediction applies the trained model to new data and returns probabilities or labels.
predictions=model.predict(X_test)Expected text output or note
313/313 [==============================] - 1s 2ms/stepListing 31. Inspect the raw probability matrix
This step supports the workflow shown in the surrounding listings.
predictionsExpected text output or note
array([[0., 0., 0., ..., 0., 0., 1.],
[0., 0., 1., ..., 0., 0., 0.],
[0., 1., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 1., 0.],
[0., 1., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.]], dtype=float32)Listing 32. Convert probabilities to predicted class indexes
Prediction applies the trained model to new data and returns probabilities or labels.
import numpy as np
y_pred=np.argmax(predictions,axis=-1)Listing 33. Inspect predicted class indexes
Prediction applies the trained model to new data and returns probabilities or labels.
y_predExpected text output or note
array([9, 2, 1, ..., 8, 1, 5])Listing 34. Convert predicted class indexes to readable class names
Prediction applies the trained model to new data and returns probabilities or labels.
np.array(class_names)[y_pred]Expected text output or note
array(['Ankle boot', 'Pullover', 'Trouser', ..., 'Bag', 'Trouser',
'Sandal'], dtype='<U11')Listing 35. Display the first five test predictions
Prediction applies the trained model to new data and returns probabilities or labels.
for i in range(0,5):
plt.subplot(151+i)
plt.imshow(X_test[i], cmap='gray')
plt.title(class_names[y_pred[i]]) # predicted class
plt.show()Expected text output or note
<Figure size 640x480 with 5 Axes>
[visual output omitted; run the code to display the image or chart]Listing 36. Print precision, recall, and F1-score for each fashion class
This step supports the workflow shown in the surrounding listings.
from sklearn.metrics import classification_report
print(classification_report(y_test,y_pred, target_names=class_names))Expected text output or note
precision recall f1-score support
T-shirt/top 0.76 0.90 0.82 1000
Trouser 0.92 0.98 0.95 1000
Pullover 0.81 0.70 0.75 1000
Dress 0.92 0.79 0.85 1000
Coat 0.62 0.93 0.74 1000
Sandal 0.98 0.91 0.94 1000
Shirt 0.87 0.41 0.55 1000
Sneaker 0.98 0.76 0.86 1000
Bag 0.91 0.98 0.94 1000
Ankle boot 0.79 1.00 0.88 1000
accuracy 0.84 10000
macro avg 0.85 0.84 0.83 10000
weighted avg 0.85 0.84 0.83 10000Listing 37. Build and display the confusion matrix
This evaluation step compares predicted classes with the true labels.
from sklearn import metrics
confusion_matrix_values = metrics.confusion_matrix(y_test, y_pred)
cm_display = metrics.ConfusionMatrixDisplay(confusion_matrix = confusion_matrix_values, display_labels = class_names)
fig, ax = plt.subplots(figsize=(10,10))
cm_display.plot(ax=ax)
plt.show()Expected text output or note
<Figure size 1000x1000 with 2 Axes>
[visual output omitted; run the code to display the image or chart]