0Pricing
Machine Learning Academy · 강의

합성곱과 필터: 경계와 패턴 감지

학습자는 이미지에 직접 설계한 경계 감지 커널을 적용한 다음, nn.Conv2d가 필터를 자동으로 학습하도록 하고 학습 후 가중치를 확인합니다.

합성곱과 필터: 경계와 패턴 감지은(는) CoddyKit의 무료 Machine Learning Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Machine Learning Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

What Is a Convolution Operation?

Convolution is a mathematical operation that slides a small matrix called a filter (or kernel) across an input (e.g., an image), computing an element-wise dot product at each position. The result is a feature map that highlights where the pattern represented by the filter appears in the input. In image processing, different filters detect different features: edges, corners, textures, or higher-level concepts when stacked in multiple layers.

import torch

# Manual 2D convolution (single filter)
image = torch.tensor([
    [1., 0., 1., 0.],
    [0., 1., 0., 1.],
    [1., 0., 1., 0.],
    [0., 1., 0., 1.]
]).unsqueeze(0).unsqueeze(0)  # shape: (1,1,4,4)

# Vertical edge detector filter
filter_ = torch.tensor([[[-1., 1., -1.],
                          [-1., 1., -1.],
                          [-1., 1., -1.]]]).unsqueeze(0)  # (1,1,3,3)

import torch.nn.functional as F
feature_map = F.conv2d(image, filter_, padding=0)
print(feature_map.shape)   # (1, 1, 2, 2)

Filters and Edge Detection

Classic image processing uses hand-crafted filters: the Sobel filter detects horizontal or vertical edges; the Laplacian filter detects all edges; the Gaussian filter blurs (smooths) images. In deep learning, these filters are learned from data rather than hand-crafted. The key insight of CNNs is that the network automatically discovers which filters are useful for the task by minimising the training loss.

import torch
import torch.nn.functional as F

# Sobel horizontal edge detector
sobel_h = torch.tensor([[
    [-1., -2., -1.],
    [ 0.,  0.,  0.],
    [ 1.,  2.,  1.]
]]).unsqueeze(0)   # shape (1, 1, 3, 3)

# Create a simple gradient image (brightness increases left->right)
image = torch.arange(16.).reshape(1, 1, 4, 4)
feature_map = F.conv2d(image, sobel_h, padding=1)
print('Edge response shape:', feature_map.shape)
print('Edge values:', feature_map.squeeze())

nn.Conv2d: Parameters Explained

nn.Conv2d(in_channels, out_channels, kernel_size) is the core CNN layer. in_channels is the number of input channels (3 for RGB images); out_channels is the number of filters to learn; kernel_size is the spatial size of each filter (3 means 3x3). Each filter produces one output channel, so 64 filters produce a 64-channel feature map. The total parameters in one Conv2d layer is out_channels * in_channels * kernel_h * kernel_w + out_channels (bias).

import torch
import torch.nn as nn

# 3-channel (RGB) input -> 64 feature maps, 3x3 filters
conv = nn.Conv2d(
    in_channels=3,
    out_channels=64,
    kernel_size=3,
    padding=1,     # 'same' padding: output same size as input
    stride=1       # move filter by 1 pixel at a time
)
print('Filter shape:', conv.weight.shape)  # (64, 3, 3, 3)
# 64 filters, each 3x3 applied to 3 channels

params = 64 * 3 * 3 * 3 + 64  # weights + bias
print('Parameters:', params)   # 1792

Padding and Stride

Padding adds zeros around the input border before convolution. padding=1 with a 3x3 filter preserves the spatial dimensions of the input (same padding). Without padding, each convolution reduces width and height by kernel_size - 1. Stride controls how many pixels the filter moves at each step. stride=2 halves the output dimensions, acting like a lightweight pooling operation. Stride-2 convolutions are often used in modern CNNs instead of explicit pooling.

import torch
import torch.nn as nn

# Output size formula: floor((W - K + 2P) / S) + 1
# W=input, K=kernel, P=padding, S=stride

x = torch.randn(1, 3, 32, 32)  # single 32x32 RGB image

conv_same = nn.Conv2d(3, 16, 3, padding=1, stride=1)
print(conv_same(x).shape)  # (1, 16, 32, 32) -- same size

conv_down = nn.Conv2d(3, 16, 3, padding=1, stride=2)
print(conv_down(x).shape)  # (1, 16, 16, 16) -- halved

