2. 신경망과 로지스틱 회귀
📌이진 분류(C1W2L01)
핵심어: 이진 분류(Binary Classification), 로지스틱 분류(Logistic Classification)
로지스틱 회귀: 이진 분류를 위한 알고리즘

예를 들어 고양이 사진이라고 판단하면 1을, 고양이 사진이 아니라고 판단하면 0을 출력하는 고양이 인식기를 생성한다고 가정했을때, y로 출력 레이블을 표시함.
RGB 세 개의 행렬로 나누어 저장하며, 세 개의 64x64 행렬들 사진의 빨간 초록 파란색 픽셀 강도 값을 나타냄.
해당 픽셀 강도 값들을 특성 벡터로 바꾸려면, 모든 픽셀값을 입력될 특성 벡터 x의 한 열로 나열할 것임.
픽셀 값을 하나의 벡터로 펼치기 위해 주어진 사진에 대한 특성 벡터 x를 다음과 같이 정의함.
픽셀값 전부를 차례대로 나열하고 매우 긴 특성 벡터가 되도록 함. 따라서 64x64일 경우 벡터 x의 전체 차원은 64x64x3=12288이 된다고 볼 수 있는데, 이는 이 행렬들의 원소들을 포함하고 있기 때문임.
해당 벡터는 차원을 n_x로 표현한다면, n_x=12288인 것임.

단 하나의 훈련 샘플을 한 쌍 (x, y)로 표시할 때, x는 n_x 차원 상의 특성 벡터이고 레이블 y는 0 또는 1임. 훈련 세트는 m개의 훈련 샘플을 포함하고 다음과 같이 표기될 것임:
(x^(1), y^(1)), (x^(2), y^(2)), ... , (x^(m), y^(m)) (괄호 안의 위첨자는 순서를 표시한 것)
이때 X 행렬은 m개의 열과 n_x개의 행으로 이루어진 행렬임.
요약하자면 X는 n_x x m 행렬이고, 파이썬으로 구현한다면 X.shape으로 행렬의 차원 파악 가능.
이렇게 훈련 샘플들의 x를 행렬로 묶을 수 있음.
반면 Y의 경우, y의 값들을 열로 놓는 것이 편리함, 그러므로 Y는 y^(1) y^(2)부터 y^(m)으로 이루어진 1xm행렬로 정의할 수 있음. 추후 신경망을 구현할 때 여기서 X랑 Y를 정의한 것처럼, x나 y 또는 나중에 볼 여러 훈련 샘플에 관한 데이터를 각각의 열로 놓는 것이 유용할 것임.
📌로지스틱 회귀(C1W2L02)
핵심어: 로지스틱 회귀(Logistic Regression), 예측값 y-hat, 시그모이드(sigmoid) 함수
지도 학습 문제에서 로지스틱 회귀 알고리즘은 출력될 레이블 y가 0이나 1일 경우, 즉 이진 분류 문제에서 사용됨.
예를 들어 입력될 특성 벡터 x가 있다고 가정하고(고양이 사진 등) y의 예측값(y hat)을 출력하는 알고리즘을 원함.
더 자세히는 y의 예측값은 입력 특성 x가 주어졌을 때 y가 1일 확률을 뜻함. 다른 말로 x가 사진이라면, y의 예측값은 이 사진이 고양이 사진일 확률을 알려줌.

전 영상에서 보았던 것처럼 x는 n_x 차원 상의 벡터이고, 로지스틱 회귀의 파라미터의 w와 b는 각각 n_x 차원 상의 벡터와 실수임. 입력 x와 파라미터 w와 b가 주어졌을 때 어떻게 y의 예측값을 출력할 수 있을까?
y의 예측값을 w의 전치행렬 x X+b처럼 선형 함수로 놓는 방법도 있지만, 이는 이진 탐색에서 좋은 방법이 아님.(y의 예측값은 y가 1일 확률이 때문에 항상 0과 1사이어야 하기 때문, 하지만 위 식은 그런 경우가 잘 일어나지 않음).
대신 로지스틱 회귀에서는 y의 예측값이 시그모이드 함수를 적용하여 출력된 값이 됨.
시그모이드 함수에서 z가 수평축일 때, z의 시그모이드는 0부터 1까지 매끈하게 올라감. 수직축은 0.5에서 교차.
여기서 z는 w의 전치행렬 x X+b의 값을 의미함.
시그모이드 공식은 다음과 같음:
z가 실수일 때 z의 시그모이드는 1/(1+e^(-z))임. 여기서 주목할 것이 있는데, z가 아주 크면 e^(-z)가 0으로 수렴함. 이에 따라 z의 시그모이드는 대략 1과 0에 가까운 숫자 합을 1에서 나누었기 때문에 1에 가까워짐. 반대로 z가 아주 작거나 아주 큰 음수인 경우, e^(-z)가 큰 수가 되고 z의 시그모이드는 1과 엄청 큰 수의 합을 1에서 나누었기 때문에 크기가 거의 0과 같음. z가 큰 음수일수록 z의 시그모이드도 0에 수렴함. 그러므로 로지스틱 회귀를 구현할 때, y가 1일 확률을 잘 예측하도록 파라미터 w와 b를 학습해야 함.
우리가 신경망을 구현할 때 보통 파라미터 w와 b를 분리하며 여기서 b는 인터셉트 항을 뜻함.
📌로지스틱 회귀의 비용함수(C1W2L03)
핵심어: 손실 함수(Loss Function), 비용 함수(Cost Function)
위에서 보았던 로지스틱 회귀의 파라미터 w와 b를 학습하려면 비용함수를 정의해야 함.시그모이드 함수에서 i번째 훈련 샘플의 y의 예측값은 w의 전치 x x^(i) + b에 시그모이드 함수를 적용해 구할 수 있음.이제 알고리즘이 얼마나 잘 가동되는지를 측정할 수 있는 손실 함수 또는 오차 함수에 대해 알아볼 것.

