[Neural Networks and Deep Learning] One hidden layer Neural Network
Neural Network Representation
다음 그림은 2계층 신경망의 표현법이다.
우선 2계층 신경망은 input, hidden, output layer로 이루어져 있다. 신경망의 계층을 셀 때는 input layer을 제외하고 hidden layer와 output layer 개수를 모두 합하여 총 계층 수를 계산하면 된다.
다음으로 신경망의 notation에 대해 알아보자. 신경망에서는 해당 변수가 어느 계층에 속하는지, 몇번째 유닛에 속하는지 정확히 표시하는 것이 중요하다. 위 그림에서 변수 위에 "[1]"처럼 대괄호로 표현된 것이 해당 변수가 몇계층에 속해있는지를 나타낸다. 그리고 변수 아래에 적힌 숫자는 해당 계층의 몇 번째 유닛인지를 나타낸다.
예를 들어 해당 유닛은 1계층의 3번째 유닛이라는 것을 알 수 있다. 비슷하게 만약 w[2]_3과 같이 표현된 변수가 있다면 2계층 3번째 유닛에 속하는 가중치를 나타내는 것이다.
Computing a Neural Network's Output
로지스틱 회귀와 비교하여 신경망의 output에 대해 알아보자. 로지스틱 회귀에서는 입력 특징들로 선형식을 계산한 후 시그모이드 함수를 거쳐 해당 입력 특징의 클래스에 속할 확률을 계산한다. 이것을 위에서 본 신경망과 비교하자면 단일 계층에 unit이 하나 있는 모습으로 볼 수 있다. 로지스틱 회귀는 은닉층 없이 입력층과 출력층으로 구성된 모델이기 때문에 신경망으로 볼 수는 없다.
이제 2계층 신경망에 대해 알아보자. 은닉층의 유닛별 계산 과정을 살펴보면 다음과 같다.
이렇게 입력 특징으로 다음 계층의 유닛마다 각각 결과 값을 계산한다. 비유하자면 로지스틱 회귀의 과정을 각 유닛마다 진행하는 것이다. 그래서 이 과정을 유닛마다 하나하나 식으로 표현하면 다음과 같다.
참고로 로지스틱 회귀에서 x의 차원과 w의 차원은 서로 (nx,1)로 동일하여 wx를 계산할 때는 w를 전치시켜 연산을 진행한다. 신경망에서는 유닛마다 로지스틱 회귀 과정을 진행한다고 표현할 수 있으므로, 연산마다 각 유닛에 해당하는 w를 전치시키기보단 모든 w를 전치시키고 이 값을 vertical 방향으로 쌓아 행렬 W로 표현하면 조금 더 편하게 연산이 가능해진다. 그러면 W의 shape은(n[l], n[l-1])이 된다. 여기서 n[l]은 l계층의 유닛 수다. 더하여 b도 마찬가지로 vertical 하게 값을 쌓아주면 된다. b는 스칼라 값이기에 w처럼 전치를 할 필요는 없다. 다음은 이 설명에 대한 참고 그림이다.
Vectorizing across multiple examples
신경망을 훈련할 때 여러개의 훈련 예제로 모델을 학습시킨다. 그렇기 때문에 반복문을 사용하여 훈련 예제마다 결과 값을 계산을 하는데, 이렇게 하면 계산 속도가 굉장히 느려진다. 이러한 문제를 해결하기 위해 벡터화를 사용하는데, 벡터화를 쓰기 위해서는 m개의 훈련 예제들을 horizontal 방향으로 쌓아 행렬로 표현해주어야 한다.
그러면 X의 shape은 (nx,m)이 되는데, 여기서 nx는 특징 벡터 수이다. 이렇게 나타낸 X 행렬과 W 행렬을 계산하여 결과 값 Z를 계산하면 각 훈련 예제마다의 결과 값이 horizontal 방향으로 쌓이게 된다. 이러한 Z에 활성화 함수를 계산한 결과인 A도 마찬가지로 horizontal 방향으로 쌓여 결과 값이 나타난다.
<벡터화 전>
<벡터화 후>
Activation function
4가지 활성화 함수(sigmoid, tanh, relu, leaky relu)에 대해 알아보자.
① sigmoid
시그모이드 함수는 y=0,1과 같은 이진분류에서만 사용한다. 보통은 sigmoid와 비슷한 tanh가 항상 더 나은 성능을 보이지만, tanh는 출력 값의 범위가 -1~1이고 sigmoid는 0~1기 때문에, 이진 분류에서는 sigmoid가 더 적합하다.
② tanh
tanh 함수는 대개 sigmoid보다 더 나은 성능을 보인다. 출력 값의 범위가 -1~1라 평균 값이 0에 더 가까워, 다음 층의 학습을 조금 더 쉽게 해주기 때문이다.
[sigmoid와 tanh의 공통 단점]
위의 그래프를 잘 보면 두 함수 사이에는 공통점이 존재한다. 입력 값이 아주 크거나 작은 범위에서 도함수 값이 0에 가까울 정도로 작아진다는 것이다. 이처럼 도함수 값이 0에 가까워지면 backpropagation 과정에서 gradient가 "사라지는" 현상이 발생하기 때문에 경사하강이 느려진다.
③ relu - max(0,z)
relu는 현재 가장 인기있는 활성화 함수이다. 활성화 함수에 어떤 함수를 사용해야할지 모르겠다면 relu를 사용하면 된다. relu의 단점이라면 z가 0인 지점에서는 도함수가 없고, 음수인 지점에서는 도함수가 0이라는 것이 단점이다. 하지만 z값이 0이 되는 경우는 극히 드물어서 따로 신경을 쓰지 않아도 괜찮다.
④ leaky relu - max(alpha*z, z)
leaky relu는 relu의 단점인 z가 음수일 때의 도함수 문제를 해결하기 위해 고안된 활성화 함수이다. relu보다 더 좋은 성능을 보이긴 하지만 실제로 많이 사용하지는 않는다.
※ leaky relu보다 relu를 더 많이 사용하는 이유..
leaky relu가 더 성능이 좋다고 했는데 relu를 더 많이 사용하는 이유가 궁금하여 찾아보았다. 우선 relu는 식부터 아주 단순하며 계산이 효율적이다. 그리고 relu는 대부분의 경우에서 좋은 성능을 보여준다.
leaky relu도 좋은 성능을 보이긴 하지만 relu보다 상대적으로 계산이 효율적이지 않고, 항상 relu보다 좋은 성능을 낸다는 보장이 없다고 한다. 성능이 더 좋다고 하더라도 relu와 크게 차이나지 않으며, alpha 라는 새로운 학습 값이 생기기 때문에 굳이 leaky relu를 사용하지 않는다고 한다.
※ 비선형 활성화 함수를 쓰는 이유
신경망에 비선형 활성화 함수를 쓰지 않으면 신경망은 입력의 선형식만 출력하게 되고, 이는 은닉층이 얼마나 많든 간에 은닉층이 없는 것과 같게 된다. 참고로 회귀 문제에서는 출력층에 선형함수를 쓰는 것이 의미가 있다.(only 출력층!)
Derivatives of activation functions
앞서 본 4가지 활성화 함수의 도함수에 대해 알아보자. g를 각 활성화 함수로 가정.
① sigmoid
g(z)=a
dg/dz = a(1-a)
② tanh
g(z)=a
dg/dz = 1-a^2
③ relu
- z<0 일 때: dg/dz = 0
- z>=0 일 때: dg/dz = 1
④ leaky relu
- z<0 일 때: dg/dz = alpha
- z>=0 일 때: dg/dz = 1
Random Initialization
신경망의 가중치를 0으로 초기화한다면 각 층의 모든 뉴런이 어떤 입력을 받든 동일한 결과를 출력한다. 이러한 현상을 유닛 간의 대칭성 문제라고 한다. 0으로 초기화하면 대칭성이 깨지지 않으며, 이렇게 되면 뉴런 학습 간 다양성이 사라지고 복잡한 패턴 학습이 불가능해진다. 그렇기에 가중치 초기화의 한 방법으로 "랜덤 초기화" 방식을 사용한다.
W[1] = np.random((2,2)) * 0.01
b[1] = np.zeros((2,1))
W[2] = np.random((1,2)) * 0.01
b[2] = np.zeros((1,1)) -> 0
이런 방식으로 np.random, np.zeros를 사용하여 매개변수들을 초기화시켜주면 된다. 가중치 크기를 너무 크지 않게 잘 조절해야 경사 하강이 잘 이루어지기 때문에 W에 0.01 과 같은 값을 곱해주어야 한다.