본문 바로가기
IT Expertise/Deep Learning

[Coursera] 2 신경망과 로지스틱 회귀 | Andrew Ng (한국어 자막 스크립트)

by 2den 2025. 3. 22.
728x90

Youtube Link

01 이진 분류 https://www.youtube.com/watch?v=eqEc66RFY0I

02 로지스틱 회귀 https://www.youtube.com/watch?v=hjrYrynGWGA

03 로지스틱 회귀의 비용함수 https://www.youtube.com/watch?v=SHEPb1JHw5o

04 경사하강법 https://www.youtube.com/watch?v=uJryes5Vk1o

05 미분 https://www.youtube.com/watch?v=GzphoJOVEcE

06 더 많은 미분 예제 https://www.youtube.com/watch?v=5H7M5Vd3-pk

07 계산 그래프 https://www.youtube.com/watch?v=hCP1vGoCdYU

08 계산 그래프로 미분하기 https://www.youtube.com/watch?v=nJyUyKN-XBQ

09 로지스틱 회귀의 경사하강법 https://www.youtube.com/watch?v=z_xiwjEdAC4

10 m개 샘플의 경사하강법 https://www.youtube.com/watch?v=KKfZLXcF-aE

 


한국어 자막

 

01 이진 분류

 

돌아온 것을 환영합니다. 이번 주에는 신경망 프로그래밍의 기초를 살펴보겠습니다. 신경망을 구현할 때에 정말 중요한 몇몇 구현 기법들이 있습니다. 예를 들면 m 개의 훈련 샘플의 훈련 세트가 있을 때 훈련 세트을 처리하는 익숙한 방법은 아마 for 문을 이용해 m 개의 데이터를 일일이 보는 것입니다. 사실은 훈련 세트를 처리할 때 보통 for 문을 굳이 사용하지 않고 처리하길 원할 것입니다 어떻게 하는지는 이번 주 수업을 통해 배우겠습니다. 하나 더 예를 들면 보통 신경망의 계산 과정을 살펴볼 때 정방향 패스 또는 정방향 전파라는 단계 뒤에 역방향 패스 또는 역방향 전파라는 단계가 있습니다. 그래서 이번 주 수업을 통해 신경망을 학습하는 계산 과정이 왜 정방향 전파와 역방향 전파로 구성되어 있는지에 대한 직관 또한 얻을 것입니다. 이번 주에는 이런 원리들을 더 쉽게 이해할 수 있도록  로지스틱 회귀를 이용하겠습니다. 로지스틱 회귀를 전에 보았더라도 이번 수업을 통해 얻는 게 있을 거로 생각합니다.

자 이제 시작해 봅시다.

로지스틱 회귀이진 분류를 위한 알고리즘입니다. 먼저 문제를 설정해 봅시다. 이진 분류 문제의 예 하나를 한 번 살펴봅시다. 이러한 사진이 입력으로 주어졌을 때 두 범주 중 어떻게 분류했는지 출력하기를 원합니다. 고양이 사진으로 알아보았을 때 1을 출력하고 고양이 사진이 아니라고 판단하면 0을 출력하고 싶습니다. 이때 y로 출력 레이블을 표시하겠습니다.

 

이제 사진이 어떻게 컴퓨터에 저장되는지 알아봅시다. 이 사진의 빨간 초록 파란색 채널들과 일치하는 세 개의 행렬을 따로따로 저장합니다. 그러므로 입력된 사진이 64 x 64픽셀이라면 세 개의 64 x 64 행렬들이 사진의 빨간 초록 파란색 픽셀 강도 값을 나타냅니다. 하지만 보여주기 위해서 여기에는 훨씬 작은 행렬들로 그렸습니다. 64 x 64 대신 5 x 4 행렬들로 나타냈습니다.

 

이 픽셀 강도 값들을 특성 벡터로 바꾸려면 모든 픽셀값을 입력될 특성 벡터 x의 한 열로 나열할 겁니다. 픽셀값을 하나의 벡터로 펼치기 위해서 주어진 사진에 대한 특성 벡터 x를 다음과 같이 정의하겠습니다. 픽셀값 전부를 차례대로 255 231 등등 모든 빨간색 픽셀들을 나열하고, 뒤이어 255 134 등등 매우 긴 특성 벡터가 되도록 이 사진의 모든 빨간 초록 파란색 픽셀 강도 값들을 나열합니다. 그러므로 이 사진이 64 x 64일 경우 벡터 x의 전체 차원은 64 x 64 x 3가 됩니다. 왜냐하면 이 행렬들의 원소들을 포함하고 있기 때문입니다. 이 경우에는 12,288입니다. 곱해서 나온 수이죠. 12,288인 입력 특성 벡터 x의 차원을 n_x로 표현할 것이고, 때로는 간결함을 위해서 소문자 n을 쓰겠습니다.

 

이진 분류의 목표는 입력된 사진을 나타내는 특성 벡터 x를 가지고 그에 대한 레이블 y가 1 아니면 0, 다시 말해 고양이 사진인지 아닌지를 예측할 수 있는 분류기를 학습하는 것입니다. 이제 지금부터 자주 쓸 표기법을 소개하겠습니다. 단 하나의 훈련 샘플을 한 쌍 (x, y)로 표시할 때, x는 n_x 차원 상의 특성 벡터이고, 레이블 y는 0 또는 1입니다. 훈련 세트는 m개의 훈련 샘플을 포함하고 다음과 같이 표기될 것입니다. 첫 번째 훈련 샘플의 입력과 출력인 (x^(1), y^(1)), 두 번째 훈련 샘플인 (x^(2), y^(2)) 부터, 마지막 훈련 샘플인 (x^(m), y^(m)) 까지 다 합한 것이 훈련 세트가 됩니다. 훈련 샘플의 개수를 m으로 표시할 것입니다. 때때로 무엇을 의미하는지 강조하기 위해 m_train이라 쓸 수 있고, 테스트 세트에 대해서는 테스트 세트의 개수를 m_test로 표시할 것입니다.

마지막으로 모든 훈련 샘플들을 더 간결하게 표기하기 위해 행렬 X를 다음과 같이 정의하겠습니다. X의 열들을 입력된 훈련 세트 x^(1) x^(2)등등으로 이루어져 있습니다. x^(1)은 이 행렬의 첫 열로 놓고, x^(2)는 두 번째 열로, x^(m)까지 m 번째 열로 놓으면 행렬 X가 완성됩니다. 그러므로 m이 훈련 샘플의 개수일때 X는 m개의 열과 n_x개의 행들로 이루어져 있습니다. 다른 강좌에서는 X가 다르게 정의되었을 수도 있습니다. 훈련 세트들을 X의 열 대신 행들로 놓는 것입니다. x^(1)의 전치부터 x^(m)의 전치까지 말입니다. 하지만 알고 보면 신경망을 구현할때 왼쪽의 방법으로 구현하기가 훨씬 쉽습니다. 요약하자면, X는 n_x × m 행렬이고, 파이썬으로 구현한다면 파이썬 명령인 X.shape로 행렬의 차원을 알 수 있습니다. 이 경우에는 (n_x, m)을 출력하게 되고, n_x × m 행렬인 것을 뜻합니다. 이렇게 훈련 샘플들 x를 행렬로 묶을 수 있습니다.

출력될 레이블 Y는 어떨까요? 신경망의 구현을 더 쉽게하기 위해 y의 값들을 열로 놓는 것이 편리합니다. 그러므로 Y는 y^(1), y^(2)부터 y^(m)으로 이루어진 1 x m 행렬으로 정의하겠습니다. 다시 한번 파이썬 문법을 사용해 Y.shape를 이용하면 Y의 차원이 (1, m)임을 알 수 있습니다.

 

나중에 신경망을 구현할 때 여기서 X랑 Y를 정의한 것처럼 x나 y, 또는 나중에 볼 여러 훈련 샘플에 관한 데이터를 각각의 열로 놓는 것이 유용할 것입니다. 이 표기법들이 로지스틱 회귀와 나중에 볼 신경망들을 위한 것입니다. 혹시 m이나 n이 뭔지 또는 다른 표기법을 까먹었다면 손쉽게 찾을 수 있도록 표기법 가이드를 올려놨으니 참고하여 주시길 바랍니다.

 

