코딩하는 해맑은 거북이

[딥러닝] 얕은 신경망, 심층 신경망 네트워크 본문

AI

[딥러닝] 얕은 신경망, 심층 신경망 네트워크

#CJE 2023. 9. 7.
본 게시물의 내용은 'Google ML Bootcamp 2023 커리큘럼의 Coursera 강의,
Neural Networks and Deep Learning(Andrew Ng)'를 듣고 정리하여 작성하였다.
해당 글은 아래의 2가지를 다룬다.
📌 얕은 신경망 네트워크
📌 심층 신경망 네트워크

📌 얕은 신경망 네트워크

🔷 Neural Network Representation - 신경망 네트워크의 구조

아래의 그림으로 신경망 네트워크의 구조를 알아보자.

  • Input layer
    • 가장 왼쪽의 입력의 특징들(x1, x2, x3)로 이루어진 층으로, \(a^{[0]}\) 으로 표기한다.
  • Hidden layer
    • Input layer와 Output layer의 사이에 있는 모든 층을 의미하고, \(l\)번째 은닉층의 \(i\)번째 노드는 \(a_{i}^{[l]}\) 으로 표기한다. 
  • Output layer
    • 가장 오른쪽의 하나의 노드로 구성되어 있고, 결과값 \(\hat{y}\)를 출력하는 층이다.

Q. 아래의 그림은 총 몇 개의 층으로 이루어져 있는가?

신경망 층의 개수를 셀 때는 Input layer를 제외한다. (Input layer는 0번째 layer)

즉, Hidden layer 1개, Output layer 1개로 '2-layer Neural Network' 이다.

 

각 노드와 층에서 로지스틱 회귀의 계산 과정이 적용된다. 이때 파라미터 w와 b의 차원은 Hidden layer의 노드의 수에 의해 결정된다. 첫 번째와 두 번째 층에서의 w와 b의 차원은 다음과 같다.

  • \(a^{[1]}\)
    • w : (4, 3) → (Hidden Node의 갯수, 입력 특성의 갯수)
    • b : (4, 1)
  • \(a^{[2]}\)
    • w : (1, 4) → (Output Node의 갯수, Hidden Node의 갯수)
    • b : (1, 1)

2-layer Neural Network

 

 

🔷 Computing a Neural Network's Output - 신경망 네트워크 출력의 계산

로지스틱 회귀에서 결과값 \(\hat{y}\)을 구하려면, 입력값이 하나의 노드를 통과할 때 z와 a를 구하는 2가지 과정을 거친다.

 

 

그렇다면, 2-layer Neural Network에서 결과값 \(\hat{y}\)을 구하는 계산 그래프는 아래 같이 이루어진다.

이는 하나의 과정에서의 계산 그래프를 보여주며, 모든 과정에 대해서는 아래의 계산 과정이 노드별로 반복된다.

 

결과값 \(\hat{y}\)을 구하는 계산 과정을 벡터화를 통해 아래의 4줄의 코드로 간단하게 표현할 수 있다.

*이는 하나의 훈련 샘플에 대한 계산 과정이다.

 

 

🔷 Vectorizing Across Multiple Examples - 많은 샘플에 대한 벡터화

m개의 훈련 샘플에 대한 계산 과정은 아래와 같이 for loop를 통해 구할 수 있다.

  • 아래의 표기법은 \(a^{[l](i)}\)는 \(l\)은 몇 번째 층인지, \(i\)는 몇 번째 훈련 샘플인지 의미한다.

하지만, for loop를 사용하면 계산 속도가 느리다는 단점이 있으므로 이를 벡터화로 한번에 계산할 수 있다.

벡터화는 입력값 X로 모든 훈련 샘플을 열로 쌓는다면, 결과값도 열로 쌓인 값이 나온다는 것을 이용할 수 있다.

 

 

🔷 Activation Functions - 활성화 함수

앞서 내용에서는 Hidden layer와 Outptut layer에 시그모이드 활성화 함수를 사용하였다.

하지만, 상황에 따라 다른 함수를 사용하는 것이 더 좋을 수도 있다.

 

