Tensorflow:恢复一个图和模型,然后在单个imag上运行求值

2024-05-12 12:23:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我认为,如果有一个很好的解决方案来完成一个关键的任务,即根据convnet in the CIFAR-10 tutorial创建的模型测试一个新图像,这将对Tensorflow社区非常有帮助。

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

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

Tensorflow: how to save/restore a model?

Restoring TensorFlow model

Unable to restore models in tensorflow v0.8

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

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

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

我希望我们能集中在一个每个人都能使用的工作脚本上。

下面的脚本还不起作用,我很高兴从您那里听到如何改进,以提供一个使用CIFAR-10tf教程训练模型的单一图像分类解决方案。

假设所有的变量、文件名等都是原始教程中未涉及的。

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

Tags: to答案模型图像imageappgetmodel
1条回答
网友
1楼 · 发布于 2024-05-12 12:23:53

有两种方法可以将单个新图像馈送到cifar10模型。第一种方法是一种更干净的方法,但需要修改主文件,因此需要重新培训。当用户不想修改模型文件,而是想使用现有的check point/meta graph文件时,可以使用第二种方法。

第一种方法的代码如下:

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 runner对象,queue runner对象是一个多级队列,可以并行预取文件中的数据。看到队列运行器的漂亮动画here

虽然队列运行器在预取大型数据集以进行训练方面是有效的,但对于只需要对单个文件进行分类的推理/测试来说,它们是一种过激的做法,而且它们更需要修改/维护。 为此,我添加了一个占位符“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,并将来自队列运行器的数据替换为从文件中读取的数据。

将批大小设置为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_一次,并修改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的文件。

网友
2楼 · 发布于 2024-05-12 12:23:53

下面是我如何一次运行一个图像。我承认,重新使用范围似乎有点老套。

这是一个helper函数

def restore_vars(saver, sess, chkpt_dir):
    """ Restore saved net, global score and step, and epsilons OR
    create checkpoint directory for later storage. """
    sess.run(tf.initialize_all_variables())

    checkpoint_dir = chkpt_dir

    if not os.path.exists(checkpoint_dir):
        try:
            os.makedirs(checkpoint_dir)
        except OSError:
            pass

    path = tf.train.get_checkpoint_state(checkpoint_dir)
    #print("path1 = ",path)
    #path = tf.train.latest_checkpoint(checkpoint_dir)
    print(checkpoint_dir,"path = ",path)
    if path is None:
        return False
    else:
        saver.restore(sess, path.model_checkpoint_path)
        return True

下面是在for循环中一次运行单个映像的代码的主要部分。

to_restore = True
with tf.Session() as sess:

    for i in test_img_idx_set:

            # Gets the image
            images = get_image(i)
            images = np.asarray(images,dtype=np.float32)
            images = tf.convert_to_tensor(images/255.0)
            # resize image to whatever you're model takes in
            images = tf.image.resize_images(images,256,256)
            images = tf.reshape(images,(1,256,256,3))
            images = tf.cast(images, tf.float32)

            saver = tf.train.Saver(max_to_keep=5, keep_checkpoint_every_n_hours=1)

            #print("infer")
            with tf.variable_scope(tf.get_variable_scope()) as scope:
                if to_restore:
                    logits = inference(images)
                else:
                    scope.reuse_variables()
                    logits = inference(images)


            if to_restore:
                restored = restore_vars(saver, sess,FLAGS.train_dir)
                print("restored ",restored)
                to_restore = False

            logit_val = sess.run(logits)
            print(logit_val)

这里有一个替代的实现上面使用占位符-在我看来它有点干净。但出于历史原因,我将留下上面的例子。

imgs_place = tf.placeholder(tf.float32, shape=[my_img_shape_put_here])
images = tf.reshape(imgs_place,(1,256,256,3))

saver = tf.train.Saver(max_to_keep=5, keep_checkpoint_every_n_hours=1)

#print("infer")
logits = inference(images)

restored = restore_vars(saver, sess,FLAGS.train_dir)
print("restored ",restored)

with tf.Session() as sess:
    for i in test_img_idx_set:
        logit_val = sess.run(logits,feed_dict={imgs_place=i})
        print(logit_val)
网友
3楼 · 发布于 2024-05-12 12:23:53

有了这个

softmax = gn.inference(image)
saver = tf.train.Saver()
ckpt = tf.train.get_checkpoint_state(FLAGS.checkpoint_dir)
with tf.Session() as sess:
  saver.restore(sess, ckpt.model_checkpoint_path)
  softmaxval = sess.run(softmax)
  print(softmaxval)

输出

[[  6.73550041e-03   4.44930716e-04   9.92570221e-01   1.00681427e-06
    3.05406687e-08   2.38927707e-04   1.89839399e-12   9.36238484e-06
    1.51646684e-09   3.38977535e-09]]

相关问题 更多 >