未知错误:KeyError: ‘pyfunc_0’

我正在导出一个保存的模型,该模型使用字符串占位符作为输入张量。我注入了一个图来预处理这个字符串张量,以便它可以传递到模型中。然而,我使用py_func来对张量执行我的Python字符串操作。

在这里,input_text是保存模型签名中的输入张量。我创建了另一个具有默认值input_ints的占位符,该值通过对input_text执行py_func来初始化。我最初将input_text作为一个操作(input_ints =tf.py_func(preprocess, [input_text], tf.int64)),但随后tf.nn.dynamic_rnn不接受形状未指定的张量。

    # 创建图对象
with tf.name_scope('inputs'):
    input_text = tf.placeholder(tf.string, name="input_text")
    input_ints = tf.placeholder_with_default(
        tf.py_func(preprocess, [input_text], tf.int64), shape=[None, None])
def lstm_cell():
    # 你的基础LSTM单元
    lstm = tf.contrib.rnn.BasicLSTMCell(lstm_size, reuse=tf.get_variable_scope().reuse)
    # 为单元添加dropout
    return tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob)
# def create_rnn():
with tf.name_scope("Embeddings"):
    embedding = tf.Variable(tf.random_uniform((vocab_size, embed_size), -1, 1))
    embed = tf.nn.embedding_lookup(embedding, input_ints)
with tf.name_scope("RNN_layers"):
    cell = tf.contrib.rnn.MultiRNNCell([lstm_cell() for _ in range(lstm_layers)])
initial_state = cell.zero_state(batch_size, tf.float32)
with tf.name_scope("RNN_forward"):
    outputs, final_state = tf.nn.dynamic_rnn(cell, embed, initial_state=initial_state)
with tf.name_scope('predictions'):
    predictions = tf.contrib.layers.fully_connected(outputs[:, -1], 1, activation_fn=tf.sigmoid)

现在使用上述实现,我可以正确导出模型,但在恢复模型时,我遇到了以下错误:

2017-11-23 17:29:14.600184: W tensorflow/core/framework/op_kernel.cc:1192] Unknown: KeyError: 'pyfunc_0'
Traceback (most recent call last):
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1327, in _do_call
    return fn(*args)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1306, in _run_fn
    status, run_metadata)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/contextlib.py", line 89, in __exit__
    next(self.gen)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/framework/errors_impl.py", line 466, in raise_exception_on_not_ok_status
    pywrap_tensorflow.TF_GetCode(status))
tensorflow.python.framework.errors_impl.UnknownError: KeyError: 'pyfunc_0'
     [[Node: inputs/PyFunc = PyFunc[Tin=[DT_STRING], Tout=[DT_INT64], token="pyfunc_0", _device="/job:localhost/replica:0/task:0/cpu:0"](_arg_inputs/input_text_0_0)]]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "neural_load_model.py", line 85, in <module>
    result = sess.run(output_tensor, {input_tensor: "Charter Communications, Inc. (CHTR) Stock Rating Reaffirmed by Goldman Sachs Group, Inc. (The)"})
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 895, in run
    run_metadata_ptr)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1124, in _run
    feed_dict_tensor, options, run_metadata)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1321, in _do_run
    options, run_metadata)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/client/session.py", line 1340, in _do_call
    raise type(e)(node_def, op, message)
tensorflow.python.framework.errors_impl.UnknownError: KeyError: 'pyfunc_0'
     [[Node: inputs/PyFunc = PyFunc[Tin=[DT_STRING], Tout=[DT_INT64], token="pyfunc_0", _device="/job:localhost/replica:0/task:0/cpu:0"](_arg_inputs/input_text_0_0)]]
Caused by op 'inputs/PyFunc', defined at:
  File "neural_load_model.py", line 74, in <module>
    model = tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], import_path)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/saved_model/loader_impl.py", line 216, in load
    saver = tf_saver.import_meta_graph(meta_graph_def_to_load, **saver_kwargs)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/training/saver.py", line 1698, in import_meta_graph
    **kwargs)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/framework/meta_graph.py", line 656, in import_scoped_meta_graph
    producer_op_list=producer_op_list)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/framework/importer.py", line 313, in import_graph_def
    op_def=op_def)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 2630, in create_op
    original_op=self._default_original_op, op_def=op_def)
  File "/Users/sakibarrahman/anaconda/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 1204, in __init__
    self._traceback = self._graph._extract_stack()  # pylint: disable=protected-access
UnknownError (see above for traceback): KeyError: 'pyfunc_0'
     [[Node: inputs/PyFunc = PyFunc[Tin=[DT_STRING], Tout=[DT_INT64], token="pyfunc_0", _device="/job:localhost/replica:0/task:0/cpu:0"](_arg_inputs/input_text_0_0)]]

我已经查看了GitHub上发布的这个问题,但我不知道如何实现它。此外,我只是加载模型并传入一个字符串作为输入,并没有使用’freeze_graph’。

我的保存模型的代码:

