deep learning

인공신경망 이해하기 (2) 퍼셉트론과 신경망

이전 글에서는 분류 문제를 해결하기 위해 간단한 선형 분류기를 만드는 데에 필요한 요소들을 다루었다. 이제 우리는 분류기(모형)를 학습시키기 위해서는 판별함수 s, 정규화 손실항이 포함된 손실함수 L 필요함을 알고 있다. 또한 학습 과정에서 최적화 과정(SGD )을 통해 손실이 작아지는 방향으로 가중치 W와 편향 b의 값을 반복적으로 업데이트할 수 있다.

직선(또는 hyperplane)으로 서로 다른 카테고리의 영역을 구획짓는 가장 단순한 형태의 선형 분류기를 만들어 학습시킨 결과, 붓꽃 분류 문제를 92.7% accuracy로 성공적으로 분류해낼 수 있었다. 그러나 직선으로 구획지을 수 없는 분류 문제에서는 매우 낮은 성능을 보였다.

이번 글에서는 직선으로 구획지을 수 없는 분류 문제를 해결하는 분류기를 다루면서 신경망 이론에 (드디어!) 발을 들이고자 한다.

 

  1. 계속 선형 분류기를 고집하기
  2. 선형 분류기를 넘어서
    1. 퍼셉트론과 활성화 함수
    2. 다중층 퍼셉트론
  3. 신경망 학습시키기
  4. 2층 신경망 구현

 

선형 분류기를 고집하기 (커널 트릭)

선형 분류기(linear classifier)라는 이름은 판별함수값이 가중치 w_i feature x_i 선형 조합으로 표현될 있었기 때문에 붙은 이름이었다. 약간의 꼼수를 쓰면, 선형 분류기가 곡선적으로 판별하도록 변형시킬 있다.

붓꽃 분류 문제로 돌아가보자. 붓꽃 데이터에는 4차원의 feature(x_1: 꽃받침 길이, x_2: 꽃받침 너비, x_3: 꽃잎 길이, x_4: 꽃잎 너비) 존재했다. 여기에 추가로 다섯 번째 feature x_5 추가해보자. 다섯 번째 feature 꽃잎 길이의 제곱, x_5 = (x_3)^2이다.

이제 우리의 feature 데이터는 5차원이 되었다. 데이터의 차원이 바뀌었을 뿐, 여전히 판별함수의 식은 s = XW + b로 동일하다. 판별함수 식이 여전히 선형조합의 형태이므로 이 분류기 또한 여전히 선형 분류기라고 할 수 있다.

스케치

 

그러나 내부를 들여다보면 이 선형 분류기는 직선적으로 카테고리를 구획짓지는 않는다.

번째 관찰의 번째 카테고리의 판별함수값을 보면 s_{i1} = \sum_{j} w_{ji} x_{ij} + b_i = w_{1i} x_{i1} + w_{2i} x_{i2} + w_{3i} x_{i3} + w_{4i} x_{i4} + w_{5i} x_{i5} + b_i이고 x_5 = (x_3)^2이므로, 판별함수는 다음과 같은 이차식(, 곡선 또는 곡면) 형태 띄게 된다.

s_{i1} = w_{5i} (x_{i3})^2 + w_{1i} x_{i1} + w_{2i} x_{i2} + w_{3i} x_{i3} + w_{4i} x_{i4} + b_i

단순히 판별함수에 학습시키는 인풋 데이터를 변형함으로써 곡선적으로 분류하는 선형 분류기를 만들 수 있는 것이다. 인풋 데이터를 일정 규칙에 따라 변형시켜주는 함수를 커널 함수(kernel function)라고 하며 커널 함수를 사용해서 곡선적으로 분류하는 선형분류기를 만드는 것을 ‘커널 트릭(kernel trick)을 사용한다’고 한다.

XOR 문제

‘exclusive OR (XOR)’라고 불리는 다음과 같은 문제가 있다. 이런 형태의 데이터는 하나의 함수만으로는 분류가 불가능하다.

스케치

하지만 다항(polynomial) 커널을 사용해서 feature를 변형하면 직선적으로 분류가 가능해진다. 다항 커널을 사용해서 변형한 feature 값에 softmax 선형 분류기를 구현한 다음, 변형하기 이전 원래 feature 값에 판별 hyperplane을 나타내보면 아래처럼 곡선적으로 분류가 되었음을 확인할 수 있다.

poly_softmax

 

 

선형 분류기를 넘어서

똑같은 선형 분류기를 사용해도 단순히 인풋 데이터를 변형하기만 해도 몇몇 형태의 곡선적 데이터는 성공적으로 분류할 수 있다. 그러나 커널 트릭은 근본적인 해결책은 되지 못한다. 분류기의 형태는 여전히 단순 선형조합만으로 표현되므로, 커널 트릭으로 해결할 수 있는 곡선적 분류 문제는 극히 일부이다. 따라서 우리는 모든 경우에도 높은 성능을 내는 비선형 분류기(non-linear classifier)를 구현할 필요가 있다.

