티스토리 뷰

Backpropagation


 - multiple layers와 gradient descent를 이용한 네트워크 학습에대해 더 알아보자.

 - 우리가 만든 네트워크를 이용하여 최초의 시도로 output을 뽑아낸 뒤, 

 - 얼만큼 이 값이 잘못된지를 반영하여 weights를 다시 설정하여야 하지 않겠는가?

 - 따라서 input → hidden → output 으로 이어지는 네트워크 flow에서

 - weights를 다시 바로잡기위해 역행하며 정보를 전달하는 과정을 Backpropagation이라 함.

 - gradient descent를 사용하여 hidden layer의 weights를 업데이트하려면

 - 각 hidden unit이 최종 output에 얼마나 많은 오차를 남겼는지를 알아야한다.

 - 각 layer의 output은 layer간의 weights에 영향을 받으므로, 

 - 이 오차를 알아내야 weights를 수정하여 최종 목표로 나아갈 수 있다.

 - error는 output을 통해 알 수 있기 때문에, 우리는 역방향으로 작업을 해 나가야 하는것임.



 - 예를들어, output layer에서 각 output unit인 k에 기여한 좌측 델타의 error가 있다.

 - hidden unit인 j에 기여한 output error는 

 - output과 hidden layers 사이의 weights와 그래디언트 값에 의한것임.



 - 그렇게되면, 그래디언트 스텝은 전과 동일하지만 새로운 에러만 반영됨.

 - 여기서 Wij는 input layer와 hidden layer사이의 weight이고, Xi는 input unit의 값이다.

 - 이 양식은 아무리 layer들이 많아도 모두 적용됨

 


 - weight의 step들은 위와같이 구할 수 있다.

 - (step size) * (the output error of the layer) * (the values of the inputs to that layer)

 - 여기서 상위 계층의 error를 역으로 전파(propagating)하여 output error인 델타를 얻고, 

 - input values인 V는 input layer에 있어서는 input value가 되고, 

 - hidden layer에 있어서는 activation된 즉, sigmoid function에 의한 output이 됨(output layer의 input value).



Working through an example


 - 예제를 통해 이해해보자. 

 - 최하단에 input layers, 그다음 중간에 hidden layer, 마지막에 output layer가 있고, 

 - 각 layer들을 이어주는 weights 값이 표시되어있다.

 - 또한 hidden layer 와 output layer에는 sigmoid function이 들어간다.




 · Calculating the input to the hidden unit

 - binary data(0 또는 1)를 찾아가려 하고있고, 이 때의 target은 y = 1일 경우, 

 - 우리는 먼저 순서대로 hidden unit에 대한 input을 먼저 계산한다.



 · Output of the hidden unit

 - hidden layer에 대한 input값에 sigmoid function을 돌려서 hidden unit의 output을 구해낸다.



 · Using this(output of the hidden unit) as the input to the output unit

 - 즉, 최종 output of the network는 0.512가 나오게 된다.



 · Backwards pass to calculate the weight updates(output unit → hidden unit)

 - network output을 통해 다시 뒤로 역행하며 weight을 업데이트 해야한다.

 - sigmoid function의 미분값이 위와같이 떨어지는점을 활용하여
 - output unit으로부터 error term을 다음과 같이 구할 수 있다.




 · Backwards pass to calculate the weight updates(hidden unit → input unit)

 - 이제 backpropagation을 이용해서 hidden unit의 error term을 계산해보자.

 - output unit으로 부터의 error term을 weight인 W를 hidden unit에 연결하여 조정한다.

 - hidden unit의 error term은 위와같이 구하지만, 

 - 예시에서는 하나의 hidden unit과 하나의 output unit뿐이라 훨씬 간단하다.




 · Gradient descent steps

 - error를 얻었으므로, gradient descent step을 진행할 수 있다.

 - hidden 에서 output weight step은 learning rate에 해당하고

 - 거기에 output unit의 error를 곱하고 

 - 그리고 hidden unit의 activation value(sigmoid function의 결과값)까지 곱해준다.


 - The hidden to output weight = learning rate * output unit error * hidden unit activation value 로 구함




 · Update input to hidden weights

 - 그 다음으로는 input에서 hidden unit으로 가는 weight들을 업데이트 해주면 된다.

 - learning rate * hidden unit error * input values 로 구함.




 - 이 예제에서 sigmoid function을 activation function으로 사용했을때의 효과를 알아볼 수 있다.

 - sigmoid function의 최대 미분값은 0.25이므로, output layer의 error가 75%이상 감소하고

 - hidden layer의 error는 최소 93.75%로 축소된다.

 - 만약 layer들이 많을 경우(multi-layers) sigmoid function을 이용하면

 - 매우 빠르게 가중치 단계(weight steps)들을 줄일 수 있다.

 - 이를 Vanishing gradient problem 이라 칭함.

 - 물론 나중에 또 다른 activation function에 대해 더 알아볼것임.