다음에는 이 표기법을 이용해 로지스틱 회귀를 더 살펴보겠습니다.


 

02 로지스틱 회귀

 

이번 주에 배울 것은 바로 로지스틱 회귀입니다. 이 학습 알고리즘은 지도 학습 문제에서 출력될 레이블 y가 0이나 1일 경우, 다시 말해 이진 분류 문제들에서 쓰입니다. 입력될 특성 벡터 x가 있다고 해봅시다. 예를 들어 고양이 사진인지 아닌지 구분하고 싶은 사진이 주어졌을 때 y의 예측값을 출력하는 알고리즘을 원합니다. 더 자세히는 y의 예측값은 입력 특성 x가 주어졌을 때 y가 1일 확률을 뜻합니다. 다른 말로 x가 지난 시간에 본 사진이라면 y의 예측값은 이 사진이 고양이 사진일 확률을 알려줍니다. 전에 말한 대로 x는 n_x 차원 상의 벡터이고, 로지스틱 회귀의 파라미터 w와 b는 각각 n_x 차원 상의 벡터와 실수입니다.

 

입력 x와 파라미터 w와 b가 주어졌을 때 어떻게 y의 예측값을 출력할 수 있을까요? 시도할 순 있지만 잘 안되는 방법은 y의 예측값을 (w의 전치) × x + b로 놓는 것입니다. 입력 x에 대한 선형 함수처럼 말입니다. 사실 선형 회귀를 하는 거였다면 이러한 함수를 쓸 것입니다. 하지만 이진 분류를 위한 좋은 알고리즘이 아닙니다. 왜냐하면 y의 예측값은 y가 1일 확률이기 때문에 항상 0과 1사이어야 하기 때문입니다. 이 경우에는 그럴 일이 별로 없습니다. 왜냐하면 (w의 전치) × x + b는 1보다 훨씬 크거나 음수일 수도 있어서 0과 1 사이어야 하는 확률의 값으로 말이 안됩니다.

 

대신에 로지스틱 회귀에서는 y의 예측값이 시그모이드 함수를 적용하여 출력된 값입니다. 시그모이드 함수는 이렇게 생겼습니다. 수평축이 z일 때 z의 시그모이드는 0부터 1까지 매끈하게 올라갑니다. 축들을 표시해보면 여기는 0 그리고 수직축을 0.5에서 교차합니다. z의 시그모이드는 이러한 모양을 가지고 있고, 여기서 z는 (w의 전치) × x + b의 값을 의미합니다. 시그모이드 함수의 공식은 이렇습니다. z가 실수일 때 z의 시그모이드는 1 ÷ (1 + e^(-z)) 입니다. 여기서 몇 가지 주목할 게 있어요. 만약에 z가 아주 크다면 e^(-z)가 0으로 수렴합니다. 이러므로 z의 시그모이드는 대략 1과 0에 가까운 숫자의 합을 1에서 나누었기 때문에 1에 가깝습니다. 왼쪽에 있는 그래프를 통해 쉽게 확인할 수 있습니다. z가 아주 크면 z의 시그모이드가 1에 수렴합니다. 반대로 z가 아주 작거나 아주 큰 음수일 경우에는, 그러면 z의 시그모이드는 1 ÷ (1 + e^(-z))이고 e^(-z)가 아주 큰 수가 됩니다. 그래서 1과 엄청 큰 수의 합을 1에서 나누었기 때문에 크기가 거의 0과 같습니다. 보시다시피 z가 큰 음수일수록 z의 시그모이드도 0에 수렴합니다. 그러므로 로지스틱 회귀를 구현할 때 y가 1일 확률을 잘 예측하도록 파라미터 w와 b를 학습해야 합니다. 표기법에 대해 하나 덧붙이자면 우리가 신경망을 구현할 때는 보통 파라미터 w와 파라미터 b를 분리할 것입니다. 여기서 b는 인터셉트 항을 뜻합니다.

다른 수업들에서는 또 다른 표기법을 봤을 수도 있습니다. 어떤 경우에는 값이 1인 새로운 특성 x_0을 정의해서 x가 n_{x+1} 상의 차원의 벡터이고 y의 예측값은 (θ의 전치) × x의 시그모이드로 지정합니다. 이러한 표기법으로는 벡터 θ가  θ_0, θ_1, θ_2부터 θ_{n_x}까지 이루어져있고 θ_0은 b의 역할을 하는 실수이고, θ_1부터 θ_{n_x}까지는 w의 역할을 합니다. 신경망을 구현할 때 b와 w를 분리하면 더 쉬우므로 빨간색으로 쓴 표기법은 이 수업에서 쓰지 않을 겁니다. 전에 본 적이 없다면 걱정하지 마세요. 이런 표기법을 본 사람들만을 위해 이 수업에 쓰지 않겠다고 말하고 싶었습니다. 전에 보지 않았다면 중요하지 않고 걱정할 필요가 없습니다.

이제 로지스틱 회귀 모델이 어떤지 살펴봤으니 이제 파라미터 w와 b를 학습하기 위해 비용 함수를 정의해야 합니다. 다음 비디오에서 해봅시다.

 

 

 

03 로지스틱 회귀의 비용함수

 

저번 강의에서 로지스틱 회귀 모델에 대해 알아봤습니다. 매개 변수들 w와 b를 학습하려면 비용함수를 정의해야 합니다. 로지스틱 회귀를 학습할 수 있는 비용 함수에 대해 알아봅시다.

 

지난번에 정의한 것을 요약하자면 y의 예측값은 (w의 전치) × x + b의 시그모이드이며 이때 시그모이드 함수 σ(z)는 상단 가운데 수식처럼 정의됩니다. 로지스틱 회귀 모델의 매개 변수들 w와 b를 주어진 m개의 훈련 샘플로 학습할 때 당연히 훈련 세트를 바탕으로 출력한 y^(i)의 예측값이 훈련 세트에 포함된 참값 y^(i)에 가까워지도록 하고 싶을 것입니다.

 

맨 위의 공식을 더 설명하자면 이 공식은 훈련 샘플 x가 주어졌을 때 y의 예측값을 정의하며 각각의 훈련 샘플은 괄호로 감싸진 위첨자를 사용해 순서가 표시됩니다. i번째 훈련 샘플의 y의 예측값은 (w의 전치) × x^(i) + b에 시그모이드 함수를 적용해 구할 수 있습니다. 또한 여기서 z^(i)를 (w의 전치) × x^(i) + b의 시그모이드로 정의할 수 있습니다. 앞으로도 이 강의에서는 i가 괄호 안에 위첨자로 있으면 그것이 x이든 y이든 z이든 i번째 훈련 샘플에 관한 데이터임을 뜻하는 표기법으로서 쓰겠습니다.

 

이제 위첨자 (i)의 뜻을 알았으니 알고리즘이 얼마나 잘 가동되는지를 측정할 수 있는 손실 함수 또는 오차 함수에 대해 알아봅시다. 한 가지 할 수 있는 것은 알고리즘이 출력한 y의 예측값과 참 값 y의 제곱 오차의 반으로 손실 함수를 정의할 수 있습니다. 이런 방식을 쓸 수 있지만 로지스틱 회귀에서는 주로 사용하지 않습니다. 이는 매개 변수들을 학습하기 위해 풀어야할 최적화 함수가 볼록하지 않기 때문입니다. 그러므로 여러 개의 지역 최적값을 가지고 있게 되어 문제가 생깁니다. 이럴 경우 경사하강법이 전역 최적값을 못 찾을 수도 있습니다. 방금 말한 것들을 이해하지 못했다면 나중에 설명할 테니 걱정하지 마세요. 여기서 얻어갈 점은 L이란 함수는 손실 함수이고 출력된 y의 예측값과 참값 y 사이에 오차가 얼마나 큰지 측정합니다. 제곱 오차가 합리적인 선택으로 보일 수 있지만 로지스틱 회귀에서는 경사하강법을 적용하지 못하게 만듭니다. 그러므로 제곱 오차와 비슷한 역할을 하지만 최적화 문제가 볼록해지는 또 다른 손실 함수를 정의할 것입니다. 이러하면 최적화하기 더 쉬워집니다.

