统一调整5千兆字节的numpy数据

sen*_*rle 7 python numpy shuffle machine-learning

我正在训练一个神经网络,其中大约有5千兆字节的数据存储为numpy数组.数据被分成100000行的块,我以随机顺序对所有块进行了六个周期的训练.不幸的是,网络已经开始过度适应.我认为它仍然有能力更紧密地拟合数据; 我怀疑每个块内的内部规则开始相互矛盾,我需要更彻底地调整数据,以便它可以训练不同的组合.我想在获得更多训练数据之前尝试这个.

有谁知道一个很好的方法来生成360万(非常长)的numpy数据行的新排列?我想过使用这些技术之一,但是使用这些数据编写numpy.savetxt产生令人难以置信的巨大文件,我无法告诉如何以npy有助于解决此问题的方式处理标准文件中的各个行.

现在,我最好的想法是在数据中创建配对索引的排列(c, r),其中c选择一个块并r从该块中选择一行.我可以将每一行存储在一个新的预分配数组中,然后保存它.但我想知道是否有一个不那么可怕的I/O限制解决方案.是否有一些原则性的方法可以将随机对的块组合在一起,直到你得到一个统计上独立于起始排列的排列?

sen*_*rle 7

在我迄今为止尝试过的事情中,PyTables解决方案目前是最好的,其次是使用numpy对memmapped数组的支持的解决方案.但PyTables解决方案并不简单.如果你使用一个混洗的整数数组来直接索引PyTables数组,那么速度非常慢.以下两步过程要快得多:

  1. 使用布尔索引数组选择数组的随机子集.这必须以一种方式完成.如果将索引数组直接传递给PyTables数组,则速度很慢.
    • 预分配一个numpy数组并创建一个切片列表,将PyTables数组拆分为块.
    • 将每个块完全读入内存,然后使用索引数组的相应块为该块选择正确的值.
    • 将选定的值存储在预分配的数组中.
  2. 然后随机播放预分配的数组.

这个过程产生的排列随着正常的混洗过程一样随机.如果这看起来不明显,请考虑一下:(n choose x) * x! = x! * n! / (x! * (n - x)!) = n! / (n - x)!.这种方法足够快,可以为每个训练周期进行随机播放.它还能够将数据压缩到约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
Run Code Online (Sandbox Code Playgroud)

对于我来说,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))
Run Code Online (Sandbox Code Playgroud)