공부시간 | 점수 |
---|---|
1 | 20 |
2 | 40 |
3 | 60 |
우리가 수집한 공부시간과 점수 데이터를 바탕으로 둘 간의 관계를 식으로 정의 할 수 있으면 내가 몇시간 공부하면 점수를 얼마 받을 수 있는지 예측할 수 있게 된다.
수집한 데이터를 기반으로 앞으로 예측할 수있는 모형을 만드는 것이 머신러닝 모델링이다.
가설
- 아직은 이 식이 feature와 target의 관계를 잘 표현하는 함수인지 여부를 알 수없기 때문에 이 식을 가설(hypothesis) 라고 한다.
- 가설을 세우고 모델링을 한 뒤 검증을 해서 좋은 예측결과를 내면 그 가설을 최종 결과 모델로 결정한다. 예측결과가 좋지 않을 경우 새로운 가설로 모델링을 한다.
공부시간
1개의 변수를 가진다.시험점수
한개이다.import torch study_hours = [[1], [2], [3]] # input (X) scores = [[20],[40],[60]] # output (y) X_train = torch.tensor(study_hours, dtype=torch.float32) y_train = torch.tensor(scores, dtype=torch.float32) print(X_train.shape, y_train.size()) ## (3:개수, 1:feature shape)
torch.Size([3, 1]) torch.Size([3, 1])
파라미터 (weight, bias) 정의
torch.manual_seed(0) # W * X + b ==> # Weight -> X feature 들에 곱해줄 가중치. X feature개수: 1 => weight: 1개 # bias -> 모든 feature들의 값이 0일 때 y의 값: 1개 ## weight, bias가 경사하강법을 이용한 최적화 대상. -> gradient를 구할 대상. # -> requires_grad=True weight = torch.randn(1, 1, requires_grad=True) # 1 - input shape(입력feature 개수) X 1 - output shape(출력값의 개수) bias = torch.randn(1, requires_grad=True) print("------- 초기파라미터(weight, bias) ---------") # 랜덤값 print(f"Weight shape: {weight.shape}, Bias shape: {bias.shape}") print("Weight:", weight) print("Bias:", bias)
------- 초기파라미터(weight, bias) ---------
Weight shape: torch.Size([1, 1]), Bias shape: torch.Size([1])
Weight: tensor([[1.5410]], requires_grad=True)
Bias: tensor([-0.2934], requires_grad=True)model_pred = X_train @ weight + bias model_pred
tensor([[1.2476],
[2.7886],
[4.3296]], grad_fn=)y_train
tensor([[20.],
[40.],
[60.]])
# 모델 정의 def linear_model(X) : return X @ weight + bias # 오차 계산 함수 (Loss Function, Cost Function) def loss_fn(pred, y): # 모델추정값과 정답을 받아서 오차 계산. ### 회귀 -> MSE (Mean Squared Error) return torch.mean((pred-y)**2)
# 모델로 추론 -> 오차 계산 pred = linear_model(X_train) loss = loss_fn(pred, y_train) print(pred) print(loss)
tensor([[1.2476],
[2.7886],
[4.3296]], grad_fn=)
tensor(1611.8477, grad_fn=)# 손실 함수(loss)를 역전파(backpropagation)하여 # 모든 학습 가능한 매개변수(가중치와 편향)에 대한 기울기(gradient)를 계산 loss.backword() lr = 0.001 # 경사하강법 알고리즘 # weight를 업데이트 # weight.grad : 손실 함수에 대한 가중치의 기울기 # 기울기의 방향으로 가중치를 조정하여 손실을 줄인다. weight.data = weight.data - weight.grad * lr bias.data = bias.data - bias.grad * lr
pred2 = linear_model(X_train) loss2 = loss_fn(pred2, y_train)
loss
tensor(1611.8477, grad_fn=)
loss2
tensor(1576.4189, grad_fn=)
torch.manual_seed(0) # weight, bias weight = torch.randn(1, 1, requires_grad=True) bias = torch.randn(1, requires_grad=True)
# model def linear_model(X) : return X @ weight + bias # loss fn(손실함수) - MSE def loss_fn(pred, y) : return torch.mean((pred-y)**2)
print(weight) print(bias)
tensor([[1.5410]], requires_grad=True)
tensor([-0.2934], requires_grad=True)linear_model(X_train)
tensor([[1.2476],
[2.7886],
[4.3296]], grad_fn=)epochs = 1000 # 반복횟수 lr = 0.01 for epoch in range(epochs) : # 1. 모델 추정 pred = linear_model(X_train) # 2. 오차 계산 loss = loss_fn(pred, y_train) # 3. parameter들의 gradient를 계산 loss.backward() # 4. parameter update ### weight update # weight.data: 현재값, weight.grad: gradient값 weight.data = weight.data - weight.grad * lr ### bias update bias.data = bias.data - bias.grad * lr # 5. weight, bias들의 gradient 값 초기화 weight.grad = None # weight.grad.zero_() bias.grad = None ##### 로그 출력(loss 값 출력) 100번 반복당 1회 출력 if epoch % 100 == 0 : print(f"[{epoch:03d}/{epochs}] loss - {loss}")
[000/1000] loss - 1611.84765625
[100/1000] loss - 3.812145471572876
[200/1000] loss - 2.3556692600250244
[300/1000] loss - 1.4556654691696167
[400/1000] loss - 0.8995130062103271
[500/1000] loss - 0.555845320224762
[600/1000] loss - 0.34347668290138245
[700/1000] loss - 0.21224628388881683
[800/1000] loss - 0.13115528225898743
[900/1000] loss - 0.08104630559682846# 결과 확인 print("최종 loss: ", loss.item())
최종 loss: 0.050322484225034714
print(weight) print(bias)
tensor([[19.7401]], requires_grad=True)
tensor([0.5908], requires_grad=True)pred2 = linear_model(X_train) pred2
tensor([[20.3309],
[40.0710],
[59.8111]], grad_fn=)y_train
tensor([[20.],
[40.],
[60.]])
######################################## # 파이토치 optimizer를 이용해서 파라미터 업데이트 ## w.data = w.data - w.grad * lr (이 작업을 처리하는 함수) ## gradient 초기화. torch.manual_seed(0) # weight, bias weight = torch.randn(1, 1, requires_grad=True) bias = torch.randn(1, requires_grad=True) # model def linear_model(X) : return X @ weight + bias # loss_fn(손실함수) -MSE def loss_fn(pred, y) : return torch.mean((pred-y)**2) # optimizer (instance) - 최적화대상 변수, learning rate optim = torch.optim.SGD( [weight, bias], # 최적화 대상(requires_grad=True) lr=0.01 )
a = torch.tensor(100)
#### 학습 for epoch in range(epochs): # 1. 모델 추정 pred = linear_model(X_train) # 2. loss 계산 loss = loss_fn(pred, y_train) # 3. gradient 계산 - 역전파(backpropagation) loss.backward() # 4. 파라미터 최적화 -> optimizer.step() optim.step() # w.data = w.data - w.grade * lr, bias # 5. 파라미터 grad 값 초기화 optim.zero_grad() # log if epoch % 100 == 0 or epoch == 999: print(f"[{epoch:03d}/{1000}] - loss: {loss}")
[000/1000] - loss: 1611.84765625
[100/1000] - loss: 3.812145471572876
[200/1000] - loss: 2.3556692600250244
[300/1000] - loss: 1.4556654691696167
[400/1000] - loss: 0.8995130062103271
[500/1000] - loss: 0.555845320224762
[600/1000] - loss: 0.34347668290138245
[700/1000] - loss: 0.21224628388881683
[800/1000] - loss: 0.13115528225898743
[900/1000] - loss: 0.08104630559682846
[999/1000] - loss: 0.050322484225034714
다음 가상 데이터를 이용해 사과와 오렌지 수확량을 예측하는 선형회귀 모델을 정의한다.
참조
온도(F) | 강수량(mm) | 습도(%) | 사과생산량(ton) | 오렌지생산량 |
---|---|---|---|---|
73 | 67 | 43 | 56 | 70 |
91 | 88 | 64 | 81 | 101 |
87 | 134 | 58 | 119 | 133 |
102 | 43 | 37 | 22 | 37 |
69 | 96 | 70 | 103 | 119 |
사과수확량 = w11 * 온도 + w12 * 강수량 + w13 * 습도 + b1
오렌지수확량 = w21 * 온도 + w22 * 강수량 + w23 *습도 + b2
온도
, 강수량
, 습도
값이 사과와, 오렌지 수확량에 어느정도 영향을 주는지 가중치를 찾는다.개별 과일를 예측하기 위한 weight들 @ feature들
의 계산 결과를 Node, Unit, Neuron 이라고 한다.온도, 강수량, 습도
세개의 변수를 가진다.사과수확량, 오렌지 수확량
2개의 값이다.# input: 생산환경 (temp, rainfall, humidity) : (5, 3) environs = [ [73, 67, 43], [91, 88, 64], [87, 134, 58], [102, 43, 37], [69, 96, 70] ] # Targets: 생산량 - (apples, oranges) - (5, 2) apple_orange_output = [ [56, 70], [81, 101], [119, 133], [22, 37], [103, 119] ]
X = torch.tensor(environs, dtype=torch.float32) y = torch.tensor(apple_orange_output, dtype=torch.float32) X.shape, y.shape
(torch.Size([5, 3]), torch.Size([5, 2]))
(2, 3)
(2, )
# input: (N, 3) weight: (3, 2) 3: feature들의 가중치개수, 2: 출력결과 개수(사과,오렌지) ### 행렬곱: N x 2 weight = torch.randn(3, 2, requires_grad=True) bias = torch.randn(2, requires_grad=True) # 사과, 오렌지 생산량에 각각 더할 bias print(weight) print(bias)
tensor([[-2.1788, 0.5684],
[-1.0845, -1.3986],
[ 0.4033, 0.8380]], requires_grad=True)
tensor([-0.7193, -0.4033], requires_grad=True)import pandas as pd result = X @ weight + bias print(result.shape) ### tensor.detach() : tensor객체를 gradient 계산 그래프에서 제거. (ndarray로 변경시 필요.) pd.DataFrame(result.detach().numpy(), columns=["사과생산량", "오렌지생산량"])
torch.Size([5, 2])
모델은 weights w
와 inputs x
의 내적(dot product)한 값에 bias b
를 더하는 함수.
weight = torch.randn(3, 2, requires_grad=True) bias = torch.randn(2, requires_grad=True) # model def model(X): return X @ weight + bias # loss 함수 def loss_fn(pred, y): # MSE return torch.mean((pred - y)**2) # total loss -> 두 값의 오차를 합한다.
gradient decent 알고리즘을 이용해 loss를 줄여 모델의 추론 성능을 높인다. 이를 위해 좋은 성능을 낼 수 있도록 경사하강법(gradient decent) 을 이용해 weight와 bias를 update한다.
epochs = 5000 lr = 0.00001 # 1e-5 for epoch in range(epochs): # 1. 추론 pred = model(X) # 2. loss 계산 loss = loss_fn(pred, y) # 3. gradient 계산 loss.backward() # 4. update weight.data = weight.data - weight.grad * lr bias.data = bias.data - bias.grad * lr # 5. grad값 초기화. weight.grad.zero_() # weight.grad = None bias.grad.zero_() if epoch % 100 == 0 or epoch == epochs-1: print(f"[{epoch:03d}/{epochs}] - loss: {loss}")
[000/5000] - loss: 36143.9296875
[100/5000] - loss: 180.45205688476562
[200/5000] - loss: 88.39179992675781
[300/5000] - loss: 56.189537048339844
[400/5000] - loss: 41.86906814575195
[500/5000] - loss: 33.46678924560547
[600/5000] - loss: 27.47199058532715
[700/5000] - loss: 22.7724666595459
[800/5000] - loss: 18.950511932373047
[900/5000] - loss: 15.801193237304688
[1000/5000] - loss: 13.194560050964355
[1100/5000] - loss: 11.033700942993164
[1200/5000] - loss: 9.24149227142334
[1300/5000] - loss: 7.754761695861816
[1400/5000] - loss: 6.521358489990234
[1500/5000] - loss: 5.498096942901611
[1600/5000] - loss: 4.649182319641113
[1700/5000] - loss: 3.944906711578369
[1800/5000] - loss: 3.3606231212615967
[1900/5000] - loss: 2.875887393951416
[2000/5000] - loss: 2.4737133979797363
[2100/5000] - loss: 2.1400771141052246
[2200/5000] - loss: 1.8632856607437134
[2300/5000] - loss: 1.6336517333984375
[2400/5000] - loss: 1.4431394338607788
...
[4700/5000] - loss: 0.5280918478965759
[4800/5000] - loss: 0.5259395837783813
[4900/5000] - loss: 0.5241520404815674
[4999/5000] - loss: 0.5226835608482361
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
import torch import torch.nn as nn inputs = torch.tensor( [[73, 67, 43], [91, 88, 64], [87, 134, 58], [102, 43, 37], [69, 96, 70]], dtype=torch.float32) targets = torch.tensor( [[56, 70], [81, 101], [119, 133], [22, 37], [103, 119]], dtype=torch.float32)
Pytorch는 nn.Linear 클래스를 통해 Linear Regression 모델을 제공한다.
nn.Linear에 입력 feature의 개수와 출력 값의 개수를 지정하면 random 값으로 초기화한 weight와 bias들을 생성해 모델을 구성한다.
## model: 선형회귀 -> nn.Linear() model = nn.Linear(3, 2) # 3: input feature 개수, 2: output 개수 # model.weight, model.bias # model.parameters() # weight/bias를 generator로 반환. ## optimizer -> model의 parameter들을 넣어서 생성. optim = torch.optim.SGD( model.parameters(), #최적화 대상 파라미터. lr=0.00001) #### loss 함수 (nn.functional의 함수, nn 클래스) loss_fn = nn.functional.mse_loss
주어진 epoch 만큼 학습하는 fit
함수를 정의한다.
def fit(epochs, model, loss_fn, optim): """ epochs: 학습 반복 횟수 model: 학습시킬 대상 모델 loss_fn: loss function객체 optim: optimizer 객체 """ for epoch in range(epochs): pred = model(inputs) loss = loss_fn(pred, targets) # 추정값, 정답 loss.backward() optim.step() # 파라미터 업데이트 optim.zero_grad() # 파라미터 초기화. if epoch % 100 == 0 or epoch == epochs-1: print(f"[{epoch:03d}/{epochs}] - loss: {loss}")
fit(5000, model, loss_fn, optim)
[000/5000] - loss: 5417.5205078125
[100/5000] - loss: 140.97897338867188
[200/5000] - loss: 60.7963752746582
[300/5000] - loss: 34.740440368652344
[400/5000] - loss: 24.478763580322266
[500/5000] - loss: 19.151737213134766
[600/5000] - loss: 15.62641716003418
[700/5000] - loss: 12.95262622833252
[800/5000] - loss: 10.804781913757324
[900/5000] - loss: 9.042614936828613
[1000/5000] - loss: 7.586211204528809
[1100/5000] - loss: 6.379502773284912
[1200/5000] - loss: 5.3788251876831055
[1300/5000] - loss: 4.548752784729004
[1400/5000] - loss: 3.8601462841033936
[1500/5000] - loss: 3.2888665199279785
[1600/5000] - loss: 2.81492018699646
[1700/5000] - loss: 2.4217281341552734
[1800/5000] - loss: 2.0955140590667725
[1900/5000] - loss: 1.8248975276947021
[2000/5000] - loss: 1.600362777709961
[2100/5000] - loss: 1.4140926599502563
[2200/5000] - loss: 1.2595579624176025
[2300/5000] - loss: 1.131352186203003
[2400/5000] - loss: 1.0249972343444824
...
[4700/5000] - loss: 0.514125406742096
[4800/5000] - loss: 0.5129227042198181
[4900/5000] - loss: 0.5119251012802124
[4999/5000] - loss: 0.5111059546470642
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...