250922 [ Day 55 ] - Machine Learning (3), PyTorch (3)

TaeHyun·2025년 9월 22일

TIL

목록 보기
57/182

시작하며

오늘로 Machine Learning에 대한 이론 수업은 모두 끝났고, PyTorch를 사용해서 직접 모델을 만들어보는 시간을 가졌다. 이론으로만 들었던 내용을 코드로 구현해가니까 상당히 재미있었고, 이론을 알고 있으니 코드를 작성하면서 어떤 기능인지 바로바로 알 수 있어서 꽤 만족스러운 이론 학습이었던 것 같다.

기울기 소실(Vanishing Gradient)

시그모이드 함수의 문제

  • 시그모이드 함수 접선의 기울기의 최대값은 1/4
  • 큰 입력 값에서 기울기는 0에 수렴

기울기 소실

  • 입력층에 가까울수록 계산이 깊어지면서 0에 수렴하기 때문에 가중치 업데이트가 잘 이루어지지 않음 → 학습이 되지 않음
  • 입력층 부분에서 학습이 진행되지 않으면 품질이 낮은 데이터가 전달

ReLU(Rectified Linear Unit)

  • 입력이 0보다 크면 그대로 출력(기울기가 1)하고, 0이하이면 0을 출력하는 활성화 함수
  • f(x) = max(0,x)
  • 최근 가장 많이 사용되는 활성화 함수
  • 음수 값이 들어오면 0을 출력하기 때문에 노드가 죽어버리는 문제가 있음
    • 0이하의 값을 작은 기울기를 곱해 출력하는 다양한 ReLU 함수가 있음

배치 정규화와 레이어 정규화

배치 정규화(Batch Normalization)

  • 각 배치별로 평균과 분산을 이용해 정규화 하는것
  • 평균은 0, 표준 편차는 1로 데이터의 분포를 조정
    • 재배치 하되, 순서는 바꾸지 않음
  • 이미지 데이터 및 회귀 처리에 활용

레이어 정규화(Layer Normalization)

  • 배치들의 층에 대해 평균과 분산을 이용해 정규화 하는것
  • RNN Model(자연어) 등 시퀀스 모델에 활용

과적합(Overfitting)

  • 학습 데이터에 대해 모델이 지나치게 적합 되어, 새로운 데이터나 테스트 데이터에서 성능이 저하되는 현상

과적합 원인

  1. 학습 시간 과다 : 학습을 지나치게 오래 진행하면 모델이 데이터의 작은 변동까지 학습하게 되어 과적합 발생
  2. 복잡한 모델 구조 : 학습 데이터의 패턴을 과도하게 학습하는 복잡한 모델로 인해 발생
  3. 학습 데이터 부족 : 데이터의 양이 적거나, 데이터가 특정 패턴에 편중되어 있어 모델이 일반화된 패턴을 학습하지 못함
  4. 노이즈 학습 : 학습 데이터에 포함된 노이즈(불필요한 정보)를 모델이 학습하여, 본질적인 패턴 대신 노이즈에 의존하게 됨

해결 방법

  • 데이터 증강 : 데이터의 다양성을 높이기 위해 데이터를 변형하거나 추가로 생성
  • 데이터 확대 : 학습 데이터의 양을 늘려 모델이 더 일반화된 패턴을 학습할 수 있도록 함
  • Regularization : 모델의 복잡도를 제어하는 기법
  • Drop-Out : 랜덤하게 일부 뉴런을 비활성화 하여 각 층에 포함된 weight 중에서 일부만 참여시키는 방법

Regularization

  • 손실 함수에 가중치의 합을 더하는 것
  • 규제를 통해 모델이 갈 수 있는 범위를 제한

Weight normalization

  • Norm : 벡터의 크기를 측정하는 방법, 두 벡터 사이의 거리를 측정하는 방법
    • L1 Norm : 절대값의 합 → 모든 값을 일괄로 적용
    • L2 Norm : 제곱의 합 → 큰 값을 더 민감하게 적용

L1 Regularization

  • L1 정규화를 사용하는 모델을 Lasso 모델이라고 함
  • 불필요한 Weight를 0으로 만들어버려서 노드가 죽어버림(Feature selection의 효과)

L2 Regularization

  • L2 정규화를 사용하는 모델을 Ridge 모델이라고 부름
  • 가중치가 너무 크지 않은 방향으로 학습되게 함
  • Weight 가 클수록 더 빠르게 감소
  • 불필요한 Feature를 0에 가깝게 만드는 특성