conv_no_pad = nn.Conv2d(3, 16, 3, padding=0, stride=1)
print(conv_no_pad(x).shape)  # (1, 16, 30, 30) -- reduced

Multiple Channels: Input and Output

A colour image has 3 channels (R, G, B). Each filter in a Conv2d layer has depth equal to in_channels — it operates across all input channels simultaneously, producing a single output value per spatial position. With 64 filters you get 64 output channels. The next convolution layer then takes these 64 channels as input. This channel-stacking allows the network to progressively build more abstract representations from low-level colour edges to high-level object parts.

import torch
import torch.nn as nn

# Layer 1: RGB (3ch) -> 32 feature maps
conv1 = nn.Conv2d(3, 32, 3, padding=1)
# Layer 2: 32 feature maps -> 64 feature maps
conv2 = nn.Conv2d(32, 64, 3, padding=1)

x = torch.randn(4, 3, 28, 28)  # batch of 4 MNIST-like images
out1 = torch.relu(conv1(x))
print('After conv1:', out1.shape)  # (4, 32, 28, 28)
out2 = torch.relu(conv2(out1))
print('After conv2:', out2.shape)  # (4, 64, 28, 28)

Parameter Efficiency: Weight Sharing

A key advantage of convolutions is weight sharing: the same filter is applied at every spatial location. A 3x3 filter over a 256x256 image involves 9 parameters regardless of image size, compared to a fully connected layer that would require millions of parameters. This makes CNNs far more parameter-efficient than MLPs for image data and gives them translation equivariance — a shifted version of a pattern in the input produces a correspondingly shifted feature map.

# Parameter comparison: Conv vs FC for 256x256 images
image_size = 256 * 256

# Convolution: 3x3 filter, 1 input channel, 1 output channel
conv_params = 3 * 3 * 1 + 1   # 10 parameters

# Fully connected: every input pixel connects to every output
fc_params = image_size * image_size  # 4 billion params!

print(f'Conv params:    {conv_params}')
print(f'FC params:      {fc_params:,}')
print(f'Ratio: {fc_params / conv_params:.1e}x fewer parameters for convolution')

What Filters Learn in CNNs

Visualising learned filters reveals a hierarchy of learned features. First layer filters typically detect oriented edges, colour gradients, and textures — similar to hand-crafted Sobel filters. Middle layer filters detect combinations: curves, corners, textures. Deep layer filters respond to object parts (eyes, wheels, feathers). This hierarchical feature learning is why deep CNNs dramatically outperform shallow models on image recognition tasks.

import torch
import torch.nn as nn

# Visualise first-layer filter weight ranges
conv1 = nn.Conv2d(3, 64, 3, padding=1)
print('Filter weights shape:', conv1.weight.shape)
# (64, 3, 3, 3) -- 64 filters, each 3x3 for 3 RGB channels

# One filter: 3-channel 3x3 spatial pattern
filter_0 = conv1.weight[0]   # shape: (3, 3, 3)
print('Filter 0 (R channel):')
print(filter_0[0].detach())  # 3x3 pattern for Red channel
# After training, this would show edge-like patterns

Receptive Field: What Each Neuron Sees

The receptive field of a neuron in a CNN is the region of the original input image that contributes to its activation. A single 3x3 conv layer has a 3x3 receptive field. Two stacked 3x3 layers give a 5x5 receptive field. Three give 7x7. Stacking many small filters is more parameter-efficient than one large filter while achieving the same receptive field. This is why modern CNNs use 3x3 filters almost exclusively — inspired by the VGGNet finding.

# Receptive field grows with depth
# Each 3x3 conv adds 2 to each side of the receptive field

def receptive_field(n_layers, kernel_size=3):
    rf = 1
    for _ in range(n_layers):
        rf += (kernel_size - 1)
    return rf

for n in [1, 2, 3, 5, 10, 20]:
    rf = receptive_field(n)
    print(f'{n} layers of 3x3: receptive field = {rf}x{rf}')
# 1 -> 3, 2 -> 5, 3 -> 7, 5 -> 11, 10 -> 21, 20 -> 41

Building a Simple CNN Block

The standard CNN block follows the pattern: Conv2d -> BatchNorm2d -> ReLU -> (optional Pooling). This trio is repeated multiple times with increasing channel counts, progressively reducing spatial dimensions while increasing the number of feature channels. The spatial reduction compresses location information while the channel expansion captures more abstract features. This pattern is the backbone of ResNet, VGG, EfficientNet, and most other architectures.

