tensorflow2.0(tf2.0) 多维numpy.array数据写入tfrecords文件并且从中读取数据参与训练,以及相关参数的说明

tfrecords介绍

说明:tfrecords是一种二进制编码文件,读取效率高且跨平台,最重要的是当训练数据过大时采用直接读取数据是不能的,所以可以用tfrecords来读取数据。

tfrecords原理:将数据放入一个内存队列,在内存队列前还有一个文件名队列,每次从内存队列里读取数据使用,并且数据读入内存与计算是多线程,大大提高了效率。

 

tfrecords制作

这部分全部写入函数 write_tfrecords(filename='pre_data')

#将数据处理为tfrecords
def write_tfrecords(filename='pre_data'):
    pass

训练数据读取

训练数据的文件

获取数据目录,这里的TRAINING_CHUNK_RE是用来匹配训练数据的文件名,获取到这种格式的文件名,因为这个文件夹里还有其他格式的文件

import os
import tensorflow as tf
import numpy as np

#将数据处理为tfrecords
def write_tfrecords(filename='pre_data'):

    #训练目录正则表达式
    TRAINING_CHUNK_RE = re.compile(r"train\d+\.chunk.gz")

    #获取目录
    train_dataset=[os.path.join(filename,fname) for fname in os.listdir(filename) if TRAINING_CHUNK_RE.match(fname)]

tfrecords文件写入 

这里就是写入tfrecords的开头部分,先是打开这个格式的文件,没有会创建一个

#写入tfrecords
    i=0
    with tf.io.TFRecordWriter(os.path.join(filename,'data.tfrecords')) as writer:
        pass

这里加了一个for循环遍历这个目录的每个包,这里有个DataSet.read_data()函数是自己写的用来解压每个包并将数据返回为np.array格式。所以就只用理解为这是为了的到每个包的数据就行了,并且每个包都有4096条数据,每条数据都是三维的。所以train_data就是一个np.array,是一个多维的数组。后面的num_pos就是训练的x值,num_next是y值,并且num_pos的shape是[4096,9,9,28],num_next的shape是[4096,81]

    with tf.io.TFRecordWriter(os.path.join(filename,'data.tfrecords')) as writer:
        for _ in train_dataset:
            print('正在处理第',i,'个包...')
            train_data=DataSet.read_data(_)
            #4096条x与y值
            num_pos=train_data.pos_features
            num_next=train_data.next_moves

但是我做的卷积神经网络输入的shape为[9,9,28],输出的shape为[81],所以保存的tfrecords也要按这个格式,故这里还要加一个for循环来处理每个包,使每条数据切分开,得到n条输入为[9,9,28],输出为[81]的数据。这里的zip()函数就是让两个值进行配对哦,不懂得小伙伴可以百度查一下哦。然后这里就分别得到每个包train_x与train_y。shape分别为[9.9,28],[81]

#写入tfrecords
    i=0
    with tf.io.TFRecordWriter(os.path.join(filename,'data.tfrecords')) as writer:
        for _ in train_dataset:
            print('正在处理第',i,'个包...')
            train_data=DataSet.read_data(_)
            #4096条x与y值
            num_pos=train_data.pos_features
            num_next=train_data.next_moves
            #x与y一一对应,并一一取出
            for train_x,train_y in zip(num_pos,num_next):
                pass

到这步就要先讲下写入tfrecords需要用到的一个特征字典,先上代码。

#制作特征字典
                features = tf.train.Features(
                    feature={
                        "train_x": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_x.astype(np.int32).tostring()])),
                        "train_y": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_y.astype(np.int32).tostring()]))
                    }
                )

↑↑↑上面的features可以理解为写入tfrecords需要的一个参数,tf.train.Features将字典包装成了一个这样参数的数据格式。而feature就是一个字典写出了这个tfrecords存入数据的名字(key值)以及它的格式。这里tf.train提供了3种数据格式,为BytesList,Int64List,FloatList。

