CS231n Lecture 9 - Object Detection, Image Segmentation, and Visualization

LECTURE 글 목록
목차

핵심 한 줄 정리

Image segmentation과 object detection은 image-level classification을 pixel, region, object 단위의 dense prediction으로 확장한 문제이며, saliency map과 CAM 계열 기법은 예측 score를 다시 image 공간에 연결해 model이 어느 영역을 사용했는지 해석한다.

반드시 기억할 개념

Computer vision task의 출력 단위

같은 image를 입력받더라도 무엇을 출력하느냐에 따라 task가 달라진다.

Task출력같은 class의 여러 object 구분
Image classificationimage 전체의 class 하나불가능
Semantic segmentationpixel마다 semantic class불가능
Object detectionobject마다 class와 bounding box가능
Instance segmentationobject마다 class, box, pixel mask가능

Semantic segmentation에서 dog가 두 마리 있으면 두 object의 pixel은 모두 dog class로 표시된다. Instance segmentation은 같은 dog class 안에서도 서로 다른 instance ID를 부여한다.

이 task들은 입력 image 하나를 label 하나로 줄이는 classification보다 출력 구조가 복잡하다. Spatial information을 유지하면서 image의 여러 위치에 prediction을 만들어야 하므로 dense prediction이라고 부른다.

Semantic segmentation

Semantic segmentation은 image의 모든 pixel에 class label을 할당하는 문제이다.

Input image가 다음 shape라고 하자.

XRH×W×CinX \in \mathbb{R}^{H \times W \times C_{\text{in}}}

Class 수가 KK이면 model은 pixel마다 KK개의 score를 출력한다.

SRH×W×KS \in \mathbb{R}^{H \times W \times K}

최종 segmentation map은 각 pixel에서 score가 가장 큰 class를 선택한다.

y^i,j=argmaxkSi,j,k\hat{y}_{i,j} = \arg\max_{k}S_{i,j,k}

Pixel 하나의 RGB 값만 보고 class를 결정하기는 어렵다. 같은 색도 object와 주변 context에 따라 의미가 달라지므로 model의 receptive field가 주변 영역을 함께 봐야 한다.

각 pixel을 중심으로 patch를 잘라 image classifier를 반복 실행할 수도 있지만, H×WH \times W개의 pixel마다 full network를 실행하므로 계산이 지나치게 크다. 실제로는 image 전체를 한 번 입력해 모든 pixel의 prediction을 동시에 만든다.

Fully Convolutional Network

Fully Convolutional Network, FCN은 fully connected layer를 사용하지 않고 convolutional layer만으로 spatial output을 생성한다. Input resolution을 줄이는 encoder와 다시 키우는 decoder로 구성할 수 있다.

H×Wencoderh×wdecoderH×WH \times W \xrightarrow{\text{encoder}} h \times w \xrightarrow{\text{decoder}} H \times W

Encoder는 pooling이나 strided convolution으로 resolution을 줄인다. Resolution이 작아질수록 계산량이 줄고 receptive field가 커지며, channel 수를 늘려 더 추상적인 feature를 저장한다.

H,WCH,W \downarrow \qquad C \uparrow

Decoder는 low-resolution feature map을 원래 image resolution으로 upsampling한다. 마지막 1×11 \times 1 convolution은 각 위치의 feature vector를 KK개의 class score로 바꾼다.

Fi,jRC1×1 ConvSi,jRKF_{i,j} \in \mathbb{R}^{C} \xrightarrow{1 \times 1\text{ Conv}} S_{i,j} \in \mathbb{R}^{K}

Pixel-wise classification loss

Semantic segmentation은 모든 pixel에서 classification을 수행한다. Ground-truth label map을 Y{1,,K}H×WY \in \{1,\ldots,K\}^{H \times W}라고 하면 pixel-wise cross-entropy loss는 다음과 같다.

Li,j=logexp(Si,j,Yi,j)k=1Kexp(Si,j,k)L_{i,j} = -\log \frac{\exp(S_{i,j,Y_{i,j}})} {\sum_{k=1}^{K}\exp(S_{i,j,k})}

Image 전체의 loss는 유효한 pixel의 loss를 합하거나 평균 낸 값이다.

