Related to: Deep Learning
배경
당시 연구결과에 따르면 네트워크의 깊이는 매우 중요한데, 실제로 많은 모델들이 깊은 네트워크를 통해 좋은 성능을 보였다고 합니다.
Network의 Depth가 중요해지면서, layer를 많이 쌓았을 때 발생하는 Vanishing / Exploding gradient 현상은 큰 방해 요소였습니다.
ResNet이란?

ResNet은 컴퓨터 비전 관련 딥러닝 모델로, 2015년 ImageNet 대회에서 우승한 모델입니다.
ResNet은 각 레이어에서 입력 데이터를 단순화하고 보다 정확하게 분류하기 위해 특별한 구조인 Skip-Connection를 사용합니다. Skip-Connection은 모델이 보다 깊은 레이어를 학습하고 잘 작동할 수 있게 해줍니다.
ResNet의 특징

Shortcut connection을 도입하여 기존보다 더 깊게 층을 쌓을 수 있게 되었습니다.
- 기존 네트워크는 입력 x를 받고 layer를 거쳐 H(x)를 출력하는데, 이는 입력값 x를 타겟값 y로 mapping 하는 함수 H(x)를 얻는 것이 목적입니다.
- 하지만 ResNet의 Residual Learning은 H(x)가 아닌 출력과 입력의 차인 H(x) - x를 얻도록 목표를 수정했습니다.

- 곱셈 연산에서 덧셈 연산으로 변형되어 몇 개의 layer를 건너뛰는 효과가 있었는데, 이 덕에 forward와 backward path가 단순해지는 효과가 있었으며, gradient의 소멸 문제를 해결 할 수 있었다고 합니다.
ResNet 구현
-
ConvBlock
class ConvBlock(nn.Module): def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1): super().__init__() #\#fill it## self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding) # kernel size = ... self.batchnorm = nn.BatchNorm2d(out_channels) def forward(self, x): #\#fill it## x = self.conv(x) x = self.batchnorm(x) return x -
ResBlock
class ResBlock(nn.Module): def __init__(self, in_channels, out_channels, pool_stride = 1): super().__init__() self.kernel_size = 3 self.padding = 1 self.stride = 1 self.relu = nn.ReLU() self.pool_stride = pool_stride self.in_channels = in_channels self.out_channels = out_channels if(in_channels == out_channels): self.skip = torch.nn.Identity() else: self.skip = torch.nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=self.pool_stride) self.conv1 = ConvBlock(in_channels=in_channels, out_channels = out_channels, kernel_size=self.kernel_size, stride=self.stride, padding=self.padding) self.conv2 = ConvBlock(in_channels=out_channels, out_channels = out_channels, kernel_size=self.kernel_size, stride=self.pool_stride, padding=self.padding) def forward(self, x): #\#fill## y = self.conv1(x) y = self.relu(y) y = self.conv2(y) return self.relu(y + self.skip(x)) -
Resnet Model
class ResNet(nn.Module): def __init__(self, in_channels, out_channels, nker=64, nblk=[3,4,6,3]): super(ResNet, self).__init__() self.enc = ConvBlock(in_channels, nker, kernel_size=7, stride=2, padding=1) self.max_pool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.average_pool = nn.AvgPool2d(kernel_size=5, stride=1) #\#fill## self.relu = nn.ReLU() layers = [] for j, b in enumerate(nblk): __out_chennel = 64 * (j+1) for i in range(b): if(j != 0 and i == 0): __pool_stride = 2 __in_chennel = 64 * j else: __pool_stride = 1 __in_chennel = __out_chennel print(__in_chennel, __out_chennel, __pool_stride) layers.append(ResBlock(__in_chennel, __out_chennel, __pool_stride)) print('complete auto layer making') self.conv = nn.Sequential(*layers) self.fc = nn.Linear(nker*2*2, 10) def forward(self, x): x = self.enc(x) x = self.max_pool(x) #\#fill## x = self.conv(x) x = self.average_pool(x) x = x.view(x.shape[0], -1) out = self.fc(x) return out
참조
https://arxiv.org/abs/1512.03385
https://phil-baek.tistory.com/entry/ResNet-Deep-Residual-Learning-for-Image-Recognition-논문-리뷰