로지스틱 회귀에서는 이러한 손실 함수를 대신 씁니다. −(y × log (y의 예측값) + (1−y) × log(1−y의 예측값)) 이런 손실 함수를 왜 쓰는지에 대한 직관적인 이유를 드리자면 우리가 만약 제곱 오차를 쓴다 하면 그 오차를 최소화하려 할 것입니다. 똑같이 이 로지스틱 회귀 손실 함수를 사용할 때 이 값을 최소화해야 합니다.

 

왜 이런 함수를 쓰는지 알아보기 위해 두 가지 경우를 살펴보겠습니다. 첫번째 경우로 y가 1일 경우 손실 함수 L(y의 예측값, y)는 그냥 −log(y의 예측값)이 됩니다. 이는 y가 1이기 때문에 두 번째 항 (1−y)가 0이 되기 때문입니다. 그렇다면 y가 1일 경우 −log(y의 예측값)이 최대한 커지기를 원할 것입니다. 그러려면 log(y의 예측값)이 최대한 커져야 할 것이며 따라서 y의 예측값이 최대한 커야 합니다. 하지만 y의 예측값은 시그모이드 함수 값이기 때문에 1보다 클 수 없습니다. 그러므로 y가 1일 경우 y의 예측값이 1보다 클 순 없으므로 1에 수렴하길 원한다는 뜻입니다.

 

다른 경우는 y가 0일 경우입니다. y가 0일 때 손실 함수의 첫 항이 0이 됩니다. 그러면 두 번째 항이 남고 손실 함수는 −log(1−y의 예측값)이 됩니다. 따라서 학습 중에 손실 함숫값을 줄이고 싶다면 마이너스 부호가 붙어있기 때문에 log(1−y의 예측값)이 최대한 커야 합니다. 따라서 아까와 비슷한 논리로 y의 예측값이 최대한 작아야 한다는 것을 알 수 있습니다. y의 예측값은 0과 1사이어야 하므로 y가 0이면 손실 함수는 y의 예측값이 0에 수렴하도록 매개 변수들을 조정할 것입니다.

 

y가 1일 때 y의 예측값이 크고 y가 0일 때 y의 예측값이 작은 성질을 가지고 있는 함수들은 많습니다. 여기 초록색으로 적은 것은 이 손실 함수에 대한 비공식적인 검증이고, 왜 로지스틱 회귀에서 이러한 형태의 손실 함수를 사용하는지에 대한 더 공식적인 증명은 나중에 관련된 강의를 올릴 테니 참고하시면 됩니다.

 

