본문 바로가기

책/파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습

03 파이토치 기초 (3) 손실 함수, 최적화

손실 함수(Loss Function)

단일 샘플의 실젯값과 예측값의 차이가 발생했을 때 오차가 얼마인지 계산하는 함수이다. 인공 신경망은 실젯값과 예측값을 통해 계산된 오찻값을 최소화해 정확도를 높이는 방법으로 학습이 진행된다.

 

  • 목적 함수(Objective Function) : 함숫값의 결과를 최댓값 또는 최솟값으로 최적화하는 함수
  • 비용 함수(Cost Function) : 전체 데이터에 대한 오차를 계산하는 함수

손실 함수 $\subset$ 비용 함수  $\subset$ 목적 함수의 포함 관계를 가지고 각각의 의미를 정확히 구분해 사용하는 것이 좋다.

 

손실과 비용을 코드로 표현하자면 다음과 같다.

for epoch in range(10):
  cost = 0.0
  for batch in dataloader:
    <<중략>>

    loss = criterion(output, y)
    cost += loss

 

 

연속형 변수에 사용되는 손실 함수는 주로 평균 제곱 오차(Mean Squared Error, MSE) 방법을 사용하며 이전 글 에서 확인할 수 있다.

2023.12.08 - [Machine Learning/Business Analytics] - Evaluating Regression Models

 

Evaluating Regression Models

1. Average Error 실제값과 예측값의 차이를 평균내어 비교 부호 효과로 인해 부적절한 결론을 잘못 도출함 모든 샘플에서 $\pm 3$ 이상의 차이가 나지만 Average Error는 0.1로 작은 값을 나타냄 실전에서

ai-junha.tistory.com

 

교차 엔트로피

이산형 변수는 교차 엔트로피(Cross-Entropy)를 사용한다. 교차 엔트로피는 실젯값의 확률분포와 예측값의 확률분포 차이를 계산한다. 수식은 다음과 같다.

 

$CE(y, \hat{y}) = -\sum {y_j{\log \hat{y_j}}}$

 

  • $y$가 1일 때
    • $\hat{y}$이 1에 가까운 값이라면 즉, 올바른 예측을 하고있다면 $y \log \hat{y}$ 값은 0에 가까워짐
    • $\hat{y}$이 0에 가까운 값, 즉 잘못된 예측을 하고있다면 $y \log \hat{y}$ 값은 커짐

 

최적화

최적화(Optimization)란 목적 함수의 결괏값을 최적화하는 변수를 찾는 알고리즘을 의미한다. 여기서 말하는 변수란 가중치와 편향을 의미한다.

 

독립 변수와 종속 변수가 각각 1개인 단순 선형 회귀 데이터에 대해 가중치에 따른 오차 그래프는 다음과 같다.

그래프에서 확인할 수 있듯이 최적의 가중치에서는 오차가 가장 작으며, 최적의 가중치에서 멀어질수록 오차가 커지는 것을 확인할 수 있다. 또 가중치와 오차 그래프에서 기울기(Gradient)가 0에 가까워질 때 최적의 가중치를 갖는 것을 알 수 있다.

 

학습 관련 기술들은 이전 글에서 확인할 수 있다.

2023.09.20 - [책/밑바닥부터 시작하는 딥러닝] - 6장 학습 관련 기술들 (1)

 

6장 학습 관련 기술들 (1)

매개변수 갱신 최적화(optimization) : 매개변수의 최적값을 찾는 문제 확률적 경사 하강법(SGD) 앞장에서 보았던 가장 간단한 방법 파이썬으로 구현해보자 class SGD: """확률적 경사 하강법 (Stochastic Gra

ai-junha.tistory.com

 

단순 선형 회귀

파이토치로 단순 선형 회귀를 구현해 본다.

프레임 워크 선언

import torch
from torch import optim
  • optim 모듈을 통해 다양한 최적화 함수를 간단하게 사용할 수 있다.

 

데이터 선언

x = torch.FloatTensor([
    [1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
    [11], [12], [13], [14], [15], [16], [17], [18], [19], [20],
    [21], [22], [23], [24], [25], [26], [27], [28], [29], [30]
])
y = torch.FloatTensor([
    [0.94], [1.98], [2.88], [3.92], [3.96], [4.55], [5.64], [6.3], [7.44], [9.1],
    [8.46], [9.5], [10.67], [11.16], [14], [11.83], [14.4], [14.25], [16.2], [16.32],
    [17.46], [19.8], [18], [21.34], [22], [22.5], [24.57], [26.04], [21.6], [28.8]
])

 

하이퍼파라미터 초기화

weight = torch.zeros(1, requires_grad=True)
bias = torch.zeros(1, requires_grad=True)
learning_rate = 0.001
  • torch.zeros는 size를 인수로 받는다.
  • requires_grad=True로 설정하면 모든 텐서에 대한 연산을 추적하며 역전파 메서드를 호출해 기울기를 계산하고 저장한다. 이 기능은 파이토치에서 지원하는 Autograd 기능의 사용 여부라고 볼 수 있다.

 

최적화 선언

optimizer = optim.SGD([weight, bias], lr=learning_rate)

 

학습

for epoch in range(10000):
  hypothesis = weight * x + bias
  cost = torch.mean((hypothesis - y) ** 2)
  # 가중치와 편향 갱신
  optimizer.zero_grad()
  cost.backward()
  optimizer.step()
  # 학습 기록 출력
  if (epoch + 1) % 1000 == 0:
        print(f"Epoch : {epoch+1:4d}, Weight : {weight.item():.3f}, Bias : {bias.item():.3f}, Cost : {cost:.3f}")
  • optimizer.zero_grad 메서드로 optimizer 변수에 포함시킨 매개변수들의 기울기를 0으로 초기화한다. 텐서의 기울기는 grad 속성에 누적해서 더해지기 때문에 0으로 초기화해야 한다. 구체적으로 설명하자면, 기울기가 weight = x의 형태가 아닌, weight += x의 구조로 저장되기 때문에 기울기를 0으로 초기화해 중복 연산을 방지하는 것이다.
  • cost.backward 메서드를 통해 역전파를 수행한다. 이 연산을 통해 optimzier 변수에 포함시킨 매개변수들의 기울기가 새로 계산된다.
  • 이 결과를 최적화 함수에 반영해야 하므로 optimizer.step 메서드를 수행한다.

신경망 패키지

이번에는 신경망(Neural Networks) 패키지를 활용해 모델을 구성해보자.

 

모델 선언

model = torch.nn.Linear(in_features=1, out_features=1,
                        bias=True, device=None, dtype=None)
  • 이전에는 weight과 bias 변수를 선언하여 사용하였는데 신경망 패키지를 사용하면 모델의 입출력 데이터 차원 크기 매개변수(in_features, out_features)가 weight 변수를 대체하며 bias 매개변수가 bias 변수를 대체한다.

 

오차 클래스

criterion = torch.nn.MSELoss()

 

학습

for epoch in range(10000):
    output = model(x)
    cost = criterion(output, y)

    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    if (epoch + 1) % 1000 == 0:
        print(f"Epoch : {epoch+1:4d}\n Model : {list(model.parameters())}\n Cost : {cost:.3f}")
  • 이전에는 weight의 grad 속성을 통해 값을 확인하였는데, 지금은 model.parameters()를 통해 모델 매개변수를 확인할 수 있다.