
本文详解 slurm 集群中 python 脚本长时间无响应(如 `dataset.map()` 卡住)却本地正常运行的问题,核心原因常为环境不一致(特别是 numpy/scipy 版本冲突、hugging face 缓存路径、并行配置差异),提供可落地的诊断与修复方案。
在 Slurm 集群上运行 Hugging Face 相关数据处理脚本时,出现“本地 2 分钟跑完,Slurm 运行数小时无进展且被超时终止”的现象,根本原因通常不是代码逻辑错误,而是运行环境的静默不兼容。从你提供的日志可见,关键线索已浮现:
Slurm 日志中明确提示:A NumPy version >=1.16.5 and red for this version of SciPy (detected version 1.24.4)
→ 这是 严重版本不匹配警告:SciPy 依赖特定范围的 NumPy ABI,越界版本(如 1.24.4)可能导致底层 C 扩展崩溃、死锁或无限等待,尤其在 datasets.map() 这类涉及多进程/共享内存的操作中极易触发。同时,tokenizer 类型警告(BertTokenizer vs RobertaTokenizerFast)虽不影响执行,但暗示模型/分词器路径可能混用,增加不确定性。
? 快速诊断步骤(务必在 Slurm 计算节点上执行)
# 1. 检查 Python 及关键库版本(对比本地)
python --version
python -c "import numpy; print('numpy:', numpy.__version__)"
python -c "import scipy; print('scipy:', scipy.__version__)"
python -c "import transformers; print('transformers:', transformers.__version__)"
python -c "import datasets; print('datasets:', datasets.__version__)"
# 2. 检查是否启用多进程(Slurm 默认可能限制 fork 或共享内存)
python -c "import os; print('OMP_NUM_THREADS:', os.environ.get('OMP_NUM_THREADS', 'not set'))"
python -c "import os; print('TOKENIZERS_PARALLELISM:', os.environ.get('TOKENIZERS_PARALLELISM', 'not set'))"✅ 标准化环境:推荐使用 Conda 精确复现
不要依赖系统 Python 或全局 pip 安装。在 Slurm 集群上创建隔离、可重现的 Conda 环境:
# 在计算节点(非登录节点)创建环境(示例:py38v1-env)
conda create -n py38v1-env python=3.8.18
conda activate py38v1-env
# 严格指定兼容版本(根据你的 transformers==4.33.2 推荐)
pip install "numpy>=1.21.0,<1.23.0" \
"scipy>=1.7.0,<1.10.0" \
"transformers==4.33.2" \
"datasets==2.14.6" \
"tokenizers==0.13.3" \
"torch==2.0.1"
# 验证安装
python -c "import numpy, scipy, transformers, datasets; print('All imported successfully')"⚠️ 注意:conda install scipy 有时会拉取过新 NumPy,优先用 pip install 控制版本;若需 conda-forge 版本,加 -c conda-forge 并显式指定 numpy=1.22.4。
? 关键代码优化:规避 Slurm 环境陷阱
在脚本开头强制禁用潜在冲突的并行机制,并设置确定性缓存路径:
import os
# --- 强制禁用 tokenizers 多进程(避免 fork 问题)---
os.environ["TOKENIZERS_PARALLELISM"] = "false"
# --- 避免 OMP 线程争抢(尤其在共享节点)---
os.environ["OMP_NUM_THREADS"] = "1"
# --- 显式设置 Hugging Face 缓存目录(确保有写权限且路径存在)---
os.environ["HF_HOME"] = "/data/home/your_username/hf_cache" # 替换为你的实际路径
os.makedirs(os.environ["HF_HOME"], exist_ok=True)
# --- (可选)限制 datasets 的 num_proc,避免资源耗尽 ---
from datasets import load_dataset
dataset = load_dataset("glue", "mrpc", num_proc=1) # 显式设为 1然后,在调用 dataset.map() 时,务必添加 num_proc=1 参数(即使你希望并行,也先验证单进程是否通过):
mapped_dataset = dataset.map(
lambda x: tokenizer(x["sentence1"], x["sentence2"],
max_length=MAX_LEN,
truncation=True,
padding='max_length',
return_tensors='pt'),
batched=True,
num_proc=1, # ? 关键!Slurm 下首次调试必须设为 1
desc="Tokenizing MRPC"
)? 总结与最佳实践
- 环境一致性是前提:Slurm 计算节点 ≠ 你的本地开发机。永远通过 conda env export > environment.yml 导出本地工作环境,并在集群上 conda env create -f environment.yml 复现。
- 警惕版本警告:NumPy/SciPy 不兼容是 HPC 上 datasets 和 transformers 卡死的最常见元凶,绝不能忽略。
- 控制并行行为:TOKENIZERS_PARALLELISM=false + num_proc=1 是 Slurm 调试黄金组合,确认功能正确后再逐步放开。
- 检查存储与权限:确保 /data/home//raw_roberta/... 路径在所有计算节点均可访问(NFS 挂载正常)、有读权限;HF_HOME 目录有写权限。
-
Slurm 提交脚本中显式激活环境:
#!/bin/bash #SBATCH --job-name=hf-debug #SBATCH --cpus-per-task=4 source /path/to/anaconda3/bin/activate conda activate py38v1-env python your_script.py
遵循以上步骤,90% 的“本地快、Slurm 卡”问题可快速定位并解决。记住:在 HPC 上,可重现的环境比精巧的代码更重要。