마지막으로 손실 함수는 훈련 샘플 하나에 관하여 정의돼서 그 하나가 얼마나 잘 예측 되었는지 측정해줍니다. 이제 비용 함수가 무엇인지 소개해 드리자면 훈련 세트 전체에 대해 얼마나 잘 추측되었는지 측정해주는 함수입니다. 비용 함수 J는 매개 변수 w와 b에 대해 손실 함수를 각각의 훈련 샘플에 적용한 값의 합들의 평균 즉 m으로 나눈 값입니다. 여기서 y의 예측값은 로지스틱 회귀 알고리즘이 정해진 매개 변수들 w와 b를 적용해서 출력하는 값이고 위의 손실 함수의 정의를 이용해 이것을 풀어쓰자면 비용 함수는 −(1 ÷ m)를 [(y^(i)×log(y^(i)의 예측값)+(1−y^(i))×log(1−y^(i)의 예측값)]을 i=1부터 i=m까지의 합에 곱한 값과 같습니다. y에 관한 항을 전부 대괄호로 닫아 놓았기 때문에 마이너스 부호를 바깥으로 뺄 수 있습니다. 요점은 손실 함수가 하나의 훈련 샘플에 적용이 된다는 것이고, 비용 함수는 매개 변수의 비용처럼 작용한다는 것입니다. 결과적으로 로지스틱 회귀 모델을 학습하는 것이란, 손실 함수 J를 최소화해주는 매개 변수들 w와 b를 찾는 것입니다.

이렇게 로지스틱 회귀 알고리즘의 큰 틀을 살펴보았습니다. 훈련 샘플에 대한 손실 함수와 알고리즘의 매개 변수들에 대한 비용 함수를 말입니다. 흥미롭게도 로지스틱 회귀는 아주 작은 신경망과 같습니다. 다음 강의에선 이를 다뤄 여러분이 신경망에 대한 직관을 얻으실 수 있도록 하겠습니다. 로지스틱 회귀가 어떻게 작은 신경망과 같은지 다음 강의에서 함께 보도록 합시다.

 

 

 

04 경사하강법

 

로지스틱 회귀 모델과 단일 훈련 샘플이 얼마나 잘 작동하는지 측정하는 손실 함수, 그리고 매개변수 w, b가 훈련 세트 전체를 얼마나 잘 예측하는지 측정하는 비용 함수에 대해서 알아보았습니다. 그러면 이제 경사하강법 알고리즘을 사용해 매개변수 w와 b를 훈련 세트에 학습시키는 방법을 알아봅시다.

전에 배웠던 로지스틱 회귀 알고리즘입니다. 그리고 두 번째 줄에는 비용 함수 J가 있습니다. 매개변수 w와 b에 대한 함수이죠. 이는 평균으로 정의할 수 있으므로 1/m에 손실 함수의 합을 곱합니다. 그리고 손실 함수는 알고리즘이 각 훈련 샘플의 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의 최솟값에 해당하는 w와 b를 찾아야 합니다. 이 특정 비용 함수 J는 활처럼 볼록한 함수입니다. 볼록하지 않은 함수는 이런 함수로서 지역 최적값이 여러 개입니다. 이 비용 함수 J(w, b)가 볼록하다는 사실이 로지스틱 회귀에 위의 비용 함수 J를 사용한 큰 이유 중 하나입니다.

매개변수에 쓸 좋은 값을 찾기 위해서 w와 b를 어떤 초깃값으로 초기화해야 합니다. 이는 여기 빨간 점으로 나타내겠습니다. 로지스틱 회귀에는 거의 모든 초기화 방법을 사용할 수 있는데 보통 초깃값을 0으로 설정합니다. 무작위 초기화도 가능하지만 보통 로지스틱 회귀에는 사용하지 않습니다. 하지만 이 함수는 볼록하기 때문에 어디서 초기화를 해도 거의 같은 점에 도착하게 될 것입니다. 경사하강법에서는 이 초기점에서 시작해 가장 가파른 내리막 방향으로 한 단계 내려갑니다. 그러면 한 단계 후에 이쯤에 오게 될 것입니다. 가장 가파른 내리막, 가장 빨리 내려올 수 있는 방향을 택합니다. 경사하강법을 한 번 반복하면 이렇게 되고 두 번 반복하면 이렇게 세 번째는 이럴 것이고 그 다음엔 도표에 가리겠네요. 그러다가 언젠가 여기 있는 전역 최적값이나 그 근사치에 도달하게 될 것입니다.

경사하강법을 이런 그림으로 나타내 보았는데 좀 더 세부적인 것들을 적어보도록 하겠습니다. 예를 들어 이렇게 생긴 함수 J를 최소화한다고 해 봅시다. 그리기 쉽도록 잠깐 b를 제외해 높은 차원이 아니라 1차원으로 생각해 봅시다. 경사하강법은 이렇습니다. 계속해서 다음 갱신을 반복합니다. w의 값을 갱신합니다. :=는 값을 갱신한다는 뜻입니다. w를 w - α에, J(w)의 미분계수 dJ(w)/dw를 곱한 값으로 갱신하고 이를 알고리즘이 수렴할 때까지 반복합니다. 여기서 α는 학습률이고, 경사하강법을 반복할 때 한 단계의 크기를 결정합니다. 학습률 α를 고르는 방법은 나중에 알아보도록 하겠습니다. 그리고 이것은 미분계수입니다. 갱신할 때 매개변수 w에 줄 변화를 나타냅니다. 경사하강법을 구현하는 코드를 만들 때는 관습적으로 코드에 이 미분계수의 변수 이름을 dw라고 정합니다. 예를 들면 코딩을 할 때 w := w - α·dw라고 쓰는 것이죠. 이 미분계수 항의 변수 이름을 dw라고 하는 것입니다.

이 경사하강법이 잘 작동하는지 확인해 봅시다. w가 여기 있고 그에 따라 J(w)도 여기 있다고 해 봅시다. 미분계수는 이 점에서 함수의 기울기라고 정의할 수 있습니다. 기울기는 J(w)에 접선하는 삼각형의 세로/가로라고 할 수 있죠. 이 점의 미분계수는 양수입니다. w는 w - 학습률 x 미분계수로 갱신되는데 미분계수가 양수이므로 w에서 미분계수를 빼는 것이 되어서 왼쪽으로 한 단계 갑니다. 따라서 경사하강법은 큰 w에서 시작한 경우에 서서히 매개변수를 감소시킵니다. 반대로 w가 여기 있었다면 기울기 dJ(w)/dw는 음수가 되고, 따라서 경사하강법은 α에 음수를 곱한 값을 빼게 되므로 서서히 w를 증가시키게 됩니다. 각 반복마다 w가 점점 증가하는 것입니다. 그러면 왼쪽에서 초기화하든, 오른쪽에서 초기화하든 경사하강법은 매개변수를 전역 최솟값까지 도달하게 해 줍니다.

도함수에 대해서 잘 알지 못하고 dJ(w)/dw가 무슨 뜻인지 모른다면 다음 동영상에서 알아 볼테니 크게 걱정하지 않아도 됩니다. 이미 미적분에 대해 잘 알고 있다면 신경망이 어떻게 작동하는지 더 깊은 직관을 가질 수 있을 것이고, 미적분에 익숙하지 않더라도 추후 동영상에서 미적분과 도함수에 대해 충분한 직관을 얻어 이를 신경망에 효과적으로 적용할 수 있게 될 것입니다. 지금은 이 항이 함수의 기울기를 나타낸다고만 알면 됩니다. 그리고 현재 매개변수 위치에서 함수의 기울기를 찾아 가장 가파른 경사로 내려가는 각 단계에 적용함으로써 비용 함수 J에서 내려가는 방향을 찾을 수 있습니다.

여태까지 매개변수가 w만 있을 경우인 J(w)에 대한 경사하강법을 알아보았습니다. 로지스틱 회귀에서 비용 함수는 w와 b에 대한 함수이고, 그런 경우 여기 있는 경사하강법의 내부 반복문은 다음과 같이 바꿀 수 있습니다. w는 w - (학습률 α) x (w에 대한 J(w,b)의 미분계수), b는 b - (학습률 α) x (b에 대한 비용 함수의 미분계수)로 갱신합니다. 구현할 때 사용하게 될 식은 밑에 있는 두 식입니다.

 

잠시 미적분에서 사용하는 표기법 하나를 알아 봅시다. 헷갈려 하는 사람이 꽤 있을 것입니다. 미적분을 이해하는 것이 아주 중요하다고 생각하지는 않지만 이것을 보고 헷갈리는 일이 없었으면 합니다. 바로 이 항을 이렇게 휘어진 문자를 사용해 쓰는 것입니다. 이 휘어진 문자는 소문자 d를 다른 폰트로 쓴 것 뿐인데, 이것은 단순히 J(w,b)의 미분계수를 의미합니다. 그러니까 J(w,b)가 w 방향으로 얼마나 기울었는지를 나타냅니다. 미적분에서 이 표기는 완벽히 논리적이지도 않고 복잡하기만 한 것 같지만 J가 두 개 이상의 변수를 가진 함수일 때, J가 두 개 이상의 변수를 가진 함수일 때 d 대신 사용합니다. 이 기호는 편미분 기호라고 하는데 크게 신경 쓸 필요는 없습니다. 그리고 J가 변수가 하나인 함수라면 그냥 소문자 d를 사용합니다. 따라서 편미분 기호와 소문자 d의 차이는 J가 두 개 이상의 변수를 가진 함수이면 이 편미분 기호를 J가 하나의 변수를 가진 함수이면 소문자 d를 사용하는 것입니다. 이것은 미적분에서 사용하는 특이한 표기법 중 하나인데 제 생각에는 필요 이상으로 복잡해지기만 하는 것 같습니다. 어쨋든 편미분 기호를 보면 여러 변수 중 하나에 대한 함수의 기울기를 구하는 것이라고 알면 됩니다.  그래서 정확하게 미적분의 표기법을 따르려면 여기 밑에 있는 J의 변수는 두 개니까 편미분 기호를 사용해야 합니다. 그래도 의미는 소문자 d와 거의 똑같습니다.

 

마지막으로 코드 구현 시 관습적으로 w의 변화를 나타내는 이 값은 변수의 이름을 dw라 하고, 코드에서 b의 변화량을 나타내는 이 값은 변수의 이름을 db라 합니다.

 

좋습니다. 경사하강법은 이렇게 구현하는 것이고, 미적분을 공부한지 꽤 되었다면 감당할 수 있는 이상으로 미적분이 많이 나온다고 생각할 수 있는데, 그렇게 생각한다면 다음 동영상에서 미분에 대해 더 나은 직관을 얻을 수 있을 것입니다. 미적분에 대한 깊은 수학적 지식 없이 직관적으로 이해하는 것만으로도 신경망을 효율적으로 만들 수 있게 될 것입니다. 그러면 다음 동영상에서 미분에 대해 더 알아보겠습니다

 

 

05 미분

 

이 동영상에서는 미적분과 도함수에 대한 직관을 얻을 수 있도록 해 보겠습니다. 대학교 때 이후로 미적분을 본적이 없다면, 언제 졸업했는지에 따라 꽤 오래전이었을 수도 있겠지만, 그래도 걱정할 필요는 없습니다. 미적분에 대한 깊은 이해 없이도 딥러닝과 신경망을 효율적으로 만들 수 있습니다. 이 동영상이나 이후 동영상에서 나오는 미적분이 복잡해서 이 강좌를 듣는 것이 맞는 것인지 생각이 들 수도 있습니다. 제 생각에는 동영상을 보고 프로그래밍 숙제나 다른 숙제를 잘 완료할 수 있다면, 딥러닝도 할 수 있다고 생각합니다. 4주차에서는 몇 가지의 함수를 정의해 볼텐데 미적분에 필요한 모든 것을 그 안에 담을 수 있습니다. 이것을 정방향 함수와 역방향 함수라 하는데 미적분에 관한 것을 모두 이 함수에 담아 미적분에 그 이상으로 신경 쓸 필요가 없어집니다. 그래도 딥러닝에 대해 배우고 있으니 이번 주에는 상자를 열고 미적분에 대해서 좀 더 알아보고자 하는데 알고리즘을 만들 때는 직관적인 이해만 가지고 있어도 됩니다. 그리고 여러분이 미적분에 능숙한 몇 안되는 사람 중 한 명이라면 이 동영상을 건너 뛰어도 괜찮습니다.

나머지 분들은 이제 도함수에 대해 배워 봅시다.

함수 f(a) = 3a를 그려놓았습니다. 직선이죠. 도함수에 대한 이해를 돕기 위해 이 함수에 대하여 알아봅시다. a가 2라고 해 봅시다. 그러면 f(a) = 3a이니 f는 6입니다. a가 2일 때 f(a)는 6입니다. a의 값을 살짝 밀어서 이제 a가 2.001이라고 해 봅시다. 0.001의 차이는 그리기에 너무 작으니 그림의 비율은 신경쓰지 않겠습니다. a를 오른쪽으로 살짝 밀면 이제 f(a)는 세 배를 곱한 6.003입니다. 여기에 그려 줍니다. 실제 비율은 생각하지 마세요. 여기가 6.003입니다. 여기 초록색으로 된 부분을 보면 a를 오른쪽으로 0.001만큼 밀었을 때 f(a)는 0.003증가합니다. f가 올라간 정도는 a를 오른쪽으로 민 정도보다 세 배 많습니다. 그러면 a = 2에서 함수 f(a)의 기울기, 도함수는 3입니다. 그러면 a = 2에서 함수 f(a)의 기울기, 도함수는 3입니다. 도함수는 기울기라고 볼 수 있습니다. 도함수라고 하면 어렵게 들리는데 기울기는 도함수의 개념을 쉽게 말한 것입니다. 도함수라고 하면 함수의 기울기라고 생각하면 됩니다. 기울기를 좀 더 정확히 정의하면 이 작은 삼각형의 높이를 밑변으로 나눈 값이라고 할 수 있습니다. 0.003 / 0.001이죠. 기울기, 미분계수가 3이라는 것은 a를 0.001만큼 조금 움직여도 f(a)는 a를 가로로 민 정도보다 세 배나 커진다는 것을 뜻합니다.

 

이제 선의 기울기를 알아보았으니 이 함수를 다르게 생각해 봅시다. a가 5라고 한다면 f(a) = 3a이므로 f(a)는 15입니다. a를 오른쪽으로 살짝 밀어서 5.001이 되게 만들면 f(a)는 그 세 배이니까 15.003이 됩니다. 이번에도 a를 오른쪽으로 0.001만큼 움직이면 f(a)는 그보다 세 배 증가합니다. f(a)가 5일 때의 기울기도 3입니다. f(a)의 기울기가 3이라는 것은 df(a)/da가 이것은 변수 a를 아주 조금 움직였을 때 함수 f의 기울기라는 뜻이고 이 기울기가 3과 같다고 할 수 있습니다. 이 도함수는 이렇게도 쓸 수 있습니다. (d/da) · f(a), 그러니까 f(a)는 위에 놓든 옆에 놓든 상관없습니다. 어쨌든 이 식이 의미하는 것은 a를 오른쪽으로 조금 밀었을 때 f(a)는 a가 바뀐 양의 세 배 올라간다는 것입니다.

이 동영상에서는 도함수를 변수 a를 0.001만큼 민 경우로 설명하였는데 도함수의 정의를 수학적으로 정확히 하려면 a를 오른쪽으로 훨씬 작은 값만큼 밀었을 경우로 정의해야 합니다. 0.001도,  0.00000001도, 0.0000000001도 아니고 더 작은 값이어야 합니다. 도함수의 정확한 정의는 a를 무한소로 밀었을 경우에, 무한대로 작고 작은 양이죠, 그랬을 때 f(a)가 그 작고 작은 양의 세 배가 증가된다는 것입니다. 도함수의 정확한 정의는 이러하고 지금은 직관적인 이해가 필요하니까 a를 아주 작은 양 0.001만큼 밀었을 경우로 생각하도록 하겠습니다. 0.001는 작지만 무한소는 아닙니다. 이 도함수의 특성 중 하나는 함수의 어느 곳이든 기울기가 3이라는 것입니다. a가 2일 때도, 5일 때도 함수의 기울기는 3입니다. a의 값이 무엇이든 0.001만큼 증가시키면 f(a)의 값은 이것의 세 배 증가한다는 뜻입니다. 따라서 이 함수는 모든 곳의 기울기가 같습니다. 이 직각삼각형을 어디에 그리던지 높이/밑변의 비율은 항상 3:1입니다. 함수가 직선일 때 기울기, 도함수가 어떤지 이해 하셨나요?

방금 본 예제에서는 함수의 기울기가 모든 곳에서 3이었습니다. 다음 동영상에서는 좀 더 복잡한 경우로 위치가 다를 때 함수의 기울기가 달라지는 경우를 살펴보겠습니다.

 

 

06 더 많은 미분 예제

 

이번 동영상에서는 조금 더 복잡한 예로 함수의 다른 부분이 다른 기울기를 가지는 경우를 살펴봅시다.

 

다음은 f(a) = a²의 그래프입니다. 여기에서도 a = 2인 경우를 살펴봅시다. 그러면 a², f(a)는 4입니다. a를 오른쪽으로 밀어서 a가 2.001이 되도록 하면 f(a)는 a²이니까 약 4.004입니다. 사실 계산기로 계산해 보면 4.004001이지만 4.004도 충분히 가까우니까 이렇게 하겠습니다. 이것이 무슨 의미이냐면 a가 2일 때 먼저 그래프에 그려봅시다. a가 2일 때 f(a)는 4이고 x와 y축의 비율은 신경쓰지 않겠습니다. 실제로는 세로 높이가 가로 길이보다 훨씬 길어야 합니다. 이제 a를 2.001까지 밀면 f(a)는 약 4.004가 됩니다. 여기에 삼각형을 다시 그려보죠. a를 오른쪽을 0.001만큼 밀면 f(a)는 그것의 네 배인 0.004만큼 증가함을 알 수 있습니다. 미적분의 관점에서 이는 a = 2일 때 f(a)의 기울기, 미분계수가 4라고 말합니다. 미적분 표기법을 사용하면 a = 2일 때, (d/da)·f(a) = 4입니다.

 

이 함수 a²에서는 a값이 다르면 기울기도 다릅니다. 지난 번에 본 예제와는 차이가 있죠. 그러면 다른 점으로 가봅시다. a가 5이면 a², f(a)는 25입니다. 그리고 a를 5.001이 되도록 오른쪽으로 아주 조금 밀면 f(a)는 약 25.010가 됩니다. 여기서는 a를 0.001만큼만 밀어도 f(a)는 거의 열 배 증가합니다. 따라서 a가 5일 때 (d/da)·(f(a))는 10입니다. a를 살짝 밀었을 때 f(a)가 a에 비해 열 배나 많이 증가하기 때문입니다.

 

다른 점마다 미분계수가 다른 이유는 다른 위치에 이렇게 작은 삼각형을 그려보면 알 수 있습니다. 곡선 위의 다른 위치마다 높이/밑변의 비율이 다 다르죠. 이 경우엔 a가 2일 때의 기울기는 4이지만 a가 5일 때는 기울기가 10입니다. 미적분 책에서 (d/da)·(f(a)), f(a)는 a²이니까 (d/da)·a²에 대한 공식을 보면 여기 있는 함수 a²의 기울기는 2a라고 나와 있습니다. 여기서 증명까지 하진 않겠지만 미적분 책에서 공식 모음을 찾아보면 a²의 도함수는 2a라고 나와있을 것입니다. 이는 방금 계산한 것들과도 맞아떨어집니다. a가 2일 때 함수의 기울기가 2a이므로 2 x 2를 하면 4가 나오고, a가 5일 때 함수의 기울기가 2a이므로 2 x 5를 하면 10이 나옵니다. 언제라도 미적분 책에서 (d/da)·a² = 2a라는 공식을 보면 이는 아무 값 a를 아주 작은 값 0.001만큼 밀었을 때 f(a)의 값은 2a만큼 증가한다는 뜻일 뿐입니다. 기울기 혹은 도함수에 a를 민 정도를 곱한 것이죠.

잠깐 짚고 넘어가자면 여기에 근사치를 의미하는 기호를 썼습니다. 이것은 정확히 4.004가 아니라 끝에 001이 더 있었습니다. 추가로 붙은 001은 a를 0.001만큼 밀었기 때문에 생긴 것입니다. 만약 a를 무한소만큼 밀었다면 이 오차는 없어지고 f(a)가 증가하는 양은 정확히 도함수에 a를 오른쪽으로 민 만큼을 곱한 값과 같습니다. 이것이 정확히 4.004가 아닌 이유는 도함수의 정의는 a를 미는 값으로 0.001이 아니라 무한소를 사용하기 때문입니다. 0.001은 작기는 하지만 무한소는 아닙니다. 그래서 f(a)가 증가한 값이 정확히 공식과 같지 않고 근사치인 것입니다.

예제 몇 개만 더 보고 동영상을 마무리 하겠습니다. 방금 f(a) = a²이면 미적분 책에 나오는 공식에 따라 그 도함수는 2a라고 했습니다. 그 예제로 a가 2이면 f(a)는 4이고 a를 살짝 크게 만들면  f(a)는 약 4.004라는 것을 확인했습니다. f(a)는 a보다 네 배 증가했죠. 그리고 역시 a가 2이면 미분계수는 4가 맞습니다.

그럼 다른 예제를 살펴봅시다. f(a)가 a³이라고 해보죠. 미적분 책에서 공식을 찾아보면 기울기, 그러니까 이 함수의 도함수는 3a²이라고 나와있을 것입니다. 이것이 무엇을 의미하는지는 이렇게 하면 알아볼 수 있습니다. 다시 a가 2일 때를 보면 f(a)는 a³이고 2³이 8이므로 8입니다. a를 아주 조금 밀면 f(a)는 약 8.012입니다. 실제로 계산해 보세요. 값이 8.012와 거의 같을 것입니다. 역시 a가 2일 때 3 x 2²는 12이니까 도함수의 식은 a를 조금 밀면 f(a)는 그것의 12배만큼 증가한다고 말하는데 이것과 맞아 떨어집니다. a가 0.001 증가하니 f(a)는 그 12배인 0.012 증가하였습니다.

 

마지막으로 예제 하나만 더 보겠습니다. f(a)가 로그 함수 log(a)라고 해 봅시다. 밑이 e인 로그입니다. ln(a)라고 쓰기도 하죠. 미적분 책을 보면 log(a)의 도함수는 이렇게 생긴 함수의 기울기는 1/a입니다. 이게 무슨 의미일까요? 아무 a의 값에 대해서 일단 a가 2일 때를 살펴보죠. a를 오른쪽으로 0.001만큼 움직이면 f(a)는 1/a만큼 증가합니다. 도함수에 a를 증가시킨 만큼을 곱한 것이죠. 계산기로 계산해보면 a가 2일 때 f(a)는 약 0.69315이고 a를 2.001로 증가시키면 f(a)는 약 0.69365입니다. 0.0005만큼 증가했죠. 역시나 도함수의 식을 보면 a가 2일 때 (d/da)·(f(a))는 1/2이고 따라서 이 도함수의 식은 a를 0.001만큼 증가시켰을 때 f(a)는 그것의 절반만 증가한다고 말하고 있고 0.001의 반은 0.0005입니다. 여기서 구한 것과 맞아 떨어집니다. a가 0.001 증가해 2에서 2.001이 되었을 때 f(a)는 그것의 절반인 약 0.0005만 증가했습니다. f(a)는 그것의 절반인 약 0.0005만 증가했습니다. 다시 작은 삼각형을 그려보면 가로축이 0.001 증가할 때 log(a)는 그것의 반인 0.0005만 증가합니다. 따라서 1/a, 이 경우 1/2은 a가 2일 때 이 선의 기울기입니다. 따라서 1/a, 이 경우 1/2은 a가 2일 때 이 선의 기울기입니다.

도함수에 관한 내용은 여기까지입니다. 기억해야 할 것이 두 가지 있습니다. 첫 번째, 함수의 도함수는 함수의 기울기를 의미할 뿐이고, 함수의 기울기는 함수의 위치에 따라 다른 값을 가질 수 있다는 것입니다. 첫 예제였던 f(a) = 3a는 직선이었고, 미분계수는 모든 곳에서 3으로 같았습니다. 하지만 f(a) = a²이나 f(a) = log(a) 같은 경우 선의 기울기가 다르기 때문에 위치가 달라지면 도함수의 값이 달라집니다. 도함수는 선의 기울기일 뿐이라는 것이 첫 번째이고, 두 번째는 함수의 도함수를 찾아야 할 때 미적분 관련 책이나 위키피디아를 보면 여러 위치의 기울기에 대한 공식을 찾을 수 있다는 것입니다.

 

선의 기울기, 도함수에 대한 직관적인 이해를 얻으셨길 바라며 다음 동영상에서는 계산 그래프를 사용해 더 복잡한 함수의 도함수를 구하는 방법에 대해 알아보겠습니다.

 

 

07 계산 그래프

 

전에 신경망의 계산은 이렇게 나눌 수 있다고 했었습니다. 정방향 패스, 정방향 전파는 신경망의 출력값을 계산하고, 이는 역방향 패스, 역방향 전파로 이어져 경사나 도함수를 계산합니다. 계산 그래프를 보면 왜 이렇게 나누는지 알 수 있는데 이번 동영상에서는 그 예제를 살펴보도록 하겠습니다.

계산 그래프에 대해 설명하기 위해 로지스틱 회귀나 완성된 신경망보다 더 쉬운 것을 예로 들어 봅시다. 함수 J를 계산한다고 해 보죠. 이 함수는 변수 세 개 A, B, C를 가지고 있습니다. 이 함수는 3(a + b·c)입니다. 이 함수를 계산하는 데에는 서로 다른 세 단계의 과정이 필요합니다. 먼저 b·c를 계산해야 합니다. 이를 u라는 변수에 저장해서 u = bc라고 합시다. 다음에 v = a + u라고 할 때 v를 계산해야 합니다. 이것이 v입니다. 마지막으로 출력값 J = 3v입니다. 이것이 함수 J의 계산입니다. 이것이 계산하려고 했던 함수 J의 마지막이죠.

위의 세 단계를 다음과 같이 계산 그래프로 나타낼 수 있습니다. 세 변수 a, b, c를 여기에 그립니다. 처음으로 계산할 것은 변수 u = bc입니다. 사각형 안에 넣고 이것의 입력값은 b와 c입니다. 다음에 v = a + u가 있겠죠. 이것의 입력값은 u와 a입니다. 그리고 마지막으로 J = 3v가 있습니다. 예를 들어 a가 5, b가 3, c가 2라고 한다면, u = bc는 6입니다. v = a + u는 5 + 6이니까 11이고, J는 그 세 배인 33입니다. 확인해 보면 알겠지만 3(5 + 3×2)는 33이 맞습니다. 계산 그래프는 J같은 특정한 출력값 변수를 최적화하고 싶을 때 유용합니다. 그리고 로지스틱 회귀의 경우에 J는 당연히 최적화할 비용 함수입니다. 이 예제에서 확인할 수 있는 것은 왼쪽에서 오른쪽의 패스로 J의 값을 계산할 수 있다는 것입니다.

 

다음 강의에서는 도함수를 구하기 위해 오른쪽에서 왼쪽으로 패스하는 것을 알아볼 것입니다. 이렇게 파란 화살표의 반대 방향으로 가는 것이죠. 도함수를 계산하는 가장 자연스러운 방법입니다. 정리해 보면 계산 그래프는 왼쪽에서 오른쪽으로 계산하는 파란색 화살표를 사용해 계산을 정리하였습니다. 다음 동영상에서는 역방향으로 빨간색 화살표를 이용해 오른쪽에서 왼쪽 방향으로 도함수를 계산해 보겠습니다.

 

 

 

08 계산 그래프로 미분하기

 

지난 동영상의 예제에서는 계산 그래프를 사용해 함수 J를 계산해 보았습니다. 그 그래프를 다시 정리해서 그려 놓았는데, 어떻게 이를 이용해 함수 J의 도함수를 계산하는지 알아봅시다.

 

계산 그래프입니다. v에 대한 J의 도함수를 구해 봅시다. 무슨 뜻일까요? v의 값을 아주 조금 바꾸면 J의 값이 어떻게 바뀌는지 묻는 것이죠. J  = 3v라고 정의되어 있습니다. v는 11입니다. 따라서 11을 조금 증가시켜 11.001로 만들면 J = 3v이고 현재 33이므로 33.003으로 증가됩니다. v를 0.001 증가시켰더니 J가 그 세 배 증가했으니까 v에 대한 J의 도함수는 3입니다. J의 증가량이 v의 증가량의 세 배이기 때문입니다. J의 증가량이 v의 증가량의 세 배이기 때문입니다. 지난 동영상에서 했던 것과 비슷합니다. f(a) = 3a였고, df(a)/da를 구했더니 간단하게 df/da라고도 쓸 수 있는데 이는 3이었습니다. 여기서 J = 3v이므로 dJ/dv는 3입니다. J가 f를 대신하고 v가 a를 대신하는 것입니다.  역전파는 이렇습니다. 이 마지막 출력값 변수의 v에 대한 도함수를 얻으면 보통 얻고자 하는 것이 이것일 텐데 역전파의 한 단계를 끝낸 것입니다. 그래프에서 한 단계 뒤로 가는 것이죠.

다른 경우를 살펴봅시다. dJ/da는 얼마일까요? 그러니까 a의 값을 증가시키면 J의 값에 어떤 영향을 끼칠까요? 예제를 봅시다. 현재 a = 5인데 5.001로 증가시켜 봅시다. 이것이 어떤 영향을 끼치나면  v가 a + u이고 이는 11이었으므로 11.001로 증가하고 그러면 위에서 볼 수 있듯이 J는 33.003으로 증가합니다. a를 0.001만큼 증가시키면 J는 0.003만큼 증가합니다. 증가한다는 것은 5라는 값 대신 새 값을 넣었을 때 a의 변화가 계산 그래프의 오른쪽으로 전파되어 J가 33.003이 된다는 뜻입니다. J의 증가량은 a의 증가량보다 세 배 많고 이는 도함수가 3이라는 뜻입니다.

 

이렇게 생각할 수도 있습니다. a를 바꾸면 v도 바뀌고, v를 바꾸는 것으로 J도 바꿀 수 있다고 말입니다. a의 값을 조금 높였을 때 J에 일어나는 전체 변화는 먼저 a를 바꾸면 v가 증가합니다. v는 얼마만큼 증가할까요? dv/da에 의한 양만큼 증가합니다. 그리고 v의 변화는 J를 증가시킵니다. 미적분에는 연쇄법칙이라는 것이 있는데 만약 a가 v에 영향을 끼치고 그것이 J에 영향을 끼친다면 a를 밀었을 때 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(최종 출력값)/d(var)라고 해 봅시다. 계산의 많은 부분이 a, b, c, u, v 같은 여러 중간 변수를 포함하는 최종 출력값 J의 도함수를 구하는데 사용되는데, 이를 소프트웨어에서 구현할 때는 변수의 이름을 무엇이라고 할 수 있을까요? 파이썬의 경우 아주 긴 변수 이름으로 d(최종 출력값)_over_dvar 등으로 지정할 수는 있겠지만 그렇게 되면 너무 길어집니다. 이 경우엔 dJ_over_dvar정도가 되겠죠. 하지만 계속 최종 출력값 J의 도함수를 구하고 있는 것이니까 새로운 표기법을 사용해서 코드에서 이것을 계산할 때 이 값을 나타내는 변수 이름을 dvar이라고만 합니다. 코드에서 dvar이 구하고자 하는 최종 출력값 변수 J나 때때로 손실 함수의 L같은 변수의 여러 중간 값에 대해 계산한 도함수를 의미하게 되는 것입니다. 코드에서 이 값은 dv라고 쓰고 값은 3이 됩니다. 그리고 이것은 da라고 나타내고 이 값 또한 3이었습니다. 계산 그래프를 통해 역방향 전파를 어느 정도 알아보았는데 다음 슬라이드에서 나머지를 살펴봅시다.

계산 그래프를 복사하고 여태까지 한것을 되짚어보면 역방향으로 계산해서 dv = 3이라는 것을 구했고 dv는 코드에서 dJ/dv를 나타내는 변수이름입니다. 그리고 da = 3이라는 것도 구했습니다. da 또한 코드에서 dJ/da를 나타내는 변수 이름입니다. 이제까지 두 간선을 따라 역방향으로 진행했는데 계속해서 도함수를 계산해 봅시다.

 

u에 대해 알아보겠습니다. dJ/du는 얼마일까요? 전에 했던 것처럼 u를 6에서 시작해서 6.001로 증가시키면 v는 11에서 11.001로 증가합니다. 그러면 J는 33에서 33.003로 증가하므로 J는 세 배 증가합니다. u의 경우도 a의 경우와 거의 똑같이 (dJ/dv)(dv/du)입니다. 이것은 아까 3이라고 했었고 이것은 1입니다. 역방향 전파에서 한 단계 더 나아가니 du도 3이었다는 것을 계산할 수 있었습니다. 당연히 du는 dJ/du를 의미합니다.

마지막 예제를 자세히 살펴봅시다. dJ/db는 얼마일까요? b의 값을 바꾸는 것이 허용되고 b를 바꿔서 J의 값을 최소화하거나 최대화하려고 한다고 합시다. 그려먼 b의 값을 조금 바꿨을 때 함수 J의 기울기 도함수는 무엇일까요? 미적분에서의 연쇄법칙을 사용하면 두 값의 곱으로 나타낼 수 있습니다. (dJ/du)(du/db)이죠. 그 이유는 b를 조금만 바꿔 3에서 3.001이 되게 했을 때 J에 그 영향이 닿으려면 먼저 u를 통해야 합니다. u의 변화량은 얼마일까요? u = bc이므로 b가 3일 땐 6이었다가 c가 2이니까 6.002로 증가합니다. 따라서 du/db = 2임을 알 수 있습니다. b가 0.001 증가했을 때 u는 그 두 배 증가했기 때문입니다. du/db는 2입니다. 이제 u는 b의 증가량의 두 배 증가한다는 것을 알고 있는데 dJ/du는 얼마일까요? 그것은 이미 3이라고 구했습니다. 둘을 곱해보면 dJ/db = 6입니다. 그 이유를 생각해 보면 이렇습니다. u가 0.002 증가하면 J에 어떤 영향이 있는지 알아보려 하는데 dJ/du = 3이기 때문에 u가 0.002 증가하면 J는 그 세 배인 0.006 증가해야 합니다. dJ/du = 3이라는 사실 때문이죠. 계산해 보면 b가 3.001이 되었을 때 u는 6.002가 되고 v는 11.002가 되는데, a + u, 그러니까 5 + u이기 때문이고 J = 3v이므로 J는 33.006이 됩니다. 그러므로 dJ/db = 6입니다. 채워보면 이렇게 역방향으로 와서 db = 6입니다. db는 dJ/db의 파이썬 코드 변수 이름입니다.

 

마지막 계산은 자세히 하진 않겠지만, dJ/dc = (dJ/du)(du/dc)이고, 계산해 보면 3 x 3으로 9가 됩니다. 과정을 자세히 보진 않겠지만 계산해 보면 dc = 9입니다. 

 

이 동영상에서 얻어가야 할 사실은 이 모든 도함수를 계산할 때 가장 효율적인 방법으로 하려면 빨간 화살표 방향처럼 오른쪽에서 왼쪽으로 계산한다는 것입니다. 이 경우 먼저 v에 대한 도함수를 구했고 구한 값을 사용해 a에 대한 도함수와 u에 대한 도함수를 구했습니다. 여기있는 u에 대한 도함수는 b에 대한 도함수와 c에 대한 도함수를 구하는데 사용하였습니다.

지금까지 계산 그래프를 보고 왼쪽에서 오른쪽으로 가는 정방향 계산으로 최적화하고자 하는 J 같은 비용함수를 계산하는 것과, 오른쪽에서 왼쪽으로 가는 역방향 계산으로 도함수를 계산해 보았습니다. 미적분이나 연쇄법칙이 익숙하지 않다면 강의가 조금 빠르게 진행되었다고 생각할 수도 있는데 전부 이해하지 못했어도 괜찮습니다.

다음 동영상에서는 이 내용을 로지스틱 회귀의 관점에서 다시 살펴보고 로지스틱 회귀에 필요한 도함수의 계산을 구현하는데 무엇이 필요한지 보여드리도록 하겠습니다.

 

 

09 로지스틱 회귀의 경사하강법

 

이번 동영상에서는 로지스틱 회귀의 경사하강법을 구현하는 데 필요한 도함수를 계산하는 방법에 대해 알아보겠습니다. 여기서 알고 가야 할 것은 로지스틱 회귀의 경사하강법을 위해 필요한 핵심 공식을 구현하는 방법입니다. 이 동영상에서는 이를 계산 그래프를 통해 하려고 합니다. 계산 그래프를 로지스틱 회귀의 경사하강법에 사용하는 것은 조금 과하긴 하지만 이런 방법을 사용해 설명하면 이런 개념이 익숙해져서 나중에 완전한 신경망를 다룰 때 이해가 더 잘 될 것입니다. 그러면 로지스틱 회귀의 경사하강법에 대해 알아봅시다.

다음과 같은 로지스틱 회귀를 복습해 봅시다. y의 예측값은 이렇게 정의하고 그 안에 있는 z의 정의는 이렇습니다. 그리고 샘플 하나만 생각 할 때 그 하나의 샘플에 대한 손실 함수는 이렇습니다. 여기서 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)를 계산합니다. 그 다음엔 (y의 예측값) = a = σ(z)를 계산합니다. 이게 계산 그래프에서의 다음 단계이고, 마지막으로 L(a, y)를 계산합니다. 식을 다시 쓰진 않겠습니다. 로지스틱 회귀에서의 목적은 매개변수 w와 b를 변경해서 이 손실을 줄이는 것입니다. 단일 훈련 샘플에 대한 손실의 계산에 대해서는 예전에 보았습니다. 이제 반대 방향에서 도함수의 계산에 대해 이야기해 봅시다. 그래프를 깔끔하게 만들어 보았습니다. 구하고자 하는 것은 이 손실 함수의 도함수이니까 역방향으로 가서 a에 대한 손실 함수의 도함수를 계산해 봅시다. 코드에서는 이 변수를 da라고 나타낼 수 있습니다. 미적분에 대한 지식을 이용하여 이를 계산하면 다음과 같은 결과가 나옵니다. -(y/a) + ((1 - y)/(1 - a)) 미적분을 잘 알아서 손실 함수의 식을 가지고 a에 대한 도함수를 계산해보면 이런 결과가 나옵니다.

 

