4. 얕은 신경망 네트워크
📌신경망 네트워크 개요(C1W3L01)
핵심 키워드: 개요(overview)

위 계산 모델에서, 특성 x와 변수 w, b를 입력하면 z를 계산할 수 있으며 z는 yhat라고도 썼던 a를 계산하는 데 사용됨.
이를 토대로 마지막으로는 손실 함수인 L(a, y)를 계산할 수 있었음.
신경망 슬라이드 하단에 있는 그림처럼 생겼는데, 이전 시간에 배웠던 것처럼 신경망은 시그모이드 유닛을 쌓아서 만들 수 있음. x1, x2, x3가 모이는 해당 노드는 z를 계산하고 a를 계산하는 두 단계로 이루어져 있음. 신경망에서 앞에 있는 노드들은 z와 a를 계산하고, 뒤에 있는 노드는 또 다른 z와 a를 계산함.
이후에 사용할 표기법은 W[1], b[1]로 하 특성 x와 변수 W, b를 입력하면 z[1]을 계산함.
새로운 표기법에서는 '층'이라고 불리는 일련의 노드값을 위첨자[1]를 사용해 표기함.
나중에 위첨자[2]를 사용해 두 번째 노드와 관련된 값을 칭함. 이때 대괄호 위첨자와 각 훈련 샘플을 뜻하는 소괄호 위첨자를 헷갈리면 안됨.
위첨자 [1]과 [2]는 이 신경망의 1, 2번 레이어를 뜻하며, 로지스틱 회귀와 비슷하게 z[1]을 계산한 뒤 σ(z[1])인 a[1]을 계산하고 그 후 다른 선형 식을 사용하여 z[2]를 계산함. 마지막으로 yhat이라고도 쓸 수 있는 신경망의 최종 출력값인 a[2]를 계산해줌. 여기서 알아야 할 부분은, 로지스틱 회귀에서는 z와 a를 한 번 계산했지만, 신경망에서는 z와 a를 여러 번 계산해준다는 점이며, 공통적으로 둘 다 마지막에는 손실 L(a, y)를 계산한다는 것임.
로지스틱 회귀에서는 도함수 계산을 위해 da, dz를 계산하는 등 역방향 계산을 진행했는데, 신경망에서도 이와 마찬가지로 역방향 계산을 해줌. da[2]와 dz[2]를 계산한 값을 가지고 dw[2]와 db[2]를 계산함. 슬라이드 속 빨간 화살표(오른쪽 >> 왼쪽)가 역방향 계산 방향.
📌신경망 네트워크의 구성 알아보기(C1W3L02)
핵심어: 입력층(input layer), 은닉층(hidden layer), 출력층(output layer)

은닉층이 하나인 신경망의 경우
입력 특성 x1 x2 x3가 세로로 쌓여있는 것 >> 신경망의 입력층
중간에 배치된 원들 >> 은닉층
노드 하나로 이루어진 마지막 층 >> 출력층, 예측 값인 yhat의 계산을 책임짐
지도학습(supervised learning)으로 훈련시키는 신경망에서는 훈련 세트가 입력값 X와 출력값 Y로 이루어져 있음.
은닉층의 실제 값은 훈련 세트에 기록되지 않는데, 이는 즉 훈련 세트에서 무슨 값인지 알 수 없다는 것. 입력값과 출력값은 알 수 있지만 은닉층은 알 수 없음, 따라서 은닉층이라는 이름은 훈련 세트에서 볼 수 없다는 것을 의미.
또 다른 표기법을 보자면, 전에는 입력 특성을 나타내기 위해 벡터 X를 사용했는데 입력값의 다른 표기법은 a[0]가 됨. a는 활성값을 의미하고 신경망의 층들이 다음 층으로 전달해주는 값을 의미. a[0]=X이라 하면 입력층은 X를 은닉층으로 전달해주게 되는 것. 다음 층인 은닉층은 활성값 a[1]을 만드는데, 여기서 첫 번째 노드는 a1[1]을, 두 번째 노드는 a2[1]을 생성함. 이런 방식으로 이어나가면 a[1]은 4차원 벡터가 되며 파이썬에서는 (1, 4)행렬 혹은 열 벡터라고 할 수 있음. 4차원인 이유는 이 은닉층에 은닉 노드가 네 개 있기 때문. 마지막으로 출력층은 실수값 a[2]를 만들게 되며 yhat은 a[2]의 값을 가지게 되는 것. 로지스틱 회귀에서 yhat가 a의 값을 가지는 것과 비슷하며 로지스틱 회귀에서는 출력층 하나만 있어서 대괄호 위첨자를 사용하지 않았지만 신경망에서는 위첨자를 사용해 어떤 층에서 만들어진 것인지 표기함.
신경망 표기 관례에서 조금 이상한 점은 위 슬라이드 속 신경망은 겉보기에 층이 3개일지라도 실제 이름은 2층 신경망(2 layer Neural Network)이라는 것인데, 이는 신경망의 층을 셀 때 입력층은 세지 않기 때문임. 즉 은닉층이 첫 번째 층, 출력층이 두 번째 층인 것. 물론 입력층을 0번째 층이라고도 하기 때문에 이 신경망에 입력층, 은닉층, 출력층 이렇게 층이 총 3개 있다고 할 수 있으나, 관례적으로 논문에서는 보통 해당 신경망을 2층 신경망이라고 부름.
나중에 다시 언급될 내용이지만, 은닉층과 출력층은 연관된 매개변수가 있는데, 은닉층은 매개 변수 w[1]과 b[1]에 연관되어 있고(첫 번째 층인 은닉층에 관련된 변수이기 때문에 위첨자[1]을 붙임) w는 (4, 3) 행렬, b는 (4, 1) 벡터가 됨. 4는 이 층에 은닉 노드가 네 개 있기 때문이고, 3은 입력 특성이 세 개이기 때문.
출력층도 비슷하게 w[2]와 b[2]에 관련되어 있고 차원은 (1, 4), (1, 1)이 됨. (1, 4)는 은닉층에 은닉 노드가 네 개가 있고 출력층에는 노드가 한 개 있기 때문.
📌신경망 네트워크 출력의 계산(C1W3L03)
핵심어: 층(Layer), 노드(node)
신경망 출력은 로지스틱 회귀와 비슷하지만 여러 번 반복된다는 특징이 있음.
슬라이드 왼쪽에 위치한 원은 두 단계의 계산을 나타내는데, z를 w^Tx + b 식으로 계산하고 활성화 a를 σ(z)로 계산함.
신경망에서는 해당 과정을 많이 반복하는데, 먼저 은닉층의 노드 하나를 집중해서 살펴볼 것.

