Slurm 作业卡在 Hugging Face 数据集映射阶段的排查与解决指南

11次阅读

Slurm 作业卡在 Hugging Face 数据集映射阶段的排查与解决指南

本文详解 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 上,可重现的环境比精巧的代码更重要

text=ZqhQzanResources