我有一个大约200 GB的结构化数据集(CSV特征文件)。我使用make_csv_dataset来创建输入管道。这是我的代码
def pack_features_vector(features, labels): """将特征打包成单一数组。""" features = tf.stack(list(features.values()), axis=1) return features, labelsdef main(): defaults=[float()]*len(selected_columns) data_set=tf.data.experimental.make_csv_dataset( file_pattern = "./../path-to-dataset/Train_DS/*/*.csv", column_names=all_columns, # all_columns=["col1,col2,..."] select_columns=selected_columns, # selected_columns= all_columns的一个子集 column_defaults=defaults, label_name="Target", batch_size=1000, num_epochs=20, num_parallel_reads=50, # shuffle_buffer_size=10000, ignore_errors=True) data_set = data_set.map(pack_features_vector) N_VALIDATION = int(1e3) N_TRAIN= int(1e4) BUFFER_SIZE = int(1e4) BATCH_SIZE = 1000 STEPS_PER_EPOCH = N_TRAIN//BATCH_SIZE validate_ds = data_set.take(N_VALIDATION).cache().repeat() train_ds = data_set.skip(N_VALIDATION).take(N_TRAIN).cache().repeat() # validate_ds = validate_ds.batch(BATCH_SIZE) # train_ds = train_ds.batch(BATCH_SIZE) model = tf.keras.Sequential([ layers.Flatten(), layers.Dense(256, activation='elu'), layers.Dense(256, activation='elu'), layers.Dense(128, activation='elu'), layers.Dense(64, activation='elu'), layers.Dense(32, activation='elu'), layers.Dense(1,activation='sigmoid') ]) model.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy(from_logits=True), metrics=['accuracy']) model.fit(train_ds, validation_data=validate_ds, validation_steps=1, steps_per_epoch= 1, epochs=20, verbose=1 )if __name__ == "__main__": main()print('训练完成!')
现在,当我执行这段代码时,它在几分钟内就完成了(我认为没有经过整个训练数据),并出现了以下警告:
W tensorflow/core/kernels/data/cache_dataset_ops.cc:798] 调用迭代器没有完全读取被缓存的数据集。为了避免数据集意外截断,部分缓存的内容将被丢弃。这可能发生在你的输入管道类似于
dataset.cache().take(k).repeat()
的情况下。你应该使用dataset.take(k).cache().repeat()
来代替。
根据这个警告以及训练在几分钟内完成意味着…输入管道配置不正确…请问有人可以指导我,如何纠正这个问题吗?
我的系统GPU是NVIDIA Quadro RTX 6000(计算能力7.5)。
基于其他函数如 experimental.CsvDataset
的解决方案也可以工作。
编辑
通过更改代码避免任何缓存,这个警告消失了,如下所示
validate_ds = data_set.take(N_VALIDATION).repeat() train_ds = data_set.skip(N_VALIDATION).take(N_TRAIN).repeat()
但现在的问题是,我得到了零准确率,即使是在训练数据上。我认为这是输入管道的问题。以下是输出。
编辑2
经过一些努力,我通过使用一个略低级但相似的API,CsvDataset,解决了已知问题。但现在,我得到了准确率=1.00,我认为这不太对。第一轮时是0.95,然后在接下来的19轮中是1.00。这是我的最终代码。
def preprocess(*fields): features=tf.stack(fields[:-1]) # 将Target列的值转换为int以便用于二分类 labels=tf.stack([int(x) for x in fields[-1:]]) return features,labels # x, ydef main(): # selected_columns=["col1,col2,..."] selected_indices=[] for selected_column in selected_columns: index=all_columns.index(selected_column) selected_indices.append(index) print("All_columns长度"+str(len(all_columns))) print("selected_columns长度"+str(len(selected_columns))) print("selected_indices长度"+str(len(selected_indices))) print(selected_indices) defaults=[float()]*(len(selected_columns)) #defaults.append(int()) print("defaults"+str(defaults)) print("defaults长度"+str(len(defaults))) FEATURES = len(selected_columns) - 1 training_csvs = sorted(str(p) for p in pathlib.Path('.').glob("path-to-data/Train_DS/*/*.csv")) testing_csvs = sorted(str(p) for p in pathlib.Path('.').glob("path-to-data/Test_DS/*/*.csv")) training_csvs testing_csvs training_dataset=tf.data.experimental.CsvDataset( training_csvs, record_defaults=defaults, compression_type=None, buffer_size=None, header=True, field_delim=',', # use_quote_delim=True, # na_value="", select_cols=selected_indices ) print(type(training_dataset)) for features in training_dataset.take(1): print("训练样本在映射前") print(features) validate_ds = training_dataset.map(preprocess).take(10).batch(100).repeat() train_ds = training_dataset.map(preprocess).skip(10).take(90).batch(100).repeat() validate_ds train_ds for features,labels in train_ds.take(1): print("训练样本") print(features) print(labels) testing_dataset=tf.data.experimental.CsvDataset( testing_csvs, record_defaults=defaults, compression_type=None, buffer_size=None, header=True, field_delim=',', use_quote_delim=True, na_value="", select_cols=selected_indices ) print(type(testing_dataset)) test_ds = testing_dataset.map(preprocess).batch(100).repeat() test_ds for features,labels in test_ds.take(1): print("测试样本") print(features) print(labels) model = tf.keras.Sequential([ layers.Dense(256,activation='elu'), layers.Dense(128,activation='elu'), layers.Dense(64,activation='elu'), layers.Dense(1,activation='sigmoid') ]) history = model.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy(from_logits=False), metrics=['accuracy']) model.fit(train_ds, validation_data=validate_ds, validation_steps=20, steps_per_epoch= 20, epochs=20, verbose=1 ) loss, accuracy = model.evaluate(test_ds) print("测试准确率", accuracy)if __name__ == "__main__": main()print('训练完成!')
我尝试仅向模型提供一些无用的特征,但仍然得到准确率=1.00或100%。现在哪里出错了?是过拟合等问题吗?
回答:
在代码片段中,你写了
model.fit(train_ds, validation_data=validate_ds, validation_steps=1, steps_per_epoch= 1, epochs=20, verbose=1)
steps_per_epoch= 1
是打字错误吗?如果不是,这意味着你只使用一个批次进行训练,这解释了快速训练和低准确率。validation_steps=1
也是一个问题