如何为1600万条Reddit评论的Pandas数据集高效生成Embedding?
解决大规模数据集Embedding生成的内存问题
一、优化提前生成Embedding的方案
针对1600万条Reddit评论,核心思路是避免全量加载数据到内存,同时优化Embedding生成过程的内存占用:
1. 分块读取数据并增量写入结果
不要用pd.read_csv()全量加载数据集,而是通过chunksize参数分批次读取,每处理完一批就将结果写入磁盘(优先选择Parquet格式,比CSV更节省空间且支持高效存储数组类型),避免内存持续累积。
示例代码:
import pandas as pd import torch import gc from sentence_transformers import SentenceTransformer # 初始化模型,明确指定CPU设备 model = SentenceTransformer( "jinaai/jina-embeddings-v2-base-en", trust_remote_code=True, device="cpu" ) # 分块大小根据内存调整,16G内存建议10000条/块 chunk_size = 10000 output_path = "reddit_embeddings.parquet" first_chunk = True for chunk in pd.read_csv("your_dataset.csv", chunksize=chunk_size): # 提取需要生成Embedding的文本列(假设评论内容列名为"body") texts = chunk["body"].tolist() # 优化Embedding生成流程:禁用梯度+转numpy数组+合理批次大小 with torch.no_grad(): embeddings = model.encode( texts, batch_size=64, # 可根据内存调整为64-128 convert_to_numpy=True, # numpy数组比torch Tensor内存占用更低 show_progress_bar=True ) # 将Embedding添加到当前块 chunk["embedding"] = list(embeddings) # 写入Parquet文件,首次创建,后续追加 if first_chunk: chunk.to_parquet(output_path, index=False) first_chunk = False else: chunk.to_parquet(output_path, index=False, mode="append") # 手动清理临时变量释放内存 del embeddings, texts, chunk gc.collect()
2. 进一步压缩内存开销
- 禁用梯度计算:用
torch.no_grad()包裹编码过程,避免生成不必要的梯度张量,减少内存浪费。 - 控制批次大小:不要盲目调大
batch_size,16G内存下64-128是比较稳妥的范围,过大容易触发内存溢出。 - 清理临时变量:每处理完一个块后,手动删除临时变量并调用
gc.collect(),强制释放未使用的内存。 - 放弃多进程并行:多进程会复制模型和数据,导致内存占用翻倍,反而更容易被系统终止,单进程分块处理是更稳妥的选择。
二、训练阶段实时生成Embedding的可行性
如果提前生成方案始终无法落地,可以考虑训练时实时生成Embedding,但需要明确利弊:
优点
- 无需提前存储巨大的Embedding文件,节省磁盘空间。
- 训练时仅加载当前批次的样本,内存压力极小,不会出现OOM问题。
缺点
- 训练时间大幅增加:每轮训练都要重新生成所有样本的Embedding,1600万条数据+多轮迭代的时间成本极高。
- Embedding无法复用:如果后续需要用Embedding做检索、聚类等其他任务,必须重新生成。
适用场景
仅适合一次性训练且迭代次数极少的场景,或者内存/磁盘空间极度受限的情况。如果需要多次训练或复用Embedding,优先选择提前生成并存储。
内容的提问来源于stack exchange,提问作者Panzer
相关产品推荐
相关产品推荐