Lseg=1Ω(i,j)ΩLi,jL_{\text{seg}} = \frac{1}{|\Omega|} \sum_{(i,j)\in\Omega}L_{i,j}

Ω\Omega는 annotation이 있는 유효 pixel 집합이다. Fully supervised segmentation은 pixel-level ground-truth map이 필요하며, 초기 dataset은 사람이 각 pixel을 직접 표시해 만들었다.

Class별 pixel 수가 크게 다르면 background가 loss를 지배할 수 있다. 이때 class weight를 적용하거나 focal loss, Dice loss 같은 대안을 사용할 수 있다.

Upsampling

Downsampling은 pooling이나 stride로 쉽게 수행할 수 있지만 decoder에는 resolution을 키우는 연산이 필요하다.

Nearest-neighbor upsampling

Nearest-neighbor upsampling은 low-resolution 값을 주변 위치에 그대로 복사한다. 2×22 \times 2 feature map을 scale factor 2로 키우면 4×44 \times 4가 된다.

[abcd][aabbaabbccddccdd]\begin{bmatrix} a & b \\ c & d \end{bmatrix} \longrightarrow \begin{bmatrix} a & a & b & b \\ a & a & b & b \\ c & c & d & d \\ c & c & d & d \end{bmatrix}

학습 parameter가 없으며, 보통 뒤에 convolution을 붙여 feature를 보정한다.

Bed-of-nails upsampling

Bed-of-nails 방식은 정해진 위치에 원래 값을 놓고 나머지를 00으로 채운다.

[abcd][a0b00000c0d00000]\begin{bmatrix} a & b \\ c & d \end{bmatrix} \longrightarrow \begin{bmatrix} a & 0 & b & 0 \\ 0 & 0 & 0 & 0 \\ c & 0 & d & 0 \\ 0 & 0 & 0 & 0 \end{bmatrix}

뒤쪽 convolution이 비어 있는 위치로 정보를 퍼뜨린다.

Max unpooling

Encoder에서 max pooling을 수행할 때 선택된 maximum의 위치를 저장해 두었다가 decoder에서 같은 위치에 값을 되돌릴 수 있다. 저장한 argmax index가 spatial structure를 복원하는 힌트가 된다.

Max unpooling도 학습 parameter가 없는 연산이며, pooling에서 버린 정확한 값까지 복구하는 것은 아니다.

Transposed convolution

Transposed convolution은 학습 가능한 upsampling 연산이다. Input의 각 값을 kernel로 펼쳐 output 위치에 더하며, overlap되는 위치는 합산한다.

1차원에서 input이 [A,B][A,B]이고 kernel이 [w1,w2,w3][w_1,w_2,w_3]이면 stride 1의 output은 다음과 같은 형태가 된다.

[A,B][Aw1,Aw2+Bw1,Aw3+Bw2,Bw3][A,B] \longrightarrow [Aw_1,Aw_2+Bw_1,Aw_3+Bw_2,Bw_3]

2차원 output size는 kernel size KK, stride SS, padding PP, output padding PoutP_{\text{out}}에 따라 다음처럼 계산한다.

Hout=(Hin1)S2P+K+PoutH_{\text{out}} = (H_{\text{in}}-1)S-2P+K+P_{\text{out}}

Transposed convolution이라는 이름은 convolution을 matrix multiplication으로 표현했을 때 그 matrix의 transpose를 사용하는 데서 나온다. 일반 convolution의 정보를 정확히 되돌리는 inverse convolution은 아니다.

U-Net

U-Net은 encoder-decoder 구조에 같은 resolution끼리 연결하는 skip connection을 추가한 segmentation network이다.

Fdec(l)=Concat(Upsample(Fdec(l+1)),Fenc(l))F_{\text{dec}}^{(l)} = \operatorname{Concat} \left( \operatorname{Upsample}(F_{\text{dec}}^{(l+1)}), F_{\text{enc}}^{(l)} \right)

Encoder의 깊은 feature는 넓은 context와 semantic information을 담지만 downsampling 과정에서 정확한 boundary와 위치 정보가 약해진다. 같은 resolution의 encoder feature를 decoder에 직접 전달하면 다음 두 정보를 함께 사용할 수 있다.

  • 깊은 layer의 semantic context
  • 얕은 layer의 세밀한 spatial structure

