인공지능/딥 러닝

[모두의 딥러닝] 05. 참 거짓 판단 장치: 로지스틱 회귀

Chipmunks 2018. 5. 6.
728x90


로지스틱 회귀 : 참과 거짓 중에 하나를 판단하는 것을 만들어 주어진 입력 값의 특징을 추출.


이를 저장해 모델(model)을 만듦. 새 질문이 오면, 그 모델을 꺼내 답을 함.

=> 딥러닝의 원리


1. 로지스틱 회귀의 정의

점수가 아니라 합격과 불합격만을 발표되는 시험이 있음


합격을 1, 불합격을 0이라 함. 이를 좌표 평면으로 표현해보자


S자 형태여야 이들의 데이터를 구분할 수 있음.


로지스틱 회귀는 선형 회귀와 마찬가지로 적절한 선을 그려가는 과정.

선형 회귀와 다른 점은 직선이 아니라, 참(1)과 거짓(0) 사이를 구분하는 S자 형태의 선을 그어주는 작업


2. 시그모이드 함수

시그모이드 함수(sigmoid function) : S자 형태로 그래프가 그려지는 함수


e : 자연 상수라고 불리는 무리수, 값은 2.71828...

우리가 구해야 하는 값 : ax + b


a : 그래프의 경사도

b : 그래프의 좌우 이동


a와 b의 값이 클수록 오차가 생긴다.

a 값이 작아지면 오차가 무한대로 커진다. 그러나 a 값이 커진다고 오차가 무한대로 커지지는 않음. 0 으로 수렴한다.

b 값은 너무 작거나 커도 오차가 무한대로 커진다. 이차 함수로 표현이 가능하다.


3. 오차 공식

실제값이 1일 때, 예측 값이 0이면 오차가 커져야 한다. 반대로 실제값이 0일 때, 예측 값이 1이면 오차카 커져야 한다. 이를 공식으로 표현할 수 있게 해주는 함수는 로그(log) 함수다.



4. 로그 함수

위 함수에 해당되는 함수는, -log(h)와 -log(1-h) 함수다. y의 실제 값이 1일 때 -log(h) 그래프를 쓴다. 0일 때 -log(1-h) 그래프를 써야 한다. 이를 식으로 표현하면 다음과 같다.


실제 값 y가 1이면, 뒤 식인 (1-y)log(1-h) 부분이 없어진다. 반대로 0이면 앞 ylog(h) 부분이 없어진다.


5. 코딩으로 확인하는 로지스틱 회귀 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import tensorflow as tf
import numpy as np
 
# x, y의 데이터 값
data = [[20], [40], [60], [81], [101], [121], [141]]
x_data = [x_row[0for x_row in data]
y_data = [y_row[1for y_row in data]
 
# a와 b의 값을 임의로 정한다.
= tf.Variable(tf.random_normal([1], dtype=tf.float64, seed=0))
= tf.Variable(tf.random_normal([1], dtype=tf.float64, seed=0))
 
# y 시그모이드 함수의 방정식을 세운다.
= 1/(1 + np.e**(a * x_data + b))
 
# loss를 구하는 함수
loss = -tf.reduce_mean(np.array(y_data) * tf.log(y) + (1 - np.array(y_data)) * tf.log(1 - y))
 
# 학습률 값
learning_rate = 0.5
 
# loss를 최소로 하는 값 찾기
gradient_decent = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss);
 
# 학습
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
 
    for i in range(60001):
        sess.run(gradient_decent)
        if i % 6000 == 0:
            print("Epoch: %.f, loss = %.4f, 기울기 a = %.4f, y 절편 = %.4f" % (i, sess.run(loss), sess.run(a), sess.run(b)))
cs


1
2
3
4
5
6
7
8
9
10
11
Epoch: 0, loss = 1.2676, 기울기 a = 0.1849, y 절편 = -0.4334
Epoch: 6000, loss = 0.0152, 기울기 a = -2.9211, y 절편 = 20.2982
Epoch: 12000, loss = 0.0081, 기울기 a = -3.5637, y 절편 = 24.8010
Epoch: 18000, loss = 0.0055, 기울기 a = -3.9557, y 절편 = 27.5463
Epoch: 24000, loss = 0.0041, 기울기 a = -4.2380, y 절편 = 29.5231
Epoch: 30000, loss = 0.0033, 기울기 a = -4.4586, y 절편 = 31.0675
Epoch: 36000, loss = 0.0028, 기울기 a = -4.6396, y 절편 = 32.3346
Epoch: 42000, loss = 0.0024, 기울기 a = -4.7930, y 절편 = 33.4086
Epoch: 48000, loss = 0.0021, 기울기 a = -4.9261, y 절편 = 34.3406
Epoch: 54000, loss = 0.0019, 기울기 a = -5.0436, y 절편 = 35.1636
Epoch: 60000, loss = 0.0017, 기울기 a = -5.1489, y 절편 = 35.9005
cs


오차(loss) 값이 점차 줄어들고 a와 b의 최적값을 찾아간다.


6. 여러 입력 값을 갖는 로지스틱 회귀

변수가 x에서 x1, x2로 추가된다. 따라서 각각의 기울기 a1, a2도 계산해야 한다.

ax => a1x1 + a2x2 으로 바뀐다. a1x1 + a2x2는 행렬곱을 이용해 [a1, a2] ✻ [x1, x2]로도 표현할 수 있다.

텐서플로에서는 matmul() 함수를 이용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import tensorflow as tf
import numpy as np
 
# 실행할 때마다 같은 결과를 출력하기 위한 seed 값 설정
seed = 0
np.random.seed(0)
tf.set_random_seed(seed)
 
# x, y의 데이터 값
x_data = np.array([[23,], [43], [64], [86], [107], [128], [149]])
y_data = np.array([0001111]).reshape(71)
 
# 입력 값을 플레이스 홀더에 저장
= tf.placeholder(tf.float64, shape=[None, 2])
= tf.placeholder(tf.float64, shape=[None, 1])
 
# 기울기 a와 바이어스 b의 값을 임의로 정함
= tf.Variable(tf.random_uniform([21], dtype=tf.float64))
# [2, 1] 의미 : 들어오는 값은 2개, 나가는 값은 1개
= tf.Variable(tf.random_normal([1], dtype=tf.float64, seed=0))
 
# y 시그모이드 함수의 방정식을 세운다.
= tf.sigmoid(tf.matmul(X, a) + b)
 
# loss를 구하는 함수
loss = -tf.reduce_mean(Y * tf.log(y) + (1 - Y) * tf.log(1 - y))
 
# 학습률 값
learning_rate = 0.1
 
# loss를 최소로 하는 값 찾기
gradient_decent = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss);
 
