Tensorflow-tfrecords:将加载的 tfrecords 传递给 model.fit() 时出错

问题描述

我正在尝试加载 tfrecords 以提高训练速度。我的 tfrecord 包含音频文件提取特征及其相应的标签。为了重现相同的结果,我生成一个大小为 (50,50) 和标签 (0 或 1) 的随机 NumPy 数组,并保存为 tfrecord 并读取它们以进行训练。

tensorflow 版本:2.3.0

这是我的示例代码

生成TFrecord

from pathlib import Path
import tensorflow as tf
import numpy as np
import os
import shutil
from tensorflow.keras.optimizers import SGD,Adadelta,Adam,Nadam,RMSprop 
from tensorflow.keras.layers.experimental import preprocessing
from tensorflow.keras.layers import Conv1D,Conv2D,Dense,Flatten,MaxPool1D,MaxPool2D,Dropout,Batchnormalization,Input,MaxPooling1D,Activation,Concatenate,SeparableConv1D
from tensorflow.keras.layers import GlobalAveragePooling1D,GlobalMaxPooling1D,Bidirectional,GRU,LSTM,Timedistributed,ConvLSTM2D,SimpleRNN,AveragePooling1D
from tensorflow.keras.layers import Reshape,Lambda,Dot,softmax,LocallyConnected1D,Layernormalization,add
from tensorflow.keras.models import Model,Sequential,load_model

def _bytes_feature(value):
    """Returns a bytes_list from a string / byte."""
    # If the value is an eager tensor BytesList won't unpack a string from an EagerTensor.
    if isinstance(value,type(tf.constant(0))):
        value = value.numpy() 
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
    """Returns a float_list from a float / double."""
    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
    """Returns an int64_list from a bool / enum / int / uint."""
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def create_example(label,audio_feature):
    feature = {
      'label': _int64_feature(label),'audio_feature': _bytes_feature(audio_feature),}
    # Create a Features message using tf.train.Example.
    example_proto =  tf.train.Example(features=tf.train.Features(feature=feature))

    return example_proto

def serialize_example(audio_feature,label):
    feature = {
      'audio_feature': _bytes_feature(audio_feature),'label': _int64_feature(label),}
    # Create a Features message using tf.train.Example.
    example_proto = tf.train.Example(features=tf.train.Features(feature=feature))
    return example_proto.SerializetoString()

        
def genrate_tf_records(tf_records_dir,length):
    cnt = 1
    if os.path.exists(tf_records_dir):
            shutil.rmtree(tf_records_dir)
            print(f"Removed old directory...({tf_records_dir})")
    print("Creating new tf_record directory...")
    Path(tf_records_dir).mkdir(parents = True,exist_ok = True)

    file_path = os.path.join(tf_records_dir,"tfdata.tfrecord")
    with tf.io.TFRecordWriter(file_path) as writer:
        for fn in range(length):
            audio_feature,label = np.random.randn(50,50),np.random.choice([0,1])
            serialized_example = serialize_example(tf.io.serialize_tensor(audio_feature),label)    
            writer.write(serialized_example)

                
 tf_records_train_dir ="./tf_features_aug_train/"
 tf_records_val_dir ="./tf_features_aug_val/"
 genrate_tf_records(tf_records_train_dir,length=1000)
 genrate_tf_records(tf_records_val_dir,length=100)

读取TFrecord

AUTOTUNE = tf.data.experimental.AUTOTUNE

def _parse_batch(record_batch):
    feature_description = {
        'audio_feature': tf.io.FixedLenFeature((),tf.string),'label': tf.io.FixedLenFeature((),tf.int64),}
    example = tf.io.parse_example(record_batch,feature_description)

    audio_feature = tf.io.parse_tensor(example['audio_feature'],out_type = tf.float64)
    #audio_feature = tf.reshape(audio_feature,(input_shape[0],input_shape[1]))
    label = example['label']
    return audio_feature,label

def get_dataset_from_tfrecords(tfrecords_dir='tfrecords',mode='train',n_epochs=1):
   
    # List all *.tfrecord files for the selected split
    files_ds = tf.data.Dataset.list_files(str(tfrecords_dir)+"*.tfrecord")

    # disregard data order in favor of reading speed
    ignore_order = tf.data.Options()
    ignore_order.experimental_deterministic = False
    files_ds = files_ds.with_options(ignore_order)


    ds = tf.data.TFRecordDataset(files_ds,num_parallel_reads=AUTOTUNE)

    # Parse a batch into a dataset of [audio,label] pairs
    ds = ds.map(lambda x: _parse_batch(x))
    
    for data,label in ds.take(1):
        print(np.shape(data.numpy()))
        print(label.numpy())

    return ds.prefetch(buffer_size=AUTOTUNE)


train_ds = get_dataset_from_tfrecords(tfrecords_dir=tf_records_train_dir,mode='train')
val_ds   = get_dataset_from_tfrecords(tfrecords_dir=tf_records_val_dir,mode='val')

我能够加载保存的 tfrecords 并解析数据。但是当我将 TensorFlow 对象传递给 model.fit() 时,我们得到了一个错误

创建模型

class Model_Creator():
    def getmodel(self,model_name,input_shape,numclass):
        #import pdb;pdb.set_trace()
        if model_name in dir(self) and callable(getattr(self,model_name)):
            print(model_name,'from ACK.py')
            model = getattr(self,model_name)(input_shape,numclass) 
        else:
            print(model_name,'from ign_utils/models_audio_ign.py')
            model =  Model_Creator2().getmodel( model_name,numclass)  
        print('Created ',model_name)
        return model 
    
    def cnn_model(self,numclass):
        datainp = Input(shape=input_shape)
        x=datainp
        #x = Dropout(0.1)(x)
        
        x = Conv1D(filters=32,kernel_size=3,strides=1,activation='relu',padding='same')(x)
        x = Layernormalization(axis=2)(x)
        x = MaxPool1D(strides=2)(x)
        #x = Dropout(0.1)(x)
        
        x = GlobalAveragePooling1D()(x)
        x = Dropout(0.1)(x)
        x = Dense(numclass,activation='softmax')(x)
        output_model = Model(inputs=datainp,outputs=x)
        return output_model
    
   
modelcreator = Model_Creator()
model = modelcreator.getmodel(model_name = 'cnn_model',input_shape=(50,numclass=2)
model.summary()
model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

运行模型

model.fit(train_ds,validation_data = val_ds,epochs=10)

当我运行这个时,我收到错误

ValueError: 维度 0 的切片索引 0 越界。对于'{{节点 strided_slice}} = StridedSlice[索引=DT_INT32,T=DT_INT32, begin_mask=0,ellipsis_mask=0,end_mask=0,new_axis_mask=0,shrink_axis_mask=1](形状,strided_slice/stack,strided_slice/stack_1, strided_slice/stack_2)' 输入形状:[0],[1],[1] 和 计算输入张量:input[1] =,input[2] =,input[3] = .

我不明白为什么会出现这个错误。我可以从 tfrecords 读取和解析数据,但无法将其用于训练(model.fit())。

P.S:我已经编写了易于复制的代码。这两天我一直在坚持。期待一些帮助。提前致谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)