[tensorflow]图片新类别再训练-花分类-代码整理

目录

一、新类别模型的再训练

1、图片加载,并将数据集划分为训练集、测试集、验证集,比例分别为80%,10%,10%(默认)

2、加载hub某个模型,拉取模型信息,创建图

3、计算所有图片的bottlenecks(特征向量),并缓存

4、新类别模型训练

5、新类别预测模型保存

二、模型预测

1、预测模型加载

2、加载预测图片(图片进行解码和剪裁),预测图片类别


原网址:https://www.tensorflow.org/hub/tutorials/image_retraining

一、新类别模型的再训练

预定义-第三方包

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import collections
from datetime import datetime
import hashlib
import os.path
import random
import re
import sys

import numpy as np
import tensorflow as tf
import tensorflow_hub as hub

tf.logging.set_verbosity(tf.logging.INFO)

预定义--文件路径 

FLAGS.image_dir = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower_photos'
'''
Path to folders of labeled images.
'''

FLAGS.output_graph = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\graph\\output_graph.pb'
'''
Where to save the trained graph.
'''

FLAGS.intermediate_output_graphs_dir = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\intermediate_graph\\'
'''
Where to save the intermediate graphs.
'''

FLAGS.intermediate_store_frequency = 0
"""\
     How many steps to store intermediate graph. If "0" then will not
     store.\
  """
FLAGS.output_labels = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\labels\\output_labels.txt'
'''
Where to save the trained graph\'s labels.
'''

FLAGS.summaries_dir = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\retrain_logs'
'''
Where to save summary logs for TensorBoard.
'''
FLAGS.how_many_training_steps = 4000
'''How many training steps to run before ending.'''

FLAGS.learning_rate = t=0.01
'''How large a learning rate to use when training.'''

FLAGS.testing_percentage = 10
'''What percentage of images to use as a test set.'''

FLAGS.validation_percentage = 10
'''What percentage of images to use as a validation set.'''

FLAGS.eval_step_interval = 10
'''How often to evaluate the training results.'''

FLAGS.train_batch_size = 100
'''How many images to train on at a time.'''

FLAGS.test_batch_size = -1
"""\
  How many images to test on. This test set is only used once, to evaluate
  the final accuracy of the model after training completes.
  A value of -1 causes the entire test set to be used, which leads to more
  stable results across runs.\
  """

FLAGS.validation_batch_size = 100
"""\
  How many images to use in an evaluation batch. This validation set is
  used much more often than the test set, and is an early indicator of how
  accurate the model is during training.
  A value of -1 causes the entire validation set to be used, which leads to
  more stable results across training iterations, but may be slower on large
  training sets.\
  """

FLAGS.print_misclassified_test_images = False
"""\
  Whether to print out a list of all misclassified test images.\
  """

FLAGS.bottleneck_dir = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\bottleneck'
'Path to cache bottleneck layer values as files.'

FLAGS.final_tensor_name = 'final_result'
"""\
  The name of the output classification layer in the retrained graph.\
  """

FLAGS.flip_left_right = False
"""\
  Whether to randomly flip half of the training images horizontally.\
  """

FLAGS.random_crop = 0
"""\
  A percentage determining how much of a margin to randomly crop off the
  training images.\
  """

FLAGS.random_scale = 0
"""\
  A percentage determining how much to randomly scale up the size of the
  training images by.\
  """

FLAGS.random_brightness = 0
"""\
  A percentage determining how much to randomly multiply the training image
  input pixels up or down by.\
  """

FLAGS.tfhub_module = 'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1'
""" Which TensorFlow Hub module to use. For more options, search https://tfhub.dev for image feature vector modules. """

FLAGS.saved_model_dir = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\exportedGraph'
""" Where to save the exported graph."""

预定义--全局变量

# The location where variable checkpoints will be stored.
CHECKPOINT_NAME = 'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\retrain_checkpoint\\'

# A module is understood as instrumented for quantization with TF-Lite
# if it contains any of these ops.
FAKE_QUANT_OPS = ('FakeQuantWithMinMaxVars','FakeQuantWithMinMaxVarsPerChannel')

1、图片加载,并将数据集划分为训练集、测试集、验证集,比例分别为80%,10%,10%(默认)