saver = tf.train.Saver()
# 定义新函数
def preprocess(text):
    ...
tf.reset_default_graph()
...
# 定义原始模型图中没有的新占位符
# 定义原始模型图中没有的、使用py_func初始化的新占位符的默认值
with tf.name_scope('inputs'):
    input_text = tf.placeholder(tf.string, name="input_text")
    input_ints = tf.placeholder_with_default(
        tf.py_func(preprocess, [input_text], tf.int64), shape=[None, None])
...
# 定义我需要的占位符和操作,这些在原始图中存在
saver = tf.train.Saver()
# 服务模型
with tf.Session() as sess:
    # 从旧检查点恢复
    saver.restore(sess, import_path)
    print ('正在导出训练好的模型到 %s'%(export_path))
    builder = saved_model_builder.SavedModelBuilder(export_path)
    original_assets_directory = export_path + '/assets'
    original_assets_filename = "vocabulary.pickle"
    original_assets_filepath = write_vocab(original_assets_directory, 
                                          original_assets_filename)
    # 设置资产集合。
    assets_filepath = tf.constant(original_assets_filepath)
    tf.add_to_collection(tf.GraphKeys.ASSET_FILEPATHS, assets_filepath)
    filename_tensor = tf.Variable(
        original_assets_filename,
        name="vocab_tensor",
        trainable=False,
        collections=[])
    assign_filename_op = filename_tensor.assign(original_assets_filename)
    # 构建signature_def_map。
    classification_inputs = utils.build_tensor_info(input_text)
    classification_outputs_classes = utils.build_tensor_info(predictions)
    classification_signature = signature_def_utils.build_signature_def(
        inputs={signature_constants.CLASSIFY_INPUTS: classification_inputs},
        outputs={
            signature_constants.CLASSIFY_OUTPUT_CLASSES:
                classification_outputs_classes,
        },
        method_name=signature_constants.CLASSIFY_METHOD_NAME)
    legacy_init_op = tf.group(
        tf.tables_initializer(), name='legacy_init_op')
    # 添加签名到可服务模型
    builder.add_meta_graph_and_variables(
        sess, [tag_constants.SERVING],
        signature_def_map={
            signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                classification_signature
        },
        assets_collection=tf.get_collection(tf.GraphKeys.ASSET_FILEPATHS),
        legacy_init_op=tf.group(assign_filename_op))
    print ("已添加元图和变量")
    builder.save()
    print("模型已保存")

我的加载模型的代码。不定义函数或占位符会导致’pyfunc_0’错误:

# 定义预处理函数
def preprocess(text_bin):
    ...
# 定义新占位符
with tf.name_scope('inputs'):
    input_text = tf.placeholder(tf.string, name="input_text")
    input_ints = tf.placeholder_with_default(
        tf.py_func(preprocess, [input_text], tf.int64), shape=[None, None])
with tf.Session(graph=tf.Graph()) as sess:
    # 恢复保存的模型
    model = tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], import_path)
    print("模型已恢复")
    loaded_graph = tf.get_default_graph()
    # 按名称获取必要的张量
    input_tensor_name = model.signature_def[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY].inputs[signature_constants.CLASSIFY_INPUTS].name
    input_tensor = loaded_graph.get_tensor_by_name(input_tensor_name)
    output_tensor_name = model.signature_def[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY].outputs[signature_constants.CLASSIFY_OUTPUT_CLASSES].name
    output_tensor = loaded_graph.get_tensor_by_name(output_tensor_name)
    result = sess.run(output_tensor, {input_tensor: "Some String"})
    print (result)

更新:

在加载保存的模型时定义函数和占位符似乎有效。然而,我不知道为什么它们在使用构建器保存模型之前没有被添加到图中


回答:

使用的预处理函数实际上并不是图的一部分,所以在加载保存的模型时,py_func()不知道使用哪个函数。目前在TensorFlow Serve流程中没有简单的方法在模型内进行预处理。这必须在使用模型之前在客户端完成,或者可能需要创建一个自定义操作,使其成为模型的一部分。另一种选择可能是创建一个自定义可服务模型。

Related Posts

为什么我们在K-means聚类方法中使用kmeans.fit函数?

我在一个视频中使用K-means聚类技术,但我不明白为…

如何获取Keras中ImageDataGenerator的.flow_from_directory函数扫描的类名?

我想制作一个用户友好的GUI图像分类器,用户只需指向数…

如何查看每个词的tf-idf得分

我试图了解文档中每个词的tf-idf得分。然而,它只返…

如何修复 ‘ValueError: Found input variables with inconsistent numbers of samples: [32979, 21602]’?

我在制作一个用于情感分析的逻辑回归模型时遇到了这个问题…

如何向神经网络输入两个不同大小的输入?

我想向神经网络输入两个数据集。第一个数据集(元素)具有…

逻辑回归与机器学习有何关联

我们正在开会讨论聘请一位我们信任的顾问来做机器学习。一…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注