파이톨치

[BoostCamp AI Tech] 선형 회귀 모델 본문

AI&ML/BoostCamp AI Tech

[BoostCamp AI Tech] 선형 회귀 모델

파이톨치 2024. 8. 9. 14:47
728x90

 

 

선형 회귀란

선형 회귀란 다음을 목표로 한다.

1. 트레이닝 데이터 사용

2. 특징 변수와 목표 변수 사이의 선형 관계 분석

3. 이를 바탕으로 모델 학습

4. 새로운 데이터 예측

 

집 값을 예측하는 데이터 파일이 csv 파일로 존재한다면 아래와 같이 불러온다. 

import pandas as pd
# csv 파일은 기본적으로 ,를 기준으로 데이터를 구분한다.
data = pd.read_csv('Boston-house-price-data.csv', sep=',')

 

이 데이터를 x와 t (target)으로 나누어 준다. 

x = data.iloc[:, 1].values
t = data.iloc[:, 2].values

 

선형 회귀 모델에서 입력층은 특징 변수를 포함한다. 

학습 과정에서 가중치와 바이어스가 학습된다. 출력층은 예측 변수이며, 회귀모델에서는 하나의 뉴런으로 존재한다.

 

pytorch에서 모델을 만들 때, nn.Module을 사용한다. 

이는 일관성 + 모듈화 + GPU 지원이라는 장점이 있다.

이 모듈 안에 linear 층을 넣어주면 선형 회귀 모델 완성이다. 

import torch.nn as nn

class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)

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


model = LinearRegression()

 

최적화 알고리즘와 학습 

실제 모델을 효율적으로 돌리기 위해서는 최적화 사용한다. 

이는 데이터에 대해서 가중치를 어떻게 업데이트 할지 정하는 것이다. 

 

예를 들어, 데이터 전체에 대해 손실을 계산하고 가중치를 업데이트 하면 배치 경사하강법이다.

데이터 하나에 대해 손실을 계산하고 가중치를 업데이트 하면 확률적 경사 하강법이다. 

작은 배치에 대해 손실을 계산하고 가중치를 업데이트 하면 미니 배치 경사 하강법이다. 

 

동작 과정은 다음과 같다. 

1. 가중치 w값의 변화에 따른 손실 값을 본다. 

loss = criterion(predict_t, batch_t)

 

2. 손실에 대한 경사를 자동 미분 한다. 

loss.backward()

 

3. 경사(손실값)에 따라 가중치를 업데이트 한다. 

optimizer.step()

 

이를 몇 번 반복했느냐가 에폭이다.

에폭이 너무 크면 과적합이 생길 수 있음에 유의하자. 

 

정리하자면, 다음과 같다. 

criterion = nn.MSELoss()

num_epochs = 100
for epoch in range(num_epochs):
   for x_tensor, t_tensor in DataLoader:
  	  optimizer.zero_grad()
	  y = model(x_tensor)
	  loss = criterion(y, t_tensor)
	  loss.backward()
	  optimizer.step()

 

위에서 다루지 않은 DataLoader는 이제 설명하려 한다.

 

Dataset & DataLoader

예전에는 귀찮게 이런거 뭐하러 쓰냐고 생각했는데, 지금 보면 모듈화 해서 관리하는 엄청난 장점이 있다.

데이터를 일일이 처리하는게 아니라 한번에 묶어서 관리하는 것이다. 

 

먼저 Dataset 클래스를 통해서 인덱스 별로 데이터를 어떻게 넘겨줄지 정의한다. 

이 때, Series 와 같은 데이터 형으로 되어 있는 것을 tensor로 변환해준다. 

 

아래는 과제로 한 내용인데, self.X 와 self.y를 csv파일로 부터 읽은 후에 저장해준다. 

 

그리고 이것을 iloc을 통해서 인덱스 별로 넘겨준다. 공식문서를 보니, 대부분의 처리는 getitem 매서드에서 담당한다. 

때문에 이 메서드에서 텐서의 변환과 타입 지정을 해주었다. 또한 아래에서 문제가 생기길래 reshape을 통해서 차원을 맞추었다. 

class Dataset(Dataset):
    def __init__(self, file_path="car_data.csv", mode="train"):
        # [CODE START]
		# 생략
        # [CODE END]

    def __len__(self):
        # [CODE START]
        return len(self.X)
        # [CODE END]

    def __getitem__(self, idx) -> tuple:
        # [CODE START]
        X_item = torch.tensor(self.X.iloc[idx].values, dtype=torch.float32)
        y_item = torch.tensor(self.y.iloc[idx], dtype=torch.float32)
        return (X_item.reshape(-1), y_item.reshape(-1))
        # [CODE END]

 

Dataset 클래스가 잘 정의되어 있다면 로더 클래스에서는 그냥 하이퍼파라미터만 잘 넣어주면 된다. 

 

train_loader = DataLoader(train_data, batch_size=32, shuffle=True)
test_loader = DataLoader(test_data, batch_size=64, shuffle=False)

 

설명이 코드의 순서를 따르진 않지만, 잘 조합하면 학습 코드를 돌릴 수 있을 것이다. 

 

테스트 

테스트 데이터는 모델의 성능을 평가하기위해 존재한다. 이는 학습 데이터와 별개로 존재하며, 학습에 사용하지 않는다.

 

def predict_test_data(test_data):
    # 테스트 데이터 표준화
    test_scaled = scaler_x.transform(test_data.reshape(-1, 1))
    test_tensor = torch.tensor(test_scaled, dtype=torch.float32).view(-1, 1).to(device)

    # 모델을 사용하여 예측
    model.eval()  # 평가 모드로 전환
    with torch.no_grad():
        predictions_scaled = model(test_tensor)

    # 표준화 해제
    predictions = scaler_t.inverse_transform(predictions_scaled.cpu().numpy())
    return predictions

 

위의 함수를 통해서 테스트가 어떻게 진행되는지 알 수 있다. 

우선 scaler의 경우, 학습 데이터에서 fit을 하고 test에서는 fit하지 않는다. 평가 모드로 바꾸어, 모델 학습을 하지 않는다.

 또한 with torch.no_grad()를 통해 기울기 계산도 하지 않는다. (필요 없으니깐.) 

예측값을 실제로 우리에게 보여줄 때는 표준화를 해제한다. 이때 cpu로 올린다.

 

이를 정답값과 비교한다. 코드의 일부는 다음과 같다. 많이 나오는 코드 같으니 기억해주자. 

# model.eval()
inputs, targets = inputs.to(device).type(torch.float32), targets.to(device).type(torch.float32)

y_pred = model(inputs) # 예측
y_pred_class = (y_pred >= 0.5).float()
correct += (y_pred_class == targets).sum().item()
# n_data를 += 말고 = 으로 잘못 작성 했더니, 성능 낮게 나왔다.
n_data += len(targets)

print(f"accuracy: {correct/n_data}")

 

# 참고: 초기 가중치 초기화에 대해 

https://yngie-c.github.io/deep%20learning/2020/03/17/parameter_init/

 

가중치 초기화 (Weight Initialization) · Data Science

이번 게시물은 “밑바닥부터 시작하는 딥러닝”과 “Weight Initialization Techniques in Neural Networks”를 참조하여 작성하였습니다. Parameter Initialization 신경망 모델의 목적은 손실(Loss)을 최소화하는 과

yngie-c.github.io

 

 

728x90