David의 개발 이야기!

다변수 선형회귀, Multivariable Linear Regression Pytorch 구현하기 본문

인공지능공부

다변수 선형회귀, Multivariable Linear Regression Pytorch 구현하기

david.kim2028 2023. 7. 23. 16:54
반응형

다변수 선형회귀란, 변수가 여러개 있는 상태에서 회귀를 하는 것을 의미한다. 

 

기존 포스팅에서는 독립변수 1개, 종속변수가 1개 였지만, 다변수라 함은, 독립변수가 여러개라는 뜻이다.

원리는 기존 포스팅과 매우 흡사하다.

2023.07.23 - [인공지능공부] - Linear Regression Pytorch 로 구현하기

 

Linear Regression Pytorch 로 구현하기

지난 포스팅에서 Linear Regression 의 bias 있을때, 없을때 여부에 따라, 밑바닥부터 구현해보았다. 2023.07.14 - [인공지능공부] - Linear Regression 바닥부터 구현하기 ( bias 없을때 ) Linear Regression 바닥부터

david-kim2028.tistory.com

 

1. 라이브러리 불러오기

import matplotlib.pyplot as plt
import torch
import torchvision
import numpy as np

[코드 설명]

# matplotlib -> 그래프를 그려주는 시각화 도구

# torch -> PyTorch 기본 라이브러리

  PyTorch에서는 다양한 라이브러리를 제공하는데 아래와 같은 것들을 포함함.

      1) torch.nn : 뉴럴 네트워크(neural network) 그 자체 (모델 그 자체)

      2) torch.data : 뉴럴 네트워크에 들어갈 데이터 등을 처리하는 라이브러리 

# torchvision -> PyTorch 를 사용해서 vision 문제를 풀 때 각종 라이브러리 제공 

 

2. 학습할 데이터 불러오기

X = [[1, 33],
     [2, 27],
     [3, 29],
     [4, 45],
     [5, 27],
     [6, 33],
     [7, 35]]
Y = [25000, 55000, 75000, 125000, 128000, 155000, 182000]

Y = [[i] for i in Y]

x_data = torch.Tensor(X)
y_data = torch.Tensor(Y)

print(x_data)
print(y_data)

Y = [[i] for i in Y] # 왜 굳이 한 번 더 감싸주는가?

-> 데이터 Y의 차원 [7, 1] => [batch_size, 데이터차원] 형태를 맞추어 주려고

-> 왜 맞춰야하냐면, PyTorch 는 항상 첫번째 축(axis)으로 batch_size 를 가져야 하므로

 

 

3. 학습할 모델 정의하기

class LinearRegressionModel(torch.nn.Module):
  def __init__(self, input_dim, output_dim):
    super(LinearRegressionModel, self).__init__()
    self.linear = torch.nn.Linear(input_dim, output_dim)
  def forward(self, x):
    y_pred = self.linear(x)
    return y_pred

model = LinearRegressionModel(2, 1)

* torch.nn.Module -> 뉴럴 네트워크의 기능을 가지고 있는 클래스

  __init__(), forward() 를 "미리" 정의해놓은 라이브러리 라고 생각하기

 -> 따라서, 우리가 이친구를 "상속" 받아서 이 두가지 기능을 이름 그대로, 내용만 바꾸어서 구현(객체지향 프로그래밍)

-> "뉴럴 네트워크"라는 "객체"를 정의하고, 그 "기능"을 미리 정해진 함수 이름으로 구현

 

*def __init__(self, input_dim, output_dim):

보통 __init()__ 에서는 해당 객체의 내부적인 "변수" 혹은 "파라미터"가 들어가도록 함

ex) 학생 클래스면, 해당 학생의 이름, 학번, 성적 등

여기에서는 뉴럴네트워크 이기 때문에 파라미터 자체임. (여기선 학습할 가중치 w1, w2 등)

 

 

*super(LinearRegressionModel, self).__init__()

-> 이전 포스팅 참고

 

*self.linear = torch.nn.Linear(input_dim, output_dim)

Linear(행축, 열축) 으로 초기화

여기에서는 [2, 1] 짜리 행렬로 초기화 (엄밀히 보면, bias 포함해서, [2, 1] + 1 임)

 

+) 

torch.nn.Linear() 도 하나의 "행렬"임.

보면 알 수 있듯이, Linear도 하나의 neural network 에 속함.

Linear 클래스의 forward 함수는 바로 "행렬 곱"을 의미

