【问题标题】:Prediction from model saved with `tf.estimator.Estimator` in Tensorflow在 Tensorflow 中使用“tf.estimator.Estimator”保存的模型进行预测
【发布时间】:2017-05-14 16:06:54
【问题描述】:

我正在使用tf.estimator.Estimator 训练模型:

def model_fn(features, labels, mode, params, config):

    input_image = features["input_image"]

    eval_metric_ops = {}
    predictions = {}

    # Create model
    with tf.name_scope('Model'):

        W = tf.Variable(tf.zeros([784, 10]), name="W")
        b = tf.Variable(tf.zeros([10]), name="b")
        logits = tf.nn.softmax(tf.matmul(input_image, W, name="MATMUL") + b, name="logits")

    loss = None
    train_op = None

    if mode != tf.estimator.ModeKeys.PREDICT:
        loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits))
        train_op = tf.contrib.layers.optimize_loss(loss=loss,
                                                       global_step=tf.contrib.framework.get_global_step(),
                                                       learning_rate=params["learning_rate"],
                                                       optimizer=params["optimizer"])
    # Add prediction
    classes = tf.as_string(tf.argmax(input=logits, axis=1, name="class"))
    with tf.name_scope('Predictions'):
        predictions["logits"] = logits
        predictions["classes"] = classes

    export_outputs = {"classes": tf.estimator.export.ClassificationOutput(classes=classes)}
    export_outputs = {"classes": tf.estimator.export.PredictOutput({"labels": classes})}

    spec = tf.estimator.EstimatorSpec(mode=mode,
                                      predictions=predictions,
                                      loss=loss,
                                      train_op=train_op,
                                      eval_metric_ops=eval_metric_ops,
                                      export_outputs=export_outputs,
                                      training_chief_hooks=None,
                                      training_hooks=None,
                                      scaffold=None)
    return spec

def input_fn(dataset, n=10):  

    return dataset.images[:n], dataset.labels[:n]


model_params = {"learning_rate": 1e-3,
                "optimizer": "Adam"}

#run_path = os.path.join(runs_path, datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
run_path = os.path.join(runs_path, "run1")
if os.path.exists(run_path):
    shutil.rmtree(run_path)

estimator = tf.estimator.Estimator(model_fn=model_fn, model_dir=run_path, params=model_params)


# Train
inputs = lambda: input_fn(mnist.train, n=15)
estimator.train(input_fn=inputs, steps=1000)

模型和权重在训练期间正确保存。

现在我想在另一个脚本中重新加载模型 + 权重以进行预测。

但我不知道如何指定输入,因为我在 model_fn 函数中没有引用它。

# Get some data to predict
input_data = mnist.test.images[:5]

tf.reset_default_graph()
run_path = os.path.join(runs_path, "run1")

# Load the model (graph)
input_checkpoint = os.path.join(run_path, "model.ckpt-1000")
saver = tf.train.import_meta_graph(input_checkpoint + '.meta', clear_devices=True)

# Restore the weights
sess = tf.InteractiveSession()
saver.restore(sess, input_checkpoint)
graph = sess.graph

# Get the op to compute for prediction
predict_op = graph.get_operation_by_name("Predictions/class")

# predictions = sess.run(predict_op, feed_dict=????)

这是返回 graph.get_collection("variables"):

[<tf.Variable 'global_step:0' shape=() dtype=int64_ref>,
 <tf.Variable 'Model/W:0' shape=(784, 10) dtype=float32_ref>,
 <tf.Variable 'Model/b:0' shape=(10,) dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/learning_rate:0' shape=() dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/beta1_power:0' shape=() dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/beta2_power:0' shape=() dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/Model/W/Adam:0' shape=(784, 10) dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/Model/W/Adam_1:0' shape=(784, 10) dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/Model/b/Adam:0' shape=(10,) dtype=float32_ref>,
 <tf.Variable 'OptimizeLoss/Model/b/Adam_1:0' shape=(10,) dtype=float32_ref>]

我是否需要为输入指定tf.placeholder?但是,Tensorflow 是如何知道输入应该提供给这个特定占位符的呢?

另外,如果我在模型的开头指定features = tf.constant(features, name="input") 之类的东西,我就不能使用它,因为它不是张量而是操作。


编辑

