Import
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
자주쓰는 기능들
optimizer.zero_grad() : 미분을 통해 얻은기울기 0 으로 초기화
cost.backward() : 비용함수를 미분하여 gradient계산
optimizer.step : 업데이트
단순 y = wx+b
# 데이터
x_train = torch.FloatTensor([[1], [2], [3]])
y_train = torch.FloatTensor([[2], [4], [6]])
# 모델 초기화
W = torch.zeros(1, requires_grad=True)
b = torch.zeros(1, requires_grad=True)
# optimizer 설정
optimizer = optim.SGD([W, b], lr=0.01)
nb_epochs = 1999 # 원하는만큼 경사 하강법을 반복
for epoch in range(nb_epochs + 1):
# H(x) 계산
hypothesis = x_train * W + b
# cost 계산
cost = torch.mean((hypothesis - y_train) ** 2)
# cost로 H(x) 개선
optimizer.zero_grad()
cost.backward()
optimizer.step()
# 100번마다 로그 출력
if epoch % 100 == 0:
print('Epoch {:4d}/{} W: {:.3f}, b: {:.3f} Cost: {:.6f}'.format(
epoch, nb_epochs, W.item(), b.item(), cost.item()
))
- optimizer = optim 여기서 이미 얘는 optimizer의 성격을 가지고
- zero_grad() 매 epoch마다 값이 변경되므로, 초기화를 시켜준다
- cost = torch.mean h-y 의 값을 cost로 가진다.
- cost.backward() 계산한 cost값을 기준으로 역전파를 진행한다
- optimizer.step() 미리 선언한 SGD를 기준으로 변수 업데이트를 진행한다
역전파 예제
import torch
w = torch.tensor(2.0, requires_grad=True)
y = w**2
z = 2*y + 5
z.backward()
print(z) # 13
print(z.grad) # None
print(w.grad) #8
- require_grad=True에서 w를 업데이트시키겠다고 하는게 보임
- z = 2 * y + 5 = 2 * (w**2) + 5 라는 수식임
- z.backward()를 했는데
- z.grad를 찍어보면 오히려 기울기가 안나오고
- w 오히려 w.grad로 기울기가 나옴
- 이유는 w변수가 requires_grad=True, 미분이 가능한 변수기 때문
loss가 2개??
x_train = torch.FloatTensor([[73, 80, 75],
[93, 88, 93],
[89, 91, 80],
[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)
# optimizer 설정
optimizer1 = optim.SGD([W, b], lr=1e-5)
nb_epochs = 20
for epoch in range(nb_epochs + 1):
# H(x) 계산
# 편향 b는 브로드 캐스팅되어 각 샘플에 더해집니다.
hypothesis = x_train.matmul(W) + b
# cost 계산
cost1 = torch.mean((hypothesis - y_train) ** 2)
cost2 = torch.mean((hypothesis - y_train) +2)
# cost로 H(x) 개선
optimizer1.zero_grad()
cost1.backward()
cost2.backward()
optimizer1.step()
print('Epoch {:4d}/{} hypothesis: {} Cost: {:.6f}'.format(
epoch, nb_epochs, hypothesis.squeeze().detach(), cost.item()
))
- W, b는 변수, requires_grad=True 에 주목
- 원래같으면 cost를 계산하는 수식이 1개인데, 여기서는 cost1, cost2를 만들어놨음(???)
- optimizer1.zero_grad() 기울기를 초기화 시켜주는 과정
- 만들어둔 cost1, cost2를 모두 backward() 시켜줌
- optimizer1.step() 으로 학습을 진행시켜줌
결과
RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time
왜 안될까?
딥러닝의 한계, backpropagation은 2개이상의 로스에 대해서는 제공하지않음
어떻게 고쳤으면 되었을까?
cost3 = (cost1+cost2).backward()
한땀한땀 쌓는 과정 nn.Linear
class LinearRegressionModel(nn.Module): # torch.nn.Module을 상속받는 파이썬 클래스
def __init__(self): #
super().__init__()
self.linear = nn.Linear(3, 2) # 단순 선형 회귀이므로 input_dim=3, output_dim=2
def forward(self, x):
return self.linear(x)
해당 소스코드는
model = nn.Linear(in_features=3, out_features=2) 이 소스코드와 동일한 기능을 함
nn.Linear는 레이어 한 줄을 의미함
데이터에 대한 DataLoader예제 (모델구성)
from torch.utils.data import TensorDataset # 텐서데이터셋
from torch.utils.data import DataLoader # 데이터로더
dataset= TensorDataset(x_train,y_train)
dataloader = DataLoader(dataset)
class modelex1 (nn.Module) :
def __init__(self) :
super().__init__()
self.layer1 = nn.Linear(in_features=3, out_features=1)
def forward(self, x):
return self.layer1(x)
- x_train과 y_train을 모두 TensorDataset에 넣고
- TensorDataset을 DataLoader에 넣는다
- super().__init__() 를 통해 torch.nn.Module를 상속받음
- 모델은 단순하게 in(3) → out(1) 의 단순한구조
- forward() 에서 모델의 학습을 진행시킴
- dataloader = DataLoader(x_train,y_train) 해봤는데 에러난다
데이터에 대한 DataLoader예제 (학습진행)
model = modelex1()
#model = nn.Linear(3,1)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-5)
nb_epochs = 20
for epoch in range(nb_epochs + 1):
for batch_idx, samples in enumerate(dataloader):
# print(batch_idx)
# print(samples)
x_train, y_train = samples
# H(x) 계산
prediction = model(x_train)
# cost 계산
cost = F.mse_loss(prediction, y_train)
# cost로 H(x) 계산
optimizer.zero_grad()
cost.backward()
optimizer.step()
print('Epoch {:4d}/{} Batch {}/{} Cost: {:.6f}'.format(
epoch, nb_epochs, batch_idx+1, len(dataloader),
cost.item()
))
- 모델은 아까 짜줬음
- Optimizer를 SGD로 선택함
- for문을 통해서 학습 진행
- for batch_idx, samples in enumerate(dataloader) 로 데이터로더에서 꺼낸다
- bacth_idx로 횟수를 확인해내는거고
- x_train, y_train = samples 로 데이터를 따로 받아서 설정한다
nn.Sequential의 간편함
model = nn.Sequential(
nn.Linear(2, 1), # input_dim = 2, output_dim = 1
nn.Sigmoid() # 출력은 시그모이드 함수를 거친다
)
- 이전까지는 모델을 짤때 nn.Linear로 한땀한땀 모델을 짜줬었다
- nn.Sequential() 을 만들어서. 한번에 여러개의 층을 만든다
- 해당 model에는 nn.Linear(2,1) nn.Sigmoid()를 포함한다
nn.Squential이 없다면
class BinaryClassifier(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(2, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
return self.sigmoid(self.linear(x))
위에 두개는 동일한 기능을 한다
TRAIN과정
def train(epochs) :
model.train() #모델 학습모드
for data, target in dataLoader :
optimizer.zero_grad
outputs= model(data)
loss = loss_fn(outputs, targets)
loss.backward()
optimizer.step()
- model.train 에서 train을 하겠다는 의지를 보여준다
- for data, target in dataLoader 데이터로더에서 데이터를 가져온 이후
- optimizer.zero_grad 기울기를 0으로 초기화
- outputs 은 data를 model에 거친 결과, 예측값
- loss는 예측값, 실제값의 오차
- loss.backward() 오차에 대한 역전파 진행
- optimizer.step() 학습을 진행
TEST과정
def test(epochs):
model.eval() #모델 평가모드
with torch.no_grad() : # 기울기를 구할필요가없음 # 미분을사용하지않음 #기울기를 0으로 고정
for data,targets in dataLoader :
outputs = model(data)
'DeepLearning' 카테고리의 다른 글
Recommending What Video to Watch Next : A Multitask Ranking System (0) | 2021.10.16 |
---|---|
BPR, Bayesian Personalized Ranking from Implicit feedback, Rendle (0) | 2021.10.16 |