다음과 같이 다른 노드들은 전부 회색 처리한 후, 로지스틱 회귀와 비슷하게 첫 번째 노드는 두 단계의 계산을 함. 첫 번째 단계는 이 노드의 왼쪽 부분으로 생각하고 z=w^Tx + b를 계산하며, 이 값들은 모두 첫 번째 은닉층과 관련되었기 때문에 모두 [1]을 붙여줌. 또한 은닉층의 첫 번째 노드이기 때문에 아래첨자 1도 붙임. 두 번째 단계(노드의 오른쪽 부분)에선 a1[1] = σ(z1[1])을 계산함. z와 a의 표기법에 대해 말하자면 대괄호[]안은 층 번호, 아래 첨자는 노드 번호임. 슬라이드에 표시된 노드는 1번 층의 1번 노드이므로 아래 첨자와 위 첨자 모두 1이 됨. 신경망의 노드인 원은 이 두 계산을 의미함.
은닉층의 두 번째 노드를 살펴보면, 이 노드 역시 왼쪽의 로지스틱 회귀와 비슷하게 이 원은 계산 두 단계를 나타냄. 첫 번째는 z2[1]을 계산하는데, 이때 아직 층은 첫 번째 층이지만 해당 은닉층의 두 번째 노드가 됨. z2[1] = w2^[1]Tx + b2[1]이고 a2[1] = σ(z2[1])이 됨.
이렇게 처음 두 은닉 노드를 살펴봤고 나머지 두 노드도 비슷하게 계산을 함.

해당하는 두 노드 계산식을 신경망과 함께 다시 살펴보면, 나머지 노드에 대한 식도 적는 것도 가능함.
표기법을 이해하기 쉽게 말하자면 z1[1] 식에서 벡터 w1[1]의 전치에 x을 곱한 것.
이전 강의에서 다뤘듯 신경망은 for문을 써서 구현하면 굉장히 비효율적이기 때문에, z1[1]부터 z4[1]까지 네 등식을 벡터화해야함.
z를 벡터로 계산할 때, w를 행렬처럼 쌓는다면 열 벡터의 전치인 행 벡터 w1^[1]T와 w2^[1]T, w3^[1]T, w4^[1]T가 됨.
다른 관점(로지스틱 회귀)에서 보면, 로지스틱 회귀 유닛 네 개가 있고 각 유닛은 상응하는 매개변수 w가 존재함. 매개변수 w의 벡터 4개를 쌓으면 (4, 3) 행렬을 얻는 것. 이 행렬을 특성 x1, x2, x3과 곱하면 w1^[1]Tx, w2^[1]Tx, w3^[1]Tx, w4[1]Tx를 얻게됨. 여기에 b1, b2, b3, b4로 이루어진 b를 더해준다면 w 벡터와 x 특성을 곱한 결과에 각 값을 더해주게 되고, 계산 결과의 각 행은 위에서 계산한 네 값과 정확히 일치한다는 점을 알 수 있으며 이에 따라 이 값은 z1[1]. z2[1], z3[1], z4[1]와 같다는 것 또한 확인 가능. 각 z를 열 벡터로 쌓은 이 벡터를 z[1]이라고 부른다는 가정함.
별개로 벡터화를 수월하게 하기 위해서는, 한 층에 노드가 여러 개이면 세로로 쌓는 것이 중요함. 위의 예시에서도 은닉 층의 네 노드에 상응하는 z1[1]부터 z4[1]를 세로로 쌓아서 벡터 z[1]을 만든 것도 이 때문임.
표기법 하나를 더 적용하자면 w를 쌓아서 만든 이 (4, 3) 행렬은 w[1]라고 부를 수 있으며 그 옆의 (4, 1) 벡터는 b[1]라고 부름. 여기서 z를 행렬로 표기하여 계산할 때, 마지막으로 해야 할 일은 a의 값을 계산하는 것.
a[1]을 a1[1]부터 a4[1]까지 쌓은 벡터로 정의했을 때, 이 값들을 쌓아서 a[1]이라 부르고 값은 σ(z[1])이 됨. 이 시그모이드 함수는 z[1]의 각 원소들의 시그모이드 값을 계산한 함수.
다시 정리하자면 z[1]은 w[1]에 x를 곱하고 b[1]을 더해준 것으로, a[1]은 σ(z[1])이됨.