이 skip connection 덕분에 object boundary가 더 선명한 segmentation map을 만들 수 있다. U-Net과 그 변형은 medical image segmentation처럼 pixel 위치가 중요한 task에서 여전히 강한 baseline이다.

%% title: U-Net Encoder-Decoder와 Skip Connection
%% caption: 256 × 256 input을 예로 든 U-Net이다. Encoder는 해상도를 절반으로 줄이며 채널을 늘리고, decoder는 같은 해상도의 encoder feature를 concatenate해 경계 정보를 복원한다.
flowchart LR
    image["Image<br/>3 × 256 × 256"] --> e1["Encoder Conv Block 1<br/>64 × 256 × 256"]
    e1 -->|"MaxPool /2"| e2["Encoder Conv Block 2<br/>128 × 128 × 128"]
    e2 -->|"MaxPool /2"| bottleneck["Bottleneck<br/>256 × 64 × 64"]
    bottleneck -->|"Upsample ×2"| d2["Decoder Conv Block 2<br/>128 × 128 × 128"]
    d2 -->|"Upsample ×2"| d1["Decoder Conv Block 1<br/>64 × 256 × 256"]
    d1 --> mask["1 × 1 Conv<br/>K × 256 × 256"]
    e2 -. "skip: concat" .-> d2
    e1 -. "skip: concat" .-> d1

Semantic segmentation과 instance segmentation

Semantic segmentation output은 class별 map이다.

Ysemantic{1,,K}H×WY_{\text{semantic}} \in \{1,\ldots,K\}^{H \times W}

같은 class object가 여러 개 있어도 하나의 class ID만 표시되므로 서로 다른 instance를 구분할 수 없다. Instance segmentation은 각 object를 먼저 분리하고 object마다 binary mask를 예측한다.

O={(cn,bn,mn)}n=1N\mathcal{O} = \left\{ (c_n,b_n,m_n) \right\}_{n=1}^{N}

cnc_n은 class, bnb_n은 bounding box, mnm_n은 해당 instance의 mask이다. 따라서 instance segmentation은 object detection과 pixel segmentation을 결합한 task로 볼 수 있다.

Object detection의 출력

Object detection은 image 안의 각 object에 대해 class와 bounding box를 예측한다.

D={(pn,bn)}n=1N\mathcal{D} = \left\{ (p_n,b_n) \right\}_{n=1}^{N}

pnp_n은 class probability vector이고 bounding box는 예를 들어 다음 네 값으로 표현할 수 있다.

bn=(xn,yn,wn,hn)b_n = (x_n,y_n,w_n,h_n)

Single-object image라면 network가 class score와 box coordinate 네 개를 직접 출력할 수 있다. Loss는 classification과 box regression을 합한 multi-task loss이다.

L=Lcls+λLboxL = L_{\text{cls}} + \lambda L_{\text{box}}

강의의 단순한 설정에서는 class에 softmax loss, box coordinate에 L2 loss를 사용한다.

Lbox=bb^22L_{\text{box}} = \lVert b-\hat{b}\rVert_2^2

실제 detector에서는 outlier에 덜 민감한 Smooth L1 loss나 IoU 계열 loss도 자주 사용한다.

Object 수 NN은 image마다 다르다. Object가 세 개라면 box coordinate만 1212개가 필요하고 object 수가 바뀌면 output 길이도 달라진다. 고정된 output vector에 모든 object를 단순히 나열하는 방식은 확장하기 어렵다.

Intersection over Union

Detection에서 predicted box와 ground-truth box가 얼마나 겹치는지는 Intersection over Union, IoU로 측정한다.

IoU(Bp,Bg)=BpBgBpBg\operatorname{IoU}(B_p,B_g) = \frac{|B_p\cap B_g|}{|B_p\cup B_g|}

두 box가 완전히 같으면 IoU는 11, 전혀 겹치지 않으면 00이다. 일정 IoU threshold 이상이면서 class도 맞아야 true positive로 판단한다.

