Transformers 文档

多 CPU 上的高效训练

Hugging Face's logo
加入 Hugging Face 社区

并获得增强版文档体验

开始使用

在多个 CPU 上高效训练

当在单个 CPU 上训练速度太慢时,我们可以使用多个 CPU。本指南重点介绍基于 PyTorch 的 DDP,它可以高效地在 裸机Kubernetes 上进行分布式 CPU 训练。

英特尔® oneCCL 针对 PyTorch 的绑定

英特尔® oneCCL(集体通信库)是一个用于高效分布式深度学习训练的库,它实现了诸如 allreduce、allgather、alltoall 之类的集体操作。有关 oneCCL 的更多信息,请参阅 oneCCL 文档oneCCL 规范

模块 oneccl_bindings_for_pytorch(在 1.12 版之前为 torch_ccl)实现了 PyTorch C10D ProcessGroup API,可以动态加载为外部 ProcessGroup,目前仅适用于 Linux 平台。

查看有关 oneccl_bind_pt 的更多详细信息。

英特尔® oneCCL 针对 PyTorch 的绑定安装

以下 Python 版本提供了 Wheel 文件

扩展版本 Python 3.6 Python 3.7 Python 3.8 Python 3.9 Python 3.10
2.1.0
2.0.0
1.13.0
1.12.100
1.12.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.1.0。查看有关 oneccl_bind_pt 安装 的更多方法。oneCCL 和 PyTorch 的版本必须匹配。

oneccl_bindings_for_pytorch 1.12.0 预构建的 wheel 不适用于 PyTorch 1.12.1(它适用于 PyTorch 1.12.0),PyTorch 1.12.1 应适用于 oneccl_bindings_for_pytorch 1.12.100。

英特尔® MPI 库

使用此基于标准的 MPI 实现,在英特尔® 架构上提供灵活、高效、可扩展的集群消息传递。此组件是英特尔® oneAPI HPC 工具包的一部分。

oneccl_bindings_for_pytorch 与 MPI 工具集一起安装。需要在使用它之前设定环境变量。

对于英特尔® oneCCL >= 1.12.0

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

对于英特尔® oneCCL 版本 < 1.12.0

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

英特尔® 针对 PyTorch 的扩展安装

英特尔针对 PyTorch 的扩展(IPEX)为使用 Float32 和 BFloat16 的 CPU 训练提供了性能优化(请参阅 单 CPU 部分 了解详情)。

以下“在训练器中使用”以英特尔® MPI 库中的 mpirun 为例。

在训练器中使用

要在训练器中使用 ccl 后端启用多 CPU 分布式训练,用户应在命令参数中添加 --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 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(节点 0 和节点 1,以节点 0 为主进程)上总共使用四个进程进行训练,ppn(每个节点的进程数)设置为 2,每个套接字运行一个进程。变量 OMP_NUM_THREADS/CCL_WORKER_COUNT 可以调整以获得最佳性能。

在节点 0 中,您需要创建一个包含每个节点 IP 地址的配置文件(例如 hostfile),并将该配置文件路径作为参数传递。

 cat hostfile
 xxx.xxx.xxx.xxx #node0 ip
 xxx.xxx.xxx.xxx #node1 ip

现在,在节点 0 中运行以下命令,4DDP 将在节点 0 和节点 1 中启用,并使用 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 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

上一节中相同的分布式训练作业可以使用 Kubeflow PyTorchJob 训练操作符 部署到 Kubernetes 集群。

设置

此示例假定您拥有

  • 访问已 安装 Kubeflow 的 Kubernetes 集群
  • kubectl 已安装并配置为访问 Kubernetes 集群
  • 可用于存储数据集和模型文件的 持久卷声明 (PVC)。设置 PVC 有多种选择,包括使用 NFS 存储类 或云存储桶。
  • 包含您的模型训练脚本和运行脚本所需的所有依赖项的 Docker 容器。对于分布式 CPU 训练作业,这通常包括 PyTorch、Transformers、英特尔针对 PyTorch 的扩展、英特尔 oneCCL 针对 PyTorch 的绑定和 OpenSSH 以在容器之间进行通信。

以下代码段是 Dockerfile 的示例,它使用支持分布式 CPU 训练的基础镜像,然后将 Transformers 版本解压到 /workspace 目录,以便示例脚本包含在镜像中

FROM intel/intel-optimized-pytorch:2.3.0-pip-multinode

