딥러닝은 머신러닝의 하위 분야로, 인공신경망(Artificial Neural Networks)을 활용하여 데이터를 학습하는 기술이다.
여러 층의 신경망을 쌓아올려 복잡한 패턴을 학습할 수 있다는 게 특징이다. 특히 컴퓨터 비전, 자연어 처리, 음성 인식 등의 분야에서 뛰어난 성능을 보여준다.
딥러닝의 구조적 이해
딥러닝의 구조를 제대로 이해하기 위해서는 층층이 쌓여있는 각 요소들의 역할을 알아야 한다.
1. 입력층 (Input Layer)
출처: 합성곱 신경망의 기본 개념
입력층은 데이터가 처음 들어오는 곳이다. 예를 들어:
- 이미지의 경우: 픽셀 값들이 입력된다 (224x224 크기 이미지면 50,176개의 뉴런)
- 텍스트의 경우: 단어나 문자의 수치화된 값이 들어간다
- 숫자 데이터의 경우: 정규화된 수치들이 입력된다
# 입력 데이터 준비 예시
x = torch.randn(32, 3, 224, 224) # 배치크기 32, RGB 3채널, 224x224 이미지
입력 데이터는 항상 전처리가 필요하다. 정규화(Normalization)나 스케일링(Scaling)은 모델 학습에 매우 중요한 영향을 미친다.
2. 은닉층 (Hidden Layer)
출처: 다층 신경망 이해하기
은닉층은 딥러닝의 심장이라고 할 수 있다. 필자가 생각하기에 가장 신비로운 부분이다.
class DeepNN(nn.Module):
def __init__(self):
super().__init__()
self.hidden1 = nn.Linear(784, 256) # 첫 번째 은닉층
self.hidden2 = nn.Linear(256, 128) # 두 번째 은닉층
self.hidden3 = nn.Linear(128, 64) # 세 번째 은닉층
self.output = nn.Linear(64, 10) # 출력층
def forward(self, x):
x = F.relu(self.hidden1(x))
x = F.relu(self.hidden2(x))
x = F.relu(self.hidden3(x))
return self.output(x)
은닉층의 특징:
- 다양한 크기: 각 층의 뉴런 수는 자유롭게 설정할 수 있다
- 활성화 함수: 각 층 뒤에는 보통 활성화 함수가 붙는다
- 가중치와 편향: 각 층은 학습 가능한 파라미터를 가진다
은닉층의 개수와 각 층의 크기를 결정하는 것은 일종의 예술이다. 너무 작으면 학습이 부족하고, 너무 크면 과적합이 일어난다.
3. 출력층 (Output Layer)
출처: 순환 신경망의 구조
출력층은 모델의 최종 예측을 만들어내는 곳이다. 문제의 종류에 따라 다양한 형태를 가질 수 있다.
- 분류 문제:
# 다중 클래스 분류
self.output = nn.Linear(hidden_size, num_classes)
output = F.softmax(self.output(x), dim=1)
# 이진 분류
self.output = nn.Linear(hidden_size, 1)
output = torch.sigmoid(self.output(x))
- 회귀 문제:
self.output = nn.Linear(hidden_size, 1) # 단순 선형 출력
딥러닝의 학습 메커니즘
1. 가중치 초기화
가중치 초기화는 생각보다 중요하다.
def weight_init(m):
if isinstance(m, nn.Linear):
nn.init.xavier_uniform_(m.weight)
nn.init.zeros_(m.bias)
model.apply(weight_init) # 모델의 모든 층에 가중치 초기화 적용
Xavier 초기화는 가장 널리 쓰이는 방법 중 하나다. 층이 깊어져도 기울기가 폭발하거나 사라지는 것을 방지해준다.
2. 손실 함수 (Loss Function)
손실 함수는 모델이 얼마나 잘못 예측했는지 측정하는 기준이다. 필자는 이걸 '모델의 성적표'라고 생각한다.
# 다양한 손실 함수들
criterion_bce = nn.BCELoss() # 이진 분류
criterion_ce = nn.CrossEntropyLoss() # 다중 분류
criterion_mse = nn.MSELoss() # 회귀
각각의 특징:
- BCE: 이진 분류에 사용, 0~1 사이의 예측값 필요
- CrossEntropy: 다중 분류의 표준, 소프트맥스와 짝꿍
- MSE: 회귀 문제에서 가장 기본적인 손실 함수
3. 옵티마이저 (Optimizer)
옵티마이저는 손실을 바탕으로 모델의 파라미터를 업데이트하는 방법을 결정한다.
# 다양한 옵티마이저
optimizer_sgd = optim.SGD(model.parameters(), lr=0.01)
optimizer_adam = optim.Adam(model.parameters(), lr=0.001)
optimizer_rmsprop = optim.RMSprop(model.parameters(), lr=0.001)
솔직히 말하면, 대부분의 경우 Adam을 쓰면 잘 동작한다. 하지만 각각의 장단점을 아는 것도 중요하다:
- SGD: 가장 기본적인 방법, 노이즈가 심하다
- Adam: 대부분의 경우에 잘 작동, 하이퍼파라미터 튜닝이 비교적 쉽다
- RMSprop: Adam과 비슷하지만, 모멘텀을 사용하지 않는다
마치며
이렇게 딥러닝의 구조를 자세히 살펴보았다. 필자도 이걸 처음 배울 때는 정말 어려웠는데, 하나씩 이해하다 보니 이제는 꽤 재미있게 느껴진다. 다른 분들도 꼭 한번 도전해보시길 바란다.
다음 글에서는 실제 프로젝트에서 딥러닝을 어떻게 활용하는지, 그리고 자주 마주치는 문제들의 해결 방법에 대해 다뤄보려고 한다.