본문 바로가기
컴퓨터

[pytorch] 파이토치 튜토리얼3

by skyjwoo 2020. 2. 10.
728x90
반응형

https://pytorch.org/tutorials/beginner/blitz/neural_networks_tutorial.html#sphx-glr-beginner-blitz-neural-networks-tutorial-py

 

Neural Networks — PyTorch Tutorials 1.4.0 documentation

Note Click here to download the full example code Neural Networks Neural networks can be constructed using the torch.nn package. Now that you had a glimpse of autograd, nn depends on autograd to define models and differentiate them. An nn.Module contains l

pytorch.org

 

Neural Networks, 신경망

 

신경망은 torch.nn 패키지를 이용해 구성할 수 있다.

nn(neural network)은 autograd에 의존하여 모델들을 정의하고, 모델들 간의 차이를 만들어낸다. nn.Module은 layer들과 output을 return하는 forward(input) method를 포함한다.

숫자 이미지를 분류하는 네트워크를 살펴보자, 간단한 feed-forward network이다. input을 받아서 몇 개의 다음 layer에서 그 다음 layer로 전달한다. 그리고 마지막으로 output을 뽑아낸다.

 

전형적인 신경망의 단계는 다음을 따른다.

  • 학습 가능한 매개변수(또는 가중치)를 가진 신경망을 정의힌다.

  • 입력된 dataset을 순회한다.

  • 신경망 속에서 input에 대해 처리한다.

  • loss를 계산한다. (정답에서 얼마나 벗어났는지)

  • 신경망의 각 매개변수에 gradients를 전달한다.

  • gradients를 바탕으로 신경망의 가중치를 갱신한다, 일반적으로 간단한 갱신 규칙을 사용한다. weight := weight - learning_rate * gradient

 

신경망 정의하기

import torch
import torch.nn as nn
import torch.nn.functional as F
#torch.nn.functional은 여러 함수를 갖고 있음, relu같은 활성화 함수?

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        # 1 input image channel, 6 output channels, 3x3 square convolution kernel
        self.conv1 = nn.Conv2d(1, 6, 3)
        self.conv2 = nn.Conv2d(6, 16, 3)
        # an affine operation: y = Wx + b
        self.fc1 = nn.Linear(16 * 6 * 6, 120)  # 6*6 from image dimension 
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # If the size is a square you can only specify a single number
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(-1, self.num_flat_features(x))
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = Net()
print(net)

forward function을 정의해야 하고, 역전파 함수는 autograd를 쓰면 자동으로 정의된다. forward에서는 어떤 Tensor 연산이든 사용할 수 있다.

모델의 학습 가능한 매개변수는 net.parameters()에 의해 return된다.

 

params = list(net.parameters())
print(len(params))
print(params[2].size())  # conv1's .weight

임의의 3232 input을 넣어보자. 주의: 이 신경망(LeNet)의 입력 크기는 3232이다. MNIST dataset을 이 신경망에 쓰기 위해선 이미지를 32*32로 resizing 해야 한다.

input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

모든 매개변수의 gradient buffer를 0으로 reset하고 임의의 gradients로 역전파를 시행한다.

net.zero_grad()
out.backward(torch.randn(1, 10))

주의: torch.nn은 mini-batch만 지원한다. 모든 torch.nn package는 하나의 표본이 아닌 여러 표본들의 mini-batch인 input만 다룬다.

예를 들어, nn.Conv2d는 'nSamples x nChannels x Height x Width' 4D Tensor를 다룰 것이다.

만일 하나의 sample만을 갖고 있다면, input.unsqueeze(0)을 통해 가짜 batch dimension을 추가해 사용해라

 

#unsqueeze 사용
input_sample = torch.randn(32, 32)
print(input_sample.size())
input_sample = input_sample.unsqueeze(0)
print(input_sample.size())

 

되돌아 보기

  • torch.Tensor - backward()와 같은 autograd 연산이 지원 되는 다차원 배열. tensor와 관련한 gradient를 갖고 있다.

  • nn.Module - 신경망 모듈,. 매개변수를 encapsulate하고 GPU로 옮기거나, 불러오거나 하는 데 도움을 주는 편리성을 제공.

  • nn.Parameter - Tensor의 한 종류로, Module의 attribute로 할당되었을 때 자동적으로 등록된다.

  • autograd.Function - autograd 연산의 정의된 forward, backward 연산을 수행한다. 모든 Tensor 연산은 적어도 하나의 Function node를 생성하고, 이 Function node는 Tensor를 생성한 function들에 연결되며, history를 부호화한다.

손실 함수, loss function

 

손실 함수는 (output, target)쌍을 input으로 받은 후, output(모델의 예측값)이 얼마나 target(우리가 원하는 값)을 벗어낫는 지를 값으로 계산한다.

nn package에는 여러 손실 함수들이 있다. 가장 간단한 함수는 nn.MSELoss로 output과 target 사이의 mean-squared error(평균 제곱 오차)를 구한다.

 

output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

.grad_fn을 이용해 역 방향으로 loss를 추적해 간다면, 다음과 같은 graph를 보게될 것이다.

 

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss

 

loss.backward()를 호출할 때, 전체 graph는 해당 loss에 의해 달라지고, graph의 모든 requires_grad=True된 Tensor는 그 Tensor의 .grad Tensor가 gradient로 쌓이게 될 것이다.

print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU

 

역전파

 

오차를 역전파하기 위해서는 loss.backward()를 하면 된다. 현재 존재하는 gradients들을 clear해 주는데, 그렇지 않으면 남아 있던 gradients에 누적된 값이 계산될 것이다.

net.zero_grad()     # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

nn package의 다양한 module과 loss function list https://pytorch.org/docs/stable/nn.html

 

 

가중치 갱신, weight update

 

가장 간단하면서 실제로 잘 쓰이는 규칙은 Stochastic Gradient Descent(SGD)

weight = weight - learning_rate * gradient

learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

 

그러나 여러 SGD 이외의 여러 update rule을 쓰고 싶다면, 작은 package를 만든다: torch.optim, 이 package가 모든 method를 수행할 것이다.

-> 원하는 optimizer를 설정할 수 있다.

 

import torch.optim as optim

# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)

# in your training loop:
optimizer.zero_grad()   # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # Does the update

주의: 왜 gradient buffer가 직접 0으로 set해야 했었는가(optimizer.zero_grad()) -> gradients가 역전파 과정에서 축적 돼 있었기 때문에

728x90
반응형

댓글