일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- rstudio 설치 오류
- 맵지도
- soa환불
- 대학원연수프로그램
- iris대학원
- dependency modeling
- rstudio 이전버전
- 행정동시각화
- 민원데이터
- 태블로에러
- soa자리선택
- soa시험예약
- explicit random effect model
- 태블로맵지도시각화
- 천안시 데이터 분석
- 이공계 대학원 연수 프로그램
- 모수추정
- 한-캐대학원
- rstudio이전버전 설치
- 태블로맵
- 맵지도시각화
- soa날짜
- 행정동표시
- 태블로행정동
- 한국캐나다대학원연수
- torch.nn.Linear
- random effect model
- soa시험
- 태블로
- wishart-gamma
- Today
- Total
수리통계 분석 코딩 실습
[torch] Loss 함수를 이용한 학습 모델링 본문
1. 목적함수란?
data(X,Y)가 주어졌을 때, ✔ 최적화하고싶은 함수를 정한 뒤, 추정하고 싶은 값을 구하는 근사치(using X)를 분류해 알아둬야한다.
❗ 다시말해, 최적화하고 싶은 함수는 추정치인($Y_{hat}$)과 $Y$값의 차이를 계산할 수 있는 방법(mse, rmse, 유클리디안거리 등)이 되는 것이고 추정하고 싶은 값($Y_{hat}$)은 $X$를 이용해 만드는 우리의 모델이 되는 것이다.
즉, $loss$에 사용되는 것이 최적화하고 싶은 함수(opitm function) 가 되는 것이고 이 loss의 미분을 계산해서 $Y_{hat}$의 weight(linear regression에선 coeff)를 update 시켜주는 것이다.
이해하기 쉽게 데이터를 만들어 구성해 아래 Y의 추정치가 의미하는 바를 이해하고, 최적화하고 싶은 함수를 왜 정의하는 지를 알아보자. 결론적으로 $Y_{hat}$이 어떻게 모델을 사용해 $Y$에 근접해지도록 코드가 구성되는 지를 파악하자.
[ 데이터를 이용한 최적함수 이해 ]
우리가 추정하고자 하는 $\hat{y} $이 데이터 $x$를 이용해 $\hat{y}=wx+b$와 같이 구성되어 있다고 하자.
이때, 실제 비교하는 $y = w*x + b +\epsilon$ 이라고 하자.
그럼 우린 $\hat{y}$를 계산하기 위해서 초기값 w,b(i.e $w_0, b_0$)를 주고 데이터 $x$ 값을 이용해 계산할 것이다.
이를 실제 값 $y$와 비교해 어느정도 차이가 나는지 비교해볼 것이다. (그래프를 이용하든..)
🎈 파이썬 코드
[1] data generation:
$b=-1,w=2$
$\hat{y}=xw+b$
import torch
torch.manual_seed(2021)
X = torch.arange(-3,3, 0.3).view(-1, 1)
Y = w0 * X + b0 + torch.randn(X.shape) # torch.randn(X.shape)은 random하게 주는 값 즉 eps이라고 볼수 있음
[2] calculate $\hat{y}$
w0 = torch.tensor(2.0) # w의 초기값은 2, b의 초기값은 -1로 줌
b0 = torch.tensor(-1.0)
yhat = w0*X+b0
[3] compare $\hat{y}$ & $y$
import matplotlib.pyplot as plt
plt.scatter(X.numpy(),Y.numpy())
plt.plot(X.numpy(),yhat.numpy())
우리는 $\hat{y}$는 $x$값을 이용해 추정되는 값임을 알았고 그 값은 $y$와 거의 유사한 값을 갖길 바란다. 그렇다면, 우리는 $\hat{y}$를 $y$와 근접하게 할 수 있을까? 방법은 $\hat{y} = X \cdot w + b$이므로 $w$와 $b$ 값을 update해 $yhat$을 y와 근접하게 해주면 된다!
그렇다면 어떻게 $w$와 $b$의 값을 update시켜 $\hat{y}$를 $y$에 근접하게 만들 수 있을까?
이때 필요한 것이 최적화하고자 하는 함수 즉, $loss$함수 이다.
▪ loss함수를 정의해 $\hat{y}$와 $y$의 차이를 계산한 뒤, 이 함수를 $\hat{y}$에 대해 미분하여, $w$, $b$값을 update시켜 줄 수 있다. 이는 학습률(lr)을 이용해 미분값을 곱해 기존값에서 빼줌으로써 다음 스텝의 $w$와 $b$를 update해준다. 이게 바로 모델 학습의 과정이다!!
최종적으로 모델 학습이 끝나면, $\hat{y}$와 $y$를 비교해 제대로 추정이 된건지를 판단한다.
2. $y_{hat}$이 linear regression인 모델 with 생성 데이터
$y_{hat}$이 linear regression이라는 것은 $y_{hat} = x \cdot w + b$위의 식과 같은 추정치임을 알 수 있다.
이때, $y_{hat}$의 coeff인 즉 $y_{hat}$의 값을 $y$로 근접하게 만들어 주기 위해 우리가 바꿀 수 있는 값은 $w$와 $b$일 것이다.
그렇다면 $w$와 $b$가 잘 만들어졌는지를 평가하는 함수, 즉, 최적화하고자 하는 함수인 $loss$를 정의해줘야할 것이다.
이때, 이 $loss$를 우리는 $Loss(w, b)=\sum\limits_{i=1}^{n}(Y -Y_{hat}(w,b))^2$를 이용하게 되는 것이다.
※ $Y_{hat} = x \cdot w + b $로 w와 b에 대한 함수이므로 $ Y_{hat}(w,b)$로 표현했으니 착오 없길 바란다.
▪ gradient descent
따라서, 학습 모델은 이 $ Loss(w, b)$를 각각 $w$, $b$에 대해 미분해서 기존의 $w$와 $b$값을 update하는데 학습률 lr을 곱해 기존값에서 빼는 방법을 gradient descent 방식이라고 부른다.
❔ 왜 학습률을 곱해 빼야할까?
이는 무작정 $ Loss(w, b)$를 미분해서 기존값에서 빼버리면 휙휙 값이 크게 빠져 $w$와 $b$를 어느정도 조정할 건지를 정한다. 이 조정되는 값을 학습률(learning rate, lr)로 부른다.
이때, $w_{grad}$와 $b_{grad}$의 계산방식은 아래와 같다.
[1] 데이터 생성
import torch
torch.manual_seed(2021)
X = torch.arange(-3,3, 0.3).view(-1, 1)
Y = w0 * X + b0 + torch.randn(X.shape) # torch.randn(X.shape)은 random하게 주는 값 즉 eps이라고 볼수 있음
[2] yhat 추정 모델 및 loss 함수 생성
앞서는 $\hat{y}=xw+b$로 직접 정의했으나, 우린 $w$와 $b$를 학습시켜 $Y_{hat}$을 $Y$와 유사해지도록 update시켜줄 것이므로 $Y_{hat}$을 $X$에 대한 모델로 정의한다.
def forward(x):
return x*w+b
w = torch.tensor(torch.randn([1,1]), requires_grad=True)
b = torch.tensor(torch.randn([1,1]), requires_grad=True)
# Loss(w,b) 함수 정의
def criterion(yhat, y):
return torch.mean((yhat-y)**2)
[3] 모델 학습
▪ 학습(m1)
history=[]
lr=0.1
for epoch in range(100):
# X에 대한 추정치
Yhat = forward(X)
# Yhat과 Y를 근사 시켜줄 최적화 함수 계산
loss = criterion(Yhat,Y)
# 해당 모델에 대한 w,b update를 위한 loss함수 미분
loss.backward()
# w,b update using Gradient descent method
w.data = w.data-lr*w.grad.data
b.data = b.data-lr*b.grad.data
# w_grad, b_grad값이 쌓이므로 이를 제거
w.grad = None
b.grad = None
# 모델 학습 epoch별 최적화 함수 loss 계산
history.append(loss.item())
학습의 방식은 $Y_{hat}$이 $w$와 $b$로 이뤄진 함수여서 위와 같이 $w,b$를 lr을 활용해 update했으나, torch.optim.SGD를 이용해서도 구할 수 있다.
즉, my_optimizer = torch.optim.SGD([w,b], lr=0.1) 를 이용해 모델의 Gradient desent 방식과 Loss(w,b)를 다시 미분하기 전 grad를 지워주는 방법을 아래와 같이 정의할 수 있다.
my_optimizer = torch.optim.SGD([w,b], lr=0.1) 1> Gradient descent my_optimizer.step() which is equivalent with w.data = w.data-lr*w.grad.data b.data = b.data-lr*b.grad.data 2> Making zero-grad before differentiation my_optimizer.zero_grad() which is equivalent with w.grad = None b.grad = None |
▪ 학습(m2)
my_optimizer = torch.optim.SGD([w,b], lr=0.1)
history=[]
lr=0.1
for epoch in range(100):
# X에 대한 추정치
Yhat = forward(X)
# Yhat과 Y를 근사 시켜줄 최적화 함수 계산
loss = criterion(Yhat,Y)
# 해당 모델에 대한 w,b update를 위한 loss함수 미분
loss.backward()
# w,b update using Gradient descent method with optimizer
my_optimizer.step()
# w_grad, b_grad값이 쌓이므로 이를 제거
my_optimizer.zero_grad()
# 모델 학습 epoch별 최적화 함수 loss 계산
history.append(loss.item())
[4] 학습 결과 확인
import matplotlib.pyplot as plt
plt.plot(history)
3. $y_{hat}$이 linear regression인 모델 with dataload
※ dataload를 이용하면, data(X,Y)를 Boston, Catseats pandas를 이용해서 생성할 수 있음.
이때도 학습 순서는 똑같다. 다만 train시키는 X와 Y값이 dataload를 이용해 저장해주는 것뿐..
[1] 데이터 생성 및 torch로 dataload
# Import libraries
import torch
from torch.utils.data import Dataset, DataLoader, TensorDataset
from torch import optim
앞선 X와 Y를 이용해 dataload함.
dataset = TensorDataset(X,Y)
trainloader=DataLoader(dataset = dataset, batch_size=5, shuffle=True)
[2] yhat 추정하는 model과 loss function에 대한 계산 함수 생성
# 아래 모델은 torch 내장 함수인 x @ beta는 torch.nn.Linear(1, 1, bias=False)와 같음.
def model(x):
return x @ beta + beta0
def criterion(yhat, y):
return torch.mean((yhat-y)**2)
▪ beta와 beta0의 초기값 설정
beta = torch.tensor(torch.randn([1,1]), requires_grad=True)
beta0 = torch.tensor(torch.randn([1,1]), requires_grad=True)
my_optimizer = torch.optim.SGD([beta, beta0], lr=0.1)
▪ 학습 with optimizer
trainloader란 학습 데이터가 (X,Y)로 생성했을 때 이를 쪼개서 학습시킬 수 있다. 즉, 앞서 dataload를 사용하지 않았을 땐 forward(X)로 X를 통으로 넣어 $Y_{hat}$을 계산했는데, dataload를 사용함으로써, 앞서 정의한 batch_size만큼 학습하는 데이터의 수를 줄여 (xx,yy)로 데이터를 학습시킬 수 있다.
이때, 계산된 학습과정을 살펴보고 싶으면, trainloader를 다 돈 뒤에 history에 저장해주어야한다.
그러므로, trainloader안에 xx,yy가 for문을 돌고 있으면, LOSS_sum을 새롭게 정의해
epochs=100
history=[]
n=len(X)
for epoch in range(epochs):
LOSS_sum = 0
for xx, yy in trainloader:
yhat = model(xx) + beta0 # 주의해야할 것은 mode(x)는 x *beta로 이뤄져있으므로, beta0를 더해서 yhat을 추정해야한다.
loss = criterion(yhat, yy)
LOSS_sum = LOSS_sum + loss * len(yy)
my_optimizer.zero_grad()
loss.backward()
my_optimizer.step()
history.append(LOSS_sum.item()/n)
plt.plot(history)
❔ 더 나은 추정방법은 무엇이 있을까? → X_design을 사용, 즉, model이 x @ beta로 정의되어 있으므로, yhat을 추정할 때 beta0를 더 해주지말고 coeff가 계산될 수 있도록 [1,1,...,1] colum을 X에 추가해 yhat 모델을 만들어 주자!
ones = torch.ones([X.shape[0],1])
XX = torch.concat([ones, X], axis=1)
dataset_xx = TensorDataset(XX,Y)
trainloader_xx=DataLoader(dataset = dataset_xx, batch_size=5, shuffle=True)
beta = torch.tensor(torch.randn([2,1]), requires_grad=True) ### coeff항이 추가 됐으므로 shape은 [2,1]
#my_optimizer = torch.optim.SGD(model.parameters(), lr=0.1)도 아래와 같음.
my_optimizer = torch.optim.SGD([beta], lr=0.1)
▪ 모델 학습
epochs=100
history=[]
n=len(X)
for epoch in range(epochs):
LOSS_sum = 0
for xx, yy in trainloader_xx:
yhat = model(xx)
loss = criterion(yhat, yy)
LOSS_sum = LOSS_sum + loss * len(yy)
my_optimizer.zero_grad()
loss.backward()
my_optimizer.step()
history.append(LOSS_sum.item()/n)
plt.plot(history)
[3] yhat 추정하는 model을 torch.nn.Linear를 이용해 생성 및 loss function에 대한 계산 함수 생성
앞서, yhat의 학습시키는 function 즉, model(x)를 정의해 yhat을 추정했는데 사실 이건 torch 내장 함수인 torch.nn.Linear(param_num, outlayer, bias = T/F)를 이용해 정의할 수 있다.
※ bias = True는 coeff를 추가로 주는 것을 의미한다. 즉, design_matrix가 아닌 X자체로 linear reg을 할 경우 bias = True로 설정하면 자동적으로 $\beta_0$를 계산할 수 있게 된다.
'''def model(x):
return x @ beta + beta0
와 같은 기능을 하는 함수'''
model = torch.nn.Linear(1,1, bias = True)
list(model.parameters())
'''
# output
[Parameter containing:
tensor([[0.2632]], requires_grad=True),
Parameter containing:
tensor([0.7931], requires_grad=True)]
beta, beta0 둘 다 있음을 알 수 있음.
'''
▪ 모델 학습
모델 학습을 위한 optimizer 함수 적용
my_optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
epochs=100
history=[]
n=len(X)
lr = 0.1
for epoch in range(epochs):
LOSS_sum = 0
for xx, yy in trainloader:
yhat = model(xx)
loss = criterion(yhat, yy)
LOSS_sum = LOSS_sum + loss * len(yy)
loss.backward()
my_optimizer.step()
my_optimizer.zero_grad()
history.append(LOSS_sum.item()/n)
plt.plot(history)
'대학원 > 통계프로그래밍' 카테고리의 다른 글
[torch] torch.stack을 이용한 데이터 쌓기 with Boston data (0) | 2023.10.23 |
---|---|
[torch] linear regression with Boston, Catseats data (0) | 2023.10.17 |