Jupyter Notebook代码块运行过慢求助:本地超2小时,Kaggle仅需1分钟
问题分析与优化方案
核心问题定位
你的代码本地运行极慢,主要是两个关键原因:
- 用
df.iterrows()逐行遍历DataFrame,这是Pandas里效率极低的遍历方式,逐行处理会大幅拖慢整体速度。 - 情感计算(尤其是RoBERTa模型)每次只处理单条文本,完全没利用模型的批量推理能力,浪费了并行计算的潜力。
另外Kaggle服务器的CPU性能通常比普通本地机器更强,且环境默认做了优化(比如PyTorch的线程配置),这是速度差异的辅助因素,但代码本身的低效才是主因。
具体优化步骤
1. 替换逐行遍历为批量处理
直接提取整个文本列进行批量操作,比逐行循环快得多。避免用iterrows()这类逐行处理的方式。
2. 改造RoBERTa函数支持批量推理
RoBERTa这类Transformer模型的推理效率在批量处理时会暴涨,单条处理完全浪费了模型的并行计算能力。把你的polarity_Scores_roberta改成支持文本列表输入的版本:
# 示例批量版本(根据你的原函数逻辑调整) def polarity_Scores_roberta_batch(texts): # 批量编码文本 inputs = tokenizer(texts, return_tensors="pt", padding=True, truncation=True, max_length=512) # 批量推理 outputs = model(**inputs) # 批量解析结果(对应原单文本的处理逻辑) results = [] for logit in outputs.logits: # 这里替换成你原函数的计算逻辑 score = {"roberta_neg": logit[0].item(), "roberta_neu": logit[1].item(), "roberta_pos": logit[2].item(), "roberta_compound": ...} results.append(score) return results
3. 重构整个代码流程
改成全批量处理的逻辑,彻底告别逐行循环:
# 批量提取文本和ID text_list = df["Text"].tolist() id_list = df["Id"].tolist() # 批量计算VADER结果 vader_results = [] for text in text_list: vader_res = sia.polarity_scores(text) vader_results.append({f"vader_{k}": v for k, v in vader_res.items()}) # 批量计算RoBERTa结果 roberta_results = polarity_Scores_roberta_batch(text_list) # 合并结果到字典 res = {} for myid, vader, roberta in zip(id_list, vader_results, roberta_results): try: res[myid] = {**vader, **roberta} except Exception: print(f"Broke for id {myid}")
4. 本地环境优化
- 确保PyTorch/TensorFlow是针对本地CPU优化的版本(比如带MKL优化的PyTorch),避免用通用版本。
- 设置PyTorch利用全部CPU核心:
import torch import os torch.set_num_threads(os.cpu_count()) - 关闭不必要的后台程序,确保本地有足够内存,避免内存不足触发磁盘交换(这会让速度暴跌)。
5. 细节优化
- 如果不需要逐行进度,去掉
tqdm的逐行显示,减少IO开销;如果需要进度,改用批量处理的进度条。 - 把异常处理移到批量合并环节,避免逐行捕获异常的额外消耗。
验证效果
优化后的代码在本地应该能大幅缩短运行时间,接近Kaggle的速度。如果还有差距,大概率是本地CPU性能确实不如Kaggle服务器,但代码优化带来的提升会是最显著的。
内容的提问来源于stack exchange,提问作者faraz shoaib
相关产品推荐
相关产品推荐

