python - 统一洗牌 5 GB 的 numpy 数据

标签 python numpy machine-learning shuffle

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

有谁知道生成 360 万(很长)行 numpy 数据的新排列的好方法?我考虑过使用 one of these技术,但是使用 numpy.savetxt 编写这些数组会产生令人难以置信 巨大的文件,而且我不知道如何从标准 npy 以有助于解决此问题的方式归档。

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

最佳答案

到目前为止,在我尝试过的方法中,PyTables 解决方案目前是最好的,其次是使用 numpy 对内存映射数组的支持的解决方案。 PyTables 解决方案并不简单。如果使用打乱的整数数组直接索引 PyTables 数组,速度会非常慢。以下两步过程要快得多:

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

此过程产生的排列与正常的洗牌过程一样随机。如果这看起来不是很明显,考虑一下:(n choose x) * x! = x! * n!/(x! * (n - x)!) = n!/(n - x)!。这种方法足够快,可以为每个训练周期进行加载随机播放。它还能够将数据压缩到约 650M —— 接近 90% 的紧缩。

这是我当前的实现;语料库中的每个训练 block 都会调用一次。 (返回的数组在别处洗牌。)

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) 方法(为每个 block 迭代整个 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))

关于python - 统一洗牌 5 GB 的 numpy 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27049810/

相关文章:

python - 如何在Python中的字典中获取非空值的位置

python - 如何使用numpy调整图像数据的大小?

python - 多个 numpy place 调用会产生奇怪的结果

python - 在使用 kmeans 创建集群时,有没有办法输出每行的失真?

machine-learning - 哪个是对纯输入文本进行分类的最佳 svm 示例?

python - 具有稀疏矩阵的决策树分类器

python - django doctests 没有运行

python - Django 在更新时触发 post_save()

python - 想使用 panda 使其看起来/像 sql 一样工作

python - 如何检查两片 numpy 数组是否相同(或重叠)?