딥러닝(Deep Learning)의 본질: '깊은' 신경망의 힘

딥러닝은 단순히 '데이터를 넣으면 결과가 나오는 상자'가 아니라, 인간의 뇌 속 신경세포인 뉴런(Neuron)이 신호를 전달하는 방식을 수학적으로 모방한 모델입니다. 수많은 뉴런층을 쌓아 올렸기 때문에 '깊다(Deep)'는 표현을 사용하며, 이를 통해 기계가 스스로 데이터의 복잡한 특징을 추출하게 됩니다.

1-1. 핵심 연산: 가중치(W)와 편향(b)의 춤

신경망의 각 층에서는 다음과 같은 수학적 연산이 일어납니다.

  • 가중치 (W, Weight): 입력 데이터($x$)가 결과에 미치는 영향력(중요도)을 결정합니다. 학습의 목표는 최적의 W값을 찾는 것입니다.
  • 편향 (b, Bias): 뉴런이 얼마나 쉽게 활성화될지를 조절하는 민감도 역할을 합니다.
  • 가합산: 모든 입력값에 가중치를 곱하고 편향을 더해 하나의 값으로 모읍니다.

1-2. 활성화 함수 (Activation Function): 신경망에 '생명'을 불어넣기

단순히 W*x+b만 계산하면 아무리 층을 많이 쌓아도 결국 하나의 직선(선형) 모델일 뿐입니다. 복잡한 곡선 형태의 데이터를 학습하기 위해 비선형성을 추가하는 도구가 바로 활성화 함수입니다.

  • Sigmoid: 출력값을 0과 1 사이로 압축합니다. 주로 이진 분류의 출력층에서 확률을 나타낼 때 사용합니다.
  • ReLU (Rectified Linear Unit): 0보다 작으면 0을, 크면 그대로 출력합니다. 연산이 빠르고 성능이 좋아 현대 딥러닝의 은닉층에서 가장 많이 쓰입니다.
  • Softmax: 여러 개의 선택지 중 하나를 고르는 다중 분류 문제에서 각 선택지의 확률 합이 1이 되도록 만듭니다.

1-3. 손실 함수 (Loss Function): "얼마나 틀렸니?"

모델의 예측값(y^)과 실제 정답(y) 사이의 거리를 측정하는 지표입니다.

  • MSE (Mean Squared Error): 예측값과 정답의 차이를 제곱하여 평균을 냅니다. 주로 회귀(값 예측) 문제에 쓰입니다.
  • Binary Cross Entropy (BCE): 이진 분류에서 사용됩니다. 정답이 1인데 모델이 0에 가깝게 예측할수록 손실값을 기하급수적으로 키워 강하게 벌을 줍니다.

1-4. 최적화 (Optimization): 오답 노트를 통한 성장

손실 함수를 통해 계산된 오차를 줄여나가는 과정입니다.

  1. 순전파 (Forward Propagation): 데이터를 입력하여 예측값을 계산합니다.
  2. 역전파 (Backpropagation): 출력층에서 발생한 오차를 입력층 방향으로 거슬러 올라가며 전달합니다. 이때 각 가중치가 오차에 얼마나 기여했는지 기울기를 계산합니다.
  3. 경사하강법 (Gradient Descent): 계산된 기울기(Gradient)의 반대 방향으로 가중치를 조금씩 이동시켜 손실을 최소화합니다.
  4. 학습률 (Learning Rate, lr): 가중치를 한 번에 얼마나 이동시킬지 결정하는 보폭입니다. 너무 크면 최적점을 지나치고, 너무 작으면 학습이 너무 오래 걸립니다.

1-5. 딥러닝의 구조적 단계 (Architecture)

딥러닝 모델은 보통 세 가지 종류의 층으로 구성됩니다.

층(Layer) 역할 특징
입력층 (Input Layer) 데이터를 받아들이는 관문 데이터의 피처(Feature) 개수만큼 뉴런이 존재합니다.
은닉층 (Hidden Layer) 데이터 속의 패턴을 학습 층이 깊어질수록(Deep) 더 추상적이고 복잡한 특징을 파악합니다.
출력층 (Output Layer) 최종 예측 결과 산출 풀고자 하는 문제(분류, 회귀 등)에 따라 뉴런 수와 활성화 함수가 결정됩니다.

 


2. 코드 상세 분석: 이론과 실제의 연결

이 코드는 특정 입력값(x)을 기반으로 결과(y)가 0인지 1인지 판단하는 이진 분류(Binary Classification) 신경망을 구축하고 학습시키는 과정을 담고 있습니다.

① 데이터셋 정의: 모델의 학습 재료

x_train=torch.Tensor([2,4,6,8,10,12,14,16,18,20]).view(10,1)
y_train=torch.Tensor([0,0,0,0,0,0,1,1,1,1]).view(10,1)
  • 데이터의 형상(Shape): .view(10, 1)은 10개의 데이터를 '10행 1열'의 행렬 형태로 바꿉니다. 딥러닝 모델은 보통 (데이터 개수, 특징 개수) 형태의 입력을 기대하기 때문에 이 작업이 필수적입니다.
  • 학습 목표: x 값이 12 이하일 때는 0, 14 이상일 때는 1이 되도록 모델이 그 경계선을 스스로 찾게 만듭니다.

