TF_record 加 dataset 为network 打数据基础

本文详细介绍了如何使用TensorFlow的TFRecord格式存储数据,并利用Dataset API进行高效读取与处理,包括数据转换、批处理、填充及数据集重复等操作。

根据知乎文章 这个 总结而成,方便以后的使用。  主要是为了使用estimator 构建神经网络来处理数

主要流程如下1、将数据处理成tfrecord的形式,2、用tf解析tf_record ,并放到dataset中,3、像操作张量一样来操作dataset。

TensorFlow中层API:Datasets+TFRecord的数据导入

一、使用TFRecord的好处

  1. 只定义一条数据的处理方式,所有数据都按照这个方式来处理。更加简洁。
  2. 将数据操作放到图里面去,省去了feed数据的过程。
  3. 对于大的数据集,可以提速和节约空间。
  4. 对接estimator
  5. 一些小操作很方便 尤其是padding

二、TFRecord 简介

是一个字典类型数据{ “age”:15,“preference”:[1,0,1,0], "学历":{“初中”:0,“大学”:1} } 形势很灵活value的值可以是任何维度的值。

(1)使用方法 将数据写入到TFRecord文件中

  1. 首先建立一个文件读写器:
    writer = tf.python_io.TFRecordWriter('%s.tfrecord' %'test')
  2. 可以写入以下三种的类型
    1. 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(向量)

  3. 将数据一条一条的写入,注意最后的张量的写入方式,因为只接受list类型,所以把张量转化为list,再加一个shape保存信息。
    # 这里我们将会写3个样本,每个样本里有4个feature:标量,向量,矩阵,张量
    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()]))
        # 存储丢失的形状信息(806,806,3)
        features['tensor_shape'] = tf.train.Feature(int64_list = tf.train.Int64List(value=tensors[i].shape))
  4. 转化为相应类型之后 经过下面操作将数据一条一条的写入进去
# 将存有所有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个样本

如此这般之后,我们得到了 TFrecord文件 名字叫 test.tfrecord

