참고
Click here to download the full example code
PyTorch: nn¶
\(y=\sin(x)\) 을 예측할 수 있도록, \(-\pi\) 부터 \(pi\) 까지 유클리드 거리(Euclidean distance)를 최소화하도록 3차 다항식을 학습합니다.
이번에는 PyTorch의 nn 패키지를 사용하여 신경망을 구현하겠습니다. PyTorch autograd는 연산 그래프를 정의하고 변화도를 계산하는 것을 손쉽게 만들어주지만, autograd 그 자체만으로는 복잡한 신경망을 정의하기에는 너무 저수준(low-level)일 수 있습니다; 이것이 nn 패키지가 필요한 이유입니다. nn 패키지는 입력으로부터 출력을 생성하고 학습 가능한 가중치를 갖는 신경망 계층(layer) 같은 Module의 집합을 정의합니다.
99 680.5642700195312
199 458.1858825683594
299 309.6250915527344
399 210.3185577392578
499 143.89418029785156
599 99.434814453125
699 69.65674591064453
799 49.6972541809082
899 36.3090705871582
999 27.32168960571289
1099 21.283653259277344
1199 17.223657608032227
1299 14.491271018981934
1399 12.650792121887207
1499 11.409923553466797
1599 10.572504043579102
1699 10.006810188293457
1799 9.624289512634277
1899 9.365362167358398
1999 9.189911842346191
Result: y = -0.013234248384833336 + 0.8424402475357056 x + 0.002283128211274743 x^2 + -0.0912962481379509 x^3
import torch
import math
# 입력값과 출력값을 갖는 텐서들을 생성합니다.
x = torch.linspace(-math.pi, math.pi, 2000)
y = torch.sin(x)
# 이 예제에서, 출력 y는 (x, x^2, x^3)의 선형 함수이므로, 선형 계층 신경망으로 간주할 수 있습니다.
# (x, x^2, x^3)를 위한 텐서를 준비합니다.
p = torch.tensor([1, 2, 3])
xx = x.unsqueeze(-1).pow(p)
# 위 코드에서, x.unsqueeze(-1)은 (2000, 1)의 shape을, p는 (3,)의 shape을 가지므로,
# 이 경우 브로드캐스트(broadcast)가 적용되어 (2000, 3)의 shape을 갖는 텐서를 얻습니다.
# nn 패키지를 사용하여 모델을 순차적 계층(sequence of layers)으로 정의합니다.
# nn.Sequential은 다른 Module을 포함하는 Module로, 포함되는 Module들을 순차적으로 적용하여
# 출력을 생성합니다. 각각의 Linear Module은 선형 함수(linear function)를 사용하여 입력으로부터
# 출력을 계산하고, 내부 Tensor에 가중치와 편향을 저장합니다.
# Flatten 계층은 선형 계층의 출력을 `y` 의 shape과 맞도록(match) 1D 텐서로 폅니다(flatten).
model = torch.nn.Sequential(
torch.nn.Linear(3, 1),
torch.nn.Flatten(0, 1)
)
# 또한 nn 패키지에는 주로 사용되는 손실 함수(loss function)들에 대한 정의도 포함되어 있습니다;
# 여기에서는 평균 제곱 오차(MSE; Mean Squared Error)를 손실 함수로 사용하겠습니다.
loss_fn = torch.nn.MSELoss(reduction='sum')
learning_rate = 1e-6
for t in range(2000):
# 순전파 단계: x를 모델에 전달하여 예측값 y를 계산합니다. Module 객체는 __call__ 연산자를
# 덮어써서(override) 함수처럼 호출할 수 있도록 합니다. 이렇게 함으로써 입력 데이터의 텐서를 Module에 전달하여
# 출력 데이터의 텐서를 생성합니다.
y_pred = model(xx)
# 손실을 계산하고 출력합니다. 예측한 y와 정답인 y를 갖는 텐서들을 전달하고,
# 손실 함수는 손실(loss)을 갖는 텐서를 반환합니다.
loss = loss_fn(y_pred, y)
if t % 100 == 99:
print(t, loss.item())
# 역전파 단계를 실행하기 전에 변화도(gradient)를 0으로 만듭니다.
model.zero_grad()
# 역전파 단계: 모델의 학습 가능한 모든 매개변수에 대해 손실의 변화도를 계산합니다.
# 내부적으로 각 Module의 매개변수는 requires_grad=True일 때 텐서에 저장되므로,
# 아래 호출은 모델의 모든 학습 가능한 매개변수의 변화도를 계산하게 됩니다.
loss.backward()
# 경사하강법을 사용하여 가중치를 갱신합니다.
# 각 매개변수는 텐서이므로, 이전에 했던 것처럼 변화도에 접근할 수 있습니다.
with torch.no_grad():
for param in model.parameters():
param -= learning_rate * param.grad
# list의 첫번째 항목에 접근하는 것처럼 `model` 의 첫번째 계층(layer)에 접근할 수 있습니다.
linear_layer = model[0]
# 선형 계층에서, 매개변수는 `weights` 와 `bias` 로 저장됩니다.
print(f'Result: y = {linear_layer.bias.item()} + {linear_layer.weight[:, 0].item()} x + {linear_layer.weight[:, 1].item()} x^2 + {linear_layer.weight[:, 2].item()} x^3')
Total running time of the script: ( 0 minutes 0.266 seconds)