출처: 차근차근 실습하며 배우는 파이토치 딥러닝 프로그래밍
경사하강법 구현 방법
예측 계산, 손실 계산, 경사 계산, 파라미터 수정 4개의 단계로 진행된다.
데이터 입력 및 변환
sampleData1 = np.array([
[166, 58.7],
[176.0, 75.7],
[171.0, 62.1],
[173.0, 70.4],
[169.0,60.1]
])
print(sampleData1)
데이터를 불러와서 독립변수, 종속변수를 나눠준다
x = sampleData1[:,0]
y = sampleData1[:,1]
print(x) #독립변수
print(y) #종속변수
[166. 176. 171. 173. 169.]
[58.7 75.7 62.1 70.4 60.1]
X = x - x.mean()
Y = y - y.mean()
plt.scatter(X, Y, c='k', s=50)
plt.xlabel('$X$')
plt.ylabel('$Y$')
#plt.title('데이터 가공 후 신장과 체중의 관계')
plt.show()
경사하강법의 대상이 될 값은 절댓값이 1을 넘지 않는 비교적 작은 값이 필요하다. 각 평균값을 빼주면 경사하강법이 수월해짐.
1) 예측 계산
데이터 X와 Y를 텐서 변수로 바꿔줌
X= torch.tensor(X).float()
Y= torch.tensor(Y).float()
print(X)
print(Y)
W= torch.tensor(1.0,requires_grad=True).float()
B= torch.tensor(1.0,requires_grad=True).float()
초기값은 1.0, 경사계산을 위해 자동으로 계산된 미분값이 저장되도록 requires_grad=True로 설정함.
def pred(X):
return W*X +B
Yp = pred(X)
print(Yp)
tensor([-4., 6., 1., 3., -1.], grad_fn=<AddBackward0>)
params = {'W': W, 'B': B}
g = make_dot(Yp, params=params)
display(g)
각 파라미터를 W,B값을 넣고 계산 그래프를 그려준다.
2) 손실 계산
def mse(Yp,Y):
loss = ((Yp-Y) **2).mean()
return loss
loss = mse(Yp,Y)
print(loss)
tensor(13.3520, grad_fn=<MeanBackward0>)
손실함수의 계산그래프를 그려준다.
손실이란 예측함수와 손실함수의 합성함수이다.
params = {'W': W, 'B': B}
g = make_dot(loss, params=params)
display(g)
3) 경사 계산
loss.backward()
print(W.grad)
print(B.grad)
tensor(-19.0400)
tensor(2.0000)
4) 파라미터 수정
경사 계산 후 파라미터 - 학습률* 파라미터 기울기를 통해 파라미터를 갱신함
W,B값은 외부에 영향을 끼치므로 마음대로 값을 수정할 수 없기 때문에, with torch.no_grad()를 통해 일시적으로 계산 그래프 생성 기능이 작동하지 않게 한다. grad.zero를 통해 다음 경사 계산을 준비하기 위해 경사값을 초기화 한다.
lr = 0.001
with torch.no_grad():
W -= lr * W.grad
B -= lr * B.grad
W.grad.zero_()
B.grad.zero_()
print(W)
print(B)
print(W.grad)
print(B.grad)
반복 계산
W = torch.tensor(1.0, requires_grad=True).float()
B = torch.tensor(1.0, requires_grad=True).float()
num_epochs = 500
lr = 0.001
history = np.zeros((0,2))
루프 처리 구현은 다음과 같다
for epoch in range(num_epochs):
Yp = pred(X)
loss = mse(Yp,Y)
loss.backward()
with torch.no_grad():
W -= lr* W.grad
B -= lr * B.grad
W.grad.zero_() #경삿값 초기화
B.grad.zero_()
if (epoch % 10 == 0):
item = np.array([epoch,loss.item()])
history = np.vstack((history,item))
print(f'epoch = {epoch} loss = {loss:.4f}')
결과평가
손실이 13.35에서 최종 4.67까지 줄어들었다.
# 최종 파라미터 값
print('W = ', W.data.numpy())
print('B = ', B.data.numpy())
# 손실 확인
print(f'초기상태 : 손실:{history[0,1]:.4f}')
print(f'최종상태 : 손실:{history[-1,1]:.4f}')
최적화 함수와 step 함수 이용
확률적 경사하강법으로 최적화를 진행하는 코드를 추가한다.
W = torch.tensor(1.0, requires_grad=True).float()
B = torch.tensor(1.0, requires_grad=True).float()
num_epochs = 500
lr = 0.001
import torch.optim as optim
optimizer = optim.SGD([W,B],lr = lr)
history = np.zeros((0,2))
for epoch in range(num_epochs):
Yp = pred(X)
loss = mse(Yp,Y)
loss.backward()
optimizer.step() #파라미터 수정
optimizer.zero_grad() #경사값 초기화
if (epoch % 10 ==0):
item = np.array([epoch,loss.item()])
history = np.vstack((history,item))
print(f'epoch = {epoch} loss = {loss:.4f}')
step() 함수를 호출하여 파라미터값을 변경했다.초기화도 zero_grad 함수를 사용한다.
# 최종 파라미터 값
print('W = ', W.data.numpy())
print('B = ', B.data.numpy())
# 손실 확인
print(f'초기상태 : 손실:{history[0,1]:.4f}')
print(f'최종상태 : 손실:{history[-1,1]:.4f}')
이전버전 결과와 비슷하게 나왔다.
최적화 함수의 튜닝버전 -> momentum = 0.9 옵션을 추가하여 학습속도를 더 빠르게 진행한다.
import torch.optim as optim
optimizer = optim.SGD([W, B], lr=lr, momentum=0.9)
'Machine Learning' 카테고리의 다른 글
MNIST 활용한 숫자 인식 (1) | 2024.04.15 |
---|---|
다중분류 with pytorch (0) | 2024.04.12 |
이진 분류 with pytorch (0) | 2024.04.11 |
선형회귀 with Pytorch (0) | 2024.04.08 |
예측 함수 정의 with pytorch (1) | 2024.04.06 |