딥러닝(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): 오답 노트를 통한 성장
손실 함수를 통해 계산된 오차를 줄여나가는 과정입니다.
- 순전파 (Forward Propagation): 데이터를 입력하여 예측값을 계산합니다.
- 역전파 (Backpropagation): 출력층에서 발생한 오차를 입력층 방향으로 거슬러 올라가며 전달합니다. 이때 각 가중치가 오차에 얼마나 기여했는지 기울기를 계산합니다.
- 경사하강법 (Gradient Descent): 계산된 기울기(Gradient)의 반대 방향으로 가중치를 조금씩 이동시켜 손실을 최소화합니다.
- 학습률 (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])
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= 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)을 더 쌓고 데이터의 형태만 바꾸면 이미지 인식이나 자연어 처리 모델로 발전할 수 있다는 점이 딥러닝의 매력인 것 같습니다.
'현장실습 일기' 카테고리의 다른 글
| 2주차 회고 -FashionMNIST로 비교하는 MLP vs CNN 성능 차이 분석 (1) | 2026.01.22 |
|---|---|
| 2주차 회고 - 딥러닝의 Hello World: MNIST 손글씨 숫자 분류하기 (1) | 2026.01.22 |
| 현장실습 2주차 회고 (0) | 2026.01.22 |
| 1주차 회고 – Oxford-IIIT Pet Dataset으로 CLIP 적용하기 (0) | 2026.01.11 |
| 1주차 회고 – CLIP 모델 첫 구현과 Zero-shot 분류 실험 (0) | 2026.01.11 |