테디노트: PyTorch의 자동미분(AutoGrad)기능과 경사하강법(Gradient Descent) 구현
✅
PyTorch의 자동미분(AutoGrad) 기능을 활용하여 경사하강법 알고리즘 직접 구현하기
✅ 손실(loss) 값과weight,bias변화량 시각화하기
# 모듈 import
from IPython.display import Image
import matplotlib.pyplot as plt
import numpy as np
import torch
y = 0.3x + 0.5의 선형회귀 식을 추종하는 샘플 데이터셋을 생성w=0.3, b=0.5를 추종하는 결과를 도출def make_linear(w=0.5, b=0.8, size=50, noise=1.0):
x = np.random.rand(size)
y = w * x + b
noise = np.random.uniform(-abs(noise), abs(noise), size=y.shape)
yy = y + noise
plt.figure(figsize=(10, 7))
plt.plot(x, y, color='r', label=f'y = {w}x + {b}', linestyle=':', alpha=0.3)
plt.scatter(x, yy, color='black', label='data', marker='.')
plt.legend(fontsize=15)
plt.show()
print(f'w: {w}, b: {b}')
return x, yy
x, y = make_linear(w=0.3, b=0.5, size=100, noise=0.01)
# w: 0.3, b: 0.5

torch.as_tensor())하고 랜덤한 w, b 생성# 샘플 데이터셋을 텐서(tensor)로 변환
x = torch.as_tensor(x)
y = torch.as_tensor(y)
# random 한 값으로 w, b를 초기화 합니다.
w = torch.rand(1)
b = torch.rand(1)
print(w.shape, b.shape)
# requires_grad = True로 설정된 텐서에 대해서만 미분을 계산합니다.
w.requires_grad = True
b.requires_grad = True
# torch.Size([1]) torch.Size([1])
# Hypothesis Function 정의
y_hat = w * x + b
# 손실함수 정의
loss = ((y_hat - y)**2).mean()
# 미분 계산 (Back Propagation)
loss.backward()
# 계산된 미분 값 확인
w.grad, b.grad
# 출력: (tensor([-0.6570]), tensor([-1.1999]))
# 하이퍼파라미터(hyper-parameter) 정의
# 최대 반복 횟수 정의
num_epoch = 500
# 학습율 (learning_rate)
learning_rate = 0.1
# loss, w, b 기록하기 위한 list 정의
losses = []
ws = []
bs = []
# random 한 값으로 w, b를 초기화 합니다.
w = torch.rand(1)
b = torch.rand(1)
# 미분 값을 구하기 위하여 requires_grad는 True로 설정
w.requires_grad = True
b.requires_grad = True
for epoch in range(num_epoch):
# Affine Function
y_hat = x * w + b
# 손실(loss) 계산
loss = ((y_hat - y)**2).mean()
# 손실이 0.00005보다 작으면 break 합니다.
if loss < 0.00005:
break
# w, b의 미분 값인 grad 확인시 다음 미분 계산 값은 None이 return 됩니다.
# 이러한 현상을 방지하기 위하여 retain_grad()를 loss.backward() 이전에 호출해 줍니다.
w.retain_grad()
b.retain_grad()
# 미분 계산
loss.backward()
# 경사하강법 계산 및 적용
# w에 learning_rate * (그라디언트 w) 를 차감합니다.
w = w - learning_rate * w.grad
# b에 learning_rate * (그라디언트 b) 를 차감합니다.
b = b - learning_rate * b.grad
# 계산된 loss, w, b를 저장합니다.
losses.append(loss.item())
ws.append(w.item())
bs.append(b.item())
if epoch % 5 == 0:
print("{0:03d} w = {1:.5f}, b = {2:.5f} loss = {3:.5f}".format(epoch, w.item(), b.item(), loss.item()))
print("----" * 15)
print("{0:03d} w = {1:.1f}, b = {2:.1f} loss = {3:.5f}".format(epoch, w.item(), b.item(), loss.item()))
# 전체 loss 에 대한 변화량 시각화
plt.figure(figsize=(14, 6))
plt.plot(losses, c='darkviolet', linestyle=':')
plt.title('Losses over epoches', fontsize=15)
plt.xlabel('Epochs')
plt.ylabel('Error')
plt.show()
# w, b에 대한 변화량 시각화
fig, axes = plt.subplots(1, 2)
fig.set_size_inches(14, 6)
axes[0].plot(ws, c='tomato', linestyle=':', label='chages')
axes[0].hlines(y=0.3, xmin=0, xmax=len(ws), color='r', label='true')
axes[0].set_ylim(0, 0.7)
axes[0].set_title('"w" changes over epoches', fontsize=15)
axes[0].set_xlabel('Epochs')
axes[0].set_ylabel('Error')
axes[0].legend()
axes[1].plot(bs, c='dodgerblue', linestyle=':', label='chages')
axes[1].hlines(y=0.5, xmin=0, xmax=len(ws), color='dodgerblue', label='true')
axes[1].set_ylim(0.2, 0.9)
axes[1].set_title('"b" changes over epoches', fontsize=15)
axes[1].set_xlabel('Epochs')
axes[1].set_ylabel('Error')
axes[1].legend()
plt.show()