제곱 오차가 합리적인 선택으로 보일 수 있지만 로지스틱 회귀에서는 경사 하강법을 적용하지 못하게 만들기 때문에, 제곱 오차와 비슷한 역할을 하지만 최적화하기 더 쉬운 방법을 선택할 것. 이 방법이 바로 손실함수.
손실 함수는 L 함수라고도 하며, 출력된 y의 예측값과 참값 y 사이에 오차가 얼마나 큰지 측정함.
손실함수 L의 공식은 다음과 같음: L(y^,y)=−(ylogy^+(1−y)log(1−y^))
이러한 손실 함수를 왜 쓰는지에 대한 직관적인 이유는, 만약 제곱 오차를 쓴다 하면 그 오차를 최소화하려 할 것. 똑같이 이 로지스틱 회귀 손실 함수를 사용할 때, 이 값을 최소화해야 함.
이 함수를 왜 사용하는지는 두 가지 경우를 통해 설명할 수 있음.
첫 번째, y가 1일 경우 손실함수 L(y-hat, y)는 단순히 -log(y hat)이 됨. 즉 y가 1일 때 -log(y의 예측값)이 최대한 커지기를 원하는 것임. 그러려면 log(y hat)이 최대한 커져야 하며, 따라서 y의 예측값이 최대한 커야 함. 하지만 y hat은 시그모이드 함수값이기 때문에 1보다 클 수 없음. 그러므로 y가 1일 경우, y의 예측값이 1보다 클 수는 없으므로 1에 수렴하기를 원한다는 의미임.
또 다른 경우는 y가 0일 경우임. y가 0일 때 손실 함수의 첫 항이 0이 됨. 그러면 두 번째 항이 남고 이에 따라 손실 함수는 -log(1-y hat)이 됨. 따라서 학습 중에 손실 함숫값을 줄이고 싶다면 마이너스 부호가 붙어있기 때문에 log(1-y hat)이 최대한 커져야만 함. 따라서 아까와 비슷한 논리로 y의 예측값(y hat)이 최대한 작아야 한다는 것을 알 수 있음.
y의 예측값은 0과 1 사이어야 하므로, y가 0이면 손실 함수는 y의 예측값이 0에 수렴하도록 매개 변수들을 조정할 것임.
y가 1일 때 y의 예측값이 크고, y가 0일 때 y의 예측값이 작은 성질을 가지고 있는 함수들은 많음. (초록색 필기 부분은 손실 함수에 대한 비공식적인 검증)
마지막으로, 손실 함수는 훈련 샘플 하나에 관하여 정의되어 그 하나가 얼마나 잘 예측 되었는지 측정해줌.
한편 비용 함수는 훈련 세트 전체에 대해 얼마나 잘 추측되었는지 측정해주는 함수임.
비용 함수 J는 매개 변수 w와 b에 대해 손실 함수를 각각의 훈련 샘플에 적용한 값의 합들의 평균, 즉 m으로 나눈 값임.
여기서 y의 예측값은 로지스틱 회귀 알고리즘이 정해진 매개 변수들 w와 b를 적용해서 출력하는 값이고, 위의 손실 함수의 정의를 이용하여 이를 풀어쓰자면 비용 함수는 -(1/m)을 [y^(i) x log(y^(i)의 예측값) + (1-y^(i)) x log(1-y^(i)의 예측값)]을 i=1부터 i=m까지의 합에 곱한 값과 같음.
기호로 표현하자면, 비용함수 J의 공식은 다음과 같음: J(w,b)=−m1Σi=1i=m(y(i)logy^(i)+(1−y(i))log(1−y^(i)))
중요한 것은 손실 함수가 하나의 훈련 샘플에 적용이 된다는 것이고, 비용 함수는 매개 변수의 비용처럼 작용한다는 것임.
결과적으로 로지스틱 회귀 모델을 학습하는 것이란, 비용 함수 J를 최소화해주는 매개 변수들 w와 b를 찾는 것임.
📌경사하강법(C1W2L04)
핵심어: 경사하강법(Gradient Descent), 도함수(Derivative), 기울기(Slope), 볼록한(Convex)
지금까지 단일 훈련 샘플이 얼마나 잘 적동하는지 측정하는 손실 함수, 매개변수 w, b가 훈련 세트 전체를 얼마나 잘 예측하는지 측정하는 비용 함수에 대해 공부함.
이제부터 경사 하강법 알고리즘을 사용하여 매개변수 w와 b를 훈련 세트에 학습시키는 방법을 알아볼 것.
손실함수는 알고리즘이 각 훈련 샘플의 y 예측값이 얼마나 좋은지를 각 훈련 샘플에 대한 참값 y^(i)와 비교해 측정함.
비용함수는 매개변수 w와 b가 훈련 세트를 잘 예측하는지 측정하는데, 그러면 매개변수 w와 b를 알아내기 위해서는 비용 함수 J(w,b)를 가장 작게 만드는 w와 b를 찾아야 함.

