Tensorflow:恢复图形和模型,然后对单个图像进行评估 [英] Tensorflow: restoring a graph and model then running evaluation on a single image

查看:38
本文介绍了Tensorflow:恢复图形和模型,然后对单个图像进行评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为如果针对 CIFAR-10 教程中的convnet.

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

I may be wrong, but this critical step that makes the trained model usable in practice seems to be lacking. There is a "missing link" in that tutorial—a script that would directly load a single image (as array or binary), compare it against the trained model, and return a classification.

先前的答案给出了解释整体方法的部分解决方案,但我都无法成功实施.可以在这里和那里找到其他零碎的东西,但不幸的是还没有形成一个有效的解决方案.在将其标记为重复或已经回答之前,请考虑我所做的研究.

Prior answers give partial solutions that explain the overall approach, but none of which I've been able to implement successfully. Other bits and pieces can be found here and there, but unfortunately haven't added up to a working solution. Kindly consider the research I've done, before tagging this as duplicate or already answered.

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

恢复 TensorFlow 模型

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

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

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

The most popular answer is the first, in which @RyanSepassi and @YaroslavBulatov describe the problem and an approach: one needs to "manually construct a graph with identical node names, and use Saver to load the weights into it". Although both answers are helpful, it is not apparent how one would go about plugging this into the CIFAR-10 project.

非常需要功能齐全的解决方案,以便我们可以将其移植到其他单图像分类问题中.在这方面有几个关于 SO 的问题,但仍然没有完整的答案(例如 加载检查点并使用 tensorflow DNN 评估单个图像).

A fully functional solution would be highly desirable so we could port it to other single image classification problems. There are several questions on SO in this regard that ask for this, but still no full answer (for example Load checkpoint and evaluate single image with tensorflow DNN).

我希望我们能达成一个每个人都可以使用的工作脚本.

I hope we can converge on a working script that everyone could use.

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

The below script is not yet functional, and I'd be happy to hear from you on how this can be improved to provide a solution for single-image classification using the CIFAR-10 TF tutorial trained model.

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

Assume all variables, file names etc. are untouched from the original tutorial.

新文件: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()

推荐答案

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

There are two methods to feed a single new image to the cifar10 model. The first method is a cleaner approach but requires modification in the main file, hence will require retraining. The second method is applicable when a user does not want to modify the model files and instead wants to use the existing check-point/meta-graph files.

第一种方法的代码如下:

The code for the first approach is as follows:

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) 

该脚本要求用户创建两个占位符和一个条件执行语句以使其工作.

The script requires that a user creates two placeholders and a conditional execution statement for it to work.

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

The placeholders and conditional execution statement are added in cifar10_train.py as shown below:

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 模型中的输入连接到队列运行器对象,该对象是一个多级队列,可以并行地从文件中预取数据.在此处

The inputs in cifar10 model are connected to queue runner object which is a multistage queue that can prefetch data from files in parallel. See a nice animation of queue runner here

虽然队列运行器在预取用于训练的大型数据集方面很有效,但它们对于只需要对单个文件进行分类的推理/测试来说是一种矫枉过正,而且它们需要更多地修改/维护.出于这个原因,我添加了一个占位符is_training",它在训练时设置为 False,如下所示:

While queue runners are efficient in prefetching large dataset for training, they are an overkill for inference/testing where only a single file is needed to be classified, also they are a bit more involved to modify/maintain. For that reason, I have added a placeholder "is_training", which is set to False while training as shown below:

 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.

Another placeholder "imgs" holds a tensor of shape (1,32,32,3) for the image that will be fed during inference -- the first dimension is the batch size which is one in this case. I have modified cifar model to accept 32x32 images instead of 24x24 as the original cifar10 images are 32x32.

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

Finally, the conditional statement feeds the placeholder or queue runner output to the graph. The "is_training" placeholder is set to False during inference and "img" placeholder is fed a numpy array -- the numpy array is reshaped from 3 to 4 dimensional vector to conform to the input tensor to inference function in the model.

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

That is all there is to it. Any model can be inferred with a single/user defined test data like shown in the script above. Essentially read the graph, feed data to the graph nodes and run the graph to get the final output.

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

Now the second method. The other approach is to hack cifar10.py and cifar10_eval.py to change batch size to one and replace the data coming from the queue runner with the one read from a file.

将批量大小设置为 1:

Set batch size to 1:

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

使用读取的图像文件进行调用推理.

Call inference with an image file read.

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:

Then pass logits to eval_once and modify eval once to evaluate 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 的文件.

There is no separate script to run this method of inference, just run cifar10_eval.py which will now read a file from the user defined location with a batch size of one.

这篇关于Tensorflow:恢复图形和模型,然后对单个图像进行评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