위에서 정리한 내용을 바탕으로 보면, 해당 슬라이드에서 볼 수 있는 것은 신경망의 첫 층에서는 x가 주어졌을 때 z[1]은 W[1]x + b[1]이고 a[1]은 σ(z[1])이됨. z의 차원은 (4, 3) 행렬과 (3, 1) 벡터를 곱하고 (4, 1) 벡터를 더해 총 합해서 (4, 1)이고 a는 z와 마찬가지로 (4, 1) 벡터라고 할 수 있음. 여기서 x는 a[0]이고 yhat은 a[2]라는 점을 끌고 와야 함. 이에 따라 x를 a[0]으로 바꿀 수 있음.
다음 층에 대한 표현도 이와 유사한데, 출력층에서는 매개 변수 w[2]와 b[2]가 있고 각각 (1, 4) 행렬, (1, 1) 행렬임. 계산 과정에 따라 z[2]는 실수가 될 것. (1x4 행렬 * 4x1 행렬 + 1x1 행렬 = 1x1 행렬, 즉 실수)
마지막 출력 유닛을 매개 변수 w와 b를 가지는 로지스틱 회귀와 비슷하게 생각하면 w는 w^[2]T와 비슷하고 b는 b^[2]와 비슷함. 왼쪽 부분 신경망을 가리고 보면, 마지막 출력 유닛은 로지스틱 회귀와 굉장히 흡사하다고 할 수 있음. 단 w와 b 대신 (1, 4)차원의 w[2]와 (1, 1) 차원의 b[2]를 사용하는 것은 다름.
다시 말해서, 로지스틱 회귀에서 출력 혹은 예측값을 계산하려면 z=w^Tx + b와 yhat = a = σ(z)를 계산했는데, 은닉 층이 하나인 신경망에서는 출력값을 계산하기 위해 z[1], a[1], z[2], a[2] 이 네 등식을 구현하면 됨. 이는 출력값을 계산하는 벡터화된 구현이라고 할 수 있음. 여기서 z[1], a[1]은 은닉층의 네 로지스틱 회귀 유닛의 출력값을 계산한다면, z[2]와 a[2]는 출력층의 로지스틱 회귀를 계산한다고 보면 됨. 중요한 것은 이 신경망의 출력값을 계산하는 데엔 이 코드 네 줄만이 필요하다는 것임.
📌많은 샘플에 대한 벡터(C1W3L04)
핵심어: 벡터화(Vectorization)
앞서 다룬 내용은 훈련 샘플이 하나만 있을 때 신경망에서 예측값을 계산하는 법이었는데, 이버네는 다수의 훈련 샘플에 대한 벡터화를 진행할 것이며 이는 로지스틱 회귀의 결과와 비슷함. 훈련 샘플을 행렬의 열로 쌓아서 앞에서 다룬 등식을 조금씩 변형하면 신경망은 모든 샘플에 대한 출력값을 거의 동시에 계산할 수 있음.

앞서 봤던 z[1], z[2], a[1], a[2] 등식들은 입력 특성 벡터인 x가 주어졌을 때 한 훈련 샘플에 대해 yhat인 a[2]를 계산함.
만약 훈련 샘플을 m개로 확장시킨다면, 이 과정을 첫 훈련 샘플인 x(1)에 적용하여 첫 샘플의 예측갑신 yhat(1)을 계산하고
이 과정을 x(2)와 x(m)까지 적용해서 y(2)와 y(m)을 계산해줌. 이 값들을 활성화 함수 표기법으로 나타내기 위해 a[2](1)로 표기함. 이 다음은 a[2](2)가 되고 a[2](m)까지 이어짐. 여기서 () 안의 숫자는 몇 번째 훈련 샘플인지를 의미하고 []안의 숫자는 몇 번째 층인지 의미함.
모든 훈련 샘플의 예측값을 벡터화되지 않은 방법으로 계산한다면 i가 1부터 m까지일 때 z[1]~a[2] 공식들을 구현해야 함.
슬라이드 내의 코드로 나와있듯, 위 네 등식에서 훈련 샘플과 관련 있는 모든 변수에 위첨자 (i)를 붙여줘야 하며 m개의 모든 훈련 샘플의 출력값을 계산하고 싶다면 x, z와 a에 위첨자(i)를 붙여야 함.
이렇게 되면 for문을 이용한 수많은 반복이 존재할텐데, 이를 없애기 위해 해당 계산을 벡터화시킬 수 있음.

