Squeeze-and-Excitation 밑바닥부터 구현하기: 어떤 피처 맵이 중요한지 학습하는 저렴한 채널 어텐션 (Channel
요약
Squeeze-and-Excitation(SE) 블록의 원리를 이해하고 라이브러리 없이 밑바닥부터 직접 구현하는 튜토리얼입니다. Squeeze, Excite, Scale의 세 단계를 통해 채널 간의 상호 의존성을 모델링하고 피처 맵을 재보정하는 과정을 다룹니다.
핵심 포인트
- Squeeze 단계에서 전역 평균 풀링을 통해 채널 기술자를 생성합니다.
- Excite 단계에서 2층 병목 MLP를 사용하여 채널 간 상호 의존성을 모델링합니다.
- Softmax 대신 Sigmoid를 사용하여 각 채널을 독립적으로 제어합니다.
- Scale 단계를 통해 학습된 게이트 값으로 피처 맵을 재보정합니다.
컨볼루션 레이어 (Convolution layer)는 에지 검출기, 질감 검출기, 색상 블롭(colour blob)과 같은 C개의 출력 채널을 생성하며, 그 후 모든 채널을 동일한 비중으로 하류(downstream)로 전달합니다. 이 레이어에는 "이 이미지의 경우, 털 질감 채널은 중요하지만 하늘 기울기 채널는 중요하지 않다"라고 말할 수 있는 내장된 방법이 없습니다. Squeeze-and-Excitation (Hu et al., 2017)은 바로 그 기능을 추가합니다. 즉, 입력마다 채널의 중요성을 재보정하는 저렴하고 학습 가능한 게이트 (gate)를 결합하는 것입니다. 저는 라이브러리 없이 평균(average), 두 번의 행렬 곱셈 (matrix multiplies), ReLU, 그리고 sigmoid만 사용하여 이를 밑바닥부터 직접 구현했습니다. 이는 세 가지 아주 작은 단계로 이루어져 있습니다.
Squeeze: 채널 기술자(channel descriptor)를 위한 전역 평균 풀링 (global average pool)
채널의 중요도를 결정하려면 먼저 해당 채널에 대한 요약이 필요합니다. Squeeze는 각 채널의 전체 H×W 피처 맵 (feature-map)을 하나의 숫자 z_c로 평균화합니다. 그 결과는 z_c가 채널 c의 전역 기술자 (global descriptor)가 되는 C 길이의 벡터가 됩니다. 여기서 핵심은 바로 그 전역 수용 영역 (global receptive field)입니다. 일반적인 컨볼루션 (conv)은 작은 윈도우만 보지만, 이 기술자는 전체 공간적 범위를 요약하므로 다음 단계에서 이미지를 전체적으로 추론할 수 있습니다.
function squeeze(maps) { // maps: C channels, each H*W values
return maps.map(m => // -> z: one number per channel
m.reduce((a, v) => a + v, 0) / m.length);
}...
Excite: z를 게이트로 변환하는 2층 병목 MLP (two-layer bottleneck MLP)
이제 그 기술자를 게이트로 변환합니다. Excite는 아주 작은 2층 MLP (Multi-Layer Perceptron)입니다. 첫 번째 FC (Fully Connected) 레이어는 C를 C/r개의 은닉 유닛 (hidden units)으로 매핑하고 (그 후 ReLU 적용), 두 번째 레이어는 C/r을 다시 C로 매핑한 다음, sigmoid가 각 출력을 (0,1) 사이로 압착합니다. 축소 비율 (reduction ratio) r (논문 기본값 16)이 핵심 비결입니다. 병목 (bottleneck) 구조는 전체 C→C 레이어보다 훨씬 저렴하며, 이 구조는 블록이 z를 그대로 복사하는 대신 전역 문맥 (global context)으로부터 채널 간의 상호 의존성을 모델링하도록 _강제_합니다.
const relu = v => v.map(x => Math.max(0, x));
const sigmoid = v => v.map(x => 1 / (1 + Math.exp(-x)));
...
Softmax가 아닌 Sigmoid를 사용하는 것은 의도적인 설계이며, 사람들이 흔히 실수하는 디테일입니다. Softmax를 사용하면 마치 단 하나의 채널만 "켜질" 수 있는 것처럼 게이트(gate)들이 서로 경쟁하며 합이 1이 되도록 강제하게 됩니다. 하지만 채널들은 상호 배타적이지 않습니다. 하나의 이미지에는 동시에 여러 개의 강력한 채널이 필요할 수 있습니다. 채널별로 독립적인 Sigmoid를 사용함으로써, 블록은 어떤 부분 집합(subset)이든 자유롭게 높이거나 낮출 수 있습니다.
Scale: 게이트를 통해 모든 맵을 재보정(recalibrate)하기
마지막 단계는 사소하지만 이 과정의 결실이 맺어지는 지점입니다. 각 원본 피처 맵(feature-map)에 스칼라 게이트(scalar gate)를 곱하며, 이는 H×W 전체에 브로드캐스트(broadcast)됩니다. 정보가 풍부한 채널(게이트 값이 1에 가까운 경우)은 거의 손상되지 않은 채 통과하고, 도움이 되지 않는 채널(게이트 값이 0에 가까운 경우)은 0을 향해 사라집니다. 이 블록은 입력 채널별로 자신의 입력을 재보정(recalibrate)하여 그 결과를 다음 레이어(layer)로 전달합니다.
function scale(maps, s) {
return maps.map((m, c) => m.map(v => v * s[c]));
}
...
제 데모에서는 "에지(edges)", "질감(texture)", "복잡한 장면(busy scene)", "평탄한 하늘(flat sky)"와 같은 합성 입력(synthetic input)을 선택하여 게이트가 실시간으로 재계산되는 것을 관찰할 수 있습니다. 가장 흥미로운 사례는 평탄한 하늘입니다. 모든 것이 낮고 균일하며 눈에 띄는 것이 없기 때문에, 모든 게이트가 중립적인 0.5에 머물며 아무것도 재가중(re-weighted)되지 않습니다. "에지"로 전환하면 처음 몇 개의 채널은 강하게 활성화되는 반면 나머지는 억제됩니다. 재보정(recalibration)은 _입력 의존적(input-dependent)_입니다. 이것이 핵심 아이디어의 전부입니다.
전체 블록, 그리고 비용이 거의 들지 않는 이유
PyTorch에서는 단 몇 줄이면 충분합니다. AdaptiveAvgPool2d(1)이 squeeze 단계이고, 두 개의 선형 레이어(linear layers)가 excite 단계이며, sigmoid가 게이트를 만들고, 브로드캐스트 곱셈(broadcast multiply)이 scale 단계입니다. 게이트의 형태가 (B, C, 1, 1)로 출력되어 깔끔하게 브로드캐스트된다는 점에 주목하세요.
class SEBlock(nn.Module):
def __init__(self, C, r=16):
super().__init__()
...
두 개의 FC (Fully Connected) 레이어는 2·C·(C/r) = 2C²/r개의 가중치를 가집니다. 이것이 SE가 추가하는 유일한 파라미터입니다. C=512, r=16일 때 이는 32,768개의 가중치로, 단일 3×3 컨볼루션 (conv)의 C²·9 ≈ 2.36M에 비하면 반올림 오차 수준에 불과합니다. 작은 r 값은 병목 (bottleneck)을 넓히며 (더 세밀한 게이트, 더 많은 파라미터), r을 너무 크게 설정하면 병목이 결핍되어 게이트가 쓸모없는 평탄한 0.5 값으로 붕괴됩니다. 논문에서는 16이 견고한 최적점 (sweet spot)임을 발견했으며, 이는 ResNet-50에 약 2.5%의 파라미터만을 추가했습니다.
가장 좋은 점은 SE가 아키텍처 (architecture)가 아니라 _모듈 (module)_이라는 것입니다. ResNet에서는 identity 더하기 직전의 잔차 브랜치 (residual branch)에 이를 적용하여 — y = x + SE(F(x)) — 스킵 연결 (skip connection)을 건드리지 않은 채 학습 안정성을 유지하면서, 학습 가능한 채널 어텐션 (channel attention)을 얻을 수 있습니다. 이러한 즉시 적용 가능한 단순함은 ILSVRC 2017에서 우승을 차지했으며, SE를 MobileNetV3와 모든 EfficientNet에 포함시켰고, SE → CBAM (공간 어텐션 포함) → ECA (저렴한 1-D conv)로 이어지는 어텐션 계보의 씨앗이 되었습니다.
입력을 선택하고 squeeze → excite → rescale 과정이 실시간으로 실행되는 것을 확인해 보세요:
https://dev48v.infy.uk/dl/day40-squeeze-excitation.html
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기