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

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

问题描述

我认为,如果针对针对由

I think it would be immensely helpful to the Tensorflow community if there was a well-documented solution to the crucial task of testing a single new image against the model created by the convnet in the CIFAR-10 tutorial.

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

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的问题要求解决,但仍然没有完整的答案(例如

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()

推荐答案

有两种方法可以将单个新图像提供给

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进行黑客攻击,以将批处理大小更改为一个,并将来自队列运行器的数据替换为从文件中读取的数据.

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:

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)

然后将登录信息传递给eval_once并修改一次eval以评估登录信息:

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天全站免登陆