[딥러닝 기초] Linear Regression

[딥러닝 기초] Linear Regression

다음의 책을 공부하며 정리한 내용입니다

선형회귀란

: 선형 회귀란 학습 데이터와 가장 잘 맞는 하나의 직선을 찾는 일.

  • 하나의 직선W와 b로 정의할 수 있다.
  • 선형 회귀의 목표: 가장 잘 맞는 직선을 정의하는 W와 b의 값을 찾는 것.

파이토치에서의 선형회귀

  • 선형 회귀 모델: nn.Linear()

  • 평균 제곱오차: nn.functional.mse_loss()

    torch.manual_seed() : 현재의 코드를 재실행해도 다음에도 같은 결과가 나오도록 랜덤 시드(random seed)를 준다.

선형회귀 훈련을 위한 기본적인 코드의 뼈대는 아래와 같다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 1.훈련데이터의 선언
# x_train의 벡터가 y_train이 되도록 하는 w와 b를 찾는다
import torch

x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])


# 2.가중치 W와 편향 b를 0으로 초기화
# requires_grad: 학습을 통해 값이 변경되는 변수임을 명시.
W = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)


# 3.직선의 방정식(=선형회귀)에 해당되는 가설을 선언한다.
# 가설 = 시스템이 학습한 w,b로 예측한 y_hat값
hypothesis = x_train * W + b
# print(hypothesis)


# 4.사용할 비용함수 선언(MSE)
cost = torch.mean((hypothesis - y_train) ** 2)


# 5.W와 b를 SGD(경사하강법: Stochastic Gradient Descent)로 훈련시킨다
# lr: learning rate
optimizer = torch.optim.SGD([W, b], lr=0.01)

이를 바탕으로 실제 동작하는 선형회귀 모델을 제작해 학습을 진행해보면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 최종코드
import torch
torch.manual_seed(1)

# 훈련데이터 선언
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])

# 학습데이터 w,b 선언. 둘다 값이 1인 임의의 스칼라 텐서
w = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)


# SGD방식을 사용한 최적화 선언
optimizer = torch.optim.SGD([w, b], lr=0.01)

# 학습 횟수는 1000+1회
tot_epoch = 1000

for cur_epoch in range(tot_epoch + 1):

# 새 학습값
y_hat = (w * x_train) + b

# MSE함수통한 비용 계산
cost = torch.mean((y_train - y_hat) ** 2)

# optimizer로 w,b 학습시킴으로서 y_hat 개선
# gradient를 0으로 초기화
optimizer.zero_grad()
# 비용 함수를 미분하여 gradient 계산
cost.backward()
# W와 b를 업데이트
optimizer.step()

# 100번마다 로그 출력
if cur_epoch % 100 == 0:
print('Epoch {:4d}/{} w: {:.3f}, b: {:.3f} Cost: {:.6f}'.format(
cur_epoch, tot_epoch, w.item(), b.item(), cost.item()
))
1
2
3
4
5
6
7
8
9
10
11
12
[결과]
Epoch 0/1000 w: 0.187, b: 0.080 Cost: 18.666666
Epoch 100/1000 w: 1.746, b: 0.578 Cost: 0.048171
Epoch 200/1000 w: 1.800, b: 0.454 Cost: 0.029767
Epoch 300/1000 w: 1.843, b: 0.357 Cost: 0.018394
Epoch 400/1000 w: 1.876, b: 0.281 Cost: 0.011366
Epoch 500/1000 w: 1.903, b: 0.221 Cost: 0.007024
Epoch 600/1000 w: 1.924, b: 0.174 Cost: 0.004340
Epoch 700/1000 w: 1.940, b: 0.136 Cost: 0.002682
Epoch 800/1000 w: 1.953, b: 0.107 Cost: 0.001657
Epoch 900/1000 w: 1.963, b: 0.084 Cost: 0.001024
Epoch 1000/1000 w: 1.971, b: 0.066 Cost: 0.000633

위의 코드와 결과는 다음을 의미한다.

  • x가 [1, 2, 3]일때 y가 [2,4,6]이 되는 w와 b는 2, 0이다.
  • 학습을 통해 최종적으로 찾은 결과 w,b는 1.971, 0.066이므로 어느정도 답을 찾아냈다고 볼 수 있다.

다중선형회귀

: 기존의 선형회귀가 y = wx + b의 w,b를 찾는 모델이었다면, 다중선형회귀는 y = w1x1 + w2x2 + w3x3 + bw1, w2, w3, b를 찾는 모델이다.

선형회귀 훈련을 위한 기본적인 코드의 뼈대는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# N개의 x_train 벡터와 가중치 w는 행렬로 표현할 수 있다.
# 5 * 3 학습벡터 => 길이 5의 x_train벡터 3개
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])

# y_train벡터의 길이 = x_train벡터의 길이(5)
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])

# 가중치 w의 개수 = x_train벡터의 개수(3) ** 길이는 1 **
w = torch.zeros((3, 1) ,requires_grad=True)
b = torch.zeros(1, requires_grad=True)

# x_train과 y_train벡터가 각각 행렬이므로
# 가설은 파이토치 행렬곱을 활용해 정의해준다.
hypothesis = x_train.matmul(w) + b

이를 바탕으로 실제 동작하는 다중선형회귀 모델을 제작해 학습을 진행해보면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 학습을 위한 코드는 기존과 동일하다.
import torch
torch.manual_seed(1)

x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]])
y_train = torch.FloatTensor([[152], [185], [180], [196], [142]])

# 모델 초기화
w = torch.zeros((3, 1) ,requires_grad=True)
b = torch.zeros(1, requires_grad=True)

# SGD방식을 사용한 최적화 선언
optimizer = torch.optim.SGD([w, b], lr=1e-5)

tot_epoch = 1000
for cur_epoch in range(tot_epoch + 1):

y_hat = x_train.matmul(w) + b
cost = torch.mean((y_train - y_hat) ** 2)

optimizer.zero_grad()
cost.backward()
optimizer.step()

# 100번마다 로그 출력
if cur_epoch % 100 == 0:
print('Epoch {:4d}/{} Cost: {:.6f}'.format(
cur_epoch, tot_epoch, cost.item()
))
1
2
3
4
5
6
7
8
9
10
11
12
[결과]
Epoch 0/1000 Cost: 29661.800781
Epoch 100/1000 Cost: 1.563628
Epoch 200/1000 Cost: 1.497595
Epoch 300/1000 Cost: 1.435044
Epoch 400/1000 Cost: 1.375726
Epoch 500/1000 Cost: 1.319507
Epoch 600/1000 Cost: 1.266222
Epoch 700/1000 Cost: 1.215703
Epoch 800/1000 Cost: 1.167810
Epoch 900/1000 Cost: 1.122429
Epoch 1000/1000 Cost: 1.079390

댓글