본문 바로가기
AI

[ai-2team] 2. Multi-variable linear regression, Logistic regression, Softmax Classifier

by 번둥천개1 2021. 1. 15.

Multi-variable linear regression

시험 점수 예측하기

입력 값 1개(x)를 이용한 회귀(regression)

One-variable(One-feature)

여기서 입력값 x를 variable 혹은 feature라고 한다.

 

입력 값 3개(x1, x2, x3)를 이용한 회귀(regression)

 

Multi-variable(Multi-feature)

두 차례의 쪽지시험 점수와 중간고사 점수를 통해 기말고사 점수를 예측하는 모델이다. 즉 새로운 학생의 쪽지시험 점수와 중간고사 점수를 알면 기말고사 점수를 예측할 수 있다.

 

Hypothesis

가설 함수

기존의 Hypothesis 함수이다.

다변수 회귀의 경우 변수(x)가 3개로 늘어나면 가중치(w)도 3개가 된다.

 

Cost function

cost 함수는 기존에 변수가 하나일 때와 동일하다.

 

Multi-variable

변수가 3개뿐이라면 괜찮지만

변수가 10개 혹은 100개로 훨씬 많아지면 식이 복잡하고 길어진다.

이를 해결하기 위해 matrix를 이용할 수 있다.

 

Matrix

우선 행렬곱(Matrix multiplication)에 대해 알아야 한다.

점곱(Dot product)

dot product란 위 예시에서 앞 행렬의 첫 번째 행과 뒷 행렬의 첫 번째 열을 곱하고 더해서 결과 행렬의 첫 번째 요소를 구하는 것이다. 즉, 1*7 + 2*9 + 3*11을 계산해 58을 구한 것이다.

 

Hypothesis using matrix

이렇게 n개의 입력 값과 가중치가 있을 때

각 행과 열을 곱해서 각 요소를 구해내면 된다.

이를 식으로 표현하면

이렇게 되는데 X와 W의 순서가 바뀐 이유는 X는 행, W는 열을 의미하기 때문이다.

 

Many x instances

5명의 학생의 세 차례의 중간 시험 점수와 기말 시험 점수

위 예시를 이용해 행렬을 이용한 가설함수를 구해보자.

주목해야 할 점은 데이터의 건수(instance)가 늘어나도 가설함수는 동일하다는 것이다.

 

행렬곱을 하기 위해서는 첫 번째 행렬의 열과 두 번째 행렬의 행의 크기가 일치해야 하고 결과 행렬은 첫 번째 행렬의 행, 두 번째 행렬을 열의 크기와 일치하게 된다.

 

이 성질을 이용해 필요한 가중치(w, weight) 행렬의 크기를 구할 수 있다.

위와 같이 입력이 3열, 출력이 2열인 경우는 W가 3행 2열이어야 한다.

 

여기서 다시 주목할 점은 이 경우에서도 결국 가설 함수(H)는 H(X) = XW로 표현이 가능하다는 것이다.

어떤 크기의 입력이 주어지든 동일한 표현이 가능한 것이 matrix 사용의 진정한 이점이라고 할 수 있다.

 

WX vs XW

앞서 언급했듯이 식에 따라서 W와 X의 순서를 다르게 쓴다.

  • Lecture (theory)
    주로 이론에서는 가설 함수를 H(x) = Wx + b로 표현하는데 여기서 W는 계수이므로 변수인 x보다 앞에 씀
  • Implementation(TensorFlow)
    코드에서는 가설 함수를 H(x) = XW로 써야함. 행렬곱을 계산하기 위해서는 필요한 행과 열을 행, 열의 순서로 써야 계산이 가능하기 때문

다른 자료에서는 가설 함수를 다음과 같이 표현하기도 한다.

위 경우는 θ1이 weight, θ0가 bias를 의미한다.

그리고 위 경우는 a가 weight, b가 bias를 의한다.

 

실습

입력 데이터를 행렬로 표현하는 방법에는 두 가지가 있다.

우선 첫 번째는 각 열을 한 개의 리스트로 표현하는 방법이다.

