《tensorflow:实战google深度学习框架》7.3.4输入数据处理框架

1、用之前flower的数据集制作TFRecord文件

使用了队列以及线程

import glob
import os.path
import numpy as np
import tensorflow as tf


# 生成整数型的属性
def _int64_feature(value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))


# 生成字符串属性
def _bytes_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))


INPUT_DATA = '../../data/flower_photos'


def get_list():
    sub_dirs = [x[0] for x in os.walk(INPUT_DATA)]
    is_root_dir = True

    current_label = 0
    file_list = []
    label_list = []

    # 读取所有子目录
    for sub_dir in sub_dirs:
        if is_root_dir:
            is_root_dir = False
            continue
        cur_file_list = []
        # 获取一个子目录中所有的图片文件
        extensions = ['jpg', 'jpeg']

        dir_name = os.path.basename(sub_dir)
        print("正在处理文件夹" + dir_name)
        for extension in extensions:
            file_glob = os.path.join(INPUT_DATA, dir_name, '*.' + extension)
            cur_file_list.extend(glob.glob(file_glob))
        if not cur_file_list: continue
        print("当前文件夹下样例个数%d" % len(cur_file_list))
        file_list.extend(cur_file_list)
        label_list.append([current_label] * len(cur_file_list))
        print(len(file_list), len(label_list))
        current_label += 1  # 这里同一个标签表示在同一个file_name下的文件夹里
    # file_list=tf.reshape(file_list,[None,1])
    # label_list = tf.reshape(label_list, [None, 1])
    return file_list, label_list


# 模拟海量文件下 将数据写入不同的文件
num_shards = 5  # 总共写入文件数
# instance_per_shard = 100  # 定义每个文件中有多少数据

files, labels = get_list()
filename_queue = tf.train.string_input_producer(files, shuffle=False, num_epochs=1)

# 读取并解析一个样本
reader = tf.WholeFileReader()
_, image_raw_data = reader.read(filename_queue)
image = tf.image.decode_jpeg(image_raw_data)
if image.dtype != tf.float32:
    image = tf.image.convert_image_dtype(image, dtype=tf.float32)
image = tf.image.resize_images(image, [299, 299])

height = image.shape[0]
width = image.shape[1]
channels = 3

print(height,width)

with tf.Session() as sess:
    tf.local_variables_initializer().run()
    tf.global_variables_initializer().run()

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess=sess, coord=coord)

    cur = 0
    for i in range(num_shards):
        # 分文件是可以按照0000n-of-0000m的形式,n是当前文件编号,m是数据总共被存在了多少个文件中
        filename = ("flower_process_data.tfrecords-%.5d-of-%.5d" % (i, num_shards))
        writer = tf.python_io.TFRecordWriter(filename)

        # 记录当前样例属于第几个文件以及是当前文件的第几个样本
        for j in range(len(labels[i])):

            print("正在写第%d样例,当前文件夹序号%d,当前文件序号%d" % (cur, i, j))
            image_value = sess.run(image)
            example = tf.train.Example(
                features=tf.train.Features(feature={'image': _bytes_feature(image_value.tostring()),
                                                    'label': _int64_feature(labels[i][j]),
                                                    'height': _int64_feature(height),
                                                    'width': _int64_feature(width),
                                                    'channels': _int64_feature(channels)}))
            writer.write(example.SerializeToString())
            cur += 1
        writer.close()

    coord.request_stop()
    coord.join(threads)

2、实现输入数据处理框架

这里用了google的inception-v3模型,下载地址为 http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz

数据集预处理在preprocess_image.py

网络的设置在net.py

import tensorflow as tf
import tensorflow.contrib.slim as slim

# 加载slim里定义好的inception-v3模型
import tensorflow.contrib.slim.python.slim.nets.inception_v3 as inception_v3

import preprocess_image
import net

'''
经典输入数据处理流程:
    1 指定原始数据文件列表
    2 创建文件列表队列
    3 从文件中读取数据
    4 数据预处理
    5 整理成batch作为神经网络的输入
'''

# 创建文件列表队列
files = tf.train.match_filenames_once("flower_process_data.tfrecords-*")
filename_queue = tf.train.string_input_producer(files, shuffle=False)

# 解析一个样例
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue)
features = tf.parse_single_example(serialized_example, features={'image': tf.FixedLenFeature([], tf.string),
                                                                 'label': tf.FixedLenFeature([], tf.int64),
                                                                 'height': tf.FixedLenFeature([], tf.int64),
                                                                 'width': tf.FixedLenFeature([], tf.int64),
                                                                 'channels': tf.FixedLenFeature([], tf.int64)
                                                                 })
image, label = features['image'], tf.cast(features['label'], tf.int32)
height, width = tf.cast(features['height'], tf.int32), tf.cast(features['width'], tf.int32)
# channels = tf.cast(features['channels'], tf.int32)

# 解码图像
image_size = 299
channels = 3
decoded_image = tf.decode_raw(image, tf.float32)
retyped_image = tf.reshape(decoded_image, [image_size, image_size, channels])

# 定义神经网络输入层图片的大小,并对图像进行随机调整,定义在preprocess_image.py里
distorted_image = preprocess_image.preprocess_for_train(retyped_image, image_size, image_size, channels, None)

# 整理batch
min_after_dequeue = 10000
batch_size = 100
capacity = min_after_dequeue + 3 * batch_size
image_batch, label_batch = tf.train.shuffle_batch([distorted_image, label], batch_size=batch_size, capacity=capacity,
                                                  min_after_dequeue=min_after_dequeue)