경사하강법 그래프에서 두 가로축은 매개변수 w와 b의 공간을 나타냄. 실제로는 w가 더 높은 차원을 취할 수도 있지만, 도표를 그릴 때는 w와 b를 각각 하나의 실수라고 가정함.
이렇게 되면 비용함수 J(w,b)는 가로축 w,b위의 곡면이고 곡면의 높이는 그 점의 J(w,b)값을 나타냄.
여기서 비용 함수 J의 최솟값에 해당하는 w와 b를 찾아야 함. 이 특정 비용 함수 J는 활처럼 볼록한 함수인데, 볼록하지 않은 함수는 지역 최적값이 여러 개임. 이와 달리 비용 함수 J(w, b)가 볼록한 부분이 하나라는 사실이 로지스틱 회귀에 위의 비용 함수 J를 사용한 큰 이유 중 하나임.
매개 변수에 쓸 좋은 값을 찾기 위해서, w와 b를 어떤 초깃값(빨간 점)으로 초기화해야 함. 로지스틱 회귀에는 거의 모든 초기화 방법을 사용할 수 있는데, 보통 초깃값을 0으로 설정함. 무작위 초기화도 가능하지만 보통 로지스틱 회귀에는 사용하지 않음. 하지만 이 함수는 볼록하기 때문에, 어디서 초기화를 해도 거의 같은 점에 도착하게 될 것임.
경사하강법에서는 초기점에서 시작해 가장 가파른 내리막 방향으로 한 단계 내려감(가장 가파른 내리막, 가장 빨리 내려올 수 있는 방향 택함). 이 과정을 두 세번 반복하다 보면 가장 밑에 있는 전역 최적값이나 그 근사치에 도달하게 될 것임.

위 함수를 보면, w는 w - (학습률x미분계수)로 갱신되는데 미분계수가 양수이므로 w에서 미분계수를 빼는 것이 되어 왼쪽으로 한 단계 감. 따라서 경사 하강법은 큰 w에서 시작한 경우에 서서히 매개변수를 감소시킴.
w가 만약 반대편에 있다면 미분계수 또한 부호가 반대가 되고, 서서히 w를 증가시킴.
따라서 왼쪽에서 초기화하던 오른쪽에서 초기화하던 상관 없이 경사 하강법은 매개변수를 전역 최솟값까지 도달하게 함.
즉 현재 매개변수 위치에서 함수의 기울기를 찾아, 가장 가파른 경사로 내려가는 각 단계에 적용함으로써 비용 함수 J에서 내려가는 방향을 찾을 수 있음.
여태까지 매개변수가 w만 있을 경우인 J(w)에 대한 경사하강법을 알아보았는데, 로지스틱 회귀에서 비용 함수는 w와 b에 대한 함수이고 이 때 경사하강법의 내부 반복문은 다음과 같이 바꿀 수 있음.
w는 w - (학습률 x w에 대한 J(w,b)의 미분계수)
*w에 대한 J(w,b)의 미분계수라 하면, J(w,b)가 w 방향으로 얼마나 기울었는지를 나타냄.
b는 b - (학습률 x b에 대한 비용 함수의 미분계수)로 갱신함.
따라서 구현할 때 사용하게 될 식은 이 두 식이 될 것.
**소문자 d는 J가 하나의 변수를 가진 함수일 때, 편미분 기호는 J가 두 개 이상의 변수를 가진 함수일 때 사용.
편미분은 여러 변수 중 하나에 대한 함수의 기울기를 구하는 것.
관습적으로 w의 변화를 나타내는 값은 이름을 dw라 하고, 코드에서 b의 변화량을 나타내는 이 값은 변수의 이름을 db라고 부름.
📌미분(C1W2L05)
핵심어: 기울기(slope), 도함수(derivative)

