Tensorflow官网CIFAR-10数据分类教程代码详解

本教程详述如何使用Tensorflow处理CIFAR-10数据集,讲解CIFAR-10的图像分类任务,涵盖数据介绍、模型构建、训练与评估,提供大型复杂模型构建的实践案例,适合学习Tensorflow的初学者。代码已做详细注释,并提供下载链接。
摘要由CSDN通过智能技术生成

标题

概述

对CIFAR-10 数据集的分类是机器学习中一个公开的基准测试问题,本教程代码通过解决CIFAR-10数据分类任务,介绍了Tensorflow的一些高阶用法,演示了构建大型复杂模型的一些重要技巧,着重于建立一个规范的网络组织结构,训练并进行评估,为建立更大规模更加复杂的模型提供一个范例,可以作为学习Tensorflow的一个经典示例。本文章对每行代码做了详细注释,以便对其他学习的朋友有所帮助,并欢迎读者对不恰当处提出意见,以帮助完善。

CIFAR-10数据介绍

CIFAR-10数据集是一组大小为32x32的RGB图像,这些图像涵盖了10个类别:飞机, 汽车, 鸟, 猫, 鹿, 狗, 青蛙, 马, 船以及卡车。

在这里插入图片描述
数据集总共包含60000张图片,每个类别6000张。其中,训练集包含50000张图片,测试集包含10000万张图片。数据集被分为5个训练batch和一个测试batch,每个batch包含10000张图片。从每个类别的图片中随机选出1000张图片共10000张图片作为测试的batch,将剩余图片按照随机排序组成测试batch,每个训练batch中各个类别的图片数量不一定相等,某些类别可能会多一些,某些类别可能会少一些,但是所有训练batch加一起,每个类别的图片数量为5000。各个类别的图片是互斥的,不存在一张图片属于两个或两个以上类别的情况。

数据集的数据类型分Python versions、Matlab versions和Binary version三种,本文代码使用Binary version,故主要介绍这个类型的数据格式。Binary version的数据下载解压后包括data_batch_1.bin、data_batch_2.bin、data_batch_3.bin、data_batch_4.bin data_batch_5.bin和test_batch.bin五个文件,每个文件包含10000个图片数据,每个图片数据包含3073字节,由于每个图片数据之间没有分隔符,所以每个文件共30730000字节。

每个图片数据格式为:

  1. 第一个字节为0-9的数字,为10个类别的标签,对应的类别名称在batches.meta.txt文件中存储,batches.meta.txt包含10行数据,类别标签i对应第i行的名称;
  2. 每张图片为32*32=1024个像素,第2-1025字节为每个像素的red值,第1026-2049字节为每个像素的green值,第2050-3073字节为每个像素的blue值。
  3. 由于数据是按照行主序排列,所以2-33为图片的第一行像素的red值,以此类推。

更多信息请参考CIFAR-10 page

代码详解

代码文件包括:

文件 作用
cifar10_input.py 读取本地CIFAR-10的二进制文件格式的内容。
cifar10.py 建立CIFAR-10的模型。
ccifar10_train.py 读在CPU或GPU上训练CIFAR-10的模型。
cifar10_multi_gpu_train.py 在多GPU上训练CIFAR-10的模型。
cifar10_eval.py 评估CIFAR-10模型的预测性能。
  • cifar10_input.py
# 绝对引入,忽略目录下相同命名的包,引用系统标准的包
from __future__ import absolute_import
# 导入精确除法
from __future__ import division
# 使用python 3.x的print函数
from __future__ import print_function

import os
# xrange返回类,每次遍历返回一个值,range返回列表,一次计算返回所有值,xrange效率要高些
from six.moves import xrange
import tensorflow as tf

IMAGE_SIZE = 24
# CIFAR10的数据分类数为10
NUM_CLASSES = 10
# CIFAR10的训练集有50000个图片
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000
# CIFAR10的测试集有10000个图片
NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = 10000

def read_cifar10(filename_queue):
    # 创建空类,方便数据结构化存储
    class CIFAR10Record(object):
        pass
    result = CIFAR10Record()
    # 1 for cifar-10;2 for cifar-100
    label_bytes = 1
    # cifar10的图片包含32*32个像素,每个像素包含三个RGB值
    result.height = 32
    result.width = 32
    result.depth = 3
    # 计算每幅图片特征向量的字节数
    image_bytes = result.height * result.width * result.depth
    # 计算每条记录的字节数=标签字节数+每幅图片特征向量的字节数
    record_bytes = label_bytes + image_bytes
    # 读取固定长度字节数信息,可以参看文章https://blog.csdn.net/fegang2002/article/details/83046584
    reader = tf.FixedLengthRecordReader(record_bytes=record_bytes)
    result.key, value = reader.read(filename_queue)
    # CIFAR10数据通过Reader读取后通过Record传输变为字符串类型,既value为字符串类型
    # 但是要使用的话,需要还原为CIFAR10原始数据格式tf.uint8(8位无符号整形)类型,可以通过tf.decode_raw函数实现
    record_bytes = tf.decode_raw(value, tf.uint8)
    # 从读取的数据记录中截取出标签值
    result.label = tf.cast(tf.strided_slice(record_bytes, [0], [label_bytes]), tf.int32)
    # 从读取的数据记录中截取出图片数据,并且转换为【深,高,宽】的形状[3,32,32]
    depth_major = tf.reshape(
        tf.strided_slice(record_bytes, [label_bytes], [label_bytes + image_bytes]),
        [result.depth, result.height, result.width],
    )
    # 转换depth_major的维度,将第一个维度放在最后,既更新为【高,宽,深】的形状[32,32,3]
    result.uint8image = tf.transpose(depth_major, [1, 2, 0])

    return result