+ 합성함수의 미분, 로그함수의 미분 +


미적분을 잘 알지 못해도 괜찮습니다. 강의에서 필요한 도함수의 식은 항상 알려드리도록 하겠습니다. 미적분을 잘 안다면 지난 슬라이드에서 손실 함수의 식을 보고 직접 a에 대한 도함수를 계산해 보는 걸 추천합니다. 하지만 미적분에 대해 잘 알지 못한다면 상관없습니다.

 

a에 대한 최종 출력값의 도함수인 da를 계산했으니 이제 역방향으로 더 갈 수 있습니다. 계산해 보면 파이썬 코드 변수 이름 dz는 z에 대한 손실 함수의 도함수이고 L을 a와 y에 대한 손실이라고 직접 써도 좋습니다. 두 표기법 모두 괜찮습니다. 그러면 이는 a - y라고 나타낼 수 있습니다. 미적분을 잘 알고 있다면 이렇게 이해할 수 있습니다. 그렇지 않다면 신경쓰지 마세요.

 

+ 시그모이드 함수의 미분 +

 

dL/dz는 (dL/da)(da/dz)라고 나타낼 수 있는데 계산해 보면 da/dz는 a(1 - a)이고 dL/da는 방금 이것이라고 계산 했습니다. 그래서 dL/da인 이 항과 da/dz인 이 항을 서로 곱하면 식을 a - y로 간단히 할 수 있습니다. 잠깐 설명했던 연쇄법칙을 사용해 이렇게 도함수를 구한 것입니다. 미적분을 할 줄 알면 직접 계산해 보아도 좋고 그렇지 않다면 그냥 dL/dz = a - y라고 알고 있으면 됩니다.