다양한 활성화 함수와 각각의 특성을 살펴보면 아래와 같다. (x축: z, y축: a)

  • Sigmoid
    • a의 값이 [0, 1] 사이에 있고, z의 값이 너무 작거나 크게 되면 함수의 기울기가 0에 가까워진다. 이에 따라 경사하강법이 매우 천천히 진행되어 성능이 좋지 않다.
    • 하지만, Output layer에서 [0, 1] 사이로 출력하는 것이 더 좋기 때문에 많이 사용된다.
    • 특히, 이진 분류의 Output layer에서 많이 사용된다.
  • Tanh
    • a 값이 [-1, 1] 사이에 있고 데이터의 평균이 0 이기 때문에, (데이터를 원점으로 이동하는 효과로) 다음 층에서의 학습을 더 쉽게 해준다.
    • 대부분의 경우에 Hidden layer에서 Sigmoid보다 더 좋은 성능을 보여 많이 사용한다.
  • ReLU
    • a의 값이 max(0, z)로 머신러닝에서 인기 있는 함수이다.
    • z가 양수일 때 도함수가 1 이고, z가 음수일 때 도함수가 0이 된다.
    • 본래의 기울기를 가지는 특징으로 경사하강법이 빠르게 진행되어 가장 보편적으로 사용되는 함수이다.
  • Leaky ReLU
    • 기존의 ReLU에서 z가 음수일 때 도함수가 0이라는 단점을 보완하여 약간의 기울기를 준 함수이다.
    • 실제로 많이 쓰이진 않지만 ReLU 보다 좋은 성능을 보인다.

 

 

🔷 Why do you need non-linear activation functions? - 왜 비선형 활성화 함수가 필요한가?

비선형 활성화 함수를 각 층마다 사용하는 이유는 Input layer에서 Output layer로 학습하는 과정에서 비선형(non-linear)의 특징을 뽑아내기 위해서 사용한다.

 

cf) 예를 들어, 선형 함수 \(z = W^Tx+b\) 와  a = g(z) 에서 g(z) = z 라는 선형 활성화 함수(항등함수)를 사용한다고 가정하면, 여러개의 Hidden layer를 사용하든 간에 신경망은 선형 활성화 함수만 계산하기 때문에 Hidden layer가 없는 것과 다름없다. 즉, 선형 함수의 중첩의 결과는 선형 관계이기 때문에, 선형 은닉층은 쓸모가 없다.

*선형 활성화 함수를 사용하는 경우는 출력값이 실수인 회귀문제일 때 Output layer에 사용한다.

 

 

🔷 Derivatives of activation functions - 활성화 함수의 미분

신경망에서 역방향 전파를 구현하려면 활성화 함수의 도함수를 구해야한다.

