Multi-variable linear regression
시험 점수 예측하기
입력 값 1개(x)를 이용한 회귀(regression)
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
여기서 입력값 x를 variable 혹은 feature라고 한다.
입력 값 3개(x1, x2, x3)를 이용한 회귀(regression)
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
두 차례의 쪽지시험 점수와 중간고사 점수를 통해 기말고사 점수를 예측하는 모델이다. 즉 새로운 학생의 쪽지시험 점수와 중간고사 점수를 알면 기말고사 점수를 예측할 수 있다.
Hypothesis
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
기존의 Hypothesis 함수이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
다변수 회귀의 경우 변수(x)가 3개로 늘어나면 가중치(w)도 3개가 된다.
Cost function
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
cost 함수는 기존에 변수가 하나일 때와 동일하다.
Multi-variable
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
변수가 3개뿐이라면 괜찮지만
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
변수가 10개 혹은 100개로 훨씬 많아지면 식이 복잡하고 길어진다.
이를 해결하기 위해 matrix를 이용할 수 있다.
Matrix
우선 행렬곱(Matrix multiplication)에 대해 알아야 한다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
dot product란 위 예시에서 앞 행렬의 첫 번째 행과 뒷 행렬의 첫 번째 열을 곱하고 더해서 결과 행렬의 첫 번째 요소를 구하는 것이다. 즉, 1*7 + 2*9 + 3*11을 계산해 58을 구한 것이다.
Hypothesis using matrix
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
이렇게 n개의 입력 값과 가중치가 있을 때
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
각 행과 열을 곱해서 각 요소를 구해내면 된다.
이를 식으로 표현하면
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
이렇게 되는데 X와 W의 순서가 바뀐 이유는 X는 행, W는 열을 의미하기 때문이다.
Many x instances
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
위 예시를 이용해 행렬을 이용한 가설함수를 구해보자.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
주목해야 할 점은 데이터의 건수(instance)가 늘어나도 가설함수는 동일하다는 것이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
행렬곱을 하기 위해서는 첫 번째 행렬의 열과 두 번째 행렬의 행의 크기가 일치해야 하고 결과 행렬은 첫 번째 행렬의 행, 두 번째 행렬을 열의 크기와 일치하게 된다.
이 성질을 이용해 필요한 가중치(w, weight) 행렬의 크기를 구할 수 있다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
위와 같이 입력이 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로 써야함. 행렬곱을 계산하기 위해서는 필요한 행과 열을 행, 열의 순서로 써야 계산이 가능하기 때문
다른 자료에서는 가설 함수를 다음과 같이 표현하기도 한다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
위 경우는 θ1이 weight, θ0가 bias를 의미한다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
그리고 위 경우는 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
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
logistic은 0과 1 두 가지로 구분되는 데이터이고 linear는 연속적인 수치형 데이터이다.
Hypothesis Representation
다음은 공부한 시간과 합격 여부의 상관 관계를 표현한 가설 함수이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
Linear regression을 이용하여 연속적인 수치로 나타내었지만 실제 합격 여부를 나타내는 데 필요한 값은 0과 1뿐이다. 따라서 이를 위한 새로운 수식이 필요하다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
여기서 g 함수는 logistic function을 의미한다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
입력 데이터 X에 우선 Linear function을 적용하고 그 결과로 나온 연속적인 데이터를 Logistic function을 이용해 그래프의 모양을 바꿔준다. 그리고 그 결과에 Decision boundary를 0.5로 설정해 0과 1의 값으로 분류하는 것이 g 함수이다.
Sigmoid(Logistic) function
g function을 수식으로 나타내면
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
이 된다. 이를 sigmoid 함수라고도 한다. TensorFlow에 구현되어 있다.
hypothesis = tf.sigmoid(z)
hypothesis = tf.div(1., 1. + tf.exp(z))
Decision Boundary
Decision Boundary는 선형인 경우도 있고 아닌 경우도 있다.
앞서 설명한 예와 같은 경우는 0.5를 기준으로 Decision boundary를 설정했는데 이는 선형이 아닌 수치 하나를 가지고 설정한 경우이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
predicted = tf.cast(hypothesis > 0.5, dtype=tf.int32)
다음은 decision boundary가 선형 함수인 경우들이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
Cost Function
Logistic regression에서 cost가 최소가 되는 θ(가중치, W)를 찾는 과정은 간략하게 다음과 같이 나타낼 수 있다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
Logistic regression의 cost 함수를 그래프로 나타내면 다음과 같이 구불구불한 모양이 된다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
이 구불구불한 값을 로그 함수에 대입하면 원하는 값을 표현할 수 있다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
실제 값이 1일 때, hypothesis가 0에 가까워지면 cost가 커지고 1에 가까워지면 cost가 작아지고
실제 값이 0일 때, hypothesis가 0에 가까워지면 cost가 작아지고 1에 가까워지면 cost가 커진다.
즉 원하는 대로 cost가 표현이 가능하게 된다.
위 두 식을 다음과 같이 하나의 식으로 표현할 수 있다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
cost = -tf.reduce_mean(labels * tf.log(hypothesis) + (1 - labels) * tf.log(1 - hypothesis))
여기서 reduce_mean은 차원 축소를 위한 함수이다.
Optimization
cost가 최소인 θ(가중치, W)를 찾는 방법은 마찬가지로 기울기가 0이 되는 지점을 찾는 것이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
위 식을 통해θ 값을 계속 업데이트해 나가면서 최적의 θ 값을 찾는다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
Softmax Classifier
다음 Sample Dataset을 이용하여 Softmax Classifier에 대해 설명할 것이다.
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
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
![](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
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
'AI' 카테고리의 다른 글
[ai-2team] 4. Neural Networks (0) | 2021.01.27 |
---|---|
[ai-2team] 3. Learning rate, Data preprocessing, Overfitting, Data set (0) | 2021.01.23 |
[AI-3Team] 소프트맥스 회귀(Softmax Regression) 다중 클래스 분류 (0) | 2021.01.13 |
[ai-1team] 6. Recurrent Neural Network (0) | 2021.01.08 |
[ai-2team]1. Linear Regression, minimize cost (0) | 2021.01.07 |