def create_image_lists(image_dir, testing_percentage, validation_percentage):

    """Builds a list of training images from the file system.

    Analyzes the sub folders in the image directory, splits them into stable
    training, testing, and validation sets, and returns a data structure
    describing the lists of images for each label and their paths.

    Args:
    image_dir: String path to a folder containing subfolders of images.
    testing_percentage: Integer percentage of the images to reserve for tests.
    validation_percentage: Integer percentage of images reserved for validation.

    Returns:
    An OrderedDict containing an entry for each label subfolder, with images
    split into training, testing, and validation sets within each label.
    The order of items defines the class indices.
    """

    if not tf.gfile.Exists(image_dir):
        tf.logging.error("Image directory '" + image_dir + "' not found.")
        return None

    result = collections.OrderedDict()
    sub_dirs = sorted(x[0] for x in tf.gfile.Walk(image_dir))
    # The root directory comes first, so skip it.
    is_root_dir = True
    for sub_dir in sub_dirs:
        if is_root_dir:
          is_root_dir = False
          continue
            
        extensions = sorted(set(os.path.normcase(ext)  for ext in ['JPEG', 'JPG', 'jpeg', 'jpg', 'png']))
        file_list = []
        dir_name = os.path.basename(sub_dir)
        if dir_name == image_dir:
            continue
        #tf.logging.info("Looking for images in '" + dir_name + "'")
        for extension in extensions:
            file_glob = os.path.join(image_dir, dir_name, '*.' + extension)
            file_list.extend(tf.gfile.Glob(file_glob))
        if not file_list:
            tf.logging.warning('No files found')
            continue
        if len(file_list) < 20:
            tf.logging.warning( 'WARNING: Folder has less than 20 images, which may cause issues.')
        elif len(file_list) > MAX_NUM_IMAGES_PER_CLASS:
            tf.logging.warning('WARNING: Folder {} has more than {} images. Some images will never be selected.'.format(dir_name, MAX_NUM_IMAGES_PER_CLASS))
        label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower())
        
        training_images = []
        testing_images = []
        validation_images = []
        for file_name in file_list:
            base_name = os.path.basename(file_name)
            hash_name = re.sub(r'_nohash_.*$', '', file_name)
            hash_name_hashed = hashlib.sha1(tf.compat.as_bytes(hash_name)).hexdigest()
            percentage_hash = ((int(hash_name_hashed, 16) %(MAX_NUM_IMAGES_PER_CLASS + 1)) *(100.0 / MAX_NUM_IMAGES_PER_CLASS))
            if percentage_hash < validation_percentage:
                validation_images.append(base_name)
            elif percentage_hash < (testing_percentage + validation_percentage):
                testing_images.append(base_name)
            else:
                training_images.append(base_name)
                
        result[label_name] = {
            'dir': dir_name,
            'training': training_images,
            'testing': testing_images,
            'validation': validation_images,
        }
    return result
def main(_):
    #获取商品图片
    image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage, FLAGS.validation_percentage)
    class_count = len(image_lists.keys())

image_lists数据格式为:

([('daisy',
       {'dir': 'daisy',
        'testing':['100080576_f52e8ee070_n.jpg','10172379554_b296050f82_n.jpg',...],
        'training':['10140303196_b88d3d6cec.jpg',...],
        'validation':['102841525_bd6628ae3c.jpg',]}),
  ('dandelion',
        {'dir': 'dandelion',
         'testing': ['10294487385_92a0676c7d_m.jpg',...],
         'training':['10140303196_b88d3d6cec.jpg',...],
         'validation':['102841525_bd6628ae3c.jpg',]}),

2、加载hub某个模型,拉取模型信息,创建图

#加载tensorflow中的某个模型,并拉取模型信息
def create_module_graph(module_spec):
    """Creates a graph and loads Hub Module into it.

    Args:
    module_spec: the hub.ModuleSpec for the image module being used.

    Returns:
    graph: the tf.Graph that was created.
    bottleneck_tensor: the bottleneck values output by the module.
    resized_input_tensor: the input images, resized as expected by the module.
    wants_quantization: a boolean, whether the module has been instrumented
      with fake quantization ops.
    """
    height, width = hub.get_expected_image_size(module_spec)
    with tf.Graph().as_default() as graph:
        resized_input_tensor = tf.placeholder(tf.float32, [None, height, width, 3])
        m = hub.Module(module_spec)
        bottleneck_tensor = m(resized_input_tensor)
        wants_quantization = any(node.op in FAKE_QUANT_OPS for node in graph.as_graph_def().node)
        
    return graph, bottleneck_tensor, resized_input_tensor, wants_quantization



#对图片进行解码和调整大小
def add_jpeg_decoding(module_spec):
    """Adds operations that perform JPEG decoding and resizing to the graph..

    Args:
    module_spec: The hub.ModuleSpec for the image module being used.

    Returns:
    Tensors for the node to feed JPEG data into, and the output of the
      preprocessing steps.
    """
    input_height, input_width = hub.get_expected_image_size(module_spec)
    input_depth = hub.get_num_image_channels(module_spec)
    jpeg_data = tf.placeholder(tf.string, name='DecodeJPGInput')
    
    decoded_image = tf.image.decode_jpeg(jpeg_data, channels=input_depth)
    # Convert from full range of uint8 to range [0,1] of float32.
    decoded_image_as_float = tf.image.convert_image_dtype(decoded_image,tf.float32)
    decoded_image_4d = tf.expand_dims(decoded_image_as_float, 0)
    
    resize_shape = tf.stack([input_height, input_width])
    resize_shape_as_int = tf.cast(resize_shape, dtype=tf.int32)
    resized_image = tf.image.resize_bilinear(decoded_image_4d,resize_shape_as_int)
    
    return jpeg_data, resized_image
def mian(_):
    #加载hub某个模型,并拉取模型信息,创建图
    module_spec = hub.load_module_spec(FLAGS.tfhub_module)
    graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (create_module_graph(module_spec))

    with tf.Session(graph=graph) as sess:
        # Initialize all weights: for the module to their pretrained values, and for the newly added retraining layer to random initial values.
        init = tf.global_variables_initializer()
        sess.run(init)

        # Set up the image decoding sub-graph.
        jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)

拉取的模型信息为:

graph, bottleneck_tensor, resized_image_tensor, wants_quantization:
(<tensorflow.python.framework.ops.Graph at 0x190481d0>,
 <tf.Tensor 'module_apply_default/hub_output/feature_vector/SpatialSqueeze:0' shape=(?, 2048) dtype=float32>,
 <tf.Tensor 'Placeholder:0' shape=(?, 299, 299, 3) dtype=float32>,
 False)

jpeg_data_tensor, decoded_image_tensor:
(<tf.Tensor 'DecodeJPGInput:0' shape=<unknown> dtype=string>,
 <tf.Tensor 'ResizeBilinear:0' shape=(1, 299, 299, 3) dtype=float32>)

3、计算所有图片的bottlenecks(特征向量),并缓存

获取路径:

def ensure_dir_exists(dir_name):
    #创建文件
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)
        
