관리 메뉴

Bull

[DL/CNN] ResNet (Residual Network) 본문

Artificial Intelligence/Deep Learning

[DL/CNN] ResNet (Residual Network)

Bull_ 2024. 3. 16. 21:47

개요


ResNet(Residual Network)은 깊은 신경망의 학습을 용이하게 만들기 위해 개발된 아키텍처다.

 

이 모델은 2015년에 Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun에 의해 개발되었으며,

 

"Deep Residual Learning for Image Recognition"이라는 논문을 통해 소개되었다.

 

ResNet은 깊은 신경망이 가지는 주요 문제점 중 하나인 기울기 소실 문제를 해결하는 데 초점을 맞춘다.

핵심 개념


잔차 블록(Residual Blocks)

ResNet의 핵심은 "잔차 블록"이라고 불리는 구조에 있다.

 

그림과 같이 잔차를 기준으로 다시 학습하고, 그것을 원본에 더한다고(스킵연결) 생각하면 된다.

$H(x)=F(x)+x$를 만족하며,

 

$H(x)$: 최종출력

$F(x)$: 잔차

$x$: 예측값 + 학습된 잔차 (검은부분)

 

이 블록은 입력을 블록의 출력에 직접 더하는 스킵 연결(skip connection) 을 포함한다.

스킵 연결(Skip Connections)

스킵 연결은 잔차 블록의 입력을 한 개 이상의 레이어를 건너뛰고 출력과 직접 연결한다.

 

이는 역전파 시에 기울기가 사라지거나 폭발하는 문제를 완화시켜 준다.

구조


출처: https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/He_Deep_Residual_Learning_CVPR_2016_paper.pdf


각각은 레이어의 수와 구조적 복잡성이 다르다. 가장 대표적인 변형은 다음과 같다.

ResNet-18, ResNet-34

비교적 간단한 구조로, 일반적인 작업에 적합하다.

ResNet-50, ResNet-101, ResNet-152

이 변형들은 "병렬 블록"을 사용하여 더 깊고 복잡한 모델을 구현한다.

 

이들은 더 많은 계산을 요구하지만, 복잡한 이미지 분류 문제에서 더 좋은 성능을 제공한다.

간단한 Residual Learning 코드 구현


 

 

import tensorflow as tf
from tensorflow.keras import layers, models

def residual_block(input_layer, num_filters):
    """간단한 잔차 블록 구현"""
    # 첫 번째 컨볼루션 레이어 + 배치 정규화 + ReLU 활성화
    x = layers.Conv2D(num_filters, kernel_size=3, padding='same')(input_layer)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
    
    # 두 번째 컨볼루션 레이어 + 배치 정규화
    x = layers.Conv2D(num_filters, kernel_size=3, padding='same')(x)
    x = layers.BatchNormalization()(x)
    
    # 스킵 연결을 추가하고 ReLU 활성화 적용
    x = layers.Add()([x, input_layer])
    x = layers.ReLU()(x)
    
    return x

# 모델 입력 정의
input_layer = layers.Input(shape=(32, 32, 3)) # 32x32 크기의 이미지

# 간단한 잔차 블록을 사용
x = residual_block(input_layer, num_filters=64)

# 간단한 분류를 위한 레이어 추가
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(10, activation='softmax')(x) # CIFAR-10에는 10개의 클래스가 있음

# 모델 생성
model = models.Model(inputs=input_layer, outputs=x)

model.summary()

 

1. 모델 제시 및 학습 시작

# 모델 입력 정의
input_layer = layers.Input(shape=(32, 32, 3)) # 32x32 크기의 이미지

# 간단한 잔차 블록을 사용
x = residual_block(input_layer, num_filters=64)

2. 잔차인 F(x), 여기서는 변수 x 학습시키기

# 첫 번째 컨볼루션 레이어 + 배치 정규화 + ReLU 활성화
x = layers.Conv2D(num_filters, kernel_size=3, padding='same')(input_layer)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)

# 두 번째 컨볼루션 레이어 + 배치 정규화
x = layers.Conv2D(num_filters, kernel_size=3, padding='same')(x)
x = layers.BatchNormalization()(x)

3. 스킵연결, 즉 h(x) = F(x)+x 해주는 것.

# 스킵 연결을 추가하고 ReLU 활성화 적용
x = layers.Add()([x, input_layer])
x = layers.ReLU()(x)