② 모델 설계: 신경망 아키텍처 (Architecture)

class MyDeepLearningModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.deepLearningstack=nn.Sequential(
            nn.Linear(1,8),  # [입력층 -> 은닉층] 입력 1개, 뉴런 8개
            nn.Linear(8,1),  # [은닉층 -> 출력층] 뉴런 8개, 출력 1개
            nn.Sigmoid()     # [활성화 함수] 결과를 0~1 사이 확률로 변환
        )
  • nn.Linear(1, 8): 가중치(W) 8개와 편향(b) 8개를 가진 첫 번째 층입니다. 하나의 입력값을 8개의 복잡한 특징으로 확장하여 학습 능력을 높입니다.
  • nn.Linear(8, 1): 은닉층에서 계산된 8개의 신호를 다시 하나로 모아 최종 예측값(y^)을 만듭니다.
  • nn.Sigmoid(): 앞서 배운 활성화 함수입니다. 출력된 선형 연산 값을 0.5를 기준으로 하는 확률값으로 변환하여 비선형성을 부여합니다.

③ 손실 함수와 최적화: "어떻게 공부할 것인가?"

loss_function=nn.BCELoss()
optimizer=torch.optim.SGD(deepLearning_model.parameters(), lr=1e-1)
  • BCELoss (Binary Cross Entropy): 모델의 예측 확률이 정답(0 또는 1)과 멀어질수록 큰 패널티를 줍니다. 이론에서 다룬 '얼마나 틀렸니?'를 수치화하는 도구입니다.
  • SGD (Optimizer): '오답 노트를 통한 성장' 단계입니다. 계산된 오차를 바탕으로 모델 내부의 가중치($W, b$)들을 어느 방향으로 수정할지 결정합니다.
  • lr=1e-1: 학습률(0.1)입니다. 가중치를 한 번에 수정하는 보폭을 의미합니다.

④ 학습 루프: 수만 번의 반복을 통한 지능 형성

for epoch in range(nums_epoch+1):
    # 1. 순전파 (Forward): 데이터를 모델에 통과시켜 예측값 계산
    outputs=deepLearning_model(x_train)

    # 2. 손실 계산: 예측값과 실제 정답(y_train) 비교
    loss=loss_function(outputs, y_train)

    # 3. 역전파 (Backpropagation): 오차를 뒤로 전달하며 기울기 계산
    optimizer.zero_grad() # 이전 단계의 기울기 초기화 (필수!)
    loss.backward()       # 기울기 계산

    # 4. 가중치 업데이트: 계산된 기울기 방향으로 W, b 수정
    optimizer.step()
  • optimizer.zero_grad(): 파이토치는 미분값을 누적하는 성질이 있어, 매 반복마다 이전의 기울기 값을 비워줘야 새로운 공부가 제대로 이루어집니다.
  • loss.backward(): 이 한 줄이 복잡한 미분 연산을 자동으로 수행하여 각 뉴런의 기여도를 찾아냅니다.

⑤ 평가 및 추론: 학습 결과 확인

deepLearning_model.eval() # 학습용 기능을 끄고 평가 모드로 전환
test_data=torch.Tensor([0.5, 3.0, 13.0, 31.0]).view(-1,1)
pred=deepLearning_model(test_data)
logical_value=(pred>0.5).float()
  • eval(): 드롭아웃이나 배치 정규화 같은 학습 전용 기법들을 끄고 오직 예측에만 집중하게 합니다.
  • logical_value: 모델은 0.88, 0.12 같은 확률을 내놓습니다. 이를 사람이 이해하기 쉽게 0.5를 기준으로 "1(참)" 혹은 "0(거짓)"으로 최종 결정(Thresholding)을 내리는 단계입니다.

3. 전체 코드

#딥러닝
import torch

x_train=torch.Tensor([2,4,6,8,10,12,14,16,18,20]).view(10,1)
y_train=torch.Tensor([0,0,0,0,0,0,1,1,1,1]).view(10,1)

print(x_train.shape,y_train.shape)
 
torch.Size([10, 1]) torch.Size([10, 1])
torch.Size([10, 1]) torch.Size([10, 1])
from torch import nn

class MyDeepLearningModel(nn.Module):

    def __init__(self):
        super().__init__()
        self.deepLearningstack=nn.Sequential(
            nn.Linear(1,8),
            nn.Linear(8,1),
            nn.Sigmoid()
        )

    def forward(self, data):
        pred=self.deepLearningstack(data)
        return pred
deepLearning_model=MyDeepLearningModel()

for name, child in deepLearning_model.named_children():
    for param in child.parameters():
        print(name,param)
        

deepLearningstack Parameter containing:
tensor([[-0.9485],
        [-0.2915],
        [ 0.4580],
        [-0.8432],
        [ 0.1640],
        [-0.2325],
        [ 0.8114],
        [ 0.7352]], requires_grad=True)
