자동 미분
tape_gradient()는 자동 미분 기능을 수행한다. 임의로 2w^2 + 5라는 식을 세워보고, w에 대해 미분해보자
Tensorflow를 활용한 자동 미분
import tensorflow as tf
w = tf.Variable(2.)
def f(w) :
y = w**2
z = 2*y + 5
return z
gradient를 출력하면 w에 대해 미분한 값이 저장된 것을 확인할 수 있다.
with tf.GradientTape() as tape :
z = f(w)
gradient = tape.gradient(z, [w])
print(gradient)
출력 결과 : [<tf.Tensor: shape=(), dtype=float32, numpy=8.0>]
Pytorch를 활용한 자동 미분
import torch
w = torch.tensor([2], dtype = float, requires_grad=True)
def f(w) :
y = w**2
z = 2*y + 5
return z
backward를 통해 w.grad에 미분된 값이 저장된 것을 확인할 수 있다.
z = f(w)
z.backward()
print(w.grad)
출력 결과 : tensor([8.], dtype=torch.float64)
이 자동 미분 기능을 사용해 선형 회귀를 구현해보자.
자동 미분을 이용한 선형 회귀 구현
Tensorflow를 활용한 선형 회귀 구현
선형 회귀를 위해 사용하고자 데이터는 x와 y가 약 10배의 차이를 가지는 데이터이다.
x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부하는 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부하는 시간에 매핑되는 성적
우선 가중치 변수 w와 b를 선언한다. 학습될 값이므로 임의의 값인 4와 1로 초기화하였다.
# 학습될 가중치 변수를 선언
w = tf.Variable(4.)
b = tf.Variable(1.)
이후 가설을 함수로 정의한다
# 가설을 함수로 정의
def hypothesis(x):
return w*x + b
현재의 가설에서 w와 b는 각각 4와 1이므로 임의의 입력값을 넣었을 때의 결과는 다음과 같다.
x_test = [3.5, 5, 5.5, 6]
print(hypothesis(x_test).numpy())
출력 결과 : [15. 21. 23. 25.]
이후 평균 제곱 오차(MSE)를 손실 함수로서 정의한다.
# 평균 제곱 오차를 손실 함수로 정의
# reduce_mean : 전체 평균을 구한다.
# square : 제곱 계산을 취한다.
def mse_loss(y_pred, y) :
# 두 개의 차이값을 제곱을 해서 평균을 취한다.
return tf.reduce_mean(tf.square(y_pred - y))
옵티마이저는 경사 하강법을 사용하되, 학습률(learning rate)는 0.01을 사용한다.
optimizer = tf.optimizers.SGD(0.01)
약 300번에 걸쳐서 경사 하강법을 수행하자.
for i in range(301) :
with tf.GradientTape() as tape :
# 현재 파라미터에 기반한 입력 x에 대한 예측값을 y_pred
y_pred = hypothesis(x)
# 평균제곱오차를 계산
cost = mse_loss(y_pred, y)
# 손실 함수에 대한 파라미터의 미분값 계산
gradients = tape.gradient(cost, [w, b])
# 파라미터 업데이트
optimizer.apply_gradients(zip(gradients, [w, b]))
if i % 10 == 0 :
print("epoch : {:3} | w 값 : {:5.4f} | b 값 : {:5.4f} | cost : {:5.4f}".format(i, w.numpy(), b.numpy(), cost))
w와 b값이 계속 업데이트 됨에 따라 cost가 지속적으로 줄어드는 것을 확인할 수 있다. 학습된 w와 b의 값에 대해 임의의 입력을 넣었을 경우의 예측값을 확인해보자.
x_test = [9.5]
print(hypothesis(x_test).numpy())
출력 결과 : [102.11695]
Pytorch를 활용한 선형 회귀 구현
x, y를 Pytorch의 형식에 맞게 변환한다.
x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부하는 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부하는 시간에 매핑되는 성적
x = torch.tensor(x, dtype = float)
y = torch.tensor(y, dtype = float)
다음으로 학습될 가중치를 선언한다. 값은 Tensorflow와 마찬가지로 w, b 값을 설정하였다.
# 학습될 가중치 변수를 선언
w = torch.tensor(4, dtype = float, requires_grad=True)
b = torch.tensor(1, dtype = float, requires_grad=True)
이후 가설을 함수로 정의한다
# 가설을 함수로 정의
def hypothesis(x) :
return w*x + b
이후 평균 제곱 오차(MSE)를 손실 함수로서 정의한다.
def mse_loss(y_pred, y) :
return torch.mean((y_pred - y) ** 2)
옵티마이저는 경사 하강법을 사용하되, 학습률(learning rate)는 0.01을 사용한다.
optimizer = torch.optim.SGD([w, b], lr = 0.01)
약 300번에 걸쳐 경사 하강법을 수행하자.
record_cost = [] # cost값 저장을 위한 list
for i in range(301) :
y_pred = hypothesis(x)
cost = mse_loss(y_pred, y)
record_cost.append(cost)
if i % 10 == 0 :
print("epoch : {:3} | w 값 : {:5.4f} | b 값 : {:5.4f} | cost : {:5.4f}".format(i, w.item(), b.item(), cost.item()))
# 학습
optimizer.zero_grad() # gradient 초기화
cost.backward() # gradient 계산
optimizer.step() # step()으로 개선
마찬가지로 w와 b값이 계속 업데이트 됨에 따라 cost가 지속적으로 줄어드는 것을 확인할 수 있다. 학습된 w와 b의 값에 대해 임의의 입력을 넣었을 경우의 예측값을 확인해보자.
x_test = torch.tensor([9.5])
print(hypothesis(x_test).item())
출력 결과 : 102.24478912353516
케라스로 구현하는 선형 회귀
모델을 구현하는 방법은 한 가지가 아니다. 텐서플로우의 경우, 케라스라는 고수준의 API를 사용하면 모델을 이보다 좀 더 쉽게 구현할 수 있다.
위와 같이 옵티마이저로 기본 경사 하강법인 sgd를 사용하며, 학습률은 0.01로 정했다. 손실 함수로는 평균 제곱 오차를 사용하며 전체 데이터에 대한 훈련 횟수는 300으로 하였다.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras import optimizers
x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부하는 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부하는 시간에 매핑되는 성적
model = Sequential() # 모델 선언
model.add(Dense(1, input_dim = 1, activation = "linear"))
SGD = optimizers.SGD(lr=0.01)
# 모델 컴파일
model.compile(optimizer = SGD, loss = 'mse', metrics = ['mse'])
# 모델 요약
model.summary()
# 모델 훈련
model.fit(x, y, epochs = 300)
학습 이후 최종적으로 선택된 오차를 최소화하는 직선을 그래프로 그려보자.
import matplotlib.pyplot as plt
# 폰트 지정
from matplotlib import rc
rc('font', family = 'AppleGothic')
plt.plot(x, model.predict(x), 'b', label = "오차를 최소화하는 직선")
plt.plot(x, y, 'k.', label = "훈련 데이터의 학습 시간에 따른 성적")
plt.xlabel('학습 시간')
plt.ylabel('예상 성적')
plt.legend()
위의 그래프에서 각 점은 우리가 실제 주었던 실제값에 해당되며, 직선은 실제값으로부터 오차를 최소화하는 w와 b의 값을 가지는 직선이다. 이 직선을 통해 9시간 30분을 공부하였을 때의 시험 성적을 예측해보자.
print(model.predict([9.5]))
출력 결과 : [[102.20154]]
Pytorch nn.module로 구현하는 선형 회귀
x, y를 Pytorch의 형식에 맞게 변환한다.
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
x = torch.FloatTensor([[1], [2], [3], [4], [5], [6], [7], [8], [9]]) # 공부하는 시간
y = torch.FloatTensor([[11], [22], [33], [44], [53], [66], [77], [87], [95]]) # 각 공부하는 시간에 매핑되는 성적
옵티마이저는 경사 하강법을 사용하되, 학습률(learning rate)는 0.01을 사용한다. 이후 약 300번에 걸쳐 경사 하강법을 수행하자.
model = nn.Sequential(
nn.Linear(1, 1)
)
optimizer = optim.SGD(model.parameters(), lr = 0.01)
epochs = 300
for i in range(1, epochs+1) :
# H(x) 계산
hypothesis = model(x)
# cost 계산
cost = F.mse_loss(hypothesis, y)
# cost로 H(x) 개선하는 부분
# gradientfmf 0으로 초기화
optimizer.zero_grad()
# 비용 함수를 미분하여 gradient 개선
cost.backward()
# W, b 업데이트
optimizer.step()
if i % 10 == 0 :
print("epoch : {:d} | cost : {:5.4f}".format(i, cost))
마찬가지로 w와 b값이 계속 업데이트 됨에 따라 cost가 지속적으로 줄어드는 것을 확인할 수 있다. 학습된 w와 b의 값에 대해 임의의 입력을 넣었을 경우의 예측값을 확인해보자.
print(model(torch.FloatTensor([9.5])).item())
출력 결과 : 102.17679595947266
Tensorflow, Pytorch에서의 자동 미분을 이용한 선형 회귀 구현, Keras를 활용한 선형 회귀 구현, Pytorch nn.module을 활용한 선형회귀 구현 모두 9시간 반을 공부했다고 했을 때의 출력값이 약 102 점으로 모두 유사한 것을 확인할 수 있다.
'NLP > 딥러닝을 이용한 자연어 처리 입문' 카테고리의 다른 글
[NLP] 5-6. 로지스틱 회귀 실습 (1) | 2024.01.05 |
---|---|
[NLP] 5-5. 로지스틱 회귀(Logistic Regression) (1) | 2024.01.05 |
[NLP] 5-3. 선형 회귀 (1) | 2024.01.04 |
[NLP] 5-2. 머신 러닝 훑어보기 (1) | 2024.01.03 |
[NLP] 5-1. 머신 러닝이란 (0) | 2024.01.03 |