수업 복습/머신러닝과 딥러닝
파이토치로 구현한 선형회귀
김복칠
2024. 1. 9. 17:50
1. 단항 선형 회귀 실습
- 한 개의 입력이 들어가서 한 개의 출력이 나오는 구조
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
x_train = torch.FloatTensor(([1],[2],[3]))
y_train = torch.FloatTensor(([2],[4],[6]))
print(x_train, x_train.shape)
# 결과 : tensor([[1.],[2.],[3.]]) torch.Size([3, 1])
print(y_train, y_train.shape)
# 결과 : tensor([[2.],[4.],[6.]]) torch.Size([3, 1])
- 선형 회귀에 필요한 함수 및 모듈을 import 해주고 임의의 데이터를 만들어 줍니다
- 여기서 torch.FloatTensor 는 부동 소수점 타입의 텐서를 생성해주는 클래스입니다
plt.figure(figsize=(6,4))
plt.scatter(x_train, y_train)
- 해서 데이터를 figure로 나타내 주면 정비례 그래프가 점 형태로 나오는걸 확인할 수 있습니다
# y = ax + b -> y = Wx + b
model = nn.Linear(1, 1) # bias=True 가 디폴트로 적용되어 있음
print(model)
# 결과 : Linear(in_features=1, out_features=1, bias=True)
- 이후 위의 데이터를 기울기로 나타내기 위해 model을 만들어서 확인하는 작업을 해줍니다
- 여기서 model 변수에 입력된 코드는 데이터를 학습시켜주는 장비(?) 이며 Linear() 에 들어가는 값은 입력받은 데이터 수(x_train)와 출력하는 결과 수(y_train)를 넣어줍니다
y_pred = model(x_train)
print(y_pred) # 학습이 되어 있지 않기 때문에 아무 값이나 출력
# 결과 : tensor([[0.7260], [0.7894], [0.8528]], grad_fn=<AddmmBackward0>)
- 이후 만들어진 모델에 x_train 을 넣어 답안지를 확인해보면 학습이 진행되지 않았기 때문에 아무값이나 출력되는걸 확인할 수 있습니다
print(list(model.parameters()))
# 결과 : W : 0.0634, b : 0.6625
# y = 0.0634x + 0.6625
0.0634 + 0.6625
loss = nn.MSELoss()(y_pred, y_train)
loss
# 결과 : tensor(12.8082, grad_fn=<MseLossBackward0>)
print(0.0634*1 + 0.6625)
print(0.0634*2 + 0.6625)
print(0.0634*3 + 0.6625)
# 결과 : 0.7259 // 0.7893 // 0.8527
- model의 학습이 전혀 진행되지 않았기 때문에 W와 b의 값도 랜덤으로 출력되었고 Loss 값 또한 굉장히 높은걸 알수가 있습니다
- 그리고 x 값을 넣고 출력한 결과를 보면 하나도 일치하지 않는다는걸 확인할 수 있습니다
2. 경사하강법(Gradient Descent)
- 비용함수의 값을 최소로 하는 W와 b를 찾는 알고리즘을 옵티마이저(최적화) 알고리즘이라고 함
- 옵티마이저 알고리즘 중 가장 기본적인 기술이 경사하강법
- 옵티마이저 알고리즘을 통해 W와 b를 찾아낸 과정을 "학습"이라고 부름
'''
SGD(Stochastic Gradient Descent)
- 랜덤하게 데이터를 하나씩 뽑아서 loss을 만듦(랜덤이라 Stochastic)
- 데이터를 뽑고 다시 데이터를 넣고 반복
- 빠르게 방향을 결정
학습률(Learning rate)
- 한 번 움직이는 거리(increment step)
'''
optimizer = optim.SGD(model.parameters(),lr=0.01)
loss = nn.MSELoss()(y_pred, y_train)
# gradiant를 초기화
optimizer.zero_grad()
# 역전파 : 비용 함수를 미분히여 gradient(기울기) 계산
loss.backward()
# W와 b를 업데이트
optimizer.step()
print(list(model.parameters()))
# 결과 : W : 0.2177, b : 0.7267
- 이후 model을 학습시키고 정확성을 높이기 위해 Loss값과 optimizer 값의 학습을 입력해줍니다
- 이후 다시 한번 parameters() 를 확인해 주면 값이 기존값보다 향상된 걸 확인할 수 있습니다
# 반복 학습을 통해 틀린 W, b를 수정하면서 오차를 계속 줄여나감
# epochs : 반복 학습 횟수(에포크)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.MSELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f'Epoch : {epoch}/{epochs} Loss : {loss : 6f}')
print(list(model.parameters()))
# 결과 : W : 1.9499, b : 0.1138
x_test = torch.FloatTensor([[8]])
y_pred = model(x_test)
print(y_pred)
# 결과 : tensor([[15.7134]], grad_fn=<AddmmBackward0>)
- 이제 위의 내용들을 바탕으로 학습을 진행해 줍니다
- 학습할 횟수(epoch)를 설정하고 model을 학습해줍니다
- 이때 model을 통해 나온 y_pred(시험지를 학습을 통해 나온 결과지) 의 Loss값을 확인해 줍니다
- 그리고 optimizer를 초기화 하고 다시 세팅하는 과정을 반복해 줍니다
- 학습이 다 끝나게 되면 parameters() 를 통해 최적의 W,b 를 출력해서 임의의 데이터를 입력하여 결과가 잘 나오는지 확인해 줍니다
3. 다중 선형 회귀
- 여러 개의 입력이 들어가서 한 개의 출력이 나오는 구조
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[150], [190], [180], [200], [130]])
# y = a1x + a2x + a3x + b
model = nn.Linear(3, 1)
y_pred = model(x_train)
print(list(model.parameters()))
# 결과 : [Parameter containing:tensor([[ 0.5448, -0.4396, -0.3846]], requires_grad=True), Parameter containing:tensor([-0.1738], requires_grad=True)]
- 다중 선형 회귀는 input 값을 여러개 받아 output 으로 출력하는 과정을 나타냅니다
- 먼저 데이터를 임의로 만들어주고 model을 생성합니다
- 이때 input 의 데이터 구조를 보고 얼마를 받아서 출력할지를 결정합니다
- 위와 마찬가지로 학습이 되어있지 않기 때문의 결과가 랜덤으로 나오는 것을 알수 있습니다
optimizer = optim.SGD(model.parameters(),lr=0.000001)
epochs = 20000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.MSELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f'Epoch : {epoch}/{epochs} Loss : {loss : 6f}')
print(list(model.parameters()))
# 결과 : [Parameter containing:tensor([[0.9914, 0.5217, 0.4980]], requires_grad=True), Parameter containing:tensor([-0.1917], requires_grad=True)]
x_test = torch.FloatTensor([[92,90,89]])
y_pred = model(x_test)
print(y_pred)
# 결과 : tensor([[182.2965]], grad_fn=<AddmmBackward0>)
- 이제 위와 동일하게 학습을 시켜줍니다
- 그리고 학습한 model과 같은 input으로 데이터를 만들어서 확인해 주면 최적의 값이 나오는것을 확인할 수 있습니다
4. temps.csv 데이터에서 기온에 따른 지면 온도를 예측해보기
# df에 데이터 프레임으로 불러오기
import pandas as pd
PATH = '/content/drive/MyDrive/머신러닝과 딥러닝/data/temps.csv'
temp_df = pd.read_csv(PATH , encoding='euckr')
temp_df = temp_df.dropna()
temp_df.rename(columns={'기온(°C)':'temp','지면온도(°C)':'basetemp'}, inplace=True)
# data를 tensor 형태로 변경
x_data = temp_df[['temp']]
y_data = temp_df[['basetemp']]
x_data = torch.FloatTensor(x_data.values)
y_data = torch.FloatTensor(y_data.values)
- 이제 위에서 배운 내용들을 적용해보도록 하겠습니다
- 먼저 데이터를 df 형태로 받아옵니다
- 이후 데이터를 원하는 구성으로 정제해 줍니다
- 그리고 종속변수와 독립변수를 설정해서 딥러닝 작업을 위해 torch.FloatTensor() 적용을 해줍니다
- 여기서 values 값 출력을 위해 tensor 형태로 변환이 필요해서 x_data 초기 구성과정에 [] 를 한번 더 씌운것을 알수 있습니다
model = nn.Linear(1, 1)
optimizer = optim.SGD(model.parameters(),lr=0.001)
epochs = 5000
for epoch in range(epochs + 1):
y_pred = model(x_data)
loss = nn.MSELoss()(y_pred, y_data)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
print(f'Epoch : {epoch}/{epochs} Loss : {loss : 6f}')
print(list(model.parameters()))
y_pred = model(x_data).detach().numpy()
plt.figure(figsize=(8,6))
plt.scatter(x_data, y_data)
plt.plot(x_data, y_pred, color='deepskyblue')
- 종속변수(output) 과 독립변수(input) 이 1대1 구조로 되어있기 때문에 model에 학습을 시켜줍니다
- 이후 동일하게 학습을 진행해주고 최종모델에 x_data(독립변수) 를 입력해서 y_pred(모델에 독립변수를 넣어서 나온 예측결과지)를 만들어 줍니다
- 마지막으로 기존에 가지고 있던 x_data(독립변수)와 y_data(종속변수)를 점으로 나타내주고 학습시킨 모델을 바탕으로 나온 x_data(독립변수), y_pred(예측결과지)는 선으로 나타내주어서 비교해 줍니다