본문 바로가기
C.W.K.
Stream
Lesson 06 of 08 · published

합성곱 계층: Conv2d와 관련 모듈

~14 min · conv2d, cnn, channels, padding

Level 0텐서 탐구자
0 XP0/62 lessons0/13 achievements
0/120 XP to next level120 XP to go0% complete

PyTorch의 NCHW 관례에서 쓰는 합성곱 계층

PyTorch는 이미지 데이터를 (N, C, H, W), 즉 배치·채널·높이·너비 순서로 다뤄. TensorFlow와 Core ML에서 흔한 다른 관례는 NHWC야. 프레임워크 사이를 오갈 때는 permute로 차원 순서를 바꿀 준비를 해 둬.

nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0)는 입력 위를 미끄러지며 작동하는 필터 out_channels개를 학습하고, 같은 수의 특징 맵을 만들어. groups=1일 때 가중치 텐서의 모양은 (out_channels, in_channels, kernel_height, kernel_width)라서 각 필터가 모든 입력 채널을 포함해. 출력 공간 크기는 표준 공식 out = (in + 2*padding - kernel) / stride + 1로 구해.

실제로 자주 쓰는 변형

  • Conv2d: 2차원 합성곱이야. 이미지에 기본으로 사용해.
  • Conv1d: 1차원 합성곱이야. 오디오 파형, 문자 단위 텍스트, 시계열 같은 시퀀스에 유용해.
  • ConvTranspose2d: 전치 합성곱으로 업샘플링해. U-Net의 디코더와 DCGAN의 생성기에서 볼 수 있어.
  • 깊이별 분리 합성곱: Conv2d(groups=in_channels)Conv2d(1x1)를 조합해 만들어. MobileNet과 EfficientNet을 효율적으로 만드는 핵심 기법이야.

간편한 패딩 표기

PyTorch 1.10부터 padding='same' 문자열을 지원해. stride=1일 때 공간 차원을 그대로 유지하며, 커널 크기로 패딩을 직접 계산하던 일을 대신해 줘. 공간 차원을 줄여야 할 특별한 이유가 없다면 편하게 사용할 수 있어.

Code

Conv2d 기본·python
import torch
import torch.nn as nn

# 3 RGB channels in, 16 feature maps out, 3x3 kernel
conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3,
                 stride=1, padding=1)

x = torch.randn(8, 3, 32, 32)   # batch=8, RGB, 32x32 image
y = conv(x)
print(y.shape)                   # torch.Size([8, 16, 32, 32]) — same spatial
print(conv.weight.shape)         # torch.Size([16, 3, 3, 3])  — out, in, kH, kW
print(conv.bias.shape)           # torch.Size([16])

# stride=2 halves spatial dims
conv_down = nn.Conv2d(3, 16, 3, stride=2, padding=1)
print(conv_down(x).shape)        # torch.Size([8, 16, 16, 16])
간단 CNN: 기준 방식·python
import torch
import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 32, 3, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(2),                 # 32x32 → 16x16

            nn.Conv2d(32, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(2),                 # 16x16 → 8x8

            nn.Conv2d(64, 128, 3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d(1),         # global avg pool → 1x1
        )
        self.classifier = nn.Linear(128, num_classes)

    def forward(self, x):
        x = self.features(x)
        x = x.flatten(1)                     # (B, 128, 1, 1) → (B, 128)
        return self.classifier(x)

model = SimpleCNN()
print(model(torch.randn(4, 3, 32, 32)).shape)   # torch.Size([4, 10])
깊이별 분리 합성곱: MobileNet의 핵심 기법·python
import torch.nn as nn

class DepthwiseSeparable(nn.Module):
    """Replace a regular conv with depthwise + pointwise — far fewer params."""
    def __init__(self, in_ch, out_ch, kernel=3):
        super().__init__()
        # Depthwise: each input channel gets its own kernel
        self.depthwise = nn.Conv2d(in_ch, in_ch, kernel,
                                    padding=kernel // 2, groups=in_ch)
        # Pointwise: 1x1 conv to mix channels
        self.pointwise = nn.Conv2d(in_ch, out_ch, kernel_size=1)

    def forward(self, x):
        return self.pointwise(self.depthwise(x))

# Compare param counts
regular = nn.Conv2d(64, 128, 3, padding=1)
sep = DepthwiseSeparable(64, 128, 3)

regular_params = sum(p.numel() for p in regular.parameters())
sep_params = sum(p.numel() for p in sep.parameters())
print(f"Regular: {regular_params:,}")    # 73,856
print(f"Separable: {sep_params:,}")       # 8,896 — about 8x fewer

External links

Exercise

작은 ResNet식 블록을 만들어 봐. Conv2d(64, 64, 3, padding=1) → BatchNorm → ReLU → Conv2d(64, 64, 3, padding=1) → BatchNorm 순서로 계산한 뒤 입력을 다시 더해 건너뛰기 연결을 만들고, 마지막에 ReLU를 적용해. 공간 차원과 채널 수가 그대로 유지되는지 검증해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.