Neural Networks and MNIST¶
By the end of this lesson you'll be able to:
- Explain what makes a Convolutional Neural Network (CNN) different from a dense network
- Understand Conv2D, MaxPooling2D, Flatten, and Dropout layers
- Read and write a complete Keras CNN model
- Use
model.compile(),model.fit(),model.evaluate(), andmodel.predict() - Describe at a high level: RNNs, LSTMs, and autoencoders
Dense networks from Chapter 37 treat an image as a flat vector — losing all spatial information. Convolutional networks keep the 2-D structure of images and look for local patterns like edges, corners, and shapes. This is why CNNs are the dominant architecture for image recognition.
Welcome to Chapter 38!
Welcome to the final chapter of Beginning Python!
You've come from printing "Hello, World!" all the way to building AI that reads handwritten digits.
Let's finish strong! Let's code it together!
Why Convolutions?¶
A dense network that takes a 28×28 image flattens it to 784 numbers — it completely discards the fact that pixel (3, 5) is next to pixel (3, 6).
A convolutional layer slides a small filter (called a kernel) across the image. The kernel detects local patterns — a 3×3 kernel can detect a horizontal edge, a diagonal, or a corner. Multiple kernels at the same layer detect different features simultaneously.
This gives CNNs two huge advantages: - Parameter efficiency — one kernel is shared across the whole image (vs dense where every pixel has its own weight for every neuron) - Translation invariance — a kernel that detects a "7" shape in the top-left also recognizes it in the bottom-right, because the same kernel scans everywhere
Key CNN Layer Types¶
Before reading Keras code, here are the four new layer types in this chapter:
| Layer | Purpose |
|---|---|
Conv2D(filters, kernel_size, activation) |
Slide filters kernels of size kernel_size×kernel_size across the image |
MaxPooling2D(pool_size) |
Shrink the spatial dimensions by taking the max in each region |
Dropout(rate) |
Randomly set rate fraction of neurons to zero during training — fights overfitting |
Flatten() |
Convert 2-D feature maps to a 1-D vector before the dense layers |
A filter (or feature map) is the output of one kernel applied to the full image.
Conv2D(32, (3,3)) creates 32 different 3×3 kernels — producing 32 feature maps.
MaxPooling2D((2,2)) divides the image into 2×2 blocks and keeps only the maximum value in each block — halving the width and height.
What Do You Think Will Happen?
The code below simulates one step of Max Pooling on a tiny 4×4 grid.
If the pool size is 2×2, how many output values do you expect?
Make your guess — then run it!
Dropout — Fighting Overfitting¶
Dropout is a simple but powerful regularization technique.
During each training step, Dropout randomly sets a fraction of neurons' outputs to zero.
With Dropout(0.5), half the neurons are randomly silenced each time — so the network can't rely on any single neuron.
This forces the network to learn redundant representations — multiple ways to detect the same feature. At inference time (prediction), Dropout is automatically disabled and all neurons participate.
1 2 | |
A Complete CNN for MNIST¶
Here is a full CNN that achieves ~99% accuracy on MNIST:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Understanding model.compile()¶
model.compile() sets three key training choices:
- optimizer — how weights are updated (e.g.,
"adam","sgd") - loss — what to minimize during training
"sparse_categorical_crossentropy"— for integer class labels (e.g., 0, 1, 2, …, 9)"categorical_crossentropy"— for one-hot encoded labels"binary_crossentropy"— for two-class (yes/no) problems- metrics — what to track but not optimize (e.g.,
"accuracy")
Training with model.fit()¶
1 2 3 4 5 6 | |
model.fit() returns a history object.
history.history is a dict with keys "accuracy", "val_accuracy", "loss", "val_loss".
You can plot training curves to visualize overfitting:
1 2 3 4 5 6 7 | |
Evaluating with model.evaluate()¶
1 2 | |
Call this once, at the very end, on data the model has never seen.
Making Predictions with model.predict()¶
1 2 3 4 | |
predictions is an array of shape (10, 10) — 10 images, each with 10 class probabilities.
.argmax(axis=1) picks the index of the highest probability for each image.
Feature Extraction¶
A trained CNN isn't just a digit classifier — its intermediate layers have learned meaningful visual features:
- Early Conv2D layers: detect edges and corners
- Middle Conv2D layers: detect curves and simple shapes
- Later layers: detect digit-specific features
Transfer learning exploits this: take a CNN pre-trained on millions of images, cut off the last few layers, and attach new layers trained on your smaller dataset. The pre-trained features transfer to the new task.
This is why a model trained on ImageNet (1.3M photos) can be quickly adapted to classify medical X-rays, satellite images, or art styles — with only hundreds of new labeled examples.
Other Neural Network Architectures¶
Recurrent Neural Networks (RNNs)¶
RNNs process sequences — text, audio, time series — one step at a time. Each step produces a hidden state that is passed to the next step, giving the network memory of the past.
1 | |
RNNs struggle with long sequences because the gradient signal weakens across many time steps (the "vanishing gradient" problem).
Long Short-Term Memory (LSTM)¶
LSTMs are a special type of RNN with gating mechanisms that let them remember or forget information over long sequences. They are the standard choice for language modeling, speech recognition, and time series forecasting.
1 | |
Autoencoders¶
An autoencoder learns to compress data into a small representation (the bottleneck) and then reconstruct the original.
1 | |
Applications: anomaly detection, denoising, generative art, data compression.
Putting It All Together — The CNN Shape Journey¶
The table below traces the data shape through the CNN for a single 28×28 MNIST image:
| Layer | Output Shape | Parameters |
|---|---|---|
| Input | (28, 28, 1) | 0 |
| Conv2D(32, 3×3) | (26, 26, 32) | 320 |
| MaxPooling2D | (13, 13, 32) | 0 |
| Conv2D(64, 3×3) | (11, 11, 64) | 18,496 |
| MaxPooling2D | (5, 5, 64) | 0 |
| Flatten | (1,600,) | 0 |
| Dense(128) | (128,) | 204,928 |
| Dropout(0.5) | (128,) | 0 |
| Dense(10) | (10,) | 1,290 |
Total parameters: 225,034 — much more efficient than a dense-only model of similar depth.
Learning Check¶
Your Turn — Count the Parameters
A Dense(64) layer following a Flatten() layer with 1,600 inputs has 1,600 × 64 weights plus 64 bias values.
Write a function that computes the parameter count for a Dense layer from its input size and neuron count!
Experiments¶
Try these changes. Predict what will happen first, then run it to check!
-
Modify the max pooling simulation to use a 3×3 pool size on a 6×6 grid. What is the output size? You'll know it worked when you see a 2×2 output.
-
In the prediction simulator, change the last row's logits so they favor class 5 more strongly. You'll know it worked when the confidence for class 5 exceeds 70%.
-
Implement
min_pool_2d(same asmax_pool_2dbut usingmininstead ofmax). How do the outputs differ from max pooling on the same input? You'll know it worked when you see that min pooling keeps darker (smaller) values. -
Compute the parameter count for a
Dense(256)layer following aDense(128)layer. You'll know it worked when you get 128 × 256 + 256 = 33,024. -
Research: look up "GPT" or "BERT" and describe in 2-3 sentences how they differ from the CNN described in this chapter. You'll know it worked when you can explain: what kind of data they process and what architecture they use.
You Did It — Python Graduate!
You have completed all 38 chapters of Beginning Python!
You started with a turtle drawing a square and finished by building an AI that reads handwritten digits with 99% accuracy.
You are no longer a beginner — you are a Python programmer. Go build something amazing!