三、 使用dataset

  1.     dataset 是我们需要用的所有的数据集,从TFrecord种读取得到
    filenames = ["test.tfrecord", "test.tfrecord"]
    dataset = tf.data.TFRecordDataset(filenames)
  2.    操作dataset,当我们得到从TFrecord中得到的数据后需要解析一下以便使用我们首先构建一个解析函数
    1. #首先创建一个解析函数
      def parse_function(example_proto):
          # 只接受一个输入:example_proto,也就是序列化后的样本tf_serialized
          =====================================================================
          #STEP1 :创建样本解析字典
           
            该字典存放着所有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=dtype('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: 改变形状
          ==================================
          # 转变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 :返回 
          ==================================
      
      return parsed_example
      
      
    2.   执行解析函数 值得注意的是  如果对数据集有特殊的处理可以在解析函数的末尾一起返回。
      new_dataset = dataset.map(parse_function)
  3. 再之后就是使用了
#迭代器
iterator = new_dataset.make_one_shot_iterator()

# 获得下一个样本
next_element = iterator.get_next()

# 创建Session
sess = tf.InteractiveSession()

# 获取
i = 1
while True:
    # 不断的获得下一个样本
  
    # 获得的值直接属于graph的一部分,所以不再需要用feed_dict来喂
    scalar,vector,matrix,tensor = sess.run([next_element['scalar'],
                                                next_element['vector'],
                                                next_element['matrix'],
                                                next_element['tensor']])

shuffle

buffer_size设置成一个大于你数据集中样本数量的值来确保其充分打乱。如果 数据集很大 可以把数据集组成多个tf_record 这样来打乱。抽空写一下具体的操作方法

shuffle_dataset = new_dataset.shuffle(buffer_size=10000)
iterator = shuffle_dataset.make_one_shot_iterator()
next_element = iterator.get_next()

 batch

batch_dataset = shuffle_dataset.batch(4)
iterator = batch_dataset.make_one_shot_iterator()
next_element = iterator.get_next()

padding 

padded_shapes指定了内部数据是如何pad的。

  • rank数要与元数据对应
  • rank中的任何一维被设定成None或-1时都表示将pad到该batch下的最大长度
batch_padding_dataset = new_dataset.padded_batch(4, 
                        padded_shapes={'scalar': [],
                                       'vector': [-1,5],
                                       'matrix': [None,None],
                                       'matrix_shape': [None],
                                       'tensor': [None,None,None],
                                       'tensor_shape': [None]})
iterator = batch_padding_dataset.make_one_shot_iterator()
next_element = iterator.get_next()

Epoch

# num
num_epochs = 2
epoch_dataset = new_dataset.repeat(num_epochs)
iterator = epoch_dataset.make_one_shot_iterator()
next_element = iterator.get_next()
import sys import os sys.path.append('/data/coding') # 添包所在的根目录到 Python 路径中,防止找不到 tensor2robot 和 robotics_transformer import tensorflow as tf import numpy as np import tf_agents from tf_agents.networks import sequential from keras.layers import Dense from tf_agents.agents.dqn import dqn_agent from tf_agents.utils import common from typing import Type from tf_agents.networks import network from tensor2robot.utils import tensorspec_utils from tf_agents.specs import tensor_spec from robotics_transformer import sequence_agent from tf_agents.trajectories import time_step as ts from tensorflow_datasets.core.data_sources import array_record import tensorflow_datasets as tfds from robotics_transformer import transformer_network from robotics_transformer import transformer_network_test_set_up import collections from tf_agents.replay_buffers import reverb_replay_buffer from tf_agents.replay_buffers import reverb_utils import reverb from tf_agents.replay_buffers import tf_uniform_replay_buffer from gin import parse_config_file # 训练集 datasets_path_1 = "./moxing_use/1" # 路径 datasets_path_2 = "./moxing_use/2" # 路径 datasets_path_3 = "./moxing_use/3" # 路径 datasets_path_4 = "./moxing_use/4" # 路径 datasets_path_5 = "./moxing_use/5" # 路径 checkpointer_dir = "/data/coding/media2/model" # 验证集 val_datasets_path_val_1 = "./moxing_val/1" # 路径 file_path = "/data/coding/output.txt" # # 配置文件路径 #gin_config_file = '/data/coding/robotics_transformer/configs/transformer_mixin.gin' # # 解析配置文件 #parse_config_file(gin_config_file) """ 智能体 """ # 设置动作规则,时间步规则,环境规则select vdisk file="C:\Users\明\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc\LocalState\ext4.vhdx" learning_rate = 0.0001 # 设置学习率(RT1官方推荐) action_spec = tensorspec_utils.TensorSpecStruct() action_spec.world_vector = tensor_spec.BoundedTensorSpec( (3,), dtype=tf.float32, minimum=-1., maximum=1., name='world_vector') action_spec.rotation_delta = tensor_spec.BoundedTensorSpec( (3,), dtype=tf.float32, minimum=-np.pi / 2, maximum=np.pi / 2, name='rotation_delta') action_spec.gripper_closedness_action = tensor_spec.BoundedTensorSpec( (1,), dtype=tf.float32, minimum=-1., maximum=1., name='gripper_closedness_action') action_spec.terminate_episode = tensor_spec.BoundedTensorSpec( (2,), dtype=tf.int32, minimum=0, maximum=1, name='terminate_episode') state_spec = tensorspec_utils.TensorSpecStruct() state_spec.image = tensor_spec.BoundedTensorSpec([256, 320, 3], dtype=tf.float32, name='image', minimum=0., maximum=1.) state_spec.natural_language_embedding = tensor_spec.TensorSpec( shape=[512], dtype=tf.float32, name='natural_language_embedding') time_step_spec = ts.time_step_spec(observation_spec=state_spec) # 实例化网络 actor_network = transformer_network.TransformerNetwork global_step = tf.compat.v1.train.get_or_create_global_step() # 训练步数计数器 # 创建代理的函数,须传入网络结构 def create_agent_and_initialize( **kwargs): """Creates the agent and initialize it.""" agent = sequence_agent.SequenceAgent( time_step_spec=time_step_spec, action_spec=action_spec, actor_network=actor_network, actor_optimizer=tf.keras.optimizers.Adam(learning_rate = learning_rate), # 0.0001 train_step_counter=global_step, **kwargs) agent.initialize() return agent agent = create_agent_and_initialize() # 这行代码使用 TensorFlow 的 common.function 将 agent.train 函数包装成一个 TensorFlow 计算图(graph),以便提高代码的执行效率 agent.train = common.function(agent.train) # 这行代码将 agent 对象的训练步数计数器(train_step_counter)初始化为0" agent.train_step_counter.assign(0) """ 保存模型相关 """ my_policy = agent.policy saver = tf_agents.policies.PolicySaver(my_policy, batch_size=None) replay_buffer_capacity = 100 replay_buffer = tf_uniform_replay_buffer.TFUniformReplayBuffer( data_spec=agent.collect_data_spec, batch_size=1, max_length=replay_buffer_capacity) """ 训练 """ # 遍历数据集次数 epoch_num = 50 load_dataset_1 = tf.data.Dataset.load(datasets_path_1) # 载 load_dataset_2 = tf.data.Dataset.load(datasets_path_2) # 载 load_dataset_3 = tf.data.Dataset.load(datasets_path_3) # 载 load_dataset_4 = tf.data.Dataset.load(datasets_path_4) # 载 load_dataset_5 = tf.data.Dataset.load(datasets_path_5) # 载 combined_dataset = load_dataset_1.concatenate(load_dataset_2).concatenate(load_dataset_3).concatenate(load_dataset_4).concatenate(load_dataset_5) combined_dataset = combined_dataset.batch(1, drop_remainder=True) # 一个元素为一个批次,批次的训练不了,显存不够 # combined_dataset = combined_dataset.repeat(epoch_num) # 次遍历数据集 # 使用 prefetch 方法来预数据,这里使用 AUTOTUNE 来自动选择最佳的预取值 combined_dataset = combined_dataset.prefetch(tf.data.experimental.AUTOTUNE) # 定义一个简单的生成器函数 def train_generator(): # 重复遍历数据集指定的 epoch 数 for data in combined_dataset: yield data # # 创建迭代器 load_iterator = iter(combined_dataset) # 计算数据集大小 datasets_num_max = combined_dataset.reduce(0, lambda x, _: x + 1).numpy() # datasets_num = int(datasets_num_max/epoch_num) # print("训练集总数:", datasets_num_max) print("一遍训练集:", datasets_num_max) load_val_dataset_1 = tf.data.Dataset.load(val_datasets_path_val_1) # 载 load_val_dataset = load_val_dataset_1 load_val_dataset = load_val_dataset.batch(1, drop_remainder=True) # 一个元素为一个批次,批次的训练不了,显存不够 # load_val_dataset = load_val_dataset.repeat(epoch_num) # 次遍历数据集 # 使用 prefetch 方法来预数据,这里使用 AUTOTUNE 来自动选择最佳的预取值 load_val_dataset = load_val_dataset.prefetch(tf.data.experimental.AUTOTUNE) # 定义一个简单的生成器函数 def val_generator(): # 重复遍历数据集指定的 epoch 数 for data in load_val_dataset: yield data # # 创建迭代器 load_val_iterator = iter(load_val_dataset) # 计算数据集大小 max_num_val_dataset = load_val_dataset.reduce(0, lambda x, _: x + 1).numpy() # num_val_dataset = int(max_num_val_dataset/epoch_num) # print("验证集总数:", max_num_val_dataset) print("一遍验证集:", max_num_val_dataset) average_training_loss_list = [] # 一个epoch过后每个batch平均的loss,添到此列表 average_val_loss_list = [] # 一个epoch过后验证集每个batch平均的val_loss,添到此列表 single_all_training_batch_num = datasets_num_max # training_break = 0 # val_break = 0 for finish_epoch in range(epoch_num): print(f"epoch = {finish_epoch}---------------------------------------------------------") single_sum_training_loss = 0 # 一个epoch过后loss的总和 # 只遍历数据集一次 # for _ in range(datasets_num): for data in train_generator(): # data = next(load_iterator) # 从迭代器中取一个批次的数据 print(f"{data['element_index']}") # 只取第1帧 single_frame_image = data["image"][:, 0, :, :, :] # (1, 256, 320, 3) single_frame_nle = data["natural_language_embedding"][:, 0, :] # (1, 512) single_frame_world_vector = data["world_vector"][:, 0, :] # (1, 3) single_frame_rotation_delta = data["rotation_delta"][:, 0, :] # (1, 3) single_frame_terminate_episode = data["terminate_episode"][:, 0, :] # (1, 2) single_frame_gripper = tf.expand_dims(data["gripper_closedness_action"][:, 0], axis=-1) # (1, 1) single_frame_step_type = data["step_type"][:, 0] # (1,) single_frame_next_step_type = data["next_step_type"][:, 0] # (1,) single_frame_reward = data["reward"][:, 0] # (1,) single_frame_discount = tf.constant([0.98], shape=(1,), dtype=tf.float32) # (1,) train_observations = { 'image': single_frame_image, 'natural_language_embedding': single_frame_nle, } train_actions = { 'world_vector': single_frame_world_vector, 'rotation_delta': single_frame_rotation_delta, 'terminate_episode': single_frame_terminate_episode, 'gripper_closedness_action': single_frame_gripper, } train_policy_info = () # 训练数据转化为轨迹 trajectory = tf_agents.trajectories.Trajectory( step_type=single_frame_step_type, observation=train_observations, action=train_actions, policy_info=train_policy_info, next_step_type=single_frame_next_step_type, reward=single_frame_reward, discount=single_frame_discount, ) train_loss = agent.train(trajectory).loss step = agent.train_step_counter.numpy() print('step = {0}, loss = {1}'.format(step, train_loss)) single_sum_training_loss+=train_loss print(f"single_sum_training_loss:{single_sum_training_loss} single_all_training_batch_num:{single_all_training_batch_num}") average_training_loss_list.append((single_sum_training_loss/single_all_training_batch_num).numpy()) print(f"average_training_loss_list:{average_training_loss_list}") # 提前结束训练 if(len(average_training_loss_list)>=3): if(average_training_loss_list[-2] > average_training_loss_list[-3] and average_training_loss_list[-1] > average_training_loss_list[-3]): print("训练损失不再下降") #if (training_break ==0): #saver.save('training_break_policy_%d' % global_step) # training_break+=1 #break """ 验证集损失 """ print("验证-------------------------------------------------------------------------") single_sum_val_loss = 0 # 验证集loss的总和 single_all_val_batch_num=max_num_val_dataset # 只遍历数据集一次 for val_data in val_generator(): # val_data = next(load_val_iterator) # 从迭代器中取一个批次的数据 print(f"{val_data['element_index']}") # 只取第1帧 single_frame_image = val_data["image"][:, 0, :, :, :] # (1, 256, 320, 3) single_frame_nle = val_data["natural_language_embedding"][:, 0, :] # (1, 512) single_frame_world_vector = val_data["world_vector"][:, 0, :] # (1, 3) single_frame_rotation_delta = val_data["rotation_delta"][:, 0, :] # (1, 3) single_frame_terminate_episode = val_data["terminate_episode"][:, 0, :] # (1, 2) single_frame_gripper = tf.expand_dims(val_data["gripper_closedness_action"][:, 0], axis=-1) # (1, 1) single_frame_step_type = val_data["step_type"][:, 0] # (1,) single_frame_next_step_type = val_data["next_step_type"][:, 0] # (1,) single_frame_reward = val_data["reward"][:, 0] # (1,) single_frame_discount = tf.constant([0.98], shape=(1,), dtype=tf.float32) # (1,) train_observations = { 'image': single_frame_image, 'natural_language_embedding': single_frame_nle, } train_actions = { 'world_vector': single_frame_world_vector, 'rotation_delta': single_frame_rotation_delta, 'terminate_episode': single_frame_terminate_episode, 'gripper_closedness_action': single_frame_gripper, } train_policy_info = () # 训练数据转化为轨迹 trajectory = tf_agents.trajectories.Trajectory( step_type=single_frame_step_type, observation=train_observations, action=train_actions, policy_info=train_policy_info, next_step_type=single_frame_next_step_type, reward=single_frame_reward, discount=single_frame_discount, ) val_loss = agent._loss(experience = trajectory, weights = None, training = False).loss val_step = agent.train_step_counter.numpy() print('val_step = {0}, val_loss = {1}'.format(val_step, val_loss)) single_sum_val_loss+=val_loss print(f"single_sum_val_loss:{single_sum_val_loss} single_all_val_batch_num:{single_all_val_batch_num}") average_val_loss_list.append((single_sum_val_loss/single_all_val_batch_num).numpy()) print(f"average_val_loss_list:{average_val_loss_list}") # 提前结束训练 if(len(average_val_loss_list)>=2): if(average_val_loss_list[-1] > average_val_loss_list[-2]): print("验证集损失不再下降") # if (val_break ==0): # saver.save('val_break_policy_%d' % global_step) # val_break+=1 # break # 遍历一次数据集保存一次模型 print("过程模型保存!") checkpoint_dir = os.path.join(checkpointer_dir, 'checkpoint_%d' % global_step) train_checkpointer = common.Checkpointer( ckpt_dir=checkpoint_dir, max_to_keep=1, agent=agent, policy=agent.policy, replay_buffer=replay_buffer, global_step=global_step ) # 检查文件夹是否存在,如果不存在则创建 os.makedirs(checkpoint_dir, exist_ok=True) train_checkpointer.save(global_step) saver.save('/data/coding/media2/model_%d' % global_step) # 平均loss写入txt文件 combined_string = f"average_training_loss_list:{average_training_loss_list} average_val_loss_list:{average_val_loss_list}\n" with open(file_path, 'a') as file: file.write(combined_string) """ 保存模型 """ print(f"训练结束! 当前epoch为{finish_epoch}") # # 检查文件夹是否存在,如果不存在则创建 #os.makedirs(checkpoint_dir, exist_ok=True) #train_checkpointer.save(global_step) # 在保存前,build 一下 policy,避免Keras层未build警告 #my_policy.action(dummy_input) #saver.save(saved_path)根据此代码画出简易流程图
最新发布
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值