TensorFlow(八)TFRecords使用方法与实例

这篇文章介绍如何将大量数据存储为TFRecords格式的文件,然后将TFRecords格式的文件按批次处理的方式引入代码中,用来训练你的模型。
本文借鉴了 link中的大部分内容,加上自己的理解和对代码中用到的库的补充说明。

TFRecords 是 Tensorflow standard format ,就是tf标准的数据形式,tf源码中他提供了很多net结构,也就是网络结构,这些网络结构都是你输入数据直接就能跑的,而数据格式多种多样不好统一,tf规定的标准数据格式–TFRecords就可以实现这样一件事,只要你把你的数据转化成这个格式,就可以使用tf定义好的网络结构,然后训练你自己的模型。

1. 准备数据

原bolg中使用的数据是DOG VS CAT的数据,可以在download中下载,下载之前需要先注册账号,验证身份还是有点麻烦的,使用自己的数据库也是可以的,只是对于初学者应该把重点放在理解这个过程上,而不是捣鼓数据集,所以建议还是下载一个,不想注册的也可以留下邮箱号我可以发给你。

First, we need to list all images and label them. We give each cat image a label = 0 and each dog image a label = 1. The following code list all images, give them proper labels, and then shuffle the data. We also divide the data set into three train (%60), validation (%20), and test parts (%20).

首先为每张图片对应标签,猫为1狗为0,将匹配好的数据(图像-标签)打乱,按照6/2/2的比例分为训练集,验证集,测试集。

from random import shuffle
import glob

# shuffle the addresses before saving
shuffle_data = True  
cat_dog_train_path = 'Cat vs Dog/train/*.jpg'

# 读取数据
addrs = glob.glob(cat_dog_train_path)
# 打标签
labels = [0 if 'cat' in addr else 1 for addr in addrs] 

# to shuffle data
if shuffle_data:
    c = list(zip(addrs, labels))
    shuffle(c)
    addrs, labels = zip(*c)
    
# Divide the  data into 60% train, 20% validation, and 20% test
train_addrs = addrs[0:int(0.6*len(addrs))]
train_labels = labels[0:int(0.6*len(labels))]
val_addrs = addrs[int(0.6*len(addrs)):int(0.8*len(addrs))]
val_labels = labels[int(0.6*len(addrs)):int(0.8*len(addrs))]
test_addrs = addrs[int(0.8*len(addrs)):]
test_labels = labels[int(0.8*len(labels)):]
  • glob是python处理文件操作的模块,类似于windows的文件搜索,它的主要方法就是glob,该方法返回所有匹配的文件路径列表,这里我们返回了train文件夹下的所有jpg文件。
  • zip是一个打包方法,它会将每个参数中按照对应位置进行打包,也就是说addrs[0]对应labels[0] 一直到最后一个,因为这里两个参数长度是一样的,所以可以完全匹配,如果出现长度不一致的情况,就按照最短的那个为准,舍弃较长那个多余出来的数据。zip(*c)是一个解压的过程。

2. 创建TFRecord文件

First we need to load the image and convert it to the data type (float32 in this example) in which we want to save the data into a TFRecords file. Let’s write a function which take an image address, load, resize, and return the image in proper data type:

我们上面得到的数据集中的图片都只是图片地址,模型需要的数据是一定格式的图片数据,所以我们需要先获取图片,然后再对图片的格式进行调整。

def load_image(addr):
    # 图片格式 (224, 224)
    # cv2读取到的图片是BGR格式 转化为RGB
    img = cv2.imread(addr)
    img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img = img.astype(np.float32)
    return img

关于BGR和RGB的区别,这里简单提一句,这两种图像存储方式本质上是一样的,只是数据保存的顺序不一样,RGB是按R(8位),G(8位),B(8位)保存的数据,而BGR是按B(8位),G(8位),R(8位)保存的数据 。

Before we can store the data into a TFRecords file, we should stuff it in a protocol buffer called Example. Then, we serialize the protocol buffer to a string and write it to a TFRecords file. Example protocol buffer contains Features. Feature is a protocol to describe the data and could have three types: bytes, float, and int64. In summary, to store your data you need to follow these steps:

将数据存储到tfrecords文件前,需要将数据封装到一个叫 Example的协议缓冲区(protocol buffer)中,然后将Example序列化为字符串,最后保存到TFrecords文件中。Feature是一种描述数据的协议,有三种:bytes,float和int64。

按照以下几个步骤就可以将你的数据转化为TFRecords格式

  1. 打开一个 TFRecords file 使用 tf.python_io.TFRecordWriter
  2. 将你的数据格式转化为符合Feature协议的格式,也就是上面三种,使用tf.train.Int64List, tf.train.BytesList, or tf.train.FloatList方法
  3. 使用 tf.train.Feature创建一个Feature,将第二步得到的数据绑定到这个Feayure上
  4. 使用tf.train.Example创建一个 Example protocol buffer,将Feature绑定到Example上
  5. 将这个Example序列化为字符串 example.SerializeToString()
  6. 使用 writer.write将字符串写入TFRecord文件
