You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化70000×70000大张量的存储与快速访问?

大张量高效存储与访问优化方案

问题背景

处理约1000个规格为70000×70000的大张量时,采用h5py分块存储仍存在存储空间占用过高、读取耗时较长的问题,原实现代码如下:

import numpy as np
import h5py
from scipy.spatial.distance import cdist

def pairwise_distances_chunks(X, chunk_size=1000):
    chunked_X = np.array_split(X, X.shape[0] // chunk_size + 1)
    for i, X_chunk in enumerate(chunked_X):
        dists = cdist(X_chunk, X, metric="euclidean")
        with h5py.File(f"cdist_chunk{i}.h5", "w") as f:
            f.create_dataset("cdist", data=dists)

train_vec = np.random.randn(70000, 1000)
pairwise_distances_chunks(train_vec[:, [0]])
with h5py.File("/content/cdist_chunk0.h5", "r") as f:
    dset = f["cdist"]
    dists = dset[:]
    print(dset[:100])

优化建议与方案

1. 优化h5py存储配置

  • 合并文件并调整分块大小:避免创建大量小HDF5文件,改用单个文件存储所有分块,设置与内存匹配的分块尺寸(如(1000, 1000)),减少IO开销。
  • 启用高效压缩:创建数据集时指定压缩算法,优先选择Blosc(兼顾压缩速度和比率)或LZF(快速压缩),示例:
    with h5py.File("cdist_all.h5", "w") as f:
        dset = f.create_dataset("cdist", shape=(70000,70000), dtype='float32', 
                                chunks=(1000,1000), compression='blosc', compression_opts=9)
        # 分块写入数据
        chunked_X = np.array_split(train_vec[:, [0]], train_vec.shape[0]//1000 +1)
        for i, X_chunk in enumerate(chunked_X):
            dists = cdist(X_chunk, train_vec[:, [0]], metric="euclidean").astype('float32')
            dset[i*1000:(i+1)*1000, :] = dists
    
  • 减少文件IO次数:单次打开文件完成所有分块写入,避免循环内反复打开关闭文件。

2. 切换更高效的存储格式

  • Zarr:专为多维数组设计,支持并行读写、多种压缩算法,比HDF5更适合云环境和大数组随机访问,示例:
    import zarr
    from numcodecs import Blosc
    
    # 创建Zarr数组
    zarr_arr = zarr.open("cdist.zarr", shape=(70000,70000), dtype='float32', 
                        chunks=(1000,1000), compressor=Blosc(cname='zstd', clevel=5))
    # 分块写入
    chunked_X = np.array_split(train_vec[:, [0]], train_vec.shape[0]//1000 +1)
    for i, X_chunk in enumerate(chunked_X):
        dists = cdist(X_chunk, train_vec[:, [0]], metric="euclidean").astype('float32')
        zarr_arr[i*1000:(i+1)*1000, :] = dists
    # 读取指定块
    chunk_data = zarr_arr[:100, :]
    
  • TileDB:针对多维数组优化了随机访问和并行处理,支持稀疏/稠密存储,适合频繁随机读取场景。
  • Parquet:列式存储格式,压缩率极高,适合按行/列批量访问,通过PyArrow或FastParquet操作。

3. 数据类型与稀疏性优化

  • 降低精度:将float64转为float32(存储空间减半)或float16(存储空间减至1/4),多数距离计算场景精度足够。
  • 稀疏存储:若张量存在大量重复值或零值,使用稀疏矩阵存储(如scipy.sparse.csr_matrix),保存为.npz格式,或用TileDB/Zarr的稀疏模式。

4. 计算与存储联动优化

  • 按需计算替代预存储:若无需永久保存所有张量,可在需要时通过Dask并行计算对应块,避免存储开销:
    import dask.array as da
    from dask.diagnostics import ProgressBar
    
    X_da = da.from_array(train_vec[:, [0]], chunks=(1000,1))
    dists_da = da.map_blocks(lambda x: cdist(x, train_vec[:, [0]], metric="euclidean"), 
                             X_da, dtype='float32')
    # 计算并读取指定块
    with ProgressBar():
        chunk_data = dists_da[:100, :].compute()
    
  • 增量缓存:仅存储高频访问的张量块,低频块按需计算,结合本地缓存或Redis实现。

5. 硬件与系统优化

  • 使用SSD存储:SSD的随机读写速度远高于HDD,可大幅提升大张量读取效率。
  • 内存映射:利用numpy的memmap或h5py的内存映射模式,让数据部分加载至内存,减少内存占用:
    # numpy memmap示例
    memmap_arr = np.memmap("cdist.dat", dtype='float32', mode='r', shape=(70000,70000))
    chunk_data = memmap_arr[:100, :]
    
  • 并行读写:开启多线程/多进程读写,利用h5py的SWMR(Single Writer Multiple Reader)模式或Zarr的并行支持。

内容的提问来源于stack exchange,提问作者amkyp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 09:05:39