Tensorflow:恢复图形和模型然后在单个图像上运行评估

新手上路,请多包涵

我认为,如果针对 CIFAR-10 教程中由 convnet 创建的模型测试单个新图像这一关键任务,有一个有据可查的解决方案,那将对 Tensorflow 社区非常有帮助。

我可能是错的,但似乎缺乏使训练模型在实践中可用的关键步骤。该教程中有一个“缺失的链接”——一个直接加载单个图像(作为数组或二进制)、将其与训练模型进行比较并返回分类的脚本。

先前的答案给出了解释整体方法的部分解决方案,但我没有一个能够成功实施。可以在这里和那里找到其他点点滴滴,但不幸的是还没有加起来成为一个有效的解决方案。在将其标记为重复或已回答之前,请考虑我所做的研究。

Tensorflow:如何保存/恢复模型?

恢复 TensorFlow 模型

无法在 tensorflow v0.8 中恢复模型

https://gist.github.com/nikitakit/6ef3b72be67b86cb7868

最流行的答案是第一种,@RyanSepassi 和@YaroslavBulatov 描述了问题和一种方法:需要“手动构建具有相同节点名称的图,并使用 Saver 将权重加载到其中”。尽管这两个答案都有帮助,但尚不清楚如何将其插入 CIFAR-10 项目。

非常需要一个功能齐全的解决方案,这样我们就可以将其移植到其他单一图像分类问题中。在这方面有几个关于 SO 的问题要求这个,但仍然没有完整的答案(例如 Load checkpoint and evaluate single image with tensorflow DNN )。

我希望我们可以汇集一个每个人都可以使用的工作脚本。

以下脚本尚未运行,我很高兴收到您的来信,了解如何改进它以提供使用 CIFAR-10 TF 教程训练模型进行单图像分类的解决方案。

假设原始教程中的所有变量、文件名等都没有改变。

新文件: cifar10_eval_single.py

 import cv2
import tensorflow as tf

FLAGS = tf.app.flags.FLAGS

tf.app.flags.DEFINE_string('eval_dir', './input/eval',
                           """Directory where to write event logs.""")
tf.app.flags.DEFINE_string('checkpoint_dir', './input/train',
                           """Directory where to read model checkpoints.""")

def get_single_img():
    file_path = './input/data/single/test_image.tif'
    pixels = cv2.imread(file_path, 0)
    return pixels

def eval_single_img():

    # below code adapted from @RyanSepassi, however not functional
    # among other errors, saver throws an error that there are no
    # variables to save
    with tf.Graph().as_default():

        # Get image.
        image = get_single_img()

        # Build a Graph.
        # TODO

        # Create dummy variables.
        x = tf.placeholder(tf.float32)
        w = tf.Variable(tf.zeros([1, 1], dtype=tf.float32))
        b = tf.Variable(tf.ones([1, 1], dtype=tf.float32))
        y_hat = tf.add(b, tf.matmul(x, w))

        saver = tf.train.Saver()

        with tf.Session() as sess:
            sess.run(tf.initialize_all_variables())
            ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)

            if ckpt and ckpt.model_checkpoint_path:
                saver.restore(sess, ckpt.model_checkpoint_path)
                print('Checkpoint found')
            else:
                print('No checkpoint found')

            # Run the model to get predictions
            predictions = sess.run(y_hat, feed_dict={x: image})
            print(predictions)

def main(argv=None):
    if tf.gfile.Exists(FLAGS.eval_dir):
        tf.gfile.DeleteRecursively(FLAGS.eval_dir)
    tf.gfile.MakeDirs(FLAGS.eval_dir)
    eval_single_img()

if __name__ == '__main__':
    tf.app.run()

原文由 pepe 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 697
1 个回答

有两种方法可以将单个新图像提供给 cifar10 模型。第一种方法是一种更简洁的方法,但需要在主文件中进行修改,因此需要重新训练。当用户不想修改模型文件而是想使用现有的检查点/元图文件时,第二种方法适用。

第一种方法的代码如下:

 import tensorflow as tf
import numpy as np
import cv2