# 定义神经网络结构以及优化过程
learning_rate = 0.01
logit, loss, loaf_fn = net.inference(image_batch, label_batch)  # 定义在net.py里
# loss = net.calc_loss(logit, label_batch)  # 定义在net.py里
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
with tf.Session() as sess:
    sess.run(tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()))

    print('加载模型:Loading tuned Variables from %s' % net.CKPT_FILE)
    loaf_fn(sess)

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess=sess, coord=coord)

    # 训练神经网络
    TRAINING_ROUNDS = 5000
    for i in range(TRAINING_ROUNDS):
        sess.run(train_step)
        if i % 100 == 0:
            print("经过 %d 次训练, loss 为 %g " % (i, sess.run(loss)))

    coord.request_stop()
    coord.join(threads)


3、preprocess_image.py

import tensorflow as tf
import numpy as np


# 随机调整图像亮度、饱和度、色相、对比度
def distort_color(image, color_ordering=0):
    if color_ordering == 0:
        image = tf.image.random_brightness(image, max_delta=32. / 255.)
        image = tf.image.random_saturation(image, lower=0.5, upper=1.5)
        image = tf.image.random_hue(image, max_delta=0.2)
        image = tf.image.random_contrast(image, lower=0.5, upper=1.5)
    elif color_ordering == 1:
        image = tf.image.random_saturation(image, lower=0.5, upper=1.5)
        image = tf.image.random_brightness(image, max_delta=32. / 255.)
        image = tf.image.random_contrast(image, lower=0.5, upper=1.5)
        image = tf.image.random_hue(image, max_delta=0.2)
    # 还可以定义其他排列
    return tf.clip_by_value(image, 0.0, 1.0)


def preprocess_for_train(image, height, width, channels, bbox):
    # 如果没有提供标注框,就认为是图像整体
    if bbox is None:
        bbox = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32, shape=[1, 1, 4])
    # 转换图像张量类型
    if image.dtype != tf.float32:
        image = tf.image.convert_image_dtype(image, dtype=tf.float32)

    # 随机截取图像,减小需要关注的物体的大小对图像识别算法的影响
    bbox_begin, bbox_size, _ = tf.image.sample_distorted_bounding_box(tf.shape(image), bounding_boxes=bbox)
    distorted_image = tf.slice(image, bbox_begin, bbox_size)

    # 将随机截取的图像调整成神经网络输入层的大小。大小调整算法是随机的
    distorted_image = tf.image.resize_images(distorted_image, [height, width], method=np.random.randint(4))
    # 随机左右翻转
    distorted_image = tf.image.random_flip_left_right(distorted_image)
    # 使用随机顺序调整图像色彩
    distorted_image = distort_color(distorted_image, np.random.randint(2))

    # 规范格式
    distorted_image = tf.reshape(distorted_image, [height, width, channels])
    return distorted_image

4、net.py

import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim

# 加载slim里定义好的inception-v3模型
import tensorflow.contrib.slim.python.slim.nets.inception_v3 as inception_v3

N_CLASSES = 5
# 定义不需要从模型中加载的参数。这里就是最后的全连接层,因为在新
# 的问题中要重新训练这一层中的参数。这里给出的是参数的前缀
CHECKPOINT_EXCLUDE_SCOPES = 'InceptionV3/Logits,InceptionV3/AuxLogits'
# 定义需要加载的训练的网络层参数名称,在微调过程中就是最后的全连接层。这里给出参数的前缀
TRAINABLE_SCOPES = 'InceptionV3/Logits,InceptionV3/AuxLogits'


# 获取所有需要从训练好的模型中加载的参数
def get_tuned_variables():
    exclutions = [scope.strip() for scope in CHECKPOINT_EXCLUDE_SCOPES.split(',')]

    variables_to_restore = []
    # 枚举inception v3模型中所有的参数,然后判断是否需要从加载列表中删除
    for var in slim.get_model_variables():
        excluded = False
        for exclution in exclutions:
            if var.op.name.startswith(exclution):
                excluded = True
                break
        if not excluded:
            variables_to_restore.append(var)

    return variables_to_restore


# 获取所有需要训练的变量列表
def get_trainable_variables():
    scopes = [scope.strip() for scope in TRAINABLE_SCOPES.split(',')]

    variables_to_train = []
    # 枚举所有需要训练的参数前缀,并通过这些前缀找到所有参数
    for scope in scopes:
        variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope)
        variables_to_train.extend(variables)

    return variables_to_train

CKPT_FILE = 'inception_v3.ckpt'
def inference(image, label):
    # 定义inception v3模型,因为谷歌给出的只有模型参数取值,所以这里需要在这个代码中定义inceptionv3的模型结构,虽然理
    # 论上需要区分训练和测试中使用的模型,也就是说在测试时应该使用is_training= False,但是因为预先训练好的v3模型中使
    # 用的batch normalization参数与新的数据有差异,导致结果很差,所以这里直接使用同一个模型来进行测试
    with slim.arg_scope(inception_v3.inception_v3_arg_scope()):
        logit, _ = inception_v3.inception_v3(image, num_classes=N_CLASSES, is_training=True)

    # 获取需要训练的变量
    trainable_variables = get_trainable_variables()
    # 定义交叉熵损失,注意在模型定义的时候已经将正则化损失加入损失集合了
    tf.losses.softmax_cross_entropy(tf.one_hot(label, N_CLASSES), logit, weights=1.0)
    # 指定需要优化的变量集合
    loss = tf.losses.get_total_loss()

    # 定义加载模型的函数
    loaf_fn = slim.assign_from_checkpoint_fn(CKPT_FILE, get_tuned_variables(), ignore_missing_vars=True)
    return logit, loss,loaf_fn

在调试程序的过程中,出现了OutofRange的错误,检查了一下发现是TFRecord解码图像的时候有误,导致数据没有被读进去。

猜你喜欢

转载自blog.csdn.net/qq_29396337/article/details/88865358
今日推荐