Convolutional Neural Networks (CNNs)
Convolutional Neural Networks (CNNs)
Dense (fully-connected) layers treat every pixel independently. A CNN respects the spatial structure of images; nearby pixels are usually related, and the same pattern (like an edge or a curve) can appear anywhere in the image. CNNs exploit both of these facts to learn far more efficiently than Dense networks for image tasks.
What is a CNN?
A Convolutional Neural Network is a type of neural network designed specifically for grid-structured data like images, audio spectrograms, and video frames. The key innovation is the convolutional layer, which applies a small filter (kernel) across the input, scanning from left to right and top to bottom, learning to detect local features regardless of where they appear.
CNNs are the backbone of modern computer vision. They power face recognition, medical image analysis, self-driving car perception systems, and content moderation filters.
How CNNs Work
- Feature extraction: stacked convolutional and pooling layers learn increasingly abstract features, edges → textures → shapes → object parts → whole objects.
- Flattening: the 3-D feature maps produced by the convolutional layers are converted into a 1-D vector.
- Classification: one or more Dense layers use those features to produce class probabilities.
Convolution and Feature Extraction
A convolutional layer applies N learnable filters to the input. Each filter is a small matrix (e.g., 3x3) that slides across the image. At each position, it computes the dot product between the filter values and the corresponding image patch, producing one value in the output feature map. Filters with 32, 64, or 128 channels are common.
import tensorflow as tf
# A single Conv2D layer
# 32 filters, each 3x3, applied to a 28x28x1 (grayscale) image
conv = tf.keras.layers.Conv2D(
filters=32,
kernel_size=(3, 3),
activation='relu',
padding='same', # 'same' keeps spatial dimensions; 'valid' shrinks them
input_shape=(28, 28, 1)
)
# Output shape: (28, 28, 32) — 32 feature maps, same spatial size
Pooling Layers
Pooling layers reduce the spatial dimensions of feature maps, cutting computation and making features more position-invariant. MaxPooling2D is the most common; it takes the maximum value in each pooling window:
# MaxPooling2D with a 2x2 window halves spatial dimensions
pool = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))
# Input: (28, 28, 32) → Output: (14, 14, 32)
# Average pooling (less common but used in some architectures)
avg_pool = tf.keras.layers.AveragePooling2D(pool_size=(2, 2))
Dropout Layers
During training, Dropout randomly zeros out a fraction of neurons. This prevents co-adaptation neurons from relying on each other, forcing the network to learn more robust, distributed representations. At inference time, Dropout is automatically disabled, and all neurons are active (but outputs are scaled to compensate):
# 25% dropout after pooling; 50% dropout before the output layer
dropout_light = tf.keras.layers.Dropout(0.25)
dropout_heavy = tf.keras.layers.Dropout(0.5)
Building a CNN for Image Classification
Here is a complete CNN for CIFAR-10 (60,000 colour images across 10 classes, every 32x32 pixels). This architecture follows the classic Conv → Pool → Conv → Pool → Flatten → Dense pattern:
import tensorflow as tf
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255.0
x_test = x_test.astype('float32') / 255.0
model = tf.keras.Sequential([
# Block 1: detect low-level features (edges, colours)
tf.keras.layers.Conv2D(32, (3,3), activation='relu',
padding='same', input_shape=(32,32,3)),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Dropout(0.25),
# Block 2: detect higher-level features (shapes, textures)
tf.keras.layers.Conv2D(64, (3,3), activation='relu', padding='same'),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D((2,2)),
tf.keras.layers.Dropout(0.25),
# Classification head
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(10, activation='softmax'),
])
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=20, batch_size=64,
validation_split=0.1, verbose=1)
Evaluating CNN Models
Beyond simple accuracy, it is important to understand where a CNN makes mistakes. A confusion matrix reveals which classes are being confused with each other, pointing you toward data or architecture improvements:
import numpy as np
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(f'Test accuracy: {test_acc:.4f}') # typically ~75-80% for this CNN
# Confusion matrix to understand per-class performance
y_pred = model.predict(x_test).argmax(axis=1)
y_true = y_test.flatten()
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog ' ,'horse',' ship', 'truck']
# Per-class accuracy
for i, name in enumerate(class_names):
mask = y_true ;== i
; class_acc = (y_pred[mask] == y_true[mask]).mean()
print(f'{name:12s}: {class_acc:.2%}')
Architecture Tip
CNNs for CIFAR-10 typically achieve 75–85% with a basic architecture. Add Batch Normalization after each Conv2D layer and use data augmentation (random flips, rotations) to push toward 88–92% without changing the overall structure.










