迄今为止我尝试过的东西中,PyTables解决方案当前是最好的,其次是使用numpy
支持memmapped数组的解决方案。但PyTables解决方案并不简单。如果您使用整数的整数数组来直接索引PyTables数组,它非常缓慢。更快的是以下两步过程:
- 使用布尔索引数组选择数组的一个随机子集。 这必须以块状方式完成。如果将索引数组直接传递给PyTables数组,则速度很慢。
- 预分配一个numpy数组并创建一个将PyTables数组分割成块的切片列表。
- 将每个块完全读取到中,然后使用索引数组的相应块为该块选择正确的值。
- 将选定的值存储在预分配的数组中。
- 然后对预分配的数组进行洗牌。
这个过程产生一个像普通混洗过程一样随机的置换。如果这看起来不明显,请考虑这一点:。这种方法足够快,可以在每个训练周期进行随机洗牌。它也能够将数据压缩至〜650M--几乎达到90%的通货紧缩。
这是我目前的实施;这对于语料库中的每个训练块都被调用一次。 (返回数组别处洗牌。)
def _h5_fast_bool_ix(self, h5_array, ix, read_chunksize=100000):
'''Iterate over an h5 array chunkwise to select a random subset
of the array. `h5_array` should be the array itself; `ix` should
be a boolean index array with as many values as `h5_array` has
rows; and you can optionally set the number of rows to read per
chunk with `read_chunksize` (default is 100000). For some reason
this is much faster than using `ix` to index the array directly.'''
n_chunks = h5_array.shape[0]/read_chunksize
slices = [slice(i * read_chunksize, (i + 1) * read_chunksize)
for i in range(n_chunks)]
a = numpy.empty((ix.sum(), h5_array.shape[1]), dtype=float)
a_start = 0
for sl in slices:
chunk = h5_array[sl][ix[sl]]
a_end = a_start + chunk.shape[0]
a[a_start:a_end] = chunk
a_start = a_end
return a
这有点疯狂,我认为为O(n^2)方法(遍历整个PyTables阵列,每块),在这种情况下速度比的O( n)方法(随机选择一行中的每一行)。但是,嘿,它的作品。稍微间接一点,这可以适应加载任意非随机排列,但是这增加了比它在这里值得的复杂性。
mmap
解决方案仅供参考,对于那些因任何原因需要纯粹numpy解决方案的人员。它在大约25分钟内洗牌所有数据,而上述解决方案在不到一半的时间内管理相同数据。这也应该线性扩展,因为mmap
允许(相对)高效的随机访问。
import numpy
import os
import random
X = []
Y = []
for filename in os.listdir('input'):
X.append(numpy.load(os.path.join('input', filename), mmap_mode='r'))
for filename in os.listdir('output'):
Y.append(numpy.load(os.path.join('output', filename), mmap_mode='r'))
indices = [(chunk, row) for chunk, rows in enumerate(X)
for row in range(rows.shape[0])]
random.shuffle(indices)
newchunks = 50
newchunksize = len(indices)/newchunks
for i in range(0, len(indices), newchunksize):
print i
rows = [X[chunk][row] for chunk, row in indices[i:i + newchunksize]]
numpy.save('X_shuffled_' + str(i), numpy.array(rows))
rows = [Y[chunk][row] for chunk, row in indices[i:i + newchunksize]]
numpy.save('Y_shuffled_' + str(i), numpy.array(rows))
你可以捕鱼yates的行,然后fisher yates的列?既然你只是交换单独的行/列,它不应该滥用你的记忆。如果速度是问题,你可以把它作为C扩展(你需要大量的掉期使它实际上是随机的)。 – 2014-11-20 21:48:59
对不起,我不清楚 - 我不需要洗牌列,只是行。只是没有好的方法将它全部加载到内存中,也不是一些更明显的基于磁盘的方法。 – senderle 2014-11-20 22:25:42