Menu

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.