简体   繁体   English

将Tensorflow预处理添加到现有Keras模型(用于Tensorflow服务)

[英]Add Tensorflow pre-processing to existing Keras model (for use in Tensorflow Serving)

I would like to include my custom pre-processing logic in my exported Keras model for use in Tensorflow Serving. 我想在我导出的Keras模型中包含我的自定义预处理逻辑,以用于Tensorflow服务。

My pre-processing performs string tokenization and uses an external dictionary to convert each token to an index for input to the Embedding layer: 我的预处理执行字符串标记化并使用外部字典将每个标记转换为索引以输入到嵌入层:

from keras.preprocessing import sequence

token_to_idx_dict = ... #read from file

# Custom Pythonic pre-processing steps on input_data
tokens = [tokenize(s) for s in input_data]
token_idxs = [[token_to_idx_dict[t] for t in ts] for ts in tokens]
tokens_padded = sequence.pad_sequences(token_idxs, maxlen=maxlen)

Model architecture and training: 模型架构和培训:

model = Sequential()
model.add(Embedding(max_features, 128, input_length=maxlen))
model.add(LSTM(128, activation='sigmoid'))
model.add(Dense(n_classes, activation='softmax'))
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')

model.fit(x_train, y_train)

Since the model will be used in Tensorflow Serving, I want to incorporate all pre-processing logic into the model itself (encoded in the exported model file). 由于该模型将用于Tensorflow服务,我想将所有预处理逻辑合并到模型本身(在导出的模型文件中编码)。

Q: How can I do so using the Keras library only? 问:我怎样才能使用Keras库?

I found this guide explains how to combine Keras and Tensorflow. 我发现本指南解释了如何结合Keras和Tensorflow。 But I'm still unsure how to export everything as one model. 但我仍然不确定如何将所有东西都作为一个模型出口。

I know Tensorflow has built-in string splitting, file I/O , and dictionary lookup operations . 我知道Tensorflow有内置的字符串拆分, 文件I / O字典查找操作

Pre-processing logic using Tensorflow operations: 使用Tensorflow操作的预处理逻辑:

# Get input text
input_string_tensor = tf.placeholder(tf.string, shape={1})
# Split input text by whitespace
splitted_string = tf.string_split(input_string_tensor, " ")
# Read index lookup dictionary
token_to_idx_dict = tf.contrib.lookup.HashTable(tf.contrib.lookup.TextFileInitializer("vocab.txt", tf.string, 0, tf.int64, 1, delimiter=","), -1)
# Convert tokens to indexes
token_idxs = token_to_idx_dict.lookup(splitted_string)
# Pad zeros to fixed length
token_idxs_padded = tf.pad(token_idxs, ...)

Q: How can I use these Tensorflow pre-defined pre-processing operations and my Keras layers together to both train and then export the model as a "black box" for use in Tensorflow Serving? 问:我如何使用这些Tensorflow预定义的预处理操作和我的Keras层一起训练然后将模型导出为用于Tensorflow服务的“黑盒子”?

I figured it out, so I'm going to answer my own question here. 我想通了,所以我将在这里回答我自己的问题。

Here's the gist: 这是要点:

First, (in separate code file) I trained the model using Keras only with my own pre-processing functions, exported the Keras model weights file and my token-to-index dictionary. 首先,(在单独的代码文件中)我使用Keras仅使用我自己的预处理函数训练模型,导出Keras模型权重文件和我的令牌到索引字典。

Then, I copied just the Keras model architecture, set the input as the pre-processed tensor output, loaded the weights file from the previously trained Keras model, and sandwiched it between the Tensorflow pre-processing operations and the Tensorflow exporter. 然后,我只复制了Keras模型架构,将输入设置为预处理张量输出,从先前训练的Keras模型加载权重文件,并将其夹在Tensorflow预处理操作和Tensorflow导出器之间。

Final product: 最终产品:

import tensorflow as tf
from keras import backend as K
from keras.models import Sequential, Embedding, LSTM, Dense
from tensorflow.contrib.session_bundle import exporter
from tensorflow.contrib.lookup import HashTable, TextFileInitializer

# Initialize Keras with Tensorflow session
sess = tf.Session()
K.set_session(sess)

# Token to index lookup dictionary
token_to_idx_path = '...'
token_to_idx_dict = HashTable(TextFileInitializer(token_to_idx_path, tf.string, 0, tf.int64, 1, delimiter='\t'), 0)

maxlen = ...

# Pre-processing sub-graph using Tensorflow operations
input = tf.placeholder(tf.string, name='input')
sparse_tokenized_input = tf.string_split(input)
tokenized_input = tf.sparse_tensor_to_dense(sparse_tokenized_input, default_value='')
token_idxs = token_to_idx_dict.lookup(tokenized_input)
token_idxs_padded = tf.pad(token_idxs, [[0,0],[0,maxlen]])
token_idxs_embedding = tf.slice(token_idxs_padded, [0,0], [-1,maxlen])

# Initialize Keras model
model = Sequential()
e = Embedding(max_features, 128, input_length=maxlen)
e.set_input(token_idxs_embedding)
model.add(e)
model.add(LSTM(128, activation='sigmoid'))
model.add(Dense(num_classes, activation='softmax'))