deepLearningstack Parameter containing:
tensor([ 0.1522, -0.2707,  0.3712, -0.0549,  0.0558,  0.8139,  0.0465,  0.1193],
       requires_grad=True)
deepLearningstack Parameter containing:
tensor([[-0.0802,  0.0221, -0.2988, -0.1314, -0.2308, -0.2364,  0.3447,  0.1657]],
       requires_grad=True)
deepLearningstack Parameter containing:
tensor([0.0089], requires_grad=True)

 
loss_function=nn.BCELoss()
optimizer=torch.optim.SGD(deepLearning_model.parameters(), lr=1e-1)
nums_epoch=5000

for epoch in range(nums_epoch+1):

    outputs=deepLearning_model(x_train)

    loss=loss_function(outputs, y_train)

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

    if epoch % 100==0:
        print('epoch=',epoch,'current_loss=',loss.item())
epoch= 0 current_loss= 1.846045732498169
epoch= 100 current_loss= 0.4021102786064148
epoch= 200 current_loss= 0.31698665022850037
epoch= 300 current_loss= 0.2691454589366913
epoch= 400 current_loss= 0.23731370270252228
epoch= 500 current_loss= 0.21418245136737823
epoch= 600 current_loss= 0.1964132934808731
epoch= 700 current_loss= 0.1822265386581421
epoch= 800 current_loss= 0.17057321965694427
epoch= 900 current_loss= 0.16078615188598633
epoch= 1000 current_loss= 0.15242169797420502
epoch= 1100 current_loss= 0.1451679766178131
epoch= 1200 current_loss= 0.13880161941051483
epoch= 1300 current_loss= 0.13315676152706146
epoch= 1400 current_loss= 0.128106489777565
epoch= 1500 current_loss= 0.12355349957942963
epoch= 1600 current_loss= 0.11942143738269806
epoch= 1700 current_loss= 0.11564888805150986
epoch= 1800 current_loss= 0.11218613386154175
epoch= 1900 current_loss= 0.10899212211370468
epoch= 2000 current_loss= 0.10603348910808563
epoch= 2100 current_loss= 0.1032823696732521
epoch= 2200 current_loss= 0.10071493685245514
epoch= 2300 current_loss= 0.09830980002880096
epoch= 2400 current_loss= 0.09605184942483902
epoch= 2500 current_loss= 0.09392444789409637
epoch= 2600 current_loss= 0.09191503375768661
epoch= 2700 current_loss= 0.09001331776380539
epoch= 2800 current_loss= 0.08821355551481247
epoch= 2900 current_loss= 0.08648552745580673
epoch= 3000 current_loss= 0.08472089469432831
epoch= 3100 current_loss= 0.0834549218416214
epoch= 3200 current_loss= 0.11239330470561981
epoch= 3300 current_loss= 0.03711119666695595
epoch= 3400 current_loss= 0.037562765181064606
epoch= 3500 current_loss= 0.1960425078868866
epoch= 3600 current_loss= 0.03444613888859749
epoch= 3700 current_loss= 0.04295351356267929
epoch= 3800 current_loss= 0.03305875509977341
epoch= 3900 current_loss= 0.029057834297418594
epoch= 4000 current_loss= 0.10015998780727386
epoch= 4100 current_loss= 0.029786771163344383
epoch= 4200 current_loss= 0.026365499943494797
epoch= 4300 current_loss= 0.023624418303370476
epoch= 4400 current_loss= 0.03024677000939846
epoch= 4500 current_loss= 0.02658083103597164
epoch= 4600 current_loss= 0.02367541752755642
epoch= 4700 current_loss= 0.021311059594154358
epoch= 4800 current_loss= 0.01935839094221592
epoch= 4900 current_loss= 0.027922898530960083
epoch= 5000 current_loss= 0.02454185113310814
deepLearning_model.eval()

test_data=torch.Tensor([0.5,3.0,3.5,11.0,13.0,31.0]).view(6,1)

pred=deepLearning_model(test_data)

logical_value=(pred>0.5).float()

print(pred)
print(logical_value)

tensor([[7.2402e-12],
        [1.2468e-09],
        [3.4913e-09],
        [1.7515e-02],
        [5.2295e-01],
        [1.0000e+00]], grad_fn=<SigmoidBackward0>)
tensor([[0.],
        [0.],
        [0.],
        [0.],
        [1.],
        [1.]])


4. 결론

이 코드는 입력층(1) -> 은닉층(8) -> 출력층(1) 구조를 가진 전형적인 심층 신경망의 축소판입니다. 데이터가 적어 보이지만 내부에서는 이론에서 배운 순전파 -> 손실 계산 -> 역전파 -> 최적화라는 딥러닝의 핵심 사이클이 완벽하게 돌아가고 있습니다.

처음에는 간단한 숫자로 시작했지만, 이 구조에서 층(Layer)을 더 쌓고 데이터의 형태만 바꾸면 이미지 인식이나 자연어 처리 모델로 발전할 수 있다는 점이 딥러닝의 매력인 것 같습니다.

+ Recent posts