将Numpy数组转换成TFRecord文件
在本文中,我们将介绍如何将Numpy数组转换为TFRecord文件。TFRecord是TensorFlow中一种用于高效读写的二进制格式,它将数据序列化成字节流,并在读写过程中避免了不必要的数据转换步骤,因此可以提高数据的读写速度,适合存储大规模的数据文件。
阅读更多:Numpy 教程
TFRecord格式介绍
TFRecord是一种简单的格式,它由一系列二进制记录组成,每个记录包含两个部分:长度和数据。可以将其视为一系列的封装数据块,每个数据块都包含长度和对应的数据。
在TensorFlow中,我们常常将数据序列化成TFRecord格式,并使用tf.data API进行读取和处理。下面是一个TFRecord格式的例子:
import tensorflow as tf
# 创建一条TFRecord记录
example = tf.train.Example(
features=tf.train.Features(
feature={
"x": tf.train.Feature(float_list=tf.train.FloatList(value=[1.0, 2.0, 3.0])),
"y": tf.train.Feature(int64_list=tf.train.Int64List(value=[4, 5, 6])),
"z": tf.train.Feature(bytes_list=tf.train.BytesList(value=[b"abc", b"def"]))
}
)
)
# 将记录序列化成字节流格式
serialized_example = example.SerializeToString()
# 将字节流写入TFRecord文件
with tf.io.TFRecordWriter("example.tfrecord") as writer:
writer.write(serialized_example)
在上面的例子中,我们创建了一条TFRecord记录,包含了三个字段x,y,z。其中x和y分别是含有3个元素的float和int类型的列表,z是含有2个元素的bytes类型的列表。我们将该记录序列化成字节流格式,并将其写入TFRecord文件example.tfrecord中。
将Numpy数组转换为TFRecord文件
现在我们已经了解了TFRecord格式的基本知识,下面我们将以将Numpy数组转换为TFRecord文件为例,介绍具体的实现方法。
将单个Numpy数组转换为TFRecord记录
首先我们考虑如何将单个Numpy数组转换为TFRecord记录。假设我们有一个形状为(h,w,c)的Numpy数组data,其中h,w,c分别表示height、width和channels三个维度的大小。我们希望将该数组转换为一条TFRecord记录,其中包含一个名为data的字段,包含了该数组的所有元素。
我们可以按照如下步骤实现该功能:
import tensorflow as tf
import numpy as np
# 定义一个函数,将单个Numpy数组转换为TFRecord记录
def numpy_to_tfrecord(data, filename):
"""
Args:
data: 一个形状为(h,w,c)的Numpy数组
filename: 要保存的TFRecord文件名
"""
# 将Numpy数组转换为字节流格式
serialized_data = tf.io.serialize_tensor(data)
# 创建TFRecord记录
example = tf.train.Example(features=tf.train.Features(feature={
"data": tf.train.Feature(bytes_list=tf.train.BytesList(value=[serialized_data.numpy()]))
}))
# 写入TFRecord文件
with tf.io.TFRecordWriter(filename) as writer:
writer.write(example.SerializeToString())
# 测试代码
data = np.ones((100, 100, 3))
numpy_to_tfrecord(data, "data.tfrecord")
在上面的代码中,我们定义了一个函数numpy_to_tfrecord,该函数接受一个Numpy数组data和要保存的TFRecord文件名filename作为输入,将该数组转换为一条TFRecord记录并将其写入文件中。具体来说,该函数的实现步骤如下:
- 将Numpy数组
data序列化成字节流格式,并使用tf.train.Feature将其打包成一个序列化的特征。bytes_list类型的特征可以使用tf.train.BytesList来定义,其接受一个字节流列表作为输入。 - 创建一个
tf.train.Example对象,并将序列化后的特征添加到其中。example对象可视为一项TFRecord记录,每个记录应包含一个或多个特征,每个特征应该含有相同的数据类型和长度。 - 创建一个
tf.io.TFRecordWriter对象,并使用其write方法将example对象序列化成字节流,然后将字节流写入文件。
我们通过一个简单的测试代码来测试该函数的功能。在测试代码中,我们创建了一个100 x 100 x 3的全1 Numpy数组,并调用numpy_to_tfrecord函数将其转换为TFRecord文件data.tfrecord。运行该代码后,我们可以在当前目录下找到该文件,并使用tf.data API读取其中的数据。
将多个Numpy数组转换为TFRecord文件
接下来我们考虑如何将多个Numpy数组转换为同一个TFRecord文件。假设我们有n个形状均为(h, w, c)的Numpy数组data_1, data_2, ..., data_n,我们希望将它们全部存储到同一个TFRecord文件data.tfrecord中。
我们可以按照如下步骤实现该功能:
import tensorflow as tf
import numpy as np
# 定义一个函数,将多个Numpy数组转换为同一份TFRecord记录
def numpy_to_tfrecord_multi(data_list, filename):
"""
Args:
data_list: 一个Numpy数组列表
filename: 要保存的TFRecord文件名
"""
# 创建一个TFRecordWriter对象
with tf.io.TFRecordWriter(filename) as writer:
# 遍历每个Numpy数组
for i, data in enumerate(data_list):
# 将Numpy数组序列化为字节流
serialized_data = tf.io.serialize_tensor(data)
# 创建TFRecord记录
example = tf.train.Example(features=tf.train.Features(feature={
"data": tf.train.Feature(bytes_list=tf.train.BytesList(value=[serialized_data.numpy()]))
}))
# 将记录序列化成字符串
serialized_example = example.SerializeToString()
# 向TFRecord文件中写入记录
writer.write(serialized_example)
# 测试代码
data_list = [np.ones((100, 100, 3)), np.zeros((100, 100, 3))]
numpy_to_tfrecord_multi(data_list, "data.tfrecord")
在上面的代码中,我们定义了一个函数numpy_to_tfrecord_multi,该函数接受一个Numpy数组列表data_list和要保存的TFRecord文件名filename作为输入,遍历该列表中的每个Numpy数组,将其转换为一条TFRecord记录并将其写入文件中。具体来说,该函数的实现步骤如下:
- 创建一个
tf.io.TFRecordWriter对象,并将要写入的文件名传递给它。 - 遍历
data_list列表中的每个Numpy数组,将其分别序列化成字节流格式,并使用tf.train.Feature将其打包成一个序列化的特征。 - 创建一个
tf.train.Example对象,并将序列化后的特征添加到其中。该对象将包含一个名为data的特征,其中包含了当前迭代的Numpy数组序列化后的字节流。 - 将
example对象序列化成字节流,并使用tf.io.TFRecordWriter对象将其写入文件中。
我们通过一个简单的测试代码来验证该函数的功能。在测试代码中,我们创建了一个包含两个形状均为(100, 100, 3)的Numpy数组的列表,并调用numpy_to_tfrecord_multi函数将它们保存为同一个TFRecord文件data.tfrecord。运行该代码后,我们可以在当前目录下找到该文件,并使用tf.data API读取其中的数据。
从TFRecord文件中读取数据
最后,我们简单介绍一下如何从TFRecord文件中读取数据。假设我们已经将Numpy数组存储为了TFRecord文件data.tfrecord。现在我们需要从该文件中读取数据并进行解析。
我们可以按照如下步骤实现该功能:
import tensorflow as tf
# 创建一个TFRecordDataset对象
dataset = tf.data.TFRecordDataset("data.tfrecord")
# 定义一个解析函数,将字节流反序列化为Numpy数组
def parse_function(example_proto):
features = {
"data": tf.io.FixedLenFeature([], tf.string)
}
parsed_features = tf.io.parse_single_example(example_proto, features)
decoded_data = tf.io.decode_raw(parsed_features["data"], out_type=tf.float32)
decoded_data = tf.reshape(decoded_data, (100, 100, 3))
return decoded_data
# 对TFRecordDataset应用解析函数
dataset = dataset.map(parse_function)
# 测试代码
for data in dataset:
print(data)
在上面的代码中,我们首先创建了一个tf.data.TFRecordDataset对象,并传入要读取的TFRecord文件名。然后,我们定义一个解析函数parse_function,该函数接受一条TFRecord记录的字节流作为输入,并将其反序列化为Numpy数组。具体来说,该函数的实现步骤如下:
- 定义一个字典
features,将TFRecord记录中包含的所有特征名和数据类型映射起来。 - 使用
tf.io.parse_single_example函数将字节流解析为字典格式,并指定要解析的特征列表为features。 - 使用
tf.io.decode_raw函数将字节流解码为一个Numpy数组。这里我们指定out_type=tf.float32,因为我们预先知道该特征的数据类型为float32。 - 使用
tf.reshape函数将解码后的数组重新整形为(100, 100, 3)的形状。
最后,我们使用map函数对TFRecordDataset应用解析函数,并遍历其中的每条数据,并打印出每个Numpy数组。运行该代码后,我们应该能够看到两个形状均为(100, 100, 3)的Numpy数组,分别为全1和全0数组。
极客教程