[week 2] Part 1: Basic Machine Learning (2)
Multi-variable linear regression
- Hypothesis
- Cost function: 가설과 실제값의 제곱의 평균. Cost를 최소화하는 W(기울기)를 찾아가는 것이 포인트
- Gradient descent: Cost를 최소화하는 W를 찾을 수 있는 알고리즘 중 하나
변수가 여러개가 된다면 이에 따른 가중치도 여러개가 된다. 예를 들어서 변수가 3개라면 가중치(W)도 3개가 된다.
변수가 여러개가 된다면 Matrix 곱셈(행렬곱)을 활용하게 된다.
일반적으로 matrix는 대문자로 표현을 한다. 매트릭스 연산 시 X가 먼저, W가 뒤에 오기 때문에 기술을 할때도 XW라고 한다. X를 사용하게 된다면 컬럼의 개수가 몇 개든, 데이터의 개수가 몇 개든 상관이 없이 무조건 X로 사용하기 때문에 간단하게 식 표현이 가능하다.
Multi variable linear regression LAB
Multi variable linear regression with no matrix
# Multi variable linear regression with no matrix
import tensorflow as tf
# 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.]
# 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
hypothesis = w1 * x1 + w2 * x2 + w3 * x3 + b
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()))
>>>
0 | 21359.2578
50 | 245.4268
100 | 11.1252
150 | 8.5033
200 | 8.4521
250 | 8.4294
300 | 8.4072
350 | 8.3851
400 | 8.3629
450 | 8.3410
500 | 8.3189
550 | 8.2970
600 | 8.2751
650 | 8.2533
700 | 8.2315
750 | 8.2098
800 | 8.1882
850 | 8.1667
900 | 8.1451
950 | 8.1236
1000 | 8.1022
칼럼의 개수만큼 가중치를 따로따로 정의해주어야 됨을 알 수 있다.
Multi variable linear regression with matrix
# Multi variable linear regression with matrix
import numpy as np
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]]
# 가중치의 경우 칼럼이 3개(x1, x2, x3)니까 행은 3개가 필요하고, 결과값은 1개니까 열 개수는 1개가 필요하다.
W = tf.Variable(tf.random.normal([3, 1]))
b = tf.Variable(tf.random.normal([1]))
learning_data = 0.000001
def predict(X):
return tf.matmul(X, W) + b
n_epochs = 2000
for i in range(n_epochs + 1):
# 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()))
>>>
0 | 33753.4961
100 | 14.9227
200 | 10.7120
300 | 10.6551
400 | 10.5989
500 | 10.5431
600 | 10.4877
700 | 10.4324
800 | 10.3776
900 | 10.3230
1000 | 10.2687
1100 | 10.2147
1200 | 10.1609
1300 | 10.1075
1400 | 10.0543
1500 | 10.0015
1600 | 9.9489
1700 | 9.8966
1800 | 9.8447
1900 | 9.7929
2000 | 9.7415
행렬을 사용하게 된다면 가설 함수의 결과값을 구할 때, 훨씬 간편하게 코드를 작성할 수 있음을 확인할 수 있다.
Logistic (Regression) Classification
출처: https://copycode.tistory.com/161?category=740659 + 스터디 강의
Classification
- Exam: Pass or Fail
- Spam: Not Spam or Spam
- Face: Real or Fake
- Tummor: Not Malignant or Malignant
이게 다 Binary Classification이다. 어떤 피처의 특징을 토대로 T / F로 나눌 수 있고 이를 통해서 Logistic Regression
Logistic vs Linear
- Logistic: 두가지의 케이스로 구분할 수 있다. Show size / The number of workers
- Linear: 연속적인 데이터를 통해서 그래프에 인근하는 데이터를 예측할 수 있다. Time / Weight / Height 처럼 연속적인 값들
Hypothesis Representiation
앞에서 배웠던 Linear Regression을 가지고 0.5보다 크면 1로 작으면 0으로 하면 될 것 같다는 생각이 든다. 하지만 이 알고리즘을 하용하게 된다면 특정 데이터가 크게 나온다면 원래는 1을 받을 수 있지만 그 데이터가 0을 받을 수 있다. 정확한 데이터를 표현하지 못하게 될 수 있다. 그렇기 때문에 Sigmod 함수를 사용해서 해당 데이터를 통해서 나온 Linear Regression을 0에서 1사이의 값으로 바꾼다.
Linear Regression을 통해서 나온 실수값을 Logistic Function(Sigmoid)을 통해서 0에서 1인 구간을 만들고 Decision Boundary(0과 1을 구별하는 함수)를 통해서 0.5이상이면 1로 값을 변경시키는 방식으로 표현한다. 이게 Logistic Hypothesis가 된다.
Cost Function
Cost function은 예측을 하는 값과 실제 값의 차이를 나타내는 함수이다. Linear Regression의 Cost Function의 경우는 실제 값들과의 차이에 대한 기울기를 이용해서 만들어지게 된다.
하지만 이 Cost Function 공식을 사용하게 된다면 Logistic Regression의 경우는 울퉁불퉁한 값이 나와서 Gradient descent algorithm을 통해서 최솟값을 구할 수 없게 된다.
local cost의 최소값과 Global cost의 최솟값은 다를 수 있기 때문이다.
따라서, Logistic Regression의 cost function은 다음과 같이 정의할 수 있다.
왜냐면 가설 함수에서 시그모이드를 통해서 0~1로 바꾸어 놓았기 때문에 log를 사용하게 된다면 확실히 0인지 1인지를 확인할 수 있기 때문이다. 예를 들어서 1로 수렴할수록 log를 가지고 있는 함수에 대한 y값은 0에 수렴하게 된다. 즉, 예측값이 1에 가까워질수록 cost function의 값은 작아지게 된다. 반대로 y에 가까워진다고 해도, -log에 해당한다면 그 cost 역시 작아지게 된다.
따라서 Logistic Regression의 Cost Function은 다음과 같은 식을 가집니다.
How to minimize the cost function
그럼 위에 있는 Cost Function에서 비용의 최소화되는 값을 어떻게 알 수 있을까?
Cost Function을 구한 이유는 Gradient descent algorithm을 사용하기 위해서이다.
1️⃣ 시그모이드 함수를 가설 함수로 선언
시그모이드 함수가 적용된 식을 볼 수 있다. 이를 가설 함수로 정의한 것이다.
# Sigmoid 함수를 가설로 선언합니다
def logistic_regression(features):
hypothesis = tf.divide(1., 1. + tf.exp(tf.matmul(features, W) + b))
return hypothesis
2️⃣ 비용 함수
0이나 1로 갈수록 비용 함숫값이 작아지는 함수를 그대로 코드로 구현한 것을 확인할 수 있다.
# 비용 함수를 정의합니다.
def loss_fn(hypothesis, features, labels):
cost = -tf.reduce_mean(labels * tf.math.log(logistic_regression(features)) + (1 - labels) * tf.math.log(1 - hypothesis))
return cost
3️⃣ Gradient Decent
# GradientTape를 통해 경사값을 계산합니다.
def grad(features, labels):
with tf.GradientTape() as tape:
loss_value = loss_fn(logistic_regression(features), features, labels)
return tape.gradient(loss_value, [W,b])
4️⃣ 경사 하강 실행 코드
EPOCHS = 1001
for step in range(EPOCHS):
for features, labels in iter(dataset):
grads = grad(features, labels)
optimizer.apply_gradients(grads_and_vars=zip(grads,[W,b]))
if step % 100 == 0:
print("Iter: {}, Loss: {:.4f}".format(step, loss_fn(logistic_regression(features),features,labels)))
❓이 부분이 뭘 하는 거지?
# GradientDescentOptimizer에서 learning_rate를 설정해서 optimizer를 선언한다.
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
# 실제 optimizer.apply_gradients를 통해서 실제모델인 [W,b]가 update되서 모델이 만들어지게된다.
optimizer.apply_gradients(grads_and_vars=zip(grads,[W,b]))
5️⃣ Predict
# 추론한 값은 0.5를 기준(Sigmoid 그래프 참조)로 0과 1의 값을 리턴합니다.
def accuracy_fn(hypothesis, labels):
predicted = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, labels), dtype=tf.int32))
return accuracy
test_acc = accuracy_fn(logistic_regression(x_test),y_test)
print("Testset Accuracy: {:.4f}".format(test_acc))
>>>
dataset
<BatchDataset element_spec=(TensorSpec(shape=(None, 2), dtype=tf.float32, name=None), TensorSpec(shape=(None, 1), dtype=tf.float32, name=None))>
Iter: 0, Loss: 0.6874
Iter: 100, Loss: 0.5776
Iter: 200, Loss: 0.5349
Iter: 300, Loss: 0.5054
Iter: 400, Loss: 0.4838
Iter: 500, Loss: 0.4671
Iter: 600, Loss: 0.4535
Iter: 700, Loss: 0.4420
Iter: 800, Loss: 0.4319
Iter: 900, Loss: 0.4228
Iter: 1000, Loss: 0.4144
Testset Accuracy: 1.0000
전체 코드
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import tensorflow as tf
tf.random.set_seed(777) # for reproducibility
print(tf.__version__)
# Data
x_train = [[1., 2.],
[2., 3.],
[3., 1.],
[4., 3.],
[5., 3.],
[6., 2.]]
y_train = [[0.],
[0.],
[0.],
[1.],
[1.],
[1.]]
x_test = [[5.,2.]]
y_test = [[1.]]
# Tensorflow data API를 통해 학습시킬 값들을 담는다 (Batch Size는 한번에 학습시킬 Size로 정한다)
# features,labels는 실재 학습에 쓰일 Data (연산을 위해 Type를 맞춰준다)
dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(len(x_train))#.repeat()
W = tf.Variable(tf.zeros([2,1]), name='weight')
b = tf.Variable(tf.zeros([1]), name='bias')
# Sigmoid 함수를 가설로 선언합니다
def logistic_regression(features):
hypothesis = tf.divide(1., 1. + tf.exp(tf.matmul(features, W) + b))
return hypothesis
# 비용 함수를 정의합니다.
def loss_fn(hypothesis, features, labels):
cost = -tf.reduce_mean(labels * tf.math.log(logistic_regression(features)) + (1 - labels) * tf.math.log(1 - hypothesis))
return cost
# GradientDescentOptimizer에서 learning_rate를 설정해서 optimizer를 선언한다.
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
# GradientTape를 통해 경사값을 계산합니다.
def grad(features, labels):
with tf.GradientTape() as tape:
loss_value = loss_fn(logistic_regression(features),features, labels)
return tape.gradient(loss_value, [W,b])
EPOCHS = 1001
for step in range(EPOCHS):
for features, labels in iter(dataset):
grads = grad(features, labels)
# 실제 optimizer.apply_gradients를 통해서 실제모델인 [W,b]가 update되서 모델이 만들어지게된다.
optimizer.apply_gradients(grads_and_vars=zip(grads,[W,b]))
if step % 100 == 0:
print("Iter: {}, Loss: {:.4f}".format(step, loss_fn(logistic_regression(features),features,labels)))
# 추론한 값은 0.5를 기준(Sigmoid 그래프 참조)로 0과 1의 값을 리턴합니다.
def accuracy_fn(hypothesis, labels):
predicted = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, labels), dtype=tf.int32))
return accuracy
test_acc = accuracy_fn(logistic_regression(x_test),y_test)
print("Testset Accuracy: {:.4f}".format(test_acc))
댓글남기기