def _generate_image_and_label_batch(
    image, label, min_queue_examples, batch_size, shuffle
):
    # 设置入列的线程?
    num_preprocess_threads = 16
    if shuffle:
        # 把输入的图片像素数据和标签数据随机打乱后,按照批次生成输出的图片像素数据和标签数据
        images, label_batch = tf.train.shuffle_batch(
            [image, label],
            batch_size=batch_size,
            num_threads=num_preprocess_threads,
            capacity=min_queue_examples + 3 * batch_size,
            # 出列后,队列中要保持的最小元素数?
            min_after_dequeue=min_queue_examples,
        )
    else:
        # 把输入的图片像素数据和标签数据按照原顺序、按照批次生成输出的图片像素数据和标签数据
        images, label_batch = tf.train.batch(
            [image, label],
            batch_size=batch_size,
            num_threads=num_preprocess_threads,
            capacity=min_queue_examples + 3 * batch_size,
        )
    # 将输入的图像数据记录到缓存中,为后续展示准备
    tf.summary.image("image", image)

    return images, tf.reshape(label_batch, [batch_size])


def destorted_inputs(data_dir, batch_size):
    # 设置CIFAR10数据文件的位置和名称
    filename = [os.path.join(data_dir, "data_batch_%d.bin" % i) for i in xrange(1, 6)]
    # 如果设置的CIFAR10数据文件不存在,报错退出
    for f in filename:
        if not tf.gfile.Exists(f):
            raise ValueError("Failed to find file: " + f)

    # 将filename中包含的文件打包生成一个先入先出队列(FIFOQueue)
    # 并且在计算图的QUEUE_RUNNER集合中添加一个QueueRunner(QueueRunner包含一个队列的一系列的入列操作)
    # 默认shuffle=True时,会对文件名进行随机打乱处理
    filename_queue = tf.train.string_input_producer(filename)

    with tf.name_scope("data_augmentation"):
        # 调用read_cifar10函数,将队列filename_queue进行处理,返回值赋予read_input
        read_input = read_cifar10(filename_queue)
        # 将图片像素数据read_input.uint8image转化为tf.float32类型,赋予reshaped_image
        reshaped_image = tf.cast(read_input.uint8image, tf.float32)

        height = IMAGE_SIZE
        width = IMAGE_SIZE
        # 对图片进行随机切割,转化尺寸为[24,24,3]
        distorted_image = tf.random_crop(reshaped_image, [height, width, 3])
        # 对切割后图片沿width方向随机翻转,有可能的结果就是从左往右,从左往左等于没有翻转
        distorted_image = tf.image.random_flip_left_right(distorted_image)
        # 对切割翻转后的图片随机调整亮度,实际上是在原图的基础上随机加上一个值(如果加上的是正值则增亮否则增暗),
        # 此值取自[-max_delta,max_delta),要求max_delta>=0。
        distorted_image = tf.image.random_brightness(distorted_image, max_delta=63)
        # 对切割、翻转和随机调整亮度的图片随机调整对比度,对比度调整值取自[lower,upper]
        distorted_image = tf.image.random_contrast(
            distorted_image, lower=0.2, upper=1.8
        )
        # 对切割、翻转、随机调整亮度和对比度的图片进行标准化处理,将RGB像素的值限定在一个范围,可以加速神经网络的训练
        # 标准化处理可以使得不同的特征具有相同的尺度(Scale)。这样,在使用梯度下降法学习参数的时候,不同特征对参数的影响程度就一样了。
        float_image = tf.image.per_image_standardization(distorted_image)
        # 设置切割、翻转、随机调整亮度、对比度和标准化后的图片数据设置尺寸为[24,24,3]
        float_image.set_shape([height, width, 3])
        # 设置标签数据的形状尺寸为[1]
        read_input.label.set_shape([1])
        # 设置队列中最少样本数为每轮样本的40%?
        min_fraction_of_examples_in_queue = 0.4
        min_queue_examples = int(
            NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN * min_fraction_of_examples_in_queue
        )

        print(
            "Filling queue with %d CIFAR images before starting to train. "
            "This will take a few minutes." % min_queue_examples
        )

    return _generate_image_and_label_batch(
        float_image, read_input.label, min_queue_examples, batch_size, shuffle=True
    )


def inputs(eval_d
  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值