Detection 성능은 confidence threshold를 바꾸며 precision과 recall을 계산하고 Precision-Recall curve 아래 면적인 Average Precision, AP로 요약한다. 여러 class의 AP를 평균 낸 값이 mAP이다.

mAP=1Kk=1KAPk\operatorname{mAP} = \frac{1}{K} \sum_{k=1}^{K}\operatorname{AP}_k

Dataset에 따라 IoU 0.50.5 한 지점의 AP를 쓰거나, 0.500.50부터 0.950.95까지 여러 threshold의 AP를 평균 내기도 한다.

Sliding window와 region proposal

고정된 window를 image 전체의 여러 위치와 scale에 옮기며 각 crop을 object class 또는 background로 분류할 수 있다. 그러나 (x,y,w,h)(x,y,w,h)의 가능한 조합이 너무 많아 모든 window에 CNN을 실행하는 것은 비효율적이다.

Region proposal은 object가 있을 가능성이 높은 소수의 후보 box만 먼저 선택한다. Detector는 각 proposal에 대해 다음 두 task를 수행한다.

  • proposal 안의 object class를 분류한다.
  • ground-truth box에 더 잘 맞도록 coordinate offset을 예측한다.
b^=bproposal+Δb\hat{b} = b_{\text{proposal}}+\Delta b

Region proposal 기반 detector는 detection 문제를 제한된 수의 region classification과 box refinement 문제로 바꾼다.

R-CNN 계열

R-CNN

R-CNN은 image에서 region proposal을 만든 뒤 각 region을 crop하고 독립적으로 CNN에 통과시킨다.

ImageRegion proposalsCNN per regionClass + Box offset\text{Image} \rightarrow \text{Region proposals} \rightarrow \text{CNN per region} \rightarrow \text{Class + Box offset}

같은 image의 겹치는 region마다 CNN computation을 반복하므로 매우 느리다.

Fast R-CNN

Fast R-CNN은 CNN을 image 전체에 한 번만 적용한다. Proposal을 image가 아니라 shared feature map에 투영하고, 각 region의 feature를 ROI pooling으로 고정된 크기로 바꾼 뒤 class와 box offset을 예측한다.

ImageCNN onceFROI featuresClass + Box offset\text{Image} \xrightarrow{\text{CNN once}} F \xrightarrow{\text{ROI features}} \text{Class + Box offset}

Convolution feature map이 spatial correspondence를 유지하므로 image의 proposal 위치를 feature map 위치로 옮길 수 있다. R-CNN의 중복 convolution을 제거한 것이 핵심이다.

Faster R-CNN과 Region Proposal Network

Faster R-CNN은 별도 proposal algorithm 대신 Region Proposal Network, RPN을 feature map 위에서 학습한다. 여러 위치와 scale의 anchor마다 다음 값을 예측한다.

  • object가 있을 확률인 objectness score
  • anchor를 object box에 맞추는 coordinate offset

Confidence가 높은 top KK proposal을 선택해 두 번째 detection head로 보낸다. 따라서 Faster R-CNN은 다음 두 stage로 구성된다.

  1. RPN이 object candidate를 만든다.
  2. Detection head가 proposal의 class와 box를 정교하게 예측한다.

Two-stage detector는 정확도가 높지만 proposal과 detection을 나누어 처리하므로 one-stage detector보다 latency가 커질 수 있다.

One-stage detector와 YOLO

Single-stage detector는 region proposal과 최종 detection을 하나의 network pass에서 함께 수행한다. SSD와 YOLO가 대표적이다.

초기 YOLO는 image를 S×SS \times S grid로 나누고 각 grid cell에서 다음 값을 예측했다.

  • BB개의 bounding box
  • 각 box의 confidence 또는 objectness
  • class probability

강의의 예시는 S=7S=7, B=2B=2이다. 각 grid cell이 두 개의 candidate box를 만들므로 image 전체에는 많은 box가 나오며, network는 이를 한 번의 forward pass에서 동시에 예측한다.

output per cell=B×(4+1)+K\text{output per cell} = B\times(4+1)+K

각 box에는 coordinate 네 개와 objectness 하나가 있고, KK개의 class probability가 붙는다. 실제 YOLO version에 따라 output parameterization과 class score 결합 방식은 달라질 수 있다.

