본문 바로가기
AI/인공지능(CNN)

[인공지능] 잔차 신경망(ResNet)으로 기울기 소실 문제 해결

by Yoon_estar 2025. 10. 30.
728x90
반응형

개요

잔차 신경망(ResNet, Residual Network)은 2015년 Microsoft Research 팀에 의해 소개된 혁신적인 딥러닝 모델입니다. 이 모델은 네트워크의 층이 깊어질수록 오히려 성능이 저하되는 성능 저하(Degradation) 문제와 기울기 소실(Vanishing Gradient) 문제를 해결하기 위해 고안되었습니다. ResNet은 잔차 학습(Residual Learning)이라는 단순하지만 강력한 아이디어를 통해, 150층 이상의 깊은 신경망에서도 안정적으로 학습하고 뛰어난 성능을 발휘하여 현재까지도 컴퓨터 비전 분야의 핵심 기술로 사용되고 있습니다. 

깊이의 한계를 뛰어넘는 잔차 학습

ResNet의 핵심은 Residual Learning입니다. 기존 신경망이 입력 $x$에 대해 원하는 최종 출력 $H(x)$ 전체를 학습하려 했다면, ResNet은 $H(x)$ 대신 잔차함수 $F(x) = H(x) - x$ 를 학습하는 것을 목표로 합니다. 

수식으로 표현하면 다음과 같습니다. 

$$H(x) = F(x) + x$$

신경망이 $F(x)$를 0으로 학습하는 것이 $H(x)$ 전체를 학습하는 것보다 훨씬 쉽습니다. 만약 여러 층을 거쳐도 입력 $x$의 정보가 가장 최적의 상태라면, 네트워크는 $F(x) = 0$을 학습하기만 하면 되기 때문입니다.  즉, 네트워크는 입력 $x$에서 추가적으로 필요한 미세한 조정 $F(x)$만을 학습하게 됩니다. 


용어 정리

잔차(Residual)

  • 예측값과 실측값의 차이로 생기는 부분에 대한 느낌이나 생각의 짜임새의 뜻을 나타내는 말(사용자 제공 정의). 통계학 및 수학에서는 실제 값과 예측 값의 차이, 즉 오차를 의미합니다. 
  • 입력 $x$가 신경망 블록을 통과한 출력 $H(x)$와 입력 $x$ 자체의  차이, $F(x) = H(x) -x$를 잔차 함수라고 부릅니다. ResNet은 이 잔차함수 $F(x)$를 학습합니다. 

기울기 소실(Vanishing Gradient)

  • 딥러닝 모델의 층이 깊어질수록 역전파(Backpropagation) 과정에서 오차를 전달하는 기울기(Gradient)가 0에 가까워져 앞쪽 층의 가중치(Weight)들이 거의 업데이트되지 않는 현상. 이로 인해 학습이 정체되거나 중단됩니다. 
  • 1번부터 100번까지의 문제를 푼다고 하면 100번을 풀 땐 앞의 문제의 기억이 희미해질 것입니다. 즉 기억(기울기)이 희미해지는 현상입니다.


사용 사례 및 예시

ResNet은 컴퓨터 비전 분야의 "백본(backbone)" 모델로 불릴 만큼 광범위하게 사용됩니다. 

사용 분야 설명 및 예시
이미지 분류(Image Classification) ILSVRC(ImageNet Large Scale Visual Recognition Challenge)에서 압도적인 우승을 차지하며 그 성능을 입증했습니다. ResNet-50, ResNet-101 등이 기본 분류기로 사용됩니다.
객체 탐지(Object Detection) YOLO, Faster R-CNN, Mask R-CNN 등의 모델에서 이미지 특징을 추출하는 기본 모듈(Feature Extractor)로 활용되어 사물의 위치와 종류를 정확하게 파악합니다.
시맨틱/인스턴스 분할(Segmentation) 이미지의 각 픽셀을 분류하는 작업(예: 하늘, 건물, 사람)에서 정교한 특징 추출을 위해 ResNet이 사용됩니다.
전이 학습(Transfer Learning) ImageNet 데이터셋으로 사전 학습된 ResNet 모델의 가중치를 가져와 의료 영상 분석, 드론 이미지 분석 등 다양한 분야에 적용하여 높은 효율을 얻습니다.

 

이해를 위한 실생활 예시

실생활 예시 : 문제풀이 기억법

일반적으로 딥러닝(Plain Network) : 100개의 문제를 풀 때, 1번 문제를 풀고 100번 문제를 풀면 1번 문제에서 얻은 정보를 잊게 되어 가중치(지식)를 수정할 수 없습니다. 이것이 기울기 소실입니다.

잔차 신경망(ResNet)

1번 문제를 풀고, 채점한 기억을 2번 문제를 풀 때 기억을 더해서 진행합니다. 마찬가지로 1번 문제의 정답과 풀이 과정을 스킵 커넥션으로 100번의 문제 풀이에 직접 전달합니다. 100번 문제의 답이 틀렸을 때, 1번 문제의 기억이 명확하게 남아있기 때문에, 1번 문제풀이의 어떤 부분이 잘못되었는지 정확하게 역추적하여 가중치(지식)를 효율적으로 수정할 수 있습니다. 


실제 작동 원리 및 예시 : 잔차 블록(Residual Block)

작동 원리 : 스킵 커넥션(Skip Connection)

잔차 블록은 여러 개의 컨볼루션 레이어 $F(x)$로 이루어진 메인 경로와 입력 $x$를 곧바로 출력에 더해주는 스킵 커넥션(Shortcut Connection)으로 구성됩니다. 

  • 입력 $x$ : 입력 데이터가 들어옵니다.
  • 메인 경로 $F(x):x$ 가 컨볼루션, 배치 정규화(Batch Normalization), 활성화 함수(ReLU)를 거쳐 $F(x)$가 계산됩니다. 
  • 결합 : 메인 경로의 출력 $F(x)$와 스킵 커넥션으로 전달된 원본 입력 $x$를 더합니다. $H(x) = F(x) + x$
  • 최종 출력 $H(x) : 이 결과에 최종적으로 ReLU 활성화 함수를 적용하여 다음 블록으로 전달합니다.

