ResUNet++ : An Advanced Architecture for Medical Image Segmentation
Task?
Fully automated model for pixel-wise polyp segmentation
이 논문은 픽셀단위로 용종을 segment하는 자동화 모델에 대해서 다루고 있다.
ResUNet++ Architecture?
Semantic segmentation nueral network that takes advantage of residual blocks, seqeeze and excitation blocks, atrous spatial pyramidal pooling and attention blocks
Results?
Kvasir-SEG : Dice - 81.33%, mloU - 79.27%
CVC-612 : Dice - 79.55%, mloU - 79.62% 달성
Proceedings of the IEEE International Symposium on Multimedia (ISM) 2019에서 발표된 paper 이다.
노르웨이 출신 저자는 총 7명으로 5명의 공학자와 2명의 의사로 구성되어 있다. Debesh Jha, Michael A. Riegler, Dag Johansen, P˚al Halvorsen, H˚avard D. Johansen
/ Pia H.Smedsrud, Thomas de Lange
KVasir-Seg dataset은 기존 KVasir dataset을 소화기내과 전문의인 Pia와 Thomas가 직접 polyp을 annotation하여 생성한 dataset이다. 현재까지도 KVasir, CVC의 조합으로 의료 segmentation 대표적인 benchmark dataset으로 취급하고 있다.
논문 발표 당시에는 tensorflow, keras로 코드를 배포한 것을 확인할 수 있고 약 3년 전에 PyTorch로 update한 official code를 upload했다.

Figure에는 나타나 있지 않지만,
class ResUnetPlusPlus:
def __init__(self, input_size=256):
self.input_size = input_size
def build_model(self):
n_filters = [16, 32, 64, 128, 256]
inputs = Input((self.input_size, self.input_size, 3))
c0 = inputs
c1 = stem_block(c0, n_filters[0], strides=1)
## Encoder
c2 = resnet_block(c1, n_filters[1], strides=2)
c3 = resnet_block(c2, n_filters[2], strides=2)
c4 = resnet_block(c3, n_filters[3], strides=2)
## Bridge
b1 = aspp_block(c4, n_filters[4])
## Decoder
d1 = attetion_block(c3, b1)
d1 = UpSampling2D((2, 2))(d1)
d1 = Concatenate()([d1, c3])
d1 = resnet_block(d1, n_filters[3])
d2 = attetion_block(c2, d1)
d2 = UpSampling2D((2, 2))(d2)
d2 = Concatenate()([d2, c2])
d2 = resnet_block(d2, n_filters[2])
d3 = attetion_block(c1, d2)
d3 = UpSampling2D((2, 2))(d3)
d3 = Concatenate()([d3, c1])
d3 = resnet_block(d3, n_filters[1])
Why Residual Units?
To improve accuracy, Need deeper neural networks
-> use ResUNet for Backbone Architecture
성능을 높이기 위해서 더 깊은 네트워크를 쌓아야 했고 그렇게 하기 위해서 ResUNet 아키텍처를 백본으로 사용했다.
Pre-Activation Residual Unit?
기본적으로 ResUNet 에서는 Pre-Activation Residual Unit을 사용했다.
Original : x -> ConV -> BN -> ReLU -> ConV -> BN -> (+x) -> ReLU
ResUNet : x -> BN -> ReLU -> ConV -> BN -> ReLU -> ConV -> (+x)
뒤에 활성화함수가 붙는 Post-Activation 방식보다 더 나은 기울기 흐름을 통해 안정적으로 학습이 가능하게하고 실험적으로 더 좋은 성능을 보이는 경우가 많았다고 한다.
What is Squeeze & Excitation Units?
이 개념이 처음 나온 것은 2017년 마지막 ImageNet Competition에서, 2.53%의 압도적인 성능으로 winning한 Squeeze and Excitation Network의 핵심 구조이다.
What for?
To ensure network can increase its sensitivity to the relevant features and suppress the unneccessary features.
다시 말해, 좋은 건 살리고 별로 좋지 않은 것은 버리기 위해서.

SE block 구조
Input -> 요약vSqueeze(by GAP) ->MLP&Sigmoid -> 중요도(점수 계산 s) -> 채널별 곱셈
Transformer Attention 구조
Input -> 요약(by Query, Key 내적) -> softmax -> token 점수 계산 -> weighted sum
전체 context를 요약해서 중요도를 계산하고 계산한 점수를 바탕으로 feature를 조절한다는 점에서 Transformer의 Attention mechanism이 SE Network에서의 철학을 공유한다고 볼 수 있지 않을까? 생각해보았다.
정리해보면, Squeeze and Excitation은 마지막에 GAP(Global Average Pooling)로 Squeeze한 채널별 중요도를 가지고 기존 Feature에 곱해주었다는 점에서 channel wise한 attention 이라고도 볼 수 있을 것 같다.
class ResNet_Block(nn.Module):
def __init__(self, in_c, out_c, stride):
super().__init__()
self.c1 = nn.Sequential(
nn.BatchNorm2d(in_c),
nn.ReLU(),
nn.Conv2d(in_c, out_c, kernel_size=3, padding=1, stride=stride),
nn.BatchNorm2d(out_c),
nn.ReLU(),
nn.Conv2d(out_c, out_c, kernel_size=3, padding=1)
)
self.c2 = nn.Sequential(
nn.Conv2d(in_c, out_c, kernel_size=1, stride=stride, padding=0),
nn.BatchNorm2d(out_c),
)
self.attn = Squeeze_Excitation(out_c)

