딥러닝과 인공신경망: 활성화 함수의 역전파 구현하기

Yougurt_Man·2022년 8월 3일
0

Machine Learning Theory

목록 보기
16/18

신호를 다음 뉴런으로 보내기 위해, 활성화 함수를 거친다.

즉 신호는, 활성화 함수를 거쳐서 순전파 되기때문에, 활성화 함수 또한 역전파를 거친다는 의미를 지닌다.

이번 포스팅은, 신호를 활성화 함수에 전달하여, 순전파와 역전파가 어떻게 작동하는지 알아보도록 한다.

ReLU 계층 구현하기

수식

ReLu 활성화 함수는 순전파시 입력 신호 x가 0보다 크면, 자기 자신을 다음 노드로 전달하고, 0보다 작거나 같으면 0을 전달한다.

y={x,(x>0)0,(x0)y=\begin{cases}x, {(x >0) } \\ 0, (x \le 0) \end{cases}

역전파시, 활성화함수의 입력신호인 x에 대한 y 미분값은, 1 (x가 0보다 클때) 또는 0 (x가 0보다 작을때)이 된다.

σyσx={1,(x>0)0,(x0){\sigma y \over \sigma x}=\begin{cases}1, {(x >0) } \\ 0, (x \le 0) \end{cases}

즉, 입력신호가 0보다 크면 신호를 그대로 전달한다라는 의미에서는 동일하다고 생각할 수 있다.

코드

다음은 Relu 클래스의 멤버 함수가, numpy 배열을 매개변수로 신호 값이 0 이하 이면 값을 0, 신호값이 0 이상 이면 값을 그대로 전달하는 코드이다.

class Relu:
  def __init__(self):
    self.mask = None
  
  def foward(self, x): # x는 numpy 배열
    self.mask = (x <=0)  # numpy 배열의 원소가 0 이하 이면, 멤버변수 mask에는 True를 할당한다.  
    out = x.copy() # Numpy 배열을 out에 복사 
    out[self.mask] = 0 # True인 인덱스만 값을 0으로 저장 

    return out # 신호가 0보다 크다면, 값을 그대로 전달. 

  def backward(self, dout): 

    dout[self.mask] = 0 # True 인덱스일 경우 0을 저장  
    dx = dout # dx에 저장 # 0이하인 신호는 0, 0보다 크면 출력값을 그래도 전달. 
    return dx     

아래는 ReLu함수 테스트 코드이다.

import numpy as np
relu_test = np.array([[1,-5],[2,-10]])

print(relu_test)

relu = Relu()

relu_foward = relu.foward(relu_test)

relu_test = np.array([[1,-50],[12,-10]])

relu_backward = relu.backward(relu_test)

print(relu_foward)
print(relu_backward)

relu_test를 활성화 함수에 전달 후 relu_fowardrelu_backward를 출력 했을때 결과는 다음과 같다.

[[  1  -5]
 [  2 -10]]
[[1 0]
 [2 0]]
[[ 1  0]
 [12  0]]

즉 그림과 같이, 순전파 때의 신호값이 0이하이면, 역전파 때의 값은 0이 되어야 한다.

Sigmoid 계층 구현하기

공식

y=11+exp(x)y={1\over 1+ exp(-x)}

Sigmoid 활성화 함수의 순전파일때와 역전파일때 신호 전달은 아래 이미지와 동일하다.

역전파에서 각 노드의 계산 방식은, 다음 페이지를 참고하자.

역전파의 도식을 간단화해보자.

도식을 간단히 하면 다음과 동일하다.

를 다시 한번 y에 대해 정리하여 간단화 시킬수 있다.

  • σLσyy2exp(x){\sigma L \over \sigma y} y^2 exp(-x) = σLσyy(1y){\sigma L \over \sigma y} y(1-y)

코드 구현

간단화된 공식을, Sigmoid 함수의 역전파 (backward)의 멤버함수에서 공식 σLσyy(1y){\sigma L \over \sigma y} y(1-y)을 적용하면 다음과 같다.

class Sigmoid:
  def __init__(self):
    self.out = None 

  def foward(self, x):
    out = 1 / (1 + np.exp(-x))
    self.out = out 

    return out 
  
  def backward(self, dout):
    dx = dout * (1.0 - self.out) * dout 

    return dx 

활성화 함수의 순전파와 역전파를 계산그래프를 통해 이해하고 코드를 구현해보는 기회를 가졌다. 다음은 행렬 계산을 위해 Affine / Softmax의 계층을 구현하는 시간을 가지자.

profile
Greek Yogurt

0개의 댓글