위 슬라이드에 있던 m개의 모든 훈련 샘플을 계산하는 for문 코드를 다시 가져옴. X는 훈련 샘플이 열로 쌓은 행렬이란 점을 기억하고, 훈련 샘플을 열로 쌓으면 nx X m행렬이 됨.
이 for문을 벡터화하려면 우선 z[1] = w[1]X + b[1]을 계산하고 A[1] = σ(Z[1])을 계산함. 다음으로 Z[2] = W[2]A[1] + b[2]을 계산하고 A[2] = σ(Z[2])을 계산함. 비교해본다면 벡터였던 소문자 x를 열로 쌓아 행렬인 대문자 X를 얻은 것.
z에도 같은 작업을 한다면 열 벡터인 z[1](1), z[1](2)부터 z[1](m)까지, 이 값 전체 m개를 열로 쌓는다면 행렬 Z[1]이 될 것.
a 또한 마찬가지로 a[1](1)부터 a[1](m)까지 열로 쌓는다면 소문자 x에서 대문자 X, 소문자 z에서 대문자 Z가 된 것 처럼 a도 벡터인 소문자 a에서 대문자 A[1]이 됨. Z[2]와 A[2]도 비슷하게 계산 가능한데, 이 벡터들을 가로로 쌓아서 Z[2]와 A[2]를 얻을 수 있음.
이 표기법이 우리한테 도움이 되는 것은, 행렬 Z와 A에 가로는 훈련 샘플의 번호가 되며 각기 다른 훈련 샘플에 대응되는 반면 세로는 신경망의 노드들과 대응됨. 예를 들어 행렬 왼쪽 위에 있는 값은 첫 은닉 유닛의 첫 훈련 샘플의 활성값이 되며 바로 아래 값은 첫 훈련 샘플의 두 번째 은닉 유닛의 활성값이 됨. 이는 Z, X와 같은 다른 행렬들에서도 마찬가지임.
📌벡터화 구현에 대한 설명(C1W3L05)
핵심어: 벡터화(Vectorization)

앞서 다룬 내용이 신경망의 정방향 전파의 벡터화였는데, 왜 그런것인지 이번에 그 이유를 살펴볼 것.
첫 훈련 샘플에 대해 z[1](1) = w^[1]x^(1) + b^[1]을 계산하고, 두 번째 훈련 샘플에 대해 z[1](2) = w^[1]x^(2) + b^[1]을 계산, 세 번째 훈련 샘플에서 z[1](3) = w^[1]x^(3) + b^[1]을 계산한다고 가정.
더욱 알기 쉬운 설명을 위해 간단히 b를 0이라고 하면, W[1] 어떤 한 행렬이 될것. x(1)에 관련된 계산을 보면 Q[1]와 x(1)의 곱은 열 벡터가 됨. x(2)도 이와 비슷하게 W[1]에 곱하면 열 벡터가 나옴. 이는 Z[1](2)가 됨. 마지막으로 W[1]과 x(3)을 곱하면 z[1](3) 열 벡터가 됨. 훈련 샘플을 모두 쌓아 만든 훈련 세트인 X를 살펴보면, 행렬 X는 x(1), x(2), x(3)를 모두 가로로 쌓아 만든 것. 훈련 샘플이 더 많다면 가로로 더 많이 쌓아야 함. 이 행렬 X와 W를 곱한다면 행렬 곱은 첫 열은 w[1]x(1)와 같게 되고, 둘째 열은 w[1]x(2)와 같게, 셋째 열은 w[1]x(3)와 같게 될 것. 이 값은 z[1](1), z[1](2), z[1](3)이 열 벡터로 표기된 것과 같음. 훈련 샘플이 더 많다면 열이 더 많아질 것. 즉 이 값은 행렬 Z[1]이 됨.
이 설명이 전에 하나의 훈련 샘플만 봤을 경우 W^[1]x^(i) = Z^[1](i)가 있었을 때 훈련 샘플을 다른 열에 채운다면 나오는 결과인 Z도 z가 열로 쌓임. 추가적으로 파이썬 브로드캐스팅을 통해 b를 더한다면 b[i]를 이 행렬의 각 열에 더해줌.
이 슬라이드에서 Z[1] = W^[1]X + b[1]이 전 슬라이드에서 봤던 네 단계 중 첫 단계에 맞는 식이라는 것을 보였고, 비슷한 분석을 하면 다른 단계들도 비슷한 논리를 통해 식을 구할 수 있음. 입력값을 열로 쌓는다면 결과도 열로 쌓인 값이 나오게 되는 것.

