본문 바로가기
AI

파이토치로 구현한 선형회귀

by 코낄2 2024. 1. 8.

1. 단항 선형 회귀 실습

단항 선형 회귀는 하나의 독립 변수와 종속 변수 간의 선형 관계를 모델링하는 통계적 기법입니다.

import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
torch.manual_seed(2024)
# 동일한 시드를 사용하는 경우 항상 동일한 난수가 생성
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])
plt.figure(figsize = (6,4))
plt.scatter(x_train, y_train)

✔️ y = ax + b -> y = Wx + b

일반적으로 기울기는 W[weight]로 표현합니다.

model = nn.Linear(1, 1)
  • nn.Linear는 PyTorch에서 제공하는 선형 레이어를 의미
  • (1, 1) 첫 번째 인자는 입력 피처의 수, 두 번째 인자는 출력 피처의 수. 즉,  단일 입력과 단일 출력을 가지는 선형 레이어를 정의
  • (1, 1, bias = False) : 'b를 쓰지 않고 W 만으로 계산하겠다'고 정의할 수 있음. 하지만 계산이 정확하지 않고 틀릴 확률이 높아져서 거의 쓰지 않음
print(model)
// Linear(in_features=1, out_features=1, bias=True)
y_pred = model(x_train)
print(y_pred)
tensor([[0.7260],
        [0.7894],
        [0.8528]], grad_fn=<AddmmBackward0>)

# 학습이 안된 모델에 데이터를 넣었기 때문에 예측이 하나도 맞지 않는다.

  • model.parameters() : 모델 내의 각 레이어에 대한 가중치(weight) 및 편향(bias) 등과 같은 매개변수들이 포함된 iterator가 반환
print(list(model.parameters()))

[Parameter containing:
tensor([[0.0634]], requires_grad=True), Parameter containing:
tensor([0.6625], requires_grad=True)]

# W : 0.0634, b: 0.6625
# y = 0.0634x + 0.6625
# MSE 직접 구해보기
((y_pred - y_train) ** 2).mean()
// tensor(12.8082, grad_fn=<MeanBackward0>)

# MSE 구하는 함수
loss = nn.MSELoss()(y_pred, y_train)
loss // tensor(12.8082, grad_fn=<MseLossBackward0>)
# 데이터: 1, 2, 3
# W: 0.0634, b: 0.6625
# y = Wx + b

print(0.0634*1 + 0.6625) // 0.7259
print(0.0634*2 + 0.6625) // 0.7893
print(0.0634*3 + 0.6625) // 0.8527
# 처음 나온 예측값 [0.7260],[0.7894],[0.8528] 확인

2. 경사하강법(Gradient Descent)

머신러닝에서 학습은 모델이 주어진 데이터에 대해 최적의 예측을 수행할 수 있도록 모델의 매개변수를 조정하는 과정을 의미합니다. 이때 사용되는 핵심 개념 중 하나는 경사 하강법(Gradient Descent)입니다.

비용 함수는 현재 모델의 예측값과 실제 값 사이의 차이를 측정하는 함수입니다. 최적화 알고리즘은 이 비용 함수의 값을 최소로 만드는 모델 매개변수를 찾는 과정을 수행합니다. 이때 매개변수는 주로 가중치(W)와 편향(b)으로 이루어진 벡터입니다.

경사 하강법의 기본 원리

경사 하강법은 최적화 알고리즘 중 가장 기본적인 기법 중 하나입니다. 알고리즘은 현재 모델의 매개변수에서 비용 함수의 기울기(경사)를 계산하고, 이를 이용하여 매개변수를 조금씩 업데이트합니다. 이를 반복하면서 비용 함수를 최소화하는 최적의 매개변수를 찾아갑니다.

  • 경사 하강법의 핵심 단계
  1. 초기화: 가중치(W)와 편향(b)을 임의의 값으로 초기화합니다.
  2. 예측: 현재의 가중치와 편향을 사용하여 예측값을 계산합니다.
  3. 비용 계산: 예측값과 실제 값 사이의 차이를 나타내는 비용 함수 값을 계산합니다.
  4. 기울기 계산: 비용 함수의 기울기(경사)를 계산합니다.
  5. 매개변수 업데이트: 학습률과 기울기를 이용하여 가중치와 편향을 업데이트합니다.
  6. 반복: 위 단계를 반복하여 비용 함수를 최소화하는 매개변수를 찾습니다.

모델을 효과적으로 학습시키기 위해서는 적절한 학습률(learning rate) 및 다양한 변형된 경사 하강법 알고리즘을 사용하는 것이 중요합니다.

  • 학습률 (learning rate)

학습률은 각 반복에서 매개변수를 얼마나 업데이트할지 결정하는 중요한 하이퍼파라미터입니다. 즉, 학습률은 각 반복에서 경사의 방향으로 얼마나 많이 이동할지를 결정하는 요소로 작용합니다. 적절한 학습률을 선택하는 것은 모델의 수렴 속도와 성능에 영향을 미칩니다. 학습률이 너무 작으면 수렴이 느려질 수 있고, 너무 크면 발산할 수 있습니다.