RUN apt-get update -y && \
    apt-get install -y --no-install-recommends --fix-missing \
    google-perftools \
    libomp-dev

WORKDIR /workspace

# Download and extract the transformers code
ARG HF_TRANSFORMERS_VER="4.44.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 文件示例。

apiVersion: "kubeflow.org/v1"
kind: PyTorchJob
metadata:
  name: transformers-pytorchjob
spec:
  elasticPolicy:
    rdzvBackend: c10d
    minReplicas: 1
    maxReplicas: 4
    maxRestarts: 10
  pytorchReplicaSpecs:
    Worker:
      replicas: 4  # The number of worker pods
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: <image name>:<tag>  # Specify the docker image to use for the worker pods
              imagePullPolicy: IfNotPresent
              command: ["/bin/bash", "-c"]
              args:
                - >-
                  cd /workspace/transformers;
                  pip install -r /workspace/transformers/examples/pytorch/question-answering/requirements.txt;
                  source /usr/local/lib/python3.10/dist-packages/oneccl_bindings_for_pytorch/env/setvars.sh;
                  torchrun /workspace/transformers/examples/pytorch/question-answering/run_qa.py \
                    --model_name_or_path distilbert/distilbert-base-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/pvc-mount/output_$(date +%Y%m%d_%H%M%S) \
                    --no_cuda \
                    --ddp_backend ccl \
                    --bf16 \
                    --use_ipex;
              env:
              - name: LD_PRELOAD
                value: "/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4.5.9:/usr/local/lib/libiomp5.so"
              - name: TRANSFORMERS_CACHE
                value: "/tmp/pvc-mount/transformers_cache"
              - name: HF_DATASETS_CACHE
                value: "/tmp/pvc-mount/hf_datasets_cache"
              - name: LOGLEVEL
                value: "INFO"
              - name: CCL_WORKER_COUNT
                value: "1"
              - name: OMP_NUM_THREADS  # Can be tuned for optimal performance
                value: "240"
              resources:
                limits:
                  cpu: 240  # Update the CPU and memory limit values based on your nodes
                  memory: 128Gi
                requests:
                  cpu: 240  # Update the CPU and memory request values based on your nodes
                  memory: 128Gi
              volumeMounts:
              - name: pvc-volume
                mountPath: /tmp/pvc-mount
              - mountPath: /dev/shm
                name: dshm
          restartPolicy: Never
          nodeSelector:  # Optionally use nodeSelector to match a certain node label for the worker pods
            node-type: gnr
          volumes:
          - name: pvc-volume
            persistentVolumeClaim:
              claimName: transformers-pvc
          - name: dshm
            emptyDir:
              medium: Memory

要运行此示例,请根据您的训练脚本和集群中的节点更新 yaml。

yaml 中的 CPU 资源限制/请求以 cpu 单位 定义,其中 1 个 CPU 单位相当于 1 个物理 CPU 内核或 1 个虚拟内核(取决于节点是物理主机还是虚拟机)。yaml 中定义的 CPU 和内存限制/请求量应小于单个机器上可用的 CPU/内存容量。通常建议不要使用整个机器的容量,以便为 kubelet 和操作系统保留一些资源。为了获得 “保证” 服务质量,请为工作器 Pod 设置相同的 CPU 和内存量,用于资源限制和请求。

部署

在使用适合您的集群和训练作业的值更新 PyTorchJob 规范后,可以使用以下方法将其部署到集群中

export NAMESPACE=<specify your namespace>

kubectl create -f pytorchjob.yaml -n ${NAMESPACE}

然后可以使用 kubectl get pods -n ${NAMESPACE} 命令列出您命名空间中的 Pod。您应该看到刚部署的 PyTorchJob 的工作器 Pod。最初,它们的状态可能是“Pending”,因为容器正在被拉取和创建,然后状态应该更改为“Running”。

NAME                                                     READY   STATUS                  RESTARTS          AGE
...
transformers-pytorchjob-worker-0                         1/1     Running                 0                 7m37s
transformers-pytorchjob-worker-1                         1/1     Running                 0                 7m37s
transformers-pytorchjob-worker-2                         1/1     Running                 0                 7m37s
transformers-pytorchjob-worker-3                         1/1     Running                 0                 7m37s
...

可以使用 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 训练作业。这两种情况都利用了英特尔 PyTorch 扩展和英特尔 oneCCL PyTorch 绑定,以实现最佳训练性能,并且可以用作在多个节点上运行您自己的工作负载的模板。

< > 在 GitHub 上更新