정리하자면 한 번에 하나의 훈련 샘플에 대해 정방향 전파를 한다면 i가 1부터 m까지 for문 코드를 반복해야 함. 다음엔 훈련 샘플을 열로 쌓아서 (for문의 값들을 모두 열로 쌓기, 슬라이드 상 A[1]만 있지만 나머지 값들도 마찬가지) 모든 m개의 훈련 샘플에 대해 벡터화를 해줌. 비슷한 방법으로 나머지 줄도 위의 코드에 맞는 구현임을 볼 수 있음. X는 A[0]과 같은데, 입력 특성 벡터 x는 a[0]과 같았기 때문. 따라서 x(i)는 a[0](i)와 동일.
그렇게 되면 위 식들은 대칭성이 있게 되는데, 다시말해 Z[1] 식은 W^[1]A^[0] + b[1]이라고도 쓸 수 있는 것. 이 공식 쌍들은 굉장히 비슷하게 생겼는데, 지수 차이가 1만큼 있을 뿐임. 이것은 신경망의 두 층이 대략 같은 것을 계산하고 있다는 것을 보여줌. 여기서는 2층 신겨망을 봤지만, 앞으로 더 깊은 신경망에서 이 두 단계를 더 많이 반복하게 될 것.
📌활성화 함수(C1W3L06)
핵심어: 활성화 함수(Activation Function), Sigmoid, Tanh, ReLU, leakyReLU
신경망을 만들 때 선택해야 하는 것 중 하나는 은닉층과 출력층에서 어떤 활성화 함수를 사용할지인데, 지금까지는 시그모이드 활성화 함수를 썼으나 다른 함수가 더 좋을 수 있음. 따라서 몇 가지 함수를 살펴볼 것.

우선 시그모이드 함수를 쓰는 두 단계가 있었는데, 일반적으로는 다른 함수인 g(z[1])를 쓸 수 있음. (g는 시그모이드 함수가 아닌 비선형 함수일 수 있음). 시그모이드 함수보다 대부분 경우 좋은 것은 쌍곡 탄젠트 함수인 tanh 함수임. a=tanh(z) 함수의 공식은 (e^z - e^-z) / (e^z +e^-z)인데, 수학적으로 시그모이드 함수를 조금 옮긴 것. 시그모이드 함수와 비슷하지만 원점을 지나고 비율이 달라짐(-1과 +1 사이). g(z[1])과 tanh(z)를 놓고 비교했을 때, 은닉 유닛에 대해서는 거의 항상 시그모이드 함수보다 쌍곡 탄젠트 함수가 더 좋음. 이는 값이 1과 -1 사이이기 때문에 평균값이 0에 더 가깝기 때문. 학습 알고리즘을 훈련할 때 평균값의 중심을 0으로 할 때가 있는데, 시그모이드 함수 대신 tanh 함수를 쓴다면 데이터의 중심을 0.5대신 0으로 만드는 효과가 있음. 이는 다음 층의 학습을 더욱 쉽게 해줌.
단 출력층에서는 예외적으로, y가 0이거나 1이라면 yhat은 -1과 1 사이 대신 0과 1 사이로 출력하는 것이 좋기 때문에 쌍곡 탄젠트 함수보다 시그모이드 함수가 잘 쓰임. 이처럼 시그모이드 활성화 함수를 쓰는 한 가지 예외는 이진 분류로, 출력층에 시그모이드 함수를 쓰고 g(z[2]) = σ(z[2])가 됨. 이 예에서 보듯 은닉층에선 tanh 활성화 함수를, 출력층에서는 시그모이드 함수를 사용하는데 이처럼 다른 층에서 다른 활성화 함수가 쓰일 수 있고 이를 보여주기 위해 대괄호 위첨자를 쓸 수 있음. 즉 g[1], g[2]가 다를 수 있다는 것. 시그모이드 함수와 tanh 함수의 단점은 z가 굉장히 크거나 작으면 함수의 도함수가 굉장히 작아진다는 것으로, z가 크거나 작으면 함수의 기울기가 0에 가까워지고 경사 하강법이 느려질 수 있음.
머신러닝에서 인기 있는 함수는 ReLU라고 불리는 정류 선형 유닛으로, 공식은 max(0, z)임. z가 양수일 때 도함수가 1, z가 음수일 때 도함수가 0이 됨. 엄밀하게는 z가 0일 때의 도함수는 정의되지 않지만, 컴퓨터에서 구현했을 때 z가 정확히 0이 될 확률은 굉장히 낮기 때문에 걱정하지 않아도 됨.
활성화 함수 선택에서, 이진 분류의 출력층에는 자연스럽게 시그모이드 함수를 사용하며 다른 경우에 ReLU가 활성화 함수의 기본값으로 많이 사용됨. 은닉 층에 어떤 함수를 써야 할지 고민이라면 ReLU를 쓰는 것이 좋음. ReLU의 단점 중 하나는 z가 음수일 때 도함수가 0이라는 것인데, 이를 보완한 leaky ReLU가 있음. 여기서는 z가 음수일 때 도함수가 0이 아니고 약간의 기울기가 있음. 이는 실제로 많이 쓰이지는 않지만 ReLU보다 좋은 결과를 보여줌.
ReLU와 leaky ReLU의 장점은 대부분의 z에 대해 기울기가 0과 매우 다르다는 것. 따라서 시그모이드나 tanh 대신 ReLU 함수를 쓴다면 신경망은 훨씬 더 빠르게 학습할 수 이씀. 학습을 느리게하는 원인인 함수의 기울기가 0에 가까워지는 것을 막아주기 때문. z의 절반에 대해 ReLU의 기울기가 0이지만 실제로는 충분한 은닉 유닛의 z는 0보다 크기 때문에 문제없이 잘 작동함.

