python里面Dataset干嘛的_TFRecord + Dataset 进行数据的写入和读取

一、TFRecord数据处理的优点

在数据集较小时,我们会把数据全部加载到内存里方便快速导入,但当数据量超过内存大小时,就只能放在硬盘上来一点点读取,这时就不得不考虑数据的移动、读取、处理等速度。使用TFRecord就是为了提速和节约空间的。

二、将数据写入TFRecord 文件

  • 首先创建一个writer,也就是我们的TFrecord生成器
writer = tf.python_io.TFRecordWriter(record_path)

record_path:生成的TFrecord文件路径

  • 创建存储类型tf_feature

.tfrecord里面写数据的时候首先要先定义写入数据项(feature)的类型。

int64:tf.train.Feature(int64_list = tf.train.Int64List(value=输入))
float32:tf.train.Feature(float_list = tf.train.FloatList(value=输入))
string:tf.train.Feature(bytes_list=tf.train.BytesList(value=输入))

注意:输入必须是list(向量),由于tensorflow feature类型只接受list数据,但是如果数据 类型是矩阵或者张量的时候,有两种解决方法:

转成list类型:将张量fattenlist(也就是向量),再用写入list的方式写入 2、转成string类型:将张量用.tostring()转换成string类型,再用tf.train.Feature(bytes_list=tf.train.BytesList(value=[input.tostring()])) 来存储。
形状信息:不管那种方式都会使数据丢失形状信息,所以在向该样本中写入feature时应该额外加入shape信息作为额外feature。shape信息是int类型,这里我是用原feature名字+'_shape'来指定shape信息的feature名

  • 将 tf_feature 转换成 tf_example 以及进行序列化

将各种Feature创建成一个字典并送入tf.train.Features中,在将其变成一个样本example

tf_example = tf.train.Example(features = tf.train.Features(feature={
                 key1:tf.train.Feature(int64_list = tf.train.Int64List(value=输入))
                 key2:tf.train.Feature(float_list = tf.train.FloatList(value=输入))
                 key3:tf.train.Feature(bytes_list=tf.train.BytesList(value=输入))}))
# 序列化该样本
tf_serialized = tf_example.SerializeToString()
# 关闭文件    
writer.close()
  • 实例
import matplotlib.image as mpimg
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#标量
scalars = np.array([1,2,3],dtype=np.int64)
#向量
vectors = np.array([[0.1,0.1,0.1],
                   [0.2,0.2,0.2],
                   [0.3,0.3,0.3]],dtype=np.float32)
#矩阵
matrices = np.array([np.array((vectors[0],vectors[0])),
                    np.array((vectors[1],vectors[1])),
                    np.array((vectors[2],vectors[2]))],dtype=np.float32)
#张量
img=mpimg.imread('/home/leiwei/桌面/flower.jpeg') 
tensors = np.array([img,img,img])
print(scalars)
print('*'*50)
print(vectors)
print('*'*50)
print(matrices)
print('*'*50)
print(tensors)
writer = tf.python_io.TFRecordWriter('test.tfrecord')
for i in range(3):
    # 创建字典
    features={}
    # 写入标量,类型Int64,由于是标量,所以"value=[scalars[i]]" 变成list
    features['scalar'] = tf.train.Feature(int64_list=tf.train.Int64List(value=[scalars[i]]))
    
    # 写入向量,类型float,本身就是list,所以"value=vectors[i]"没有中括号
    features['vector'] = tf.train.Feature(float_list = tf.train.FloatList(value=vectors[i]))
    
    # 写入矩阵,类型float,本身是矩阵,一种方法是将矩阵flatten成list
    features['matrix'] = tf.train.Feature(float_list = tf.train.FloatList(value=matrices[i].reshape(-1)))
    # 然而矩阵的形状信息(2,3)会丢失,需要存储形状信息,随后可转回原形状
    features['matrix_shape'] = tf.train.Feature(int64_list = tf.train.Int64List(value=matrices[i].shape))
    
    # 写入张量,类型float,本身是三维张量,另一种方法是转变成字符类型存储,随后再转回原类型
    features['tensor']   = tf.train.Feature(bytes_list=tf.train.BytesList(value=[tensors[i].tostring()]))
    # 存储丢失的形状信息
    features['tensor_shape'] = tf.train.Feature(int64_list = tf.train.Int64List(value=tensors[i].shape))
    #将存有所有feature的字典送入tf.train.Features中
    tf_features = tf.train.Features(feature= features)
    # 再将其变成一个样本example
    tf_example = tf.train.Example(features = tf_features)
    # 序列化该样本
    tf_serialized = tf_example.SerializeToString()
    # 写入一个序列化的样本
    writer.write(tf_serialized)
    # 由于上面有循环3次,所以到此我们已经写了3个样本
    # 关闭文件    
writer.close()

83216ddf871498d4d403e8c10edd5cdd.png

三、使用Dataset读取数据

1、从TFRecord文件导入