def get_image_path(image_lists, label_name, index, image_dir, category):
    #获取一张图片的路径
    if label_name not in image_lists:
        tf.logging.fatal('Label does not exist %s.', label_name)
    label_lists = image_lists[label_name]
    if category not in label_lists:
        tf.logging.fatal('Category does not exist %s.', category)
    category_list = label_lists[category]
    if not category_list:
        tf.logging.fatal('Label %s has no images in the category %s.',label_name, category)
    mod_index = index % len(category_list)
    base_name = category_list[mod_index]
    sub_dir = label_lists['dir']
    full_path = os.path.join(image_dir, sub_dir, base_name)
    return full_path        

def get_bottleneck_path(image_lists, label_name, index, bottleneck_dir, category, module_name):
    #获取一张图片bottlenecks保存路径
    module_name = (module_name.replace('://', '~')  # URL scheme.
                 .replace('/', '~')  # URL and Unix paths.
                 .replace(':', '~').replace('\\', '~'))  # Windows paths.
    return get_image_path(image_lists, label_name, index, bottleneck_dir, category) + '_' + module_name + '.txt'

计算一张图片的bottlenecks,并保存到文件:

#计算一张图片的bottlenecks,2048维向量
def run_bottleneck_on_image(sess, image_data, image_data_tensor,decoded_image_tensor, resized_input_tensor,bottleneck_tensor):
    # First decode the JPEG image, resize it, and rescale the pixel values.
    resized_input_values = sess.run(decoded_image_tensor, {image_data_tensor: image_data})
    # Then run it through the recognition network.
    bottleneck_values = sess.run(bottleneck_tensor, {resized_input_tensor: resized_input_values})
    bottleneck_values = np.squeeze(bottleneck_values)
    return bottleneck_values

#获取一张图片的bottlenecks,并写入文件
def create_bottleneck_file(bottleneck_path, image_lists, label_name, index, image_dir, category, 
                           sess, jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor):
    """Create a single bottleneck file."""
    tf.logging.info('Creating bottleneck at ' + bottleneck_path)
    image_path = get_image_path(image_lists, label_name, index, image_dir, category)
    if not tf.gfile.Exists(image_path):
        tf.logging.fatal('File does not exist %s', image_path)
    image_data = tf.gfile.FastGFile(image_path, 'rb').read()
    
    try:
        bottleneck_values = run_bottleneck_on_image(sess, image_data, jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor)
    except Exception as e:
        raise RuntimeError('Error during processing file %s (%s)' % (image_path,
                                                                 str(e)))
    bottleneck_string = ','.join(str(x) for x in bottleneck_values)
    with open(bottleneck_path, 'w') as bottleneck_file:
        bottleneck_file.write(bottleneck_string)

缓存所有图片的bottlenecks(特征向量):

#读取一张图片的bottlenecks
def get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir,category, bottleneck_dir, 
                             jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor, module_name):
    """Retrieves or calculates bottleneck values for an image.

    If a cached version of the bottleneck data exists on-disk, return that, otherwise calculate the data and save it to disk for future use.

    Args:
    sess: The current active TensorFlow Session.
    image_lists: OrderedDict of training images for each label.
    label_name: Label string we want to get an image for.
    index: Integer offset of the image we want. This will be modulo-ed by the available number of images for the label, so it can be arbitrarily large.
    image_dir: Root folder string of the subfolders containing the training images.
    category: Name string of which set to pull images from - training, testing, or validation.
    bottleneck_dir: Folder string holding cached files of bottleneck values.
    jpeg_data_tensor: The tensor to feed loaded jpeg data into.
    decoded_image_tensor: The output of decoding and resizing the image.
    resized_input_tensor: The input node of the recognition graph.
    bottleneck_tensor: The output tensor for the bottleneck values.
    module_name: The name of the image module being used.

    Returns:
    Numpy array of values produced by the bottleneck layer for the image.
    """
    label_lists = image_lists[label_name]
    sub_dir = label_lists['dir']
    sub_dir_path = os.path.join(bottleneck_dir, sub_dir)
    ensure_dir_exists(sub_dir_path)
    bottleneck_path = get_bottleneck_path(image_lists, label_name, index, bottleneck_dir, category, module_name) #获取图片bottleneck 路径
    
    if not os.path.exists(bottleneck_path):
        create_bottleneck_file(bottleneck_path, image_lists, label_name, index, image_dir, category, 
                               sess, jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor) #图片bottleneck写入文件
        
    with open(bottleneck_path, 'r') as bottleneck_file: #读取图片bottleneck
        bottleneck_string = bottleneck_file.read()
    did_hit_error = False
    try:
        bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
    except ValueError:
        tf.logging.warning('Invalid float found, recreating bottleneck')
        did_hit_error = True
        
    if did_hit_error: #文件存在,但读取失败,重新计算,在读取
        create_bottleneck_file(bottleneck_path, image_lists, label_name, index, image_dir, category, 
                               sess, jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor)
        with open(bottleneck_path, 'r') as bottleneck_file:
            bottleneck_string = bottleneck_file.read()
        bottleneck_values = [float(x) for x in bottleneck_string.split(',')]
    return bottleneck_values



