Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将Tensorflow预处理添加到现有Keras模型中(用于Tensorflow服务)_Python_Tensorflow_Keras_Tensorflow Serving - Fatal编程技术网

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

Python 将Tensorflow预处理添加到现有Keras模型中(用于Tensorflow服务),python,tensorflow,keras,tensorflow-serving,Python,Tensorflow,Keras,Tensorflow Serving,我想在导出的Keras模型中包含我的自定义预处理逻辑,以便在Tensorflow服务中使用 我的预处理执行字符串标记化,并使用外部字典将每个标记转换为索引,以便输入到嵌入层: 模型架构和培训: 由于该模型将用于Tensorflow服务,因此我希望将所有预处理逻辑合并到模型本身(在导出的模型文件中编码) Q:如何仅使用Keras库进行此操作? 我发现了如何结合Keras和Tensorflow的解释。但我仍然不确定如何将所有内容导出为一个模型 我知道Tensorflow有内置的字符串拆分,而且 使用

我想在导出的Keras模型中包含我的自定义预处理逻辑,以便在Tensorflow服务中使用

我的预处理执行字符串标记化,并使用外部字典将每个标记转换为索引,以便输入到嵌入层:

模型架构和培训:

由于该模型将用于Tensorflow服务,因此我希望将所有预处理逻辑合并到模型本身(在导出的模型文件中编码)

Q:如何仅使用Keras库进行此操作?

我发现了如何结合Keras和Tensorflow的解释。但我仍然不确定如何将所有内容导出为一个模型

我知道Tensorflow有内置的字符串拆分,而且

使用Tensorflow操作的预处理逻辑:


Q:我如何使用这些Tensorflow预定义的预处理操作和我的Keras层来同时进行训练,然后将模型导出为“黑匣子”以用于Tensorflow服务?

我想出来了,所以我将在这里回答我自己的问题

要点如下:

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"]})
首先,(在单独的代码文件中)我仅使用Keras和我自己的预处理函数训练模型,将Keras模型权重文件和我的令牌导出到索引字典

然后,我复制了Keras模型架构,将输入设置为预处理的tensor输出,从先前训练的Keras模型加载权重文件,并将其夹在Tensorflow预处理操作和Tensorflow导出器之间

最终产品:

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"]})

公认的答案非常有用,但是它使用了@Qululu提到的过时Keras API和过时的TF服务API(导出器),并且它没有显示如何导出模型,以便其输入是原始TF占位符(相对于Keras model.input,这是后预处理)。以下是TFV1.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()  

更新使用Tensorflow进行推理的预处理是一项CPU操作,如果模型部署在GPU服务器上,则无法有效执行。GPU的延迟非常严重,吞吐量非常低。因此,为了在客户端过程中进行有效的预处理,我们放弃了这种方法。

找到了解决方案?@OphirYoktan请参见下面的答案。仅供参考,层方法
set_input()
仅适用于Keras版本1.1.1。之后,它被移除了。在以后的版本中,我不知道如何将层的输入设置为Tensorflow张量。如果有人这样做,请发表评论。Hi@Qululu,在Keras 2.0+中,您现在可以使用Keras模型/层自动调用Tensorflow张量/占位符(就像您通常使用Keras层/张量等一样)。。。例如,请参阅此官方页面:。。。希望这有帮助!;)如何使用tf预处理训练模型?如何调用.fit()以及tf占位符是如何输入的?目前似乎不支持该占位符。为了调用.fit(),我最终从模型中删除了InputLayer,并这样调用了fit():
model.fit(token\u idxs\u embedding.eval(session=sess,feed\u dict={x\u input:x\u train}),y\u train…
。这具体化了TF占位符。为了进行推断,我将InputLayer放回模型并保存了它。您是如何调用model.fit()的这里?输入只是字符串列表吗?我把原始字符串放在哪里处理?@chattrat423这是一个用于导出模型进行推理的脚本,这样Tensorflow可以代替客户端进行预处理。对于培训,您可以使用仅限Keras的版本,而不需要Tensorflow预处理代码(您可以在任何python库中进行预处理)。谢谢,我真的很欣赏这种清晰。您是否也有一个后处理示例,我们可以将预测的标签索引转换为字符串标签形式?我正在尝试为tensorflow创建此示例,用于我的Kerasmodel@chattrat423我不确定我是否理解您的问题。当您将模型导出为Sav时edModel,您应该使用
tf.saved_model.signature_def_utils.build_signature_def
定义输出签名,如代码所示。这是特定于模型的,应该适合模型的输出层。客户端应该提取预测从TF Serving调用并解析它们。如果您的SavedModel已成功保存,请编写一个小python脚本来调用它并打印响应,它将向您显示需要解析的数据结构。@chattrat423我没有做过类似的操作(即使用Tensorflow进行“后处理”).如前所述,我发现最好在客户端流程中进行所有预处理/后处理,而不是在Tensorflow中。
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"]})
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()