어떤 형태의 곡선적 또는 비선형 문제든지 모두 학습이 가능하도록 고안된 분류 모형 인공신경망(Artifical Neural Network; ANN)이다.

퍼셉트론

인공신경망에 다이빙하기 전에 퍼셉트론의 개념을 다룰 필요가 있다. 퍼셉트론(perceptron; 또는 그냥 neuron이라고도 )은 시신경세포를 수학적으로 비유/모델링하는 과정에서 탄생한 분류기이다. 실제 시신경세포의 작용과는 (당연히) 큰 차이가 있다. 입력 정보의 강도에 따라 출력 여부가 결정된다는 점(, 출력이 thresholding된다는 점)에 착안해서 만들어진 분류기라고 이해하면 좋다.

스케치

퍼셉트론 하나의 판별함수는 다음과 같이 식으로 나타낼 수 있다.

s = f(XW + b)

가중치 W feature X의 선형조합 XW + b에 함수 f를 씌운 형태이다. 여기서 함수 f는 출력의 여부 및 세기를 결정(뉴런으로 비유하자면 활성화 여부와 정도를 결정)한다고 해서 활성화 함수(activation function)라고 부른다. 활성화 함수로는 항상 비선형 함수를 사용한다.

활성화 함수를 softmax 함수로 설정하고 손실함수를 cross-category loss(L_i = - \sum_{j} p_{y_i} log{p_j}) 설정한 퍼셉트론은 앞서 구현한 softmax 분류기와 동일한 분류기가 된다. 비슷한 방법으로 손실함수를 max-margin loss 설정하면 퍼셉트론은 서포트 벡터 머신이 된다. 결국 퍼셉트론은 선형 분류기에 약간의 비선형 트윅(활성화 함수) 가한, 선형 분류기의 연장이다.

로지스틱 함수 외에도 쌍곡탄젠트 함수 등 몇 가지 활성화 함수가 제시되어 있지만 일반적으로 가장 많이 사용하는건 ReLU(Rectified Linear Unit)라는 녀석이다. ReLU activation을 식으로 나타내면 다음과 같고, 이는 0 이상 강도의 신호만을 출력하게 하는 0-역치값(zero-threshold) 역할을 한다.

스케치

다중층 퍼셉트론: 신경망

, 다시 XOR 문제로 돌아가보자. 지금까지의 내용을 정리해보면 이렇다.

  1. XOR 문제는 하나의 판별함수로는 분류할 수 없는 문제다 (두 개 이상의 함수가 필요하다).
  2. 퍼셉트론은 시신경세포에 대한 매우 단순한 수학적 모형이다.
  3. 퍼셉트론은 선형 분류기에 비선형 변형을 가한 출력값을 반환한다 (비선형 함수값을 준다).

이 내용을 보고 이렇게 생각해볼 수 있다:

  1. 그럼 함수 두 개 이상을 만들면 되겠네.
  2. 신경뭉치(더 나아가서, )처럼 퍼셉트론을 여러개 연결시키면 어떨까?
  3. 퍼셉트론은 곧 비선형 함수 한 개니까, 퍼셉트론 뭉치는 두 개 이상의 함수의 조합이겠네.
  4. 그럼 퍼셉트론 뭉치로 XOR 포함한 비선형 분류 문제를 해결할 있겠다!

이렇게 해서 퍼셉트론을 여러 쌓아 하나의 거대한 비선형 분류기를 만들 있다. 이를 다중층 퍼셉트론(multi-layer perceptron; MLP) 또는 신경망(Neural Network; NeuralNet; NN)이라고 부른다.

신경망은 다음과 같은 구성으로 이루어져 있다.

스케치

  • 입력층(input layer): 학습 데이터 feature를 입력받는 층이다. Feature의 차원 수(붓꽃 데이터의 경우 4)만큼의 뉴런 갯수를 가진다. 입력 층은 MLP 당 하나 뿐이다.
  • 은닉층(hidden layer): 입력층과 출력층 사이의 모든 층을 뜻한다. 입력층에서 입력받은 raw data에 대해 다수의 비선형 판별함수가 학습되는 층이다. 그림의 신경망에는 각각 6개 뉴런을 가지는 2개의 은닉층이 있다.
  • 출력층(output layer): 데이터에 대해 각 카테고리에 대응하는 판별함수값을 출력하는 층이다. 카테고리 수(붓꽃 데이터의 경우 3)만큼의 뉴런 갯수를 가진다. 출력층도 입력층과 같이 MLP 당 하나 뿐이다. 출력층에 있는 뉴런은 활성화함수를 가지지 않는 경우가 일반적이다.
  • 신경망은 “n-층 신경망”과 같이 층 갯수로 이름을 붙인다. 이 때 입력층은 갯수를 셀 때 포함하지 않는다. 그림의 신경망은 3 신경망이다.
  • 같은 층에 있는 뉴런끼리는 연결되어 있지 않다.
  • 한 층에 있는 뉴런은 다음 층에 있는 모든 뉴런과 연결된다.
  • 뉴런의 출력은 방향(출력층 -> 은닉층1 -> 은닉층2 -> … -> 출력층)으로만 전파된다.

