我有一个大型数据集(300,000个样本 x 33,000个特征),当然无法一次性加载进内存。数据以HDF5格式保存。数据值大多为零(稀疏数据)。它们看起来像这样:
Attr1 52 52 52 52 52 52 52 52 ... Attr2 umb umb umb umb umb umb umb umb ... CellID TGC-1 TGG-1 CAG-1 TTC-1 GTG-1 GTA-1 CAA-1 CAC-1 ...Acc Gene ...243485 RP11-.3 0 0 0 0 0 0 0 0 ...237613 FAM138A 0 0 0 0 0 0 0 0 ...186092 OR4F5 0 0 0 0 0 0 0 0 ...238009 RP11-.7 0 0 0 0 0 0 0 0 ...239945 RP11-.8 0 0 0 0 0 0 0 0 ...279457 FO538.2 0 0 0 0 0 0 0 0 ...228463 AP006.2 0 0 0 0 0 0 0 0 ...... ... ... ... ... ... ... ... ... ...
我已经尝试了以下方法,可以在TensorFlow中加载整个数据集(loompy
只是一个在后台使用hdf5的包):
import tensorflow as tfimport numpy as npimport loompy as lpbatch_size = 1000with loompy.connect(filename, 'r') as ds: ds_shape = (batch_size, ds.shape[0]) ds_dtype = ds[0:1, 0:1].dtype labels = np.asarray([ds.ca.CellID, ds.ca.Attr1]).T labels_shape = (batch_size, 1)data_placeholder = tf.placeholder(ds_dtype, ds_shape)labels_placeholder = tf.placeholder(labels[:,1].dtype, labels_shape)dataset = tf.data.Dataset.from_tensor_slices((data_placeholder, labels_placeholder))dataset = dataset.prefetch(batch_size)iterator = dataset.make_initializable_iterator()next_element = iterator.get_next()with tf.Session() as sess: with loompy.connect(filename, 'r') as ds: for i in range(0, ds.shape[1], batch_size): batch = ds[0 : ds_shape[1], i : i + batch_size].T batch_labels = np.asarray([ds.ca.CellID[i : i + batch_size], ds.ca.Attr1[i : i + batch_size]]).T[:,1] sess.run(iterator.initializer, feed_dict = {data_placeholder: batch, labels_placeholder: batch_labels.reshape(batch_size, 1)}) for _ in range(batch_size): print(sess.run(next_element))
输出:
(array([0, 0, 0, …, 0, 0, 0], dtype=int32), array([b’52’], dtype=object))
(array([0, 0, 0, …, 0, 0, 0], dtype=int32), array([b’52’], dtype=object))
…
然而,通过这种方法,我无法将数据分割成训练、测试和评估集。此外,我只能在每个批次内进行洗牌,这通常效果不佳,因为一个批次中的数据通常属于同一类别。
如何处理这种数据,以便能够将它们加载为训练、测试和评估集,并进行洗牌等操作(最好尽可能利用我的TitanX GPU)?
回答:
如果还有人对这个话题感兴趣,以下是我对这个问题所找到的解决方案。最终我选择继续使用Loompy文件格式,因为它与我的工作非常方便(可以查看Loompy的相关信息)。为了将如此大量的信息导入我的模型,我使用了TensorFlow API中tf.data.Dataset
的from_generator()
函数。此外,我创建了一个生成器来按需生成数据。
以下是我的输入函数的示例:
import loompy as lpimport tensorflow as tffrom sklearn.model_selection import train_test_splitmodel_input_name = ""input_size = 10000batch_size = 32epochs = 10# 训练、测试和评估集的输入函数def train_input_fn(): return _input_fn('TRAIN')def test_input_fn(): return _input_fn('TEST')def eval_input_fn(): return _input_fn('EVAL')# 通用输入函数def _input_fn(mode = 'TRAIN'): """ 参数 mode : 'TRAIN', 'TEST', 'EVAL' """ # 一个生成器,用于根据分配给"indices"变量的索引,从给定的文件中生成数据和标签。 # 如果更改标签,请记得更新下面的from_generator()参数,以反映它们的类型。 def gen(): with lp.connect(FILE, 'r') as ds: if ae: for i in indices: yield {model_input_name: ds[:, i]}, ds[:, i] else: for i in indices: yield {model_input_name: ds[:, i]}, ds.ca.x_CellType[i] # 获取训练、测试和评估集的索引 train_idx, test_idx, eval_idx = train_test_set_idx_split(TRAIN_RT, TEST_RT, EVAL_RT) # 检查条件并将相应的集合分配给"indices"变量 if mode == 'TRAIN': indices = train_idx elif mode == 'TEST': indices = test_idx elif mode == 'EVAL': indices = eval_idx else: print("错误的模式选择: ", mode) exit(1) dataset = tf.data.Dataset.from_generator(gen, ({model_input_name: tf.int64}, tf.int64), output_shapes=({model_input_name: [input_size,]}, [])) # 对数据集进行洗牌、分批、映射、预取和重复。 # 如果需要对数据进行一些预处理,请在上面的单元格中创建你的函数,并在map()函数中调用它。 dataset = dataset.shuffle(buffer_size=batch_size*50) dataset = dataset.batch(batch_size) dataset = dataset.map(_reshape_labels) dataset = dataset.map(_int2float) # 映射到你需要的其他函数 dataset = dataset.map( ... ) dataset = dataset.prefetch(2) dataset = dataset.repeat(epochs) iterator = dataset.make_one_shot_iterator() return iterator.get_next()# 获取给定数据集的训练、测试、评估索引def train_test_set_idx_split(train_rt, test_rt, eval_rt): """ 该函数返回给定数据集的训练、测试和评估集的索引。 参数: train_rt: 训练数据集的比例 test_rt: 测试数据集的比例 eval_rt: 评估数据集的比例 返回: train_idx: 训练数据集的索引(来自给定数据集) test_idx: 测试数据集的索引(来自给定数据集) evel_idx: 评估数据集的索引(来自给定数据集) 注意: 只要(test_rt == evel_rt)为真,该函数就能正确工作。 如果需要(test_rt != evel_rt),则需要更复杂的方法。 """ with lp.connect(FILE, 'r') as ds: idx = np.array(range(0, ds.shape[1])) train_idx, test_idx = train_test_split(idx, train_size=train_rt, test_size=test_rt+eval_rt) test_idx, eval_idx = train_test_split(test_idx, train_size=0.5, test_size=0.5) return train_idx, test_idx, eval_idx# 根据需要重塑标签def _reshape_labels(data, labels): return data, tf.reshape(labels, (-1,1))