도함수는 기울기라고 볼 수 있음. 기울기는 도함수의 개념을 쉽게 말한 것이며, 도함수라고 하면 함수의 기울기라고 생각해주면 이해하기 쉬울 것.
기울기를 좀 더 정확하게 설명하자면, f(a)의 증가량을 a의 증가량으로 나눈 것임(y증가량/x증가량).
예를 들어 f(a) = 3a라는 일차함수에서 기울기, 미분계수가 3이라는 것은 a를 아주 조금 움직여도, f(a)는 a를 가로로 민 정도보다 세 배나 커진다는 것을 의미함. 이는 a가 5일 때도 마찬가지임.
f(a)의 기울기가 3이라는 것은, 변수 a를 아주 조금 움직였을 때 함수 f의 기울기라는 뜻이고 이 기울기가 3과 같다는 것임.
도함수의 정확한 정의는 a를 무한소로 밀었을 때, 즉 아주 작은 값일 때, 그 때의 f(a)가 작고 작은 a의 세 배 만큼 증가한다는 것임.
위 일차함수의 도함수의 특징이라고 하면, 함수의 어느 곳이든 기울기가 3이라는 것임. a가 2일 때도, 5일 때도 함수의 기울기는 3임. a의 값이 무엇이든 0.001만큼 증가시키면 f(a)의 값은 이것의 세 배 증가한다는 뜻임.
따라서 이 함수는 모든 곳의 기울기가 같으며, 이 a가 어디에 위치하는지와 상관 없이 (f(a)의 증가량)/(a의 증가량) 값이 3이라는 의미임.
📌더 많은 미분 예제(C1W2L06)
핵심어: 기울기(slope), 도함수(derivative)
앞서 살펴본 함수에서는 a좌표의 위치가 변해도 기울기가 달라지지 않았다면, 이번에는 함수의 a좌표가 달라지면 기울기 또한 같이 달라지는 경우를 살펴볼 것.

예를 들어 f(a) = a^2 함수에서 a=2인 경우를 살펴보면, 이 때 f(a)=4가 됨. 여기서 a를 0.001만큼 밀면 f(a)인 그것의 네 배인 4.004로 증가함. 미적분의 관점에서는 이를 a=2일 때 f(a)의 기울기, 미분계수가 4라고 말할 수 있음.
미적분 표기법을 사용하면 a=2일 때, (d/da) x f(a)=4인 것.
위 함수 a^2에서는 a값이 다르면 기울기도 바뀜. 만약 a가 5라면, f(a)는 25이고 a를 5.001로 밀면 f(a)는 약 25.010이 됨. 이는 f(a)가 열 배 가까이 증가하는 것이며, a가 5일 때 (d/da) x f(a)=10, 미분계수가 10인 것임. a를 살짝 밀었을 때 f(a)가 a에 비해 열 배나 많이 증가했기 때문. 다른 점마다 미분 계수가 다른 이유는, 곡선 위의 위치마다 (f(a)의 증가량)/(a의 증가량)의 비율이 전부 다르기 때문임.
이 경우 a가 2일 때의 기울기는 4이지만, a가 5일 때의 기울기는 10임.
미분 공식에 의하면 (da^2/da) = 2a이므로 a가 아무 값 a를 아주 작은 값 0.001만큼 밀었을 때 f(a)의 값은 2a만큼 증가함. 기울기 혹은 도함수에 a를 민 정도를 곱한 것임. 실제 도함수의 정의에서는 a를 0.001보다 훨씬 작은 무한소만큼 밀기 때문에, 실제로는 약간의 오차가 생길 수 있음. 만약 a를 무하소만큼 밀었다면 이 오차는 없어지고 f(a)가 증가하는 양은 정확히 도함수에 a를 오른쪽으로 민 만큼을 곱한 값과 같음.