역방향 전파의 마지막 단계는 w와 b를 얼마나 바꾸어야 하는지 계산하는 것입니다. 예를 들어 w_1에 대한 도함수는 코드에서는 dw1이라고 나타내고 x_1·dz와 같으며 w_2의 변화량을 나타내는 dw_2는 x_2·dz와 같습니다. 그리고 db = dz입니다. 단일 샘플에 대해서만 경사하강법을 사용한다면 이렇게 할 수 있습니다. 이 식을 사용해 dz를 계산하고 이 식들로 dw_1, dw_2, db를 계산한 후 이렇게 갱신합니다. w_1 := w_1 - (학습률 α)·dw_1, w_2는 똑같이 하면 되고, b := b - (학습률 α)·db입니다. 이것은 단일 샘플에 대한 경사하강법의 한 단계입니다.

도함수를 계산하고 단일 샘플에 대한 로지스틱 회귀의 경사하강법을 구현하는 방법을 알아보았습니다. 하지만 로지스틱 회귀 모델을 훈련시키려면 단일 샘플이 아니라 m개의 훈련 샘플을 가진 훈련 세트 전체를 훈련해야 합니다. 다음 동영상에서는 이것을 가지고 단일 샘플이 아닌 훈련 세트 전체를 학습시키는 방법을 알아보도록 합시다.

 

 

