2020. 12. 5. 23:26ㆍ머신러닝
import tensorflow as tf
import numpy as np
print(tf.__version__)
tf.random.set_seed(777) # for reproducibility
x_data = [[1, 2, 1, 1],
[2, 1, 3, 2],
[3, 1, 3, 4],
[4, 1, 5, 5],
[1, 7, 5, 5],
[1, 2, 5, 6],
[1, 6, 6, 6],
[1, 7, 7, 7]]
y_data = [[0, 0, 1],
[0, 0, 1],
[0, 0, 1],
[0, 1, 0],
[0, 1, 0],
[0, 1, 0],
[1, 0, 0],
[1, 0, 0]]
#convert into numpy and float format
x_data = np.asarray(x_data, dtype=np.float32)
y_data = np.asarray(y_data, dtype=np.float32)
코드를 이해해 봅시다~
4개의 Feature, 8개의 Batch와 3개의 Label이네요~ x_data는 (8, 4) y_data는 (8, 3).
#Weight and bias setting
W = tf.Variable(tf.random.normal(4, 3), name='weight')
b = tf.Variable(tf.random.normal(3), name='bias')
variables = [W, b]
그럼 Weight는 (4, 3)인 행렬일테고, Bias는 3 짜리 벡터겠지요~ 4개의 feature와 3개의 label이니까.
<tf.Variable 'weight:0' shape=(4, 3) dtype=float32, numpy=
array([[ 0.7706481 , 0.37335402, -0.05576323],
[ 0.00358377, -0.5898363 , 1.5702795 ],
[ 0.2460895 , -0.09918973, 1.4418385 ],
[ 0.3200988 , 0.526784 , -0.7703731 ]], dtype=float32)>
<tf.Variable 'bias:0' shape=(3,) dtype=float32, numpy=array([-1.3080608 , -0.13253094, 0.5513761 ], dtype=float32)>
# tf.nn.softmax computes softmax activations
# softmax = exp(logits) / reduce_sum(exp(logits), dim)
def hypothesis(X):
return tf.nn.softmax(tf.matmul(X, W) + b)
print(hypothesis(x_data))
hypothesis를 정의해주는데, 저번에 Sigmoid 처럼 직접 함수를 만들 수 있지만 이번에는 softmax를 씌워줍니다. tf.nn.softmax()를 이용하네요.
여기에 x_data를 넣어봤더니
tf.Tensor(
[[1.36571955e-02 7.90162385e-03 9.78441238e-01]
[3.92597765e-02 1.70347411e-02 9.43705440e-01]
[3.80385250e-01 1.67723164e-01 4.51891571e-01]
[3.23390484e-01 5.90759404e-02 6.17533624e-01]
[3.62997412e-06 6.20727292e-08 9.99996305e-01]
[2.62520202e-02 1.07279615e-02 9.63019967e-01]
[1.56525111e-05 4.21802781e-07 9.99983907e-01]
[2.94076904e-06 3.81133276e-08 9.99997020e-01]], shape=(8, 3), dtype=float32)
궁금해서 더해봤다.
1.36571955e-02 + 7.90162385e-03 + 9.78441238e-01 = 1.00000005735
3.92597765e-02 + 1.70347411e-02 + 9.43705440e-01 = 0.99999995760 (여기까지~ softmax가 잘 되는구나~)
근데 다음 줄에서 이게 되나 테스트를 하네? ㅋㅋㅋ
# Softmax onehot test
sample_db = [[8,2,1,4]]
sample_db = np.asarray(sample_db, dtype=np.float32)
print(hypothesis(sample_db))
tf.Tensor([[0.9302204 0.06200533 0.00777428]], shape=(1, 3), dtype=float32)
다음은 cost function. Cross entropy를 떠올려보자. Label(정답, y_data)과 우리 hypothesis의 예측 결과에 -log씌운 값을 곱해준다. -log(hypothesis(x_data)) -> -(y_data*log(hypothesis(x_data))
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))
세 번째 줄 cost = -tf.reduce_sum(Y * tf.math.log(logits), axis=1) 에서 axis = 1이 의미하는 바는 뭘까? 찾아보니 tf.reduce_sum()할 때처럼 2차원 이상의 행렬 두 개를 만질 때 필요한 개념인 것 같다.
우리의 코드에 맞춰 생각해보자. Y*tf.math.log(logists) 로 element wise 곱을 하면 8*3의 행렬이 나오겠지?
ex) [[0, 0, 1], [0, 0, 2], [0, 0, 3], [0, 4, 0], [0, 5, 0], [0, 6, 0], [7, 0, 0], [9, 0, 0]] 이런 모양.
그럼 이걸 sum 할 때 각각의 성분을 모조리 더해야 할지, 3개씩 묶인 행 단위로 더해야 할 지 알려줘야 한다. 이걸 axis로 알려줘야 하는데 0은 가장 바깥. 한 차원씩 들어갈 때마다 1씩 올라간다. 그러니까 만약 위 행렬을 axis = 0으로 tf.reduce_sum 하면 [16, 15, 6] 이 결과가 될 테고, axis = 1으로 tf.reduce_sum 한 차원 더 들어가서 각 성분끼리 더하면 37이 될 것이다.
행렬 만질 때 기본적인 개념들이 있는 글 : https://doorbw.tistory.com/135
이걸 우리의 hypothesis에 적용했더니 tf.Tensor(6.07932, shape=(), dtype=float32)
'''
x = tf.constant(3.0)
with tf.GradientTape() as g:
g.watch(x)
y = x * x # x^2
dy_dx = g.gradient(y, x) # Will compute to 6.0
print(dy_dx) >> tf.Tensor(6.0, shape=(), dtype=float32)
'''
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))
[<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)>]
위의 cost_fn을 GradeintDescent 해주려고 GradientTape를 이용한다. 주석 박스는 GradientTape가 뭔지 보여주는 예제이다.
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)
Loss at epoch 1: 2.849417
Loss at epoch 100: 0.684151
Loss at epoch 200: 0.613813
Loss at epoch 300: 0.558204
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.165351
Loss at epoch 2000: 0.159483
keras 옵티마이저로 최적화.
테스트를 해보자.
b = hypothesis(x_data)
print(b)
print(tf.argmax(b, 1))
print(tf.argmax(y_data, 1)) # matches with y_data
여기서 tf.argmax에 들어가는 숫자는 axis이다. 1이니까 하나의 행을 한 단위로 잘라서 그 안의 최댓값의 인덱스를 뽑는다.
tf.Tensor( [[2.1975952e-06 1.2331170e-03 9.9876475e-01]
[1.1288594e-03 8.1546687e-02 9.1732442e-01]
[2.2205539e-07 1.6418624e-01 8.3581358e-01]
[6.3921816e-06 8.5045439e-01 1.4953922e-01]
[2.6150808e-01 7.2644734e-01 1.2044534e-02]
[1.3783246e-01 8.6214006e-01 2.7417480e-05]
[7.4242145e-01 2.5754160e-01 3.6978410e-05]
[9.2197549e-01 7.8023903e-02 6.0005692e-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)
우리의 모델이 뽑은 결과를 보면 각각의 행에서 2,2,2,1,1,1,0,0 의 값들이 가장 높다고 나온다. 실제 y_data도 같은 결과다.
feature를 갖는 데이터를 넣어서 그에 따른 출력을 뽑고 그게 정답과 비슷하게 유도해가는 과정. 단순한 것 같은데 단순하게 이해는 안 된다. 그리고 단순하게 만들어지지도 않았겠지? 그리고 강력하다.
'머신러닝' 카테고리의 다른 글
[텐서플로우로 시작하는 딥러닝 기초] Lab 07-1: Application & Tips: 학습률(Learning Rate)과 데이터 전처리(Data Preprocessing) (0) | 2020.12.27 |
---|---|
[텐서플로우로 시작하는 딥러닝 기초] Lab 06-2: Fancy Softmax classifier 를 TensorFlow 로 구현하기 (0) | 2020.12.22 |
[텐서플로우로 시작하는 딥러닝 기초] Lec 06-2: Softmax Classifier의 cost함수 (0) | 2020.11.11 |
[텐서플로우로 시작하는 딥러닝 기초] Lec 06-1: Softmax Regression: 기본 개념소개 (0) | 2020.10.29 |
[텐서플로우로 시작하는 딥러닝 기초] 복습과 고민 (0) | 2020.10.17 |