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/nnWhat 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 ===