f(a) = a^2 뿐만이 아니라 다른 함수들을 미분한 결과는 위 노트 같음.
도함수에 관해서 우리가 기억하고 가야할 것은 다음 두 가지임.
1. 함수의 도함수는 함수의 기울기를 의미할 뿐이고, 함수의 기울기는 함수의 위치에 따라 다른 값을 가질 수 있음
2. 함수의 도함수를 찾아야 할 때 다양한 미적분 관련 자료들을 통해 여러 위치에서의 기울기에 대한 공식을 찾을 수 있음
📌계산 그래프(C1W2L07)
핵심어: 계산 그래프(Computation Graph)
신경망의 계산은 정방향 패스 또는 정방향 전파(신경망의 출력값 계산)와 역방향 패스, 역방향 전파(경사나 도함수 계산)으로 나뉨. 계산 그래프를 보면 왜 이렇게 나누는지 확인할 수 있음.

계산 그래프에 대해 설명하기 위해, 로지스틱 회귀와 같이 완성된 신경망보다 더욱 간단한 형태의 신경망을 사용함.
함수 J(a, b, c)를 계산한다고 했을 때, 이 함수는 변수 세 개를 가지고 있으며 J=3(a+bc)임. 이 함수를 계산하는 데에는 서로 다른 세 단계의 과정이 필요함.
1. bc 계산. 이를 u라는 변수에 저장해 u=bc라고 함.
2. v=a+u라고 할 때 v를 계산. (v=a+bc)
3. 마지막으로 출력값 J=3v 계산
이것이 함수 J를 계산하는 과정이며, 이 세 단계를 계산 그래프로 나타낼 수 있음(오른쪽 그래프).
예를 들어 a가 5, b가 3, c가 2라고 하면 u=bc이므로 6, v=a+u이므로 11, H는 그 세 배인 33임.
실제로 3(5+3*2)를 계산하면 그 결과 33이 나옴.
계산 그래프는 J같은 특정한 출력값 변수를 최적화하고 싶을 때 유용함.
그리고 로지스틱 회귀의 경우에 J는 당연히 최적화할 비용 함수가 됨.
위 예제에서 확인할 수 있는 것은, 왼쪽에서 오른쪽으로의 패스(전파)로 J의 값을 계산할 수 있다는 사실임.
반면 도함수를 구하기 위해서는 J에서 시작하여 오른쪽에서 왼쪽으로 패스(전파)해야 함.
📌계산 그래프로 미분하기(C1W2L08)
핵심어: 계산 그래프(Computation Graph), 미분의 연쇄법칙(Chain Rule)
앞서 본 예시에서는 J 함수를 이용해 계산그래프를 그리는 방법에 대해 알아보았는데, 이번에는 어떻게 이 계산 그래프를 이용하여 함수 J의 도함수를 계산하는지 알아볼 것.

위 계산 그래프를 통해 v에 대한 J의 도함수(v의 값을 아주 조금 바꿨을 때 J의 값이 어떻게 바뀌는지)를 계산할 것.
J=3v라고 정의되어 있는데, J의 증가량이 v의 증가량의 세 배이기 때문 v에 대한 J의 도함수는 3임.
이 마지막 출력값 변수의 v에 대한 도함수를 얻으면, 역전파의 한 단계를 끝낸 것임. 즉 그래프에서 한 단계 뒤로 갔다고 할 수 있음.
다음으로 dJ/da 값, 다시 말해 a의 값을 증가시켰을 때 J의 값에 얼만큼 영향을 주는지 그 값을 계산해야 함.
a가 0.001만큼 증가할 때 v, 즉 a+u는 11.001로 0.001만큼 증가하고, 이에 따라 J는 33.003, 즉 세 배가 됨.
J의 증가량은 a의 증가량보다 세 배 많고, 이는 도함수가 3이라는 뜻임.
또 다른 관점에서 생각해보자면, a가 조금 증가했다고 했을 때 v는 dv/da에 의한 양만큼 증가하며 v의 변화는 J를 증가시킴. 미적분에는 연쇄법칙이 있는데, 만약 a가 v에 영향을 끼치고 그것이 J에 영향을 끼친다면
a를 변화시켰을 때의 v의 변화량과 v를 변화시켰을 때 J의 변화량의 곱이 됨.
미적분에서는 이를 연쇄법칙이라고 하며, 이 계산으로 알 수 있는 것은 a를 0.001만큼 바꾸면 v는 같은 양으로 바뀐다는 것임. 따라서 dv/da는 1임.
전에 계산했던대로 dJ/dv=3이고 dv/da=1이므로 곱해보면 dJ/da의 값은 3이 됨.
여기서 알 수 있는 것은, 이 변수에 대한 도함수인 dJ/dv를 계산하는 것이 dJ/da를 계산하는 데 도움을 줄 수 있다는 것임.
이것이 역방향 계산의 여러 단계 중 하나라고 할 수 있음.
표기법 하나를 더 알아보자면, 역방향 전파를 구현하는 코드를 작성할 때 보통 구하고자 하는 최종 출력값이 있을텐데, 아마 최적화 하려는 값일 것임(위 예시에서 최종 출력값은 계산 그래프의 마지막 노드 J).
많은 계산을 통해 최종 출력값의 도함수를 계산하게 됨. 이것을 var라는 변수에 대한 도함수(d최종 출력값/dvar)라고 했을 때, 계산의 많은 부분이 a, b, c, u, v 등 여러 중간 변수를 포함하는 최종 출력값 J의 도함수를 구하는데 사용됨. 이를 소프트웨어에서 구현할 때, 변수의 이름은 새로운 표기법을 사용하여 코드에서 이를 계산할 때 dvar라고만 이름 붙일 수 있음.
코드에서 dvar가 구하고자 하는 최종 출력값 변수 J나 혹은 손실 함수 L같은 변수의 여러 중간 값에 대해 계산한 도함수를 의미하게 되는 것임.

