파이토치 헬로 월드

저는 최근에 신경망 및 기계 학습을 위한 Python 프레임워크인 PyTorch 작업을 시작했습니다. 기계 학습에는 많은 양의 데이터 처리가 포함되기 때문에 때때로 네트워크에서 반환되는 결과를 이해하기 어려울 수 있습니다. 더 복잡한 것에 들어가기 전에 온전성 검사로 정말 기본적인 역전파를 복제해 봅시다. 이 기사의 코드를 실행하려면 NumPyPyTorch 을 설치해야 합니다.

에서 우리는 하나의 입력 뉴런, 하나의 숨겨진 뉴런 및 하나의 출력 뉴런으로 구성된 작은 네트워크에 대한 순방향 및 역방향 전파를 수동으로 계산하는 방법을 보았습니다.



우리는 네트워크를 통해 0.8의 입력을 실행한 다음 0.1의 학습률로 목표 값으로 1을 사용하여 역전파했습니다. 활성화 함수로 시그모이드를 사용하고 네트워크의 실제 출력과 원하는 출력을 비교하기 위해 2차 비용 함수를 사용했습니다.

아래 코드는 PyTorch를 사용하여 동일한 작업을 수행합니다.

import torch
import torch.nn as nn
import torch.optim as optim


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.hidden_layer = nn.Linear(1, 1)
        self.hidden_layer.weight = torch.nn.Parameter(torch.tensor([[1.58]]))
        self.hidden_layer.bias = torch.nn.Parameter(torch.tensor([-0.14]))

        self.output_layer = nn.Linear(1, 1)
        self.output_layer.weight = torch.nn.Parameter(torch.tensor([[2.45]]))
        self.output_layer.bias = torch.nn.Parameter(torch.tensor([-0.11]))

    def forward(self, x):
        x = torch.sigmoid(self.hidden_layer(x))
        x = torch.sigmoid(self.output_layer(x))
        return x


net = Net()
print(f"network topology: {net}")

print(f"w_l1 = {round(net.hidden_layer.weight.item(), 4)}")
print(f"b_l1 = {round(net.hidden_layer.bias.item(), 4)}")
print(f"w_l2 = {round(net.output_layer.weight.item(), 4)}")
print(f"b_l2 = {round(net.output_layer.bias.item(), 4)}")

# run input data forward through network
input_data = torch.tensor([0.8])
output = net(input_data)
print(f"a_l2 = {round(output.item(), 4)}")

# backpropagate gradient
target = torch.tensor([1.])
criterion = nn.MSELoss()
loss = criterion(output, target)
net.zero_grad()
loss.backward()

# update weights and biases
optimizer = optim.SGD(net.parameters(), lr=0.1)
optimizer.step()

print(f"updated_w_l1 = {round(net.hidden_layer.weight.item(), 4)}")
print(f"updated_b_l1 = {round(net.hidden_layer.bias.item(), 4)}")
print(f"updated_w_l2 = {round(net.output_layer.weight.item(), 4)}")
print(f"updated_b_l2 = {round(net.output_layer.bias.item(), 4)}")

output = net(input_data)
print(f"updated_a_l2 = {round(output.item(), 4)}")

