본문 바로가기

STUDY/인공지능

[딥러닝] ResNet이란? 예제 코드 tensorflow, pytorch

728x90

ResNet은 "Residual Network"의 줄임말로, 딥 러닝 모델의 한 종류입니다. ResNet은 2015년에 발표된 기법으로, 깊은 신경망에서 발생하는 그레디언트 소실 문제를 해결하고, 더 깊은 네트워크를 효과적으로 학습할 수 있도록 도와줍니다.

 

장점:

  1. 깊은 네트워크 학습 가능성: ResNet은 스킵 연결(skip connection)을 사용하여 그레디언트 소실 문제를 완화합니다. 이를 통해 매우 깊은 신경망도 효과적으로 학습할 수 있습니다.
  2. 효율적인 학습: ResNet은 학습 과정에서 더 빠르게 수렴할 수 있습니다. 스킵 연결은 정보의 흐름을 원활하게 만들어주고, 그레디언트가 잘 전달되어 경사 하강법의 수렴을 도와줍니다.
  3. 정확도 향상: ResNet은 깊은 네트워크를 학습할 수 있어서, 복잡한 데이터셋에서 높은 정확도를 달성할 수 있습니다.

단점:

  1. 모델 복잡성: ResNet은 일부 잔차 블록에서 추가되는 스킵 연결 때문에 모델의 복잡성이 증가할 수 있습니다. 이는 모델의 파라미터 수를 늘리고 계산 비용을 증가시킬 수 있습니다.
  2. 메모리 요구량: 깊은 ResNet 모델은 많은 수의 레이어를 포함하므로, 메모리 요구량이 높아질 수 있습니다. 특히 GPU 메모리가 제한적인 경우에는 고려해야 할 사항입니다.
  3. 과적합 가능성: 깊은 네트워크의 경우, 훈련 데이터에 대한 과적합이 발생할 수 있습니다. 이를 방지하기 위해 드롭아웃(dropout) 등의 정규화 기법을 사용하는 것이 중요합니다.

 

예시 코드 Tensorflow:

입력 이미지는 32x32 크기이고, 10개의 클래스를 분류하는 모델을 생성합니다. Residual block은 3개로 구성되어 있으며, 각각 64개의 필터를 사용합니다.

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, Add

def residual_block(input_tensor, filters):
    x = Conv2D(filters, (3, 3), padding='same')(input_tensor)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = Conv2D(filters, (3, 3), padding='same')(x)
    x = BatchNormalization()(x)
    x = Add()([x, input_tensor])
    x = Activation('relu')(x)
    return x

def create_resnet(input_shape, num_classes):
    inputs = tf.keras.Input(shape=input_shape)
    x = Conv2D(64, (7, 7), strides=(2, 2), padding='same')(inputs)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = residual_block(x, 64)
    x = residual_block(x, 64)
    x = residual_block(x, 64)
    x = tf.keras.layers.GlobalAveragePooling2D()(x)
    outputs = tf.keras.layers.Dense(num_classes, activation='softmax')(x)
    model = tf.keras.Model(inputs=inputs, outputs=outputs)
    return model

# 예시: 32x32 크기의 이미지에 대한 ResNet 모델 생성
model = create_resnet((32, 32, 3), 10)

 

예제 코드 pytorch:

BasicBlock은 ResNet의 기본 블록을 정의하고, ResNet 클래스에서 레이어를 구성합니다. 모델은 CIFAR-10 데이터셋과 같은 32x32 크기의 이미지에 대해 10개의 클래스를 분류합니다. 코드는 PyTorch의 nn.Module을 상속받아 모델을 구현하고, 각 레이어와 스킵 연결 등이 정의되어 있습니다.

import torch
import torch.nn as nn
import torch.nn.functional as F

class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels)
            )
        
    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out += self.shortcut(x)
        out = F.relu(out)
        return out

class ResNet(nn.Module):
    def __init__(self, block, num_blocks, num_classes=10):
        super(ResNet, self).__init__()
        self.in_channels = 64
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
        self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
        self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
        self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
        self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
        self.fc = nn.Linear(512, num_classes)
        
    def _make_layer(self, block, out_channels, num_blocks, stride):
        layers = []
        layers.append(block(self.in_channels, out_channels, stride))
        self.in_channels = out_channels
        for _ in range(1, num_blocks):
            layers.append(block(out_channels, out_channels))
        return nn.Sequential(*layers)
    
    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.avgpool(out)
        out = torch.flatten(out, 1)
        out = self.fc(out)
        return out

# ResNet-18 모델 생성
model = ResNet(BasicBlock, [2, 2, 2, 2], num_classes=10)
728x90