Implementing in NumPy

 - Backpropagation을 수행하는데에 있어 NumPy는 매우 강력한 도움을 준다.

 - 이전에는 하나의 unit에 대한 error term만을 다뤘다면,

 - 앞으로는 weight 업데이트에 있어서 hidden layer에 있는 각각의 unit에 대한 error를 고려해야한다.

 - 위와같이 다루게 되는데, input과 hidden unit의 개수가 다를 수 있다.

 - 따라서 이전과 같이 error와 input들을 곱해버리면 다음과같은 에러를 던진다.


- 각각의 shape이 다르기 때문.




 - 또한 Wij(가중치)는 이제 행렬이므로, 곱해질 좌 우 의 행과 열을 즉 shape를 고려해서 곱해야한다.

 - NumPy는 이를 적절하게 처리해 줄 수 있는데 다음과 같이 처리해주면 됨.

 

 - 이 경우 (len(column_vector), len(row_vector)) 꼴의 shape를 가진 matrix를 리턴한다.

 - 이 방법이 정확하게 우리가 weight를 업데이트하는데에 있어 원하는 결과값을 도출해내고

 - 전에 언급하였듯, 2차원 배열이지만 하나의 행을 가진경우 transpose (inputs.T 와 같이)를 사용할 수 있다.

 - 1차원의 경우 transpose는 불가능.




Backpropagation exercise


import numpy as np


def sigmoid(x):
    """
    Calculate sigmoid
    """
    return 1 / (1 + np.exp(-x))


x = np.array([0.5, 0.1, -0.2])
target = 0.6
learnrate = 0.5

weights_input_hidden = np.array([[0.5, -0.6],
                                 [0.1, -0.2],
                                 [0.1, 0.7]])

weights_hidden_output = np.array([0.1, -0.3])

## Forward pass
hidden_layer_input = np.dot(x, weights_input_hidden)
hidden_layer_output = sigmoid(hidden_layer_input)

output_layer_in = np.dot(hidden_layer_output, weights_hidden_output)
output = sigmoid(output_layer_in)

## Backwards pass
## TODO: Calculate output error
error = target - output

# TODO: Calculate error term for output layer
output_error_term = error * output * (1 - output)

# TODO: Calculate error term for hidden layer
hidden_error_term = np.dot(output_error_term, weights_hidden_output) * \
                    hidden_layer_output * (1 - hidden_layer_output)

# TODO: Calculate change in weights for hidden layer to output layer
delta_w_h_o = learnrate * output_error_term * hidden_layer_output

# TODO: Calculate change in weights for input layer to hidden layer
delta_w_i_h = learnrate * hidden_error_term * x[:, None]

print('Change in weights for hidden layer to output layer:')
print(delta_w_h_o)
print('Change in weights for input layer to hidden layer:')
print(delta_w_i_h)



댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함