One-stage detector는 shared dense feature map에서 모든 prediction을 바로 만들기 때문에 빠르며 real-time robotics, industrial inspection, medical application 등에 널리 쓰인다.

%% title: Two-Stage와 One-Stage Object Detector
%% caption: Two-stage detector는 proposal 생성과 정밀 예측을 나누고, one-stage detector는 dense feature map에서 class와 box를 한 번에 출력한다.
flowchart LR
    image["Image"] --> backbone["Shared Backbone<br/>Feature Map"]
    subgraph two["Two-Stage: Faster R-CNN"]
        rpn["RPN<br/>Region Proposals"] --> roi["ROIAlign"]
        roi --> head2["Class + Refined Box"]
    end
    subgraph one["One-Stage: YOLO"]
        dense["Dense Prediction Head"] --> head1["Class + Objectness + Box"]
    end
    backbone --> rpn
    backbone --> roi
    backbone --> dense
    head2 --> candidates["Candidate Detections"]
    head1 --> candidates

Non-Maximum Suppression

Detector는 같은 object 주변에 confidence가 높은 box를 여러 개 만들 수 있다. Non-Maximum Suppression, NMS는 중복 prediction을 제거한다.

  1. Confidence가 가장 높은 box를 선택한다.
  2. 선택한 box와 IoU가 threshold보다 큰 같은 class box를 제거한다.
  3. 남은 box에서 다시 가장 높은 confidence를 선택한다.
  4. 후보가 없어질 때까지 반복한다.
IoU(Bi,Bselected)>τNMSBi 제거\operatorname{IoU}(B_i,B_{\text{selected}}) > \tau_{\text{NMS}} \quad\Rightarrow\quad B_i\text{ 제거}

Threshold가 너무 낮으면 가까이 있는 서로 다른 object까지 제거할 수 있고, 너무 높으면 같은 object의 duplicate box가 남는다.

DETR

DETR, Detection Transformer는 object detection을 fixed-size set prediction으로 바꾼다. 전체 구조는 image encoder와 Transformer decoder로 구성된다.

  1. CNN backbone이 image feature map을 만든다.
  2. Feature map을 token sequence로 펼치고 positional encoding을 더한다.
  3. Transformer encoder가 image token을 처리한다.
  4. Transformer decoder가 learnable object query와 encoder output을 처리한다.
  5. Query마다 class와 bounding box를 출력한다.

Object query는 image patch나 미리 정한 bounding box가 아니다.

QobjRNq×dQ_{\text{obj}} \in \mathbb{R}^{N_q \times d}

각 row는 학습 가능한 parameter이며 하나의 output slot 역할을 한다. Decoder 안에서는 query끼리 self-attention하고, encoder image token과 cross-attention한다.

각 query output은 class probability와 normalized bounding box를 만든다.

(pi,bi)=Head(zi)(p_i,b_i) = \operatorname{Head}(z_i)

Class에는 실제 object class 외에 no object class가 포함된다. Query 수가 NqN_q이면 최대 NqN_q개의 object를 출력할 수 있다. Image에 object가 더 많으면 전부 표현할 수 없으므로 충분한 query 수를 정해야 한다.

Bipartite matching

Ground-truth object에는 순서가 없으므로 query 1이 특정 object를 맡아야 한다고 미리 정할 수 없다. DETR은 predicted set과 ground-truth set 사이의 minimum-cost bipartite matching을 구한다.

σ^=argminσj=1NgtC(yj,y^σ(j))\hat{\sigma} = \arg\min_{\sigma} \sum_{j=1}^{N_{\text{gt}}} \mathcal{C} \left( y_j, \hat{y}_{\sigma(j)} \right)

Matching cost에는 class error와 box distance, IoU 계열 cost가 들어간다. Matching된 pair에는 class와 box loss를 적용하고, 남은 query는 no object를 예측하도록 학습한다.

LDETR=Lcls+λ1L1(b,b^)+λIoULIoUL_{\text{DETR}} = L_{\text{cls}} + \lambda_1L_1(b,\hat{b}) + \lambda_{\text{IoU}}L_{\text{IoU}}