predicted = tf.cast(y > 0.5, dtype=tf.float64)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float64))
 
# 학습
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
 
    for i in range(3001):
        a_, b_, loss_, _ = sess.run([a, b, loss, gradient_decent], feed_dict={X: x_data, Y: y_data})
        if (i+1) % 300 == 0:
            print("step=%d, a1=%.4f, a2=%.4f, b=%.4f, loss=%.4f" % (i + 1, a_[0], a_[1], b_, loss_))
        
    new_x = np.array([76]).reshape(12# [7, 6]은 각각 공부한 시간과 과외 수업 횟수
    new_y = sess.run(y, feed_dict={X: new_x})
 
    print("공부한 시간: %d, 과외 수업 횟수: %d" % (new_x[:, 0], new_x[:, 1]))
    print("합격 가능성: %6.2f %%" % (new_y*100))
cs


1
2
3
4
5
6
7
8
9
10
step=300, a1=0.7703, a2=-0.4312, b=-2.7566, loss=0.2474
step=600, a1=0.7666, a2=-0.1696, b=-4.1359, loss=0.1807
step=900, a1=0.6844, a2=0.1382, b=-5.1498, loss=0.1428
step=1200, a1=0.5891, a2=0.4270, b=-5.9591, loss=0.1178
step=1500, a1=0.4974, a2=0.6859, b=-6.6344, loss=0.1000
step=1800, a1=0.4137, a2=0.9155, b=-7.2143, loss=0.0868
step=2100, a1=0.3389, a2=1.1192, b=-7.7227, loss=0.0766
step=2400, a1=0.2724, a2=1.3007, b=-8.1756, loss=0.0685
step=2700, a1=0.2131, a2=1.4635, b=-8.5839, loss=0.0619
step=3000, a1=0.1602, a2=1.6104, b=-8.9556, loss=0.0565
cs


오차(loss) 값이 점차 줄어들고, a1, a2와 b가 각각 최적값을 찾아간다.


7. 실제 값 적용하기

1
2
3
4
5
new_x = np.array([76]).reshape(12# [7, 6]은 각각 공부한 시간과 과외 수업 횟수
new_y = sess.run(y, feed_dict={X: new_x})
 
print("공부한 시간: %d, 과외 수업 횟수: %d" % (new_x[:, 0], new_x[:, 1]))
print("합격 가능성: %6.2f %%" % (new_y*100))
cs


1
2
공부한 시간: 7, 과외 수업 횟수: 6
합격 가능성:  86.16 %
cs


8. 로지스틱 회귀에서 퍼셉트론으로

입력 값을 통해 출력 값을 구하는 함수 y는 다음과 같이 표현한다.

입력값 x1, x2 값을 가지고 있다. 출력값 y를 구해야 한다. 이 때 a 값과 b 값이 필요하다. 이를 그림으로 표현하면 다음과 같다.



x1, x2 가 입력됨. 가중치 a1, a2를 만남. 여기에 b 값을 더해 시그모이드 함수를 거쳐 1또는 0의 출력 값 y를 출력. 이 개념을 '퍼셉트론(perceptron)' 이라는 이름을 붙임.


이는 인공 신경망, 오차 역전파 등의 발전을 거쳐 지금의 딥러닝으로 이어지게 됨

댓글