누구나 이해할 수 있는 딥러닝 - cs231n 4강(Backpropagation and Neural Networks)
- cs231n 4강의 내용을 정리한 글입니다.
- 최대한 쉽게, cs231n 강의를 스스로 다시 이해하며, 처음 딥러닝을 공부하는 사람들도 쉽게 이해할 수 있게 정리해보았습니다.
- 저도 초보인지라 틀리는 부분이 있을 수 있고, 이해가 안 되는 부분이 있을 수 있습니다. 만약 틀린 부분이 있거나 잘 이해가 되지 않는 부분이 있다면, 바로 댓글로 질문해 주세요! 내용과 관련된 질문은 최대한 아는 선에서 대답해 드리겠습니다!
- 보는 중에 사진들에 나오는 수식같은 경우는, 따로 설명하지 않았다면 건너뛰어도 됩니다.
- 이해가 잘 되지 않은 설명이거나, 설명이 명확하지 않은 것 같으면, 댓글로 피드백 부탁드립니다.
이번 강좌에서는, Backpropagation(역전파법)과 Neural Network(인공 신경망)에 대해서 알아보겠습니다!
우선, 저번 시간 복습부터 시작하겠습니다.
위의 scores function으로 각 클래스마다의 점수를 구한 이후에,
그 점수를 사용해서 SVM loss (또는 softmax loss)를 구하고,
거기다가 regularization을 더해서, 총 loss를 구한 다음에,
그 loss를 가장 적게 만들어 봅시다.
그런 다음, 산을 천천히 내려간다는 그 비유처럼, 조금씩 조금씩 loss가 내려가는 방향으로 분류기를 수정합니다.
이를 optimization이라고 하죠.
그리고, numerical 과 analytic, 기억 나시죠?
기울기를 조금씩 줄여주면서 optimization을 할 것이다!
그리고 지금까지 말한걸 computational graph로 표현한 것이 위의 슬라이드입니다.
그런데, 이건 그나마 f=Wx같은 간단한 거였으니깐 이런 식으로 예쁘게 그래프가 나오지, 나중에 나올 악랄한 식들도 존재하고, 그러면 그래프도 엄청나게 복잡해지고.. 이걸 하나하나 다 계산하는 건 미친 짓이라는 거죠 ㅎ
이게 대표적인 예인데, 이건 AlexNet이라는 Convolutional network를 computational graph로 나타낸 것입니다.
그게 뭐냐구요?
곧 할 거니깐, 그냥 그렇다고 알아두세요~!
이따구로 생긴, 징그럽다는 생각까지 들 정도로 이상하게 생긴 그래프도 있는데,
그걸 무수히 많이 사용하는 경우도 있으니..
저 블록 거의 하나하나마다 미분을 다 하고 있으면, 아무리 analytic이라도 엄청나게 오래 걸리겠죠?
그래서 나온 게 backpropagation(역전파법)인데... 음.. 어..
이것도 신나는 수학 시간이네요!
본격적으로 들어가기에 앞서, 드릴 말씀이 있습니다!
지금부터는 그냥 죄다 미분 및 계산에 관련된 내용입니다. 그렇기 때문에, 저런 계산에 약하신 분들은, backpropagation 부분 말미에 마지막 정리 부분만 봐주셔도 괜찮습니다!
게다가, 저조차도 계산을 잘 못하기 때문에, 중간중간 틀리는 부분이 있을 수도 있습니다.
설명 중간에 이상한 부분을 포착했다면 댓글로 저 좀 혼내주시면 감사하겠습니다 ㅎㅎ
또, 슬라이드가 이 부분은 굉장히 많습니다. 그만큼 슬라이드가 자세히 설명을 해 주고 있으니, 설명이 빈약한 부분은 슬라이드를 통해 더 자세히 이해할 수 있으면 좋겠습니다.
아무튼! 시작해 보도록 하겠습니다!
우리의 모델이 f(x, y, z) = (x+y) * z라고 해봅시다.
여기서의 예에서는 x=-2, y=5, z=-4로 두겠습니다.
그리고, q=x+y, f=q*z라고 할 때, 우리가 구하고 싶은 것은 밑의 식 세 개입니다.
f를 각각 x, y, z로 편미분 한 값을 원하는 것이죠.
왜냐고요??
입력값이 x, y, z일 때, 이 x, y, z값이 마지막 output 값에 끼치는 영향을 알고 싶은데, 그것이 바로 저 편미분 값이기 때문이죠.
자, 한번 거꾸로 가 봅시다!
일단 f를 f로 편미분 한 값은?
당연히 1!(팩토리얼 아님 ㅎ)
그러면, f를 z로 미분하면?
f=qz이므로, f를 z로 편미분 하니깐 당연히 q, 즉 3이 나옵니다!
같은 방식으로, f를 q로 미분한 값은, z인 -4가 되겠지요?
그런데, f를 y로 미분한 값은 어떻게 구할까요?
위에서 나와있는 Chain rule에 따라, f를 q로 편미분 한 값인 -4 와 q를 y로 편미분한 값을 곱해야 합니다.
그러면, q를 y로 편미분한 값은?
q=x+y이므로, q를 y로 편미분 하면 당연히 정답은 1이기 때문에
-4 * 1 = -4, 즉 f를 y로 편미분 한 값은 -4가 됩니다.
Chain rule이 뭐냐고요?
.. 우리 착한 수학자 형아들이 만들어 준거예요! 그냥 그렇구나! 하고 넘어갑시다!
마찬가지로, f를 x로 편미분 한 값도,
Chain rule을 이용하여 -4 * 1 = -4라고 구할 수 있습니다.
자, 이것을 보기 쉽게 그림으로 확인해 볼까요?
우선, x값과 y값을 입력으로 받고, f라는 함수에다가 집어넣어서 z라는 값을 얻어냅니다.
이때, 우리는 z를 x로 미분한 값과, z를 y로 미분한 값들을 얻어낼 수 있습니다.
그러고, z를 끝으로 L, 즉 loss를 계산했다고 해봅시다.
자, 이때는 역전파법을 어떻게 사용할까요?
우선, 마지막에서 시작합니다.
L을 z로 미분하는 것이죠.
그리고 나서, L를 각각 x, y로 미분한 값을 구할 때면, 아까 구해놨던 z를 x,y로 미분한 값과 chain rule을 사용하여 구할 수 있습니다!
그리고, 이 값들을 구해내는 것이죠.
이렇게, 입력값을 받아서 loss값을 구하기까지 계산해 가는 과정을 forward pass라고 하고,
forward pass가 끝난 이후 역으로 미분해가며 기울기 값들을 구해가는 과정은 backward pass라고 부릅니다.
다른 예제로는, 다음과 같은 그래프가 있는데...
얍!!!
자, 계산이 끝났습니다! 정말 쉽죠?
만약 직접 계산해보고 싶다면, 아래의 식 4개만으로도 충분히 모두 계산할 수 있으니, 한번 제대로 계산이 되었나 검산 한번 해보세요!
아니, 갑자기 왜 이렇게 스킵하냐고요? 왜 슬라이드 13개나 갑자기 넘기냐고요??
이걸 하나하나 다 계산해 보는 것에 큰 의미도 없을뿐더러, 그냥 계산 연습 수준의 예제라서 계산만 가능하다면 크게 이해하는 것에 어려움을 느끼진 않을 것이라 생각했기 때문입니다. 계산 못하면, 그냥 넘기셔도 됩니다!
그런데, 조금 특이한 점이 있습니다.
어떤 것을 미분을 하려고 할 때, 위의 sigmoid gate라고 적혀있는 저 부분만 떼서 보았을 때, 저 부분을 한 번에 미분이 가능하다는 것입니다! 즉,
0.73 부분에서 1/x부분 미분해서 -0.53, +1 미분해서 -0.53... 할 필요 없이,
그냥 한 번에 (0.73)*(1-0.73) = 0.2 라고 계산이 가능하다는 것이죠.
띠용?? 그럼 지금까지 했던 모든 미분을 죄다 한번에 할 수도 있는 거 아님?? 하실 수도 있는데..
사실 맞음! 엄청나게 긴 computational graph조차도 한방에 미분이 되게 할 수도 있습니다!
그런데.. 위에서 봤다시피 엄청나게 복잡하고, 수없이 많은 노드들이 연결되어 있는 그래프 같은 경우에는, 이게 사실상 불가능하겠죠?
그러니깐, 위의 sigmoid function과 같이 자주 사용되는 임의의 부분만 떼와서, 그 부분만 쉽게 계산할 수 있도록 하면 됩니다.
그런데 sigmoid function이 뭐냐고요??
그냥 중간에 껴들어가는 함수 언저리다~! 하고 생각하시면 됩니다. 나중에 다시 나오니깐, 뭔지 모르겠다고 끙끙대지는 마세요!
그리고, backpropagation을 하면서 자주 보일 패턴들입니다.
add gate는 덧셈을,
mul gate는 곱셈을,
max gate는 최댓값을 구하는 gate입니다.
그런데, 이것들의 backward pass를 할 때는, 조금 더 간단하게 계산이 가능합니다.
add gate가 나온다면, 이미 가지고 있던 gradient를 각각의 노드에 분배해 주면 됩니다.
mul gate가 나온다면, 현재의 gradient를 각각 숫자에 (위의 예는 x, y)에 곱해서, 바꿔치기해주면 됩니다.
max gate가 나온다면, 그냥 더 큰 쪽에만 gradient를 그대로 꽂아주고, 반대쪽은 씹고 넘어가면 됩니다.
이렇게 몇몇 gate에서는 간단하게 계산이 가능하다는 것을 알 수 있습니다.
자, 그럼 이제 위의 예제를 이 방식을 사용해서 한번 해보고 싶지 않으신가요?
저는 별로 해보기 싫으니깐 그냥 넘어가도록 하겠습니다 ㅎㅎ
그리고, 위와 같이 노드 하나에서 다른 노드 두 개로 모두 이어졌을 때, backpropagation을 수행하면 저 뒤의 두 개의 노드에서 오는 미분 값을 더해야겠죠?
반대로, 앞의 노드 하나만 바뀌어도 뒤의 노드 두 개가 모두 바뀌고, 또 그 뒤가 모두 바뀌고... 한다는 사실도 알아두시면 좋겠습니다.
그런데, 우리의 x, y, z들은 사실 어떤 한 변수가 아니었죠?
되게 여러 개가 나열되어 있는, 벡터였습니다! 그냥 수의 나열이라고 생각하시면 편해요!
그러니깐, 이런 짓거리를 벡터로도 한번 해봐야 겠.... 나요..?
.. 아니요! 안 할 겁니다!
위의 예처럼 그냥 계산만 복잡해졌다 이거지 딱히 다른 점도 없을뿐더러, 머리 터져요!!
그냥 슬라이드만 살짝궁 올려놓을 테니, 진짜로 해보고 싶으신 분들은 직접 계산 대입해서 하셔도.. 되긴.. 하는.. 데.. 비추드립니다 ㅎㅎ
아무튼, 여기까지 (간단하게나마) 했으니, 직접 한번 구현해보도록 합시다!
물론 저 위에 계산을 하나하나 다 하고 있자는 건 아니고, 그냥 어떤 식으로 이루어지는지만 확인할 겁니다.
우선, forward부분에서는 input이 주어지고, 그에 따른 loss값을 구할 수 있겠죠?
그러고 나서, backward 부분에서는 거꾸로 하나하나 미분해 가면서 미분 값들을 구하겠고요.
간단하게 하면, 이게 다예요!
쪼--끔만 더 들어가 보겠습니다.
아까 전에 gate들 중에서 mul gate를 예로 들어서 봅시다. (x, y, z는 다 벡터가 아니라 숫자라고 가정해요!)
일단, forward pass를 봅시다.
forward 부분에서의 인자 값은 간단하게 x와 y가 될 겁니다.
그리고, mul gate였으므로, x와 y를 곱해서 z값을 도출해 내고, 그 z값을 리턴하겠죠?
그렇다면, backward pass는 어떨까요?
우선, backward 부분의 인자는 어떤 것이 와야 할까요?
위 설명을 잘 읽으셨다면 아시겠지만, loss 값 L을 z로 미분한 값을 인자로 가져야겠죠?
그리고, 리턴 값은 당연히 L을 x, y로 미분한 값들이어야 할 겁니다.
우리가 backward를 하면서 구하고 싶은 값은 L를 x, y로 미분한 값이니깐요!
그리고, 위에서 설명했듯이, mul gate는 backward pass를 할떄, 서로서로 바꿔서 곱해준다고 했으니깐,
각각을 계산한 값들은 위와 같이
dx = self.y * dz
dy = self.x * dz
가 되겠죠?
이런 방식으로, forward pass와 backward pass를 구현할 수 있습니다!
물론 그걸 우리가 다 하나하나하고 있을 건 아니고, caffe 같은 라이브러리들이 대신 짜둔 것들을 우리가 써먹기만 하면 됩니다!
위에서 계산은 실전에서 그렇게까지 중요하지 않다고 한 이유가 바로 이건대, 우리가 직접 계산해야 될 것들은 별로 없기 때문이죠.
킹 갓 스탠퍼드 형님들은 이걸 저번에 배웠던 SVM과 섞어서 코드를 짜는 게 숙제라는데,
직접 해본 결과 도저히 backward pass를 짤 수가 없어서 GG 쳤었네요 ㅎㅎ
도전심이 들면 도전해보셔도 좋은데, 저처럼 이거 하느라 5시간씩 날려먹진 않으셨으면 좋겠네요..
자, 이제 정리해봅시다!
**** 이건 위에 안 읽으신 분들도 보셔야 돼요!! ****
인공 신경망은 굉장히 거대할 겁니다. 기울기, 즉 미분 값들을 하나하나 손으로 써 내려가는 것은 미친 짓입니다! (한번 해보시면 앎 ㅎ)
그래서, backpropagation(역전파법)을 사용할 겁니다.
chain rule이라는 일종의 수학 공식?을 사용하여, 모든 입력값 및 변수들에 대한 기울기를 계산해 나갈 겁니다.
그리고 이것들을 하기 위해서, 우리는 forward와 backward를 구현할 겁니다.
forward는 그냥 gate들을 거쳐가며 정방향으로 계산해 나가면서, 나오는 값들을 메모리에 저장해 나가는 것입니다.
backward는 그 값들을 토대로 뒤에서부터 계산하며 chain rule을 적용시켜, input 값이 loss값에 어떤 영향을 미치는지를 (기울기 값을) 계산할 것입니다.
여기서 나올 수 있는 질문 하나!
Q. 그런데, 굳이 거꾸로 계산하는 이유가 뭐임??
A. 정방향으로 계산하면서 하나하나 미분 값을 계산하는 것은 굉장히 연산의 낭비가 심합니다. 직접 한번 위의 예시들을 정방향으로 계산해 보면, 이미 했던 계산 또 하고 또 하는 자신을 발견하게 될 겁니다.
다른 질문 있으시면, (설명 안 했던 부분이라 하더라도) 댓글로 질문해 주시면 답변해 드리겠습니다 ㅎㅎ
그럼 이제 인공신경망을 건드려 볼까요?
아, 이번 시간에 그렇게 자세하게 들어가진 않습니다!
윗부분 읽으시면서 힘들으셨던 분들도, 쉽게 쉽게 이해하고 넘길 수 있는 부분일.. 겁니다.. 아마?
일단 인공 신경망을 우리의 신경망과 연관 짓지 말고 생각해보겠습니다.
원래 우리의 선형 분류기에서의 점수 계산은 그냥 f=W*x로 했었던 거, 기억 나시죠?
근데, 이제 그 폭을 한번 넓혀보겠습니다.
그냥 W라는 레이어 하나만을 지나는 것이 아니고, 다른 W 두 개를 지나게 만들어버리는 것이죠!
그러면 더욱 정확해지지 않을까? 하는 것이죠.
마치 초벌 된 치킨 맛과 재벌 된 치킨 맛의 차이랄까요? 물론 따로따로 먹어본 적은 없어서 잘 모르겠지만 아무튼 ㅎㅎ
위의 예에서는 f=Wx를 발전시켜
f=W2*max(0, W1x)
로 만들었습니다.
이를 조금 더 풀어보겠습니다.
우선, W1과 x를 곱해서 점수를 먼저 냅니다.
이거까지는 linear score function과 같죠?
그리고, 이 점수가 0보다 크면, W2라는 다른 레이어를 곱해줍니다. (0보다 작으면 그냥 0을 곱해줍니다!)
이렇게 이미 한번 곱해준 친구를 다시 한번 곱하는 것이죠.
그리고 이번 예에서는, W1과 x를 곱해줄 때 100개의 점수를 냅니다.
그 뒤, W2와 max(0, W1x)를 곱할 때에, 그 100개의 점수에서 10개의 점수로 줄여나갑니다.
(무조건 100개에서 10개로 줄여야 하는 것은 아닙니다! 하나의 예시일 뿐입니다!)
자, 그런데 대체 왜 max(0, W1x)라는 식이 쓰였을까요?
바로 non-linearity, 즉 비선형 식이 쓰여야 하기 때문입니다.
이에 대해서는 이후 6강에서 더욱 자세하게 다루겠지만, non-linearity 식이 중간에 껴들어가지 않는다면, 아무리 많은 레이어들을 합쳐봤자 결국 하나의 레이어와 같은 결과를 내기 때문입니다.
'어라? 그런데 그러면 max가 아니라 다른 것도 쓸 수 있지 않아요? 그냥 선형만 아니면 되는 거잖아요!'
네, 바로 그렇습니다. 위의 max(0, W1x)는 non-linearity 식 중 하나인 ReLU function이라는 것인데, 이후에 한번 나오고, 6강에서 다시 한번 보게 될 것입니다.
이 같은 non-linearity function은 위의 max(0, W1x)인 ReLU 말고도 다른 것들도 많은데, 이처럼 Linear 사이에 껴들어가는 non-linear 한 함수들을 일컬어 activation function이라고 합니다. 나중에 한번 더 나오니깐, 그때 더 자세하게 합시다!
자, 이러면 다중 레이어의 인공신경망의 기초를 알았는데, 이것을 왜 했는지가 중요하겠죠?
Linear Classifier를 배웠을 때, 한계점에 대해서도 배웠었죠?
각각의 클래스마다 하나의 사진만 나와서, 그에 최대한 가까운 사진들을 분류해내는 작업을 하는 것이었는데, 위의 그림을 보면 아시겠지만
자동차 같은 경우에는 그냥 아예 빨간 자동차의 경우만 제대로 자동차라고 인식하고, 다른 색상, 예를 들면 노란색의 차는 제대로 자동차라고 인식을 안 할 것이라고 예산할 수 있습니다.
하지만, 이와 같이 여러 개의 레이어를 덮어 씌웠다면, 중간에 100개의 h 중 하나는 빨간 자동차가 자동차라고 가리키는 노드도 있을 것이고, 노란 자동차가 자동차라고 가리키는 노드도 있을 것입니다.
그리고 이것 모두를 W2에다가 다시 한번 집어넣으니, 이젠 더욱 다양한 물체들도 인식이 가능한 것이죠.
어휴.. 슬라이드 하나에만 말할 것이 이렇게나 많다니!! 싶으시죠?
이 중에서 이해가 잘 안 되시는 것이 있어도, 걱정 말고 넘기셔도 됩니다. 어차피 5강과 6강에 걸쳐 다시 한번씩 계속 계속 설명해 드릴 테니까요.
그러면, 레이어 두 개가 아니라 세 개를 만들고 싶으면 어떻게 하면 될까요?
미리 만들어뒀던 2-layer를 그냥 따와서, non-linear 한 함수에 집어넣고, 다시 다른 레이어로 덮어 씌우면 되겠지요?
그것이 위 사진 중 가장 아래 식인,
f=W3*max(0 , W2*max(0, W1x))입니다.
그러면, 4-layer은? 5-layer은?
마찬가지로, 위의 f값에서 레이어를 하나씩, 하나씩 더 씌우면 되겠지요?
그럼 이제 조금 더, 인간의 신경망(뉴런)과 비교해볼까요?
...라고 하고 싶지만... 저는 저 뉴런의 구조와 같은 쪽에는 그냥 아예 무지한지라.. 설명이 불가능하겠네요..
그냥 우리가 방금 했던 인공 신경망이 우리 두뇌의 신경망에서 따온 것이라는 것만 알면.. 되겠습니다.
일단 슬라이드는 이해용으로 올려놓겠습니다만.. 흨 ㅠㅠ
아! 여기서부턴 다시 설명 시작 가능하겠네요 ㅎㅎ
아까 전에 Activation function부분입니다!
ReLU, 왼쪽 아래에 보이시죠? 저게 아까 봤던 max(0, W1x) 부분을 그래프로 나타낸 것입니다.
저것처럼, sigmoid, tanh, Maxout 등 다양한 친구들이 있습니다!
아 근데, 이거 지금 자세하게 다룰 거 아니고, 6 강가면 지겹도록 다루니깐, 그때 가서 봐요!
그리고, 2 레이어 인공신경망/3 레이어 인공신경망의 구조입니다.
우선 당연하게도 input layer에서 입력값이 주어질 것이고,
그다음 hidden layer라는 곳에는 x*W1값이 들어가게 되고,
output layer에서는 (위의 예에서라면) W2*max(0, W1x)가 들어가서, 결국 output에서는 점수가 뙇! 하고 나오겠죠?
3 레이어도 마찬가지로, W1*x가 첫 번째 계산, W2*max(0, W1x)가 두 번째 계산, 마지막엔 W3*max(W2*max(0, W1x))가 계산되겠죠?
이처럼, 중간중간에 모든 노드가 다음의 모든 노드에 영향을 끼치는 레이어를 fully-connected layer라고 합니다!
위의 Neural Network의 예에서도, 모든 W값들이 다음 값들에 영향을 미쳤으니, 그것도 fully connected layer라고 할 수 있겠죠?
또, 2-layer개에는 히든 레이어가 1개, 3-layer에는 히든 레이어가 2개... 이므로,
각각 1-hidden-layer 인공신경망, 2-hidden-layer 인공신경망 이라고도 불린다네요.
자, 그래서 우리는 인공신경망의 대략적인 구조를 알아보았습니다.
더욱 자세한 내용은 5강, 6강에 걸쳐 나오므로, 일단 이 정도만 알고 계시면 되겠습니다(그래도 어느 정도는 이해하셔야 합니다!)
이제 다음 강좌 때는, cs231n 5강의 내용인, CNN(Convolutional Neural Network)에 대해 알아보도록 하겠습니다!
'인공지능 > 누구나 이해할 수 있는 딥러닝(cs231n)' 카테고리의 다른 글
누구나 이해할 수 있는 딥러닝 - cs231n 5강 (Convolutional Neural Networks, CNN) (2) | 2018.08.01 |
---|---|
누구나 이해할 수 있는 딥러닝 - cs231n 3강(Loss Functions and Optimization) (6) | 2018.07.17 |
누구나 이해할 수 있는 딥러닝 - cs231n 2강 (2) | 2018.07.15 |