Set-level matching이 duplicate prediction을 직접 억제하므로 기본 DETR은 hand-designed anchor와 NMS 없이 end-to-end로 학습할 수 있다.

Fully supervised DETR의 class head는 training에서 정의한 class만 출력한다. 새로운 class를 zero-shot으로 찾으려면 text embedding 등을 결합한 open-vocabulary extension이 필요하다.

%% title: DETR의 Set Prediction 구조
%% caption: Learnable object query 각각이 하나의 output slot이 되며, image token을 cross-attention한 뒤 class와 box를 예측한다. 학습 시 bipartite matching으로 정답 object와 예측 slot을 연결한다.
flowchart LR
    image["Image"] --> cnn["CNN Backbone"]
    cnn --> tokens["Flattened Image Tokens<br/>+ Position Encoding"]
    tokens --> encoder["Transformer Encoder"]
    queries["Learnable Object Queries<br/>Nq × d"] --> decoder["Transformer Decoder"]
    encoder --> decoder
    decoder --> slots["Nq Query Outputs"]
    slots --> heads["Class Head + Box Head"]
    heads --> set["Predicted Set<br/>{class, box, no-object}"]
    gt["Ground-Truth Object Set"] -.-> match["Bipartite Matching"]
    set -.-> match
    match --> loss["Matched Set Loss"]

Mask R-CNN과 instance segmentation

Mask R-CNN은 Faster R-CNN에 object별 binary mask branch를 추가한다.