다양한 활성화 함수의 장단점을 다시 정리하자면,
- 시그모이드 함수: 이진 분류의 출력층 외에는 거의 사용 X
- tanh 함수: 시그모이드 함수보다 거의 항상 좋음
- ReLU: 가장 많이 쓰임, 뭘 써야할지 모를 때 사용
- leaky ReLU: 시도해도 좋음.
딥러닝에서는 신경망을 만들 때 굉장히 많은 선택을 할 수 있는데, 은닉층의 수, 활성화 함수와 가중치의 초기화 등이 있음. 풀 문제에 따라 좋은 결과를 내게 해줄 지점은 찾기 어려우며 각 구현의 특징에 따라 뭐가 제일 좋은지는 예측하기 쉽지 않음. 따라서 어떤 활성화 함수가 좋을지 모르겠다면 모두 시도한 뒤 나중에 다룰 검증이나 개발 세트에 시도해보고 결과를 살펴보는 것이 좋음.
📌왜 비선형 활성화 함수를 써야할까요?(C1W3L07)
핵심어: 비선형 활성화 함수

신경망이 흥미로운 함수를 계산하려면 비선형 활성화 함수가 필요함.
정방향 전파 식들에서 , 비선형 활성화 함수 대신 선형 활성화 함수(여기서는 항등함수)로 정하면 이 모델은 yhat을 입력 특성인 x에 대한 선형 함수로 계산하게 됨. 첫 두 식을 보면 a[1] = z[1] = W[1]x + b[1]이 되는데, 다음엔 a[2] = z[2] = W[2]a[1]+b[2]가 됨. a[1]을 두 번째 식에 대입한다면 a[2] = W[2](W[1]x+b[1]) + b[2]가 되고 간소화하면 (W[2]W[1])x + (W[2]b[1] + b[2])가 됨. 앞의 값을 W', 뒤 값을 b'라고 했을 때 W'x + b'이 됨. 선형 활성화 함수나 항등 활성화 함수를 쓴다면 신경망은 입력의 선형식만을 출력하게 됨. 나중에 층이 많은 신경망인 심층 신경망에 대해 다룰텐데, 선형 활성화 함수의 경우 층이 얼마나 많든 간에 신경망은 선형 활성화 함수만 계산하기 때문에 은닉층이 없는 것과 다름없음.
은닉층에 선형 활성화 함수를 쓰고 출력층에 시그모이드 함수를 쓴다면 이 모델은 표준 로지스틱 회귀보다 더 나아지지 않음(증명 건너뜀). 여기서 알아야 할 점은 선형 은닉층은 쓸모가 없다는 것. 두 선형 함수의 조합은 하나의 선형 함수가 되기 때문. 비선형식을 쓰지 않는다면 신경망이 깊어져도 흥미로운 계산을 할 수 없음.
단 선형 활성화 함수인 g(z) = z를 사용하는 곳이 하니 있는데, 회귀 문제에 대한 머신러닝에서 y가 실수일 때임. 예를 들어 주택 가격 예측 등이 있는데, y가 0이거나 1이 아닌 0부터 집값이 비싸지는 대로 올라가고 백만 달러 정도나 데이터 세트에 있는 최고 값이 되면 y가 실수값이라면 선형 활성화 함수를 써도 괜찮음. 출력값이 -무한대부터 무한대까지의 실수 값이 되어도 상관 없음.
하지만 은닉 유닛은 선형 활성화 함수가 아닌 ReLU, tanh, leaky ReLU나 다른 비선형 함수를 사용해야 함. 선형 활성화 함수를 쓸 수 있는 곳은 대부분 출력층으로, 은닉층에서 선형 활성화 함수를 사용하는 경우는 굉장히 드뭄. 첫째 주 영상에서 본 것처럼 집값을 예측할 때에는 집값은 항상 양수이기 때문에 출력값인 yhat이 양수가 되도록 ReLU 함수를 사용할 수 있음.
📌활성화 함수의 미분(C1W3L08)
핵심어: 미분

신경망의 역방향 전파를 구현하려면 활성화 함수의 도함수를 구해야 함.
우선 시그모이드 활성화 함수의 경우, 주어진 값 z에 대해 이 함수는 특정한 기울기를 가짐. 선을 그었을 때 삼각형의 높이를 너비로 나눈 값으로, g(z)가 시그모이드 함수일 때 함수의 기울기는 d/dz g(z)가 되는데 미적분에서 이 값은 z에서의 기울기가 됨. 미적분의 공식을 이용하여 g(z)를 미분하면 g(z)(1-g(z))와 같음. 이 공식이 맞는지 확인해보기 위해 우선 z가 굉장히 큰 값이 10일 때 g(z)는 1에 가까워짐. 도함수 공식에 따르면 d/dz g(z)는 1(1-1)과 비슷해지므로 0과 가까워짐. z가 커지면 기울기가 0에 가까워지기 때문에 이는 맞는 공식임을 알 수 있음. z가 아주 작은 값인 -10이라면 g(z)는 0에 가까워지고 도함 공식은 0(1-0)에 가까워지며 이 값 또한 0과 가까워짐. 마지막으로 z가 0이라고 가정하면 g(z)는 시그모이드 함수에서 볼 수 있듯 1/2가 되며 따라서 도함수는 1/2(1-1/2)인 1/4가 됨. z가 0일 때의 기울기 혹은 도함수의 값과 정확히 일치함. 한편 d/dz g(z)라는 표기 대신 g'(z)라고도 쓸 수 있는데, 이는 입력 변수 z에 대한 g의 도함수를 의미함. 신경망에서 a는 g(z)와 같고 따라서 g(z)(1-g(z)) 식은 a(1-a)로 간소화할 수 있음. 따라서 g'(z) = a(1-a)라는 표기도 가능함. 이 공식의 장점은 이미 a 값을 계산했다면 이 공식을 써서 g'의 값을 빠르게 계산할 수 있다는 것임.

