为何64GB内存无法将6.8GB CSV文件全量载入NumPy数组?
问题原因分析
嘿,我来帮你捋捋这个问题——你遇到的核心矛盾根本不是内存不够,而是np.genfromtxt的加载机制在偷偷吃掉大量额外内存:
genfromtxt解析CSV时,会先把整个文件读成一个巨型字符串数组,再逐行逐个字段转换为数值类型。这个过程会产生海量临时字符串对象和中间数组,实际内存峰值可能是最终NumPy数组的2~3倍甚至更多。哪怕你算出来最终数组只需要4.56G,解析时的内存占用可能直接冲到15G以上,要是系统还有其他进程占内存,很容易触发内存不足错误。- 另外Python的垃圾回收有延迟,临时内存没法及时释放,也会进一步加剧内存压力。
- 还有个容易忽略的点:如果你用的是32位Python,哪怕系统有64G内存,它最多也只能用4G左右——不过你有64G内存,大概率是64位版本,但还是可以检查确认下。
解决办法
结合你要用于Keras训练的场景,我给你几个递进的解决方案:
1. 换用更高效的加载工具:Pandas
pandas.read_csv的内存效率和解析速度比np.genfromtxt强太多,它会直接按指定dtype处理数据,临时内存开销极小。示例代码:
import pandas as pd import numpy as np # 用字典指定每个字段的dtype,对应你之前的"i1,i1,f4..."设置 dtype_dict = { 'col0': 'int8', 'col1': 'int8', 'col2': 'float32', # 剩下的128个字段依次对应你的类型设置 } # 加载CSV(如果没有表头,加上header=None参数) df = pd.read_csv('./data.csv', delimiter=';', dtype=dtype_dict, header=None) # 转换为NumPy数组 data = df.to_numpy()
2. 提前转成二进制格式(一劳永逸)
如果之后还要反复用这个数组,建议把它转成NumPy的.npy二进制文件,后续加载时直接读二进制,完全没有解析开销:
# 加载后保存为npy文件 data = df.to_numpy() np.save('./data.npy', data) # 后续直接加载,速度极快,内存占用就是数组本身大小 data = np.load('./data.npy')
3. 分块加载+Keras数据生成器
要是还是碰到内存问题,或者你不想一次性把所有数据塞进内存(毕竟Keras训练本来就是分批次的),可以用分块读取+自定义Keras数据生成器:
import tensorflow as tf from tensorflow.keras.utils import Sequence class CSVDataGenerator(Sequence): def __init__(self, csv_path, delimiter=';', dtype_dict=None, batch_size=32): self.csv_path = csv_path self.delimiter = delimiter self.dtype_dict = dtype_dict self.batch_size = batch_size # 先统计总行数(有表头就减1,没有就去掉-1) with open(csv_path, 'r') as f: self.total_rows = sum(1 for _ in f) - 1 def __len__(self): # 计算总批次 return int(np.ceil(self.total_rows / self.batch_size)) def __getitem__(self, idx): # 读取指定批次的数据 skiprows = idx * self.batch_size + 1 # 有表头就+1,无表头则去掉 df = pd.read_csv( self.csv_path, delimiter=self.delimiter, dtype=self.dtype_dict, skiprows=skiprows, nrows=self.batch_size, header=None ) # 根据你的任务拆分特征和标签,这里示例只返回特征 X = df.to_numpy() y = ... # 替换成你的标签逻辑 return X, y # 使用生成器训练模型 generator = CSVDataGenerator('./data.csv', delimiter=';', dtype_dict=dtype_dict, batch_size=64) model.fit(generator, epochs=10)
这种方式每次只加载一个批次的数据,内存占用极低,完美适配超大规模数据集训练。
4. 最后排查环境问题
- 确认是64位Python:执行
python -c "import sys; print(sys.maxsize > 2**32)",输出True就是64位。 - 清理系统内存:加载前关掉不必要的进程,避免内存被其他程序占用过多。
内容的提问来源于stack exchange,提问作者user4206969
相关产品推荐
相关产品推荐