# 从多个tfrecord文件中导入数据到Dataset类 (这里用两个一样)
filenames = ["test.tfrecord", "test.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)

2、解析feature信息

解析基本就是写入时的逆过程,所以会需要写入时的信息,这里先列出刚才写入时,所有feature的各项信息。

注:用到了pandas,没有的请pip install pandas。

data_info = pd.DataFrame({'name':['scalar','vector','matrix','matrix_shape','tensor','tensor_shape'],
                         'type':[scalars[0].dtype,vectors[0].dtype,matrices[0].dtype,tf.int64, tensors[0].dtype,tf.int64],
                         'shape':[scalars[0].shape,(3,),matrices[0].shape,(len(matrices[0].shape),),tensors[0].shape,(len(tensors[0].shape),)],
                         'isbyte':[False,False,True,False,False,False],
                         'length_type':['fixed','fixed','var','fixed','fixed','fixed']},
                         columns=['name','type','shape','isbyte','length_type','default'])
print(data_info)

26012a3edf942de1fffb9aed711f4e09.png

有6个信息,name, type, shape, isbyte, length_type, default。前3个好懂,这里额外说明后3个:

  • isbyte:是用于记录该feature是否字符化了。
  • default:是当所读的样本中该feature值缺失用什么填补,这里并没有使用,所以全部都是np.NaN
  • length_type:是指示读取向量的方式是否定长,之后详细说明。

注:这里的信息都是在写入时数据的原始信息。但是为了展示某些特性,这里做了改动:

  • 把vector的shape从(3,)改动成了(1,3)
  • 把matrix的length_type改成了var(不定长)

2.1、创建解析函数

def parse_function(example_proto):
    # 只接受一个输入:example_proto,也就是序列化后的样本tf_serialized

Step 1. 创建样本解析字典

该字典存放着所有feature的解析方式,key为feature名,value为feature的解析方式。

解析方式有两种:

  • 定长特征解析:tf.FixedLenFeature(shape, dtype, default_value)
    • shape:可当reshape来用,如vector的shape从(3,)改动成了(1,3)。
    • 注:如果写入的feature使用了.tostring() 其shape就是()
    • dtype:必须是tf.float32, tf.int64, tf.string中的一种。
    • default_value:feature值缺失时所指定的值。
  • 不定长特征解析:tf.VarLenFeature(dtype)
    • 注:可以不明确指定shape,但得到的tensor是SparseTensor。
dics = {# 这里没用default_value,随后的都是None
            'scalar': tf.FixedLenFeature(shape=(), dtype=tf.int64, default_value=None), 
             
            # vector的shape刻意从原本的(3,)指定成(1,3)
            'vector': tf.FixedLenFeature(shape=(1,3), dtype=tf.float32), 
            
            # 使用 VarLenFeature来解析
            'matrix': tf.VarLenFeature(dtype=tf.float32), 
            'matrix_shape': tf.FixedLenFeature(shape=(2,), dtype=tf.int64), 
            
            # tensor在写入时 使用了toString(),shape是()
            # 但这里的type不是tensor的原type,而是字符化后所用的tf.string,随后再回转成原tf.uint8类型
            'tensor': tf.FixedLenFeature(shape=(), dtype=tf.string), 
            'tensor_shape': tf.FixedLenFeature(shape=(3,), dtype=tf.int64)}

Step 2. 解析样本

# 把序列化样本和解析字典送入函数里得到解析的样本
    parsed_example = tf.parse_single_example(example_proto, dics)
 

Step 3. 转变特征

得到的parsed_example也是一个字典,其中每个key是对应feature的名字,value是相应的feature解析值。如果使用了下面两种情况,则还需要对这些值进行转变。其他情况则不用。

  • string类型:tf.decode_raw(parsed_feature, type) 来解码
    • 注:这里type必须要和当初.tostring()化前的一致。如tensor转变前是tf.uint8,这里就需是tf.uint8;转变前是tf.float32,则tf.float32
  • VarLen解析:由于得到的是SparseTensor,所以视情况需要用tf.sparse_tensor_to_dense(SparseTensor)来转变成DenseTensor
# 解码字符
    parsed_example['tensor'] = tf.decode_raw(parsed_example['tensor'], tf.uint8)
    # 稀疏表示 转为 密集表示
    parsed_example['matrix'] = tf.sparse_tensor_to_dense(parsed_example['matrix'])

Step 4. 改变形状

到此为止得到的特征都是向量,需要根据之前存储的shape信息对每个feature进行reshape。

# 转变matrix形状
    parsed_example['matrix'] = tf.reshape(parsed_example['matrix'], parsed_example['matrix_shape'])
    
    # 转变tensor形状
    parsed_example['tensor'] = tf.reshape(parsed_example['tensor'], parsed_example['tensor_shape'])

Step 5. 返回样本

现在样本中的所有feature都被正确设定了。可以根据需求将不同的feature进行拆分合并等处理,得到想要的输入

和标签
,最终在parse_function末尾返回。这里为了展示,我直接返回存有4个特征的字典
# 返回所有feature
    return parsed_example

2.2、执行解析函数

创建好解析函数后,将创建的parse_function送入dataset.map()得到新的数据集

new_dataset = dataset.map(parse_function)

3、创建迭代器

有了解析过的数据集后,接下来就是获取当中的样本。

# 创建获取数据集中样本的迭代器
iterator = new_dataset.make_one_shot_iterator()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值