본문 바로가기

AI

Logistic Regression

딥러닝 수업 들으면서 배운 내용을 정리하면서 추가로 공부도 해보려고 한다

 

- Binary Classification

 

input feature vector를 가지고 0 또는 1(binary)의 결과를 갖는 output을 만들어내는 과정

이때 m개의 training example은 $ \{(x^{(1)}, y^{(1)}),(x^{(2)}, y^{(2)}),...,(x^{(m)}, y^{(m)})\} $처럼 나타낸다

이러한 m개의 example을 전부 합하여 하나의 Matrix로 취급하면 더 빠른 계산이 가능하다

$$ X \in \mathbb{R}^{n_x \times m} $$

$$ Y \in \mathbb{R}^{1 \times m} $$

 

- Logistic Regression

 

x가 주어졌을 때 $ \hat{y} = P(y=1|x) $을 추측하는 과정

$ \hat{y} $는 0~1의 사이값을 갖는 확률이 된다

모델의 parameter는 $ w \in \mathbb{R}^{n_x}, b \in \mathbb{R} $가 있고

output은 $ \hat{y} = \sigma(w^Tx+b) $이 된다

$ \sigma(z)$ sigmoid function은 $ \frac{1}{1+e^{-z}} $로 output을 0~1 사이로 만들어준다

그림과 같이 z가 매우 큰 값이라면 1에 수렴하는, 매우 작은값이라면 0에 수렴하는 함수이다

이러한 함수를 활성화 함수(activation function)이라고 한다

 

logistic regression의 목표는 $ \hat{y} $를 정확하게 계산하는 w,b를 구하는 과정이라고 생각할 수 있다

 

- Cost Function

 

logistic regression을 실행할 때 현재 값이 얼마나 정확한지 loss를 판단해보는 loss function을 정해야 parameter를 update 할 수 있다

 

loss function과 cost function의 차이가 모호한 느낌이라 찾아보았다

quora랑 stackexchange 찾아본 결과 엄밀히 구분을 하진 않지만 보통 loss function은 data point, prediction and label과 같은 하나의 학습 데이터로 계산하는 것이고 cost function은 loss function들의 합이나 평균과 같이 전체 학습 데이터를 아우르는 개념이라고 한다

 

loss function에는

$L(\hat{y},y) = \frac{1}{2}(\hat{y}-y)^2$ Eucliean loss

$L(\hat{y},y) = -(ylog\hat{y}+(1-y)log(1-\hat{y}))$ Cross entropy loss

등이 있다

 

유클리디안 에러는 classification을 진행할 때 vanishing gradient 문제가 있다고 하여 cross entropy loss를 사용하기로 했다

 

cross entropy loss는 y가 1일때는 $-log\hat{y}$ 가 되고 0일 때는 $-log(1-\hat{y})$ 이 된다

y가 1일때는 $log\hat{y}$ 이 크게 나와야 좋으니까 $\hat{y}$ 가 크게 나오는게 좋고

y가 0일때는 반대라 작게 나오는게 좋다

 

loss function을 가지고 만든 cost function은 다음과 같다

$$ J(w,b) = \frac{1}{m}\sum_{i=1}^{m}L(\hat{y},y) = -\frac{1}{m}\sum_{i=1}^{m}y^{(i)}log\hat{y}^{(i)}+(1-y^{(i)})log(1-\hat{y}^{(i)}) $$

 

loss function은 꼭 미분이 되어야한다

정확도와 같이 개수를 세서 쓰는 경우는 미분이 안되기때문에 loss로 쓸 수 있는 함수가 한정되어 있다

 

이렇게 정의한 모델을 이제 gradient descent 알고리즘을 이용하여 학습시켜보자

 

- Gradient descent

 

gradient descent는 training set에 대해 J(w,b)를 최소화시키는 w,b를 찾는것이다

 

 

derivative를 구해서 화살표처럼 내려가다보면 점점 cost 값이 작아진다는 점을 이용한 방법이다

local minimum에 빠질 수 있다는 문제점이 있다

 

learning rate $ \alpha $ 와 derivative $ \frac{dJ(w)}{dw} $ 를 이용해서 w를 update 가능하다

b도 똑같은 방법으로 update 할 수 있다

 

$$ w \leftarrow  w - \alpha \times \frac{dJ(w)}{dw} $$

$$ b \leftarrow  b - \alpha \times \frac{dJ(b)}{db} $$

 

이런 과정을 정해진 수만큼 혹은 목표한 Cost가 되는 만큼 반복하며 Cost를 낮춰간다

 

- Logistic Regression Derivatives

 

 

logistic regression을 이렇게 단순하게 나타내어본다면 gradient descent를 이용해 w,b를 update한다고 생각하면 된다

 

$ \frac{dL}{da} = -\frac{y}{a}+\frac{1-y}{1-a} $

 

sigmoid 미분을 써서 아래와 같이 유도

 

$ \frac{dL}{dz} = \frac{dL}{da}\frac{da}{dz}= (-\frac{y}{a}+\frac{1-y}{1-a})(a\times(1-a)) = a-y $

 

$ \frac{dL}{dw_1} = \frac{dL}{da}\frac{da}{dz}\frac{dz}{dw_1}= (a-y) \times (x_1) $

$ \frac{dL}{dw_2} = \frac{dL}{da}\frac{da}{dz}\frac{dz}{dw_2}= (a-y) \times (x_2) $

$ \frac{dL}{db} = \frac{dL}{da}\frac{da}{dz}\frac{dz}{db}= a-y $

 

최적 파라미터를 구하기 위해서는 a 값이 필요하므로 forward propagation을 통해 a 값을 구한 후

이 a 값을 이용하여 derivative를 구하는 과정이 backward propagation 이다

backward propagation을 통해 구한 미분값으로 파라미터를 갱신할 수 있다

 

하지만 이 식은 하나의 학습 데이터에 대해 나타낸 것이라 m개의 학습 데이터를 위해서는 반복이 필요하다

m개의 데이터에서 forward propagation, backward propagation을 반복 후 평균을 내어주면 된다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
w1 = random.uniform(-0.10.1)
w2 = random.uniform(-0.10.1)
= random.uniform(-0.10.1)
 
for i in range(0,K):
    dw1 = 0
    dw2 = 0
    db = 0
    for j in range(0,m):
        z = w1*x1_train[j] + w2*x2_train[j] + b
        a = sigmoid(z)
        cost_arr[i] += cross_entropy(a,y_train[j])
        dz = a - y_train[j]
        dw1 += x1_train[j] * dz
        dw2 += x2_train[j] * dz
        db += dz
    cost_arr[i] /= m
    w1 = w1 - alpha * dw1/m
    w2 = w2 - alpha * dw2/m
    b = b - alpha*db/m
cs

 

해당 과정을 파이썬으로 나타내보았다

 

 

cost를 그래프로 그려보면 점점 작아지는 것을 확인할 수 있다

하지만 이 방법은 치명적인 단점이 있다

1000개의 학습 데이터를 2000번 갱신하였을 뿐인데 로컬 컴퓨터에서 계산할 때 45초나 걸렸다

 

이를 해결하기 위해 빠른 연산이 가능하도록 vectorized 하여 사용해야한다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
w1 = random.uniform(-0.10.1)
w2 = random.uniform(-0.10.1)
= random.uniform(-0.10.1)
 
for i in range(0,K):
    z = w1*x1_train + w2*x2_train + b
    a = sigmoid(z)
    cost_arr[i] = cross_entropy(a,y_train)/m
    dz = a-y_train
    dw1 = np.dot(x1_train.T, dz)/m
    dw2 = np.dot(x2_train.T, dz)/m
    db = np.dot(np.ones(m).T,dz)/m
    w1 = w1 - alpha * dw1
    w2 = w2 - alpha * dw2;
    b = b - alpha*db
cs

 

위의 코드를 실행시켜보면 처음것과 같이 cost도 점점 낮아지고 정확도도 똑같이 나온다

하지만 실행 시간은 0.15초밖에 걸리지 않았다

 

vectorized 된 파이썬 코드를 보면 dw1을 구할 때 x1_train 전체와 dz를 dot product를 사용하여 결과를 구한것을 알 수 있다

for문과 같은 반복문 중 필요없는 것을 줄여 속도를 빠르게 할 수 있는데 이를 vectorization이라고 한다

GPU와 CPU는 SIMD를 가지고 있어 하나의 명령어를 가지고 여러개의 값을 동시에 계산할 수 있다고 한다

 

결론은 vectorized 된 연산(e.g., np.dot())으로 대체할 수 있는 for문을 쓰지 않는것이 좋다고 한다~

 

- Broadcasting 

 

브로드캐스팅을 사용하면 shape이 다른 배열의 모양을 굳이 똑같이 만들지 않아도 연산이 가능하다

사칙연산에서 사용가능한데 상식적으로 될 거 같을때 다 된다

m X n matrix와 1 X n, m X 1 matrix의 연산을 한다면 matrix가 m X n으로 broadcasting 되어 연산된다

 

ITE4053 : Deep Lerarning ( Hanyang University )

'AI' 카테고리의 다른 글

Regularization 1 - L1,L2 regularization  (0) 2021.04.18
Activation Functions  (0) 2021.04.13
[Kaggle] Titanic Competition 타이타닉 생존자 예측하기  (0) 2021.01.03
Neural Networks  (1) 2020.10.03
Fisher Discriminant Analysis  (0) 2020.10.02