은닉층이 하나 있는 2-layer neural net 식으로 다음과 같이 표현할 있다.

s = hW_2 + b_2 = f(XW_1 + b_1)W_2 + b_2

일반적인 n-layer neural net 다음과 같이 표현 가능하다.

s = h_{n-1}W_n + b_n = f_{n-1}(h_{n-2}W_{n-1} + b_{n-1})W_n + b_n = ...

활성화함수의 중요성이 여기서 드러난다. 비선형 활성화함수가 매 층 사이에 존재하지 않는다면 위의 식은 결국 가중치와 feature의 선형조합으로 정리된다. 다시 말해 활성화함수가 없다면 신경망은 선형 분류기와 동일해진다. 활성화함수가 신경망 분류모형에 비선형성(non-linearity)를 제공한다고 이해할 수 있는 대목이다. 이론적으로 하나 이상의 은닉층을 갖는 신경망으로 존재하는 모든 비선형 함수를 근사할 있음이 증명되어 있다.

Feature 데이터는 입력층 -> 은닉층 -> 출력층의 순서로 전파되어 판별함수값 s로 변환되며, 이 과정을 일컬어 ‘feed-forward’라고 한다.

 

신경망 학습시키기

신경망을 학습시키는 데에도 선형 분류기를 학습시킬 때와 마찬가지로 손실함수값 L를 계산하고, 손실함수값 L의 가중치 W에 대한 그라디언트를 계산해야한다. 계산한 그라디언트의 반대 방향으로 반복적으로 가중치를 업데이트하면 우수한 성능을 내는 신경망 분류기를 얻을 수 있을 것이다.

그런데 신경망에서의 그라디언트 계산은 선형 분류기에 비해 복잡하다. 한 차례 편미분으로 쉽게 그라디언트를 구할 수 있었던 선형 분류기에서와 달리, 신경망의 손실함수는 가중치 W로 직접 편미분하기에는 식이 복잡하다.

그래서 신경망의 그라디언트는 미분의 연쇄법칙(chain rule)을 사용해서 단계적으로 계산한다.

선형 분류기의 예시

비교적 단순한 예시부터 살펴보자.

앞서 구현한 선형 Softmax 분류기는 은닉층이 없는 신경망이라고 생각할 있다. 손실함수로 softmax 손실 + Ridge 정규화 손실(L = \sum_i L_i + \alpha R(W), L_i = - \log{\frac{e^{f_{y_i}}}{\sum_j e^{f_j}}}, R(W) = \sum_i \sum_j w_{ij}^2 + \sum_k b_k^2) 둔다고 , 선형 분류기의 feed-forward 아래와 같이 왼쪽(입력측)에서 오른쪽(출력층) 방향으로 일어난다.

Image

그라디언트의 계산은 feed-forward반대 방향으로 일어난다: 출력층에서 입력층의 방향으로 단계적으로 계산된다.

Image

연쇄법칙에 의해 \frac{\partial L}{\partial W} = \frac{1}{N} \sum_i \frac{\partial L_i}{\partial W} + \frac{\partial R(W)}{\partial W} = \frac{1}{N} \sum_i \frac{\partial L_i}{\partial f} \frac{\partial f}{\partial W} + \frac{\partial R(W)}{\partial W} 그라디언트를 계산할 있다.

2-layer Neural Net 예시

신경망에서도 똑같은 방법으로 역전파할 수 있다. 그림은 좀 더 복잡하다.

Image

이처럼 연쇄법칙을 사용해서 단계적으로, 출력층에서 입력층 방향으로 그라디언트 값을 전파하는 계산법을 역전파(back-propagation; backprop)이라고 한다.

 

2-layer Neural Net 구현

붓꽃 분류 문제

판별함수(신경망 구조)와 손실함수도 정의했고 그라디언트 계산법도 알았으니 이제 직접 붓꽃 종을 분류하는 신경망을 구현해볼 시간이다. 선형 분류기를 구현했을 때와 마찬가지로 붓꽃 측정치 중에서 2개의 차원(꽃받침 길이, 꽃잎 길이)만을 사용했다.

  • 데이터 손실로 softmax loss 가지고
  • 정규화 손실로 Ridge 정규화항을 가지며,
  • 2개 뉴런이 있는 입력층 하나와
  • 100개 뉴런이 있는 은닉층 하나와
  • 3개 뉴런이 있는 출력층을 가지는,
  • back-propagation으로 그라디언트를 계산하여 가중치를 업데이트하는

