<p>有两种方法可以将单个新图像馈送到<a href="https://github.com/tensorflow/models/blob/master/tutorials/image/cifar10/cifar10.py" rel="noreferrer">cifar10</a>模型。第一种方法是一种更干净的方法,但需要修改主文件,因此需要重新培训。当用户不想修改模型文件,而是想使用现有的check point/meta graph文件时,可以使用第二种方法。</p>
<p>第一种方法的代码如下:</p>
<pre><code>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)
</code></pre>
<p>该脚本要求用户创建两个占位符和一个条件执行语句以使其工作。</p>
<p>占位符和条件执行语句添加到cifar10_train.py中,如下所示:</p>
<pre><code>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)
</code></pre>
<p>cifar10模型中的输入连接到queue runner对象,queue runner对象是一个多级队列,可以并行预取文件中的数据。看到队列运行器的漂亮动画<a href="https://www.tensorflow.org/programmers_guide/reading_data" rel="noreferrer">here</a></p>
<p>虽然队列运行器在预取大型数据集以进行训练方面是有效的,但对于只需要对单个文件进行分类的推理/测试来说,它们是一种过激的做法,而且它们更需要修改/维护。
为此,我添加了一个占位符“is_training”,在训练时设置为False,如下所示:</p>
<pre><code> 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})
</code></pre>
<p>另一个占位符“imgs”为图像保存一个形状张量(1,32,32,3),该张量将在推断过程中提供——第一个维度是批大小,在本例中是一个。我修改了cifar模型以接受32x32图像,而不是24x24,因为原始cifar10图像是32x32。</p>
<p>最后,条件语句将占位符或队列运行器输出提供给图形。“is_training”占位符在推理过程中设置为False,“img”占位符被馈送一个numpy数组——numpy数组被从3维向量重塑为4维向量,以符合模型中推理函数的输入张量。</p>
<p>这就是它的全部。任何模型都可以用一个/用户定义的测试数据进行推断,如上面的脚本所示。基本上是读取图形,将数据馈送到图形节点并运行图形以获得最终输出。</p>
<p>现在是第二种方法。另一种方法是修改cifar10.py和cifar10_eval.py,将批大小更改为1,并将来自队列运行器的数据替换为从文件中读取的数据。</p>
<p>将批大小设置为1:</p>
<pre><code>tf.app.flags.DEFINE_integer('batch_size', 1,
"""Number of images to process in a batch.""")
</code></pre>
<p>读取图像文件后调用推断。</p>
<pre><code>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)
</code></pre>
<p>然后将logits传递给eval_一次,并修改eval once以计算logits:</p>
<pre><code>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))
</code></pre>
<p>没有单独的脚本来运行这种推理方法,只需运行cifar10_eval.py,它现在将从用户定义的位置读取批大小为1的文件。</p>