Posted:      Updated:

AI 스터디를 하며 ‘파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습’ 교재를 정리한 글입니다.

단순 선형 회귀

손실 함수 정의

평균 제곱 오차 (Mean Squared Error, MSE)

$y_i$: 실제 값 $\hat{y_i} = weight \cdot x_i + bias $: 예측 값

\[J(weight, bias) = \frac{1}{n} \sum_{i=1}^n (y_i - \hat{y_i})^2\]

Chain Rule 을 활용해 가중치, 편향에 대한 편미분

$\hat{y_i}$을 $weight \cdot x_i + bias$로 치환

\[\frac{1}{n} \sum_{i=1}^n (y_i - (weight \cdot x_i + bias))^2\]
  1. $Gradient(w_n)$
  • $weight$에 대해 편미분
\[\begin{align} \frac{2}{n} \sum_{i=1}^n (y_i - (weight \cdot x_i + bias)) \cdot (-x_i) \\ = \frac{2}{n} \sum_{i=1}^n (\hat{y_i} - y_i) \cdot x_i \end{align}\]
  • 코드로 표현
2 * ((y_hat - y) * x).mean()
  1. $Gradient(b_n)$
  • $bias$에 대해 편미분
\[\begin{align} \frac{2}{n} \sum_{i=1}^n (y_i - (weight \cdot x_i + bias)) \cdot (-1) \\ = \frac{2}{n} \sum_{i=1}^n (\hat{y_i} - y_i) \end{align}\]
  • 코드로 표현
2 * (y_hat - y).mean()

가중치, 편향 갱신

(업데이트할 파라미터) - (학습률) * (손실함수의 파라미터에 대한 편미분) 편미분 후 생긴 상수 2는 학습률($\alpha$)로 대체

  1. $w_{n+1}$
\[w_{n+1} = w_n - \alpha \cdot \frac{2}{n} \sum_{i=1}^n (\hat{y_i} - y_i) \cdot x_i\]
  1. $b_{n+1}$
\[b_{n+1} = b_n - \alpha \cdot \frac{2}{n} \sum_{i=1}^n (\hat{y_i} - y_i)\]

넘파이로 구현한 단순 선형 회귀

import numpy as np

