빅데이타 & 머신러닝/머신러닝

수학포기자를 위한 딥러닝-#4 로지스틱 회귀를 이용한 분류 모델

Terry Cho 2016. 10. 10. 14:14

수포자를 위한 딥러닝

#4 - 로지스틱 회귀를 이용한 이항 분류 문제의 해결

조대협 (http://bcho.tistory.com)


1장에서 머신러닝의 종류는 결과값의 타입이 연속형인 Regression (회귀) 문제와, 몇가지 정해진 분류로 결과(이산형)가 나오는 Classification(분류) 문제가 있다고 하였다. 2,3장에 걸쳐서 회귀 문제에 대해서 알아보았고, 이번장에서는 로지스틱 회귀를 이용한 분류 문제에 대해서 알아보자.

이 글의 내용은 Sung.Kim 교수님의 “모두를 위한 딥러닝”(http://hunkim.github.io/ml/) 을 참고하였다. 여러 자료들을 찾아봤는데, 이 강의 처럼 쉽게 설명해놓은 강의는 없는것 같다.

분류 문제(Classification)의 정의

분류 문제란 학습된 모델을 가지고, 입력된 값을 미리 정해진 결과로 분류해주는 모델을 이야기 한다.

분류 결과가 참/거짓과 같이 두개만 있을때 이항 분류 분석, 두개 이상일때는 다항 분류 분석이라고 하는데, 이번장에서 살펴볼 로지스틱 회귀 분석은 분류된 결과가 두 가지만 있는 이항 분류 모델이다. (다항 분류 모델은 로지스틱 회귀에 이어서 소프트맥스 회귀 분석에서 설명하도록 하겠다.)


이항 분류의 대표적인 예는 다음과 같다.

  • 이메일 스팸과 정상 이메일 검출

  • 신용카드 거래에서 정상 거래와 이상 거래 검출

  • 게임에서 어뷰징 사용자와 정상 사용자 검출


등이 이항 분류의 예가 될 수 있다.


예를 들어 아래와 같은 데이타가 있다고 가정하자



붉은 동그라미로 표시된 데이타와, 녹색 세모로 표시된 데이타를 분류하고 싶을때, 아래와 같이 이항 분류 문제는 이를 분류할 수 있는 이상적인 직선 그래프를 찾는 것이다.


로지스틱스 회귀 분석 (Logistics Regression)

선형 회귀 분석 (Linear regression) 으로 분류 문제 접근하기

이항 분류 모델에 대한 예를 들어보자. 종양의 크기에 따라서 양성 종양(암)인지 음성 종양인지를 판별하는 문제가 있다고 하자. 아래 그림은 종양의 크기에 대한 양성과 음성 여부를 그래프로 나타낸 것인데, X축은 종양의 크기, Y축은 종양의 양성과 음성 여부를 나타낸다. 1이면 양성 0이면 음성이다.


이 문제를 선형 회귀 모델로 정의해서 그래프를 그려보면 다음과 같다.

y=W*x

와 같은 그래프가 그려지고 대략 아래 그림에서 보는것과 같이 y > 0.5 보다 크면 양성 암, y <0.5 보다 작으면 음성암으로 판단할 수 있다.


그런데, 만약에 새로운 트레이닝 데이타에서, 종양의 크기가 큰 데이타가 들어오면 어떻게 될까?

아래 그림을 보자, 예를 들어 새로운 트레이닝 데이타에 종양의 크기가 5인 경우 양성 암이라는 데이타가 새로 들어왔다고 하자


이 경우 앞에서 선형 회귀로 만든 그래프의 기울기가 새로 들어온 데이타를 포함하면 맞지 않기 때문에 선형 회귀로 재학습을 시키게 되면 다음과 같은 기울기(점선 그래프)로 변하게 된다.


이 경우에는 앞에서 암이 양성인 여부를 판단할때 사용한 y가 0.5라는 기준은 더이상 사용할 수 없게 되고, y가 0.2 일때를, 새 기준으로 잡아서, 암의 양성/음성 여부를 판단해야 한다.

그러면 새로운 데이타가 들어올때 마다 기준점을 다시 잡아야 하는것인가? 또한 그렇게 만든 모델로 예측을 한다면, 학습에 사용되지 않은 큰 데이타가 들어온다면 오류가 발생할 수 도 있다.

그래서, 선형 회귀 분석 모델(Linear regression) 은 이항 분류에 적절하지 않다. 그렇다면 어떤 모델이 적절할까 ?

참고



시그모이드(sigmoid) 함수

이런 형태의 이항 분류 분석에 적절한 함수로 시그모이드(sigmoid)함수라는 것이 있다. 그래프의 모양은 다음과 같다. S 자 형태의 그래프 모양으로 중심축 (x=0)을 중심으로 좌측은 0으로 수렴하고 우측은 1로 수렴한다.



이 시그모이드 함수에 앞의 데이타를 적용해보면 다음과 같은 형태가 된다.


그림과 같이 y축을 0.5를 기준으로 판단할때 y가 0.5 일때 x가 2 인데, x<2 인 부분은 y=0으로 음성, x>2인 부분은 y=1로 양성이 된다.

큰 데이타 (x=100)가 추가된다하더라도 시그모이드 함수는 그 값이 1로 수렴되기 때문에, 앞의 선형 회귀 분석의 경우 처럼 암의 양성/음성인 경우를 결정하는 y와 x값이 변화하지 않는다.

가설 (Hyphothesis)

그래서, 이 시그모이드 함수를 사용하여 가설을 정의할 수 있다.

가설은 아래와 같다

y = sigmoid(Wx + b)


결과 값 y 는 0 또는 1의 값을 갖는다. 시그모이드 함수를 수학 공식으로 표현하면, 아래와 같다. (그렇다는 것만 알아두고 외워서 쓰자)
1 / (1+ math.exp(-(W*x+b) )


디시전 바운드리(Decision boundary)


y = sigmoid (W*x + b) 을 가설 함수로 그려진 위의 그래프에서 W는 1, b는 -2로 그래프로 우측으로 두칸을 이동하였다.

W에 1,  b에 -2 를 대입해보면 y = sigmoid(1*x-2) 의 형태의 그래프인데, “x가 2를 기준으로 좌,우측이 양성암이냐 아니냐” 를 결정하기 때문에 때문에,

1*x-2 <0 이면,  y=0이 되고

1*x+2 >0 이면, y=1이 된다.

이를 일반화 해보면, 시그모이드(sigmoid) 함수 내에 들어가는

W*x+b < 0 이면,  y=0이 되고,

W*x+b > 0 이면,  y=1이 된다.

즉 로지스틱 회귀 분석은 위의 조건을 만족하는 W와 b의 값을 찾는 문제이다.

그리고  시그모이드 함수내의

z=W*x+b

그래프를 기준으로나눠서 y가 0또는 1이 되는 기준을 삼는데, 이 그래프를 기준으로 결정을 하기 때문에, 이를 디시전 바운드리 (Decision boundary) 라고 한다.


변수가 x하나가 아니라, x1,x2가 있는 문제를 살펴보자


이 문제에서 가설 함수 y = sigmoid (W1*x1 + W2*x2 + b)가 될것이고,

z=W1*x1+W2*x2+b 가 디시전 바운드리 함수가 되며, 위의 그래프상에서는 붉은선과 초록선을 나누는 직선이 되고 이것이 바로 디시전 바운드리가 된다.

코스트 함수 (비용함수/Cost function)

자 그러면 가설 함수를 정의 했으니 적정 W와 b값을 찾기 위해서 코스트 함수를 정의해보자.

다시 한번 앞에서 코스트 함수의 개념을 되집어 보면, 코스트 함수의 개념은 가설 함수에 의해서 예측된 값과 트레이닝을 위해서 입력된 값(실제값) 사이의 차이를 계산해주는 함수로, 예측된 값과 입력된값 들의 차이에 대한 평균 값을 구한다.

로지스틱 회귀에서 사용되는 코스트 함수는 다음과 같다.

cost_function =(1/n) * Sum(
                              -y_origin*log(sigmoid(Wx+b)) - (1-y_origin)*log(1-(sigmoid(Wx+b)))

                        )

  • n 의 트레이닝 데이타의 수

  • Y_origin  는 트레이닝에 사용된 x에 대한 입력값


의미를 설명하겠지만, 머리가 아프면 넘어가도 좋다. 그냥 가져다 쓰면 된다.


그러면 어떻게 저런 코스트 함수가 사용되었는지를 알아보자.

선형회귀분석(Linear regression)의 코스트 함수를 다시 한번 살펴보자

코스트 함수는 측정값과 가설에 의해서 예측된 값의 차이의 제곱 평균을 나타내는 함수였다.

선형 회귀 분석에서의 코스트 함수는 다음과 같았다.

Cost =  Sum( (y_data_n - y_origin_n) ^ 2) / n

그리고 이 함수를 그래프로 그려보면 다음과 같이 매끈한 그래프가 나왔다.


그래프의 모양이 매끈한 골짜기 모양이였기 때문에 경사 하강법(Gradient descent)을 사용할 수 있었다.

그러면 로지스틱 회귀 분석에도 기존의 코스트 함수를 이용하여 경사하강법을 적용할 수 있는지 보자

코스트 함수에서 y_data_n에 가설 함수를 대입 시켜 보면

Cost = Sum(  ( sigmoid(Wx + b) - y_origin) ^ 2) /n

Sigmoid 함수를 풀어서표현하면


Cost = Sum(  1 / (1+ math.exp(-(W*x+b) )- y_origin) ^ 2) /n

가 되는데, exp( -(W*x+b) ) (즉 e^(-Wx+b) ) 형태로 표현되기 때문에,e 가 들어간 코스트 함수의 그래프는 다음과 같은 형태를 띄게 된다.

경사 하강법은 그래프를 타고 내려가면서 가장 작은 값을 찾는 알고리즘인데, (물이 골짜기를 따라서 내려가듯이), 이 코스트 함수의 그래프는 작은 골짜기들이 모여서 큰 골짜기 형태를 만든 모양이 된다. 그래서 경사 하강법을 적용할 경우 아래 그림과 같이 코스트 함수의 최소값으로 수렴하지 않고, 중간에 작은 골짜기에서 수렴해 버린다.


그래서 로지스틱 회귀 분석에서는 경사 하강법을 사용하기 위해서 이 코스트 함수를 메끈한 형태로 만들 필요가 있고, 새로운 코스트 함수를 사용한다. “e” 때문에 이런형태의 그래프가 그려지는 건데, e를 상쇄할 수 있는 역치함수는 log 함수가 있다. 그래서 log 함수를 적용하여 메끈한 형태의 코스트 함수를 정의해보자.코스트 함수는 y=1일때와 y=0일때 나눠서 계산해야 한다. 각각의 함수를 보면 다음과 같다.


y=1
cost = (1/n) * sum (-log(가설) )
cost = (1/n) * sum (-log(sigmoid(Wx+b)) )


y=0
cost = (1/n) * sum( -log(1-가설) )
cost = (1/n) * sum( -log(1-sigmoid(Wx+b)) )


코스트 함수는 측정한 값과, 가설에 의해 예측된 값의 차이를 나타내는 함수로, 개별값이 작을 수록 적절한 모델이 된다. 그래서 측정값과 가설값이 같거나 유사할 수 록 코스트 함수의 결과값이 작게 나와야 한다.

먼저 y=1 (측정한 값이)일때를 보자,  

코스트 함수는 cost = (1/n) * sum (-log(sigmoid(Wx+b)) ) 이다.

전체 코스트 평균 말고, 개발 값에 대한 측정값과 예측값에 대한 차이는 이 함수에서 -log(sigmoid(Wx+b)) 이다. 시그모이드 함수 특성상 sigmoid(Wx+b)는 0~1까지의 범위를 가지기 때문에 -log(0~1)을 그래프로 그려보면 다음과 같다.


측정값이 1이기 때문에, 가설함수 (시그모이드 함수  sigmoid(Wx+b) )에 의한 결과가 1이면 예측이 잘된것이고, 1에서 멀어져서 0으로 갈수록 예측된 값과 측정된 값의 차이가 크다고 할 수 있는데, 위의 그래프에서 보면, 가설에 의해 계산한 결과(x축)가 1에 가까울 수록 코스트(y축)은 0으로 수렴하고, 가설에 의해 계산한 결과가 0에 수렴할 수 록, 코스트는 높아지는 것을 볼 수 있다. 즉 y=1에서는 가설이 1에 수렴해야 하기 때문에, 1에 가까워질 수록 코스트가 낮아지는 그래프를 띄게 된다.


y가 0일때도 마찬가지 원리인데 측정값이 0이기 때문에, 가설에 의한 결과값이 0이 되어야 한다. 0에서 멀어질 경우 코스트가 늘어나고 0에서 가까워질 경우 코스트가 줄어드는 형태의 비용 함수를 정의해야 한다.

마찬가지로 코스트 함수의 평균이 아닌 개별값을 보면, -log(1-sigmoid(Wx+b)) 이 되고 sigmoid(Wx+b)는 0..1의 범위이기 때문에, -log(1- (0..1) ) 이 된다. 단 1에서 0..1을 뺄셈을 했기 때문에, 그래프는 -log(1.0, 0.99,0.98,....) 형태로 y=1인 경우와 반대 모양의 그래프가 된다.



자 이제, y=1인 경우와 y=0인 경우에 대한 각각의 코스트 함수를 정의하였다. 이를 코딩으로 옮기려면 y=1인 경우와 0인 경우에 대해서 각각 다른 코스트 함수로 처리하기 위해서 if  문을 사용해야 하지만, 그러면 코딩이 복잡해지기 때문에 이를 하나의 식으로 간단히 할 수 있는 방법을 찾아보자

y=1
cost_y1 = (1/n) * sum (-log(sigmoid(Wx+b)) )


y=0

cost_y0 = (1/n) * sum( -log(1-sigmoid(Wx+b)) )


y=1일때는 y=0인 코스트 함수 cost_y0 가 0이 되고, y=0일때는 y=1의 코스트 함수 cost_y1가 0이 되면 된다.

즉 cost = y*cost_y1 + (1-y)cost_y0 형태가 되면,


y=1 이면, cost = 1*cost_y1 + (1-1)*cost_y0 = cost_y1이 되고

y=0 이면, cost = 0*cost_y1 +  (1-0)*cost_y0 = cost_y0 이 된다.


그래서 y=1인 코스트 함수와 y=0인 코스트 함수를 위의 식 cost_y1과  cost_y=0에 각각 대입해보면


cost = y*[ (1/n) * sum (-log(sigmoid(Wx+b)) )]  + (1-y)[(1/n) * sum( -log(1-sigmoid(Wx+b)) )]


으로 평균 함수인 (1/n)* sum을 앞으로 빼면

cost = (1/n)*Sum(

y*(-log(sigmoid(Wx+b)))

        + (1-y)(-log(1-sigmoid(Wx+b) ))

     )


가 된다.

수식을 따라가면서 이해하면 제일 좋겠지만, 코스트 함수가 저런 원리로 생성이 되는 구나 정도 이해하고, 그냥 가져도 쓰자. (왠지 주입식 교육 같은 느낌이 들기는 하지만)


옵티마이져 (Optimizer)

코스트 함수가 정해졌으면, 코스트를 최소화할 옵티마이져로 어떤 옵티마이져를 사용해야 할지 결정해야 한다.

앞에서 경사 하강법에 적절하도록 코스트 함수를 수정했기 때문에, 경사 하강법(Gradient descent) 알고리즘을 사용한다. 이 경사하강법은 텐서플로우 코딩에서는 간단하게

optimizer = tf.train.GradientDecentOptimizer(learningRate)

train = optimizer.minimize(cost_function)


정의하여 옵티마이져로 사용할 수 있다.

예측 (Prediction)

자 이렇게 해서, 로지스틱 회귀에 대한 학습을 끝내고, W와 b 값을 구했다고 하자. 그렇다면 이 학습된 모델을 가지고, 들어오는 데이타에 대한 분류는 어떻게 할것인가? (예측은 어떻게 할것인가)


가설 함수를 다시 생각해보면 가설함수는 sigmoid(Wx + b) 이다.

그래서 예측이 필요한 값 x가 들어왔을때, 가설함수에 의한 결과값이 y’ 이라고 하면, y’은 0..1 까지의 실수가 되고, y’은 0.75일 경우, x에 대한 결과가 1일 확률은 75%, 0일 확률은 (100-75%인) 25%가 된다.


앞에서 종양의 크기에 대한 양성암 문제를 다시 예를 들어보면, 종양의 크기 x=5이면, sigmoid(Wx+b)에 의해서 계산된 결과가 0.95라고 하면, 이 경우 양성 종양인 확률은 95%, 음성인 확률은 5% 이다.


정리

분류 문제는 회귀 분석과 함께 머신러닝에서 가장 대표적인 문제이고, 로지스틱 회귀 분석은 분류문제에 있어서 기본적이고 대표가 되는 모델이다. 수식이 많이 나와서 다소 복잡할 수 있겠지만 정리를 해보면 다음과 같다.


먼저 가설 함수 (Wx+b) 를 정의하고, 이 가설 함수에 사용된 변수 W와 b에 대한 적정값을 계산하기 위해서 코스트 함수를 정의한후, 이 코스트 함수를 이용한 W와 b를 구하기 위해서 옵티마이저를 정의해서 학습을 통해서 W와 b값을 구한다.


이 과정에서 복잡한 수학적인 설명이 있었지만, 다음과 같은 접근 방법이 좋지 않을까 한다.

  1. 로지스틱 회귀 분석은 결과가 참/거짓인 이항 분석 문제에 사용된다.

  2. 비용 함수가 있다는 것을 알고 로지스틱 회귀 분석용 비용 함수를 가져다 쓴다. 단 비용 함수가 낮을 수 록 학습이 정확하다는 의미 정도는 알아야 학습 도중에 비용 함수의 결과를 보고 학습의 정확도를 파악할 수 있다.

  3. 옵티마이져는 그레디언트 디센트 알고리즘을 사용한다. 그냥 가져다 쓴다.
    단 여기서 학습 속도(Learning Rate, 2장 선형 회귀 분석을 구현하는 문서에서도 설명하였음)의 의미를 파악하고,학습 프로그램을 돌릴때 이 패러미터를 조정하면서 사용한다.

  4. 나온 결과값 (W와 b) 값을 이용하여 예측을 수행한다.


참고