본문 바로가기

그 땐 AI했지/그 땐 DeepLearning했지

[Study/pytorch] ch03 선형 회귀 | 04 nn.Module로 구현하는 선형 회귀

728x90

참고자료: https://wikidocs.net/book/2788

 

파이토치에서 이미 구현되어 제공되고 있는 함수들을 불러오는 것으로 더 쉽게 선형 회귀 모델을 구현해보자!

👉🏻파이토치에서는 다음 함수들이 구현되어져 있다.

  • nn.Linear(): 선형 회귀 모델
  • nn.functional.mse_loss(): 평균 제곱오차

 

1. 단순 선형 회귀 구현하기


파이토치 함수를 이용해 \(y = 2x\), 즉 w=2, b=0임을 제대로 찾아내보자!
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(1)

# 데이터
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])

👉🏻필요한 도구를 import하고 데이터를 선언한다.

# 모델을 선언 및 초기화. 단순 선형 회귀이므로 input_dim=1, output_dim=1.
model = nn.Linear(1,1)

👉🏻선형 회귀 모델을 구현한다.

👉🏻nn.Linear(): 입력의 차원, 출력의 차원을 인수로 받는다. 위의 식은 하나의 입력 x에 대해서 하나의 출력 y를 가지므로 모두 1을 인수로 사용했다.

print(list(model.parameters()))

#[Parameter containing:
#tensor([[0.5153]], requires_grad=True), Parameter containing:
#tensor([-0.4414], requires_grad=True)]

👉🏻model.parameters(): model에 저장되어 있는 가중치 W와 편향 b를 불러온다. 첫 번째 값이 W이고, 두 번째 값이 b이다. 두 값 모두 학습의 대상이므로 requires_grad = True이다.

# optimizer 설정. 경사 하강법 SGD를 사용하고 learning rate를 의미하는 lr은 0.01
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

👉🏻model.parameters를 사용해 W와 b를 전달해 optimizer를 정의한다. 학습률은 0.01로 정한다.

# 전체 훈련 데이터에 대해 경사 하강법을 2,000회 반복
nb_epochs = 2000
for epoch in range(nb_epochs+1):

    # H(x) 계산
    prediction = model(x_train)

    # cost 계산
    cost = F.mse_loss(prediction, y_train) # <== 파이토치에서 제공하는 평균 제곱 오차 함수

    # cost로 H(x) 개선하는 부분
    # gradient를 0으로 초기화
    optimizer.zero_grad()
    # 비용 함수를 미분하여 gradient 계산
    cost.backward() # backward 연산
    # W와 b를 업데이트
    optimizer.step()

    if epoch % 100 == 0:
    # 100번마다 로그 출력
      print('Epoch {:4d}/{} Cost: {:.6f}'.format(
          epoch, nb_epochs, cost.item()
      ))
      
#Epoch    0/2000 Cost: 13.103540
#... 중략 ...
#Epoch 2000/2000 Cost: 0.000000

👉🏻경사 하강법을 2000번 실행하며 cost가 13에서 0으로 작아졌다.

# 임의의 입력 4를 선언
new_var =  torch.FloatTensor([[4.0]]) 
# 입력한 값 4에 대해서 예측값 y를 리턴받아서 pred_y에 저장
pred_y = model(new_var) # forward 연산
# y = 2x 이므로 입력이 4라면 y가 8에 가까운 값이 나와야 제대로 학습이 된 것
print("훈련 후 입력이 4일 때의 예측값 :", pred_y) 

#훈련 후 입력이 4일 때의 예측값 : tensor([[7.9989]], grad_fn=<AddmmBackward>)

👉🏻확인을 위해 x에 임의의 값 4를 넣어 y를 예측해보았다. 8에 가까운 7.9989가 나왔기 때문에 W와 b의 값이 어느정도 최적화가 된 것으로 볼 수 있다.

print(list(model.parameters()))

#[Parameter containing:
#tensor([[1.9994]], requires_grad=True), Parameter containing:
#tensor([0.0014], requires_grad=True)]

👉🏻W의 값이 2에 가깝고 b가 0에 가까운 것을 확인할 수 있다.

 

2. 다중 선형 회귀 구현하기


이제 nn.Linear()와 nn.functional.mse_loss()로 다중 선형 회귀를 구현해보자!
가설 수식은 \(H(x)=w_{1}x_{1}+w_{2}x_{2}+w_{3}x_{3}+b\)과 같다.
import torch
import torch.nn as nn
import torch.nn.functional as F
torch.manual_seed(1)

# 데이터
x_train = torch.FloatTensor([[73, 80, 75],
                             [93, 88, 93],
                             [89, 91, 90],
                             [96, 98, 100],
                             [73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])

👉🏻필요한 도구를 import하고 데이터를 선언한다.

# 모델을 선언 및 초기화. 다중 선형 회귀이므로 input_dim=3, output_dim=1.
model = nn.Linear(3,1)

👉🏻선형 회귀 모델을 구현한다. 3개의 입력 x에 대해 하나의 출력 y를 가지므로, 입력 차원은 3, 출력 차원은 1로 인수를 사용한다.

print(list(model.parameters()))
#[Parameter containing:
#tensor([[ 0.2975, -0.2548, -0.1119]], requires_grad=True), Parameter containing:
#tensor([0.2710], requires_grad=True)]

👉🏻3개의 w와 b를 확인할 수 있다. 두 값 모두 현재 랜덤 초기화가 되어져 있고, 학습의 대상이므로 requires_grad=True가 되어져 있다.

optimizer = torch.optim.SGD(model.parameters(), lr=1e-5) 

nb_epochs = 2000
for epoch in range(nb_epochs+1):

    # H(x) 계산
    prediction = model(x_train)
    # model(x_train)은 model.forward(x_train)와 동일함.

    # cost 계산
    cost = F.mse_loss(prediction, y_train) # <== 파이토치에서 제공하는 평균 제곱 오차 함수

    # cost로 H(x) 개선하는 부분
    # gradient를 0으로 초기화
    optimizer.zero_grad()
    # 비용 함수를 미분하여 gradient 계산
    cost.backward()
    # W와 b를 업데이트
    optimizer.step()

    if epoch % 100 == 0:
    # 100번마다 로그 출력
      print('Epoch {:4d}/{} Cost: {:.6f}'.format(
          epoch, nb_epochs, cost.item()
      ))

👉🏻옵티마이저를 정의하고 경사 하강법을 2000번 반복한다.

# 임의의 입력 [73, 80, 75]를 선언
new_var =  torch.FloatTensor([[73, 80, 75]]) 
# 입력한 값 [73, 80, 75]에 대해서 예측값 y를 리턴받아서 pred_y에 저장
pred_y = model(new_var) 
print("훈련 후 입력이 73, 80, 75일 때의 예측값 :", pred_y) 
#훈련 후 입력이 73, 80, 75일 때의 예측값 : tensor([[151.2305]], grad_fn=<AddmmBackward>)

👉🏻y값이 152였는데 예측값이 151로 근사하게 나왔다.

print(list(model.parameters()))
#[Parameter containing:
#tensor([[0.9778, 0.4539, 0.5768]], requires_grad=True), Parameter containing:
#tensor([0.2802], requires_grad=True)]

👉🏻3개의 w와 b의 값도 최적화된 것을 볼 수 있다.

 

 

728x90