将压缩后的数组完全从磁盘加载到内存(同样)压缩的智能方法是什么?

2024-05-28 22:20:17 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在试验存储在磁盘上的三维zarr阵列:

Name: /data
Type: zarr.core.Array
Data type: int16
Shape: (102174, 1100, 900)
Chunk shape: (12, 220, 180)
Order: C
Read-only: True
Compressor: Blosc(cname='zstd', clevel=3, shuffle=BITSHUFFLE, blocksize=0)
Store type: zarr.storage.DirectoryStore
No. bytes: 202304520000 (188.4G)
No. bytes stored: 12224487305 (11.4G)
Storage ratio: 16.5
Chunks initialized: 212875/212875

据我所知,zarr数组也可以驻留在内存压缩中,就像它们在磁盘上一样。所以我想为什么不尝试将整个东西加载到内存为32gbyte的机器上的RAM中。压缩,数据集将需要约50%的RAM。未压缩时,它需要的内存大约是可用内存的6倍。你知道吗

准备工作:

import os
import zarr
from numcodecs import Blosc
import tqdm
zpath = '...' # path to zarr data folder

disk_array = zarr.open(zpath, mode = 'r')['data']

c = Blosc(cname = 'zstd', clevel=3, shuffle = Blosc.BITSHUFFLE)
memory_array = zarr.zeros(
    disk_array.shape, chunks = disk_array.chunks,
    dtype = disk_array.dtype, compressor = c
    )

以下实验几乎立即失败,出现内存不足错误:

memory_array[:, :, :] = disk_array[:, :, :]

据我所知,disk_array[:, :, :]将尝试创建一个未压缩的全尺寸numpy数组,这显然会失败。你知道吗

第二次尝试,虽然很慢,但很痛苦:

chunk_lines = disk_array.chunks[0]
chunk_number = disk_array.shape[0] // disk_array.chunks[0]
chunk_remain = disk_array.shape[0] % disk_array.chunks[0] # unhandled ...
for chunk in tqdm.trange(chunk_number):
    chunk_slice = slice(chunk * chunk_lines, (chunk + 1) * chunk_lines)
    memory_array[chunk_slice, :, :] = disk_array[chunk_slice, :, :]

在这里,我试图一次读取一定数量的块,并将它们放入内存数组中。 它可以工作,但比最初将此内容写入磁盘所需的速度慢6到7倍。编辑:是的,它仍然很慢,但这6到7倍的速度是由于磁盘问题造成的。你知道吗

实现这一目标的智能快速方法是什么?我猜,除了没有使用正确的方法,我的块也可能太小-但我不确定。你知道吗

编辑:磁盘阵列和内存阵列的形状、块大小和压缩应该是相同的。因此,在我上面的示例中,应该可以消除解压缩压缩过程。你知道吗

我找到了zarr.convenience.copy,但它被标记为experimental feature,可能会进一步更改。你知道吗


Related issue on GitHub


Tags: 内存importdataslice数组arraychunks磁盘
2条回答

您可以尝试使用^{},它有一个.make_mapper()方法,您可以使用该方法生成zarr所期望的对象类型。你知道吗

然而,这真的只是一句格言路径:io.BytesIO如果你愿意,你可以自己做。你知道吗

今天有几种方法可以解决这个问题。你知道吗

  1. 使用^{}在内存中缓存(一些)压缩数据。你知道吗
  2. 将底层存储强制为dict,并将其用作存储。你知道吗

如果您只希望内存中有一些常用数据,那么第一个选项可能是合适的。当然,您可以配置加载到内存中的量。所以这可能是整个阵列。这只会发生在按需数据的情况下,这可能对您有用。你知道吗

第二个选项只是通过从磁盘中提取所有压缩数据来创建阵列的新内存副本。一个缺点是,如果你打算写回磁盘,这将是你需要手动做的事情,但它不是太难。^{} method对于促进不同存储之间的数据复制非常方便。你知道吗

相关问题 更多 >

    热门问题