2층 신경망을 구현한 코드는 아래와 같다.

def train_nn(x, y, D, K, reg=.001, eta=.05, epochs=5000):
    # initialize weights
    W1 = np.random.randn(D, 100) * 0.01
    b1 = np.zeros((1, 100))
    W2 = np.random.randn(100, K) * 0.01
    b2 = np.zeros((1, K))

    # training process
    losses = []

    for epoch in range(epochs):
        h = np.maximum(0, x.dot(W1) + b1) # hidden layer
        f = h.dot(W2) + b2 # final layer

        # backprop to hidden layer
        p = np.exp(f) / np.sum(np.exp(f), axis=1, keepdims=True)
        dhidden = p.copy()
        dhidden[range(x.shape[0]), y] -= 1
        dhidden /= x.shape[0]
        dW2 = (h.T).dot(dhidden) + reg * W2
        db2 = np.sum(dhidden, axis=0, keepdims=True)

        # backprop the activation (relu)
        drelu = (dhidden).dot(W2.T)
        drelu[h <= 0] = 0

        # backprop to input layer
        dW1 = (x.T).dot(drelu) + reg * W1
        db1 = np.sum(drelu, axis=0, keepdims=True)

        # update weights
        W1 -= eta * dW1; b1 -= eta * db1
        W2 -= eta * dW2; b2 -= eta * db2

        # compute loss
        data_loss = -np.sum(np.log(p[range(x.shape[0]), y])) / x.shape[0]
        reg_loss = 0.5 * reg * (np.sum(W2**2) + np.sum(W1**2))
        loss = data_loss + reg_loss
        losses.append(loss)
        if epoch % 1000 == 0:
            print("{}: loss={}".format(epoch, loss))
 
    return W1, b1, W2, b2, losses

output_19_1

학습시킨 신경망으로 붓꽃 종을 분류한 결과 96% accuracy를 얻을 수 있었다 (선형 분류기에서는 92.7%였다).

자동으로 그라디언트를 계산해주는 Tensorflow등의 프레임워크를 사용하면 더 간단히 구현할 수 있다. 거기에 Keras와 같은 high-level 프레임워크를 사용하면 훨씬 더 간단히 구현할 수 있다. 그냥 구현은 남에게 맡기고 간단히 체험만 해보고싶다면 구글에서 제공하는 웹페이지에서 클릭 몇 번으로 간단한 신경망을 학습시킬 수 있다.

비선형 데이터 분류 문제

붓꽃 분류 문제는 선형 분류기로도 쉽게 해결할 수 있었다. 신경망은 비선형 분류 문제에서 더욱 빛난다. 선형 분류기를 사용했을 때는 엉망진창으로 분류되던 데이터가 신경망을 사용한 분류에서는 매우 높은 accuracy (~99%)로 해결되는 것을 확인할 수 있다.

지금까지 가장 단순한 신경망 구조인 MLP를 이용해서 비선형 분류 문제를 해결해 보았다. 다음 글에서는 신경망 구조를 학습시킬 때 주의깊게 살펴야 하는 점들에 대해 다루어보겠다.

 

참고

  • 이 글은 CS231n 강의록을 매우 많이 참고했다. 원 강의록을 읽어보시기를 강하게 추천드린다.
  • polynomial kernel을 사용한 softmax classifier 및 2-layer neural net를 구현한 전체 코드는 이 노트북에서 확인할 수 있다.
  • 애니메이션을 만들어보면 decision hyperplane이 학습되고 있는 상황을 확인할 수 있다. 꽤 재미지고 신기하다.

Animated GIF-downsized_large

 

인공신경망 이해하기 (1) 선형 분류기

인공지능이 알파고의 형태로 대중에 모습을 드러내 굉장한 충격을 가져다 준 이후, 인공지능에 대한 관심은 그야말로 폭발했다. 조류 인플루엔자, 어도비 일러스트레이터의 약자로 더 자주 쓰였던 AI는 대부분의 경우 인공지능을 뜻하게 되었다.

그러나 단순한 신경망 구조는 생각보다는 어렵지 않은 개념임에도 인공지능이라는 단어에서 오는 중압감과 다소 투박하게 표현된 수식 때문인지, 엔지니어 분야 밖의 대중적인 개념이 되는 데에는 실패한 듯하다.