x = np.array([
    [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 = np.array([
    [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 = 0.0
bias = 0.0
learning_rate = 0.001
# learning_rate = 0.005
for epoch in range(10000):
    y_hat = weight * x + bias # batch size: 30
    cost = ((y - y_hat) ** 2).mean()

    weight = weight - learning_rate * ((y_hat - y) * x).mean()
    bias = bias - learning_rate * (y_hat - y).mean()

    if (epoch + 1) % 1000 == 0:
        print(f"Epoch : {epoch+1:4d}, Weight : {weight:.3f}, Bias : {bias:.3f}, Cost : {cost:.3f}")

출력

Epoch : 1000, Weight : 0.860, Bias : -0.059, Cost : 1.406
Epoch : 2000, Weight : 0.864, Bias : -0.138, Cost : 1.393
Epoch : 3000, Weight : 0.867, Bias : -0.201, Cost : 1.385
Epoch : 4000, Weight : 0.870, Bias : -0.251, Cost : 1.380
Epoch : 5000, Weight : 0.872, Bias : -0.290, Cost : 1.377
Epoch : 6000, Weight : 0.873, Bias : -0.321, Cost : 1.375
Epoch : 7000, Weight : 0.874, Bias : -0.345, Cost : 1.374
Epoch : 8000, Weight : 0.875, Bias : -0.364, Cost : 1.373
Epoch : 9000, Weight : 0.876, Bias : -0.379, Cost : 1.373
Epoch : 10000, Weight : 0.877, Bias : -0.391, Cost : 1.373

파이토치 기능으로 구현한 단순 선형 회귀

  • 확률적 경사 하강법 (Stochastic Gradient Descent, SGD) 사용: 미니 배치(Mini-Batch) 형태로 전체 대이터를 N등분하여 학습 진행
import torch
from torch import 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
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()  # weight, bias 에 저장된 기존 기울기값 초기화
    cost.backward()  # 역전파 수행, cost에 대한 각 파라미터의 gradient 계산
    optimizer.step()  # optimizer에 등록된 파라미터들에 대해 역전파로 계산된 파라미터 갱신

    if (epoch + 1) % 1000 == 0:
        print(f"Epoch: {epoch + 1:4d}, Weight: {weight.item():.3f}, Bias: {bias.item():.3f}, Cost: {cost.item():.3f}")

출력

Epoch: 1000, Weight: 0.864, Bias: -0.138, Cost: 1.393
Epoch: 2000, Weight: 0.870, Bias: -0.251, Cost: 1.380
Epoch: 3000, Weight: 0.873, Bias: -0.321, Cost: 1.375
Epoch: 4000, Weight: 0.875, Bias: -0.364, Cost: 1.373
Epoch: 5000, Weight: 0.877, Bias: -0.391, Cost: 1.373
Epoch: 6000, Weight: 0.878, Bias: -0.408, Cost: 1.372
Epoch: 7000, Weight: 0.878, Bias: -0.419, Cost: 1.372
Epoch: 8000, Weight: 0.878, Bias: -0.425, Cost: 1.372
Epoch: 9000, Weight: 0.879, Bias: -0.429, Cost: 1.372
Epoch: 10000, Weight: 0.879, Bias: -0.432, Cost: 1.372

신경망 패키지

신경망 생성, 학습 과정을 빠르게 구현 가능

  • 네트워크(Net) 정의 모듈
  • 자동 미분, 계층 등 정의를 위한 모듈

선형 변환 클래스

  • 선형 변환(Linear Transformation): 기하학적으로 벡터의 크기 스케일링, 방향 회전, 좌표 이동 시키는 연산
  • 머신러닝에서는 다음 레이어에서 학습 가능하도록 하기 위한 입력 데이터의 차원 변환, 선형 회귀에서 데이터 예측에 사용
layer = nn.Linear(
    in_features=10,
    out_features=5,
    bias=True,
    device=None,
    dtype=None
)

평균 제곱 오차 클래스

criterion = nn.MSELoss()

신경망 패키지로 구현한 단순 선형 회귀

  • weight, bias 변수를 사용하지 않음
  • 학습 결과는 model.parameters() 로 확인
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]
])
model = nn.Linear(1, 1)
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)
for epoch in range(10000):
    output = model(x)  # 모델에 입력 데이터 전달, 출력 데이터 차원 크기와 동일한 output(= y_hat)
    cost = criterion(output, y)  # input: output, target: y (MSE에서 y_hat, y 의미)

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

    if (epoch + 1) % 1000 == 0:
        print(f"Epoch : {epoch + 1:4d}, Model : {list(model.parameters())}, Cost : {cost:.3f}")

출력

Epoch : 1000, Model : [Parameter containing:
tensor([[0.8888]], requires_grad=True), Parameter containing:
tensor([-0.6379], requires_grad=True)], Cost : 1.382
Epoch : 2000, Model : [Parameter containing:
tensor([[0.8851]], requires_grad=True), Parameter containing:
tensor([-0.5616], requires_grad=True)], Cost : 1.376
Epoch : 3000, Model : [Parameter containing:
tensor([[0.8827]], requires_grad=True), Parameter containing:
tensor([-0.5141], requires_grad=True)], Cost : 1.374
Epoch : 4000, Model : [Parameter containing:
tensor([[0.8813]], requires_grad=True), Parameter containing:
tensor([-0.4846], requires_grad=True)], Cost : 1.373
Epoch : 5000, Model : [Parameter containing:
tensor([[0.8804]], requires_grad=True), Parameter containing:
tensor([-0.4662], requires_grad=True)], Cost : 1.372
Epoch : 6000, Model : [Parameter containing:
tensor([[0.8798]], requires_grad=True), Parameter containing:
tensor([-0.4548], requires_grad=True)], Cost : 1.372
Epoch : 7000, Model : [Parameter containing:
tensor([[0.8795]], requires_grad=True), Parameter containing:
tensor([-0.4477], requires_grad=True)], Cost : 1.372
Epoch : 8000, Model : [Parameter containing:
tensor([[0.8793]], requires_grad=True), Parameter containing:
tensor([-0.4432], requires_grad=True)], Cost : 1.372
Epoch : 9000, Model : [Parameter containing:
tensor([[0.8791]], requires_grad=True), Parameter containing:
tensor([-0.4405], requires_grad=True)], Cost : 1.372
Epoch : 10000, Model : [Parameter containing:
tensor([[0.8790]], requires_grad=True), Parameter containing:
tensor([-0.4388], requires_grad=True)], Cost : 1.372

Categories:

댓글남기기