# 这个过程要用到的库
import tensorflow as tf
import sys
import cv2
import numpy as np

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]))

import tensorflow as tf

# TFRecords文件的保存地址
train_filename = 'Cat vs Dog/train.tfrecords' 
# 第一步 打开文件
writer = tf.python_io.TFRecordWriter(train_filename)

for i in range(len(train_addrs)):
    # 每保存1000张输出一次结果
    if not i % 1000:
        print( 'Train data: {}/{}'.format(i, len(train_addrs)))
        sys.stdout.flush()
        
    # 载入图片和标签
    img = load_image(train_addrs[i])
    label = train_labels[i]
    
    # 第二三步,创建Feature的时候使用的参数就是第二步转化的结果
    feature = {'train/label': _int64_feature(label),
               'train/image': _bytes_feature(tf.compat.as_bytes(img.tostring()))}
    
    # 第四步 创建一个Example
    example = tf.train.Example(features=tf.train.Features(feature=feature))
   
    # 第五六步 序列化为字符串 然后写入
    writer.write(example.SerializeToString())

# 关闭io  刷新缓冲区
writer.close()
sys.stdout.flush()
    

我用的是jupyter notebook ,运行上面的代码后就会显示完成记录,在Cat vs Dog文件夹下面会有train.tfrecords文件,因为图片数量1w5张,博主电脑配置渣还是跑了挺久的,所以建议如果只想看看效果,熟悉这个流程,可以吧数据集缩减一小,节省时间。

读取TFRecords文件

It’s time to learn how to read data from the TFRecords file. To do so, we load the data from the train data in batchs of an arbitrary size and plot images of the 5 batchs. We also check the label of each image. To read from files in tensorflow, you need to do the following steps:

要读取TFRecords文件,我们以任意设定的批次大小去加载训练集中的数据,然后绘制5个批次的图像,并且检查图像对应的标签是不是正确的,也就是说确定在数据转变的这些过程中,是可以恢复原貌的。类似的读文件也有下面几个步骤:

  1. 首先创建一个list,里面的元素是你tfrecord文件名,这里我们只有一个文件 [data_path]
  2. 创建一个队列(FIFO)存放这些名字,使用tf.train.string_input_producer 这个函数,它有一些可选的参数,比如num_epochs ,表示每次遍历获取的数据量,和是否选择打乱数据,shuffle,默认是True
  3. 使用reader = tf.TFRecordReader()定义一个reader, reader.read(filename_queue)会返回下一个record
  4. 定义一个decoder,它使用 tf.parse_single_example 解码第三步中reader读到的数据,完成代码是features = tf.parse_single_example(serialized_example, features=feature)
    其中serialized_example就是reader读到的之前序列化好的example
  5. 转化数据格式,将字符串转化为数字,tf.decode_raw(bytes, out_type) .
  6. 将图片数据重新塑型 image = tf.reshape(image, [224, 224, 3])
  7. Preprocessing,这个过程就是处理数据,意思是如果你想对数据进行归一化或者均值化处理,将数据resize以后就可以处理数据了
  8. 创建另一个队列,使用 tf.train.shuffle_batch([image, label], batch_size=10, capacity=30, num_threads=1, min_after_dequeue=10) ,这个队列是用来批处理example中的数据的,capacity是队列最大值,min_after_dequeue 是出列后队列的最小值,num_threads 是进行处理的线程数量,使用多个线程速度会更快。
import matplotlib.pyplot as plt

# 第一步 tfrecord文件路径
data_path = 'Cat vs Dog/train.tfrecords'  

with tf.Session() as sess:
    
    # 第二步 文件名队列
    filename_queue = tf.train.string_input_producer([data_path], num_epochs=1)
    
    # 第三步 定义reader 获取serialized_example
    reader = tf.TFRecordReader()
    _, serialized_example = reader.read(filename_queue)
    
    # 第四步 解码
    
    #这里的feature和之前定义的feature是对应的
    feature = {'train/image': tf.FixedLenFeature([], tf.string),
               'train/label': tf.FixedLenFeature([], tf.int64)}
    
    features = tf.parse_single_example(serialized_example, features=feature)
    
    # 第五步 将字符串还原为数字
    image = tf.decode_raw(features['train/image'], tf.float32)
    label = tf.cast(features['train/label'], tf.int32)
    
    # 第六步 还原图片
    image = tf.reshape(image, [224, 224, 3])
    
    # 第七步 如果要处理数据的话
    
    # 第八步 得到批处理数据
    images, labels = tf.train.shuffle_batch([image, label], batch_size=10, capacity=30, num_threads=1, min_after_dequeue=10)

大致流程简化就是这样,正反操作,第一次接触可能非常云里雾里,把它当做一个工具,多用几次就会熟练了,也会更好的理解它的整个流程。后面我会写一个使用TFRecords格式完整的训练案例,可以参考。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Bazingaea/article/details/85009701