이 코드에 대한 몇 가지 참고 사항:
  • nn.Linear는 완전히 연결되거나 조밀한 계층에 사용됩니다. 이 간단한 경우에는 각 레이어에 대해 단일 입력과 단일 출력이 있습니다.
  • forward 메서드는 입력을 output = net(input_data)로 네트워크에 전달할 때 호출됩니다.
  • 기본적으로 PyTorch는 임의 가중치 및 편향을 설정합니다. 그러나 여기에서는 결과가 수동 계산과 일치하기를 원하므로 직접 초기화합니다(이 문서의 뒷부분 참조).
  • PyTorch에서 tensor는 numpy의 array와 유사합니다.
  • criterion = nn.MSELoss()는 2차 비용 함수를 설정합니다. PyTorch에서는 평균 제곱 오류 손실 함수라고 합니다.
  • loss = criterion(output, target)는 손실이라고도 하는 비용을 계산합니다.
  • 다음으로 net.zero_grad()를 사용하여 그래디언트를 0으로 재설정합니다(그렇지 않으면 역전파가 누적됨). 여기서 반드시 필요한 것은 아니지만 루프에서 역전파를 실행할 때 이를 염두에 두는 것이 좋습니다.
  • loss.backward()는 기울기, 즉 모든 가중치 및 편향에 대한 비용의 미분을 계산합니다.
  • 마지막으로 학습률이 0.1인 SGD(확률적 경사하강법) 옵티마이저를 사용하여 네트워크의 가중치와 편향을 업데이트하기 위해 이 기울기를 사용합니다.

  • 결과는 다음과 같습니다.

    C:\Dev\python\pytorch>python backprop_pytorch.py
    network topology: Net(
      (hidden_layer): Linear(in_features=1, out_features=1, bias=True)
      (output_layer): Linear(in_features=1, out_features=1, bias=True)
    )
    w_l1 = 1.58
    b_l1 = -0.14
    w_l2 = 2.45
    b_l2 = -0.11
    a_l2 = 0.8506
    updated_w_l1 = 1.5814
    updated_b_l1 = -0.1383
    updated_w_l2 = 2.4529
    updated_b_l2 = -0.1062
    updated_a_l2 = 0.8515
    

    역전파 단계 전후에 네트워크 토폴로지와 가중치, 편향, 출력을 출력합니다.

    아래에서 이 계산을 일반 Python으로 복제해 보겠습니다. 이 계산은 신경망 입문서에서 본 것과 거의 동일합니다. 유일한 차이점은 PyTorch의 MSELoss 함수에는 2로 추가 나누기가 없기 때문에 아래 코드에서 PyTorch가 수행하는 것과 일치하도록 조정했습니다dc_da_l2 = 2 * (a_l2-1).

    import numpy as np
    
    
    def sigmoid(z_value):
        return 1.0/(1.0+np.exp(-z_value))
    
    
    def z(w, a, b):
        return w * a + b
    
    
    def sigmoid_prime(z_value):
        return sigmoid(z_value)*(1-sigmoid(z_value))
    
    
    def dc_db(z_value, dc_da):
        return sigmoid_prime(z_value) * dc_da
    
    
    def dc_dw(a_prev, dc_db_value):
        return a_prev * dc_db_value
    
    
    def dc_da_prev(w, dc_db_value):
        return w * dc_db_value
    
    
    a_l0 = 0.8
    w_l1 = 1.58
    b_l1 = -0.14
    print(f"w_l1 = {round(w_l1, 4)}")
    print(f"b_l1 = {round(b_l1, 4)}")
    
    z_l1 = z(w_l1, a_l0, b_l1)
    a_l1 = sigmoid(z_l1)
    
    w_l2 = 2.45
    b_l2 = -0.11
    print(f"w_l2 = {round(w_l2, 4)}")
    print(f"b_l2 = {round(b_l2, 4)}")
    
    z_l2 = z(w_l2, a_l1, b_l2)
    a_l2 = sigmoid(z_l2)
    print(f"a_l2 = {round(a_l2, 4)}")
    
    dc_da_l2 = 2 * (a_l2-1)
    dc_db_l2 = dc_db(z_l2, dc_da_l2)
    dc_dw_l2 = dc_dw(a_l1, dc_db_l2)
    dc_da_l1 = dc_da_prev(w_l2, dc_db_l2)
    
    step_size = 0.1
    updated_b_l2 = b_l2 - dc_db_l2 * step_size
    updated_w_l2 = w_l2 - dc_dw_l2 * step_size
    
    dc_db_l1 = dc_db(z_l1, dc_da_l1)
    dc_dw_l1 = dc_dw(a_l0, dc_db_l1)
    
    updated_b_l1 = b_l1 - dc_db_l1 * step_size
    updated_w_l1 = w_l1 - dc_dw_l1 * step_size
    
    print(f"updated_w_l1 = {round(updated_w_l1, 4)}")
    print(f"updated_b_l1 = {round(updated_b_l1, 4)}")
    
    print(f"updated_w_l2 = {round(updated_w_l2, 4)}")
    print(f"updated_b_l2 = {round(updated_b_l2, 4)}")
    
    updated_z_l1 = z(updated_w_l1, a_l0, updated_b_l1)
    updated_a_l1 = sigmoid(updated_z_l1)
    updated_z_l2 = z(updated_w_l2, updated_a_l1, updated_b_l2)
    updated_a_l2 = sigmoid(updated_z_l2)
    print(f"updated_a_l2 = {round(updated_a_l2, 4)}")
    

    결과는 다음과 같습니다.

    C:\Dev\python\pytorch>python backprop_manual_calculation.py
    w_l1 = 1.58
    b_l1 = -0.14
    w_l2 = 2.45
    b_l2 = -0.11
    a_l2 = 0.8506
    updated_w_l1 = 1.5814
    updated_b_l1 = -0.1383
    updated_w_l2 = 2.4529
    updated_b_l2 = -0.1062
    updated_a_l2 = 0.8515
    

    결과가 PyTorch 네트워크의 결과와 일치하는 것을 볼 수 있습니다! 다음 기사에서는 PyTorch를 사용하여 MNIST 데이터베이스에서 숫자를 인식합니다.

    코드는 github에서 사용할 수 있습니다.


    중첩 소프트웨어 / 파이토치


    기본 PyTorch 사용법 데모. 조밀한 네트워크와 컨벌루션 네트워크를 사용하는 MNIST 인식을 포함합니다.





    이 프로젝트에는 기본 PyTorch 사용법을 보여주는 스크립트가 포함되어 있습니다. 이 코드에는 Python 3, numpy 및 pytorch가 필요합니다.

    수동 대 PyTorch 역전파 계산


    수동 역전파 계산을 동등한 PyTorch 버전과 비교하려면 다음을 실행하십시오.
    python backprop_manual_calculation.py
    w_l1 = 1.58
    b_l1 = -0.14
    w_l2 = 2.45
    b_l2 = -0.11
    a_l2 = 0.8506
    updated_w_l1 = 1.5814
    updated_b_l1 = -0.1383
    updated_w_l2 = 2.4529
    updated_b_l2 = -0.1062
    updated_a_l2 = 0.8515
    
    그리고
    python backprop_pytorch.py
    network topology: Net(
      (hidden_layer): Linear(in_features=1, out_features=1, bias=True)
      (output_layer): Linear(in_features=1, out_features=1, bias=True)
    )
    w_l1 = 1.58
    b_l1 = -0.14
    w_l2 = 2.45
    b_l2 = -0.11
    a_l2 = 0.8506
    updated_w_l1 = 1.5814
    updated_b_l1 = -0.1383
    updated_w_l2 = 2.4529
    updated_b_l2 = -0.1062
    updated_a_l2 = 0.8515
    
    블로그 게시물:

    MNIST 인식


    다음 예제는 처음에는 조밀한 네트워크를 사용한 다음 몇 가지 컨볼루션 네트워크 디자인을 사용하여 MNIST 숫자를 인식합니다(예제는 Michael Nielsen의 책 Neural Networks and Deep Learning에서 채택됨).
    나는 추가했다…

    View on GitHub


    관련된



  • 좋은 웹페이지 즐겨찾기