10 m개 샘플의 경사하강법

 

지난 동영상에서는 도함수를 계산해 단일 샘플에 대한 로지스틱 회귀의 경사하강법을 구현해 보았습니다. 이제 이를 m개의 훈련 샘플에 대해서 해 보려고 합니다.

그 시작으로 비용 함수 J의 정의를 다시 살펴봅시다. w, b에 대한 비용 함수는 다음과 같이 평균 값입니다. 1/m에 i = 1부터 m까지 샘플 y에 대한 출력값 a^(i)의 손실의 합을 곱한 것이죠. a^(i)는 i번째 샘플의 예측값을 나타내고 σ(z^(i))와 같습니다. 이는 다시 σ(w^T·x^(i) + b)와 같습니다. 지난 강의에서는 아무 단일 샘플에 대해 도함수를 계산하는 방법을 보았습니다. 훈련 샘플이 하나일 때 말이죠. dw_1^(i), dw_2^(i), db^(i)는 이제 i를 사용해 전 강의에서처럼 계산했을 때 각각 해당하는 값을 나타냅니다. 단일 훈련 샘플 (x^(i), y^(i))를 사용했을 때 말입니다. 여기 i가 빠졌네요. 식을 보면 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(i) + b와 예측값 a^(i) = σ(z^(i))를 계산하고 J에 더해 줍니다. J += -[y^(i) log a^(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라고 가정하고 한 것입니다. 아니라면 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 문을 두 개 만들어야 합니다. 첫 번째 for 문은 m개의 훈련 샘플을 반복하고 두 번째 for 문은 여기처럼 특성을 반복합니다. 여기는 n = 2, 특성이 두 개뿐이지만 특성이 더 많다면 dw_1,  dw_2도 있고, dw_3도 같은 방식으로 계산해 dw_n까지 있을 것이기 때문에 n개의 특성을 반복하는 for 문이 필요합니다. 딥러닝 알고리즘을 구현할 때 코드에서 이런 명시적인 for 문은 알고리즘을 비효율적으로 만듭니다. 딥러닝의 전성기에 접어들면서 데이터 집합이 점점 더 커졌기 때문에, 코드를 명시적인 for 문 없이 구현하는 것이 중요해졌습니다. 그렇게 해야 더 큰 데이터 집합도 처리할 수 있죠. 그러한 방법 중 벡터화라는 것이 있습니다. 명시적인 for 문을 제거할 수 있게 해줍니다. 딥러닝이 뜨기 전에는 벡터화는 있으면 좋은 것일 뿐이었습니다. 속도 향상을 위해 가끔 쓸 때도 있고 안 쓸 때도 있었죠. 하지만 딥러닝의 시대에 들어와서는 이런 for 문을 없애주는 벡터화가 아주 중요해졌습니다. 아주 큰 데이터 집합을 사용하기 때문에 코드를 효율적으로 만드는 것이 아주 중요하기 때문입니다.

다음 동영상들에서는 벡터화와 이 모든 것을 for 문 하나 없이 구현하는 법을 살펴보겠습니다. 로지스틱 회귀의 경사하강법 구현 방법이 이해되었으면 합니다. 프로그래밍을 해 보면 더 확실해질 것입니다. 프로그래밍을 해 보기 전에 먼저 벡터화에 대해 이야기 해 봅시다. 경사하강법의 완전한 한 단계를 for 문을 사용하지 않고 구현할 수 있게 될 겁니다.

 

728x90

댓글