0Pricing
R Academy · Lesson

Convolutional Neural Networks Basics

Add Conv2D and MaxPooling layers for image classification tasks.

Convolutional Neural Networks Basics is a free R Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why CNNs for Images?

A dense network treats pixels independently, losing spatial relationships. A convolutional neural network (CNN) applies learnable filters that slide across the input, detecting local patterns like edges, textures, and shapes regardless of position. This translation invariance and parameter sharing make CNNs the gold standard for image data.

library(keras)

# Images are 3D tensors: (height, width, channels)
# MNIST: (28, 28, 1) — grayscale
# CIFAR-10: (32, 32, 3) — RGB

# Reshape flat vectors into image tensors
mnist <- dataset_mnist()
x_train <- array_reshape(mnist$train$x / 255, c(-1, 28, 28, 1))
y_train <- to_categorical(mnist$train$y, 10)

cat('Input shape:', dim(x_train))

layer_conv_2d() — The Core Layer

layer_conv_2d(filters, kernel_size, activation) applies filters learnable 2D kernels of size kernel_size to the input. Each filter learns to detect one type of spatial pattern. The output has shape (height, width, filters).

library(keras)

# First conv layer: 32 filters of 3x3
model <- keras_model_sequential(input_shape = c(28, 28, 1)) |>
  layer_conv_2d(
    filters     = 32,
    kernel_size = c(3, 3),
    activation  = 'relu',
    padding     = 'same'  # keep spatial dimensions
  )

summary(model)  # output: (None, 28, 28, 32)

layer_max_pooling_2d()

