使用 Transformers Trainer 在多个 CPU 上进行分布式训练:oneCCL、Intel MPI 与 ccl 后端实战指南
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
当单颗 CPU 上的训练速度无法满足需求时,利用多颗 CPU(多 Socket、多节点)进行分布式训练是成本敏感型场景下的实用方案。本指南以 Hugging Face Transformers 官方文档(docs/source/it/perf_train_cpu_many.md)为主体,围绕基于 PyTorch 的 DDP(Distributed Data Parallel)在多 CPU 场景下的落地展开:从 Intel® oneCCL 集合通信库的安装与版本匹配、Intel® MPI 环境的初始化,到在Trainer中通过--ddp_backend ccl一键启用多进程分布式训练,并给出单节点双 Socket 与双节点四进程两种可直接复用的完整命令行示例。读完本文,你将掌握在 Linux 平台上用 Transformers Trainer 完成多 CPU 分布式训练全流程配置的能力。
一、为什么需要多 CPU 分布式训练
在 GPU 不可用或追求成本效益的场景中,CPU 训练是合理的替代方案。而当单颗 CPU 的训练耗时过长时,就需要把训练任务扩展到多颗 CPU 上并行执行。官方文档明确指出:本指南聚焦于基于 PyTorch 的 DDP(Distributed Data Parallel)在多 CPU 上的高效分布式训练。
多 CPU 训练的核心收益在于:将模型参数、梯度计算分散到多个进程(每个进程绑定一个 CPU Socket 甚至一个节点),通过高效的集合通信库完成梯度的全局同步(allreduce),从而显著缩短训练时间。在 Transformers 生态中,这一切都可以通过Trainer与TrainingArguments的少量参数配置完成,无需修改训练脚本本身。
二、Intel® oneCCL Bindings for PyTorch:CPU 分布式训练的通信基石
2.1 oneCCL 与 torch_ccl / oneccl_bindings_for_pytorch 的关系
Intel® oneCCL(oneAPI Collective Communications Library)是一个面向分布式深度学习训练的高效集合通信库,实现了allreduce、allgather、alltoall等经典集合通信原语。它是多 CPU 分布式训练中进程间梯度同步的底层支撑。
在 PyTorch 生态中,与之对接的模块是oneccl_bindings_for_pytorch(在 1.12 版本之前称为torch_ccl)。该模块实现了 PyTorch 的 C10D ProcessGroup API,可以作为外部 ProcessGroup 被动态加载,从而让 PyTorch 的分布式训练(包括 Transformers Trainer 内部的 DDP 逻辑)直接使用 oneCCL 作为通信后端。需要特别注意的是:该绑定目前仅支持 Linux 平台。
2.2 支持的 Python 版本与 wheel 版本对照
oneccl_bindings_for_pytorch针对不同 Python 版本发布了预编译 wheel,官方文档给出的版本兼容矩阵如下:
| 扩展版本 | Python 3.6 | Python 3.7 | Python 3.8 | Python 3.9 | Python 3.10 |
|---|---|---|---|---|---|
| 1.13.0 | √ | √ | √ | √ | |
| 1.12.100 | √ | √ | √ | √ | |
| 1.12.0 | √ | √ | √ | √ | |
| 1.11.0 | √ | √ | √ | √ | |
| 1.10.0 | √ | √ | √ | √ |
从表中可以看出:Python 3.6 仅支持 1.10.0 版本;Python 3.7~3.9 全系支持;Python 3.10 不支持 1.10.0。选择版本时务必以这张表为依据,并结合下文"版本必须匹配"的原则。
2.3 安装命令与版本匹配要点
安装命令非常简单,通过 pip 从 Intel 官方 wheel 仓库安装:
pip install oneccl_bind_pt=={pytorch_version} -f https://developer.intel.com/ipex-whl-stable-cpu其中{pytorch_version}需要替换为与你本地 PyTorch 完全一致的版本号,例如 PyTorch 1.13.0 对应安装oneccl_bind_pt==1.13.0。文档特别强调:oneCCL 与 PyTorch 的版本必须匹配,否则会出现运行时错误或静默异常。
这里有一个官方明确警告的版本坑,务必留意:
⚠️版本兼容警告
oneccl_bindings_for_pytorch1.12.0 的预编译 wheel 无法与 PyTorch 1.12.1 配合使用(它只对应 PyTorch 1.12.0)。 如果使用 PyTorch 1.12.1,应选择oneccl_bindings_for_pytorch1.12.100。
也就是说,PyTorch 的补丁版本(1.12.0 → 1.12.1)在 oneCCL 绑定这里被视为不兼容的独立版本,安装前一定要先确认python -c "import torch; print(torch.__version__)"的输出。
三、Intel® MPI library:集群消息传递与进程编排
3.1 MPI 在多 CPU 训练中的角色
Intel® MPI Library 是基于标准 MPI 规范的实现,为 Intel® 架构提供灵活、高效、可扩展的集群消息传递能力,属于 Intel® oneAPI HPC Toolkit 的组成部分。在多 CPU(尤其是多节点)分布式训练中,mpirun负责把训练进程分发到各节点、各 Socket 上,并管理进程间的通信拓扑。
3.2 使用前的环境初始化(source setvars.sh)
oneccl_bindings_for_pytorch在安装时会随附 MPI 工具集,但使用前必须先把对应环境变量加载进来(source setvars.sh)。由于 oneCCL 版本的差异,加载方式分两种情况:
情况一:Intel® oneCCL 版本 >= 1.12.0(对应oneccl_bindings_for_pytorch模块):
oneccl_bindings_for_pytorch_path=$(python -c "from oneccl_bindings_for_pytorch import cwd; print(cwd)") source $oneccl_bindings_for_pytorch_path/env/setvars.sh情况二:Intel® oneCCL 版本 < 1.12.0(对应旧模块名torch_ccl):
torch_ccl_path=$(python -c "import torch; import torch_ccl; import os; print(os.path.abspath(os.path.dirname(torch_ccl.__file__)))") source $torch_ccl_path/env/setvars.sh两种方式的原理相同:通过 Python 找到绑定库安装目录下的env/setvars.sh,将其source到当前 shell,从而把 oneCCL/MPI 相关的动态库路径、环境变量注入训练进程。该步骤是后续mpirun能否正常工作的前提,建议放在训练脚本执行前的同一 shell 会话中完成。
3.3 IPEX 安装:单 CPU 性能优化的补充
IPEX(Intel® Extension for PyTorch)为 CPU 训练提供额外的性能优化,同时支持 Float32 与 BFloat16 两种精度路径。在启用多 CPU 分布式训练时,IPEX 可与 oneCCL 后端叠加使用(见下文命令中的--use_ipex参数)。关于 IPEX 在单 CPU 场景下的详细优化说明,可参考同一目录下的 单 CPU 性能指南,本文不再展开。
四、在 Trainer 中使用 ccl 后端:多 CPU 分布式训练实战
4.1 启用方式:--ddp_backend ccl
在Trainer中启用多 CPU 分布式训练,只需要在命令行参数中加入--ddp_backend ccl。这一参数会传递给底层的分布式状态管理(在 Transformers 源码中,ddp_backend最终作为 backend 传入加速器/分布式初始化逻辑,见 training_args.py),告诉 Trainer 使用 oneCCL 作为通信后端而不是默认的 nccl/gloo。
配合--no_cuda强制在 CPU 上运行(在较新版本中也可使用--use_cpu,见 use_cpu 参数定义),即可完成配置。
4.2 场景一:单节点双 Socket,2 进程训练
以下示例以 Transformers 仓库中的 question-answering 示例(run_qa.py,基于 SQuAD 数据集微调 BERT-large)为蓝本。该命令在单台 Xeon 节点上启动 2 个训练进程,每个进程绑定一个 CPU Socket:
export CCL_WORKER_COUNT=1 export MASTER_ADDR=127.0.0.1 mpirun -n 2 -genv OMP_NUM_THREADS=23 \ python3 run_qa.py \ --model_name_or_path google-bert/bert-large-uncased \ --dataset_name squad \ --do_train \ --do_eval \ --per_device_train_batch_size 12 \ --learning_rate 3e-5 \ --num_train_epochs 2 \ --max_seq_length 384 \ --doc_stride 128 \ --output_dir /tmp/debug_squad/ \ --no_cuda \ --ddp_backend ccl \ --use_ipex关键点解读:
mpirun -n 2:启动 2 个分布式训练进程,对应双 Socket 节点上每 Socket 一个进程,保证每个进程的内存访问局部性(NUMA 友好),从而提升吞吐。-genv OMP_NUM_THREADS=23:通过-genv把环境变量传递给每个 MPI 进程。OMP_NUM_THREADS 建议设置为单个 Socket 的物理核心数减一(预留一个核心给操作系统),例如 24 核 Socket 设为 23。这一建议同时出现在 英文版多 CPU 文档 中。CCL_WORKER_COUNT=1:oneCCL 的工作线程数,与 OMP_NUM_THREADS 一样是可调优项,通常根据通信与计算重叠的需求在 1 附近调节。--no_cuda --ddp_backend ccl:强制 CPU 训练并指定 oneCCL 通信后端,这是多 CPU 分布式训练的核心开关。--use_ipex:叠加 IPEX 优化,进一步提升 CPU 上的计算效率。
4.3 场景二:双节点四进程训练(4DDP + BF16 自动混合精度)
当单节点资源仍不够时,可以把训练扩展到多台 Xeon 节点。以下命令在两台节点(node0、node1)上共启动4 个进程,其中ppn(processes per node)为 2,即每节点 2 个进程、每 Socket 一个,node0 作为主进程(master)。
第一步:在 node0 上创建 hostfile
hostfile 中需要包含参与训练的各节点 IP,每行一个:
cat hostfile xxx.xxx.xxx.xxx #node0 ip xxx.xxx.xxx.xxx #node1 ip第二步:在 node0 上执行训练命令
export CCL_WORKER_COUNT=1 export MASTER_ADDR=xxx.xxx.xxx.xxx #node0 ip mpirun -f hostfile -n 4 -ppn 2 \ -genv OMP_NUM_THREADS=23 \ python3 run_qa.py \ --model_name_or_path google-bert/bert-large-uncased \ --dataset_name squad \ --do_train \ --do_eval \ --per_device_train_batch_size 12 \ --learning_rate 3e-5 \ --num_train_epochs 2 \ --max_seq_length 384 \ --doc_stride 128 \ --output_dir /tmp/debug_squad/ \ --no_cuda \ --ddp_backend ccl \ --use_ipex \ --bf16与单节点场景的差异集中在三处:
mpirun -f hostfile:通过-f指定节点清单文件,mpirun 据此跨节点分发进程。-n 4 -ppn 2:总进程数为 4,每节点 2 个进程(每 Socket 一个)。MASTER_ADDR:必须设为 node0(主进程节点)的真实 IP,而不能是回环地址127.0.0.1。--bf16:启用BF16 自动混合精度(auto mixed precision)。CPU 上 BF16 相比 FP16 数值稳定性更好,能减少内存占用并加速训练,是 CPU 训练推荐的做法(详见 单 CPU 性能指南 中的说明)。
执行后,node0 与 node1 上即形成4DDP的分布式训练拓扑,梯度通过 oneCCL 的 allreduce 集合通信在四进程间同步。
4.4 训练参数调优小结
| 参数/环境变量 | 作用 | 建议 |
|---|---|---|
--ddp_backend ccl | 指定 oneCCL 作为 DDP 通信后端 | 多 CPU 分布式训练必选 |
--no_cuda/--use_cpu | 强制在 CPU 上训练 | CPU 场景必选 |
--bf16 | 启用 BF16 自动混合精度 | 降低内存占用、加速训练、数值更稳定 |
--use_ipex | 叠加 IPEX 性能优化 | 建议开启 |
OMP_NUM_THREADS | 每进程 OpenMP 线程数 | 设为单 Socket 物理核数 − 1 |
CCL_WORKER_COUNT | oneCCL 通信工作线程数 | 1 附近微调 |
MASTER_ADDR | 主进程地址 | 单节点用 127.0.0.1;多节点用 node0 IP |
五、源码层面的印证与扩展阅读
为了验证上述流程在 Transformers 中的真实落地方式,可以到仓库源码与文档中进一步确认:
--ddp_backend参数定义:位于 src/transformers/training_args.py,其 docstring 说明该参数用于指定分布式训练的 backend,并在TrainingArguments初始化阶段(约 L1846-L1858)传入分布式状态初始化逻辑。需要说明的是,从当前仓库源码的choices列表看,其枚举值随版本演进可能不显式包含ccl,但官方多 CPU 文档(即本文主题文档)明确推荐使用--ddp_backend ccl配合oneccl_bindings_for_pytorch使用,实际生效依赖于 torch-ccl 提供的 C10D ProcessGroup 扩展。--use_cpu参数定义:同样位于 src/transformers/training_args.py,用于强制 CPU 训练,在多 CPU 场景下与--ddp_backend ccl搭配。- 示例训练脚本:命令中的
run_qa.py来自 examples/pytorch/question-answering 目录,是完整的 SQuAD 问答微调示例,可直接在本地复现本文所有命令。 - 关联文档:
- 英文版多 CPU 训练指南:包含单 CPU、单机多进程、多机多进程三种场景的系统阐述,可作为本文的英文对照与补充。
- 单 CPU 性能优化指南:IPEX 在单 CPU 场景下的详细优化说明。
六、结语
多 CPU 分布式训练是一条无需 GPU 即可横向扩展算力的务实路径。通过 Intel® oneCCL 提供集合通信能力、Intel® MPI 负责跨节点进程编排、IPEX 提供单核计算优化,再配合 Transformers Trainer 的--ddp_backend ccl开关,只需在原有训练命令上增加少量参数,即可从单 CPU 平滑升级到多 Socket、多节点的 DDP 训练。配置过程中请重点核对三个环节:oneCCL 绑定库与 PyTorch 版本严格匹配、使用前正确sourceMPI 环境、按 Socket 核数设置OMP_NUM_THREADS。满足这三点后,上述单节点双进程与双节点四进程命令即可直接落地运行。
【免费下载链接】transformers🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.项目地址: https://gitcode.com/GitHub_Trending/tra/transformers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考