# data and label
x1 = [ 73.,  93.,  89.,  96.,  73.]
x2 = [ 80.,  88.,  91.,  98.,  66.]
x3 = [ 75.,  93.,  90., 100.,  70.]
Y  = [152., 185., 180., 196., 142.]

# random weights
w1 = tf.Variable(tf.random.normal([1]))
w2 = tf.Variable(tf.random.normal([1]))
w3 = tf.Variable(tf.random.normal([1]))
b  = tf.Variable(tf.random.normal([1]))

learning_rate = 0.000001

for i in range(1000+1):
    # tf.GradientTape() to record the gradient of the cost function
    with tf.GradientTape() as tape:
        hypothesis = w1 * x1 +  w2 * x2 + w3 * x3 + b
        cost = tf.reduce_mean(tf.square(hypothesis - Y))
    # calculates the gradients of the cost
    w1_grad, w2_grad, w3_grad, b_grad = tape.gradient(cost, [w1, w2, w3, b])
    
    # update w1,w2,w3 and b
    w1.assign_sub(learning_rate * w1_grad)
    w2.assign_sub(learning_rate * w2_grad)
    w3.assign_sub(learning_rate * w3_grad)
    b.assign_sub(learning_rate * b_grad)

    if i % 50 == 0:
      print("{:5} | {:12.4f}".format(i, cost.numpy()))

두 번째는 입력 데이터를 2차원 리스트로 표현하는 것이다.

data = np.array([
    # X1,   X2,    X3,   y
    [ 73.,  80.,  75., 152. ],
    [ 93.,  88.,  93., 185. ],
    [ 89.,  91.,  90., 180. ],
    [ 96.,  98., 100., 196. ],
    [ 73.,  66.,  70., 142. ]
], dtype=np.float32)

# slice data
X = data[:, :-1]  # 마지막 열 제외
y = data[:, [-1]]  # 마지막 열만

W = tf.Variable(tf.random.normal([3, 1]))
b = tf.Variable(tf.random.normal([1]))

learning_rate = 0.000001

# hypothesis, prediction function
def predict(X):
    return tf.matmul(X, W) + b

print("epoch | cost")

n_epochs = 2000
for i in range(n_epochs+1):
    # tf.GradientTape() to record the gradient of the cost function
    with tf.GradientTape() as tape:
        cost = tf.reduce_mean((tf.square(predict(X) - y)))

    # calculates the gradients of the loss
    W_grad, b_grad = tape.gradient(cost, [W, b])

    # updates parameters (W and b)
    W.assign_sub(learning_rate * W_grad)
    b.assign_sub(learning_rate * b_grad)
    
    if i % 100 == 0:
        print("{:5} | {:10.4f}".format(i, cost.numpy()))

 

 

 

 

Logistic regression

Logistic regression은 향후 deep learning과 neural network를 이해하는 데에 기초가 되는 내용이므로 확실히 이해하고 넘어가자!

 

Classification

Binary Classification이란 결과 값을 0 아니면 1이 나오도록 분류하는 것이다.

 

Logistic vs. Linear

logistic은 0과 1 두 가지로 구분되는 데이터이고 linear는 연속적인 수치형 데이터이다.

 

Hypothesis Representation

다음은 공부한 시간과 합격 여부의 상관 관계를 표현한 가설 함수이다.

Linear regression을 이용하여 연속적인 수치로 나타내었지만 실제 합격 여부를 나타내는 데 필요한 값은 0과 1뿐이다. 따라서 이를 위한 새로운 수식이 필요하다.

앞서 언급한 새로운 수식이 g 함수이다.

여기서 g 함수는 logistic function을 의미한다.

입력 데이터 X에 우선 Linear function을 적용하고 그 결과로 나온 연속적인 데이터를 Logistic function을 이용해 그래프의 모양을 바꿔준다. 그리고 그 결과에 Decision boundary를 0.5로 설정해 0과 1의 값으로 분류하는 것이 g 함수이다.

 

Sigmoid(Logistic) function

g function을 수식으로 나타내면

이 된다. 이를 sigmoid 함수라고도 한다. TensorFlow에 구현되어 있다.

hypothesis = tf.sigmoid(z)
hypothesis = tf.div(1., 1. + tf.exp(z))

 

Decision Boundary

