-
[Pytorch] 간단한 신경망 구현딥러닝 2020. 3. 16. 00:13
Pytorch 공식 튜토리얼 중 신경망 관련 내용에 대한 저의 코드입니다.
Medium https://medium.com/dair-ai/a-simple-neural-network-from-scratch-with-pytorch-and-google-colab-c7f3830618e0 예제에서는 직접 설정한 도함수를 이용해 BackPropagation을 실행하지만 저는 Pytorch의 backwatd 함수를 사용하였습니다.
본 예제에서 만드는 딥러닝 모델은 다음과 같은 간단한 모델입니다.
모델 구조 보시는 바와 같이 1개의 Hidden Layer로 구성된 매우 간단한 신경망입니다.
본 예제에서는 1x2 크기의 벡터를 입력으로 하고 1x1 텐서 (스칼라)를 출력으로 합니다.
먼저 학습 데이터입니다. X 텐서에 학습 데이터와 각각에 대응되는 결과값을 y 텐서에 넣었습니다. xPredicted는 실행시키고자 하는 데이터입니다.
X = torch.tensor(([7, 1], [5, 2], [6, 4], [7, 6], [8, 9]), dtype=torch.float) y = torch.tensor(([23], [40], [60], [62], [90]), dtype=torch.float) xPredicted = torch.tensor(([5, 5]), dtype=torch.float)
다음으로는 X텐서와 y텐서에 값들을 스케일링하겠습니다.
X_max, _ = torch.max(X, 0) xPredicted_max, _ = torch.max(xPredicted, 0) X = torch.div(X, X_max) xPredicted = torch.div(xPredicted, xPredicted_max) y = torch.div(y, torch.tensor(([100]), dtype=torch.float))
y의 경우는 최대를 100으로 설정하였습니다.
다음으로는 핵심인 신경망입니다.
import torch.nn as nn class NeuralNetwork(nn.Module): def __init__(self, ): self.inputSize = 2 self.outputSize = 1 self.hiddenSize = 3 self.w1 = torch.randn(self.inputSize, self.hiddenSize, requires_grad=True) self.w2 = torch.randn(self.hiddenSize, self.outputSize, requires_grad=True) self.learning_rate = 0.001 def forward(self, X): self.z1 = torch.matmul(X, self.w1) self.z2 = torch.sigmoid(self.z1) self.z3 = torch.matmul(self.z2, self.w2) out = torch.sigmoid(self.z3) return out def train(self, X, y): out = self.forward(X) error = ((y-out)**2).mean() error.backward() self.w1.data += self.learning_rate*(self.w1).grad self.w2.data += self.learning_rate*(self.w2).grad def saveWeights(self, model): torch.save(model, "NerualNetwork") def predict(self): print("Input Data: ", str(xPredicted)) print("Predicted: ", str(self.forward(xPredicted)))
Pytorch의 nn 을 사용하여 구현하였으며 hidden layer는 한 개이므로 두 개의 weight을 사용하였습니다.
이때 학습 과정에서는 단순화를 위해 bias는 사용하지 않았으며 각각의 wieght를 조정하여 학습하기 위해 requires_grad=True으로 설정하였습니다. train 과정에서는 에러를 계산하고 이 에러를 편미분 하여 각각의 weight에 대한 변화율을 계산합니다. 이때 self.w1.data와 같이 설정한 것은 self.w1으로 설정할 경우 runtime error가 나기 때문입니다. 이는 leaf variable을 replace 할 경우 생기는 문제입니다.
결과를 확인하기 위한 과정은 다음과 같습니다.
NN = NeuralNetwork() trainIdx = 1000 for idx in range(trainIdx): if idx%100==0: print("#"+str(idx)+" Loss: "+str(torch.mean((y-NN.forward(X))**2).detach().item())) NN.train(X, y) NN.saveWeights(NN) NN.predict()
#0 Loss: 0.07525341957807541 #100 Loss: 0.08975683152675629 #200 Loss: 0.15257836878299713 #300 Loss: 0.2301979959011078 #400 Loss: 0.2512035667896271 #500 Loss: 0.25329679250717163 #600 Loss: 0.25344881415367126 #700 Loss: 0.2534591853618622 #800 Loss: 0.25345999002456665 #900 Loss: 0.25345999002456665 Input Data: tensor([1., 1.]) Predicted: tensor([1.], grad_fn=<SigmoidBackward>)
원하는 결과를 얻은 것을 볼 수 있습니다.
'딥러닝' 카테고리의 다른 글
[Pytorch] EMNIST CNN (0) 2020.04.03 [Pytorch] MNIST CNN (0) 2020.03.31 [Pytorch] MNIST 신경망 구현 (0) 2020.03.28