经过更多调查,我发现我需要使用Estimator.export_savedmodel() 方法保存我的模型(而不是在使用估计器进行训练期间重新使用自动保存的检查点。

feature_spec = {"input_image": tf.placeholder(dtype=tf.float32, shape=[None, 784])}

input_receiver_fn = tf.estimator.export.build_raw_serving_input_receiver_fn(feature_spec)
estimator.export_savedmodel(model_path, input_receiver_fn, as_text=True)

然后我尝试加载模型并进行预测,但我不知道如何用我的 numpy 图像为模型提供数据:

preds = sess.run("class", feed_dict={"input_image": input_data})

还有异常错误:

/home/hadim/local/conda/envs/ws/lib/python3.6/site-packages/tensorflow/python/client/session.py in run(self, fetches, feed_dict, options, run_metadata)
    776     try:
    777       result = self._run(None, fetches, feed_dict, options_ptr,
--> 778                          run_metadata_ptr)
    779       if run_metadata:
    780         proto_data = tf_session.TF_GetBuffer(run_metadata_ptr)

/home/hadim/local/conda/envs/ws/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run(self, handle, fetches, feed_dict, options, run_metadata)
    931           except Exception as e:
    932             raise TypeError('Cannot interpret feed_dict key as Tensor: '
--> 933                             + e.args[0])
    934 
    935           if isinstance(subfeed_val, ops.Tensor):

TypeError: Cannot interpret feed_dict key as Tensor: The name 'input_image' looks like an (invalid) Operation name, not a Tensor. Tensor names must be of the form "<op_name>:<output_index>".

【问题讨论】:

标签: tensorflow tensorflow-estimator


【解决方案1】:

关于TypeError,我是这样解决的。

首先,给占位符命名:

feature_spec = {"input_image": tf.placeholder(dtype=tf.float32, shape=[None, 784], name='input_image')}

那么你可以这样使用它:

feed_dict={"input_image:0": input_data}

希望它可以帮助某人。


编辑

在这个问题之后,estimator.export_savedmodel(...) 你可以像这样进行预测:

with tf.Session(graph=tf.Graph()) as sess:
    meta_graph_def = tf.saved_model.loader.load(sess, [tf.saved_model.tag_constants.SERVING], model_path)
    signature = meta_graph_def.signature_def
    x_tensor_name = signature['classes'].inputs['input_image'].name
    y_tensor_name = signature['classes'].outputs['labels'].name
    x = sess.graph.get_tensor_by_name(x_tensor_name)
    y = sess.graph.get_tensor_by_name(y_tensor_name)
    predictions = sess.run(y, {x: mnist.test.images[:5]})

【讨论】:

  • 它有帮助,你能解释一下如何更清楚地构造export_outputs吗?
  • @SathyamoorthyR,也许你可以先看看export_outputs在savedmodel中的作用,这里是tensorflow的api_docs中的link
【解决方案2】:

您的输入张量的名称可能是input_image:0

您可以通过调用列出已保存模型的签名:

print(estimator.signature_def[tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY])

这应该列出预期的输入/输出张量。

【讨论】:

  • input_image:0 不起作用,'Estimator' object has no attribute 'signature_def'。我正在使用 TF 1.1.0。
  • 见上文,没有estimator.signature_def这样的东西
【解决方案3】:

我使用tensorflow.contrib.predictor成功预测:

from tensorflow.contrib import predictor

predict_fn = predictor.from_saved_model(
    export_dir='model/1535012949',  # your model path
    signature_def_key='predict', 
)

predictions = predict_fn({'examples': examples})  # FYI, rename to `input_image`

但我也想通过sessiontensors 进行预测,这样我就可以将训练模型与其他语言一起使用。期待一个完美的答案!

【讨论】:

    【解决方案4】:

    我正在使用 tf.contrib.learn.Estimator。 如我所见,语法和方法签名几乎相同,因此我相信差异与几个 Tensorflow 版本有关。 所以你可以像往常一样创建 Estimator 像

    estimator = learn.Estimator(
             model_fn=your_model,
             model_dir="tmp",
             config=tf.contrib.learn.RunConfig(
                 save_checkpoints_steps=10,
                 save_summary_steps=10,
                 save_checkpoints_secs=None
             )
         )
    

    那你就用estimator.fit(input_fn=input_function, steps=100)做火车

    然后您可以进行预测调用

    estimator .predict(prediction)
    

    Mote,有一个技巧,与 Tensorflow 的 known issue 有关。调用predict没有正确初始化Estimator,所以需要调用

    estimator.evaluate(x=prediction, y=label_array, steps=1)
    

    在致电predict之前。

    希望,这会有所帮助。

    【讨论】:

    • 我的问题是关于从先前保存在磁盘上的模型进行预测。
    • 当您创建提供“model_dir”的估计器时,您的训练模型将从磁盘(此参数中提供的目录)加载。这样你就可以做出预测了。
    • 抱歉不清楚,但我的想法是在没有model_fn 源代码的情况下从磁盘加载“任何”模型。这种方式似乎是不可能的。
    猜你喜欢
    • 2016-02-16
    • 2016-11-25
    • 2018-12-27
    • 2020-02-07
    • 2020-05-20
    • 1970-01-01
    • 2018-06-12
    • 2016-03-08
    • 2018-09-28
    相关资源
    最近更新 更多