import torch
import torch.nn as nn

def conv_block(in_ch, out_ch):
    return nn.Sequential(
        nn.Conv2d(in_ch, out_ch, 3, padding=1),
        nn.BatchNorm2d(out_ch),
        nn.ReLU(inplace=True)
    )

model = nn.Sequential(
    conv_block(3, 32),    # 3 -> 32 channels
    nn.MaxPool2d(2),      # halve spatial size
    conv_block(32, 64),   # 32 -> 64 channels
    nn.MaxPool2d(2),
    conv_block(64, 128),  # 64 -> 128 channels
)

x = torch.randn(4, 3, 32, 32)
print(model(x).shape)   # (4, 128, 8, 8)

Visualising Filter Activations

After training, you can visualise feature maps (filter activations) for a specific input image to see what each filter has detected. Bright regions in a feature map indicate where the corresponding filter pattern was detected. This is useful for debugging (checking that early layers learned edge detectors) and for interpretability (showing which regions of an image activated a 'dog fur' detector or 'wheel' detector in later layers).

import torch
import torch.nn as nn

# Extract feature maps after the first conv layer
conv1 = nn.Conv2d(3, 8, 3, padding=1)
relu = nn.ReLU()

x = torch.randn(1, 3, 16, 16)   # single image
feature_maps = relu(conv1(x))   # shape: (1, 8, 16, 16)

print('Number of feature maps:', feature_maps.shape[1])  # 8
print('Feature map size:', feature_maps.shape[2:])        # 16x16

# Plot with matplotlib:
# import matplotlib.pyplot as plt
# fig, axes = plt.subplots(1, 8)
# for i, ax in enumerate(axes):
#     ax.imshow(feature_maps[0, i].detach(), cmap='gray')

1x1 Convolutions: Channel Mixing

1x1 convolutions apply a linear combination across channels at each spatial position without any spatial mixing. They are used to reduce or expand the number of channels cheaply (as in the Inception and MobileNet bottleneck designs). A 1x1 conv from 256 to 64 channels reduces computation in the subsequent 3x3 conv by 16x. They also introduce non-linearity (via activation) between channel mixing steps, increasing model capacity at minimal parameter cost.

import torch
import torch.nn as nn

# Bottleneck block: expand -> 3x3 conv -> compress
bottleneck = nn.Sequential(
    nn.Conv2d(256, 64, 1),   # 1x1: channel reduction
    nn.ReLU(),
    nn.Conv2d(64, 64, 3, padding=1),  # 3x3: spatial mixing
    nn.ReLU(),
    nn.Conv2d(64, 256, 1),   # 1x1: channel expansion
    nn.ReLU()
)

x = torch.randn(4, 256, 14, 14)
out = bottleneck(x)
print(out.shape)   # (4, 256, 14, 14) -- same shape as input

Quick Check

Test your understanding of Machine Learning with Python concepts from this lesson.

Lesson Recap

In this lesson you learned: convolution slides a filter across the input computing dot products to produce a feature map that highlights where the filter pattern occurs, nn.Conv2d parameters (in_channels, out_channels, kernel_size, padding, stride) control the filter bank, and weight sharing makes convolutions dramatically more parameter-efficient than fully connected layers for spatial data. Next up we explore pooling layers for spatial downsampling and translation invariance.

자주 묻는 질문

“합성곱과 필터: 경계와 패턴 감지” 강의는 무료인가요?

네 — “합성곱과 필터: 경계와 패턴 감지” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Machine Learning Academy 강의 전체를 잠금 해제할 수 있습니다. Machine Learning Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“합성곱과 필터: 경계와 패턴 감지”에서 뭘 배우나요?

학습자는 이미지에 직접 설계한 경계 감지 커널을 적용한 다음, nn.Conv2d가 필터를 자동으로 학습하도록 하고 학습 후 가중치를 확인합니다. 브라우저에서 직접 실행하는 실습 코드로 Machine Learning Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Machine Learning Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Machine Learning Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“합성곱과 필터: 경계와 패턴 감지” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Machine Learning Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Machine Learning Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 합성곱과 필터: 경계와 패턴 감지
  2. 풀링 계층: 공간적 다운샘플링과 불변성
  3. CIFAR-10에서 CNN 만들고 학습하기
  4. 데이터 증강: 강건성을 위한 변환
← Machine Learning Academy(으)로 돌아가기