# 어떤 GD 모델을 선택하냐에 따라서 속도와 정확도에 영향을 줄 수 있음
optimizer = optim.SGD(model.parameters(), lr=0.01)

✔️ SGD(Stochastic Gradient Descent)는 경사 하강법의 한 변형으로, 각 학습 반복에서 랜덤으로 선택된 하나의 데이터 샘플에 대한 기울기를 사용하여 모델의 매개변수를 업데이트하는 방법입니다. (데이터를 뽑고 다시 데이터를 넣고를 반복) 빠르게 방향을 결정하기 때문에 주로 대규모 데이터셋에서 효과적으로 사용됩니다.

loss = nn.MSELoss()(y_pred, y_train)

 

1. gradient를 초기화

초기화를 하지 않으면 오차값이 누적되기때문에 제대로 된 값을 찾지 못함

optimizer.zero_grad()

2. 역전파: 비용 함수를 미분하여 gradient(기울기) 계산

미분으로 순간 기울기를 실제로 구하는 과정

loss.backward()

3. W와 b를 업데이트

optimizer.step()

위 세개 함수는 공식처럼 순서대로 써준다.

print(list(model.parameters()))
# W: 0.2177, b: 0.7267 로 변경됨
  • 반복 학습을 통해 틀린 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}')

Epoch: 0/1000 Loss :  10.171454
Epoch: 100/1000 Loss :  0.142044
Epoch: 200/1000 Loss :  0.087774
Epoch: 300/1000 Loss :  0.054239
Epoch: 400/1000 Loss :  0.033517
Epoch: 500/1000 Loss :  0.020711
Epoch: 600/1000 Loss :  0.012798
Epoch: 700/1000 Loss :  0.007909
Epoch: 800/1000 Loss :  0.004887
Epoch: 900/1000 Loss :  0.003020
Epoch: 1000/1000 Loss :  0.001866

print(list(model.parameters()))
[Parameter containing:
tensor([[1.9499]], requires_grad=True), Parameter containing:
tensor([0.1138], requires_grad=True)]
# 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>)

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)
print(list(model.parameters()))
[Parameter containing:
tensor([[ 0.2202, -0.0686,  0.0746]], requires_grad=True), Parameter containing:
tensor([-0.3564], requires_grad=True)]

# y = 0.2202x + (-0.0686x) + 0.0746x + (-0.3564)

y_pred = model(x_train)
loss = nn.MSELoss()(y_pred, y_train)
loss// tensor(23401.4746, grad_fn=<MseLossBackward0>)
optimizer = optim.SGD(model.parameters(), lr=0.00001)
loss = nn.MSELoss()(y_pred, y_train)
epochs = 100000

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 % 10000 == 0:
        print(f'Epoch: {epoch}/{epochs} Loss : {loss : .6f}')

Epoch: 0/100000 Loss :  38561.125000
Epoch: 10000/100000 Loss :  27.054819
Epoch: 20000/100000 Loss :  21.526995
Epoch: 30000/100000 Loss :  18.144735
Epoch: 40000/100000 Loss :  16.060383
Epoch: 50000/100000 Loss :  14.774798
Epoch: 60000/100000 Loss :  13.980937
Epoch: 70000/100000 Loss :  13.489850
Epoch: 80000/100000 Loss :  13.184999
Epoch: 90000/100000 Loss :  12.994925
Epoch: 100000/100000 Loss :  12.875506

-------------------여러번 반복---------------------------

Epoch: 0/100000 Loss :  12.318503
Epoch: 10000/100000 Loss :  12.312752
Epoch: 20000/100000 Loss :  12.306840
Epoch: 30000/100000 Loss :  12.301049
Epoch: 40000/100000 Loss :  12.295231
Epoch: 50000/100000 Loss :  12.289417
Epoch: 60000/100000 Loss :  12.283563
Epoch: 70000/100000 Loss :  12.277835
Epoch: 80000/100000 Loss :  12.271925
Epoch: 90000/100000 Loss :  12.266117
Epoch: 100000/100000 Loss :  12.260382

print(list(model.parameters()))
[Parameter containing:
tensor([[-1.4633, -0.2084,  3.6617]], requires_grad=True), Parameter containing:
tensor([-1.5986], requires_grad=True)]

# y = -1.4633x + -0.2084x + 3.6617x + -1.5986
# [73, 80, 75] [150] 학습 데이터
# y = -1.4633x + -0.2084x + 3.6617x + -1.5986
-1.4633 * 73 + (-0.2084) * 80 + 3.6617 * 75 + (-1.5986) // 149.53599999999997
# [89, 91, 90], [180]
x_test = torch.FloatTensor([[91, 90, 89]])
y_pred = model(x_test)
print(y_pred) // tensor([[172.3759]], grad_fn=<AddmmBackward0>)

'AI' 카테고리의 다른 글

파이토치로 구현한 논리회귀  (0) 2024.01.08
기온에 따른 지면 온도 예측  (0) 2024.01.08
파이토치  (0) 2024.01.07
KMeans  (0) 2024.01.05
다양한 모델 적용  (1) 2024.01.05