Machine Learning · Level 102
Machine Learning 102 — Building a Neural Network
Build a neuron from scratch, then train a real neural network on thousands of images with Keras.
Machine Learning · Level 102
Machine Learning 102 — Building a Neural Network
Build a neuron from scratch, then train a real neural network on thousands of images with Keras.
Machine Learning 102 — Building a Neural Network
Prerequisite: Machine Learning 101.
This course assumes you can already load a dataset, split it into training and test sets, and evaluate a classifier honestly. We won't reteach those. Instead, you will build the simplest possible neural network by hand, then use a real library to train one on thousands of images.
You are still at Solstice AI, working with Priya Shah, your lead ML engineer. Logistic regression and decision trees have taken the team a long way — but Solstice AI's newest client, a retailer, needs something those simple models can't quite deliver: recognising what's actually in a photo.
Over five modules you will do real junior-ML-engineer work:
- Understand what a neural network is, and why one is needed here.
- Build a single artificial neuron from scratch and watch it learn.
- Train a real neural network on thousands of clothing images using Keras.
- Evaluate it properly, and improve it.
- Reuse your skills for a second client, on a new image dataset.
The mindset to keep throughout:
neuron → layer → network → training → evaluation
This module is deliberately hands-on. You will type more code than in Machine Learning 101, and by the end you will have a real, trained neural network saved on your own computer.
Before you start — create your project folder
Create a folder called ml102 inside your coding folder.
Inside ml102, create:
Open VS Code. Choose File → Open Folder and open ml102.
You will save notebooks in notebooks/, charts in outputs/charts/, trained
models in outputs/models/, and short written answers in report/.
Tools
- VS Code
- Jupyter Notebook
- Python
- numpy
- matplotlib
- TensorFlow (which includes Keras)
If you need a package you have not installed yet:
pip install numpy matplotlib tensorflow jupyter ipykernelNote: TensorFlow is a larger install than the packages you've used so far and can take a few minutes. If installation fails on your machine, ask your teacher or a parent to help — it is usually a Python version issue, not something you did wrong.
Module 1 — From Models to Networks
Manager email
From: Priya Shah
Subject: Our new client needs to recognise photos, not spreadsheetsOur new retail client has a problem: sellers upload thousands of product photos a day, and someone still has to manually tag each one with a category — "shirt", "trouser", "shoe", and so on.
A logistic regression model treats every input as a flat list of numbers. That's fine for cell measurements. It's a poor fit for images, where the pattern that matters (a sleeve, a collar, a heel) can appear anywhere in the picture.
Before we touch any images, I want you to understand what a neural network actually is, and why it can learn patterns a simpler model can't.
— Priya
Why this matters
Solstice AI doesn't reach for a neural network because it sounds impressive. Neural networks earn their place when:
- the input is large and unstructured (images, audio, raw text);
- the "rule" that separates classes is too complex to describe with a handful of straight-line boundaries;
- there is enough data to actually train something more flexible.
Cell measurements in Machine Learning 101 didn't need this. Thousands of product photos do.
What you'll learn
- What a neural network is, in plain English
- What a single artificial neuron computes
- What a "layer" and "activation function" are, and why they're needed
- How training works, conceptually: adjust the weights to reduce error
From logistic regression to a neuron
Look back at Machine Learning 101's logistic regression. For each sample, it computed something very close to:
then squashed z into a probability between 0 and 1. That squashing
function, and the weighted sum before it, is already one artificial
neuron.
A neural network is what you get when you:
- connect many neurons together in layers;
- feed the output of one layer as the input to the next;
- let each neuron learn its own weights during training.
Layers, in plain English
| Layer | Job |
|---|---|
| Input layer | Holds the raw data (e.g. one number per pixel) |
| Hidden layer(s) | Combine and re-combine features into new, more useful ones |
| Output layer | Produces the final prediction (e.g. one number per class) |
The word "deep" in "deep learning" simply refers to having several hidden layers stacked between input and output.
Why an activation function?
If you stacked layers of plain weighted sums with nothing else, the whole network would collapse mathematically into a single weighted sum — no more powerful than logistic regression, no matter how many layers you added.
An activation function — a small non-linear twist applied after each neuron's weighted sum — is what lets stacking layers actually add power. You will meet two:
- ReLU (
max(0, z)) — commonly used in hidden layers; - Softmax — turns a layer's outputs into probabilities that sum to 1, used in the output layer for multi-class problems like clothing categories.
How does a network learn?
Training a neural network means repeatedly:
- Make a prediction (forward pass).
- Measure how wrong it was (the loss).
- Work out which direction to nudge each weight to reduce that error (gradient descent — using calculus you'll meet properly in A-Level).
- Nudge every weight slightly in that direction.
- Repeat, often thousands of times, over many passes through the data (epochs).
You will do this by hand, on a tiny example, in Module 2 — before letting a library do it for you at scale in Module 3.
Your task
Create report/module1_network_concepts.md and answer, in your own words
(roughly 300 words):
- What is one thing a neural network can learn that logistic regression struggles with?
- What does an activation function do, and why can't you skip it?
- In plain English, what does "training" a neural network mean?
Reflection questions
- Did the idea of "layers of neurons" feel intuitive, or confusing?
- Does the phrase "adjust the weights to reduce error" sound like something you'd enjoy debugging?
- Are you more curious about the maths behind this, or about what you can build with it?
Manager feedback
From: Priya Shah
Good. One warning for your first week with neural networks: it is very easy to reach for one before checking whether a simpler model would do. Our healthtech client's cell-measurement problem in Machine Learning 101 did not need a neural network — the data was small and structured, and logistic regression worked fine.
This retail client's raw images genuinely benefit from one. Always ask "why this tool, for this problem?" before you start building.
Tomorrow, you build a neuron by hand.
— Priya
AQA Mathematics links
- Functions and graphs — activation functions as a graph shape
- Differentiation — the rate of change gradient descent moves against
Beyond A-Level
Look up the universal approximation theorem. It's the (surprisingly deep) mathematical reason a network with enough hidden neurons can, in principle, approximate almost any pattern.
Module 2 — A Neuron From Scratch
Manager email
From: Priya Shah
Subject: Build one neuron before you use a library for a thousandBefore you touch Keras, I want you to build a single neuron with nothing but numpy, and train it by hand on a toy problem.
This is deliberately small. If you understand what's happening in these twenty lines of code, everything Keras does later is just this — done automatically, thousands of times, at scale.
— Priya
Why this matters
Every ML engineer eventually treats a deep learning library as a black box for day-to-day work. The engineers who can actually debug a network when it misbehaves are the ones who understand what's inside that box. Today, you build the box.
What you'll learn
- Represent a neuron's weights and bias as numbers
- Compute a forward pass by hand
- Measure error with a simple loss function
- Update weights with gradient descent, one step at a time
- Watch a tiny network learn
Step 1 — Create the notebook
notebooks/module2_neuron_from_scratch.ipynb
Section 1 — A toy problem
Question
Can we make up a problem small enough to see everything happening?
Code
import numpy as np
np.random.seed(0)
# Two features: hours studied, hours slept.
# Label: 1 = passed a test, 0 = did not.
X = np.array([
[1, 4], [2, 5], [3, 6], [4, 5], [5, 8],
[1, 2], [2, 3], [3, 2], [4, 3], [0, 1],
])
y = np.array([1, 1, 1, 1, 1, 0, 0, 0, 0, 0])
X, yWhat the code does
Ten made-up students, each with two features (hours studied, hours slept) and a label (passed or not). Small enough to reason about by hand, large enough to actually train something.
Section 2 — One neuron's forward pass
Question
What does a single neuron compute for one student?
Code
def sigmoid(z):
return 1 / (1 + np.exp(-z))
weights = np.array([0.0, 0.0])
bias = 0.0
def forward(x, weights, bias):
z = np.dot(x, weights) + bias
return sigmoid(z)
forward(X[0], weights, bias)What the code does
np.dot(x, weights) + bias is exactly the weighted sum from Module 1.
sigmoid squashes it into a number between 0 and 1 — the neuron's
predicted probability that this student passed.
With weights and bias both zero, every prediction starts at exactly
0.5 — the neuron knows nothing yet.
Section 3 — Measure the error
Question
How wrong is one prediction?
Code
def loss(prediction, actual):
epsilon = 1e-9
return -(actual * np.log(prediction + epsilon) +
(1 - actual) * np.log(1 - prediction + epsilon))
prediction = forward(X[0], weights, bias)
loss(prediction, y[0])What the code does
This is binary cross-entropy loss: it penalises confident wrong answers
heavily and confident correct answers barely at all. epsilon just avoids
taking the logarithm of zero.
Section 4 — One gradient descent step, by hand
Question
Which direction should we nudge the weights?
Code
def train_step(X, y, weights, bias, learning_rate=0.1):
predictions = sigmoid(np.dot(X, weights) + bias)
errors = predictions - y
weight_gradient = np.dot(X.T, errors) / len(y)
bias_gradient = np.mean(errors)
weights = weights - learning_rate * weight_gradient
bias = bias - learning_rate * bias_gradient
return weights, bias
weights, bias = train_step(X, y, weights, bias)
weights, biasWhat the code does
errors is how far off each prediction was. The gradient tells us which
direction increases the loss — so we move the weights the opposite way,
scaled by a small learning_rate. This one function is, in miniature,
everything Keras does automatically for every weight in a much bigger
network.
Section 5 — Train over many epochs
Question
What happens if we repeat this hundreds of times?
Code
weights = np.array([0.0, 0.0])
bias = 0.0
losses = []
for epoch in range(500):
predictions = sigmoid(np.dot(X, weights) + bias)
epoch_loss = np.mean(loss(predictions, y))
losses.append(epoch_loss)
weights, bias = train_step(X, y, weights, bias, learning_rate=0.5)
weights, bias, losses[0], losses[-1]What the code does
One epoch is one full pass over the training data, updating the weights
each time. Watch losses[0] (before training) against losses[-1] (after
500 epochs) — it should drop substantially.
Section 6 — Plot the loss curve
Question
Did the neuron actually learn, or get stuck?
Code
import matplotlib.pyplot as plt
plt.figure(figsize=(7, 4))
plt.plot(losses)
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.title("Training loss over time (one neuron, by hand)")
plt.savefig("../outputs/charts/module2_loss_curve.png", dpi=150)
plt.show()What the code does
A falling curve that flattens out is the signature of successful training.
If your curve is flat throughout, try a larger learning_rate; if it
bounces around wildly, try a smaller one.
Section 7 — Check the predictions
Question
Did the trained neuron learn the right pattern?
Code
final_predictions = sigmoid(np.dot(X, weights) + bias)
pd_table = np.round(final_predictions, 2)
for actual, predicted in zip(y, pd_table):
print(f"actual={actual} predicted_probability={predicted}")What the code does
Compare each predicted_probability against the actual label. Predictions
above 0.5 should mostly line up with actual=1, and predictions below 0.5
with actual=0.
Section 8 — Write what you understand
Add a markdown cell answering:
- What is
weightsandbiasat the end of training, and what do they mean? - What would happen if
learning_ratewere much larger, like 10? (You may try it.) - This neuron has no hidden layer — it's really just logistic regression written by hand. What would you need to add to make it a true multi-layer neural network?
Reflection questions
- Did seeing gradient descent written out in five lines demystify it, or make it feel harder?
- Would you rather work at this level of detail, or at the level Keras offers?
- Did the loss curve dropping feel satisfying?
Manager feedback
From: Priya Shah
Exactly right — what you built is a single neuron, mathematically identical to logistic regression. The only thing separating this from a "real" neural network is hidden layers and letting a library manage the bookkeeping for thousands of weights instead of two.
That's exactly what we do next.
— Priya
AQA Mathematics links
- Sequences — loss values converging over repeated steps
- Differentiation — gradients as the rate of change of the loss
Beyond A-Level
Look up backpropagation. With one neuron and no hidden layer, computing the gradient was simple. Backpropagation is the (elegant) technique that makes the same idea work through many stacked layers.
Module 3 — Training on Real Images
Manager email
From: Priya Shah
Subject: Time to scale up — 60,000 real imagesYou've built one neuron by hand. Now use Keras to build a real multi-layer network, and train it on a genuine image dataset — clothing photos, which is close to what our retail client actually needs.
I want a working, trained network by the end of today, with a training curve I can look at.
— Priya
Why this matters
This is the moment the course has been building toward: a real neural network, trained on thousands of real examples, using the same kind of library professional ML engineers use every day.
What you'll learn
- Load a real image dataset through Keras (no manual download needed)
- Prepare image data for a neural network (normalising, flattening)
- Build a multi-layer network with the Keras
SequentialAPI - Compile, train and plot the learning curve of a real neural network
Step 1 — Create the notebook
notebooks/module3_training_on_real_images.ipynb
Section 1 — Load Fashion-MNIST
Question
Can we get thousands of labelled clothing images without downloading a file?
Code
from tensorflow import keras
import numpy as np
(X_train, y_train), (X_test, y_test) = keras.datasets.fashion_mnist.load_data()
class_names = [
"T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot",
]
X_train.shape, y_train.shape, X_test.shapeWhat the code does
Fashion-MNIST is a well-known dataset of 70,000 small (28×28 pixel)
greyscale photos of clothing items, each labelled with one of ten
categories. keras.datasets.fashion_mnist.load_data() downloads and caches
it automatically the first time you run it — the same kind of dataset a
real retail client's photos would need to be sorted into.
Section 2 — Look at a few images
Question
What are we actually working with?
Code
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 5, figsize=(10, 4))
for i, ax in enumerate(axes.flat):
ax.imshow(X_train[i], cmap="gray")
ax.set_title(class_names[y_train[i]])
ax.axis("off")
plt.tight_layout()
plt.savefig("../outputs/charts/module3_sample_images.png", dpi=150)
plt.show()What the code does
Each image is a 28×28 grid of pixel brightness values (0–255). Looking at real examples before training is exactly the discipline you practised with tabular data in Machine Learning 101 — it just looks different for images.
Section 3 — Normalise the pixel values
Question
Why can't we feed raw pixel values straight into the network?
Code
X_train_norm = X_train / 255.0
X_test_norm = X_test / 255.0
X_train_norm.min(), X_train_norm.max()What the code does
Raw pixels range from 0 to 255. Neural networks train more reliably when inputs are on a small, consistent scale — dividing by 255 rescales everything to between 0 and 1. This is the image equivalent of the feature scale problem you noticed in Machine Learning 101.
Section 4 — Build the network
Question
What does a multi-layer network for this problem look like?
Code
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation="relu"),
keras.layers.Dense(10, activation="softmax"),
])
model.summary()What the code does
Flattenturns each 28×28 image into a single list of 784 numbers — the input layer.Dense(128, activation="relu")is a hidden layer of 128 neurons, each connected to every input, using the ReLU activation from Module 1.Dense(10, activation="softmax")is the output layer: ten neurons, one per clothing category, producing probabilities that sum to 1.
model.summary() prints every layer and how many weights ("parameters")
each one has — likely well over 100,000 in total. Keras is now managing all
of them, the same way you manually managed two weights in Module 2.
Section 5 — Compile the model
Question
How does the model know what "wrong" means, and how to improve?
Code
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)What the code does
loss="sparse_categorical_crossentropy"is the multi-class version of the loss function you wrote by hand in Module 2.optimizer="adam"is a more advanced version of the gradient descent you coded manually — it adapts the learning rate automatically as training progresses.metrics=["accuracy"]tells Keras to also track accuracy while training, purely for you to read.
Section 6 — Train the network
Question
Can we actually train it?
Code
history = model.fit(
X_train_norm, y_train,
epochs=10,
validation_split=0.1,
)What the code does
fit() runs the same forward-pass-then-gradient-descent loop from Module
2, automatically, across every one of the 60,000 training images, ten
times over (epochs=10). validation_split=0.1 holds back 10% of the
training data during training only, so you can watch performance on unseen
data as you go — not a substitute for the separate test set.
This may take a minute or two — you have just trained a real neural network.
Section 7 — Plot the training curve
Question
Did the network actually learn?
Code
plt.figure(figsize=(8, 5))
plt.plot(history.history["accuracy"], label="Training accuracy")
plt.plot(history.history["val_accuracy"], label="Validation accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.title("Fashion-MNIST training curve")
plt.legend()
plt.savefig("../outputs/charts/module3_training_curve.png", dpi=150)
plt.show()What the code does
Both lines should climb over the ten epochs. This is the large-scale version of the loss curve you plotted by hand in Module 2 — the same idea, running automatically across 100,000+ weights instead of two.
Section 8 — Save your model
Question
Can we keep this trained network to use later?
Code
model.save("../outputs/models/fashion_mnist_model.keras")What the code does
This saves every learned weight to disk. You now have a genuinely trained, reusable neural network file — not just a notebook cell that runs once.
Reflection questions
- Did watching training happen in real time feel different from the static Module 2 loss curve?
- Was
model.summary()'s parameter count surprising? - Do you find it satisfying or slightly unsettling that Keras hides so much detail compared to Module 2?
Manager feedback
From: Priya Shah
You have a trained neural network. Notice how little of today's code concerned the maths — that's the point of a library like Keras. But you could only trust it because Module 2 showed you what it's doing underneath.
Tomorrow: is this network actually good, and can we make it better?
— Priya
AQA Mathematics links
- Proportion and percentages — accuracy over tens of thousands of images
- Graphs — reading a learning curve's shape
Beyond A-Level
Look up convolutional neural networks (CNNs). The network you built treats every pixel independently once flattened; CNNs are specifically designed to notice patterns like edges and shapes in images, and are the real backbone of production image classifiers.
Module 4 — Evaluating and Improving the Network
Manager email
From: Priya Shah
Subject: Before this goes anywhere near a clientA high training accuracy doesn't tell me whether this network is ready. Evaluate it properly on the held-out test set, look at what it actually gets wrong, and tell me whether the number of epochs or hidden units changes anything.
Remember Machine Learning 101, Module 4. The same discipline applies here — it's just a bigger model.
— Priya
Why this matters
A trained network is not a finished product. Every ML engineer's job includes checking honestly whether a model is ready, and where it still fails — exactly the generalisation habit you built in Machine Learning 101.
What you'll learn
- Evaluate a Keras model on a genuine test set
- Build a confusion matrix for a 10-class image problem
- Look at specific misclassified images
- See overfitting in a neural network, and what changes affect it
Step 1 — Create the notebook
notebooks/module4_evaluating_and_improving.ipynb
Reload your saved model if you're starting a new session:
from tensorflow import keras
model = keras.models.load_model("../outputs/models/fashion_mnist_model.keras")Section 1 — Evaluate on the test set
Question
How good is the network on data it never trained on?
Code
from tensorflow import keras
import numpy as np
(_, _), (X_test, y_test) = keras.datasets.fashion_mnist.load_data()
X_test_norm = X_test / 255.0
test_loss, test_accuracy = model.evaluate(X_test_norm, y_test)
test_accuracyWhat the code does
evaluate() runs the trained network on the test set — 10,000 images
it has never seen in any form, not even during validation_split. This is
the number Priya actually cares about.
Section 2 — Confusion matrix for ten classes
Question
Which clothing categories does the network confuse?
Code
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
predictions = model.predict(X_test_norm)
predicted_labels = np.argmax(predictions, axis=1)
class_names = [
"T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot",
]
cm = confusion_matrix(y_test, predicted_labels)
fig, ax = plt.subplots(figsize=(9, 8))
ConfusionMatrixDisplay(cm, display_labels=class_names).plot(
ax=ax, xticks_rotation=45, colorbar=False
)
plt.title("Fashion-MNIST: predicted vs actual")
plt.tight_layout()
plt.savefig("../outputs/charts/module4_confusion_matrix.png", dpi=150)
plt.show()What the code does
model.predict() returns ten probabilities per image; np.argmax picks the
most likely category. The confusion matrix — the same tool from Machine
Learning 101 — now has ten rows and columns instead of two. Look for the
brightest off-diagonal cells: which categories get mixed up?
Section 3 — Look at misclassified images
Question
What do the network's mistakes actually look like?
Code
wrong = np.where(predicted_labels != y_test)[0]
fig, axes = plt.subplots(2, 5, figsize=(11, 5))
for i, ax in zip(wrong[:10], axes.flat):
ax.imshow(X_test[i], cmap="gray")
ax.set_title(
f"true: {class_names[y_test[i]]}\npred: {class_names[predicted_labels[i]]}",
fontsize=8,
)
ax.axis("off")
plt.tight_layout()
plt.savefig("../outputs/charts/module4_misclassified.png", dpi=150)
plt.show()What the code does
Looking at actual mistakes, not just a summary number, often reveals something a confusion matrix alone can't — for example, whether the network confuses "shirt" and "pullover" for genuinely visually similar images, or for something less forgivable.
Section 4 — Does more training help, or hurt?
Question
What happens if we train for many more epochs?
Code
from tensorflow import keras
(X_train, y_train), (X_test, y_test) = keras.datasets.fashion_mnist.load_data()
X_train_norm = X_train / 255.0
X_test_norm = X_test / 255.0
long_model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation="relu"),
keras.layers.Dense(10, activation="softmax"),
])
long_model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
long_history = long_model.fit(
X_train_norm, y_train,
epochs=30,
validation_split=0.1,
)What the code does
Training the same architecture for 30 epochs instead of 10 lets you see whether performance keeps improving, or whether — as in Machine Learning 101's decision tree — training accuracy pulls away from validation accuracy. This is overfitting in a neural network, and it looks the same shape as the curve you plotted with a decision tree.
Section 5 — Plot both training curves together
Question
Can we see the gap directly?
Code
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 5))
plt.plot(long_history.history["accuracy"], label="Training accuracy")
plt.plot(long_history.history["val_accuracy"], label="Validation accuracy")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.title("30 epochs: watching for overfitting")
plt.legend()
plt.savefig("../outputs/charts/module4_long_training_curve.png", dpi=150)
plt.show()What the code does
If validation accuracy plateaus or dips while training accuracy keeps rising, that is the same overfitting pattern from Machine Learning 101 — just with epochs standing in for tree depth as the "complexity dial".
Section 6 — Write your findings
Add a markdown cell answering:
- What was your test accuracy in Section 1?
- Name two clothing categories the network confuses most, based on your confusion matrix.
- Did training for 30 epochs help, hurt, or make little difference compared to 10?
- Based on today's curve, roughly how many epochs would you recommend to Priya, and why?
Reflection questions
- Did looking at specific misclassified images change how you felt about the model's accuracy number?
- Was it satisfying to see the same overfitting shape you found with a decision tree, now on a neural network?
- Would you rather spend your time improving the model, or investigating its mistakes?
Manager feedback
From: Priya Shah
This is exactly the evaluation discipline I wanted. Notice that "train for longer" is not automatically "train better" — the same lesson from Machine Learning 101, now on a network with over 100,000 weights instead of a handful of tree splits.
You're ready for a client project of your own.
— Priya
AQA Mathematics links
- Statistics — reading a confusion matrix as a cross-tabulation
- Graphs — comparing two curves and their gap over time
Beyond A-Level
Look up early stopping and dropout. Both are standard techniques for preventing exactly the overfitting pattern you saw in Section 5, without you having to guess the right number of epochs in advance.
Module 5 — Final Project
Manager email
From: Priya Shah
Subject: New client — handwritten reference numbersA logistics client scans handwritten reference numbers off shipping forms and currently types them in by hand. They want to know whether a neural network could read the digits automatically.
Use the same workflow as this week: load the data, build and train a network, evaluate it properly, and write me a short model report.
— Priya
Why this matters
Real ML engineering work is applying a workflow you trust to a new problem, quickly. Today you do that on a new, genuinely useful dataset — with significantly less guidance than the rest of this module.
The dataset
Use Keras's built-in MNIST handwritten digit dataset:
from tensorflow import keras
(X_train, y_train), (X_test, y_test) = keras.datasets.mnist.load_data()This is 70,000 small greyscale images of handwritten digits (0–9) — visually different from clothing, but the same shape and format as Fashion-MNIST, so your Module 3–4 code should adapt with only small changes.
Step 1 — Create the notebook
notebooks/module5_digits_project.ipynb
Your task
Work through the same steps as Modules 3–4, adapting your own code:
- Load and look at the data — a handful of sample images with their labels.
- Normalise the pixel values.
- Build a network — you can reuse your Module 3 architecture, or try a different number of hidden units.
- Compile and train — choose a number of epochs, informed by what you learned about overfitting in Module 4.
- Evaluate on the test set — accuracy, plus a confusion matrix.
- Look at a handful of misclassified digits.
You are not given code for this one. Reuse and adapt what you wrote in Modules 3 and 4.
Save the model
model.save("../outputs/models/digits_model.keras")Write the model report
Create report/module5_digits_model_report.md with this structure:
- Question — restate the client's request in one sentence.
- Method — network architecture, number of epochs, how you checked for overfitting.
- Results — test accuracy, plus one observation from the confusion matrix or misclassified images.
- Limitations — clean, centred, single digits are easier than messy handwriting on a real shipping form; say what else you'd want to test before shipping this to the client.
- Recommendation — is a neural network like this one ready for this client's problem? One paragraph.
Reflection questions
- Did reusing your own code from Modules 3–4 feel efficient, or did the new dataset surprise you in any way?
- Which was harder to get right: the clothing images or the digits? Why might that be?
- After building two trained networks this week, do you want to go deeper into neural networks specifically, or wider into other ML techniques?
Manager feedback
From: Priya Shah
Good work — you took the exact workflow from earlier this week and applied it correctly to a new client problem with minimal hand-holding. That is the actual job.
Real handwriting is messier than this dataset — inconsistent spacing, different pens, crossed-out digits. A production version of this would need much more testing before going anywhere near a client's real forms. Flagging that limitation, as you did, is exactly right.
If you want to go further, Machine Learning 103 is entirely your own project — your dataset, your architecture, your write-up.
— Priya
AQA Mathematics links
- Statistics — evaluation metrics as summaries of many predictions
- Probability — softmax outputs as a probability distribution over ten digits
Beyond A-Level
Look up transfer learning. Rather than training a network from scratch, many real production systems adapt an already-trained network to a new, related problem — often needing far less data than you used today.
Module 6 — What You Have Learned
By the end of Machine Learning 102, you have learned to:
- explain what a neural network is, and why it can learn patterns simpler models can't;
- build and train a single artificial neuron by hand with numpy;
- build, compile and train a real multi-layer neural network with Keras;
- evaluate a trained network properly, and diagnose overfitting;
- apply the whole workflow to a new dataset with far less guidance.
You now have two trained neural networks saved on your own computer — one for clothing photos, one for handwritten digits.
If you enjoyed building something from first principles, then scaling it up with a real library, this is a strong signal for a career in machine learning or ML engineering.
Continue to Machine Learning 103 for a fully self-directed project: your own dataset, your own architecture, no step-by-step script.