Image Recognition图像识别
我们大脑识别图像非常简单。我们的大脑让视觉看起来很容易。 对于人类来说,分开一只狮子和一只美洲虎,读一个标牌,或者认出一个人的脸,并不费事。 但使用计算机来识别图像的内容是非常不易的。
在过去的几年里,机器学习领域在解决这些难题方面取得了巨大的进步。 具体而言,我们发现一种称为深度卷积神经网络CNNs的模型能够在硬视觉识别任务上达到合理的性能 - 在某些领域匹配或超出人类的表现。
图像研究人员通过对ImageNet的努力,证明了计算机视觉方面的稳定进展。ImageNet –an academic benchmark for computer vision. 是计算机视觉的学术基准。一连串的成功模型不断提升图片识别准确率,每一次都实现了一个新的最新的结果:QuocNet,AlexNet,Inception(GoogLeNet),BN-Inception-v2。 Google内部和外部的研究人员已经发表了描述所有这些模型的论文,但是结果仍然难以重现。 我们下一步通过发布我们的最新模型Inception-v3,运行图像识别。
Inception-v3使用2012年的数据对ImageNet大型视觉识别挑战进行了训练。这是计算机视觉中的一项标准任务,模型试图将整个图像分为1000个类,如“Zebra”,“Dalmatian”和“Dishwasher”。 例如,下面是AlexNet对一些图像进行分类的结果:
为了对比模型,我们检查了模型错误率,作为前5个猜测之一 - 被称为“前5模型错误率”。 AlexNet通过设置2012年验证数据集的前5位错误率达到15.3%
初始(GoogLeNet)达到6.67%;
BN-Inception-v2达到4.9%;
Inception-v3达到3.46%。
- 人类在ImageNet挑战中的表现如何? Andrej Karpathy有一篇博客文章衡量自己的表现。 他达到了5.1%错误率。
1,Usage with Python API(使用pythonAPI实现)
本教程将教你如何使用Inception-v3。使用Python或C ++ ,您将学习如何将图像分类到1000个类中。 我们还将讨论如何从这个模型中提取更高级别的特征,这些特征可能会被其他视觉任务重用。
我们很高兴看到社区使用Python API用到这个模型。
当程序第一次运行时,classify_image.py从tensorflow.org下载训练好的模型。 您的硬盘上需要大约200M的可用空间。我们可以从github上下载源码:
python classify_image.py
上述命令将分类出一只熊猫的图像。
如果模型正确运行,将产生以下输出:
giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca (score = 0.88493)
indri, indris, Indri indri, Indri brevicaudatus (score = 0.00878)
lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens (score = 0.00317)
custard apple (score = 0.00149)
earthstar (score = 0.00127)
如果你想提供其他JPEG图像,你可以通过编辑–image_file参数来实现。
- 如果你将模型数据下载到不同的目录,你需要将–model_dir指向所使用的目录。
注解代码
# -*- coding: utf-8 -*-
""" 一个简单的图像分类器 使用ImageNet 2012 Challenge数据训练的Inception运行图像分类 组。 该程序从保存的GraphDef协议缓冲区中创建一个图形, 并在输入的JPEG图像上运行。 它输出人类可读的 排名前5的预测字符串及其概率。 将--image_file参数更改为任何jpg图像来计算a 该图像的分类。 请参阅教程和网站,了解如何进行详细说明 使用这个python脚本来执行图像识别。 https://tensorflow.org/tutorials/image_recognition/ """
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import os.path
import re
import sys
import tarfile
import numpy as np
from six.moves import urllib
import tensorflow as tf
FLAGS = None
# pylint: disable=line-too-long,数据下载地址。
DATA_URL = 'http://download.tensorflow.org/models/image/imagenet/inception-2015-12-05.tgz'
# pylint: enable=line-too-long
class NodeLookup(object):
""" 将整数节点ID转换为人类可读标签。"""
def __init__(self, label_lookup_path=None, uid_lookup_path=None):
if not label_lookup_path:
label_lookup_path = os.path.join(
FLAGS.model_dir, 'imagenet_2012_challenge_label_map_proto.pbtxt')
if not uid_lookup_path:
uid_lookup_path = os.path.join(
FLAGS.model_dir, 'imagenet_synset_to_human_label_map.txt')
self.node_lookup = self.load(label_lookup_path, uid_lookup_path)
def load(self, label_lookup_path, uid_lookup_path):
""" 为每个softmax节点加载一个人类可读的英文名称。 ARGS: label_lookup_path:字符串UID到整数节点ID。 uid_lookup_path:将UID转换为可读的字符串。 return: 从整数节点ID字符到可读的字符串。 """
if not tf.gfile.Exists(uid_lookup_path):
tf.logging.fatal('File does not exist %s', uid_lookup_path)
if not tf.gfile.Exists(label_lookup_path):
tf.logging.fatal('File does not exist %s', label_lookup_path)
# 将字符串UID映射到可读的字符串
proto_as_ascii_lines = tf.gfile.GFile(uid_lookup_path).readlines()
uid_to_human = {}
p = re.compile(r'[n\d]*[ \S,]*')
for line in proto_as_ascii_lines:
parsed_items = p.findall(line)
uid = parsed_items[0]
human_string = parsed_items[2]
uid_to_human[uid] = human_string
# 加载从字符串UID到整数节点ID的映射。
node_id_to_uid = {}
proto_as_ascii = tf.gfile.GFile(label_lookup_path).readlines()
for line in proto_as_ascii:
if line.startswith(' target_class:'):
target_class = int(line.split(': ')[1])
if line.startswith(' target_class_string:'):
target_class_string = line.split(': ')[1]
node_id_to_uid[target_class] = target_class_string[1:-2]
# 将整数节点ID的最终映射加载到可读的字符串
node_id_to_name = {}
for key, val in node_id_to_uid.items():
if val not in uid_to_human:
tf.logging.fatal('Failed to locate: %s', val)
name = uid_to_human[val]
node_id_to_name[key] = name
return node_id_to_name
def id_to_string(self, node_id):
if node_id not in self.node_lookup:
return ''
return self.node_lookup[node_id]
def create_graph():
"""从保存的GraphDef文件创建一个图形并返回一个Saver。"""
# 从 saved graph_def.pb 创建一个 graph
with tf.gfile.FastGFile(os.path.join(
FLAGS.model_dir, 'classify_image_graph_def.pb'), 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
_ = tf.import_graph_def(graph_def, name='')
def run_inference_on_image(image):
"""Runs inference on an image. Args: image: 图像名称. Returns:无 """
if not tf.gfile.Exists(image):
tf.logging.fatal('File does not exist %s', image)
image_data = tf.gfile.FastGFile(image, 'rb').read()
# 从 saved GraphDef 创建一个 graph
create_graph()
with tf.Session() as sess:
# 一些有用的张量:
#'softmax:0':包含归一化预测的张量
# 1000个标签。
#'pool_3:0':包含2048的倒数第二层的张量
# 浮动图像的描述。
#'DecodeJpeg / contents:0':包含提供JPEG的字符串的张量。
# 编码图像。
# 通过将image_data作为输入提供给图表来运行softmax张量。
softmax_tensor = sess.graph.get_tensor_by_name('softmax:0')
predictions = sess.run(softmax_tensor,
{'DecodeJpeg/contents:0': image_data})
predictions = np.squeeze(predictions)
# 创建一个ID --> 英文字符串lookup.
node_lookup = NodeLookup()
top_k = predictions.argsort()[-FLAGS.num_top_predictions:][::-1]
for node_id in top_k:
human_string = node_lookup.id_to_string(node_id)
score = predictions[node_id]
print('%s (score = %.5f)' % (human_string, score))
def maybe_download_and_extract():
"""下载训练的tar包文件。"""
dest_directory = FLAGS.model_dir
if not os.path.exists(dest_directory):
os.makedirs(dest_directory)
filename = DATA_URL.split('/')[-1]
filepath = os.path.join(dest_directory, filename)
if not os.path.exists(filepath):
def _progress(count, block_size, total_size):
sys.stdout.write('\r>> Downloading %s %.1f%%' % (
filename, float(count * block_size) / float(total_size) * 100.0))
sys.stdout.flush()
filepath, _ = urllib.request.urlretrieve(DATA_URL, filepath, _progress)
print()
statinfo = os.stat(filepath)
print('Successfully downloaded', filename, statinfo.st_size, 'bytes.')
tarfile.open(filepath, 'r:gz').extractall(dest_directory)
def main(_):
maybe_download_and_extract()
image = (FLAGS.image_file if FLAGS.image_file else
os.path.join(FLAGS.model_dir, 'cropped_panda.jpg'))
run_inference_on_image(image)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
# classify_image_graph_def.pb:
# GraphDef协议缓冲区的二进制表示。
# imagenet_synset_to_human_label_map.txt:
# 从synset ID映射到可读的字符串。
# imagenet_2012_challenge_label_map_proto.pbtxt:
# 将标签映射到synset ID的协议缓冲区的文本表示。
parser.add_argument(
'--model_dir',
type=str,
default='/tmp/imagenet',
help="""\ Path to classify_image_graph_def.pb, imagenet_synset_to_human_label_map.txt, and imagenet_2012_challenge_label_map_proto.pbtxt.\ """
)
parser.add_argument(
'--image_file',
type=str,
default='',
help='Absolute path to image file.'
)
parser.add_argument(
'--num_top_predictions',
type=int,
default=5,
help='Display this many predictions.'
)
FLAGS, unparsed = parser.parse_known_args()
tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)
更多的学习资源。
1, Michael Nielsen’s free online book is an excellent resource.
2, Chris Olah has some nice blog posts
3, Michael Nielsen’s book has a great chapter covering them.