1. 단항 선형 회귀 실습

  • 한개의 입력이 들어가서 한 개의 출력이 나오는 구조
# 필요모듈 임포트
import torch
import torch.nn as nn # 뉴럴 네트워크
import torch.optim as optim
import matplotlib.pyplot as plt
# 토치에 상수를 저장할 수 있는데, 랜덤값의 고정을 시키기 위해 2024라는 seed를 설정함.
torch.manual_seed(2024)

# 결과값 => <torch._C.Generator at 0x7c27cae915b0>
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])
print(x_train, x_train.shape)
print(y_train, y_train.shape)

# 결과값 => 
# tensor([[1.],
#         [2.],
#         [3.]]) torch.Size([3, 1])
# 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
model = nn.Linear(1, 1)
# 앞 1은 입력값, 뒤 1은 출력값을 지정함.
# 만약(1, 1, bias=False)으로 설정하면 b는 사용하지 않는다고 선언.
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>)
print(list(model.parameters())) # W: 0.0634, b : 0.6625
# y = 0.0634x + 0.6625
0.0634 + 0.6625

# 결과값 => 
# [Parameter containing:
# tensor([[0.0634]], requires_grad=True), Parameter containing:
# tensor([0.6625], requires_grad=True)]
# 0.7259
# MSE
((y_pred - y_train) ** 2).mean()
# 결과값 => tensor(12.8082, grad_fn=<MeanBackward0>)

# -------------------------------------

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)
print(0.0634 * 2 + 0.6625)
print(0.0634 * 3 + 0.6625)

# 결과값 => 
# 0.7259
# 0.7893
# 0.8527

 

2. 경사 하강법(Gradient Descent)

  • 비용함수의 값을 최소로 하는 W와 b를 찾는 알고리즘 옵티마이저(최적화) 알고리즘이라고 함
  • 옵티마이저 알고리즘 중 가장 기본적인 기술이 경사하강법임
  • 옵티마이저 알고리즘을 통해 W와 b를 찾아내는 과정, "학습"이라고 부름.
# SGD : (Stochastic Gradient Desdoent)
# 랜덤하게 데이터를 하나씩 뽑아서 loss으로 만듦(랜덤이라 stachastic
# 데이터를 뽑고 다시 데이터를 넣고, 반복
# 빠르게 방향을 결정
# 학습률(Learning rate)
# 한번 움직이는 거리(increment step)
optimizer = optim.SGD(model.parameters(), lr=0.01)

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

# gradient를 초기화
# 오차값이 최하가 되는 기울기를 찾을때 값이 누적이 되는것을 방지하기 위해 초기화를 하는 코드를 작성함.
optimizer.zero_grad()

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

# W와 b를 업데이트
optimizer.step()

                         # 기존 => W : 0.0634, b : 0.6625
print(list(model.parameters())) # W: 0.2177, b : 0.7267

# 결과값 => 
# [Parameter containing:
# tensor([[0.2177]], requires_grad=True), Parameter containing:
# tensor([0.7267], requires_grad=True)]
# 반복 학습을 통해 틀린 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())) # W : 1.9499, b : 0.1138

# 결과값 => 
# [Parameter containing:
# tensor([[1.9499]], requires_grad=True), Parameter containing:
# tensor([0.1138], requires_grad=True)]

# -------------------------------------

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

print(x_train, x_train.shape)
print(y_train, y_train.shape)

# 결과값 => 
# tensor([[ 73.,  80.,  75.],
#         [ 93.,  88.,  93.],
#         [ 89.,  91.,  90.],
#         [ 96.,  98., 100.],
#         [ 73.,  66.,  70.]]) torch.Size([5, 3])
# tensor([[150.],
#         [190.],
#         [180.],
#         [200.],
#         [130.]]) torch.Size([5, 1])
# y = a1x + a2x + a3x + b
model = nn.Linear(3, 1)
print(model)

# 결과값 => Linear(in_features=3, out_features=1, bias=True)

# ----------------------------------

optimizer = optim.SGD(model.parameters(), lr=0.00001)

epochs = 10000

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 : -0.1461,  0.4496,  1.6962, b : -0.4009

# 결과값 => 
# [Parameter containing:
# tensor([[0.3478, 0.6414, 1.0172]], requires_grad=True), Parameter containing:
# tensor([-0.2856], requires_grad=True)]

# ------------------------

x_test = torch.FloatTensor([[92, 90, 89]])

y_pred = model(x_test)
print(y_pred)

# 결과값 => tensor([[179.9619]], grad_fn=<AddmmBackward0>)