여기서는 인공지능에 접점이 없었던 사람을 대상으로 현대 인공지능의 시작과 끝이라 할 수 있는 인공신경망(artificial neural network; ANN)의 개념을 여러 글에 거쳐 풀이해보고자 한다. 작성자 본인도 부족한 학생인지라 되도록 직관으로 이해가능하게 작성하려고 노력했다.

  1. 해결하고자 하는 문제
  2. 직선적 판별
  3. 올바른 분류법을 ‘배우기위해서 필요한 것들
    1. Weight과 bias
    2. Loss function
    3. Regularization
    4. Gradient descent optimization
  4. 선형 분류기 (중 softmax 분류기) 구현
  5. 비선형 분류기의 필요성

 

들어가기 전에

쉽게 설명하겠다는 명목 하에 개념 설명에 필수적인 내용을 빼먹는 건 설명의 본분을 다하지 않는거라 생각한다. (슬프게도?) 주제가 주제이다보니 제대로 이해하기 위해서는 수학과 컴퓨팅에 대한 기초가 필요하긴 하다.

행렬 연산, 미분에 대한 기초가 있으면 이해에는 큰 어려움이 없을 거라 생각한다. 덧붙여 기하적 해석이 가능하면 더욱 좋다. , 어떤 것이든 사용하는 데에 불편함이 없는 프로그래밍 언어가 하나 있으면 좋다. 여기서는 코드가 필요한 경우 Python 2.7.x 문법과 패키지를 사용했다.

 

해결하고자 하는 문제

여기서 신경망으로 풀어보려 하는 문제는 분류(classification). 분류 문제는 이전의 관찰 데이터를 바탕으로 새로운 관찰이 어떤 카테고리에 속하는지를 예측하는 문제다. 이 때 이전의 관찰 데이터에는 각각의 관찰이 어떤 카테고리에 속한 것이었는지에 대한 정보(라벨)가 함께 제공되어야 한다.

  • 스팸 메일 예측이 분류 문제의 대표적인 예시다. 지금까지 받은 모든 메일들(이전의 관찰 데이터)을 바탕으로 새로 온 메일(새로운 관찰)이 스팸인지 아닌지를 분류하는 것이다. 이 때, 지금까지 받은 메일들이 스팸인지 아닌지(‘라벨이라 한다)는 알고있어야 한다(라벨 정보가 있어야함).
  • 동식물의 종을 맞추는 문제도 분류 문제의 일종이다. 붓꽃과에 속하는 3개 식물종의 꽃잎 너비와 길이, 꽃받침 너비와 길이에 대한 측정치(이전의 관찰 데이터)를 바탕으로 새로 관찰한 붓꽃과 식물(새로운 관찰) 3개종 중 어느 종일지를 추측할 수 있다. 역시나 각각의 측정치(특징또는 ‘feature’라 부른다)가 어떤 식물종의 개체로부터 측정된 것인지에 대한 정보(라벨)는 알고 있어야 한다.

스케치

아주 단순화한 분류 문제의 해결 흐름은 다음과 같다.

  1. 이전의 관찰 데이터를 준비한다.
  2. 이전 데이터를 바탕으로 각 카테고리에 속한 관찰들의 특징을 알고리즘이학습한다‘.
  3. 알고리즘이 학습한 내용을 바탕으로 새로운 관찰이 어떤 카테고리에 속할지 예측한다.

위에서 언급한 붓꽃과 식물의 측정 문제를 통해서 기계학습의 기초와 신경망 이론을 다룰 것이다. 이제 관찰 데이터는 준비가 됐고, 올바르게 종을 분류하는 분류기를 만들 시간이다.

 

가장 단순한 분류법 – 직선적 분류

꽃잎, 꽃받침 길이와 너비라는 수치 데이터를 보고 종을 분류하는 문제에서, 가장 먼저 단순하게 생각해 볼 수 있는 분류기는 직선적으로 데이터를 구획해주는 놈이다.

스케치

, 직선(데이터가 3차원인 경우는 평면, 4차원 이상의 데이터에서는 hyperplane)을 그어 서로 다른 라벨을 지닌 데이터를 분리해주는 것이다.

데이터를 구획해주는 직선(또는 평면, 또는 hyperplane) 함수를 우리는 판별 함수 (decision function) 부른다. 각 관찰에 대한 판별함수값은 판별 점수(decision score), 또는 클래스 점수(class score; 관찰이 해당 클래스=카테고리에 속할 가능성)라고 부르기도 한다.

선형 판별함수는 우리가 익히 알고 있는 다음과 같은 꼴의 식으로 표현할 수 있다.

s = wx + b (2차원 데이터에서, 직선 판별함수의 경우)

s = w_1x_1 + w_2x_2 + b (3차원 데이터에서, 평면 판별함수의 경우)

여기서 s 관찰 값에 대한 판별 점수, x 관찰의 features 데이터, w, b 각각 판별함수의기울기절편이다.

이 판별함수를 고차원에 대해 일반화해서 다음과 같이 행렬식으로 간단히 표현할 수 있다.

