这篇文章介绍如何将大量数据存储为TFRecords格式的文件,然后将TFRecords格式的文件按批次处理的方式引入代码中,用来训练你的模型。
本文借鉴了 link中的大部分内容,加上自己的理解和对代码中用到的库的补充说明。
TFRecords 是 Tensorflow standard format ,就是tf标准的数据形式,tf源码中他提供了很多net结构,也就是网络结构,这些网络结构都是你输入数据直接就能跑的,而数据格式多种多样不好统一,tf规定的标准数据格式–TFRecords就可以实现这样一件事,只要你把你的数据转化成这个格式,就可以使用tf定义好的网络结构,然后训练你自己的模型。
原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)):]
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格式
# 这个过程要用到的库
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张,博主电脑配置渣还是跑了挺久的,所以建议如果只想看看效果,熟悉这个流程,可以吧数据集缩减一小,节省时间。
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个批次的图像,并且检查图像对应的标签是不是正确的,也就是说确定在数据转变的这些过程中,是可以恢复原貌的。类似的读文件也有下面几个步骤:
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格式完整的训练案例,可以参考。