tanh 활성화 함수의 경우, d/dz g(z)는 미적분 공식을 이용해 구했을 때 1-(tanh(z))^2가 되는데, 이 공식이 성립한다는 것을 확인해보기 위해 z가 10이라면 tanh(z)는 1에 가까워지고 tanh는 -1부터 1까지 값을 가짐. 이 공식에 따르면 g'(z)는 1-1^2인 0에 가까워지므로 z가 큰 값이면 기울기는 0에 가까워짐. z가 매우 작은 값인 -10이라면 tanh(z)는 -1에 가까워지며 g'(z)는 1에서 -1의 제곱을 뺀 0에 가까워짐. z가 0이라면 tanh(z)는 0이 되고 기울기는 1이 됨. 실제로도 기울기가 1이므로, 해당 도함수는 잘 성립한다고 볼 수 있음. 요약하자면 a가 g(z)인 tanh(z)일 때 도함수인 g'(z)는 1-a^2가 됨. a의 값을 이미 계산했다면 이 공식을 사용하여 도함수도 빠르게 계산할 수 있음.

마지막으로 ReLU와 leaky ReLU의 도함수를 계산하는 법을 살펴볼 것인데, ReLU에서 g(z)는 max(0,z)가 됨. 따라서 도함수는 z가 0보다 작을때는 0이고 z가 0보다 크면 1이 됨. z가 0일 때 엄밀하게는 정의되어있지 않으나 실제로 z가 0일 때 도함수를 1이나 0이라고 해도 문제는 없음. 최적화에 익숙하다면 g'은 활성화 함수 g(z)의 서브 경사이기 때문에 경사 하강법이 잘 작동함. z가 정확히 0이 될 확률은 정말 작기 때문에 z가 0일 때 도함수를 뭐라고 하든지 상관없음. 따라서 실제로는 g'(z)를 이렇게 구현함.
leaky ReLU 활성화 함수를 사용하여 신경망을 훈련한다면 g(z)는 max(0.01z, z)가 됨. g'(z)는 z가 0보다 작을 때 0.01이 되고, z가 0보다 클 때는 1이 됨. 여기서도 z가 정확히 0이라면 도함수가 정의되지 않았지만 코드를 쓸 때에는 z가 0일 때 g'을 0.01이나 1 둘 중에 아무렇게나 설정해도 상관 없음.
🔎참고 자료
- 시그모이드
- g(z)=1+e−z1
- g′(z)=dzdg(z)=g(z)(1−g(z))
- Tanh
- g(z)=ez+e−zez−e−z
- g′(z)=1−(g(z))2
- ReLU
- g(z)=max(0,z)
- g′(z)=0 (z < 0인 경우)
- g′(z)=1 (z >= 0인 경우)
- Leaky ReLU
- g(z)=max(0.01z,z)
- g′(z)=0.01 (z < 0인 경우)
- g′(z)=1 (z >= 0인 경우)

📌신경망 네트워크와 경사 하강법(C1W3L09)
핵심어: 경사 하강법
한 개의 은닉층을 가진 신경망에 대한 경사 하강법 구현 방법을 알아볼 것.

현재 단일층 신경망이 w[1], b[1], w[2], b[2]의 변수를 가지고 nx는 n[0]를 입력 특성으로 가지고 n[1]은 은닉 유닛으로, n[2]는 출력 유닛으로 가짐. 현재 사용하는 샘플에서 n[2]는 1이었는데, 그렇다면 행렬 w[1]은 (n[1], n[0]) 차원을 가짐. 그리고 b[1]은 n[1] 차원을 가지는 벡터가 되며 (n[1], 1) 차원이라고 적을 수 있으며 따라서 이는 행 벡터가 될 것. w[2]는 (n[2], n[1]) 차원이 되고 b[2]는 (n[2], 1) 차원이 됨. 이것은 한 개의 은닉 유닛을 가진 n[2]가 1인 예시를 사용한 경우임. 그리고 여기에 신경망의 비용 함수 J가 있는데, 여기서는 이진 분류를 하고 있다고 가정. 이 경우 각 변수들에 대한 비용은 손실함수의 평균이 됨. 여기서 L은 신경망이 예측한 yhat값에 대한 손실이며, yhat은 a[2], y는 참값을 말함. 여기서 손실 함수는 로지스틱 회귀에서 사용했던 것과 동일. 이제 이 알고리즘에서 변수들을 훈련시키기 위해 경사 하강법을 사용. 신경망을 훈련할 때 0이 아닌 값으로 변수를 초기화하는 것이 중요한데, 변수를 어떤 값으로 초기화한 후 경사 하강법이 반복될 때마다 예측값을 계산함. 다시 말해서 yhat[i]를 계산하는 것. 이제 도함수 dw[1]을 계산해야 하는데, 이는 변수 w[i]에 대한 비용 함수의 도함수를 의미. 또한 db[1]을 계산해야 하는데 이 값은 b[1]에 대한 비용 함수의 도함수가 되는 것. w[2]와 b[2]에 대해서도 비슷하게 도함수 계산을 이어가면, 결국 경사 하강법은 w[1]을 w[1] - αdw[1]으로 바꿈. 여기서 α는 학습률을 의미함.

