使用Numpy创建超大矩阵遇内存错误,尝试memmap存文件存疑
首先得说,你要创建的这个矩阵规模实在太夸张了,咱们先算笔账:(347101 * 400 * 347101) 个float32元素,每个元素占4字节,总大小大概是 190TB——这已经远远超出了普通服务器甚至专业存储设备的承载能力,这就是你用memmap也失败的核心原因:你的磁盘根本装不下这么大的文件,或者文件系统不支持单个这么大的文件(比如很多默认文件系统对单个文件大小有隐性限制,哪怕理论上限够,实际硬件也跟不上)。
接下来给你几个可行的解决方向:
1. 先检查你的矩阵维度是否合理
这是最常见的问题——几乎没有实际的机器学习/数据处理场景需要两个维度都是347101的3D矩阵。比如你是不是把样本数和词汇表大小/特征维度搞混了?比如常见的编码器输入数据形状应该是 (样本数, 序列长度, 特征维度),其中特征维度一般是几百到几千(比如512、1024),而不是和样本数一样大。如果是维度写错了,修正形状后问题会迎刃而解。
2. 如果维度确实合理,改用稀疏矩阵存储
如果这个矩阵大部分元素是0(比如是one-hot编码、邻接矩阵这类场景),那完全没必要用密集矩阵。用scipy.sparse里的稀疏矩阵格式(比如csr_matrix、csc_matrix),只存储非零元素,能把存储空间压缩几个数量级。示例代码:
from scipy.sparse import csr_matrix import scipy.io # 创建稀疏矩阵(这里假设你有非零元素的坐标和值) rows = [...] # 非零元素的行索引 cols = [...] # 非零元素的列索引 data = [...] # 非零元素的值 sparse_matrix = csr_matrix((data, (rows, cols)), shape=(347101, 347101)) # 若要扩展为3D结构,可考虑存储多个2D稀疏矩阵,或设计分层存储逻辑 # 保存到文件 scipy.io.savemat('sparse_encoder_data.mat', {'encoder_data': sparse_matrix})
3. 分块处理矩阵
如果必须用密集矩阵,那就把大矩阵拆分成多个小的子块,比如按第一个维度切分成多个小批次,每个批次单独存储为memmap或者numpy文件,使用的时候按需加载。示例:
import numpy as np block_size = 1000 # 每个块的样本数,可根据你的存储容量调整 total_samples = 347101 for i in range(0, total_samples, block_size): end_idx = min(i + block_size, total_samples) # 创建当前块的memmap文件 block = np.memmap(f'encoder_block_{i}.memmap', dtype='float32', mode='w+', shape=(end_idx - i, 400, 347101)) # 填充当前块的数据(替换成你的数据填充逻辑) # block[:] = your_data_chunk del block # 释放关联,确保数据写入磁盘
使用的时候,只加载需要的块进行处理即可,不用一次性加载整个大矩阵。
4. 改用HDF5格式存储
HDF5是专门为超大数据集设计的存储格式,支持分块存储、按需读取,比memmap更灵活。用h5py库实现:
import h5py # 创建HDF5文件,设置分块大小(可根据你的数据访问模式调整) with h5py.File('encoder_input_data.h5', 'w') as f: dset = f.create_dataset('encoder_data', shape=(347101, 400, 347101), dtype='float32', chunks=(100, 400, 100)) # 分批次写入数据 for i in range(0, 347101, 100): end_idx = min(i + 100, 347101) dset[i:end_idx] = your_data_chunk # 替换成你的数据块
读取的时候可以直接切片,不需要加载整个文件到内存:
with h5py.File('encoder_input_data.h5', 'r') as f: chunk = f['encoder_data'][0:100] # 只读取前100个样本
最后提醒一下:如果你的业务场景真的需要这么大的密集矩阵,那你得先准备好足够的存储设备(比如PB级的存储集群),否则任何软件层面的方案都救不了。
内容的提问来源于stack exchange,提问作者jameshwart lopez

