news 2026/9/9 20:45:38

Transformers 在 CPU 上的高效训练实战指南:bf16 混合精度、Intel MPI 多路/多机扩展与 Kubernetes 部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Transformers 在 CPU 上的高效训练实战指南:bf16 混合精度、Intel MPI 多路/多机扩展与 Kubernetes 部署

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_cpubf16并不只是"表面传参",它们在 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)甚至多节点。文档给出了三种典型形态:

  1. 单 CPU:单机单进程,启用 bf16 即可;
  2. 单机多进程:一台机器上每个 CPU socket 跑一个进程;
  3. 多机多进程:跨多台机器扩展。

文档中的分布式示例统一采用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 机器、四个进程

当单机资源不足时,可将训练扩展到两台机器(示例中为node0node1),每台机器 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 分布式训练。

部署前需要完成的四项准备

  1. 拥有已安装Kubeflow的 Kubernetes 集群;
  2. 安装并配置kubectl以便操作集群;
  3. 准备一个PersistentVolumeClaim(PVC),用于存放数据集与模型文件;
  4. 为训练脚本及其依赖构建Docker 镜像

定制 Docker 镜像

文档示例从 Intel 优化版 PyTorch 基础镜像出发——该镜像自带多节点 CPU 训练所需的 MPI 支持——并额外安装两个关键性能库:

  • google-perftoolslibtcmalloc):相比系统默认分配器,能显著降低内存分配开销;
  • libomp-devlibiomp5):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

对该清单的几个关键设计点做深入解读:

  1. 弹性策略(elasticPolicy):采用 c10d 作为 rendezvous 后端,minReplicas: 1maxReplicas: 4允许 worker 数量在 1~4 间弹性伸缩,maxRestarts: 10控制重启上限;torchrun会自动适配该弹性语义。
  2. CPU 资源单位(CPU units):Kubernetes 中 1 个 CPU 单位等于 1 个物理核或 vCPU。将limitsrequests设为相同值(240 CPU / 128Gi 内存)可让 pod 获得Guaranteed级服务质量;同时应留出部分核给 kubelet 与系统进程。
  3. OMP_NUM_THREADS与 CPU 配额对齐:环境变量应等于分配的 CPU 单位数(示例 240),确保 PyTorch 的 OpenMP 线程池能覆盖全部可用核。
  4. LD_PRELOAD注入两个性能库:把libtcmalloc(内存分配)与libiomp5(Intel OpenMP 运行时)以预加载方式挂入进程,与前面 Dockerfile 中安装的google-perftoolslibomp-dev相呼应。
  5. 缓存与共享内存HF_HUB_CACHEHF_DATASETS_CACHE指向 PVC 挂载路径/tmp/pvc-mount,避免每次启动重新下载;/dev/shm使用内存型emptyDir,为 dataloader 多进程共享提供足够空间。
  6. 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/--bf16False启用 bf16 混合精度;CPU 训练优先选 bf16(training_args.py)
fp16/--fp16Falsefp16 混合精度,主要面向 GPU;CPU 场景数值稳定性不如 bf16
use_cpu/--use_cpuFalse强制使用 CPU;为 True 时同时关闭dataloader_pin_memory(training_args.py)
per_device_train_batch_size8每设备训练 batch size,CPU 上受内存限制需下调(training_args.py)
learning_rate5e-5初始学习率(training_args.py)
num_train_epochs3.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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 20:41:48

MQTT系统主题$SYS全解析:从原理到监控实践

做物联网这几年&#xff0c;MQTT算是我打交道最多的协议。不管你是搞嵌入式、写后端&#xff0c;还是做上位机&#xff0c;只要你的项目里出现过设备上报、指令下发&#xff0c;大概率都绕不开它。而说到MQTT&#xff0c;有一个特别容易被人忽略、却又特别重要的东西&#xff0…

作者头像 李华
网站建设 2026/9/9 20:40:10

物流大数据分析平台全解析:从Hadoop到机器学习预测的完整实践

每年毕业季都会被同一个问题轰炸&#xff1a;“大数据方向毕设到底选什么题&#xff1f;”我的答案一直是——做一个物流大数据分析平台。不是因为物流概念火&#xff0c;而是这个题目能把Hadoop、Spark、Hive、机器学习、深度学习一整条大数据技术链全部串起来&#xff0c;既有…

作者头像 李华
网站建设 2026/9/9 20:38:19

华为耳机单耳补配指南:丢一只不再买全套

丢耳机这事&#xff0c;只有真丢过的人才懂有多崩溃。尤其是TWS真无线耳机&#xff0c;早上出门还好好的&#xff0c;到公司一摸耳朵发现右耳空了&#xff0c;翻遍包和口袋都没有&#xff0c;那一刻真的想哭。以前遇到这种情况&#xff0c;基本只有两条路&#xff1a;要么花大几…

作者头像 李华
网站建设 2026/9/9 20:37:51

AI Agent记忆系统:从跨会话连续性到工程化落地

1. 为什么“让 Agent 记住你”不是功能升级&#xff0c;而是范式切换&#xff1f; “走进AI Agent第三篇&#xff1a;让 Agent 记住你”——这个标题乍看像一个普通功能点&#xff0c;但实际踩中了当前Agent落地最深的断层带。我从2022年第一批用LangChain搭客服Bot开始&#x…

作者头像 李华