How ASPP works?
variational dilation rate으로 convolution을 여러번 수행해서 다양한 receptive field를 concatenation한다.
Dilation Convolution?
fixed convolution kernel은 항상 고정된 범위만을 탐색하기 때문에 근처 정보밖에 볼 수 없을 것이다, 하지만 dilation convolution 팽창 합성곱을 사용하게 되면 같은 kernel size라도 또 같은 연산량임에도 불구하고 더 넓은 범위를 보는 효과를 얻을 수 있다.(Receptive Field가 넓어진다.) 또한, pooling처럼 downsample 하지 않기 때문에 해상도의 손실이 없다고 볼 수 있다.
X X X
X X X
X X X (3*3 kernel)
┐
│
▼
X - X - X
- - - - - -
X - X - X
- - - - - -
X - X - X (3*3 kernel with dilation = 2)
def aspp_block(x, num_filters, rate_scale=1):
x1 = Conv2D(num_filters, (3, 3), dilation_rate=(6 * rate_scale, 6 * rate_scale), padding="same")(x)
x1 = BatchNormalization()(x1)
x2 = Conv2D(num_filters, (3, 3), dilation_rate=(12 * rate_scale, 12 * rate_scale), padding="same")(x)
x2 = BatchNormalization()(x2)
x3 = Conv2D(num_filters, (3, 3), dilation_rate=(18 * rate_scale, 18 * rate_scale), padding="same")(x)
x3 = BatchNormalization()(x3)
x4 = Conv2D(num_filters, (3, 3), padding="same")(x)
x4 = BatchNormalization()(x4)
y = Add()([x1, x2, x3, x4])
y = Conv2D(num_filters, (1, 1), padding="same")(y)
return y

Why Attention Units?
기존 UNet의 문제는 필요없는 정보까지 모두 통째로 전달해버린다는 점이다. 그렇다면 Decoder에게 polyp에 관한 정보만을 전달할 수 없을까? 그래서 나온 것이 "attention unit"이다. skip connection을 filtering해서 중요한 부분만을 주목해서 통과시키는 부분.
transformer attention에서 영감을 받은 "attention units"
저자는 attention units을 설명하는 마지막 부분에서, " Inspired by the success of attention mechanism, both in NLP and computer vision tasks,
we implemented the attention block in the decoder part of our
architecture to be able to focus on the essential areas of the
feature maps."이라는 샤라웃과 함께 영감을 얻은 출처를 밝히고 있다.
Encoder Feature Map ----┐
│ (skip)
▼
[Attention Unit] ---> filtered feature → decoder
Decoder Feature Map ----┘ (gating signal)
def attetion_block(g, x):
"""
g: Output of Parallel Encoder block
x: Output of Previous Decoder block
"""
filters = x.shape[-1]
g_conv = BatchNormalization()(g)
g_conv = Activation("relu")(g_conv)
g_conv = Conv2D(filters, (3, 3), padding="same")(g_conv)
g_pool = MaxPooling2D(pool_size=(2, 2), strides=(2, 2))(g_conv)
x_conv = BatchNormalization()(x)
x_conv = Activation("relu")(x_conv)
x_conv = Conv2D(filters, (3, 3), padding="same")(x_conv)
gc_sum = Add()([g_pool, x_conv])
gc_conv = BatchNormalization()(gc_sum)
gc_conv = Activation("relu")(gc_conv)
gc_conv = Conv2D(filters, (3, 3), padding="same")(gc_conv)
gc_mul = Multiply()([gc_conv, x])
return gc_mul
Channel Attention : Squeeze and Excitation Units(어쩌면 transformer attention mechanism이 계승했을 지도 모르는)
Spatial Attention : Attention Units(공식적으로 attention mechanism을 계승해 공간적 중요도를 주목하는 법을 적용시킨)
Multi-scale feature extractor : Astrous Spatial Pyramidal Pooling(다양한 스케일의 feature를 뽑아 인식하는)
ResUNet++는 Sementic Segmentation의 중요 모델인 UNet의 여러 후속작들(UNet, ResUNet-a, Attention UNet 등) 에서 나온 여러 구조를 Medical Segmentation Model에 적합하게 조합하여 좋은 성능을 기록한 모델이라고 볼 수 있는데 특히 어떤 부분을 더 잘 주목할지를 판단하는 attention mechanism을 잘 적용했다고 개인적으로 평가할 수 있을 것 같다.
- U-Net: Convolutional Networks for Biomedical Image Segmentation(arXiv:1505.04597)
- Squeeze-and-Excitation Networks (arXiv:1709.01507v4)
- ResUNet-a: a deep learning framework for semantic segmentation of remotely sensed data(arXiv:1904.00592v)
- ResUNet++: An Advanced Architecture for Medical Image Segmentation(arXiv:1911.07067v1)
- Attention U-Net: Learning Where to Look for the Pancrea(arXiv:1804.03999v)
- https://github.com/DebeshJha/ResUNetPlusPlus
- https://github.com/DebeshJha/ResUNetplusplus-PyTorch-