지금까지 dJ/dv에 대해 알아보았다면 이제는 dJ/du에 대해 알아볼 것.
전에 했던 것처럼 u를 6에서 시작해 6.001로 증가시키면 v는 11에서 11.001로 증가함. 그러면 J는 33에서 33.003으로 증가하므로, J는 세 배 증가함. u의 경우도 a의 경우와 거의 똑같이 (dJ/dv)(dv/du)임(아까 계산했듯 이 결과는 3).
역방향 전파에서 한 단계 더 나아가니 du도 3이었다는 것을 계산할 수 있음(du는 dJ/du를 의미).
마지막 예제 dJ/db를 살펴보면, 여기서는 b 값을 바꿔서 J의 값을 최소화하거나 최대화하려고 할 수 있음. b의 값을 조금 바꿨을 때의 함수 J의 기울기 도함수를 계산할 때, 미적분에서의 연쇄법칙을 사용하면 두 값의 곱(dJ/du x du/db)으로 나타낼 수 있음. 그 이유는 b를 조금만 바꿔 3에서 3.001이 되었을 때, J에 그 영향이 닿으려면 u를 통과해야 하는데 u=bc이므로 b가 3일 때 6이었다가 c가 2(주어진 값)이니까 6.002로 증가함. 따라서 du/db = 2임을 알 수 있음(b가 0.001 증가하면 u는 그 2배 증가). 이제 u는 b의 증가량의 두 배 증가한다는 것을 알게 되었는데, dJ/du는 3이므로 dJ/du x du/db의 값은 6임을 알 수 있음.
u가 0.002 증가하면, dJ/du=3이기 때문에 J는 그 세 배인 0.006만큼 증가해야 함. 실제 계산을 하면 b가 3.001이 되었을 때 u는 6.002가 되고 v는 11.002가 되는데, J=3v이므로 J=33.006이 됨. 그러므로 dJ/db=6임.
그래프에 표시를 해보면 역방향으로 와서 db=6이 됨(db는 dJ/db의 파이썬 코드 변수 이름).
우리가 여기서 얻어가야 할 사실은, 이 모든 도함수를 계산할 때 가장 효율적인 방법으로 하려면 빨간 화살표 방향처럼 오른쪽에서 왼쪽으로 계산한다는 것임. 이 경우 먼저 v에 대한 도함수를 구했고, 구한 값을 사용해 a에 대한 도함수와 u에 대한 도함수를 구함. 이 u에 대한 도함수는 b에 대한 도함수와 c에 대한 도함수를 구하는데 사용됨.
지금까지 계산 그래프를 보면, 왼쪽에서 오른쪽으로 가는 정방향 계산으로 최적화하고자 하는 J같은 비용 함수를 계산할 수 있는 반면, 오른쪽에서 왼쪽으로 가는 역방향 계산으로 도함수를 계산할 수 있음.
📌로지스틱 회귀의 경사하강법(C1W2L09)
핵심어: 계산 그래프(Computation Graph), 로지스틱 회귀(Logistic Regression), 경사 하강법(Gradient Descent)
이번에는 로지스틱 회귀의 경사 하강법을 구현하는 데 필요한 도함수를 구하는 방법을 살펴볼 것이며, 여기서 알고 가야 할 것은 로지스틱 회귀의 경사 하강법을 위해 필요한 핵심 공식을 구현하는 방법이고 이는 계산 그래프를 통해 수행할 수 있음. 계산 그래프를 로지스틱 회귀의 경사 하강법에 사용하는 것은 조금 과한 면이 있지만, 나중에 완전한 신경망을 다룰 때 더 잘 이해될 수 있을것.