layer_max_pooling_2d(pool_size) reduces spatial dimensions by taking the maximum value in each pooling window. This achieves two things: it reduces the number of parameters in subsequent layers, and it introduces a degree of translation invariance (small shifts don't change the output drastically).

model <- keras_model_sequential(input_shape = c(28, 28, 1)) |>
  layer_conv_2d(32, kernel_size = c(3, 3), activation = 'relu') |>
  layer_max_pooling_2d(pool_size = c(2, 2))

summary(model)
# After pooling: (None, 13, 13, 32)
# Spatial dims halved, channel count preserved

Stacking Conv Layers

Deeper CNNs stack multiple Conv+Pool blocks. Early layers detect low-level features (edges, gradients); deeper layers combine these into high-level features (shapes, objects). Each Conv layer increases the number of filters to compensate for shrinking spatial dimensions.

model <- keras_model_sequential(input_shape = c(32, 32, 3)) |>
  layer_conv_2d(32, c(3, 3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2, 2)) |>   # 16x16
  layer_conv_2d(64, c(3, 3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2, 2)) |>   # 8x8
  layer_conv_2d(128, c(3, 3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2, 2))      # 4x4

summary(model)

layer_flatten()

layer_flatten() converts the 3D output of the last conv block (height, width, filters) into a 1D vector. This is the bridge between the feature-extraction backbone (convolutional layers) and the classification head (dense layers).

model <- keras_model_sequential(input_shape = c(28, 28, 1)) |>
  layer_conv_2d(32, c(3, 3), activation = 'relu') |>
  layer_max_pooling_2d(c(2, 2)) |>
  layer_conv_2d(64, c(3, 3), activation = 'relu') |>
  layer_max_pooling_2d(c(2, 2)) |>
  layer_flatten() |>     # 3D -> 1D vector
  layer_dense(128, activation = 'relu') |>
  layer_dense(10, activation = 'softmax')

summary(model)

layer_dropout() in CNNs

In CNNs, dropout is typically applied after the flatten layer and the dense layers, not inside the convolutional blocks (where spatial dropout layer_spatial_dropout_2d() is preferred). A rate of 0.25-0.5 after the first dense layer is common.

model <- keras_model_sequential(input_shape = c(28, 28, 1)) |>
  layer_conv_2d(32, c(3, 3), activation = 'relu') |>
  layer_max_pooling_2d(c(2, 2)) |>
  layer_conv_2d(64, c(3, 3), activation = 'relu') |>
  layer_max_pooling_2d(c(2, 2)) |>
  layer_flatten() |>
  layer_dense(128, activation = 'relu') |>
  layer_dropout(rate = 0.5) |>    # regularise the classifier head
  layer_dense(10, activation = 'softmax')

summary(model)

Compiling and Training a CNN

Compile and train a CNN just like a dense network. For multi-class classification with one-hot labels, use 'categorical_crossentropy'; for integer labels, use 'sparse_categorical_crossentropy'. CNNs often benefit from a slightly lower learning rate than dense networks.

model |> compile(
  optimizer = optimizer_adam(learning_rate = 0.0005),
  loss      = 'categorical_crossentropy',
  metrics   = c('accuracy')
)

history <- model |> fit(
  x = x_train,
  y = y_train,
  epochs     = 10,
  batch_size = 64,
  validation_split = 0.1,
  verbose = 1
)

plot(history)

Data Augmentation

Training CNNs on small datasets often leads to overfitting. Data augmentation artificially expands the training set by applying random transformations (flips, rotations, zooms) at training time. In keras3, use layer_random_flip(), layer_random_rotation() as preprocessing layers inside the model.

model <- keras_model_sequential(input_shape = c(32, 32, 3)) |>
  # Data augmentation layers (only active during training)
  layer_random_flip('horizontal') |>
  layer_random_rotation(factor = 0.1) |>
  layer_random_zoom(height_factor = 0.1) |>
  # CNN backbone
  layer_conv_2d(32, c(3, 3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2, 2)) |>
  layer_flatten() |>
  layer_dense(10, activation = 'softmax')

summary(model)

Evaluating the CNN

evaluate(model, x_test, y_test) returns the test loss and accuracy. For deeper analysis, use predict() to get class probabilities, then build a confusion matrix or compute per-class F1 scores to understand where the model struggles.

# Evaluate on test set
test_scores <- model |> evaluate(x_test, y_test, verbose = 0)
cat('Test accuracy:', test_scores['accuracy'])

# Get predicted classes
prob_matrix <- model |> predict(x_test)
pred_classes <- max.col(prob_matrix) - 1  # 0-indexed
true_classes <- mnist$test$y

# Confusion matrix
table(Predicted = pred_classes, True = true_classes)

Transfer Learning Concept

Training a CNN from scratch requires large datasets. Transfer learning reuses feature extraction layers pretrained on ImageNet (e.g. VGG, ResNet, MobileNet) and only trains a custom classification head. In keras, load a pretrained base with application_mobilenet_v2() and freeze its layers.

# Load MobileNetV2 pretrained on ImageNet
base_model <- application_mobilenet_v2(
  weights      = 'imagenet',
  include_top  = FALSE,          # remove original classifier head
  input_shape  = c(224, 224, 3)
)

# Freeze pretrained weights
base_model$trainable <- FALSE

# Add custom classifier head
model <- keras_model(
  inputs  = base_model$input,
  outputs = base_model$output |>
    layer_global_average_pooling_2d() |>
    layer_dense(128, activation = 'relu') |>
    layer_dense(5, activation = 'softmax')
)

Conv2D Padding and Strides

Two important layer_conv_2d arguments: padding = 'same' adds zeros around the input so the output has the same spatial size as the input; padding = 'valid' (default) reduces dimensions by kernel_size - 1. strides = c(2,2) replaces max pooling by sliding the filter in steps of 2.

# 'same' padding: output = input size
conv_same <- layer_conv_2d(filters = 32, kernel_size = c(3, 3),
                           padding = 'same')

# Strided convolution instead of pooling
conv_strided <- layer_conv_2d(filters = 64, kernel_size = c(3, 3),
                              strides = c(2, 2),  # halves spatial dims
                              padding = 'same')

# Model using strides instead of max pooling
model2 <- keras_model_sequential(input_shape = c(28, 28, 1)) |>
  layer_conv_2d(32, c(3,3), strides = c(2,2), activation = 'relu',
                padding = 'same') |>
  layer_conv_2d(64, c(3,3), strides = c(2,2), activation = 'relu',
                padding = 'same') |>
  layer_flatten() |>
  layer_dense(10, activation = 'softmax')
summary(model2)

Quick Check

What is the primary purpose of layer_max_pooling_2d(pool_size = c(2, 2)) in a CNN?

CNNs Recap

Key takeaways from Convolutional Neural Networks Basics:

  • CNNs use local receptive fields and parameter sharing for efficient image processing.
  • layer_conv_2d(filters, kernel_size, activation) extracts spatial features.
  • layer_max_pooling_2d(pool_size) downsamples and provides translation invariance.
  • layer_flatten() bridges the conv backbone to the dense classifier head.
  • layer_dropout(rate) regularises the classification head.
  • Data augmentation layers (layer_random_flip(), etc.) reduce overfitting.
  • Transfer learning with pretrained backbones is the practical approach for small datasets.
# Standard CNN architecture for image classification
model <- keras_model_sequential(input_shape = c(32, 32, 3)) |>
  layer_conv_2d(32,  c(3,3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2,2)) |>
  layer_conv_2d(64,  c(3,3), activation = 'relu', padding = 'same') |>
  layer_max_pooling_2d(c(2,2)) |>
  layer_conv_2d(128, c(3,3), activation = 'relu', padding = 'same') |>
  layer_flatten() |>
  layer_dense(256, activation = 'relu') |>
  layer_dropout(0.5) |>
  layer_dense(num_classes, activation = 'softmax')

model |> compile('adam', 'categorical_crossentropy', 'accuracy')
summary(model)

Frequently asked questions

Is the “Convolutional Neural Networks Basics” lesson free?

Yes — the full text of “Convolutional Neural Networks Basics” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

What will I learn in “Convolutional Neural Networks Basics”?

Add Conv2D and MaxPooling layers for image classification tasks. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start R Academy?

No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Convolutional Neural Networks Basics” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this R Academy lesson?

Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Setting Up Keras and TensorFlow in R
  2. Building Sequential Models
  3. Convolutional Neural Networks Basics
  4. Training, Validation, and Preventing Overfitting
← Back to R Academy