반응형

Neural Network 학습은 입력 데이터에서 예측값을 만들고, cost function으로 오차를 계산한 뒤, gradient descent로 가중치와 bias를 조금씩 고치는 흐름입니다.

MNIST 예제에서는 28x28 손글씨 이미지를 입력으로 읽고, 정답 label과 network output의 차이를 줄이는 방향으로 파라미터를 조정하는 과정을 볼 수 있습니다.

 

핵심 정리

MNIST 데이터는 손글씨 숫자 이미지와 해당 숫자 label로 구성됩니다. Neural Network는 이미지를 입력으로 받아 숫자별 점수나 확률을 출력하고, 그 출력이 정답과 얼마나 다른지를 cost function으로 계산합니다. cost function 값이 작아질수록 예측이 정답에 가까워졌다고 볼 수 있습니다. gradient descent는 이 값을 줄이기 위해 각 weight와 bias를 어느 방향으로 바꿀지 찾는 방법입니다. 실제 네트워크에서는 파라미터가 하나둘이 아니라 매우 많기 때문에, 단순한 2차원 그래프보다 벡터와 행렬 관점으로 이해해야 합니다.

  • MNIST의 이미지는 28x28 크기의 회색조 손글씨 숫자입니다.
  • label은 각 이미지가 실제로 어떤 숫자인지 알려주는 정답입니다.
  • network output은 모델이 입력 이미지를 보고 낸 예측 결과입니다.
  • cost function은 예측과 정답 사이의 차이를 하나의 값으로 나타냅니다.
  • gradient descent는 cost를 줄이는 방향으로 파라미터를 갱신합니다.
  • weight와 bias가 많아질수록 미분과 행렬 계산이 핵심 도구가 됩니다.

원문은 코드와 수식이 바로 나오기 때문에 처음 읽는 사람이 cost function이 왜 필요한지 놓치기 쉬웠습니다. 이번 보강은 수식을 추가하지 않고 학습 흐름을 말로 먼저 정리해 기존 수식이 덜 갑작스럽게 보이도록 했습니다.

이어서 볼 글

 

예제 공부

이 링크보고 예제 공부중

http://carpedm20.github.io/2014/7/3/neural-net-translation/

http://yann.lecun.com/exdb/mnist/ 여기있는 data 파싱해봤다.

#include "SvCommon.h"

//http://yann.lecun.com/exdb/mnist/
//여기서 training set image 파싱해본 것
//
//train-images.idx3-ubyte 이미지들
//train-labels.idx1-ubyte 레이블들(이미지가 어떤 숫자인지 정답이 써있다.)

uint get_uint(FILE* fp)
{
 char buf[5] = {0};
 fread(buf, 4, 1, fp);
 uint r = *((int*)&buf);
 SvNumber::ChangeEndian(r);
 return r;
}

uchar get_uchar(FILE* fp)
{
 char buf[2] = { 0 };
 fread(buf, 1, 1, fp);
 return buf[0];
}

int main(void)
{
 SvGC gc(SvGC::GC_TYPE_WIN32_VGS);

 FILE* fp = fopen("train-images.idx3-ubyte", "rb");

 uint magic = get_uint(fp);
 SVASSERT(magic == 2051);

 uint image_cnt = get_uint(fp);
 SVASSERT(image_cnt == 60000);

 uint H = get_uint(fp);
 uint W = get_uint(fp);
 SVASSERT(H == 28 && W == 28);

 REP(i, image_cnt)
 {
  REP(y, H)REP(x, W)
  {
   uchar c = get_uchar(fp);
   gc.SetFGColor(255-c, 255-c, 255-c);
   gc.SetPixel(x, y);
  }
 }

 fclose(fp);

 return 0;
}

결과

cost function

\[ \begin{eqnarray} C(w,b) \equiv \frac{1}{2n} \sum_x \| y(x) - a\|^2 \end{eqnarray} \]

이게 뭐냐면... cost function이라는 건데 에러가 많으면 커지고 에러가 적을수록 0에 수렴한다.

우리의 목표는 이 cost function을 0에 가깝게 만드는 것.

w나 b는 파라미터이고 이걸 조정해서 우변을 0에 가깝게 만들면 된다.

우변의 n은 전체 data 사이즈고 (60000)

x는 숫자한개의 input 값이고(예를들면 숫자 8을 나타내는 28x28 gray scale image data)

y(x)는 x에 대한 정답이다.(숫자8)

a는 x가 input일때의 output이다(예를 들면 숫자 6)

gradient descent(경사 하강법)는 상기 cost function 최소화 하기 처럼 minimization problem에 적합한 기법이다.