s = XW + b

스케치

 

 

여기서 s 관찰 값에 대한 판별 점수 행렬, X 관찰한 features 행렬, W, b 각각 판별함수의기울기‘(?) 행렬과절편‘(?) 벡터이다.

직선의 경우기울기절편이라 표현하는 것이 직관적이나, hyperplane에서는 표현이 직관적이지 않으므로 이제부터는 W가중치 (weight)’ 행렬, b편향 (bias)’ 벡터라 부르기로 한다.

위의 판별함수는 데이터의 차원만 다를 뿐, 모두 가중치 w_i feature x_i의 선형조합의 꼴로 표현할수 있으므로 선형 판별함수라 할 수 있다.

, 이제 우리는 다음과 같이 선형 분류기의 뼈대를 만들었다.

s = XW + b

이제는 이 분류기가 붓꽃 종을 올바르게 예측할 수 있도록 각 붓꽃 종의 특징을 판별함수에학습시킬차례다.

가중치와 편향을 이해하기

가중치 w_i “i번째 feature가 라벨의 예측에 끼치는 영향이라고 해석할 수 있다. i번째 가중치값 w_i의 값의 절대값이 클 수록 i번째 feature가 예측에 미치는 영향이 크다고 할 수 있고, 따라서 i번째 feature가 라벨의 예측에 중요한 정보라고 판단할 수 있다. 또한 가중치값의 부호에 따라 예측에 미치는 영향이 양의 영향인지, 음의 영향인지 알 수 있다.

편향 b_i에 대한 해석은 가중치에 비해서는 덜 명확하다. 편향 b_i 값은 i번째 feature x_i의 값이 0일 때 예측되는 라벨의 값으로 이해할 수 있다. 분류기 식에서 편향을 제거한다면 (즉 위의 붓꽃 예시에서 b_i = 0, i = 1,2,3,4 이면) 판별함수는 항상 원점을 지나는 형태일 것이다. 따라서 편향은 기하적으로는 판별함수가 원점을 지나지 않아도 되도록 해주는 역할을 한다고 이해할 수 있다.

우리가 세운 선형 분류기 식에서, X는 관측된 데이터이므로 마음대로 바꿀 수 있는 값이 아니다. 대신분류기가 데이터 x_i를 보고 학습함에 따라 새로운 관찰을 더 정확히 분류할 수 있는 방향으로 가중치 w_i와 편향 b_i의 값이 변하게 된다. 기하적으로는 더 정확히 판별 직선(혹은 평면, 또는 hyperplane)을 긋는 방향으로 기울기와 절편 값이 변한다고 이해할 수 있다.

스케치

그렇다면 어떻게 해야 더 분류를 잘 하는 방향으로 가중치와 편향 값을 변화시킬 수 있을까? 어떻게 해야 선형 분류기를 학습시킬 수 있을까?

손실 함수 (loss function)

선형 분류기가 학습을 하고 있는지, 즉 더 나은 방향으로 선형 분류기의 가중치와 편향 값이 변하고 있는지를 판단하기 위해서는 분류기의 성능을 평가하는 손실 함수(loss function)를 설정해야 한다.

손실 함수는 분류기의 성능이 낮을수록 손실 함수 값이 커지는 특성을 가져야 한다 (분류기의 성능이 높을수록 손실 함수 값이 작아져야 한다). 결국 손실 함수의 값이 크다는 것은 분류기가 카테고리를 잘 예측하지 못하고 있다는 것을 의미한다그래서 이름이손실 함수!

손실 함수를 어떻게 설정하느냐에 따라 선형 분류기의 특성이 달라진다.

판별함수값을확률이라고 생각하기

각 샘플의 판별함수값을 해당 카테고리에 속할확률이라고 해석할 수 있다. 이 때 샘플이 k번째 카테고리에 속했을 확률 p_k는 다음과 같다.

p_k = \frac{e^{s_k}}{\sum_{j} e^{s_j}}

여기서 s_k는 해당 샘플의 k번째 카테고리에 대응하는 판별함수값이다. p_k [0, 1] 사이의 값을 가지므로 일종의확률또는확신의 정도라고 해석할 수 있다.

계속해서 i번째 샘플의 손실 L_i은 다음과 같이 설정할 수 있다.

L_i = - \log{{e^{s_{y_i}}} \over {\sum_{j} e^{s_j}}} = - \log{p_{y_i}}

여기서 s_{y_i} i번째 샘플의 진짜 라벨(실제 속해있는 카테고리)의 판별함수값, s_j j번째 카테고리의 판별함수값이다. 따라서 i번째 샘플의 손실 L_i카테고리를 올바르게 예측했을 확률의 로그값에 음수를 취한 것이다.

최종적으로 전체 샘플 N개의 손실 L은 각 샘플의 손실의 평균치로 계산한다.