简单来说就是存入的数据必须是这三种类型的。而我的数据train_x,train_y的格式是numpy.array。所以这里的关键就是要进行数据处理,这里我选用BytesList方式存入,为什么不用其他的,我之后说明。由于我训练数据全是整数,所以先将它转成np的数据类型np.int32。如果数据类型是float,那么同样你只要转成np提供的一些float格式就行了。然后再用tostring转成字节,注意这里的tostring()转成的是bytes类型的数据。这样feature字典就做好了。

再来说下我的数据都是整数为什么不用Int64List?我试过将train_x用tf.train.Int64List强制转化一下,最后的结果是报错提醒我传入的数据是np.array不能使用Int64List。我没试过FloatList,但我想结果是一样的。

但是不管你的数据是那种格式,都是可以用这种转化字节方法那存储的。

之后就是部分函数剩下部分的完成了。将features对象传入tf.train.Example就行了。之后序列化写入文件,在关闭文件就完成了这个tfrecords文件的建立了。

#写入tfrecords
    i=0
    with tf.io.TFRecordWriter(os.path.join(filename,'data.tfrecords')) as writer:
        for _ in train_dataset:
            print('正在处理第',i,'个包...')
            train_data=DataSet.read_data(_)
            #4096条x与y值
            num_pos=train_data.pos_features
            num_next=train_data.next_moves
            #x与y一一对应,并一一取出
            for train_x,train_y in zip(num_pos,num_next):

                #制作特征字典
                features = tf.train.Features(
                    feature={
                        "train_x": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_x.astype(np.int32).tostring()])),
                        "train_y": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_y.astype(np.int32).tostring()]))
                    }
                )
                example = tf.train.Example(features=features)  # 通过字典建立 Example
                writer.write(example.SerializeToString())  # 将Example序列化并写入 TFRecord 文件
            i=i+1
        writer.close()

 这是我做好的tfrecords文件。

下面是这个建立tfrecords函数完整的代码:

#将数据处理为tfrecords
def write_tfrecords(filename='pre_data'):
    #获取目录
    train_dataset=[os.path.join(filename,fname) for fname in os.listdir(filename) if TRAINING_CHUNK_RE.match(fname)]

    #写入tfrecords
    i=0
    with tf.io.TFRecordWriter(os.path.join(filename,'data.tfrecords')) as writer:
        for _ in train_dataset:
            print('正在处理第',i,'个包...')
            train_data=DataSet.read_data(_)
            #4096条x与y值
            num_pos=train_data.pos_features
            num_next=train_data.next_moves
            #x与y一一对应,并一一取出
            for train_x,train_y in zip(num_pos,num_next):
                #转为bytes
                '''train_x=train_x.astype(np.int64).tostring()
                train_y=train_y.astype(np.int64).tostring()'''

                #制作特征字典
                features = tf.train.Features(
                    feature={
                        "train_x": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_x.astype(np.int32).tostring()])),
                        "train_y": tf.train.Feature(
                            bytes_list=tf.train.BytesList(value=[train_y.astype(np.int32).tostring()]))
                    }
                )
                example = tf.train.Example(features=features)  # 通过字典建立 Example
                writer.write(example.SerializeToString())  # 将Example序列化并写入 TFRecord 文件
            i=i+1
        writer.close()

从tfrecords中读取数据并训练

全部代码放入函数read_tfrecords()。

#读取tfrecords文件
def read_tfrecords():
    pass

首先获得文件目录,再用tf提供的函数来读取tfrecords文件

#读取tfrecords文件
def read_tfrecords():
    #读取文件
    tfrecord_file = 'pre_data/data.tfrecords'
    dataset = tf.data.TFRecordDataset(tfrecord_file)  # 读取 TFRecord 文件

之后用map函数解析数据。这里map需要传入一个自定义函数来解析,相当于把之前的转换在逆进行一次。简单来说就是告诉map函数这个文件该如何解码。这里的read_and_decode就是我写的这个文件的解码方式。下面讲解这个函数。