ROI feature{Class headBox headMask head\text{ROI feature} \rightarrow \begin{cases} \text{Class head} \\ \text{Box head} \\ \text{Mask head} \end{cases}

Mask head는 각 ROI 안에서 class별 pixel mask를 예측하는 작은 FCN이다. 전체 loss는 세 task의 합이다.

L=Lcls+Lbox+LmaskL = L_{\text{cls}} + L_{\text{box}} + L_{\text{mask}}

LmaskL_{\text{mask}}는 해당 object의 binary mask에 대한 pixel-wise binary cross-entropy로 계산할 수 있다.

Mask R-CNN은 ROI pooling의 coordinate quantization을 줄이기 위해 ROIAlign을 사용한다. Accurate spatial alignment가 필요한 mask prediction에서 작은 위치 오차도 boundary 품질을 떨어뜨리기 때문이다.

Model visualization의 목적

Classification accuracy만으로는 model이 올바른 근거를 사용했는지 알 수 없다. 특히 medical image에서 tumor 유무를 맞히는 것뿐 아니라 image의 어느 부분 때문에 그렇게 판단했는지 확인하는 일이 중요하다.

Linear classifier에서는 weight vector를 원래 image shape로 바꾸면 class template처럼 볼 수 있었다. CNN의 첫 convolution filter도 RGB image로 시각화하면 edge, orientation, color contrast 같은 low-level pattern을 확인할 수 있다.

깊은 layer는 channel 수가 많고 feature가 추상적이어서 weight 자체를 그대로 image로 표현하기 어렵다. 이때 input gradient나 activation을 이용해 prediction과 image 위치를 연결한다.

Saliency map

Class cc의 score를 sc(X)s_c(X)라고 하자. Input pixel을 조금 바꿨을 때 score가 얼마나 변하는지는 input에 대한 gradient로 알 수 있다.

G=scXG = \frac{\partial s_c}{\partial X}

Gi,j,k|G_{i,j,k}|가 크면 해당 pixel channel의 작은 변화가 class score에 큰 영향을 준다는 뜻이다. RGB channel을 하나의 map으로 줄이려면 channel 방향 absolute maximum 등을 사용할 수 있다.

Mi,j=maxkscXi,j,kM_{i,j} = \max_k \left| \frac{\partial s_c}{\partial X_{i,j,k}} \right|

Saliency map은 별도의 학습 없이 한 번의 backward pass로 계산할 수 있다. 다만 local sensitivity를 보는 방법이므로 gradient noise, activation saturation에 민감하고 object 전체보다 edge처럼 좁은 영역이 강조될 수 있다.

Class Activation Mapping

CAM은 마지막 convolution feature map과 class classifier weight를 이용해 class별 spatial heat map을 만든다.

마지막 convolution activation을 AkRH×WA^k \in \mathbb{R}^{H' \times W'}라고 하자. Global Average Pooling 결과는 다음과 같다.

zk=1HWi,jAi,jkz_k = \frac{1}{H'W'} \sum_{i,j}A_{i,j}^k

Class cc의 score가 다음 linear classifier로 계산된다고 하자.

sc=kwkczks_c = \sum_k w_k^c z_k

식을 정리하면 class activation map은 다음 weighted sum이 된다.

Mc(i,j)=kwkcAi,jkM_c(i,j) = \sum_k w_k^cA_{i,j}^k

wkcw_k^c는 feature channel kk가 class cc에 얼마나 기여하는지를 나타낸다. McM_c를 input resolution으로 upsampling하면 palace, dome, church처럼 class마다 서로 다른 위치를 강조하는 heat map을 얻는다.

CAM은 마지막 convolution 뒤에 Global Average Pooling과 linear classifier가 바로 이어지는 특정 architecture가 필요하다. 중간에 arbitrary fully connected layer가 있으면 class weight를 feature map에 직접 연결하기 어렵다.

Grad-CAM

Grad-CAM은 class score의 gradient를 사용해 CAM을 임의의 convolution layer로 일반화한다. 선택한 layer의 activation을 AkA^k라고 하면 class cc에 대한 channel weight는 gradient를 spatial average해 구한다.

αkc=1HWi,jscAi,jk\alpha_k^c = \frac{1}{H'W'} \sum_{i,j} \frac{\partial s_c}{\partial A_{i,j}^k}

Grad-CAM heat map은 activation의 weighted sum에 ReLU를 적용한다.

LGrad-CAMc=ReLU(kαkcAk)L_{\text{Grad-CAM}}^c = \operatorname{ReLU} \left( \sum_k\alpha_k^cA^k \right)

ReLU는 class score를 높이는 positive contribution에 집중한다. Heat map을 input image 크기로 upsampling해 원본 위에 겹치면 model이 해당 class를 판단할 때 사용한 영역을 볼 수 있다.

CAM과 Grad-CAM의 차이는 다음과 같다.

방법Channel weight적용 조건
CAMclassifier의 learned weight wkcw_k^cGAP 뒤에 linear classifier가 있는 구조
Grad-CAMgradient average αkc\alpha_k^cgradient를 계산할 수 있는 임의의 conv layer

Grad-CAM은 더 넓은 architecture에 적용할 수 있지만 heat map resolution은 선택한 feature map resolution에 제한된다.

%% title: Grad-CAM Heat Map 생성 과정
%% caption: 특정 class score를 선택한 convolution feature map까지 역전파하고, channel별 gradient를 가중치로 사용해 spatial activation을 합성한다.
flowchart LR
    image["Input Image"] --> model["CNN Forward"]
    model --> feature["Selected Feature Maps<br/>Aᵏ"]
    model --> score["Target Class Score<br/>sᶜ"]
    score --> backward["Backward to Aᵏ"]
    backward --> weights["Spatial Mean of Gradients<br/>αᵏᶜ"]
    feature --> combine["Weighted Sum<br/>Σ αᵏᶜAᵏ"]
    weights --> combine
    combine --> relu["ReLU + Upsample"]
    relu --> overlay["Heat Map Overlay"]

Transformer attention visualization

Vision Transformer는 patch token 사이의 attention matrix를 내부에서 직접 계산한다.

A(h)=softmax(Q(h)K(h)Tdk)A^{(h)} = \operatorname{softmax} \left( \frac{Q^{(h)}K^{(h)T}}{\sqrt{d_k}} \right)

Class token이 각 patch token에 주는 attention weight를 2차원 patch grid로 되돌리면 어느 image 영역을 참고했는지 시각화할 수 있다. 여러 layer와 head가 있으므로 특정 head 하나를 보거나 head를 평균하고, layer 사이의 attention을 누적하는 방법을 사용할 수 있다.

Attention weight가 높다는 사실만으로 해당 patch가 prediction의 원인이라고 단정할 수는 없다. Residual connection, FFN, 여러 head와 layer가 함께 output을 만들기 때문이다. Attention map은 유용한 내부 visualization이지만 완전한 explanation은 아니다.

Dense prediction과 visualization의 큰 흐름

각 방법은 image prediction을 spatial location과 연결하는 방식이 다르다.

방법Spatial output을 얻는 방식핵심 아이디어
FCN / U-Netdecoder가 pixel score map 생성encoder의 context와 decoder의 resolution 복원
R-CNN 계열proposal마다 class와 box 예측object candidate를 먼저 찾는 two-stage detection
YOLOdense grid에서 box와 class 동시 예측한 번의 forward pass로 빠른 detection
DETRlearned query마다 object 하나 예측attention과 set matching 기반 end-to-end detection
Mask R-CNNdetection ROI마다 binary mask 예측detection과 segmentation의 결합
Saliencyclass score의 input gradientpixel 변화에 대한 local sensitivity
CAM / Grad-CAMfeature map의 class별 weighted sumprediction을 convolution 공간에 역으로 연결

Task가 달라도 공통 질문은 같다. Model이 image의 어느 위치에서 어떤 단위의 정보를 만들고, 그 spatial information을 최종 prediction까지 어떻게 보존하는지를 추적해야 한다.

과제에서 확인할 것

Segmentation output과 loss shape

Batch까지 포함한 score shape가 다음과 같은지 확인한다.

SRB×K×H×WS \in \mathbb{R}^{B \times K \times H \times W}

Ground-truth label은 보통 다음 shape의 integer tensor이다.

Y{0,,K1}B×H×WY \in \{0,\ldots,K-1\}^{B \times H \times W}

Softmax와 cross-entropy가 class axis에 적용되고, annotation이 없는 pixel은 ignore index로 loss에서 제외되는지 확인한다.

Encoder-decoder의 spatial shape

Downsampling과 upsampling을 지날 때 HH, WW, channel 수를 layer마다 기록한다. U-Net skip connection에서 concatenate하려는 두 feature map의 spatial resolution이 같은지 확인한다.

Transposed convolution output은 다음 공식을 이용해 검증한다.

Hout=(Hin1)S2P+K+PoutH_{\text{out}} = (H_{\text{in}}-1)S-2P+K+P_{\text{out}}

Bounding box와 IoU

Box가 (x,y,w,h)(x,y,w,h)인지 (x1,y1,x2,y2)(x_1,y_1,x_2,y_2)인지 구현의 convention을 먼저 확인한다. Normalized coordinate인지 pixel coordinate인지도 일관되어야 한다.

간단한 box pair를 직접 넣어 intersection, union, IoU가 올바른지 검증한다.

0IoU(B1,B2)10 \le \operatorname{IoU}(B_1,B_2) \le 1

NMS

NMS가 confidence 내림차순으로 처리되고 같은 class의 겹치는 box만 제거하는지 확인한다. IoU threshold를 바꿨을 때 duplicate detection과 missed object 사이의 trade-off도 살펴본다.

Detection multi-task loss

Classification loss와 box loss의 scale이 지나치게 다르지 않은지 확인한다.

L=Lcls+λLboxL = L_{\text{cls}} + \lambda L_{\text{box}}

λ\lambda를 바꾸면 class accuracy와 localization quality 사이의 균형이 달라질 수 있다.

DETR object query와 matching

Object query 수가 model의 maximum prediction 수를 결정하는지 확인한다. Query output과 ground truth를 index 순서대로 비교하면 안 되며, bipartite matching 결과에 따라 loss pair를 구성해야 한다.

Ground-truth와 matching되지 않은 query는 no object class로 학습되는지도 확인한다.

Saliency와 Grad-CAM

Visualization을 계산할 때 model을 evaluation mode로 두고 원하는 class score를 정확히 선택한다. Grad-CAM에서는 선택한 convolution activation과 그 activation의 gradient를 모두 저장해야 한다.

Heat map을 normalization하고 input resolution으로 resize할 때 값의 상대적 크기가 유지되는지 확인한다. 예측이 맞았다는 이유만으로 heat map도 올바르다고 판단하지 말고, background shortcut이나 dataset bias를 사용하고 있지 않은지 함께 살펴본다.