tf.data로 데이터 파이프라인 만들고 추론하는 것 까지 해보기

2020. 3. 22. 18:02분석 Python/Tensorflow

728x90

광고 한번만 눌러주세요 ㅎㅎ 블로그 운영에 큰 힘이 됩니다.

예전에 tf.data로 인풋 파이프라인을 만들고, 모델을 만든 뒤, 모델을 저장해서 사용해봤는데, 
추론 결과가 계속 동일한 이상한 현상이 발견했다.
그래서 오랜만에 tf.data도 다시 공부하고 모델 학습 후 저장한 것을 다른 스크립트에서 돌릴 때 어떻게 했는지에 대해서 공유한다.
일단은 정확한 답은 아닐 수 있지만, 충분히 사용할만할 것 같다고 생각한다.

일단 중요한 것은 데이터 처리 이후니까 전처리 단계는 가볍게 패스

개인적으로 initializer를 사용하는 것을 선호한다.
tf.data에서는 batch_size를 정해줘야하는데, 이 부분을 빈 홀더로 남겨놓고, 전체 추론할 때는 바꾸면서 사용할 수 있게 했다. 

import tensorflow as tf
tf.reset_default_graph()
X = tf.placeholder(tf.float32 , shape = [None,train_x.shape[1]])
y = tf.placeholder(tf.float32 , shape = [None,1])
batch_size = tf.placeholder(tf.int64)

데이터 파이프 라인을 만들어 보자.

data_tuple = (X,y)
dataset = tf.data.Dataset.from_tensor_slices(data_tuple)
dataset = dataset.shuffle(buffer_size= 1000)
dataset = dataset.batch(batch_size=batch_size, drop_remainder=True)
iter = dataset.make_initializable_iterator()
feature_batch , label_batch = iter.get_next()

이제 이 데이터 파이프 라인은 데이터를 어떻게 초기값을 넣어주는냐에 따라서, 다른 값들이 들어갈 것이다.

이제 네트워크를 만들어 보자.

W1 = tf.get_variable("w",shape=[train_x.shape[1],25])
B1 = tf.get_variable("b",shape=[25])
W2 = tf.get_variable("w2",shape=[25,15])
B2 = tf.get_variable("b2",shape=[15])
W3 = tf.get_variable("w3",shape=[15,1])
B3 = tf.get_variable("b3",shape=[1])

def Layer(X , reuse = False) :
    layer1 = tf.nn.relu(tf.matmul(X, W1) + B1)
    layer2 = tf.nn.selu(tf.matmul(layer1, W2) + B2)
    logit = tf.matmul(layer2, W3) + B3
    return logit

만든 네트워크에다가 loss랑 optimizer까지 구성해보자.

loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = label_batch , logits=logit)
Loss = tf.reduce_mean(loss)
vars = tf.trainable_variables()
optimizer = tf.train.AdadeltaOptimizer(1e-3).minimize(Loss , var_list = vars)

그리고 metric으로는 auc를 보고 싶으니, auc를 볼 수 있게 해보자.

prob= tf.nn.sigmoid(logit)
auc_value , update_auc = tf.metrics.auc(label_batch , prob , curve="ROC")

## 여기가 추론 부분의 핵심 ##
보통 추론을 할 때는 batch성으로 나누지 않고, 바로 실시간이나 전체 데이터를 추론하기를 원할 것이다.
하지만 지금 포맷을 그대로 유지해서 $prob$는 객체를 그대로 쓰게 되면, 데이터 들어올 때마다 파이프라인을 초기화해줘야 하는 상황이 된다. 그래서 나는 바로 $X$를 받아서 네트워크를 태운 후 확률 값이 나올 수 있게, 새로 하나를 만들었다. 그리고 이것을 나중에 쉽게 꺼내서 사용하기 위해 tf.get_collection을 사용해서 $Probability$에 넣어 놓았다.

output = tf.nn.sigmoid(Layer(X))
tf.add_to_collection('Probability', X)
tf.add_to_collection('Probability', output)

자 일단 다 구성은 했으니, 학습을 시켜보자.
먼가 기존에 feed_dict을 쓰는 것보다 훨씬 간단해진 것 같아서 보기 좋다. 
주요하게 볼 점은 배치성 작업을 하는 것은 while 문에 넣어 놓고, 학습되게 하고, test 데이터로 추론하는 것은 while 문 밖에서 처리해서 출력하게 하는 구조로 하였다. 
그래서 학습이 모두 끝나고 저장하게 했다.