# Load weights from previously trained Keras model
weights_path = '...'
model.load_weights(weights_path)

K.set_learning_phase(0)

# Export model in Tensorflow format
# (Official tutorial: https://github.com/tensorflow/serving/blob/master/tensorflow_serving/g3doc/serving_basic.md)
saver = tf.train.Saver(sharded=True)
model_exporter = exporter.Exporter(saver)
signature = exporter.classification_signature(input_tensor=model.input, scores_tensor=model.output)
model_exporter.init(sess.graph.as_graph_def(), default_graph_signature=signature)
model_dir = '...'
model_version = 1
model_exporter.export(model_dir, tf.constant(model_version), sess)

# Input example
with sess.as_default():
    token_to_idx_dict.init.run()
    sess.run(model.output, feed_dict={input: ["this is a raw input example"]})

The accepted answer is super helpful, however it uses an outdated Keras API as @Qululu mentioned, and an outdated TF Serving API (Exporter), and it does not show how to export the model so that its input is the original tf placeholder (versus Keras model.input, which is post preprocessing). 接受的答案非常有用,但它使用过时的Keras API,如@Qululu提到的,以及过时的TF服务API(导出器),它没有显示如何导出模型以使其输入是原始的tf占位符(相对于Keras model.input,后期预处理)。 Following is a version that works well as of TF v1.4 and Keras 2.1.2: 以下版本适用于TF v1.4和Keras 2.1.2:

sess = tf.Session()
K.set_session(sess)

K._LEARNING_PHASE = tf.constant(0)
K.set_learning_phase(0)

max_features = 5000
max_lens = 500

dict_table = tf.contrib.lookup.HashTable(tf.contrib.lookup.TextFileInitializer("vocab.txt",tf.string, 0, tf.int64, TextFileIndex.LINE_NUMBER, vocab_size=max_features, delimiter=" "), 0)

x_input = tf.placeholder(tf.string, name='x_input', shape=(None,))
sparse_tokenized_input = tf.string_split(x_input)
tokenized_input = tf.sparse_tensor_to_dense(sparse_tokenized_input, default_value='')
token_idxs = dict_table.lookup(tokenized_input)
token_idxs_padded = tf.pad(token_idxs, [[0,0],[0, max_lens]])
token_idxs_embedding = tf.slice(token_idxs_padded, [0,0], [-1, max_lens])

model = Sequential()
model.add(InputLayer(input_tensor=token_idxs_embedding, input_shape=(None, max_lens)))

 ...REST OF MODEL...

model.load_weights("model.h5")

x_info = tf.saved_model.utils.build_tensor_info(x_input)
y_info = tf.saved_model.utils.build_tensor_info(model.output)

prediction_signature = tf.saved_model.signature_def_utils.build_signature_def(inputs={"text": x_info}, outputs={"prediction":y_info}, method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME)

builder = saved_model_builder.SavedModelBuilder("/path/to/model")

legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')

init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())
sess.run(init_op)


# Add the meta_graph and the variables to the builder
builder.add_meta_graph_and_variables(
  sess, [tag_constants.SERVING],
  signature_def_map={
       signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
           prediction_signature,
  },
  legacy_init_op=legacy_init_op)

builder.save()  

UPDATE Doing pre-processing for inference with Tensorflow is a CPU op, and is not carried out efficiently if the model is deployed on a GPU server. 更新使用Tensorflow进行推理的预处理是CPU操作,如果模型部署在GPU服务器上,则无法有效执行。 The GPU stalls really bad, and the throughput is very low. GPU失速非常糟糕,吞吐量非常低。 Therefore, we ditched this for efficient pre-processing in the client process, instead. 因此,我们放弃了这一点,以便在客户端进程中进行有效的预处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将某些预处理步骤包含到 Tensorflow 服务模型中 - How to INCLUDE certain pre-processing step into model for Tensorflow serving 保存在 Tensorflow 模型中的自定义文本预处理 - Custom text pre-processing saved in Tensorflow model 从 tensorflow lite model 推断的正确预处理管道 - Correct pre-processing pipeline for inference from tensorflow lite model 将预处理步骤捆绑到 Tensorflow SavedModel - Bundle pre-processing steps to Tensorflow SavedModel 使用 Tensorflow Serving 为 Keras 模型提供服务 - Serving a Keras model with Tensorflow Serving 在 AWS SageMaker 中使用预处理和后处理创建和部署预训练 tensorflow model - Creating and deploying pre-trained tensorflow model with pre-processing and post-processing in AWS SageMaker 结合 scikit-learn model 使用 TensorFlow 预处理(tf.feature_column) - Using TensorFlow pre-processing (tf.feature_column) in combination with scikit-learn model 复制 Python 工作流程以在 Javascript 环境中对 Tensorflow 的图像进行预处理 - Replicating a Python workflow for pre-processing of an image for Tensorflow in a Javascript environment 如何在 tensorflow.js 中使用现有的 keras model - How to use existing keras model in tensorflow.js 如何使用 tensorflow_datasets (tfds) 实现和理解预处理和数据扩充? - How to implement and understand Pre-processing and Data augmentation with tensorflow_datasets (tfds)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM