관리 메뉴

TEAM EDA

[파이토치로 시작하는 딥러닝 기초] 2.1~2 Perceptron, Multi Layer Perceptron 본문

EDA Study/PyTorch

[파이토치로 시작하는 딥러닝 기초] 2.1~2 Perceptron, Multi Layer Perceptron

김현우 2020. 3. 20. 15:06

이번 글에서는 PyTorch로 XOR문제를 풀어보고 Perceptron에 대해서 배워보도록 하겠습니다. 이번 글은 EDWITH에서 진행하는 파이토치로 시작하는 딥러닝 기초를 토대로 하였고 같이 스터디하는 팀원분들의 자료를 바탕으로 작성하였습니다. 

목차

  • Perceptron
  • AND, OR
  • XOR
  • Code: xor 
  • Multi Layer Perceptron 
  • Backpropagation 
  • Code : xor - nn

1. Perceptron 

출처 : https://commons.wikimedia.org/wiki/File:Neuron.svg

Perceptron은 위에 보이는 인간의 신경망을 구현한 것입니다. 인간의 신경망은 입력이 들어오면 뉴런을 통해서 에너지가 흐르고 특정 임계값을 넘으면 출력으로 넘어가게 됩니다. 그 모습을 나타낸게 아래와 같습니다. 아래의 Perceptron도 입력이 주어지면 가중치와 반응해서 값을 만들고 이게 흐르다가 threshold값 보다 크면 활성화되어 출력으로 넘어가게 됩니다. 이를 통해서 오른쪽과 같이 선형 분류를 할 수 있게 됩니다. 

출처 : https://commons.wikimedia.org/wiki/File:Rosenblattperceptron.png, https://commons.wikimedia.org/wiki/File:Perceptron_example.svg

2. AND, OR

이를 통해서 사람들은 AND, OR 문제도 풀 수 있을 거라 생각합니다. AND, OR 문제는 아래의 사진같이 분류되는 논리문제입니다. AND의 경우 두 값이 모두 1이어야 Y값으로 1을 가지고, 그렇지 않으면 0을 가집니다. 반대로 OR는 둘 중 하나라도 1을 가지면 Y값으로 1을 가지게 됩니다. 

출처 : http://www.bristolwatch.com/pport/python_examples.htmL

Perceptron의 경우 위의 문제를 아래의 사진처럼 하나의 선을 그어서 해결해 낼 수 있었습니다. 

출처 : http://blog.naver.com/PostView.nhn?blogId=windowsub0406&logNo=220883022888

3. XOR

위의 Perceptron은 AND, OR의 문제를 풀었습니다. 하지만 XOR라는 새로운 문제가 생기게 됩니다. XOR는 둘 중 하나가 1이어야지만 Y가 1을 가지는 문제입니다. 하나의 선을 어떻게 그리더라도 위의 문제를 해결할 수 없었고 인공신경망의 인기가 식게되는 계기가 됩니다. 

4. Code; xor 

# Lab 9 XOR
import torch

# .to(device) : GPU를 사용하게 하는 코드 
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# for reproducibility
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)
      
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(device)
Y = torch.FloatTensor([[0], [1], [1], [0]]).to(device)

# nn layers
linear = torch.nn.Linear(2, 1, bias=True)
sigmoid = torch.nn.Sigmoid()

# model
model = torch.nn.Sequential(
            linear, 
            sigmoid
                            ).to(device)
                            
# define cost/loss & optimizer
criterion = torch.nn.BCELoss().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=1)

for step in range(10001):
    optimizer.zero_grad()
    hypothesis = model(X)

    # cost/loss function
    cost = criterion(hypothesis, Y)
    cost.backward()
    optimizer.step()

    if step % 100 == 0:
        print(step, cost.item())

학습이 계속 진행되어도 비용이 개선이 되지 않는 것을 볼 수 있습니다. 

5. Multi Layer Perceptron 

사람들은 이를 해결하기 위해서 layer을 더 쌓는 방법을 선택합니다. 이것이 사람들이 흔히 말하는 딥러닝(multilayer perceptrons)입니다. 

출처 : http://www.texample.net/tikz/examples/neural-network/, https://commons.wikimedia.org/wiki/File:Perceptron_XOR.jpg

하지만 이런 방식에는 하나의 단점이 있습니다. 바로 계산해야하는 가중치가 너무 많고 서로 복잡하게 연결될 수록 끼치는 영향을 계산하기 어렵다는 점입니다. 

6. Backpropagation 

사람들은 위의 문제를 해결하기 위해서 가중치를 거꾸로 수정해가는 방법을 생각해내게 됩니다. 이를 Backpropagation(역전파)라고 합니다. 역전파는 가중치가 타겟에 미치는 영향을 추정하기 위해서 오차의 정도를 거꾸로 반영 해 나가는 것을 의미합니다. 

backward : back propagation(역전파)

즉, Backpropagation(역전파)은 파라미터들이 타겟에 미치는 영향을 추정하는 과정입니다. 아래의 단순한 신경망에서는 f를 파라미터들로 미분한 값을 의미하게 됩니다. 

위의 값을 구하기 위해 첫번째로 forward를 통해서 그래프에 값을 입력하고 , 두번째로 backward을 통해서 값의 영향을 계산하게 됩니다. 

예를 들어, w=-2, x=5, b=3인 상황을 생각해보겠습니다.

  1. forward를 통해서 g = -10, f = -7을 계산할 수 있습니다. 
  2. backward를 통해서 ∂f / ∂w = (∂f / ∂g) * (∂g / ∂w) = 1 * 5 = 5임을 알 수 있습니다. 마찬가지로 ∂f / ∂x와 ∂f / ∂b에 대해서도 계산을 하면 각각의 파라미터가 미치는 영향을 알 수 있습니다. 
  3. 마지막으로 이 영향도를 learning_rate와 곱해서 파라미터를 수정해주면 가중치의 개선이 되고 1번부터 다시 반복하게됩니다. 

출처 : 모두를 위한 딥러닝

보다 깊은 신경망이나 시그모이드가 있는 상황에서 역전파를 계산해보고 싶은 분들은 다음의 블로그 글(https://gomguard.tistory.com/182)을 참고하시기 바랍니다. 

7. Code : xor - nn

# Lab 9 XOR
import torch

device = 'cuda' if torch.cuda.is_available() else 'cpu'

# for reproducibility
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)
    
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(device)
Y = torch.FloatTensor([[0], [1], [1], [0]]).to(device)

# nn layers
linear1 = torch.nn.Linear(2, 2, bias=True)
linear2 = torch.nn.Linear(2, 1, bias=True)
sigmoid = torch.nn.Sigmoid()

# model
model = torch.nn.Sequential(linear1, sigmoid, linear2, sigmoid).to(device)

# define cost/loss & optimizer
criterion = torch.nn.BCELoss().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=1)  # modified learning rate from 0.1 to 1

for step in range(10001):
    optimizer.zero_grad()
    hypothesis = model(X)

    # cost/loss function
    cost = criterion(hypothesis, Y)
    cost.backward()
    optimizer.step()

    if step % 100 == 0:
        print(step, cost.item())