각 활성화 함수에서 도함수를 구해보면 아래와 같다.

  • Sigmoid
    • \(a = g(z) = \frac{1}{1+e^{-z}}\)
    • \(g'(z) = a(1-a)\)
  • Tanh
    • \(a = g(z) = \frac{e^z-e^{-z}}{e^z+e^{-z}}\)
    • \(g'(z) = 1-a^2\)
  • ReLU
    • \(g(z) = max(0, z)\)
    • z < 0 인 경우, \(g'(z) = 0\)
    • z >= 0 인 경우, \(g'(z) = 1\)
  • Leaky ReLU
    • \(g(z) = max(0.01z, z)\)
    • z < 0 인 경우, \(g'(z) = 0.01\)
    • z >= 0 인 경우, \(g'(z) = 1\)

 

 

🔷 Gradient descent for Neural Networks - 신경망 네트워크의 경사하강법

2-layer Neural Network에서의 경사하강법 유도 과정을 살펴보자.

먼저 Forward Propagation을 아래의 식으로 진행한다. 여기서 이진 분류로 진행하므로 마지막 g인 activation function은 시그모이드와 같다.

Forward Propagation

다음의 Back Propagation의 과정은 아래와 같이 진행된다.

Back Propagation

 

 

🔷 Random Initialization - 랜덤 초기화

신경망을 훈련시킬 때, 파라미터를 임의의 값으로 초기화시키는 것이 중요하다.

 

신경망에서 w를 0으로 초기화하고 경사하강법을 적용할 경우, dw를 계산했을 때 모든 층에서 같은 결과값을 가지기 때문에 올바르게 작동하지 않는다. 이를 대칭(symmetry)라고 한다.

그렇기 때문에, w를 0이 아닌 랜덤한 값으로 초기화해주어 symmetry breaking을 할 수 있다. 단, b는 0으로 초기화해주어도 상관없다.

 

예를 들어, np.random.randn 함수에 0.01을 곱하여 w를 설정할 수 있다.

여기서 0.01을 곱하여 작은 수로 만들어주는 이유는 Sigmoid나 Tanh 함수를 사용할 경우, 매우 크거나 작은 경우 기울기가 0에 가깝게 되므로 경사하강법이 매우 느리게 진행되기 때문이다. 즉, 학습의 속도가 느려진다.

따라서 초기 파라미터값이 너무 큰 값을 가지지 않도록 0.01을 곱해주는 것이다.

이외에 0.01보다 더 작은 값을 곱해주어도 된다.

w = np.random.randn(a, b) * 0.01
b = np.zeros((a, b))

 

📌 심층 신경망 네트워크

🔷 Deep L-layer Neural Network - 더 많은 층의 심층 신경망

Hidden layer가 여러개 존재하는 신경망 구조를 Deep Neural Netrowk라고 한다.

아래의 그림을 통해 표기법을 알아보자.

  • L : 전체 층의 갯수
    • L=4
  • \(n^{[l]}\) : \(l\)층에 있는 노드(유닛) 개수
    • \(n^{[1]} = 5\), \(n^{[2]} = 5\), \(n^{[3]} = 3\), \(n^{[4]} = n^{[L]} = 1\)
  • \(a^{[l]}\) : \(l\)층에서의 활성값
    • \(a^{[l]} = g^{[l]}(z^{[l]})\), \(w^{[l]}\)과 \(b^{[l]}\)은 \(z^{[l]}\) 계산을 위한 파라미터값
    • \(a^{[0]}\) : 입력 특징 (X)
    • \(a^{[L]}\) : 예측된 출력값 (\(\hat{y}\))

 

 

🔷 Forward Propagation in a Deep Network - 심층 신경망에서의 정방향 전파

심층 신경망에서의 Forward Propagation은 얕은 신경망에서 진행했던 과정과 같이 층의 개수만큼 아래의 과정이 반복해서 진행된다. 이때, 층의 개수만큼 계산 과정이 반복될 때 각각의 층에 대한 활성화를 계산해야하므로 어쩔 수 없이 for loop 과정을 거칠 수 밖에 없다.

 

 

🔷 Getting your Matrix Dimensions Right - 행렬의 차원을 올바르게 확인하기

신경망의 정확한 구현을 위해서는 행렬의 올바른 차원을 확인할 수 있어야 한다.

 

깊은 신경망의 w와 b의 차원을 확인해보면, \(W^{[l]}\)은 (현재 층의 노드 갯수, 이전 층의 노드 갯수)이고 \(b^{[l]}\)은 (현재 층의 노드 갯수, 1) 인 것을 확인할 수 있다. 또한, \(a^{[l]} = g^{[l]}(z^{[l]})\)의 식으로 a와 z의 차원도 같아야 한다.

  • \(w^{[l]}\) : \((n^{[l]}, n^{[l-1]})\) → \(dw^{[l]}\) 와도 차원이 같음
  • \(b^{[l]}\) : \((n^{[l]}, 1)\)  \(db^{[l]}\) 와도 차원이 같음
  • \(a^{[l]}\) = \(z^{[l]}\) : \((n^{[l]}, 1)\)  \(da^{[l]}\), \(dz^{[l]}\) 와도 차원이 같음

이때, m개의 훈련 샘플을 한번에 계산하기 위해 벡터화를 진행하면 w와 b의 차원은 동일하지만 a, z, x의 차원은 변경된다.

(m개의 훈련 샘플을 하나로 합친 행렬이 되므로 대문자로 표기)

  • X : \((n^{[0]}, m)\)
  • \(A^{[l]}\) = \(Z^{[l]}\) : \((n^{[l]}, m)\)  \(dA^{[l]}\), \(dZ^{[l]}\) 와도 차원이 같음

 

 

🔷 Why Deep Representations? - 왜 깊게 표현할까?

깊은 신경망이 잘 동작하는 이유에 대한 2가지 직관이 있다.

1) 네트워크가 더 깊어질수록 더 많은 특징을 잡아낼 수 있다. 낮은 층에서는 "Simple"한 특징을 찾아내고, 깊은 층에서는 앞서 탐지된 특징들을 모아 "Complex"한 특징을 찾아낼 수 있다. 즉, Hidden layer가 deep 해질수록 유의미하고 구체적인 특징을 찾아낼 수 있다.

 

예를 들어, 얼굴을 인식하거나 감지하는 시스템을 구축한다고 하자.

얼굴 이미지를 Input으로 받았을 때, 3개의 Hidden layer에서의 특징을 살펴보자.

첫번째 layer에서는 이미지의 모서리 특징을 찾아내고

두번째 layer에서는 이러한 모서리들의 특징들로 눈, 코, 입과 같은 얼굴의 일부를 찾아낸다.

마지막 layer에서는 얼굴의 일부 특징들을 조합하여 서로 다른 종류의 얼굴을 감지할 수 있게 된다.

 

2) 순환 이론에 따르면, 상대적으로 Hidden layer의 개수가 작지만 깊은 심층 신경망에서 계산할 수 있는 함수가 있다. 그러나 얕은 신경망으로 같은 함수를 계산하고자 하면 기하급수적으로 많은 은닉 노드가 계산에 필요하게 된다.

여기서 순환 이론이란 로직 게이트의 서로 다른 게이트에서 어떤 종류의 함수를 계산할 수 있는지에 관한 것이다.

 

 

🔷 Building Blocks of Deep Neural Networks & Forward and Backward Propagation 

      - 심층 신경망 네트워크를 Block으로 구성하기 & 정방향 전파와 역방향 전파

각 Hidden layer를 하나의 Block으로 Forward와 Backward 단계를 아래의 그림과 같이 생각해보자.

 

\(l\)번째 층에서의 정방향 함수는 이전 층의 활성화 값인 \(a^{[l-1]}\)을 입력으로 받고, 다음 층으로 \(a^{[l]}\) 값이 출력으로 나오게 된다. 이때 선형결합 값인 \(z^{[l]}\)과 파라미터 \(W^{[l]}\), \(b^{[l]}\) 값을 캐시로 저장해둔다.

\(l\)번째 층에서의 역방향 함수는 \(da^{[l]}\)을 입력으로 받고, 다음 층으로 \(da^{[l-1]}\) 값이 출력으로 나오게 된다.이때 업데이트를 위한 \(dW^{[l]}\), \(db^{[l]}\)도 함께 출력한다. 이들을 계산하기 위해 전방향 함수때 저장해준 캐시를 사용한다.

 

 

 

🔷 Parameters vs Hyperparameters - 파라미터 vs 하이퍼파라미터

  • Parameters
    • 신경망에서 학습 가능한 W와 b가 있다.
  • Hyperparameters
    • 학습률(learning rate, α)
    • 반복횟수(numbers of iteration)
    • 은닉층의 갯수(numbers of hidden layer, L)
    • 은닉노드(유닛)의 갯수(numbers of hidden units)
    • 활성화 함수(activation function)
    • 모멘텀 항(momentum term)
    • 미니배치 크기(mini batch size)

Hyperparameters는 W, b를 조정해주는 역할을 하고 절대적으로 결정된 것이 없다.

또한, 데이터나 환경, 목적 등 다양한 조건에 따라 모델의 최적의 Hyperparameter는 달라지기 때문에 여러번의 시도를 통해 가장 적합한 하이퍼파라미터를 찾아야 한다.

 

 

🔷 What does this have to do with the brain? - 인간의 뇌와 어떤 연관이 있는가?

딥러닝과 인간의 뇌 간의 관계는 크지 않다. 다만, 경사하강법 같은 매우 복잡한 수식들을 인간의 뇌에 비유해서 좀더 직관적이도 효과적으로 전달할 수 있다. 그러나 신경과학에서 특징짓는 것보다 하나의 뉴런은 훨씬 더 복잡하고 알기 어렵다.

뉴런이 하는 일 중 일부는 로지스틱 회귀와 비슷한 면이 있지만, 인간의 이해력으로는 하나의 뉴런이 하는 일도 다 파악하기 어렵다. 그리고 인간의 뇌가 역전파나 경사하강법 등의 알고리즘을 사용하는지도 불분명하다.

그래서 최근에는 딥러닝 분야와 인간의 뇌 비유가 점점 무너져 가고 있다.

 

Comments