Transformers 文档

在多CPU上的高效训练

在多个CPU上进行高效训练

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

Intel® oneCCL 绑定 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 绑定 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® PyTorch 扩展安装

Intel Extension 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为主进程)上总共四个进程的训练,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中运行以下命令,4DDP将在node0和node1中启用,并带有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的使用

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

设置

此示例假设您具备以下条件:

  • 访问已安装Kubeflow的Kubernetes集群
  • kubectl 已安装并配置为访问 Kubernetes 集群
  • 一个持久卷声明(PVC),可用于存储数据集和模型文件。设置PVC有多种选项,包括使用NFS存储类或云存储桶。
  • 一个包含您的模型训练脚本和运行脚本所需的所有依赖项的Docker容器。对于分布式CPU训练任务,这通常包括PyTorch、Transformers、PyTorch的Intel扩展、PyTorch的Intel oneCCL绑定以及用于容器间通信的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

# 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 规范文件

Kubeflow PyTorchJob 用于在集群上运行分布式训练任务。PyTorchJob 的 yaml 文件定义了诸如以下参数:

  • PyTorchJob 的名称
  • 副本数量(工作节点)
  • 用于运行训练任务的python脚本及其参数
  • 每个工作节点所需的资源类型(节点选择器、内存和CPU)
  • 要使用的Docker容器的镜像/标签
  • 环境变量
  • PVC 的卷挂载

卷挂载定义了PVC将在每个工作pod的容器中挂载的路径。此位置可用于数据集、检查点文件以及训练完成后保存的模型。

下面的代码片段是一个用于PyTorchJob的yaml文件示例,该作业有4个工作者运行问答示例

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 units 中定义,其中1个CPU单位相当于1个物理CPU核心或1个虚拟核心(取决于节点是物理主机还是虚拟机)。yaml中定义的CPU和内存限制/请求应小于单台机器上可用的CPU/内存容量。通常不建议使用机器的全部容量,以便为kubelet和操作系统留出一些资源。为了获得工作pod的“guaranteed” 服务质量,应为资源限制和请求设置相同的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 -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 Extension for PyTorch和Intel oneCCL Bindings for PyTorch以获得最佳训练性能,并且可以作为模板在多节点上运行您自己的工作负载。

< > Update on GitHub