데이터과학 삼학년

[TF.2.x] Keras 모델의 predict output을 사용자가 커스텀하는 방법 본문

Machine Learning

[TF.2.x] Keras 모델의 predict output을 사용자가 커스텀하는 방법

Dan-k 2020. 7. 9. 17:44
반응형

TF.2.x Keras 모델의 predict output을 사용자가 커스텀하는 방법

 

1. 배경 및 필요성

  • tf.2.X tf.keras를 이용하여 예측시 예측결과를 커스텀하는 것의 어려움이 있었음

  • 예측결과에 tf.estimator의 경우, estimatorspec의 predictoutput을 이용해 info_column 을 커스텀 할 수 있음

  • tf.keras에서도 predict output을 커스텀하게 만들 방법 모색 필요

 

2. 방법론

  • tf.keras.Model 의 다중 input, 다중 output을 받는 방식으로, info_column을 output까지 그대로 가져오는 방법

  •  

  • tf.keras.Model 을 상속받아 custom Keras model을 만들어 predict 메서드를 overriding하여 모델을 저장하는 방법

  • 학습된 keras model을 저장하고, 저장된 모델을 다시 불러와  signature의 serving_default 함수를 custom하여 재저장하는 방법

 

3. 실험 분석

  • 1번의 경우, input으로 받은 string 데이터를 Lambda를 이용해 그대로 output까지 가져왔지만, output을 표출하는 부분에서 에러가 발생

    • 무엇보다 모델의 학습과정을 그대로 계속 타고 내려와야한다는 단점이 있었음

    • info_column을 tf.string 으로 싸서 가지고 내려오면 성공했을 것 같음
  • 2번의 경우, predict 함수를 오버라이딩해 원하는 info_column을 결과에 실었지만 해당 모델을 저장한 후 다시 실행하면 동작하지 않음

    • 원인 : 모델 저장시 메서드가 함께 저장되는 것이 아니라 graph와 weight가 저장된 것을 다시 불러와 원래 정의된 serving 함수를 실행시킴

    • 수정 : 원인을 해결하려 메서드를 tf.function으로 싸서 모델을 저장하려 했지만, predict 메서드를 오버라이딩한 함수를 tf.function 데커레이터를 싸려는 과정에서 에러 발생 

  • 3번의 경우, keras 모델을 저장해야 signature로 serving이 생겨, 해당 serving signature를 다시 변경할 수 있었음. 또한 serving_default 함수를 저장하기 위해 tf.function을 데커레이터로 싸서 저장함. 매우 잘 동작함.

info_column을 tf.string으로 싸서 그대로 가져왔으면 성공했을 것 같음

info_column을 tf.string으로 싸서 그대로 가져왔으면 성공했을 것 같음

 

4. 결과

  • keras model 학습후 해당 모델을 저장한 후 다시 로드한 loaded model의 serving 함수를 custom하는 방법을 써서 ai-platform까지 잘 동작하도록 할 수 있었음

    • ai-platform에서 predict 를 실행시 파라미터로 signature-name을 custom함수로 지정한 serving_default 를 입력해줘야함 

 

5. 기타

 

방법론 1번 샘플 코드

import tensorflow as tf

input_data = Input(shape=(30,), name="input_data", dtype=tf.int32)
embed = Embedding(40 + 1, 32, input_length=30, mask_zero=True, dtype=tf.float32,name='Embedding')(input_data)
conv1d = Conv1D(filters=3, kernel_size=2, strides=2, activation='relu')(embed)
flat = Flatten()(conv1d)
output = Dense(2, activation=tf.nn.softmax, name="output")(flat)

info_col = Input(shape=(2,), name="info_column", dtype=tf.string)
output1 = Lambda(lambda x:x,name='output1')(info_col)

model = Model(inputs=[input_data,info_col], outputs=[output,output1])

tf.keras.utils.plot_model(model, show_shapes=True, dpi=90) 

방법론 2번 샘플 코드

class MyKerasRNN(tf.keras.Model):

    def __init__(self, info_cols, vocab_size, embed_dim, max_len, units, n_classes):
        super().__init__()
        self.info_cols = info_cols

        self.embed = Embedding(vocab_size + 1, embed_dim, input_shape=[max_len])
        self.gru = SimpleRNN(units)
        self.output_class = Dense(n_classes, activation='softmax')

        print('if you have any problems or issue, ask bdh for solution')

    @tf.function
    def call(self, inputs, training=False):
        embed = self.embed(inputs)
        gru = self.gru(embed)

        return self.output_class(gru)

    # method overiding

    @tf.function
    def predict(self, x, batch_size=None, verbose=0, steps=None, callbacks=None, max_queue_size=10, workers=1,use_multiprocessing=False):

        print('predict method of keras overiding')

        infos, pred_data = preprocess_for_predict_info(x, self.info_cols)
        outputs = super().predict(pred_data, batch_size, verbose, steps, callbacks, max_queue_size, workers,use_multiprocessing)
        result = get_result_with_info(infos, outputs)

        return result

 

방법론 3번 샘플 코드

MODEL_EXPORT_PATH = os.path.join(args.job_dir, 'keras_export')

print(f'Model exported to: {MODEL_EXPORT_PATH}')

tf.saved_model.save(keras_model, MODEL_EXPORT_PATH)

time.sleep(120)

loaded_model_bdh = tf.keras.models.load_model(MODEL_EXPORT_PATH)

print('completed load saved model')

input_signature = [tf.TensorSpec([None], dtype=tf.string, name=str(i)) for i in args.info_columns]
input_signature.append(tf.TensorSpec([None, MAX_LEN], dtype=tf.int32))

## serving으로 쓸 인자는 정해져 있어야 함

@tf.function(input_signature=input_signature)
def keyed_prediction(pid, logkey, data):
   pred = loaded_model_bdh(data, training=False)
   return {
       'output': pred,
       'pid': pid,
       'logkey':logkey
   }

KEYED_EXPORT_PATH = os.path.join(args.job_dir, 'keras_export', 'keyed_model')

loaded_model_bdh.save(KEYED_EXPORT_PATH, signatures={'serving_default': keyed_prediction})

print(f'Model with keys exported to: {KEYED_EXPORT_PATH}')`
[GCP ai-platform prediction]

gcloud ai-platform jobs submit prediction predict_text_model_pactice_20200709_b \
                 --model-dir gs://model/custom_keras_model_20200709_b/keras_export/keyed_model \
                --runtime-version 2.1 \
                --data-format text \
                --region us-central1 \
                --input-paths  gs://preprocess/predict/sequence_predict.json \
                --output-path gs://predict/20200709_b/output \
                --signature-name serving_default

 

728x90
반응형
LIST
Comments