Example 27
intermediate
27
CNN
Convolution
Pooling
Neural Networks

CNN Layers

Convolutional neural networks (CNNs) process grid-structured data like images and time series. This example demonstrates Conv1d, Conv2d, MaxPool2d, AvgPool2d layers and how to build a small CNN pipeline with Sequential.

Deepbox Modules Used

deepbox/ndarraydeepbox/nn

What You Will Learn

  • Conv1d for sequences (NLP, time series), Conv2d for images
  • Kernel size controls the receptive field; padding preserves spatial size
  • MaxPool2d reduces spatial dimensions — keeps strongest activations
  • Stack Conv → ReLU → Pool layers to build feature hierarchies
  • Output spatial size = (input + 2*padding - kernel) / stride + 1

Source Code

27-cnn-layers/index.ts
1import { GradTensor, tensor } from "deepbox/ndarray";2import { AvgPool2d, Conv1d, Conv2d, MaxPool2d, ReLU, Sequential } from "deepbox/nn";34console.log("=== Convolutional Neural Network Layers ===\n");56// ---------------------------------------------------------------------------7// Part 1: Conv1d — 1D Convolution for sequence/signal data8// ---------------------------------------------------------------------------9console.log("--- Part 1: Conv1d ---");1011// Conv1d expects input shape: (batch, in_channels, length)12const conv1d = new Conv1d(1, 4, 3, { padding: 1 });13console.log("Conv1d(in=1, out=4, kernel=3, padding=1)");1415const signal = tensor([[[1, 2, 3, 4, 5, 6, 7, 8]]]);16console.log(`Input shape:  [${signal.shape.join(", ")}]`);1718const conv1dOut = conv1d.forward(signal);19const conv1dTensor = conv1dOut instanceof GradTensor ? conv1dOut.tensor : conv1dOut;20console.log(`Output shape: [${conv1dTensor.shape.join(", ")}]`);21console.log("  4 output channels from 1 input channel\n");2223// ---------------------------------------------------------------------------24// Part 2: Conv2d — 2D Convolution for image data25// ---------------------------------------------------------------------------26console.log("--- Part 2: Conv2d ---");2728// Conv2d expects input shape: (batch, in_channels, height, width)29// Note: Conv2d works with plain Tensor forward (inference mode)30const conv2d = new Conv2d(1, 4, 2, { bias: false });31console.log("Conv2d(in=1, out=4, kernel=2x2, bias=false)");32console.log("  Conv2d uses im2col internally for efficient convolution");3334const conv2dParams = Array.from(conv2d.parameters()).length;35console.log(`  Parameters: ${conv2dParams} (weight only, no bias)\n`);3637// ---------------------------------------------------------------------------38// Part 3: MaxPool2d — Downsampling with max pooling39// ---------------------------------------------------------------------------40console.log("--- Part 3: MaxPool2d ---");4142const poolInput = tensor([43  [44    [45      [1, 2],46      [3, 4],47    ],48  ],49]);50const maxPool = new MaxPool2d(2, { stride: 2 });51console.log("MaxPool2d(kernel=2, stride=2)");52console.log(`Input shape:  [${poolInput.shape.join(", ")}]`);5354const pooled = maxPool.forward(poolInput);55const pooledTensor = pooled instanceof GradTensor ? pooled.tensor : pooled;56console.log(`Output shape: [${pooledTensor.shape.join(", ")}]`);57console.log("  Spatial dimensions halved via max pooling\n");5859// ---------------------------------------------------------------------------60// Part 4: AvgPool2d — Downsampling with average pooling61// ---------------------------------------------------------------------------62console.log("--- Part 4: AvgPool2d ---");6364const avgPool = new AvgPool2d(2, { stride: 2 });65console.log("AvgPool2d(kernel=2, stride=2)");6667const avgPooled = avgPool.forward(poolInput);68const avgTensor = avgPooled instanceof GradTensor ? avgPooled.tensor : avgPooled;69console.log(`Output shape: [${avgTensor.shape.join(", ")}]`);70console.log("  Average pooling preserves smoother spatial information\n");7172// ---------------------------------------------------------------------------73// Part 5: Building a simple CNN pipeline with Sequential (Conv1d)74// ---------------------------------------------------------------------------75console.log("--- Part 5: Sequential Conv1d Pipeline ---");7677const cnn = new Sequential(78  new Conv1d(1, 4, 3, { padding: 1 }),79  new ReLU(),80  new Conv1d(4, 8, 3, { padding: 1 }),81  new ReLU()82);8384console.log("Sequential 1D CNN:");85console.log("  Conv1d(1->4, k=3) -> ReLU -> Conv1d(4->8, k=3) -> ReLU");8687const cnnInput = tensor([[[1, 2, 3, 4, 5, 6]]]);88const cnnOutput = cnn.forward(cnnInput);89const cnnTensor = cnnOutput instanceof GradTensor ? cnnOutput.tensor : cnnOutput;90console.log(`Input shape:  [${cnnInput.shape.join(", ")}]`);91console.log(`Output shape: [${cnnTensor.shape.join(", ")}]`);9293const paramCount = Array.from(cnn.parameters()).length;94console.log(`Total parameters: ${paramCount}`);9596console.log("\n=== CNN Layers Complete ===");

Console Output

$ npx tsx 27-cnn-layers/index.ts
=== Convolutional Neural Network Layers ===

--- Part 1: Conv1d ---
Conv1d(in=1, out=4, kernel=3, padding=1)
Input shape:  [1, 1, 8]
Output shape: [1, 4, 8]
  4 output channels from 1 input channel

--- Part 2: Conv2d ---
Conv2d(in=1, out=4, kernel=2x2, bias=false)
  Conv2d uses im2col internally for efficient convolution
  Parameters: 1 (weight only, no bias)

--- Part 3: MaxPool2d ---
MaxPool2d(kernel=2, stride=2)
Input shape:  [1, 1, 2, 2]
Output shape: [1, 1, 1, 1]
  Spatial dimensions halved via max pooling

--- Part 4: AvgPool2d ---
AvgPool2d(kernel=2, stride=2)
Output shape: [1, 1, 1, 1]
  Average pooling preserves smoother spatial information

--- Part 5: Sequential Conv1d Pipeline ---
Sequential 1D CNN:
  Conv1d(1->4, k=3) -> ReLU -> Conv1d(4->8, k=3) -> ReLU
Input shape:  [1, 1, 6]
Output shape: [1, 8, 6]
Total parameters: 4

=== CNN Layers Complete ===