#缓存所有图片的bottlenecks(特征向量)
def cache_bottlenecks(sess, image_lists, image_dir, bottleneck_dir,
                      jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor, module_name):
    """Ensures all the training, testing, and validation bottlenecks are cached.

    Because we're likely to read the same image multiple times (if there are no
    distortions applied during training) it can speed things up a lot if we
    calculate the bottleneck layer values once for each image during
    preprocessing, and then just read those cached values repeatedly during
    training. Here we go through all the images we've found, calculate those
    values, and save them off.

    Args:
    sess: The current active TensorFlow Session.
    image_lists: OrderedDict of training images for each label.
    image_dir: Root folder string of the subfolders containing the training
    images.
    bottleneck_dir: Folder string holding cached files of bottleneck values.
    jpeg_data_tensor: Input tensor for jpeg data from file.
    decoded_image_tensor: The output of decoding and resizing the image.
    resized_input_tensor: The input node of the recognition graph.
    bottleneck_tensor: The penultimate output layer of the graph.
    module_name: The name of the image module being used.

    Returns:
    Nothing.
    """
    how_many_bottlenecks = 0
    #ensure_dir_exists(bottleneck_dir)
    if not os.path.exists(dir_name):
        os.makedirs(dir_name)
    
    for label_name, label_lists in image_lists.items():
        for category in ['training', 'testing', 'validation']:
            category_list = label_lists[category]
            for index, unused_base_name in enumerate(category_list):
                get_or_create_bottleneck(sess, image_lists, label_name, index, image_dir, category,bottleneck_dir,
                     jpeg_data_tensor, decoded_image_tensor,resized_input_tensor, bottleneck_tensor, module_name)
                
                how_many_bottlenecks += 1
                if how_many_bottlenecks % 100 == 0:
                    tf.logging.info(str(how_many_bottlenecks) + ' bottleneck files created.')

main函数测试:

if __name__=main(_):
    #获取商品图片
    image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage,                 FLAGS.validation_percentage)
    class_count = len(image_lists.keys())

    #加载hub某个模型,并拉取模型信息,创建图
    module_spec = hub.load_module_spec(FLAGS.tfhub_module)
    graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (create_module_graph(module_spec))
    with tf.Session(graph=graph) as sess:
        # Initialize all weights: for the module to their pretrained values, and for the newly added retraining layer to random initial values.
        init = tf.global_variables_initializer()
        sess.run(init)
        # Set up the image decoding sub-graph.
        jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)

        #缓存所有图片的bottlenecks(特征向量)
        cache_bottlenecks(sess, image_lists, FLAGS.image_dir,FLAGS.bottleneck_dir, 
                      jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor, FLAGS.tfhub_module)

图片bottlenecks(特征向量)数据格式(2048维向量):

0.063915215,0.7282615,0.30556193,0.42560956,0.2697923,0.06698525,0.88659924,0.32001853,0.025883203,0.08164722,0.33431992,....

4、新类别模型训练

预定义-随机获取一批bottleneck文件数据,用于随机梯度下降:

#随机获取一批bottleneck文件数据,用于随机梯度下降
def get_random_cached_bottlenecks(sess, image_lists, how_many, category,bottleneck_dir, image_dir,
                                  jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor, module_name):
    class_count = len(image_lists.keys())
    bottlenecks = []
    ground_truths = []
    filenames = []
    if how_many >= 0:
        # Retrieve a random sample of bottlenecks.
        for unused_i in range(how_many):
            label_index = random.randrange(class_count)
            label_name = list(image_lists.keys())[label_index]
            image_index = random.randrange(MAX_NUM_IMAGES_PER_CLASS + 1)
            image_name = get_image_path(image_lists, label_name, image_index, image_dir, category)
            bottleneck = get_or_create_bottleneck(sess, image_lists, label_name, image_index, image_dir, category,bottleneck_dir, 
                                                  jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor, module_name)
            bottlenecks.append(bottleneck)
            ground_truths.append(label_index)
            filenames.append(image_name)
    else:
        # Retrieve all bottlenecks.
        for label_index, label_name in enumerate(image_lists.keys()):
            for image_index, image_name in enumerate(image_lists[label_name][category]):
                image_name = get_image_path(image_lists, label_name, image_index,image_dir, category)
                bottleneck = get_or_create_bottleneck(sess, image_lists, label_name, image_index, image_dir, category,bottleneck_dir, 
                                            jpeg_data_tensor, decoded_image_tensor, resized_input_tensor, bottleneck_tensor, module_name)
                bottlenecks.append(bottleneck)
                ground_truths.append(label_index)
                filenames.append(image_name)
    return bottlenecks, ground_truths, filenames