Decision Boundary는 선형인 경우도 있고 아닌 경우도 있다.

앞서 설명한 예와 같은 경우는 0.5를 기준으로 Decision boundary를 설정했는데 이는 선형이 아닌 수치 하나를 가지고 설정한 경우이다.

predicted = tf.cast(hypothesis > 0.5, dtype=tf.int32)

다음은 decision boundary가 선형 함수인 경우들이다.

Decision Boundary x1 + x2 = 0
Decision Boundary (x1)^2 + (x2)^2 = 1

 

Cost Function

Logistic regression에서 cost가 최소가 되는 θ(가중치, W)를 찾는 과정은 간략하게 다음과 같이 나타낼 수 있다.

Logistic regression의 cost 함수를 그래프로 나타내면 다음과 같이 구불구불한 모양이 된다.

이 구불구불한 값을 로그 함수에 대입하면 원하는 값을 표현할 수 있다.

실제 값이 1일 때, hypothesis가 0에 가까워지면 cost가 커지고 1에 가까워지면 cost가 작아지고

실제 값이 0일 때, hypothesis가 0에 가까워지면 cost가 작아지고 1에 가까워지면 cost가 커진다.

즉 원하는 대로 cost가 표현이 가능하게 된다.

위 두 식을 다음과 같이 하나의 식으로 표현할 수 있다.

Logistic regression의 cost 함수

cost = -tf.reduce_mean(labels * tf.log(hypothesis) + (1 - labels) * tf.log(1 - hypothesis))

여기서 reduce_mean은 차원 축소를 위한 함수이다.

 

Optimization

cost가 최소인 θ(가중치, W)를 찾는 방법은 마찬가지로 기울기가 0이 되는 지점을 찾는 것이다.

표시한 부분이 기울기가 0인 지점이다.
(weight) := (weight) - (learning rate) * (gradient) * (cost)

위 식을 통해θ 값을 계속 업데이트해 나가면서 최적의 θ 값을 찾는다.

어느 지점에서 시작하든 결국 기울기가 0인 지점을 찾는다.

 

 

 

Softmax Classifier

다음 Sample Dataset을 이용하여 Softmax Classifier에 대해 설명할 것이다.

x_data는 4가지 feature를 가진 데이터들이고 y_data는 이를 3가지로 분류한 결과 데이터이다.

#convert into numpy and float format
x_data = np.asarray(x_data, dtype=np.float32)
y_data = np.asarray(y_data, dtype=np.float32)

nb_classes = 3 #num classes

 

Softmax function

함수 S가 softmax function을 의미

softmax function을 통해 나온 값들은 확률을 의미하므로 합이 1이 된다.

TensorFlow에서 softmax function을 제공한다.

hypothesis =
tf.nn.softmax(tf.matmul(X,W)+b)

softmax 함수를 사용해보자. 다음과 같이 weight와 bias를 무작위로 설정한다.

In:

#Weight and bias setting
W = tfe.Variable(tf.random_normal([4, nb_classes]), name='weight')
b = tfe.Variable(tf.random_normal([nb_classes]), name='bias')
variables = [W, b]

print(W, b)

Out:

<tf.Variable 'weight:0' shape=(4, 3) dtype=float32, numpy=
array([[ 2.0265348 , -0.19990598, 0.187595 ],
[-1.8624718 , 1.1830902 , -0.75108314],
[ 0.7819291 , 0.19707595, 0.6640797 ],
[ 1.5643852 , -0.04990807, -0.38255563]], dtype=float32)>
<tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([-1.4564867 , 0.53983474,
-1.1366715 ], dtype=float32)>

 

softmax 함수를 사용해 hypothesis를 구한다.

hypothesis = tf.nn.softmax(tf.matmul(x_data, W) + b)

이를 테스트해보기 위해 다음 코드를 실행해본다.

In:

sample_db = [[8,2,1,4]]
sample_db = np.asarray(sample_db, dtype=np.float32)

Out:

tf.Tensor([[0.9302204 0.06200533 0.00777428]], shape=(1, 3),
dtype=float32)

출력값을 보면 세 값의 합이 1인 결과가 나온다.

 

Cost function: cross entropy