L = \frac{1}{N} \sum_{i} {L_i} = - \frac{1}{N} \sum_{i} \log{{e^{s_{y_i}}} \over {\sum_{j} e^{s_j}}} = - \frac{1}{N} \sum_{i} \log{p_{y_i}}

손실함수 L의 값은 따라서 카테고리를 올바르게 예측했을 확률의 로그값의 평균에 음수를 취한 것이라 해석할 수 있다. 이 값은 분류기가 샘플들의 카테고리를 잘 예측할 때 작아지고 예측 성능이 나쁠수록 커진다.

여기서 f(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}} 꼴의 함수를 softmax 함수라고 부르기에 손실함수를 softmax 손실함수 칭한다. Softmax 손실함수를 사용하는 선형 분류기는 Softmax 분류기(‘다중 클래스 로지스틱 회귀라고도 ) 된다.

당연히, softmax 손실함수 외에도 수많은 손실함수가 존재한다. 일례로 max-margin 손실함수를 사용하는 선형 분류기는 서포트 벡터 머신(support vector machine; SVM) 된다.

다른 손실함수는 차차 다루기로 하고 여기서는 softmax 손실을 사용하기로 한다.

정규화 손실 추가하기

feature:label 데이터쌍만으로 손실함수를 만들면 학습시킨 데이터에서만 높은 성능을 내도록 분류기가 필요 이상의 학습을 하게 될 수도 있다. 학습 데이터에서 실제 카테고리 예측과는 상관이 없는 노이즈까지 학습하는 이 현상을 과적화(overfitting)라 한다.

스케치

따라서 오버피팅이 발생하지 않도록 손실함수에 제약을 줘야한다. 되도록 단순한 형태의 판별함수가 되도록 손실함수에 제약을 주는 것을 정규화한다(regularize)고 한다.

가장 단순한 정규화는 가중치의 제곱합이 커질수록 손실함수가 커지도록 다음의 정규화 손실 R(w) 항을 손실함수에 추가하는 것이다.

R(w) = \sum_{i} \sum_{j} w_{ij}^2 + \sum_{k} b_k^2

여기서 w_{ij}는 가중치 행렬 W i j열 성분, b_k는 편향 벡터 b k번째 성분이다. 이 방식을 Ridge 정규화 (또는 L2 정규)라고 하며 전체적으로 고르고 작은 값의 가중치로 이루어진 가중치 행렬을 선호하는 방향으로 분류기를 정규화한다.

Ridge 최적화를 적용한 최종 손실함수는 다음과 같이 표현된다.

L = \frac{1}{N} \sum_{i} L_i + \lambda R(w)

여기서 \lambda 0 이상의 값으로 정규화 강도 (regularization strength)라고 하며 정규화 손실과 데이터 손실 사이의 균형을 맞추는 역할을 한다. \lambda 값이 클수록 정규화의 강도가 강해진다.

Ridge 외에도 Lasso, Elastic Net 다양한 정규화 방법이 있다. 이에 대해서는 추후에 살펴보기로 한다.

손실함수를 설정한 후엔 선형 분류기를 학습시키면 된다.

 

수치적 최적화 – 경사 하강법

분류기를 학습시킨다는 것은 손실함수값을 작게 만드는 가중치, 편향값을 찾는 것을 의미한다. 이상적인 가중치, 편향의 값은 손실함수를 최소로 하는 값(arg\max_{w} L)이다. 분류기를 학습시킨다는 것은손실함수에 대한 W, b의 최적화 문제이다.

많은 경우 손실함수를 분석적으로 최적화하는 것은 어렵다. 손실함수에 미분불가능한 구간이 존재하거나 분석적으로 해를 구하기 복잡할 수 있기 때문이다 (아예 전역해가 존재하지 않을 수도 있다). 대신 수치적으로 손실함수를 최적화할 수 있다.

수치적 최적화의 가장 단순한 형태는 경사 하강법(gradient descent optimization)이다. 손실함수 L W b 대해 편미분하여 경사(gradient; 증가율과 같은 개념) \frac{\partial L}{\partial W} \frac{\partial L}{\partial b} 계산한 다음, 경사의 반대 방향으로 가중치를굴러 떨어뜨리는것이다.

스케치

편의상 그림에서는 오목함수의 예시를 보였지만 미분불가능한 구간이 있는 함수도 이 방법으로 최적화할 수 있다.

가중치를굴러 떨어뜨려서새로운 값으로 업데이트하는 과정을 식으로 표현하면 다음과 같다.

W_{new} = W_{old} - \eta \frac{\partial L}{\partial W}

b_{new} = b_{old} - \eta \frac{\partial L}{\partial b}