로지스틱 회귀의 내용을 되짚어보면,y의 예측값은 y hat으로 정의하고 그 안에 z의 정의는 <w의 전치 x x^(i) + b>와 같음. 한 손실 함수의 예시를 들자면 <L(a,y)=−(ylog(a)+(1−y)log(1−a))> 라고 할 수 있으며 여기서 a는 로지스틱 회귀의 출력값이고 y는 참값 레이블임.
이를 특성이 x_1, x_2로 두 개인 계산 그래프로 나타냈을 때, z를 계산하려면 특성값 x_1과 x_2를 포함해 w_1, w_2, b도 필요함. 계산 그래프에서는 이 모든 것들이 z를 계산하는 데 필요하며, z=w_1x_1 + w_2x_2 + b로 정의함.
그 다음으로 y의 예측값=a=σ(z)를 계산하고, 마지막으로 L(a,y)를 계산함. 로지스틱 회귀에서의 최종 목적은 매개변수 w와 b를 변경해서 이 손실을 줄이는 것임.

반대 방향에서 도함수의 계산에 대해 이야기 해보면, 우선 역방향으로 가서 a에 대한 손실 함수의 도함수를 계산함. 코드에서는 이 변수를 da라고 나타내며 실제로는 dL(a,y)/da라고 세움. 미적분에 대한 지식을 이용하여 이를 계산하면 -(y/a)+((1-y)/(1-a))와 같은 결과가 나옴.
a에 대한 최종 출력값의 도함수인 da를 계산했으니 이제 역방향으로 더 갈 수 있음. 계산해보면 파이썬 코드 변수 이름 dz(z에 대한 손실함수의 도함수, L을 a와 y에 대한 손실 함수라고 직접 써도 좋음)는 a-y라고 나타낼 수 있음.
dL/dz는 (dL/da)(da/dz)라고 나타낼 수 있는데, 계산해 보면 da/dz는 a(1-a)이고 dL/da는 방금 -(y/a)+((1-y)/(1-a))이라고 결과가 나옴. 그래서 dL/da인 항과 da/dz인 항을 서로 곱하면, 식을 a-y로 간단히 할 수 있음.
앞서 설명했던 연쇄법칙을 사용해 이렇게 도함수를 구해주었음. 중요한 것은 dL/dz = a-y라는 사실임.
역방향 전파의 마지막 단계는 w와 b를 얼마나 바꾸어야 하는지 계산하는 것임. 예를 들어 w_1에 대한 도함수(코드에서는 dw1으로 나타냄)는 x_1 x dz와 같으며, w_2의 변화량을 나타내는 dw_2는 x_2 x dz와 같음. 그리고 db=dz임.
단일 샘플에 대해서만 경사 하강법을 사용한다면 이렇게 dz를 계산하고, 이 식들로 d_1, dw_2, db를 계산한 후
w_1 := w_1 - (학습률 α)dw_1로 갱신할 수 있음(w_2는 똑같이 할 수 있으며, b := b-(학습률 α)db임).
이것은 단일 샘플에 대한 경사 하강법의 한 단계임.
도함수를 계산하고 단일 샘플에 대한 로지스틱 회귀의 경사 하강법을 구현하는 방법을 알아보았는데, 로지스틱 회귀 모델을 훈련시키려면 단일 샘플이 아니라 m개의 훈련 샘플을 가진 훈련 세트 전체를 훈련해야 함.
📌m개 샘플의 경사하강법(C1W2L10)
핵심어: 경사 하강법(Gradient Descent)
앞선 내용에서는 도함수를 계산하여 이를 단일 샘플에 대한 로지스틱 회귀의 경사 하강법을 구현했음. 이제는 이를 m개의 훈련 샘플에 대해서 해 보려고 함. 그 시작으로 비용 함수 J의 정의를 다시 볼 필요가 있음.

w, b에 대한 비용 함수는 위 식과 같이 세울 수 있음. 여기서 a^(i)는 i번째 샘플의 예측값을 나타내고 σ(z^(i))와 같으며 이는 다시 σ(w^T x x^(i)+ b)와 같음.
식 안에 1/m이 있으므로, 비용함수는 각 손실의 평균이라고 할 수 있음. 그래서 계산해 보면 w_1에 대한 전체 비용 함수의 도함수도 w_1에 대한 각 손실 항 도함수의 평균임. 그리고 이 항을 계산하는 방법에 대해 지난 단일 샘플에 대해 dw_1^(i)를 계산하며 이미 살펴보았었음. 그래서 지난 예제에서처럼 단일 훈련 샘플의 도함수를 구해 그 평균을 구하면 경사 하강법에 사용할 전체적인 경사를 구할 수 있음.

