使用Word2Vec处理百万级句子时内存溢出问题求助
解决Word2Vec句子嵌入的内存瓶颈问题
嗨,我来帮你搞定这个内存不够的问题——完全不用急着上云服务,通过几个针对性的代码优化,在你的16GB本地机器上就能处理完120万条句子!
核心问题分析
你现在的代码把所有120万条500维向量都存在l_encodings列表里,Python列表的每个浮点数都是独立对象,加上列表本身的存储开销,实际内存占用会比纯计算的字节数大好几倍。咱们的优化思路就是避免一次性把所有数据放在内存里,同时减少中间过程的内存浪费。
具体优化方案
1. 用生成器+逐行写入文件替代内存存储
最直接的办法是不把所有向量存在列表里,而是生成一个向量就立刻写入磁盘文件(比如文本或二进制文件),这样内存里永远只保留当前处理的那一个向量。
修改后的代码示例:
import time def generate_encodings(model, l_vocab): prev_time = time.time() for k, sentence in enumerate(l_vocab): if k % 100000 == 0: print(f"Processed {k} sentences") print(f"Time elapsed: {time.time() - prev_time:.2f}s") prev_time = time.time() # 预分配500长度的列表,避免多次拼接 l_array = [0.0] * 500 for i, word in enumerate(sentence[:5]): # 只取前5个词,防止超出长度 embedding = model[word].tolist() # 把词嵌入填充到对应位置 start_idx = i * 100 l_array[start_idx:start_idx+100] = embedding yield l_array # 把生成的向量写入文件 with open("sentence_encodings.txt", "w") as f: for vec in generate_encodings(model, l_vocab): # 把向量转成字符串写入,每行一个向量 f.write(' '.join(map(str, vec)) + '\n')
2. 避免不必要的列表拼接
你原来的代码里用l_array += l_array2来拼接向量,每次拼接都会创建新的列表对象,产生大量内存碎片。上面的代码用预分配固定长度列表+切片赋值的方式,完全避免了这个问题,内存开销会小很多。
3. 用Numpy内存映射文件(memmap)处理
如果后续需要用Numpy数组处理这些向量,可以用numpy.memmap,它会把磁盘文件当作内存数组来操作,不用一次性加载所有数据到内存:
import numpy as np # 创建一个内存映射的Numpy数组,存储在磁盘上 output_shape = (len(l_vocab), 500) memmap_arr = np.memmap("sentence_encodings.npy", dtype='float32', mode='w+', shape=output_shape) prev_time = time.time() for k, sentence in enumerate(l_vocab): if k % 100000 == 0: print(f"Processed {k} sentences") print(f"Time elapsed: {time.time() - prev_time:.2f}s") prev_time = time.time() # 直接填充memmap数组 for i, word in enumerate(sentence[:5]): embedding = model[word] # 直接用Numpy数组,不用转成列表 start_idx = i * 100 memmap_arr[k, start_idx:start_idx+100] = embedding # 写入磁盘并关闭 del memmap_arr
这里用float32代替默认的float64,还能再把内存/磁盘占用减半,完全不影响大多数机器学习任务的精度。
为什么这些优化有效?
- 生成器/逐行写入:内存里只保留当前处理的1个500维向量,内存占用几乎可以忽略不计。
- 预分配列表+切片赋值:避免了拼接产生的临时列表,减少内存碎片和对象开销。
- Numpy memmap:把磁盘当作扩展内存,120万条500维的float32向量只需要2.4GB磁盘空间,完全在你的机器承受范围内。
总结
这些优化后,你的16GB内存完全足够处理120万条句子,根本不需要云服务。优先试试生成器+写入文件的方案,操作最简单;如果后续需要Numpy数组,就用memmap的方式。
内容的提问来源于stack exchange,提问作者A555h55
相关产品推荐
相关产品推荐