dataset = dataset.map(decode_tfrecords)  # 解析数据

下面就是这个函数的全部,理解起来很简单。这个example参数就是dataset,看我上面的写法就知道了。

第一步写出这个tfrecords文件的数据是怎样的,所以要写一个特征字典,按这个格式把数据提出来。这里tf.io.FixedLenFeature需要传入两个参数,第一个是数据维度,第二个是类型。由于之前用了tostring()转成了字节码的序列,所以格式为tf.string。同样由于数据np.array被我用类型转换成了字节码,而我之前的数据是int型np.arrray(),故我必须把类型转回去再改维度。所以维度先写成一维就好了,之后再处理。

第二步就是调用tf.io.parse_single_example()来解码了,传入example,还有特征字典。

最后一步的重点就是tf.io.decode_raw()这个函数,这是可以解码字节码的函数,将它转成想要的类型。tf.io还有多种解码函数,大部分都是处理图像的,感兴趣的可以试下。利用这个函数成功将数据提取了出来,最后改成之前的维度就好了。

 

#将tfrecords数据解析出来
def decode_tfrecords(example):
    
    # 定义Feature结构,告诉解码器每个Feature的类型是什么
    feature_description = {                        
        'train_x': tf.io.FixedLenFeature([], tf.string),
        'train_y': tf.io.FixedLenFeature([], tf.string)
    }

    #按照feature_description解码
    feature_dict = tf.io.parse_single_example(example, feature_description)
    #由bytes码转化为tf.int32
    train_x=(tf.io.decode_raw(feature_dict['train_x'],out_type=tf.int32))
    #修改维度为编码前
    train_x=tf.reshape(train_x,[9,9,28])
    
    train_y=tf.io.decode_raw(feature_dict['train_y'],out_type=tf.int32)
    train_y=tf.reshape(train_y,[81])

    return train_x,train_y

下面是这部分函数

#读取tfrecords文件
def read_tfrecords():
    #读取文件
    tfrecord_file = 'pre_data/data.tfrecords'
    dataset = tf.data.TFRecordDataset(tfrecord_file)  # 读取 TFRecord 文件

    dataset = dataset.map(read_and_decode)  # 解析数据

利用tfrecords文件进行模型训练

模型训练的部分代码不多,我就直接放入read_tfrecords()函数了

首先是设定batch,及利用这个队列一次训练放入多少数据,我这个训练数据量太大,所以一次就放入了1000。这个量可以视情况而定。

之后的repeat()函数是这批数据重复,可以指定参数,不写参数是无数次。写这个的目的是当队列里最后一批数据(1000)不足时可以补,不然会出现个报错 “OutOfRangeError: End of sequence”

后面的函数prefetch是可以减少GPU空闲时间,提前加载后面批次的数据,参数是GPU预读取的数据数量,这里调成根据GPU状态动态调整。

 


    dataset_batch=dataset.batch(1000)
  
    #数据重复
    dataset_batch=dataset_batch.repeat()

    #根据GPU动态调整并行调用的数量
    AUTOTUNE = tf.data.experimental.AUTOTUNE
    #预先取数据,使得下一批次或者多个批次提前加载
    dataset_batch = dataset_batch.prefetch(buffer_size=AUTOTUNE)

模型训练

这里就是用我做好的模型进行训练了,其中nb_epoch就是epoch,表示所有数据的训练次数,steps_per_epoch相当于有多少批次的数据从队列传过来,data_size是数据的数量,在整除1000就相当于所有数据跑一次了。用整除也是为了防止之前说的那个报错。后面的参数就是验证集的设置了,就不在阐述了。

#模型训练
model.fit(dataset_batch, nb_epoch=50,steps_per_epoch=data_size//1000,validation_data=(val_x,val_y),validation_steps=4)

 

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值