cost는 다음과 같이 구할 수 있다.

# Cross entropy cost/loss
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

hypothesis에 로그를 취한 후 Y를 곱한 것에 대해 전체 합을 구하고 평균을 구하면 된다.

이를 함수로 정의해 실행해보면 다음과 같다.

In:

def cost_fn(X, Y):
    logits = hypothesis(X)
    cost = -tf.reduce_sum(Y * tf.math.log(logits), axis=1)
    cost_mean = tf.reduce_mean(cost)
    
    return cost_mean

print(cost_fn(x_data, y_data))

Out:

tf.Tensor(6.07932, shape=(), dtype=float32)

 

Gradient Function

In:

def grad_fn(X, Y):
    with tf.GradientTape() as tape:
        loss = cost_fn(X, Y)
        grads = tape.gradient(loss, variables)

        return grads

print(grad_fn(x_data, y_data))

Out:

[<tf.Tensor: shape=(4, 3), dtype=float32, numpy=
array([[ 0.06914607, -0.6509784 ,  0.5818323 ],
       [-1.5221257 , -1.214863  ,  2.7369885 ],
       [-1.2473828 , -1.7611003 ,  3.008483  ],
       [-1.2014606 , -1.8659233 ,  3.0673838 ]], dtype=float32)>, <tf.Tensor: shape=(3,), dtype=float32, numpy=array([-0.15212913, -0.34219202,  0.4943211 ], dtype=float32)>]

 

Train

In:

def fit(X, Y, epochs=2000, verbose=100):
    optimizer =  tf.keras.optimizers.SGD(learning_rate=0.1)

    for i in range(epochs):
        grads = grad_fn(X, Y)
        optimizer.apply_gradients(zip(grads, variables))
        if (i==0) | ((i+1)%verbose==0):
            print('Loss at epoch %d: %f' %(i+1, cost_fn(X, Y).numpy()))
            
fit(x_data, y_data)

Out:

Loss at epoch 1: 2.849417
Loss at epoch 100: 0.684151
Loss at epoch 200: 0.613813
Loss at epoch 300: 0.558205
Loss at epoch 400: 0.508306
Loss at epoch 500: 0.461059
Loss at epoch 600: 0.415072
Loss at epoch 700: 0.369636
Loss at epoch 800: 0.324533
Loss at epoch 900: 0.280720
Loss at epoch 1000: 0.246752
Loss at epoch 1100: 0.232798
Loss at epoch 1200: 0.221645
Loss at epoch 1300: 0.211476
Loss at epoch 1400: 0.202164
Loss at epoch 1500: 0.193606
Loss at epoch 1600: 0.185714
Loss at epoch 1700: 0.178415
Loss at epoch 1800: 0.171645
Loss at epoch 1900: 0.165350
Loss at epoch 2000: 0.159483

출력을 보면 loss 값이 감소하는 것을 볼 수 있다.

 

Prediction

In:

a = hypothesis(x_data)

print(a)
print(tf.argmax(b, 1))
print(tf.argmax(y_data, 1)) # matches with y_data

Out:

tf.Tensor(
[[2.1975954e-06 1.2331175e-03 9.9876475e-01]
 [1.1288590e-03 8.1546679e-02 9.1732454e-01]
 [2.2205469e-07 1.6418649e-01 8.3581328e-01]
 [6.3921457e-06 8.5045445e-01 1.4953916e-01]
 [2.6150835e-01 7.2644705e-01 1.2044546e-02]
 [1.3783254e-01 8.6214006e-01 2.7417505e-05]
 [7.4242175e-01 2.5754121e-01 3.6978530e-05]
 [9.2197561e-01 7.8023843e-02 6.0005704e-07]], shape=(8, 3), dtype=float32)
tf.Tensor([2 2 2 1 1 1 0 0], shape=(8,), dtype=int64)
tf.Tensor([2 2 2 1 1 1 0 0], shape=(8,), dtype=int64)

 

 

코드 및 이미지 출처: deeplearningzerotoall.github.io/season2/lec_tensorflow.html

 

모두를 위한 딥러닝 시즌 2 -TensorFlow

This is TensorFlow page.

deeplearningzerotoall.github.io