高效的方式部分读取大型numpy文件?

33

我有一个巨大的numpy 3D张量,它存储在我的磁盘上的文件中(通常使用 np.load 读取)。这是一个二进制 .npy 文件。使用 np.load 后,我很快就会使用大部分内存。

幸运的是,在每次运行程序时,我只需要一个巨大张量的特定切片。该切片是固定大小的,并且其维度由外部模块提供。

如何做到最好?我能想到的唯一方法是将此numpy矩阵以某种方式存储到MySQL数据库中。但我肯定有更好/更容易的方法。如果可以帮助我构建我的3D张量文件,我也将很高兴。


如果我的张量本质上是稀疏的,答案是否改变?


文件类型的帮助。 - Denziloe
1
这是一个二进制文件,扩展名为.npy。使用np.save保存。 - martianwars
1
好问题。我不知道有没有这样的工具(但可能会有)。切片是否总是沿着同一轴? - Denziloe
这里是一个开始的地方。张量的维度/数据类型是什么? - Aaron
1个回答

48

正常使用numpy.load,但一定要指定mmap_mode关键字,以便将数组保留在磁盘上,并且仅在访问时加载必要的位到内存中。

mmap_mode:{None,‘r+’,‘r’,‘w+’,‘c’},可选项 如果不是None,则使用给定的模式对文件进行内存映射(有关模式的详细说明,请参见numpy.memmap)。 内存映射数组保留在磁盘上。 但是,它可以像任何ndarray一样被访问和切片。 内存映射对于访问大文件的小片段而不将整个文件读入内存特别有用。

这些模式在numpy.memmap中描述:

mode:{‘r+’, ‘r’, ‘w+’, ‘c’},可选项 以此模式打开文件:‘r’ 仅为读取打开现有文件。‘r+’ 打开现有文件以进行读取和写入操作。‘w+’ 创建或覆盖现有文件以进行读写操作。‘c’ 写时复制:赋值影响内存中的数据,但更改不会保存到磁盘上。 磁盘上的文件是只读的。

*请确保不要使用'w+'模式,因为它会删除文件的内容。


3
很不幸的是,如果您需要读取整个文件,而不是一次性加载所有内容,mmap 并没有太大帮助。例如,如果您创建了一个生成器,它会产生数据块的片段,并希望您的程序永远不会消耗比一个块更多的内存。使用 mmap,随着您请求加载更多的块,使用的内存会不断增长,而不会“释放”您可能已经完成的旧块。 - ely
1
@ely 的说法没错,但使用生成器对于 numpy 来说有点不太恰当,因为更好的方法是利用向量化而非迭代。在这种情况下,我可能会使用 struct 将数据打包到二进制文件中,然后使用 numba jit 编译一个快速函数来读取和分析数据。 - Aaron
1
@ely 如果你能在将数据刷新到磁盘之前,通过'mmap'指定要保留在内存中的缓存大小,那就太好了。 (有人想写一个pull request吗??) - Aaron
1
@Aaron 我认为你混淆了两个不同的概念。使用生成器与向量化没有关联。你可以按批次加载NumPy数据(每个批次由生成器产生),只是为了节省内存,而不是一次性全部加载。但是对于每个批次,您仍然可以使用高度向量化的操作,使用常规的NumPy习惯用法对整个批次应用某些计算。请注意,我并不建议您拥有一个生成器,该生成器从某个NumPy文件中逐个记录地产生数据。相反,尽可能多地记录符合您用例的内存。 - ely
5
例如,在预处理非常大的数据集以将其作为输入馈送到神经网络训练时,您可能无法一次性将整个数据集加载到内存中,但您必须在某个时刻通过内存传递内容的每个部分,并且您可能需要以矢量化的方式执行线性代数、数据清洗等操作,即使是可放入内存的子部分数据也是如此。 - ely
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接