왜 사용하는지(기울기 소실 문제 해결)

매우  깊은 신경망에서도 기울기 소실 문제를 효과적으로 해결하여 더 높은 정확도와 성능을 제공하는 딥러닝 모델을 구축할 수 있기 때문에 사용합니다.

왜 필요한가(Degradation 문제 해결)

신경망 층을 단순하게 깊이 쌓기만 하면 발생하는 성능 저하(Degradation) 문제를 해결하기 위해 필요합니다. ResNet 이전에는 층을 깊게 쌓을수록 오히려 에러율이 높아지는 현상이 있었습니다. ResNet은 잔차 학습을 통해 이 문제를 해결하고, 딥러닝 모델의 잠재력을 극대화할 수 있게 해 주었습니다.

언제 사용하는지

이미지 데이터 기반의 고성능 컴퓨터 비전 모델을 구축할 때 표준적으로 사용됩니다. 

어떻게 사용할 건지

ResNet은 깊이에 따라 ResNet-18, ResNet-34, ResNet-50, ResNet-101, ResNet-152 등 다양한 버전이 있습니다. 프로젝트의 규모와 요구되는 성능에 따라 적절한 깊이의 모델을 선택하여 사용합니다. 


예시 코드(Tensor Flow-Keras)

라이브러리 임포트

  • tensorflow.keras.applications : 사전 훈련된 모델들을 제공하는 모듈 아래 코드에선 ResNet50을 사용
  • Sequential : 순차적인 모델을 만드는 데 사용되는 Keras 클래스. 레이어를 순차적으로 쌓을 수 있음
  • Dense : 완전 연결층(fully connected layer)을 정의하는 Keras 레이어 클래스. 
  • Flatten, GlobalAveragePooling2D : 데이터를 평탄화하거나 풀링 하는 레이어 클래스
  • Adam : Adam 최적화 알고리즘을 제공하는 클래스
  • to_categorical : 정수 인코딩된 레이블을 원-핫 인코딩 형식으로 변환하는 유틸리티 함수
  • numpy : 파이썬에서 배열을 다루는 데 사용되는 라이브러리
from tensorflow.keras.applications import ResNet50
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, GlobalAveragePooling2D
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical
import numpy as np

 

가상 데이터셋 생성

  • num_classes : 분류할 클래스의 수
  • input_shape : 입력 이미지의 형태 (224, 224, 3)은 224x224 크기의 RGB 이미지
  • x_train, x_test : 각각 1000개와 200개의 가상훈련 및 테스트 이미지를 생성
  • y_train, y_test : 0부터 num_classes 사이의 정수로 구성된 가상 레이블을 생성
  • to_categorical : 레이블을 원-핫 인코딩 형식으로 변환
num_classes = 10
input_shape = (224, 224, 3)

x_train = np.random.random((1000, 224, 224, 3))
y_train = np.random.randint(num_classes, size=(1000, 1))

x_test = np.random.random((200, 224, 224, 3))
y_test = np.random.randint(num_classes, size=(200, 1))

y_train = to_categorical(y_train, num_classes)
y_test = to_categorical(y_test, num_classes)

 

사전 훈련된 ResNet50 모델 로드

  • ResNet50 : ImageNet 데이터셋으로 사전 훈련된 ResNet50 모델을 로드합니다. 
  • include_top=False : 상단의 완전 연결층을 제외합니다. 이는 특성 추출 용도로만 사용하겠다는 의미입니다. 
  • input_shape : 입력 이미지의 형태를 정의합니다. 
base_model = ResNet50(weights=None, include_top=False, input_shape=input_shape)

 

새로운 모델 구축

  • Sequential : 순차 모델을 초기화합니다. 
  • model.add(base_model) : 사전 훈련된 ResNet50 모델을 추가합니다. 
  • GlobalAveragePooling2D : 2D 풀링 레이어를 추가하여 출력 특징 맵을 평균화 합니다. 
  • Dense(256, activation='relu') : 256개의 유닛을 가진 완전 연결층을 추가합니다. 활성화 함수는 ReLU입니다. 
  • Dense(num_classes, activation='softmax') : 클래스 수만큼의 유닛을 가진 출력층을 추가합니다. 활성화 함수는 소프트맥스입니다. 이는 다중 클래스 분류를 위한 출력층입니다. 
model = Sequential()
model.add(base_model)
model.add(GlobalAveragePooling2D())
model.add(Dense(256, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

 

모델 컴파일

  • optimizer=Adam(learning_rate=0.0001):Adam 최적화 알고리즘을 사용합니다. 학습률은 0.0001입니다. 
  • loss='categorical_crossentropy' : 다중 클래스 분류 문제에 적합한 손실 함수인 범주형 교차 엔트로피를 사용합니다. 
  • metrics=['accuracy'] : 모델의 성능을 평가할 지표로 정확도를 사용합니다. 
model.compile(optimizer=Adam(learning_rate=0.0001), loss='categorical_crossentropy', metrics=['accuracy'])

 

모델 평가

  • x_test, y_test : 테스트 데이터와 레이블을 제공
  • model.evaluate : 테스트 데이터에 대해 모델을 평가, 손실과 정확도를 반환
  • print : 평과 결과 출력
loss, accuracy = model.evaluate(x_test, y_test)
print(f"Test loss: {loss}")
print(f"Test accuracy: {accuracy}")
반응형