config = tf.ConfigProto(log_device_placement=True)
config.gpu_options.allow_growth = True
EPOCHS = 10
with tf.Session(config=config) as sess:
    saver = tf.train.Saver()
    init = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
    sess.run(init)
    for i in range(EPOCHS):
        
        sess.run(iter.initializer , 
                 feed_dict= {X : train_x.values,
                             y : train_y.values.reshape(-1,1),
                             batch_size : 1000}) # switch to train dataset
        while True :
            try :
                probs , _,auc,Loss2,_=sess.run([prob, auc_value,update_auc,Loss,optimizer])
            except tf.errors.OutOfRangeError :
                break
        sess.run(iter.initializer ,
                 feed_dict= {X : test_x.values,
                             y : test_y.values.reshape(-1,1),
                             batch_size : len(test_x)
                            }) # switch to train dataset
        probs , _ , auc = sess.run([prob,auc_value,update_auc])
        print(f"Epoch : {i}, AUC : {auc*100:.2f}", end="\r")
    meta_graph_bool = True
    saver.save(sess,
               "./tf_data_test_model.ckpt",
               global_step=i, write_meta_graph=meta_graph_bool)

모델 저장된 파일들

그러면 이런 식으로 떨궈지게 된다. 
이제 저장된 모델을 사용해서 추론을 해보자.

추론 코드는 만약 tf.get_collection을 사용했다면, 아주 간단하게 할 수 있다.
일단 모델을 불러들인다.

import tensorflow as tf
import os
file_path = "./tf_data_test_model.ckpt-9.meta"
tf.reset_default_graph()
config=tf.ConfigProto(log_device_placement=True)
config.gpu_options.allow_growth = True
sess = tf.Session(config= config)
sess.run(tf.global_variables_initializer())
saver = tf.train.import_meta_graph(file_path)
saver.restore(sess, "tf_data_test_model.ckpt-9")

그리고 불러들인 모델에서 위에서 $Probability$에 넣어놓았던, $X,Prob$를 꺼내보자. 꺼낼 때는 get_collection을 사용한다.

X = tf.get_collection("Probability")[0]
prob = tf.get_collection("Probability")[1]

이제 우리에게 이런 데이터가 있다고 했을 때 추론을 하게 되면?

import numpy as np
sample_data = np.array([[-0.97979798, -0.89655172, -0.2       , -0.2       , -0.8       ,
        -0.8       , -1.        , -1.        , -0.61658433, -0.86167135,
        -0.82655422, -0.51359173, -0.83870382, -0.553858  , -1.        ,
        -0.99886628, -1.        , -1.        , -0.97543583, -1.        ,
         0.        ,  1.        ,  0.        ,  0.        ,  1.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         1.        ,  0.        ,  0.        ]])
sess.run(prob, feed_dict={X : sample_data})

이제 또 다른 데이터를 넣으면 어떻게 될까?

sample_data2 = np.array([[-0.61616162, -0.72413793, -0.60341802, -1.        , -0.8       ,
        -0.64320093, -0.8       , -0.77777778, -0.61658433, -0.86755913,
        -0.82298324, -0.57483715, -0.83900129, -0.63972138, -1.        ,
        -0.99351527, -0.93544249, -1.        , -0.98723429, -1.        ,
         0.        ,  1.        ,  0.        ,  1.        ,  0.        ,
         0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
         0.        ,  1.        ,  0.        ]])

확률 값이 다르게 나오는 것을 확인했다!

tf.data에 집착하는 이유는, tf.data가 더 빠르다고 한다. 
그리고 유틸성이 증가한다.  shuffle에 용이성, run session할 때 깔끔하게 할 수 있고, 다른 feed_dict 같이 관리하는 것에 대해서 편리함 등이 있는 것 같다.
그리고 보통 이미지 데이터를 처리할 때 좋을 것 같고, 그리고 만약 데이터가 크다고 했을 때, 
tf.data 같은 경우 배치 단위로 가져올 수 있기 때문에, 리소스 측면에서도 훨씬 좋다고 생각한다!

http://www.programmersought.com/article/1339534134/

 

TensorFlow - Build Data Pipeline and tf.data vs. feed_dict - Programmer Sought

  Original:Why tf.data is much better than feed_dict and how to build a simple data pipeline in 5 minutes. 1. Comparison of feed_dict and tf.data The introduction to the Tensorflow Getting Started Manual is generallyfeed_dictMethod, attf.Seession.run()Sess

www.programmersought.com

 

728x90