sess = tf.Session('', tf.Graph())
with sess.graph.as_default():
    # Read meta graph and checkpoint to restore tf session
    saver = tf.train.import_meta_graph("/tmp/cifar10_train/model.ckpt-200.meta")
    saver.restore(sess, "/tmp/cifar10_train/model.ckpt-200")

    # Read a single image from a file.
    img = cv2.imread('tmp.png')
    img = np.expand_dims(img, axis=0)

    # Start the queue runners. If they are not started the program will hang
    # see e.g. https://www.tensorflow.org/programmers_guide/reading_data
    coord = tf.train.Coordinator()
    threads = []
    for qr in sess.graph.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
        threads.extend(qr.create_threads(sess, coord=coord, daemon=True,
                                         start=True))

    # In the graph created above, feed "is_training" and "imgs" placeholders.
    # Feeding them will disconnect the path from queue runners to the graph
    # and enable a path from the placeholder instead. The "img" placeholder will be
    # fed with the image that was read above.
    logits = sess.run('softmax_linear/softmax_linear:0',
                     feed_dict={'is_training:0': False, 'imgs:0': img})

    #Print classifiction results.
    print(logits)

该脚本要求用户创建两个占位符和一个条件执行语句才能运行。

在cifar10_train.py中添加占位符和条件执行语句如下图:

 def train():
"""Train CIFAR-10 for a number of steps."""
    with tf.Graph().as_default():
        global_step = tf.contrib.framework.get_or_create_global_step()

    with tf.device('/cpu:0'):
        images, labels = cifar10.distorted_inputs()

    is_training = tf.placeholder(dtype=bool,shape=(),name='is_training')
    imgs = tf.placeholder(tf.float32, (1, 32, 32, 3), name='imgs')
    images = tf.cond(is_training, lambda:images, lambda:imgs)
    logits = cifar10.inference(images)

cifar10 模型中的输入连接到队列运行器对象,该对象是一个多级队列,可以并行地从文件中预取数据。 在此处 查看队列赛跑者的精彩动画

虽然 queue runners 在预取大型数据集进行训练时很有效,但对于只需要对单个文件进行分类的推理/测试来说,它们就有点矫枉过正了,而且它们还需要更多地参与修改/维护。出于这个原因,我添加了一个占位符“is_training”,在训练时将其设置为 False,如下所示:

  import numpy as np
 tmp_img = np.ndarray(shape=(1,32,32,3), dtype=float)
 with tf.train.MonitoredTrainingSession(
     checkpoint_dir=FLAGS.train_dir,
     hooks=[tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
            tf.train.NanTensorHook(loss),
            _LoggerHook()],
     config=tf.ConfigProto(
         log_device_placement=FLAGS.log_device_placement)) as mon_sess:
   while not mon_sess.should_stop():
     mon_sess.run(train_op, feed_dict={is_training: True, imgs: tmp_img})

另一个占位符“imgs”为将在推理期间提供的图像保存形状为 (1,32,32,3) 的张量——第一个维度是批量大小,在本例中为一个。我修改了 cifar 模型以接受 32x32 图像而不是 24x24,因为原始 cifar10 图像是 32x32。

最后,条件语句将占位符或队列运行器输出提供给图形。 “is_training”占位符在推理过程中设置为 False,“img”占位符被输入一个 numpy 数组——numpy 数组从 3 维向量重塑为 4 维向量,以符合模型中推理函数的输入张量。

这就是它的全部。可以使用单个/用户定义的测试数据推断出任何模型,如上面的脚本所示。本质上是读取图形,将数据馈送到图形节点并运行图形以获得最终输出。

现在第二种方法。另一种方法是破解 cifar10.py 和 cifar10_eval.py 以将批量大小更改为一个,并将来自队列运行器的数据替换为从文件中读取的数据。

将批量大小设置为 1:

 tf.app.flags.DEFINE_integer('batch_size', 1,
                             """Number of images to process in a batch.""")

使用读取的图像文件调用推理。

 def evaluate():   with tf.Graph().as_default() as g:
    # Get images and labels for CIFAR-10.
    eval_data = FLAGS.eval_data == 'test'
    images, labels = cifar10.inputs(eval_data=eval_data)
    import cv2
    img = cv2.imread('tmp.png')
    img = np.expand_dims(img, axis=0)
    img = tf.cast(img, tf.float32)

    logits = cifar10.inference(img)

然后将 logits 传递给 eval_once 并修改 eval once 以评估 logits:

 def eval_once(saver, summary_writer, top_k_op, logits, summary_op):
    ...
    while step < num_iter and not coord.should_stop():
        predictions = sess.run([top_k_op])
        print(sess.run(logits))

没有单独的脚本来运行这种推理方法,只需运行 cifar10_eval.py,它现在将从用户定义的位置读取一个批量大小为 1 的文件。

原文由 bigdata2 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题