Residual Block은 2015년 발표된 paper "Deep Residual Learning for Image Recognition" 의 model architecture인 ResNet의 주요 아이디어 입니다.
ResNet은 2015년 COCO competitions 를 비롯한 Computer Vision 분야에서만 무려 5개 영역에서 1위를 달성할정도로 혁신적인 model이었습니다.
물론 ResNet보다 좋은 성능을 보이는 model이 계속해서 등장했지만, Residual Block은 다른 model에서도 계속해서 쓰이고 있습니다.
Residual Block

Residual Block은 Deep learning model들의 layer 수가 증가하는 시기에 등장했습니다.
Layer 수 늘리기는 마법이 아니어서, 무조건 늘린다고 정확도가 증가하지 않습니다.
Gradient Vanishing, Curse of Dimensionality, Over fitting 등의 문제가 깊어진 Deep learning models에서 나타나면서, 이를 해결하기 위한 방법으로 Residual Block은 등장했습니다.
Residual Block은 일반적인 layer, 속칭 Plane layer와는 다르게 Output에 자기자신, Identity를 더한다는 특징이 있습니다.
이러한 특징 때문에, Residual Block은 마음만 먹으면, 해당 Block의 weight=0로 하여 항등함수로서 작용할 수 있고, 이를 통해 깊어진 신경망이 비교적 간단해질 수 있습니다.
항등함수로 작용할 거면 해당 Layer가 애초에 필요없는 것이 아니냐는 의문이 생길 수 있는데, 어떤 Layer가 유용할지 아닐지는 학습중에 정해지는 것이기 때문에, 신경망이 스스로 필요없는 Layer를 항등함수로 만들 수 있게 하는 것만으로 좋은 결과를 얻을 수 있는 것입니다.
Residual Block Pytorch Code
1. Input으로 x를 받습니다.
2. Convolution → Relu → Convolution 순서로 연산합니다.
3. 2에서 얻은 output과 x를 더합니다.
4. Relu 함수를 통과합니다.
위의 과정을 거쳐서 나온 최종 Output이 Residual Block의 Output입니다. 말로 설명한 것을 참고하여, pytorch로 구현한 Residual Block을 보겠습니다.
import torch.nn as nn
class Residual_Blcok(nn.Module):
def __init__(self, in_channels, out_channels):
super(Residual_Blcok, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1, stride=1)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, stride=1)
self.relu = nn.ReLU()
def forward(self, x):
out = self.conv1(x)
out = self.relu(x)
out = self.conv2(x)
out = out + x # identity
out = self.relu(x)
return out
코드는 크게 __init__과 forward로 나누어져 있습니다.
__init__은 필요한 Convolution과 Activation Function Relu를 정의합니다.
forward는 정의한 함수를 이용해서 Residual Block의 순서에 맞게 진행합니다.
하지만, 위 코드는 이해하기 좋게 하기위해서 Batch Normalization을 생략하였습니다.
ResNet은 Convolution을 할 때 마다 Batch Normalization을 적용해야 합니다.
import torch.nn as nn
class Residual_Blcok(nn.Module):
def __init__(self, in_channels, out_channels):
super(Residual_Blcok, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1, stride=1)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, stride=1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU()
def forward(self, x):
out = self.conv1(x)
out = self.bn1(x)
out = self.relu(x)
out = self.conv2(x)
out = self.bn2(x)
out = out + x # identity
out = self.relu(x)
return out
ResNet
ResNet Architecture은 이러한 Residual Blocks가 많이 쌓여있는 형태입니다.
앞서 말했듯이, 각각의 Residual Block은 두 개의 3×3 conv layers를 포함합니다.
ResNet은 간헐적으로 이 Convolution의 Filter의 숫자를 두 배로 늘리고, stride 2를 이용하여 Down Sampling을 수행하는 점이 특징입니다.
아래 Architecture를 자세히 보면, Filter의 수가 2배로 늘때마다 뒤에 /2가 붙어있는 것을 확인할 수 있습니다. 이는 파라미터의 수가 너무 늘어나는 것을 방지하기 위함입니다.

그 외의 특징으로는 시작시 7x7 Convolution을 수행하고 시작한다는 점, 시작과 끝에 Average Pooling을 진행한다는 점이 있습니다.
ResNet Github 원문
https://github.com/KaimingHe/deep-residual-networks
GitHub - KaimingHe/deep-residual-networks: Deep Residual Learning for Image Recognition
Deep Residual Learning for Image Recognition . Contribute to KaimingHe/deep-residual-networks development by creating an account on GitHub.
github.com