단, **NN에서 경사하강법을 쓸 경우 변수가 1,2개가 아니라서 수학적 분석으로는 cost function을 최소화하기 어렵다.(w, b 두개가 아니냐고 할 수 있지만 실제로는 w와 b는 스칼라가 아닌 벡터 집합이라서 복잡하다.. 아래 다시 설명 나온다)**

실제 cost function은 복잡하므로 다음과 같이 2개의 변수(v1,v2)에만 의존하는 cost function C가 있다고 가정하고 

경사하강법을 적용하면 다음과 같은 형태가 된다.

\[ \begin{eqnarray} \Delta C \approx \frac{\partial C}{\partial v_1} \Delta v_1 + \frac{\partial C}{\partial v_2} \Delta v_2. \end{eqnarray} \]

 후에 적는글
y = x^2 + x + 2 이런 거에서 최소값 구할때 경사하강법을 쓴다는 의미는 도함수로 구한 경사대로 x값을 조금씩 바꿔가면서 y가 수렴될때까지 구하는걸 의미하고..
MINST문제에서 경사하강법을 쓴다는 의미는 다음과 같다
    y를 cost function C로 둔다.
    x에 해당하는게 모든 w랑 b이다 (굉장히 많다)
    현재 w,b에 대해서 도함수 경사를 구해서 구한 경사대로 w,b값을 조금씩 바꿔서 y가 수렴될때까지 진행한다.
        여기서 위의 다항식 경우와 다르게 도함수를 대수적으로 구하기는 non-linear라 불가능할테니.. 해석적으로 편미분하는 테크닉을 쓰는것
        그럼 현재 w,b에 대한 도함수값을 매번 (해석적으로) 빠르게 구하는게 중요할텐데 여기서 back propagation알고리즘이 쓰이는 것

여기서.. 위 식의 의미를 좀 더 생각해보자.

다음과 같이 변수가 x하나인 일반 함수가 있다고 하자.

$y = f(x) = x^n + ... + c$

특정 x근처에서 x의 변화량($\Delta x$)에 따른 y의 변화량($\Delta y$)을 구하고 싶으면, 다음과 같이 기울기(도함수)에 x의 변화량을 곱하면 될 것이다.

$\Delta y \approx f'(x) \times \Delta x$

왜냐하면 x근처에서 기울기가 급격히 높으면 약간의 x변화로도 y변화가 클 것이고,

기울기가 완만하면 큰 x변화로도 y변화가 작을 것인데.. 수식이 그걸 반영하고 있다.

다른 방법으로 도함수의 정의로 부터 생각해봐도 될 듯하다.

$f'(x) = \frac{d y}{d x}$ 이므로 $d y = f'(x) \times d x$ 이다.

$ \Delta C \approx \frac{\partial C}{\partial v_1} \Delta v_1 +\frac{\partial C}{\partial v_2} \Delta v_2.$

다시 원래 식으로 돌아와서.. C가 변수 하나(x)가 아닌 두 개(v1,v2)로 이루어진 다변수 함수라면,

대략적인 C의 변화량은 v1과 v2의 편도함수에다가 v1과 v2의 변화량을 각각 곱한것을 합산한 것이라는 걸 납득가능하다.

여기서의 v1, v2는 실제로는 모든 개별적인 w, b에 해당한다.

우리는 C를 0에 가깝게 만들고 싶으므로, $\Delta v_1$ 과 $\Delta v_2$ 를 잘 골라서 $\Delta C$를 음수로 만들고 싶다.

(그래서 결과적으로 골짜기 아래 계속까지 떨어뜨리고 싶다.)

기울기만 추려서 백터 표현으로 하면 다음과 같이 된다.

\[ \begin{eqnarray} \nabla C \equiv \left( \frac{\partial C}{\partial v_1}, \frac{\partial C}{\partial v_2} \right)^T. \end{eqnarray} \]

어려운건 아니고.. cost function C의 기울기는 각 변수(v1,v2)에 대한 편미분 도함수 집합(벡터)라는 뜻.

자 여기서 약간 어려워 지는데..

먼저 v의 움직임도 묶어서 벡터로 만들고 $\Delta v \equiv (\Delta v_1, \Delta v_2)^T$

위 식들을 살펴보면

\[ \begin{eqnarray} \nabla C \equiv \left( \frac{\partial C}{\partial v_1}, \frac{\partial C}{\partial v_2} \right)^T. \end{eqnarray} \]

에다가 $\Delta v \equiv (\Delta v_1, \Delta v_2)^T$ 를 곱하면.. 위의

