在多个 CPU 上高效训练¶
当在单个 CPU 上进行训练太慢时,我们可以使用多个 CPU。本指南重点介绍如何在裸机和 Kubernetes 上使用基于 PyTorch 的分布式数据并行(DDP)进行高效的 CPU 分布式训练。
Intel® oneCCL 绑定库 for PyTorch¶
Intel® oneCCL(集体通信库)是一个用于高效分布式深度学习训练的库,实现了诸如 allreduce、allgather、alltoall 等集体操作。有关 oneCCL 的更多信息,请参阅 oneCCL 文档 和 oneCCL 规范。
模块 oneccl_bindings_for_pytorch(1.12 版本之前称为 torch_ccl)实现了 PyTorch C10D ProcessGroup API,并且可以作为外部 ProcessGroup 动态加载,目前仅支持 Linux 平台。
更多详细信息请参阅 oneccl_bind_pt。
安装 Intel® oneCCL 绑定库 for PyTorch¶
以下 Python 版本提供了 wheel 文件:
| 扩展版本 | Python 3.7 | Python 3.8 | Python 3.9 | Python 3.10 | Python 3.11 |
|---|---|---|---|---|---|
| 2.5.0 | √ | √ | √ | √ | |
| 2.4.0 | √ | √ | √ | √ | |
| 2.3.0 | √ | √ | √ | √ | |
| 2.2.0 | √ | √ | √ | √ |
请运行 pip list | grep torch 来获取您的 pytorch_version。
pip install oneccl_bind_pt=={pytorch_version} -f https://developer.intel.com/ipex-whl-stable-cpu
其中 {pytorch_version} 是您的 PyTorch 版本,例如 2.4.0。更多安装方法请参阅 oneccl_bind_pt 安装文档。oneCCL 和 PyTorch 的版本必须匹配。
Intel® MPI 库¶
使用基于标准的 MPI 实现,在 Intel® 架构上提供灵活、高效的可扩展集群消息传递。该组件是 Intel® oneAPI HPC 工具包的一部分。
oneccl_bindings_for_pytorch 随 MPI 工具集一起安装。在使用前需要设置环境变量。
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® 扩展 for PyTorch¶
Intel 扩展 for PyTorch (IPEX) 提供了 CPU 训练性能优化,支持 Float32 和 BFloat16(更多内容请参阅 单 CPU 部分)。
以下“在 Trainer 中使用”的部分以 Intel® MPI 库中的 mpirun 为例。
在 Trainer 中使用¶
要在 Trainer 中启用多 CPU 分布式训练(使用 ccl 后端),用户需要在命令参数中添加 --ddp_backend ccl。
让我们来看一个 问答示例 的例子。
以下命令在一台 Xeon 节点上启用 2 个进程进行训练,每个进程在一个插槽上运行。可以调整 OMP_NUM_THREADS/CCL_WORKER_COUNT 变量以获得最佳性能。
export CCL_WORKER_COUNT=1
export MASTER_ADDR=127.0.0.1
mpirun -n 2 -genv OMP_NUM_THREADS=23 \
python3 examples/pytorch/question-answering/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
以下命令在两台 Xeon 节点(node0 和 node1,以 node0 为主节点)上启用总共 4 个进程进行训练,每台节点上的进程数(ppn)设置为 2,每个进程在一个插槽上运行。可以调整 OMP_NUM_THREADS/CCL_WORKER_COUNT 变量以获得最佳性能。
在 node0 中,您需要创建一个包含每个节点 IP 地址的配置文件(例如 hostfile),并将该配置文件路径作为参数传递。
cat hostfile
xxx.xxx.xxx.xxx # node0 ip
xxx.xxx.xxx.xxx # node1 ip
现在,在 node0 中运行以下命令,并在 node0 和 node1 中启用 4DDP 和 BF16 自动混合精度:
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 examples/pytorch/question-answering/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
在 Kubernetes 上使用¶
上一节中的分布式训练作业可以部署到 Kubernetes 集群中,使用 Kubeflow PyTorchJob 训练操作符。
准备工作¶
本示例假定您已经具备以下条件:
- 访问安装了 Kubeflow 的 Kubernetes 集群
- 安装并配置了
kubectl以访问 Kubernetes 集群 - 有一个 持久卷声明 (PVC) 可用于存储数据集和模型文件。设置 PVC 的选项包括使用 NFS 存储类 或云存储桶。
- 一个包含模型训练脚本及其所有依赖项的 Docker 容器。对于分布式 CPU 训练作业,这通常包括 PyTorch、Transformers、Intel 扩展 for PyTorch、Intel oneCCL 绑定库 for PyTorch 和 OpenSSH 以在容器之间通信。
以下是一个示例 Dockerfile,使用支持分布式 CPU 训练的基础镜像,然后将 Transformers 发行版提取到 /workspace 目录中,以便示例脚本包含在镜像中:
FROM intel/intel-optimized-pytorch:2.4.0-pip-multinode
RUN apt-get update -y && \
apt-get install -y --no-install-recommends --fix-missing \
google-perftools \
libomp-dev
WORKDIR /workspace
# 下载并解压 Transformers 代码
ARG HF_TRANSFORMERS_VER="4.46.0"
RUN pip install --no-cache-dir \
transformers==${HF_TRANSFORMERS_VER} && \
mkdir transformers && \
curl -sSL --retry 5 https://github.com/huggingface/transformers/archive/refs/tags/v${HF_TRANSFORMERS_VER}.tar.gz | tar -C transformers --strip-components=1 -xzf -
此镜像需要构建并复制到集群的节点上,或者推送到容器注册表,然后再将 PyTorchJob 部署到集群中。
PyTorchJob 规范文件¶
Kubeflow PyTorchJob 用于在集群上运行分布式训练作业。PyTorchJob 的 YAML 文件定义了以下参数:
- PyTorchJob 的名称
- 副本数量(工作节点)
- 将用于运行训练作业的 Python 脚本及其参数
- 每个工作节点所需的资源类型(节点选择器、内存和 CPU)
- 要使用的 Docker 镜像和标签
- 环境变量
- 卷挂载点用于 PVC
卷挂载点定义了 PVC 将在每个工作节点 Pod 的容器中挂载的路径。这个位置可以用于数据集、检查点文件和训练完成后保存的模型。
以下是一个带有 4 个工作节点的 PyTorchJob YAML 文件示例,运行 问答示例:
要运行此示例,请根据您的训练脚本和集群节点更新 YAML 文件。
YAML 文件中的 CPU 资源限制/请求定义在 CPU 单位中,其中 1 个 CPU 单位相当于 1 个物理 CPU 核心或 1 个虚拟核心(取决于节点是物理主机还是虚拟机)。YAML 文件中定义的 CPU 和内存限制/请求应小于单个机器上的可用 CPU/内存容量。通常,最好不要使用整个机器的全部容量,以留出一些资源给 kubelet 和操作系统。为了获得 “保证” 服务质量,请将相同的 CPU 和内存数量设置为资源限制和请求。
部署¶
更新 PyTorchJob 规范文件中的值,使其适合您的集群和训练作业,然后使用以下命令将其部署到集群中:
export NAMESPACE=<指定您的命名空间>
kubectl create -f pytorchjob.yaml -n ${NAMESPACE}
然后可以使用 kubectl get pods -n ${NAMESPACE} 命令列出命名空间中的 Pod。您应该看到刚刚部署的 PyTorchJob 的工作节点 Pod。初始状态可能是“Pending”,因为容器正在被拉取和创建,然后状态应变为“Running”。
可以使用 kubectl logs <pod name> -n ${NAMESPACE} 查看工作节点的日志。添加 -f 以实时流式传输日志,例如:
kubectl logs transformers-pytorchjob-worker-0 -n ${NAMESPACE} -f
训练作业完成后,可以从 PVC 或存储位置复制训练好的模型。完成作业后,可以使用 kubectl delete -f pytorchjob.yaml -n ${NAMESPACE} 从集群中删除 PyTorchJob 资源。
总结¶
本指南介绍了如何在裸机和 Kubernetes 集群上使用多个 CPU 进行分布式 PyTorch 训练。两种情况都使用了 Intel 扩展 for PyTorch 和 Intel oneCCL 绑定库 for PyTorch 以实现最佳训练性能,可以作为模板用于在多个节点上运行自己的工作负载。