자동미분

  • Pytorch는 Tensor의 모든 연산에 대해 자동미분이 가능
  • 자동미분은 역전파에 활용
  • requires_grad : Tensor의 속성으로, True로 설정해야 자동미분이 가능
  • tensor.backward() : 미분 실행
  • tensor.grad : 미분값을 확인할 수 있는 속성
x = torch.tensor([1.], requires_grad=True)
y = x ** 2
print(y)
print(x.grad)
# tensor([1.], grad_fn=<PowBackward0>)
# None

z = 3 * y
print(z)
# tensor([3.], grad_fn=<MulBackward0>)

z.backward()
print(x.grad)
# tensor([6.])

  • 결과를 연산과 분리
x = torch.tensor([1.], requires_grad=True)
a = x ** 2
b = a + 1
c = b ** 2

c.backward()
print(x.grad)
# tensor([8.])

result = x.grad.detach()
print(result)
print(result.requires_grad)
print(result.item())
# tensor([8.])
# False
# 8.0

  • 다변수 함수 미분
x = torch.tensor([1.], requires_grad=True)
y = torch.tensor([3.], requires_grad=True)
z = (2 * (x ** 2)) + (y ** 2)

print(z)
# tensor([11.], grad_fn=<AddBackward0>)

z.backward()
print(x.grad)
print(y.grad)
# tensor([4.])
# tensor([6.])

  • with torch.no_grad()
  • grad_fn 을 계산하고 싶지 않을때 사용
  • 모델 훈련 후 test data를 가지고 평가할 때 사용
x = torch.tensor([1.], requires_grad=True)

with torch.no_grad():
    y = x ** 2
    print(x.requires_grad)
    print(y)
    # True
    # tensor([1.])
    
print(x.requires_grad)
# True

y.backward() # with 구문 안쪽의 y로 미분 시도시 에러 발생

선형회귀모델

단일선형회귀

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import numpy as np

  1. 데이터 생성
x = torch.linspace(0,10,100).view(-1,1) # 입력데이터
y = 3 * x + 2 + torch.randn(100, 1) * 2 # 라벨

  1. 모델 정의
class LinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(1,1) # 입력 1개, 출력 1개 노드 생성

    def forward(self, x):
        return self.linear(x)
    
model = LinearRegressionModel()

  • 다층 구조 모델
class LinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.hidden = nn.Linear(1,10) # 입력 1개, 출력 10개 노드 생성
        self.relu = nn.ReLU()
        self.output = nn.Linear(10,1)

    def forward(self, x):
        x = self.hidden(x)
        x = self.relu(x)
        x = self.output(x)
        return x

  1. 손실함수, 옵티마이저 정의
criterion = nn.MSELoss() # 평균 제곱 오차
# Weight, Bias 포함 / 학습률
optimizer = optim.SGD(model.parameters(), lr=0.01) # 확률적 경사 하강법

  1. 가중치 업데이트
epochs = 500 # 학습 반복 횟수
losses = []

for epoch in range(epochs):
    optimizer.zero_grad() # 기울기 초기화
    outputs = model(x) # 예측값 계산
    loss = criterion(outputs, y) # 손실 계산
    loss.backward() # 역전파
    optimizer.step() # 가중치 업데이트

    losses.append(loss.item())

    # 100번에 한번씩 로그 출력
    if (epoch + 1) % 100 == 0:
        print(f"Eporch [{epoch+1} / {epochs}], Loss : {loss.item() : .4f}")

  1. 결과 시각화
plt.figure(figsize=(10,5))

# 손실 감소 그래프
plt.subplot(1, 2, 1)
plt.ylim(0, 5)
plt.plot(losses)
plt.title("Loss over Epochs")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.grid()

# 데이터와 예측 결과
plt.subplot(1, 2, 2)
plt.scatter(x.numpy(), y.numpy(), label="Original Data")
plt.plot(x.numpy(), model(x).detach().numpy(), color="r", label="Fitted Line")
plt.title("Linear Regression Fit")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()

plt.show()

print("Model Parameters :")
for name, param in model.named_parameters():
    print(f"{name} : {param.data}")

마치며

약간의 이슈는 있었지만 상당히 재미있는 수업이었다. 내일은 더 다양한 모델들을 구현해본다고 해서 더 재미있을 것 같다.

NOTION

MY NOTION (Machine Learning. 03)

profile
Hello I'm TaeHyunAn, Currently Studying Data Analysis

0개의 댓글