\[ \begin{eqnarray} \Delta C \approx \frac{\partial C}{\partial v_1} \Delta v_1 + \frac{\partial C}{\partial v_2} \Delta v_2. \end{eqnarray} \]

이런 모양이 되는걸 알 수 있다.

정리해서 쓰면 다음과 같다.

\[ \begin{eqnarray} \Delta C \approx \nabla C \cdot \Delta v. \end{eqnarray} \]

이게 별로 어려울 건 없는 것이.. 함수라고 단순화해보면 대략적으로 y값의 변화량은 기울기 곱하기 x값의 변화량 이라는 건데..

위에서 그렇다는걸 이미 서술했다.

실제로는 C가 w와 b에 대한 함수이고, w와 b가 $w^l_{jk}, b^l_j$형태로 단순 스칼라가 아니라 벡터(집합)이므로

C를 편미분 한다는 것은 굉장히 많은 변수에 대한 편미분이 존재하고, 

C의 기울기 $\nabla C$ 를 구한다는 것은 만만찮은 작업이 될 것 같다.

learning rate

자 여기서 또 중요한 개념이 나오는데..

그렇다면 x의 변화량에 해당하는 $\Delta v$를 어떻게 잡으면 될까...

다음과 같이 잡았다고 해보자

\[ \begin{eqnarray} \Delta v = -\eta \nabla C, \end{eqnarray} \]

$\eta$는 작은 입실론 값인데 휴리스틱 파라미터고 learning rate라고 부른다. 어쨌든 작은 값을 부여하고.

기울기와 곱하면..

$\Delta C \approx \nabla C \cdot \Delta v = -\eta \nabla C \cdot \nabla C = -\eta \|\nabla C\|^2$

위에 식이 이렇게 변하는데.. 제곱항이 있으므로 $\Delta C$가 항상 0보다 같거나 작음이 보장된다!!

이방식으로 계속해서 v를 업데이트 해주면 계곡으로 공을 보낼 수 있다.

$ v' = v + \Delta v = v -\eta \nabla C. $

애초에 우리의 cost function( $ C(w,b) \equiv \frac{1}{2n} \sum_x \| y(x) - a\|^2$)은 w과 b의 함수였으므로 w와 b로 환산하면 다음과 같이 된다.

\[ \begin{eqnarray} w_k' = w_k-\eta \frac{\partial C}{\partial w_k} \\ b_l' = b_l-\eta \frac{\partial C}{\partial b_l}. \end{eqnarray} \]

근데 이 cost function을 보면.. 각 training input image 하나하나($x$) 마다 개별 cost ($C_x$)를 구해서 평균을 구하는 형태다.

$C_x \equiv \frac{\|y(x)-a\|^2}{2}$

$C = \frac{1}{n} \sum_x C_x$

근데 우리 training set을 보면개수가 60,000개나 되므로 무지하게 느릴 것이 예상된다.

cost $C$뿐만 아니라 기울기 $\nabla C$에 있어서도 사정은 비슷하다.

각각의 input에 대한 기울기($\nabla C_x$)를 구해서 평균을 구하는 방식이다.

$\nabla C = \frac{1}{n} \sum_x \nabla C_x$

그러므로 60,000개 전체가 아니라 일부 샘플만 가지고 평균을 구해서 $\nabla C$ 및 $C$를 구하자는 아이디어는 자연스럽게 나올 수 있다.(이는 학습 속도를 높이는 개념이된다.)

마치 국민선거 대신 여론조사를 하는 개념과도 비슷하다.

\[ \begin{eqnarray} \nabla C \approx \frac{1}{m} \sum_{j=1}^m \nabla C_{X_{j}}, \end{eqnarray} \]

전체 n개가 아닌 랜덤하게 선택된 일부 m개만 가지고 구한 기울기 $\nabla C$를 //stochastic gradient descent// 라고 한다.

(개별 input 이미지의 기울기가 아니라 평균의 개념이 들어감에 유의)

극단적으로 m=1이 되면, 단 한개의 input을 가지고 업데이트가 일어나고 이를 //online learning// 이라고 부른다.

http://www.deeplearning.net/tutorial/gettingstarted.html

이링크도 괜찮은듯.. 파이선으로 구현..

weight는 2개 node 인 layer에서 3개 node인 layer로 가는 경우 2 x 3 = 6개이다.

bias는 destination node의 결과를 판정할때 쓰이는 스레시홀드 값이기 때문에 input layer에는 없으며,

기타 레이어에는 node 하나당 1개 이다.

아래 자료 받아서 python으로 돌려보면 얘기된걸 돌려볼 수 있다.

전체 데이터 및 소스코드

반응형

+ Recent posts