우리가 nn.Module 에서 파생된 객체 model 이 있을때, 

output = model(x) 이렇게 하면, model.forward(x) 가 호출된 결과가 반환된 것임.

Linear 클래스의 linear.forward(x) 는 사실 행렬 곱을 수행한 결과를 반환하는 것임!

 

*y_pred = self.linear(x)

이걸 수행하면, y_pred = [batch_size, 2] * [2, 1] = [batch_size, 1] 형태의 행렬 곱 결과를 반환

 

+) self, 초기화 개념

파이썬에서, 어떤 클래스든, 처음 클래스를 초기화 할때, 입력으로 넣는 인자는 자동으로, __init__ 함수에 들어감.

위 코드에서는 __init__ 만들때 인자가 3개 였음 self, input_dim, output_dim

파이썬에서 클래스를 정의할때, 내부 함수는 항상 self 라는 걸 처음으로 가지고 있음.

그래서 그 다음부터 input_dim, output_dim 에 값을 채워 넣어주는 것임. 

값을 채워 넣어준다 == 초기화 

 

따라서, model = LinearRegressionModel(2, 1) 은 input_dim = 2, output_dim = 1 로 초기화를 한것임.

 

3. 손실함수 정의하기

criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)

* optimizer = torch.optim.SGD(model.parameters(), lr = 0.0001)

 

한 번 모델에 forward()를 하고 loss를 구한 뒤에
loss에서부터 "역전파" => 기울기 구하는 과정 
역전파를 하면 모든 파라미터 w1, w2, b에 대해서 기울기가 계산됨.

정확히는, w1.grad, w2.grad, b.grad에 값이 "채워짐"
SGD를 사용하면, step()을 호출했을 때, 다음과 같이 업데이트 됨.
# w1 = w1 - lr * w1.grad
# w2 = w2 - lr * w2.grad
# b = b - lr * b.grad

 

4. 학습하기

# epoch이란? "반복 횟수"를 말함. 그냥 영어 정의상.
# 근데, 딥러닝이나 기계학습에서 epoch이란? "각 데이터를 한 번씩 보는 행위"의 반복을 의미함.

# 100,000번 반복한다는 건, 각 데이터를 10만 번씩 보겠다는 것.
for epoch in range(100001):
    # 현재 상황에서는 "전체 데이터 개수" = batch_size임.
    # x_data = [batch_size, 2] = [7, 2]
    pred_y = model(x_data)
    # 모델에 넣었으니까, pred_y = [batch_size, 1]
    loss = criterion(pred_y, y_data)
    # loss를 구해야죠. loss = E[(pred_y - y_data)^2] = [1]
    optimizer.zero_grad() # 역전파 전에는 항상 각 파라미터에 대해서 기울기를 초기화
    # w1.grad, w2.grad, b.grad의 값을 0으로 만들어 줌.
    # 이제 기울기를 구해봅시다!
    loss.backward() # backward()를 수행하면 PyTorch가 역전파(back-propagation)으로
    # 모든 가중치(w1, w2, b)에 대해서 기울기 "값"을 구함
    # (참고) PyTorch에서 모든 연산(곱하기, 빼기, 더하기 등)에 대해서 미리 구해져 있음
    # 이 라인까지 오면, w1.grad, w2.grad, b.grad가 계산됨.
    optimizer.step()
    # step()을 호출하면 아래처럼 학습 수행.
    # w1 = w1 - lr * w1.grad
    # w2 = w2 - lr * w2.grad
    # b = b - lr * b.grad
    # 참고로 linear는 w1, w2, b의 값을 다음의 이름으로 기록하고 있음.
    # Linear.weight = [input_dim, output_dim] = [2, 1]: 총 2개의 파라미터
    # Linear.bias = [output_dim] = [1]: 총 1개의 파라미터
    # 그래서 아래 코드에서 weight이 2차원 배열
    if epoch % 10000 == 0:
        print("[ epoch: %d, cost: %.2f ]" % (epoch, loss.data))
        print("w1 = %.2f, w2 = %.2f, b = %.2f" % (model.linear.weight[0][0], model.linear.weight[0][1], model.linear.bias))

print("f(x) = %.2fx1 + %.2fx2 + %.2f" % (model.linear.weight[0][0], model.linear.weight[0][1], model.linear.bias))
print("예측값: [%.2f]" % (model(torch.Tensor([[1, 33]]))))

 

반응형
Comments