#tensorflow 可视化
def variable_summaries(var):
    """Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
    with tf.name_scope('summaries'):
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean', mean)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev', stddev)
        tf.summary.scalar('max', tf.reduce_max(var))
        tf.summary.scalar('min', tf.reduce_min(var))
        tf.summary.histogram('histogram', var)

输出结果为:

#bottlenecks-选取图片的2048维向量
[[0.034603953, 0.35557234,...],[0.9271929, 0.24392605,..],...]
#ground_truth--选取图片的类别
[3, 2, 3,....]
#filenames-图片的路径
 ['E:\\DataMining\\tensorflow\\google-ImageClassification\\flower_photos\\sunflowers\\4933229357_1c5cc03f65_m.jpg',...]

增加新softmax函数,构建全连接层:

#增加新softmax函数,构建全连接层
def add_final_retrain_ops(class_count, final_tensor_name, bottleneck_tensor, quantize_layer, is_training):
    """Adds a new softmax and fully-connected layer for training and eval.

    We need to retrain the top layer to identify our new classes, so this function
    adds the right operations to the graph, along with some variables to hold the
    weights, and then sets up all the gradients for the backward pass.

    The set up for the softmax and fully-connected layers is based on:
    https://www.tensorflow.org/tutorials/mnist/beginners/index.html

    Args:
    class_count: Integer of how many categories of things we're trying to
        recognize.
    final_tensor_name: Name string for the new final node that produces results.
    bottleneck_tensor: The output of the main CNN graph.
    quantize_layer: Boolean, specifying whether the newly added layer should be
        instrumented for quantization with TF-Lite.
    is_training: Boolean, specifying whether the newly add layer is for training
        or eval.

    Returns:
    The tensors for the training and cross entropy results, and tensors for the
    bottleneck input and ground truth input.
    """
    batch_size, bottleneck_tensor_size = bottleneck_tensor.get_shape().as_list()
    assert batch_size is None, 'We want to work with arbitrary batch size.'
    with tf.name_scope('input'):
        bottleneck_input = tf.placeholder_with_default(bottleneck_tensor,shape=[batch_size, bottleneck_tensor_size],name='BottleneckInputPlaceholder')
        ground_truth_input = tf.placeholder(tf.int64, [batch_size], name='GroundTruthInput')

    # Organizing the following ops so they are easier to see in TensorBoard.
    layer_name = 'final_retrain_ops'
    with tf.name_scope(layer_name):
        with tf.name_scope('weights'):
            initial_value = tf.truncated_normal([bottleneck_tensor_size, class_count], stddev=0.001)
            layer_weights = tf.Variable(initial_value, name='final_weights')
            variable_summaries(layer_weights)

        with tf.name_scope('biases'):
            layer_biases = tf.Variable(tf.zeros([class_count]), name='final_biases')
            variable_summaries(layer_biases)

        with tf.name_scope('Wx_plus_b'):
            logits = tf.matmul(bottleneck_input, layer_weights) + layer_biases
            tf.summary.histogram('pre_activations', logits)

    final_tensor = tf.nn.softmax(logits, name=final_tensor_name)

    # The tf.contrib.quantize functions rewrite the graph in place for
    # quantization. The imported model graph has already been rewritten, so upon
    # calling these rewrites, only the newly added final layer will be
    # transformed.
    if quantize_layer:
        if is_training:
            tf.contrib.quantize.create_training_graph()
        else:
            tf.contrib.quantize.create_eval_graph()

    tf.summary.histogram('activations', final_tensor)

  # If this is an eval graph, we don't need to add loss ops or an optimizer.
    if not is_training:
        return None, None, bottleneck_input, ground_truth_input, final_tensor

    with tf.name_scope('cross_entropy'):
        cross_entropy_mean = tf.losses.sparse_softmax_cross_entropy(labels=ground_truth_input, logits=logits)

    tf.summary.scalar('cross_entropy', cross_entropy_mean)

    with tf.name_scope('train'):
        optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)
        train_step = optimizer.minimize(cross_entropy_mean)

    return (train_step, cross_entropy_mean, bottleneck_input, ground_truth_input, final_tensor)

输出数据结果为:

#train_step
name: "train/GradientDescent"
op: "NoOp"
input: "^train/GradientDescent/update_final_retrain_ops/weights/final_weights/ApplyGradientDescent"
input: "^train/GradientDescent/update_final_retrain_ops/biases/final_biases/ApplyGradientDescent"
#cross_entropy:  
Tensor("cross_entropy/sparse_softmax_cross_entropy_loss/value:0", shape=(), dtype=float32)
#bottleneck_input 
Tensor("input/BottleneckInputPlaceholder:0", shape=(?, 2048), dtype=float32)
#ground_truth_input:  
Tensor("input/GroundTruthInput:0", shape=(?,), dtype=int64)
#final_tensor:  
Tensor("final_result:0", shape=(?, 5), dtype=float32)

对训练结果的评估:

#增加 训练结果的评估
def add_evaluation_step(result_tensor, ground_truth_tensor):
    """Inserts the operations we need to evaluate the accuracy of our results.

    Args:
    result_tensor: The new final node that produces results.
    ground_truth_tensor: The node we feed ground truth data
    into.

    Returns:
    Tuple of (evaluation step, prediction).
    """
    with tf.name_scope('accuracy'):
        with tf.name_scope('correct_prediction'):
            prediction = tf.argmax(result_tensor, 1)
            correct_prediction = tf.equal(prediction, ground_truth_tensor)
        with tf.name_scope('accuracy'):
            evaluation_step = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
            
    tf.summary.scalar('accuracy', evaluation_step)
    return evaluation_step, prediction

输出结果为:

#evaluation_step:  
Tensor("accuracy/accuracy/Mean:0", shape=(), dtype=float32)
#predictions:  
Tensor("accuracy/correct_prediction/ArgMax:0", shape=(?,), dtype=int64)

用测试集对模型评估:

#用测试集对模型评估

#创建用于评估的会话
def build_eval_session(module_spec, class_count):
    # If quantized, we need to create the correct eval graph for exporting.
    eval_graph, bottleneck_tensor, resized_input_tensor, wants_quantization = (create_module_graph(module_spec))

    eval_sess = tf.Session(graph=eval_graph)
    with eval_graph.as_default():
        # Add the new layer for exporting.
        (_, _, bottleneck_input,ground_truth_input, final_tensor) = add_final_retrain_ops(class_count, FLAGS.final_tensor_name, bottleneck_tensor, wants_quantization, is_training=False)

        # Now we need to restore the values from the training graph to the evalgraph.
        tf.train.Saver().restore(eval_sess, CHECKPOINT_NAME)

        evaluation_step, prediction = add_evaluation_step(final_tensor,ground_truth_input)

    return (eval_sess, resized_input_tensor, bottleneck_input, ground_truth_input,evaluation_step, prediction)

#对测试集进行评估
def run_final_eval(train_session, module_spec, class_count, image_lists,
                   jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor):
    """Runs a final evaluation on an eval graph using the test data set.

    Args:
    train_session: Session for the train graph with the tensors below.
    module_spec: The hub.ModuleSpec for the image module being used.
    class_count: Number of classes
    image_lists: OrderedDict of training images for each label.
    jpeg_data_tensor: The layer to feed jpeg image data into.
    decoded_image_tensor: The output of decoding and resizing the image.
    resized_image_tensor: The input node of the recognition graph.
    bottleneck_tensor: The bottleneck output layer of the CNN graph.
    """
    test_bottlenecks, test_ground_truth, test_filenames = (get_random_cached_bottlenecks(train_session, image_lists,FLAGS.test_batch_size, 'testing', FLAGS.bottleneck_dir,FLAGS.image_dir, 
                                                   jpeg_data_tensor,decoded_image_tensor, resized_image_tensor,bottleneck_tensor, FLAGS.tfhub_module))

    (eval_session, _, bottleneck_input, ground_truth_input, evaluation_step,prediction) = build_eval_session(module_spec, class_count)
    test_accuracy, predictions = eval_session.run([evaluation_step, prediction],
                                        feed_dict={bottleneck_input: test_bottlenecks,ground_truth_input: test_ground_truth})
    tf.logging.info('Final test accuracy = %.1f%% (N=%d)' %(test_accuracy * 100, len(test_bottlenecks)))

训练新类别预测模型:

#获取商品图片
image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage, FLAGS.validation_percentage)
class_count = len(image_lists.keys())

#加载hub某个模型,并拉取模型信息,创建图
module_spec = hub.load_module_spec(FLAGS.tfhub_module)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (create_module_graph(module_spec))

#增加新softmax函数,构建全连接层
with graph.as_default():
    (train_step, cross_entropy, bottleneck_input,ground_truth_input, final_tensor) = add_final_retrain_ops(class_count, FLAGS.final_tensor_name, bottleneck_tensor, wants_quantization, is_training=True)

with tf.Session(graph=graph) as sess:
    # Initialize all weights: for the module to their pretrained values,
    # and for the newly added retraining layer to random initial values.
    init = tf.global_variables_initializer()
    sess.run(init)
    # Set up the image decoding sub-graph.
    jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)
    
    #缓存所有图片的bottlenecks(特征向量)
    cache_bottlenecks(sess, image_lists, FLAGS.image_dir,FLAGS.bottleneck_dir, 
                      jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor, FLAGS.tfhub_module)
    
    #增加评估
    evaluation_step, predictions = add_evaluation_step(final_tensor, ground_truth_input)

    #记录概要信息
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/train', sess.graph)
    validation_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/validation')
    train_saver = tf.train.Saver()
    
    #新类别模型训练
    for i in range(FLAGS.how_many_training_steps):
        (train_bottlenecks,train_ground_truth, train_filenames) = get_random_cached_bottlenecks(sess, image_lists, FLAGS.train_batch_size, 'training',FLAGS.bottleneck_dir, FLAGS.image_dir, 
                                                            jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor, FLAGS.tfhub_module) #获取一批bottleneck数据

        
        train_summary,_ = sess.run([merged, train_step], feed_dict={bottleneck_input:train_bottlenecks, ground_truth_input:train_ground_truth}) #完成一次更新
        train_writer.add_summary(train_summary, i)
        
        is_last_step = (i + 1 == FLAGS.how_many_training_steps)
        if (i % FLAGS.eval_step_interval) == 0 or is_last_step:
            train_accuracy, cross_entropy_value = sess.run([evaluation_step, cross_entropy], feed_dict={bottleneck_input: train_bottlenecks, ground_truth_input: train_ground_truth})
            tf.logging.info('%s: Step %d: Train accuracy = %.1f%%, Cross entropy = %f ' %(datetime.now(), i, train_accuracy * 100, cross_entropy_value))
            
            validation_bottlenecks, validation_ground_truth, _ = (get_random_cached_bottlenecks(sess, image_lists, FLAGS.validation_batch_size, 'validation',FLAGS.bottleneck_dir, FLAGS.image_dir, 
                                      jpeg_data_tensor,decoded_image_tensor, resized_image_tensor, bottleneck_tensor,FLAGS.tfhub_module))
            validation_summary, validation_accuracy = sess.run([merged, evaluation_step],feed_dict={bottleneck_input: validation_bottlenecks,ground_truth_input: validation_ground_truth})
            validation_writer.add_summary(validation_summary, i)
            tf.logging.info('%s: Step %d: Validation accuracy = %.1f%% (N=%d)' % (datetime.now(), i, validation_accuracy * 100,len(validation_bottlenecks)))
    
    #训练完成,保存训练数据
    train_saver.save(sess, CHECKPOINT_NAME)
    
    #最终的模型对测试集评估
    run_final_eval(sess, module_spec, class_count, image_lists,jpeg_data_tensor, decoded_image_tensor, resized_image_tensor,bottleneck_tensor)

输出结果为:

INFO:tensorflow:2019-03-12 16:07:53.515801: Step 0: Train accuracy = 24.0%, Cross entropy = 1.530714 
INFO:tensorflow:2019-03-12 16:07:54.157838: Step 0: Validation accuracy = 23.0% (N=100)
INFO:tensorflow:2019-03-12 16:07:56.185954: Step 9: Train accuracy = 82.0%, Cross entropy = 1.183218 
INFO:tensorflow:2019-03-12 16:07:56.307961: Step 9: Validation accuracy = 69.0% (N=100)
INFO:tensorflow:Final test accuracy = 71.8% (N=365)

5、新类别预测模型保存

将预测模型写入文件:

#新类别预测图保存到文件

def save_graph_to_file(graph_file_name, module_spec, class_count):
    """Saves an graph to file, creating a valid quantized one if necessary."""
    sess, _, _, _, _, _ = build_eval_session(module_spec, class_count)
    graph = sess.graph
    output_graph_def = tf.graph_util.convert_variables_to_constants(sess, graph.as_graph_def(), [FLAGS.final_tensor_name])
    with tf.gfile.FastGFile(graph_file_name, 'wb') as f:
        f.write(output_graph_def.SerializeToString())

#新类别预测模型保存
def export_model(module_spec, class_count, saved_model_dir):
    """Exports model for serving. """
    # The SavedModel should hold the eval graph.
    sess, in_image, _, _, _, _ = build_eval_session(module_spec, class_count)
    with sess.graph.as_default() as graph:
        tf.saved_model.simple_save(sess,saved_model_dir,
                        inputs={'image': in_image},outputs={'prediction': graph.get_tensor_by_name('final_result:0')},
                        legacy_init_op=tf.group(tf.tables_initializer(), name='legacy_init_op'))

训练新预测模型并保存:

#获取商品图片
image_lists = create_image_lists(FLAGS.image_dir, FLAGS.testing_percentage, FLAGS.validation_percentage)
class_count = len(image_lists.keys())

#加载hub某个模型,并拉取模型信息,创建图
module_spec = hub.load_module_spec(FLAGS.tfhub_module)
graph, bottleneck_tensor, resized_image_tensor, wants_quantization = (create_module_graph(module_spec))

#增加新softmax函数,构建全连接层
with graph.as_default():
    (train_step, cross_entropy, bottleneck_input,ground_truth_input, final_tensor) = add_final_retrain_ops(class_count, FLAGS.final_tensor_name, bottleneck_tensor, wants_quantization, is_training=True)

    
with tf.Session(graph=graph) as sess:
    # Initialize all weights: for the module to their pretrained values,
    # and for the newly added retraining layer to random initial values.
    init = tf.global_variables_initializer()
    sess.run(init)
    # Set up the image decoding sub-graph.
    jpeg_data_tensor, decoded_image_tensor = add_jpeg_decoding(module_spec)
    
    #缓存所有图片的bottlenecks(特征向量)
    cache_bottlenecks(sess, image_lists, FLAGS.image_dir,FLAGS.bottleneck_dir, 
                      jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor, FLAGS.tfhub_module)
    
    #增加评估
    evaluation_step, predictions = add_evaluation_step(final_tensor, ground_truth_input)
    print('add_evaluation_step:')
    print('evaluation_step: ', evaluation_step)
    print('predictions: ', predictions)

    
    #记录概要信息
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/train', sess.graph)
    validation_writer = tf.summary.FileWriter(FLAGS.summaries_dir + '/validation')
    train_saver = tf.train.Saver()
    
    #新类别模型训练
    FLAGS.how_many_training_steps = 10
    for i in range(FLAGS.how_many_training_steps):
        (train_bottlenecks,train_ground_truth, train_filenames) = get_random_cached_bottlenecks(sess, image_lists, FLAGS.train_batch_size, 'training',FLAGS.bottleneck_dir, FLAGS.image_dir, 
                                                            jpeg_data_tensor, decoded_image_tensor, resized_image_tensor, bottleneck_tensor, FLAGS.tfhub_module) #获取一批bottleneck数据
        
        if(i == 1):
            print('train_bottlenecks: ', train_bottlenecks, '\n')
            print('train_ground_truth: ', train_ground_truth, '\n')
            print('train_filenames: ', train_filenames, '\n')
        
        train_summary,_ = sess.run([merged, train_step], feed_dict={bottleneck_input:train_bottlenecks, ground_truth_input:train_ground_truth}) #完成一次更新
        train_writer.add_summary(train_summary, i)
        
        is_last_step = (i + 1 == FLAGS.how_many_training_steps)
        if (i % FLAGS.eval_step_interval) == 0 or is_last_step:
            train_accuracy, cross_entropy_value = sess.run([evaluation_step, cross_entropy], feed_dict={bottleneck_input: train_bottlenecks, ground_truth_input: train_ground_truth})
            tf.logging.info('%s: Step %d: Train accuracy = %.1f%%, Cross entropy = %f ' %(datetime.now(), i, train_accuracy * 100, cross_entropy_value))
            
            validation_bottlenecks, validation_ground_truth, _ = (get_random_cached_bottlenecks(sess, image_lists, FLAGS.validation_batch_size, 'validation',FLAGS.bottleneck_dir, FLAGS.image_dir, 
                                      jpeg_data_tensor,decoded_image_tensor, resized_image_tensor, bottleneck_tensor,FLAGS.tfhub_module))
            validation_summary, validation_accuracy = sess.run([merged, evaluation_step],feed_dict={bottleneck_input: validation_bottlenecks,ground_truth_input: validation_ground_truth})
            validation_writer.add_summary(validation_summary, i)
            tf.logging.info('%s: Step %d: Validation accuracy = %.1f%% (N=%d)' % (datetime.now(), i, validation_accuracy * 100,len(validation_bottlenecks)))
    
    #训练完成,保存训练数据
    train_saver.save(sess, CHECKPOINT_NAME)
    
    #最终的模型对测试集评估
    run_final_eval(sess, module_spec, class_count, image_lists,jpeg_data_tensor, decoded_image_tensor, resized_image_tensor,bottleneck_tensor)
    
    #模型保存
    tf.logging.info('Save final result to : ' + FLAGS.output_graph)
    save_graph_to_file(FLAGS.output_graph, module_spec, class_count)
    tf.logging.info('Save new categories to :' + FLAGS.output_labels)
    with tf.gfile.FastGFile(FLAGS.output_labels, 'w') as f:
        f.write('\n'.join(image_lists.keys()) + '\n')
    if FLAGS.saved_model_dir:
        export_model(module_spec, class_count, FLAGS.saved_model_dir)
    

结果输出为:

预测图

新类别名称:

预测模型:

二、模型预测

参数预定义:

file_name = "E:\\DataMining\\tensorflow\\google-ImageClassification\\flower_photos\\daisy\\5547758_eea9edfd54_n.jpg" #image
model_file = "E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\graph\\output_graph.pb" #graph/model to be execute
label_file = "'E:\\DataMining\\tensorflow\\google-ImageClassification\\flower\\labels\\output_labels.txt" #name of file containing labels
input_height = 299
input_width = 299
input_mean = 0
input_std = 255
input_layer = "Placeholder" #"name of input layer"
output_layer = "final_result" #"name of output layer"

#对类别名称加载
def load_labels(label_file):
    label = []
    proto_as_ascii_lines = tf.gfile.GFile(label_file).readlines()
    for l in proto_as_ascii_lines:
        label.append(l.rstrip())
    return label

1、预测模型加载

#预测模型加载
def load_graph(model_file):
    graph = tf.Graph()
    graph_def = tf.GraphDef()
    with open(model_file, "rb") as f:
        graph_def.ParseFromString(f.read())
    with graph.as_default():
        tf.import_graph_def(graph_def)
    return graph

加载模型,并引入输入层和输出层: 

graph = load_graph(model_file)
input_name = "import/" + input_layer
output_name = "import/" + output_layer
input_operation = graph.get_operation_by_name(input_name)
output_operation = graph.get_operation_by_name(output_name)

2、加载预测图片(图片进行解码和剪裁),预测图片类别

预测图片加载,并对图片进行解码和剪裁

#预测图片加载,并对图片进行解码和剪裁
def read_tensor_from_image_file(file_name,input_height=299,input_width=299, input_mean=0, input_std=255):
    input_name = "file_reader"
    output_name = "normalized"
    file_reader = tf.read_file(file_name, input_name)
    if file_name.endswith(".png"):
        image_reader = tf.image.decode_png(file_reader, channels=3, name="png_reader")
    elif file_name.endswith(".gif"):
        image_reader = tf.squeeze(tf.image.decode_gif(file_reader, name="gif_reader"))
    elif file_name.endswith(".bmp"):
        image_reader = tf.image.decode_bmp(file_reader, name="bmp_reader")
    else:
        image_reader = tf.image.decode_jpeg(file_reader, channels=3, name="jpeg_reader")
        
    float_caster = tf.cast(image_reader, tf.float32)
    dims_expander = tf.expand_dims(float_caster, 0)
    resized = tf.image.resize_bilinear(dims_expander, [input_height, input_width])
    normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std])
    sess = tf.Session()
    result = sess.run(normalized)

    return result

图片类别预测:

#加载图片
t = read_tensor_from_image_file(file_name, input_height=input_height, input_width=input_width, input_mean=input_mean, input_std=input_std)
with tf.Session(graph=graph) as sess:
    results = sess.run(output_operation.outputs[0], {input_operation.outputs[0]: t})
results = np.squeeze(results)

#输出预测概率最大的5个类别
top_k = results.argsort()[-5:][::-1]
labels = load_labels(label_file)
for i in top_k:
    print(labels[i], results[i])

输出结果:

sunflowers 0.27877674
daisy 0.21119775
dandelion 0.17498685
tulips 0.17195
roses 0.16308863

猜你喜欢

转载自blog.csdn.net/woniu201411/article/details/88394242
今日推荐