Transformers 在 CPU 上的高效训练实战指南:bf16 混合精度、Intel MPI 多路/多机扩展与 Kubernetes 部署
【免费下载链接】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 训练性能文档 为主线,系统讲解在没有 GPU 的环境下,如何使用 🤗 Transformers 的 [Trainer] 在 CPU 上完成高效训练:从单机启用 bf16 混合精度、按 CPU socket 拆分进程、跨多节点扩展(均基于 Intel MPI 与 DDP 策略),再到通过 Kubeflow PyTorchJob 在 Kubernetes 集群上编排大规模 CPU 训练任务。读完本文,你将能够独立把 SQuAD 问答微调等典型脚本无缝迁移到 CPU 环境,并正确设置OMP_NUM_THREADS、线程亲和、内存分配器与混合精度等关键性能变量。
什么时候适合用 CPU 训练,为什么优先选 bf16
CPU 训练在两类场景下是合理选择:一是没有 GPU 可用;二是希望以更低成本获得"够用"的训练吞吐。现代 Intel CPU 本身支持 bf16 混合精度训练——配合 PyTorch 针对 CPU 后端的 AMP(Automatic Mixed Precision),既显著降低内存占用,又提升训练速度。
关于精度格式,perf_train_cpu.md 明确建议:CPU 训练优先使用 bf16 而不是 fp16,因为 bf16 数值稳定性更好(其指数位宽与 fp32 相同,动态范围大,不易溢出/下溢)。这一点在仓库的TrainingArguments定义中也能看到一致的表述:bf16字段的 help 文案明确写着"Generally preferred over FP16 due to better numerical stability"(training_args.py)。
需要说明的是,bf16 并不等于全程用 bf16 计算。混合精度训练中只有部分算子运行在 bf16,梯度累积、参数更新等关键环节仍保持 fp32 精度,因此通常不会带来精度损失,却能换取内存占用下降与计算加速。
单机单 CPU:用Trainer一键启用 bf16 混合精度
Trainer原生支持在 CPU 上做 bf16 混合精度训练。开启方式只有两个开关:
--bf16:启用 PyTorch 针对 CPU 的 autocast 混合精度;--use_cpu:强制在 CPU 上训练(否则Trainer会优先探测 GPU 等加速设备)。
下面以仓库自带的问答微调脚本 run_qa.py 为例,在 SQuAD 数据集上微调google-bert/bert-base-uncased:
python run_qa.py \ --model_name_or_path google-bert/bert-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/debug_squad/ \ --bf16 \ --use_cpu各参数含义:
| 参数 | 作用 |
|---|---|
--model_name_or_path | 预训练模型 ID 或本地路径,此处为 bert-base-uncased |
--dataset_name squad | 使用 Hub 上的 SQuAD 数据集 |
--do_train / --do_eval | 训练与评估开关 |
--per_device_train_batch_size | 每设备 batch size(默认 8,见 training_args.py),CPU 上需结合内存容量调整 |
--learning_rate | 初始学习率(默认 5e-5) |
--num_train_epochs | 训练轮数(默认 3.0) |
--max_seq_length / --doc_stride | 问答任务的截断长度与滑窗步长 |
--output_dir | 模型与 checkpoint 输出目录(必填) |
--bf16 | 启用 bf16 混合精度 |
--use_cpu | 强制 CPU 训练 |
等价的中文编程式配置
上述命令行参数与TrainingArguments一一对应,因此完全可以跳过命令行、直接在 Python 脚本里声明训练配置:
from transformers import TrainingArguments training_args = TrainingArguments( output_dir="./outputs", bf16=True, use_cpu=True, )从源码理解这两个开关发生了什么
use_cpu与bf16并不只是"表面传参",它们在 training_args.py 的初始化逻辑里有着具体行为:
- 混合精度解析:在
__post_init__中,当bf16=True时,self.mixed_precision会被置为字符串"bf16"(见 training_args.py)。该值会传递给底层 Accelerate 库,由 Accelerate 决定何时用 CPU autocast 包裹前向计算。 - 设备选择:
TrainingArguments通过PartialState(cpu=self.use_cpu)初始化分布式状态(见 training_args.py),use_cpu=True时把训练设备解析为torch.device("cpu")。 - 数据加载优化:CPU 训练下
dataloader_pin_memory会被自动置为False(见 training_args.py),因为"锁页内存"是为加速 CPU→GPU 拷贝设计的,在纯 CPU 场景并无收益。 - autocast 的实际执行:
Trainer自身的autocast_smart_context_manager()直接返回nullcontext()并注明"We rely on accelerate for autocast"(见 trainer.py),即混合精度上下文由 Accelerate 依据前面解析出的bf16设置注入到训练循环中。
扩展规模:CPU 训练的三种形态
当单个 CPU 的训练速度不满足要求时,可以把规模扩展到多路 CPU(multiple sockets)甚至多节点。文档给出了三种典型形态:
- 单 CPU:单机单进程,启用 bf16 即可;
- 单机多进程:一台机器上每个 CPU socket 跑一个进程;
- 多机多进程:跨多台机器扩展。
文档中的分布式示例统一采用Intel MPI(来自 Intel oneAPI HPC Toolkit)作为通信库,配合Trainer内置的DDP(DistributedDataParallel)策略。仓库中的run_qa.py通过HfArgumentParser同时解析模型、数据与TrainingArguments三类参数(见 run_qa.py),因此同一脚本无需改动即可被mpirun/torchrun拉起多个进程。
单机多路:每 socket 一个进程
在双路(dual-socket)CPU 上,推荐每个 socket 启动一个进程。原因是内存访问局部性:NUMA 架构下,进程只访问自己所在 socket 的内存带宽与 LLC 缓存,吞吐远高于两个进程在任意 core 上漂移。
示例在单机启动两个进程(每 socket 一个),模型换成了更大的bert-large-uncased:
[!TIP] 把
OMP_NUM_THREADS设为单个 socket 的物理核数减 1(留 1 个核给操作系统)。例如 24 核 socket 设OMP_NUM_THREADS=23。
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/其中-n 2指定总进程数,-genv OMP_NUM_THREADS=23以全局环境变量方式把每个进程的 OpenMP 线程数限制为 23。MASTER_ADDR指向本机回环地址即可(单机场景 rank 0 就是本机)。Trainer会从进程环境自动识别分布式配置并切换为 DDP 模式。
跨节点扩展:两台 Xeon 机器、四个进程
当单机资源不足时,可将训练扩展到两台机器(示例中为node0与node1),每台机器 2 个进程(每 socket 一个),共 4 个进程。启动命令需在作为主节点的node0上执行。
第一步:编写 hostfile
hostfile 中列出各节点的 IP 地址(示例 IP 需替换为你的真实地址):
cat hostfile xxx.xxx.xxx.xxx #node0 ip xxx.xxx.xxx.xxx #node1 ip第二步:执行训练
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/ \ --use_cpu \ --bf16关键参数说明:
| mpirun 参数 | 含义 |
|---|---|
-f hostfile | 指定节点列表文件 |
-n 4 | 总进程数(4) |
-ppn 2 | 每节点进程数(2,即每 socket 一个) |
-genv OMP_NUM_THREADS=23 | 把每个进程的 OpenMP 线程数设为 23 |
同时把MASTER_ADDR指向node0的 IP,node0即分布式训练的主进程。相比单机示例,这里显式补充了--use_cpu --bf16,跨节点时全部按 CPU 场景训练并保持 bf16 混合精度。
Kubernetes:用 PyTorchJob 编排 CPU 分布式训练
如果团队以 Kubernetes 为基础设施,也可以用 PyTorchJob(Kubeflow 提供的自定义资源,用于管理 PyTorch 分布式训练任务)在集群上跑 CPU 分布式训练。
部署前需要完成的四项准备
- 拥有已安装Kubeflow的 Kubernetes 集群;
- 安装并配置kubectl以便操作集群;
- 准备一个PersistentVolumeClaim(PVC),用于存放数据集与模型文件;
- 为训练脚本及其依赖构建Docker 镜像。
定制 Docker 镜像
文档示例从 Intel 优化版 PyTorch 基础镜像出发——该镜像自带多节点 CPU 训练所需的 MPI 支持——并额外安装两个关键性能库:
google-perftools(libtcmalloc):相比系统默认分配器,能显著降低内存分配开销;libomp-dev(libiomp5):Intel 的 OpenMP 运行时,线程管理优于 GNU OpenMP 默认实现。
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 <transformers 对应版本源码归档地址> | tar -C transformers --strip-components=1 -xzf -镜像构建完成后,需先推送到集群节点可访问的镜像仓库,再执行部署。
编写 PyTorchJob 资源清单
PyTorchJob 负责 worker pod 的全生命周期管理(创建、重启策略、进程协调等),因此训练脚本只需关心模型与数据本身,无需自行实现分布式协调逻辑。下面的 YAML 创建 4 个 worker,全部运行仓库的 run_qa.py(微调distilbert/distilbert-base-uncased),并开启 bf16:
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; 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) \ --bf16; env: - name: LD_PRELOAD value: "/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4.5.9:/usr/local/lib/libiomp5.so" - name: HF_HUB_CACHE value: "/tmp/pvc-mount/hub_cache" - name: HF_DATASETS_CACHE value: "/tmp/pvc-mount/hf_datasets_cache" - name: LOGLEVEL value: "INFO" - name: OMP_NUM_THREADS # Set to match the number of allocated CPU units 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对该清单的几个关键设计点做深入解读:
- 弹性策略(elasticPolicy):采用 c10d 作为 rendezvous 后端,
minReplicas: 1、maxReplicas: 4允许 worker 数量在 1~4 间弹性伸缩,maxRestarts: 10控制重启上限;torchrun会自动适配该弹性语义。 - CPU 资源单位(CPU units):Kubernetes 中 1 个 CPU 单位等于 1 个物理核或 vCPU。将
limits与requests设为相同值(240 CPU / 128Gi 内存)可让 pod 获得Guaranteed级服务质量;同时应留出部分核给 kubelet 与系统进程。 OMP_NUM_THREADS与 CPU 配额对齐:环境变量应等于分配的 CPU 单位数(示例 240),确保 PyTorch 的 OpenMP 线程池能覆盖全部可用核。LD_PRELOAD注入两个性能库:把libtcmalloc(内存分配)与libiomp5(Intel OpenMP 运行时)以预加载方式挂入进程,与前面 Dockerfile 中安装的google-perftools、libomp-dev相呼应。- 缓存与共享内存:
HF_HUB_CACHE、HF_DATASETS_CACHE指向 PVC 挂载路径/tmp/pvc-mount,避免每次启动重新下载;/dev/shm使用内存型emptyDir,为 dataloader 多进程共享提供足够空间。 nodeSelector(可选):可通过节点标签(如node-type: gnr)把 worker 调度到指定型号的 CPU 节点。
注意:该 YAML 需根据你的训练脚本与集群节点数做相应调整(例如镜像名、CPU/内存配额、PVC 名称)。
部署与监控
创建资源(请先设置你的 namespace):
export NAMESPACE=<specify your namespace> kubectl create -f pytorchjob.yaml -n ${NAMESPACE}查看 pod 状态。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 的训练日志:
kubectl logs transformers-pytorchjob-worker-0 -n ${NAMESPACE} -f训练结束后,从 PVC(或你的存储位置)取回训练好的模型,然后删除 PyTorchJob 资源:
kubectl delete -f pytorchjob.yaml -n ${NAMESPACE}关键参数速查表
以下参数贯穿全文,汇总自 training_args.py 的字段定义:
| 参数 | 默认值 | 说明 |
|---|---|---|
bf16/--bf16 | False | 启用 bf16 混合精度;CPU 训练优先选 bf16(training_args.py) |
fp16/--fp16 | False | fp16 混合精度,主要面向 GPU;CPU 场景数值稳定性不如 bf16 |
use_cpu/--use_cpu | False | 强制使用 CPU;为 True 时同时关闭dataloader_pin_memory(training_args.py) |
per_device_train_batch_size | 8 | 每设备训练 batch size,CPU 上受内存限制需下调(training_args.py) |
learning_rate | 5e-5 | 初始学习率(training_args.py) |
num_train_epochs | 3.0 | 训练轮数(training_args.py) |
output_dir | 必填 | checkpoint 与最终模型输出目录(training_args.py) |
下一步建议
- 单机验证:先跑通"单 CPU + bf16"场景(使用 run_qa.py),再叠加多进程/多节点;依赖清单见 requirements.txt。
- 想要在
Trainer之外做更精细的 CPU 调优(如torch.compile、更细粒度线程绑定),可结合仓库的 Dockerfile 体系 与性能相关文档继续深入。 - 关于 bf16 在现代 Intel 硬件上的性能收益,可阅读社区博客《Accelerating PyTorch Transformers with Intel Sapphire Rapids》一文获得更深入的背景知识。
【免费下载链接】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),仅供参考