본문 바로가기
IT 도서/Pytorch로 시작하는 딥 러닝 입문

02. 선형 회귀 (Linear Regression)

by 이민우 2021. 3. 1.
728x90
반응형

wikidocs.net/53560

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

*해당 글은 학습을 목적으로 위의 포스팅 내용 중 일부 내용만을 요약하여 작성한 포스팅입니다.

 상세한 내용 및 전체 내용 확인은 위의 링크에서 확인하실 수 있습니다.

 

 

선형 회귀

 

  • 연차와 연봉을 예시로 들면, 연차가 쌓일수록 연봉은 올라가게 된다.
  • 혹은 체지방과 운동량을 예시로 들면 운동량이 많아지면 체지방이 줄어들게 된다.
  • 이처럼 수학적으로 어떤 요인의 수치에 따라 특정 요인의 수치가 영향을 받는다.
  • 이 때 다른 변수를 변하게 하는 변수를 x, 다른 변수에 종속적인 변수를 y라고 하자.
  • x는 독립적으로 변할 수 있는 데 반해 y는 x의 값에 종속적으로 결정된다.
  • 그렇기에 x를 독립 변수, y를 종속 변수라고 하는데, 한 개 이상의 독립 변수와 종속 변수의 선형 관계를 모델링한 것이 선형 회귀이다.

 

 

단순 선형 회귀

  • 독립 변수 x가 한 개인 경우의 선형 회귀이다.
  • 식으로는 y = Wx + b 로 표현된다.
  • W를 가중치, b를 편향이라 한다.

 

 

비용 함수 (Cost Function)

  • 손실 함수, 오차 함수, 목적 함수라고도 부른다.
  • 모델의 예측값과 실제 값을 비교얼마나 다른 지를 수치로 나타낸다.

 

 

옵티마이저 (최적화 알고리즘)

  • 비용 함수를 최소로 하는 방법
  • 경사하강법 : 비용 함수를 미분하여 함수의 기울기를 구한 후 비용이 최소화 되는 방향으을 찾아내는 알고리즘
  • loss 값을 구한 후 backward() 함수를 호출하면 미분하여 기울기를 구할 수 있다.

*비용 함수와 옵티마이저에는 여러 종류가 있다. 그리고 풀고자 하는 문제에 가장 걸맞는 비용 함수와 옵티마이저는 전부 다르다.

*선형 회귀의 경우 평균 제곱 오차, 경사 하강법이 가장 어울린다.

 

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]])


#파이토치의 대부분의 구현체들은 모델을 생성할 때 클래스를 사용한다.
class LinearRegressionModel(nn.Module) :
  def __init__(self) :
    super().__init__()
    self.linear = nn.Linear(1,1) # 하나의 입력, 하나의 출력

  def forward(self, x) :
    return self.linear(x)

model = LinearRegressionModel()

optimizer = torch.optim.SGD(model.parameters(), lr = 0.01) #model.parameters는 가중치 W와 편향 b가 포함되어 있다. : 학습 대상

n_epochs = 2000
for epoch in range(n_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()
      ))

print(model(torch.FloatTensor([[5]])))

 

 


다중 선형 회귀 (Multivariable Linear Regression)

  • 다수의 x로부터 y를 예측하는 선형 회귀
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]])


class MultivariateLinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(3, 1) # 다중 선형 회귀이므로 input_dim=3, output_dim=1.

    def forward(self, x):
        return self.linear(x)

model = MultivariateLinearRegressionModel()
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()
      ))

print(list(model.parameters()))

 

 


미니 배치 이용하기

미니배치

  • 전체 데이터가 아닌, 작은 단위로 나누어 학습하는 개념.
  • 이 작은 단위를 미니배치라고 한다.
  • 미니배치의 크기를 배치 크기라고 한다.
  • 배치 크기는 크면 학습이 빠르지만 메모리 부족이 일어날 수 있다.
  • 그러나 작으면 학습이 느리지만 메모리 부족이 덜하다.
  • 너무 작으면 가중치가 자주 업데이트 되기 때문에 불안정한 훈련이 일어날 수 있다.

 

미니 배치 경사 하강법

  • 모든 데이터를 활용한 경사 하강법은 배치 경사 하강법이라 한다.
  • 미니 배치로 나누어 활용한 경사 하강법은 미니 배치 경사 하강법이라 한다.
  • 배치 경사 하강법은 전체 데이터를 사용하기에 가중치 값이 최적값에 수렴하는 과정이 안정적이지만, 계산량이 너무 많이 든다.
  • 미니 배치 경사 하강법은 전체 데이터의 일부로 수행하기에 최적값으로 수렴하는 과정을 헤멜 수 있지만속도가 빠르다.
  • 배치 크기는 보통 2의 제곱수를 사용하는데, CPU와 GPU의 메모리가 2의 배수라서 2의 제곱수일 때 데이터의 송수신 효율을 높일 수 있다고 한다.

 

이터레이션

  • 한 에포크당 매개 변수 업데이트가 몇 번 이루어질 것인가?
  • 예를 들어 1,000개의 데이터를 200 사이즈의 미니 배치로 나누면 Iteration은 5

 

 

데이터 로드용 함수

  • TensorDataSet : 텐서를 입력받아 Dataset 형태로 변환하는 함수
  • DataLoader : Dataset을 미니 배치로 나누고, 섞어줄 수 있는 함수
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import TensorDataset # 텐서데이터셋
from torch.utils.data import DataLoader # 데이터로더

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]])

#dataset으로 정의
dataset = TensorDataset(x_train, y_train)
#dataloader로 분배
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)

class MultivariateLinearRegressionModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(3, 1) # 다중 선형 회귀이므로 input_dim=3, output_dim=1.

    def forward(self, x):
        return self.linear(x)

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

nb_epochs = 2000
for epoch in range(nb_epochs+1):
    for batch_idx, samples in enumerate(dataloader) :
        # print(batch_idx)
        # print(samples)
        x_train, y_train = samples
        # H(x) 계산
        prediction = model(x_train)

        # cost 계산
        cost = F.mse_loss(prediction, y_train)

        # cost로 H(x) 계산
        optimizer.zero_grad()
        cost.backward()
        optimizer.step()

        print('Epoch {:4d}/{} Batch {}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, batch_idx+1, len(dataloader), cost.item()
            ))
728x90
반응형