여기서 \eta학습률(learning rate)라고 부르고 가중치 값을 얼마나 크게 이동할 것인지를 결정하는 역할을 한다. 손실함수가 로컬 최솟값으로 수렴할 때까지 가중치 업데이트를 반복하면 수치적 최적화를 수행할 수 있다.

실제로 가중치 업데이트를 할 때는 제한된 메모리를 이유로 위와 같이 전체 가중치 값 전체 W를 사용하는 대신 이 중 일부만을 무작위로 선택해서 경사를 계산, 업데이트 하는 경우가 대부분이다. 매 업데이트 시에 가중치 중 하나 W_{ij}만을 선택해서 경사를 계산하는 경우, 다음과 같이 식으로 표현할 수 있다.

W_{new} = W_{old} - \eta \frac{\partial L}{\partial W_{ij}}

b_{new} = b_{old} - \eta \frac{\partial L}{\partial b_{k}}

이 방법을 확률적 경사하강법 (Stochastic gradient descent; SGD)이라 한다. 이 경우 경사의 정확도는 일반 경사하강법보다 떨어지지만 훨씬 적은 메모리로 빠르게 경사를 계산해낼 수 있고, 실시간으로 새로이 추가된 관찰값을 이용하여 가중치를 업데이트할 수 있다는 장점이 있다.

이 외에도 단순 경사 하강법보다 훨씬 좋은 수치적 최적화 방법들이 다수 있으나 추후에 다루기로 한다.

붓꽃 데이터의 예시에서는 메모리가 크게 필요치 않으므로 둘 중 어떤 방법을 선택하든 문제없다.

 

여기까지 선형 분류기를 만들고 학습시키는 데에 필요한 최소한의 내용을 다루었다. 이제는 직접 분류기를 구현해보자.

 

선형 분류기 구현

  1. 선형 판별함수(s = XW + b) 사용하고,
  2. Softmax 손실함수(L_i = - \frac{1}{N} \sum_{i} \log{{e^{s_{y_i}}} \over {\sum_{j} e^{s_j}}})
  3. Ridge 최적화(R(w) = \sum_{i} \sum_{j} w_{ij}^2 + \sum_{k} b_k^2)를 적용하여 손실함수를 설정했으며,
  4. 경사하강법으로 가중치를 업데이트하는

붓꽃 분류기를 구현한 결과는 아래와 같다. 전체 4차원의 feature 중 2차원(꽃받침 길이, 꽃잎 길이)만을 feature로 사용했다.

N = 150 # number of samples per class
D = 2 # feature dimension
K = 3 # number of classes

reg = 0.05 # regularization strength
eta = 0.05 # learning rate

# initialize weights (and bias)
W = np.random.randn(D, K) * 0.01
b = np.zeros(K)

# training process
losses = []
for epoch in range(1000):
    # construct linear decision function
    s = X.dot(W) + b

    # compute gradients (backpropagation / chain rule)
    p = np.exp(s) / np.sum(np.exp(s), axis=1, keepdims=True)
    I = np.zeros(p.shape)
    I[range(X.shape[0]), y] = 1
    df = (p - I) / X.shape[0]

    dW = (X.T).dot(df)
    dW += reg * W
    db = np.sum(df, axis=0)

    # update weights by gradient descent
    W -= eta * dW
    b -= eta * db

    # calculate and print loss
    data_loss = -np.sum(np.log(p[range(X.shape[0]), y])) / X.shape[0]
    reg_loss = np.sum(0.5 * reg * (W**2))
    loss = data_loss + reg_loss
    losses.append(loss)
    if epoch % 100 == 0:
        print "{}: loss={}".format(epoch, loss)
SoftmaxClass

그림의 각 데이터 포인트의 색은 진짜 붓꽃 종, 배경에 칠해진 색은 선형 분류기가 예측한 각 붓꽃 종의 영역이다.

그 결과 92.7%의 accuracy를 획득할 수 있었다.

(편의상 training set, testing set, validation set을 분리하지 않고 모든 데이터를 학습시켰다. 제대로 구현하고 성능평가 하려면 학습 전 데이터셋 분리부터 해야한다.)

 

비선형 분류기의 필요성

현실의 데이터가 직선적으로 분류 가능한 경우는 매우 드물다. 직선으로 구획하기 어려운 데이터에서 선형 분류기의 성능은 정말이지 처참하다.

커널 트릭(kernel trick) 등 학습 데이터를 변형하는 방법을 포함해 비선형 데이터를 효과적으로 분류-예측하기 위해 다양한 방법들이 연구되어왔다. 이 글 시리즈의 핵심 개념인 ANN 역시 비선형 함수를 표현하기 위해 고안된 방법 중 하나다.

다음 글에서는 직선적이지 않은 분류 문제를 다루는 것으로 시작해서 신경망의 개념과 함께 신경망을 이용한 간단한 비선형 분류기를 구현하기까지를 건드려보겠다.

 

참고