경사 하강법을 사용한 로지스틱 회귀를 구현하는 방법을 알고리즘으로 표현한 것.
J=0, dw_1=0, dw_2=0, db=0이라고 초기화하고 훈련 세트를 반복해 각 훈련 샘플에 대한 도함수를 계산하고 이를 더함.
i=1에서 훈련 샘플의 개수 m까지인 for 문에서 z^(i) = w^T x x(i) + b와 예측값 a^(i) = σ(z^(i))를 계산하고 J에 더해줌.
J += -[y^(i) loga^(i) + (1-y^(i)) log(1-a^(i))]
그리고 전에 보았듯이 dz^(i) = a(i) - y^(i)이고 dw_1 += x_1^(i) dz^(i), dw_2 += x_2^(i) dz^(i)임.
지금 계산은 특성이 두 개, 즉 n=2라고 가정하고 한 것임. n이 더 컸다면 dw_1, dw_2, dw_3 등으로 더 계산했어야 함.
for문은 이렇게 끝이 나고, 평균을 계산하는 것이기 때문에 m으로 나누어야 함.
dw_1 /= m; dw_2 /= m ; db /= m으로 평균을 계산함.
이렇게 각 매개변수 w_1, w_2, b에 대한 비용 함수 J의 도함수를 계산하였는데, 몇 가지 짚고 넘어가자면 dw_1, dw_2, db는 값을 저장하는 데 쓰고 있음. 따라서 계산을 다 하고 나면, dw_1은 w에 대한 전체 비용 함수의 도함수와 같음. dw_2와 db의 경우도 마찬가지임.
dw_1과 dw_2는 첨자 i가 없는데, 훈련 세트 전체를 합한 값을 저장하고 있기 때문임. 비교해보면 dz^(i)는 훈련 샘플 하나의 dz라서 계산하고 있는 훈련 샘플 하나를 나타내기 위해 첨자를 사용함.
모든 계산을 끝냈고, 경사 하강법의 한 단계를 구현하려면
w_1 := w_1 - (학습률 α) dw_1
w_2 := w_2 - (학습률 α) dw_2
b := b - α db라고 구현하면 됨.
여기서 dw_1, dw_2, db는 방금 계산한 값을 사용. 그리고 여기 J도 정확한 비용 함수의 값임.
해당 노트에 있는 내용은 모두 경사 하강법 한 단계에 사용되는 것인데, 경사 하강법을 여러 번 진행하려면 이것을 계속 반복해야 함.
이러한 방식으로 구현한 계산 방식에는 두 가지 약점이 있는데, 우선 이렇게 로지스틱 회귀를 구현하려면 for 문을 2개 만들어야 한다는 것임. 첫 번째 for 문은 m개의 훈련 샘플을 반복하고 두 번째 for문은 이것처럼 특성을 반복함. 여기는 n=2로 특성이 2개 뿐이지만 특성이 더 많다면 dw_1, dw_2도 있고 dw_3도 같은 방식으로 계산하여 dw_n까지 있을 것이기 때문에, n개의 특성을 반복하는 for문이 필요함. 딥러닝 알고리즘을 구현할 때, 코드에서 이런 명시적인 for문은 알고리즘을 비효율적으로 만듦. 딥러닝의 전성기로 접어들면서 데이터 집합이 점점 더 커졌기 때문에, 코드를 명시적인 for문 없이 구현하는 것이 중요해졌으며 그렇게 해야 더 큰 데이터 집합도 처리할 수 있음.
이를 가능하도록 하는 방법들 중 벡터화라는 것이 있는데, 이는 명시적인 for문을 제거할 수 있도록 해줌. 딥러닝이 뜨기 전에는 벡터화는 속도 향상을 위해 가끔 쓸 때도 있고 안 쓸 때도 있는 있으나마나 한 존재였는데, 딥러닝의 시대에 들어와서는 이런 for문을 없애주는 벡터화가 아주 중요해짐. 아주 큰 데이터 집합을 사용하기 때문에 그 만큼 효율적인 코드를 작성해야 하는 것.
'Project > DL 스터디&프로젝트' 카테고리의 다른 글
| [Euron 중급 세션 5주차] 딥러닝 2단계 1. 머신러닝 어플리케이션 설정하기 (0) | 2023.10.09 |
|---|---|
| [Euron 중급 세션 4주차] 5. 심층 신경망 네트워크 (1) | 2023.10.02 |
| [Euron 중급 세션 3주차] 4. 얕은 신경망 네트워크 (0) | 2023.09.25 |
| [Euron 중급 세션 2주차] 3. 파이썬과 벡터화 (0) | 2023.09.18 |
| [Euron 중급 세션 1주차] 1. 딥러닝 소개 (0) | 2023.09.11 |