각각의 변수에 대해 편미분 값을 계산한 결과:
A[0] (n[0], m)
W[1] (n[1], n[0])
b[1] (n[1], 1)
Z[1] (n[1], m)
A[1] (n[1], m)
W[2] (n[2], n[1])
b[2] (n[2], 1)
Z[2] (n[2], m)
A[2] (n[2], m)
dZ[2] (n[2], m)
dW[2] (n[2], n[1])
db[2] (n[2], 1)
dZ[1] (n[1], m)
dW[1] (n[1], n[0])
db[1] (n[1], 1)
keepdims 변수를 통해 shape 를 유지해주는 것이 rank 1 행렬을 만들지 않는 방법.
📌역전파에 대한 이해(C1W3L10)
핵심어: 역전파(backpropagation)




역전파 알고리즘은 정말 복잡하여 블랙박스처럼 느껴집니다. 역전파는 선형 회귀 또는 로지스틱 회귀에 비해 수학적으로 불명확하고 복잡한 알고리즘입니다. 하지만, 프로그래밍 실습을 하는 분들은 기계적으로 역전파를 구현하는 방법을 순서대로 따라 하면 인공 신경망은 스스로 작동합니다. 순전파 알고리즘을 먼저 수행합니다.
순전파는 왼쪽에서 오른쪽으로 계산하면서 가설의 예측치를 계산하고, 역전파는 오른쪽에서 왼쪽으로 계산하면서 미분항을 계산합니다. 즉, 비용은 출력 유닛이 직접 출력하는 값과 실제 값 사이의 오차의 제곱입니다. 역전파는 계산 과정에서 결과값에 영향을 미치기 위해 가중치를 얼마나 변경해야 할지를 측정합니다. 그리고, 은닉 유닛의 δ값은 계산해도 바이어스 유닛은 계산하지 않습니다.
📌랜덤 초기화(C1W3L11)

W, b 를 모든 값이 0인 행렬로 설정할 때의 문제점
1. 한 layer 에서 각각의 node 에서 출력하는 값이 모두 동일
2. 같은 층에서 모든 노드의 dz 값이 동일
3. 같은 층에서 모든 노드의 dw 값 또한 동일
-> 학습을 진행해도 모든 노드는 같은 함수의 결과값을 가짐. 이러한 형태를 symmetric 한 형태라고 표현
결국 node 가 많은 신경망을 사용하는 의미가 없고 단 하나의 노드를 사용하는 신경망을 사용하는 것과 같은 결과를 나타냄

따라서 위와 같이 W 값을 numpy 의 np.random.randn 함수를 이용해서 정규분포를 갖는 임의의 값을 초기값으로 설정
여기서 0.01을 곱해줬는데 이유는 학습을 빠르게 하기 위함.
W 값이 커질 경우 Z 값이 커지고 이런 경우 sigmoid, Tanh 함수를 사용하면 기울기가 너무 작아지므로 학습이 오래걸리는 경우가 발생할 수 있기 때문.
sigmoid, Tanh 함수가 사용되는 경우가 많지는 않지만 binary classification 에서 출력층의 g function 이 늘 sigmoid 함수이므로 W 값을 작게 만들어주는 방향으로 세팅해줌.
shallow 한 NN 에서는 0.01 으로 세팅해주는 것이 문제가 없지만 deep NN 에서는 더 작은 값으로 세팅이 필요할 수 있는데 이는 다음 강의에서 다룬다고 함.
b 값은 W 값이 임의의 값으로 초기화한다면 대칭 회피 문제가 존재하지 않으므로 모두 0의 값으로 초기화해줌.
'Project > DL 스터디&프로젝트' 카테고리의 다른 글
| [Euron 중급 세션 5주차] 딥러닝 2단계 1. 머신러닝 어플리케이션 설정하기 (0) | 2023.10.09 |
|---|---|
| [Euron 중급 세션 4주차] 5. 심층 신경망 네트워크 (1) | 2023.10.02 |
| [Euron 중급 세션 2주차] 3. 파이썬과 벡터화 (0) | 2023.09.18 |
| [Euron 중급 세션 1주차] 2. 신경망과 로지스틱 회귀 (1) | 2023.09.11 |
| [Euron 중급 세션 1주차] 1. 딥러닝 소개 (0) | 2023.09.11 |