구현을 위한 코드를 하나하나 뜯어보자
데이터 출처: https://www.kaggle.com/datasets/abhishek14398/salary-dataset-simple-linear-regression
!kaggle datasets download -d abhishek14398/salary-dataset-simple-linear-regression
!unzip salary-dataset-simple-linear-regression.zip
import torch
import pandas as pd
data = pd.read_csv("Salary_dataset.csv", sep = ",", header = 0)
x = data.iloc[:, 1].values
t = data.iloc[:, 2].values
캐글에서 데이터 다운받기: !kaggle datasets download -d 이게 명령어다. 뒤에 유저명/데이터명 넣으면 된다.그리고 다운로드된 파일을 unzip 후 사용해주면된다.
header
pd.read_csv(…., header = 0)
에서 header = 0 이란 ‘인덱스 0의 행을 데이터프레임의 열 이름으로 사용’ 이라는 의미
x = data.iloc[:, 1].values
에서 values 속성은 Pandas DataFrame이나 Series에서 데이터를 NumPy 배열 형태로 반환하는 역할을 한다
from sklearn.preprocessing import StandardScaler
scaler_x = StandardScaler()
x_scaled = scaler_x.fit_transform(x.reshape(-1, 1))
scaler_t = StandardScaler()
t_scaled = scaler_t.fit_transform(t.reshape(-1, 1))
x_tensor = torch.tensor(x_scaled, dtype=torch.float32).view(-1, 1)
t_tensor = torch.tensor(t_scaled, dtype=torch.float32).view(-1, 1)
앞서 이론 포스팅에서 한 번 다룬 바 있는 코드이다.
라이브러리 불러오기 → 스케일러 객체 생성 → 2차원 특징변수 배열 주입해 표준화 → 목적 변수에도 같은 방식 적용 → 2차원 텐서로 변경한다.
import torch.nn as nn
class LinearRegressionModel(nn.Module):
def __init__(self):
super(LinearRegressionModel, self).__init__()
self.linear = nn.Linear(1, 1)
def forward(self, x_tensor):
y = self.linear(x_tensor)
return y
model = LinearRegressionModel()
LinearRegressionModel
은 부모 클래스인 nn.Module
을 상속받는다(=자식 클래스가 부모 클래스의 기능을 자동으로 가지는 것. 추가적인 기능을 정의하거나 기존 기능을 확장할 수 있음)def init
(생성자)은 해당 클래스를 통해 객체를 처음 생성할 때 해야할 일을 정의하며, 처음 생성하는 순간 딱 한번 실행된다. super
를 통해 부모 모듈인 nn.Module
의 생성자를 그대로 받아온다. self.linear
라는 클래스 속성에 입력과 출력의 차원이 모두 1인 선형 회귀 모델을 정의한다device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
x_tensor = x_tensor.to(device)
t_tensor = t_tensor.to(device)
import torch.optim as optim
loss_function = nn.MSELoss() # 옵티마이저 정의
optimizer = optim.SGD(model.parameters(), lr = 0.01) # 학습률을 적절히 설정
optim.SGD
는 SGD의 알고리즘을 사용하며, model.parameters()
를 통해 현재 모델의 파라미터를 전달받고 학습률 0.01을 전달받아 optimizer객체를 세팅한다.
num_epochs = 1000
loss_list = []
for epoch in range(num_epochs):
y = model(x_tensor)
loss = loss_function(y, t_tensor)
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss.item())
if (epoch+1) % 100 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item()}')
for name, param in model.named_parameters():
print(f'{name}: {param.data}')
num_epochs
에 에폭 수를 1000으로 지정하면 for 문이 0부터 999번까지 실행된다. loss_list
나중에 그래프를 그리려고 손실값을 저장하는 리스트이다. model()
: 설명 변수 텐서를 입력, 예측 변수값 계산loss_function(,)
: 예측값과 실제값 입력, 손실값 계산 zero_grad()
: 이전 단계에 계산된 gradient를 0으로 초기화(누적없이 새로 계산하기 위함) backward()
:현재 loss에 대한 gradient를 계산step()
: 계산된 gradient를 사용해 parameter update model.named_parameters()
: 모델의 파라미터 이름과 그 값을 반환(각 파라미터의 이름과 값을 출력하기 때문에 학습과정 중 파라미터가 어떻게 변화하고 있는지 확인 가능하다. 디버깅에 유용)import numpy as np
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
test_experience = np.array([1.0, 2.0, 7.0])
predicted_salaries = predict_test(test_experience)
transform()
표준화할 데이터를 입력받고 표준화를 진행해 반환한다. 앞서 학습용 데이터에 fit된 scaler를 사용해 테스트 데이터를 표준화한다. torch.tensor().view(-1,1).to(device)
: 표준화를 위해 넘파이 배열 형태로 두었던 데이터를 다시 텐서로 변환한다. model.eval()
: 모델을 평가모드로 전환한다. with torch.no_grad()
: 이 블록 내에서는 gradient계산을 비활성화. 학습이 아니라 단순히 모델의 출력을 계산하려는 경우에 메모리 및 시간 비용을 줄일 수 있음 inverse_transform
: 표준화를 해제하여 예측값을 원래 스케일로 돌려놓는다
PyTorch에서 텐서(Tensor)와 모델의 연산은 같은 디바이스에서 이루어져야 한다. 모델과 입력 데이터 중 하나는 CUDA, 하나는 CPU에 할당되어 있다면 연산이 불가능하다(CPU와 GPU가 메모리를 따로 관리하기 때문)!
→ 모델, 옵티마이저, 데이터가 모두 같은 메모리를 사용하도록 해야한다!
: 일반적으로 옵티마이저는 모델의 파라미터를 추적하므로 모델과 같은 디바이스에 저장된다고 한다. 데이터와 모델의 디바이스에 신경쓰면 되겠다.
# 모델이 어느 디바이스에 있는지 확인
print(model.device)
# 특정 텐서가 어느 디바이스에 있는지 확인
print(x_tensor.device)
device
속성을 통해 확인 가능하다.
속성에 모델이 들어가는 이유: self.linear
에 회귀 모델(선형 계층)을 속성으로 정의하는 것은, 모델의 구조를 설정하고 이 구조를 여러 번 사용할 수 있게 하기 위함.
W, b의 초기값: 초기값은 nn.Linear
계층을 정의할 때 PyTorch가 자동으로 무작위로 설정!