Transformers 文档

分布式 CPU

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

分布式 CPU

CPU 很常见,并且在 GPU 不可用时,可以成为一种经济高效的训练选择。当训练大型模型或单个 CPU 太慢时,使用分布式 CPU 训练可以帮助加速训练。

本指南演示了如何使用 Trainer 和 Kubernetes 集群,在裸机上使用 DistributedDataParallel (DDP) 策略,通过多个 CPU 执行分布式训练。本指南中显示的所有示例都依赖于 Intel oneAPI HPC Toolkit

您将需要 Intel oneAPI 中的两个工具包。

  1. oneCCL 包含深度学习中常用集合通信的高效实现,例如 all-gather、all-reduce 和 reduce-scatter。要从预构建的 wheel 安装,请确保始终使用最新版本。请参阅此处的表格,以检查 Python 和 PyTorch 版本是否支持 oneCCL 版本。
# installs oneCCL for PyTorch 2.4.0
pip install oneccl_bind_pt==2.4.0 -f https://developer.intel.com/ipex-whl-stable-cpu

有关更多详细信息,请参阅 oneCCL 安装

  1. MPI 是一个消息传递接口,用于硬件和网络之间的通信。 oneCCL 工具包与 MPI 一起安装,但您需要在使用前 source 环境,如下所示。
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

最后,安装 Intex Extension for PyTorch (IPEX),它可以为 Intel 硬件实现额外的性能优化,例如权重共享和更好的线程运行时控制。

pip install intel_extension_for_pytorch==<version_name> -f https://developer.intel.com/ipex-whl-stable-cpu

有关更多详细信息,请参阅 IPEX 安装

Trainer

Trainer 支持使用 oneCCL 后端通过 CPU 进行分布式训练。在命令参数中添加 --ddp_backend ccl 参数即可启用它。

单节点
多节点

下面的示例演示了 run_qa.py 脚本。它允许在一个 Xeon CPU 上使用两个进程进行训练,每个 socket 运行一个进程。

调整变量 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

Kubernetes

使用 CPU 的分布式训练也可以使用 PyTorchJob 部署到 Kubernetes 集群。在开始之前,您应该执行以下设置步骤。

  1. 确保您可以访问已安装 Kubeflow 的 Kubernetes 集群。
  2. 安装和配置 kubectl 以与集群交互。
  3. 设置 PersistentVolumeClaim (PVC) 以存储数据集和模型文件。有多种选项可供选择,包括 StorageClass 或云存储桶。
  4. 为训练脚本和所有必需的依赖项(例如 PyTorch、Transformers、IPEX、oneCCL 和 OpenSSH)设置 Docker 容器,以方便容器之间的通信。

下面的 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

# Download and extract the transformers code
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 是 Kubernetes API 的扩展,用于在 Kubernetes 上运行 PyTorch 训练作业。它包含一个 yaml 文件,用于定义训练作业的参数,例如 PyTorchJob 的名称、worker 的数量、每个 worker 的资源类型等等。

volumeMount 参数是 PVC 在每个 worker pod 的容器中挂载的路径。 PVC 通常用于在训练完成后保存数据集、检查点文件和模型。

下面的 yaml 文件示例在 run_qa.py 脚本上设置了四个 worker。根据您的训练脚本和集群中的节点数调整 yaml 文件。

CPU 资源限制和请求在 CPU 单位中定义。一个 CPU 单位相当于一个物理 CPU 核心或虚拟核心。yaml 文件中定义的 CPU 单位应小于单台机器的可用 CPU 和内存容量,以便为 kubelet 和系统留出一些资源。对于 Guaranteed 服务质量,请为资源限制和请求设置相同的 CPU 和内存量。

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

部署

在您使用适合您的集群和训练作业的设置设置 PyTorchJob yaml 文件后,使用以下命令将其部署到集群。

export NAMESPACE=<specify your namespace>

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

使用 kubectl get pods -n ${NAMESPACE} 列出命名空间中的 pod。最初,状态可能是“Pending”,但一旦容器被拉取和创建,它应该会变为“Running”。

kubectl get pods -n ${NAMESPACE}

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
...

使用以下命令检查每个 worker 的日志。添加 -f 以流式传输日志。

kubectl logs transformers-pytorchjob-worker-0 -n ${NAMESPACE} -f

训练完成后,可以从 PVC 或存储位置复制训练好的模型。使用以下命令从集群中删除 PyTorchJob 资源。

kubectl delete -f pytorchjob.yaml -n ${NAMESPACE}
< > 在 GitHub 上更新