- 人工智能
- 大模型
- 深度学习
- 分布式训练
- 预训练
- 强化学习
【免费下载链接】higgsfield
Fault-tolerant, highly scalable GPU orchestration, and a machine learning framework designed for training models with billions to trillions of parameters
导读
本文围绕 higgsfield 开源项目中的 tutorial.md 展开,系统讲解在 higgsfield 框架下完成一次大语言模型(LLM)分布式训练的完整 API 流程:如何用现成的分片模型类(如Llama70b)管理 ZeRO 分片策略、如何通过LlamaLoader加载指令微调数据、如何使用标准 PyTorch 优化器与学习率调度器、如何保存权重并推送至 Hugging Face Hub,以及梯度累积、梯度裁剪、FP16 梯度缩放等训练稳定化技巧与 Wandb 监控集成。读完本文,你将能够基于 higgsfield 的标准 PyTorch 工作流,独立编写并运行从数据准备到模型发布的端到端训练脚本。
前置:一次性安装
在开始编写训练代码前,先完成框架安装。根据 README.md 中的说明,通过 PyPI 安装即可:
$ pip install higgsfield==0.0.3安装后即可在 Python 中导入higgsfield的各个子模块。higgsfield 的分布式训练依赖多节点环境,README 中要求节点具备 Ubuntu 系统、SSH 访问以及具有免密 sudo 权限的非 root 用户;节点初始化与首次实验部署的具体步骤参见 setup.md。
一、使用分布式模型:Llama70b与分片策略
1.1 极简的分片模型接口
tutorial 的第一步是引入现成的分片模型类。higgsfield 为 Llama 2 系列提供了开箱即用的分片封装,直接继承自 PyTorch FSDP 的FullyShardedDataParallel(见 higgsfield/llama/llama.py),因此Llama70b、Llama13b、Llama7b都是"即插即用"的 FSDP 模型:
from higgsfield.llama import Llama70b from higgsfield.loaders import LlamaLoader import torch.optim as optim from torch.optim.lr_scheduler import StepLR from datasets import load_datasetLlama70b是 Llama 2 70B 的现成分片类,其内部将model_name固定为"meta-llama/Llama-2-70b-hf"(见 higgsfield/llama/llama.py),并通过参数控制分片与精度策略:
model = Llama70b( zero_stage=3, fast_attn=False, precision="bf16", )1.2zero_stage:ZeRO 分片策略
zero_stage参数控制模型参数的切分方式,与 DeepSpeed 的 ZeRO 分级语义一致(可参考 Deepspeed 与 FSDP 论文):
zero_stage=3:全分片(ShardingStrategy.FULL_SHARD),模型参数、梯度与优化器状态全部切分到各 GPU。这是训练数十亿至万亿参数模型的可行方案,能够显著扩大可训练的模型规模或单卡 batch size,代价是通信量增加(每次前向/反向都需要 all-gather 参数)。zero_stage=2:仅切分梯度与优化器状态(ShardingStrategy.SHARD_GRAD_OP),通信开销更小,但每张卡仍要持有完整模型参数。
从源码看,除 0/2/3 之外的取值(如zero_stage=1)会直接抛出NotImplementedError,zero_stage=0对应NO_SHARD(见 higgsfield/llama/llama.py),因此合法的取值是0、2、3。
此外,Llama构造函数还暴露了两个与显存优化相关的附加参数(见 higgsfield/llama/llama.py):
cpu_init_rank0:仅在 rank 0 上加载真实预训练权重,其余 rank 先在meta设备上按配置构建空模型,再通过 FSDP 的sync_module_states同步,避免每个进程重复占用大量 CPU 内存加载 70B 权重;cpu_offload:开启 FSDP 的参数 CPU offload(CPUOffload(offload_params=True)),进一步降低单卡显存占用。
1.3precision:混合精度策略
precision参数支持灵活的混合精度训练:
"bf16":纯 bf16 训练,源码中将模型整体转为torch.bfloat16(见 higgsfield/llama/llama.py)。bf16 具有与 fp32 相同的指数位宽,数值稳定性好、收敛行为更接近 fp32,非常适合对数值稳定性与收敛性要求高的深度学习任务。但需要注意:bfloat16 仅在 Ampere 及更新架构的 GPU 上原生支持,使用前请确认硬件支持。"fp16":FP16 混合精度,对应MixedPrecision(param_dtype=fp16, reduce_dtype=fp16, buffer_dtype=fp16),需要配合后面介绍的Scaler梯度缩放使用(见 higgsfield/llama/llama.py)。"bf16_mixed":bf16 混合精度策略,参数保持 fp32、规约与 buffer 使用 bf16(见 higgsfield/llama/llama.py)。
1.4fast_attn:线性复杂度的快速注意力
fast_attn利用经典技术(tiling 分块、recomputation 重计算)显著加速注意力计算,并将序列长度方向的显存占用从二次方降为线性。源码中该选项通过 Hugging Face Optimum 的BetterTransformer.transform(model)实现(见 higgsfield/llama/llama.py),适合超长序列场景。
1.5 模型内部的 FSDP 细节
除了教程中列出的三个参数,Llama在构造时还内置了两个与训练稳定性直接相关的机制(见 higgsfield/llama/llama.py):
- 自动切分策略:使用
transformer_auto_wrap_policy,将每个LlamaDecoderLayer作为 FSDP 的切分单元(transformer_layer_cls={LlamaDecoderLayer}); - 激活重计算:对每个
LlamaDecoderLayer子模块应用checkpoint_wrapper(CheckpointImpl.NO_REENTRANT),前向时不保存中间激活、反向时重新计算,进一步降低长序列训练的显存占用。
这些细节说明Llama70b并非简单包装,而是开箱即用的"生产级"分片模型。
二、准备数据:自定义 Dataset 与LlamaLoader
2.1 自定义指令微调数据集
tutorial 以 Alpaca 指令数据集为例,定义了一个标准的 PyTorchDataset,其__getitem__返回{"prompt": ..., "completion": ...}字典:
class AlpacaDataset: def __init__(self, dataset_name, split="train"): self.dataset = load_dataset(dataset_name, split=split) def __len__(self): return len(self.dataset) def __getitem__(self, idx): item = self.dataset[idx] instruction = item["instruction"] if "input" in item.keys(): prompt = ( "Below is an instruction that describes a task. " "Write a response that appropriately completes the request.\n\n" f"### Instruction:\n{instruction}\n\n### Response:" ) else: input = item["input"] prompt = ( "Below is an instruction that describes a task, paired with an input that provides further context. " "Write a response that appropriately completes the request.\n\n" f"### Instruction:\n{instruction}\n\n### Input:\n{input}\n\n### Response:" ) completion = item["output"] return { "prompt": prompt, "completion": completion, }需要说明的是:tutorial 中if "input" in item.keys()的两个分支(有输入 / 无输入)恰好写反了,这里按"有input字段时拼接### Input:,无input字段时仅保留指令"的语义修正为上面的版本。仓库中的实际示例 higgsfield/static/project/src/dataset.py 采用同样的 prompt 模板。
2.2LlamaLoader:分布式采样 + 自动分词
数据准备完成后,直接交给LlamaLoader即可(注意 tutorial 中AplacaDataset为AlpacaDataset的笔误):
dataset = AlpacaDataset("tatsu-lab/alpaca", split="train") train_loader = LlamaLoader( dataset, max_sequence_length=2048, batch_size=64*6, )LlamaLoader是torch.utils.data.DataLoader的子类(见 higgsfield/loaders/llama_loader.py),它替你完成了三件事:
- 自动分词与标签构造:内部将
{"prompt", "completion"}样本包装为TorchCompletionDataset(见 higgsfield/dataset/dataset.py)。该 Dataset 会把prompt + completion编码为 token 序列,并追加eos_token_id;超出max_sequence_length的部分截断,不足的部分填充;同时生成input_ids、labels、attention_mask三个字段。其中prompt 部分的 label 被置为-100(CrossEntropyLoss 默认忽略索引),保证训练时只对 completion 计算损失。 - 分布式采样:内部构造
HiggsfieldSampler(继承自DistributedSampler),自动读取dist.get_rank()与dist.get_world_size(),保证每个进程在训练时拿到互不重叠的数据分片(见 higgsfield/loaders/llama_loader.py)。 - 默认分词器:未显式传入
tokenizer时使用"meta-llama/Llama-2-7b-hf"对应的 LlamaTokenizer(见 higgsfield/loaders/llama_loader.py)。
关于batch_size需要特别提醒:源码中该参数名为batch_size_per_gpu,语义是每张 GPU 上的 batch size,LlamaLoader会把batch_size_per_gpu直接传给底层DataLoader(见 higgsfield/loaders/llama_loader.py)。因此 total batch =batch_size_per_gpu × world_size × 梯度累积步数。仓库示例 higgsfield/static/project/src/alpaca_bf16.py 在 70B 场景下使用batch_size_per_gpu=1、max_sequence_length=2048,与 tutorial 中batch_size=64*6(即 384)同属"按场景调整"的示例,请以实际显存与数据量为准。
LlamaLoader还透传了shuffle、seed、num_workers、pin_memory、drop_last、prefetch_factor等标准 DataLoader 参数(见 higgsfield/loaders/llama_loader.py),行为与 PyTorch 保持一致。
三、优化模型参数:标准 PyTorch 训练循环
higgsfield 的设计哲学是"遵循标准 PyTorch 工作流"(README 的 Design 章节亦强调这一点),因此优化器与学习率调度器都可以直接使用torch.optim:
optimizer = optim.AdamW( model.parameters(), lr=1e-5, weight_decay=0.0, ) lr_scheduler = StepLR( optimizer, step_size=1, gamma=0.85, )训练循环与原生 PyTorch 完全一致:模型在前向中接收LlamaLoader产出的 batch(input_ids/labels/attention_mask),返回 loss;反向传播后更新参数。
for epoch in range(3): for i, batch in enumerate(train_loader): optimizer.zero_grad() loss = model(batch) loss.backward() optimizer.step() lr_scheduler.step()Llama.__call__内部会自动把 batch 中的每个 tensor 搬运到当前进程对应的LOCAL_RANK设备,并在precision == "fp16"时自动套上torch.cuda.amp.autocast()(见 higgsfield/llama/llama.py),所以你无需自己处理设备迁移。
四、保存模型:三种导出方式
tutorial 提供了三种模型保存方式,全部由Llama内置方法实现(见 higgsfield/llama/llama.py)。
4.1 保存为 PyTorch 权重文件
model.save("alpaca-70b/model.pt")save通过save_distributed_model_rank0将 FSDP 分片状态收集到 rank 0 后保存为普通 state dict,路径统一写入主节点(rank 0)的~/.cache/higgsfield/{save_path}(见 higgsfield/llama/llama.py 与 higgsfield/checkpoint/fsdp_checkpoint.py)。
4.2 保存为 Hugging Face 格式
model.save_huggingface_model("alpaca-hf-70b")该方式先把 FSDP 状态收集到 CPU 上的完整 state dict(fsdp_model_state_dict_rank0),再在 rank 0 上按配置重建一个普通LlamaForCausalLM、加载权重后调用save_pretrained,产出与 Transformers 完全兼容的目录(见 higgsfield/llama/llama.py)。
4.3 推送至 Hugging Face Hub
model.push_to_hub("alpaca-70b")与 4.2 相同,先在 rank 0 上恢复完整模型,再调用push_to_hub(repo_id)直接推送到 Hub(见 higgsfield/llama/llama.py)。
4.4 进阶:训练中周期性 Checkpoint
如果你希望在训练过程中按 epoch/step 周期保存模型、优化器、调度器状态,可以使用仓库提供的Checkpoint类(见 higgsfield/checkpoint/fsdp_checkpoint.py),它会写入~/.cache/higgsfield/{project_name}/experiments/{experiment_name}/{run_name}/epoch_{epoch}_steps_{steps}/目录,包含model.pt、optimizer.pt、lr_scheduler.pt与metadata.json。仓库示例 higgsfield/static/project/src/alpaca_bf16.py 展示了每 30 步保存一次检查点的用法。
五、训练稳定化技巧
tutorial 强调,由于遵循标准 PyTorch 工作流,各种训练稳定化技术都可以轻松接入。
5.1 梯度累积
梯度累积用较小的显存代价模拟大 batch 训练:把loss除以累积步数后再反向,每累积满grad_accumulation_steps步才更新一次参数:
grad_accumulation_steps = 16 for epoch in range(3): for i, batch in enumerate(train_loader): loss = loss / grad_accumulation_steps loss.backward() if (i + 1) % grad_accumulation_steps == 0 or i == len(train_loader) - 1: optimizer.step() optimizer.zero_grad()注意教程示例中把loss = loss / grad_accumulation_steps放在了循环外,实际使用时请将它移到循环内、loss.backward()之前(上面代码已修正)。结合 2.2 节,LlamaLoader的batch_size_per_gpu配合梯度累积即可精确控制 global batch size。
5.2 梯度裁剪
higgsfield 提供clip_grad_norm工具(位于 higgsfield/training/grads.py),它在调用前会先对 FSDP 的梯度执行unscale_(若配合 FP16 缩放器),然后优先调用optimizer.clip_grad_norm,否则回退到 FSDP 的clip_grad_norm_,从而正确处理分片模型下的全局梯度范数:
from higgsfield.training import clip_grad_norm max_grad_norm = 1.0 for epoch in range(3): for i, batch in enumerate(train_loader): optimizer.zero_grad() loss.backward() if max_grad_norm: clip_grad_norm(model, optimizer, max_grad_norm) optimizer.step()注意仓库中该函数的签名是clip_grad_norm(max_grad_norm, model, optimizer, scaler=None)(见 higgsfield/training/grads.py),tutorial 中clip_grad_norm(model, optimizer, max_grad_norm)的参数顺序与源码不一致,实际调用请以源码签名为准(也可参考示例 higgsfield/static/project/src/alpaca_bf16.py 中的clip_grad_norm(1.0, model, optimizer))。
5.3 FP16 梯度缩放
FP16 训练中,小梯度在 16 位下容易下溢为 0。Scaler解决这一问题:前向得到的 loss 先被放大(scale),反向后再由缩放器决定是否跳过本轮更新(检测到 Inf/NaN 时)并调整缩放因子:
from higgsfield.training import Scaler, clip_grad_norm scaler = Scaler(model) for epoch in range(3): for i, batch in enumerate(train_loader): optimizer.zero_grad() scaler.scale(loss).backward() if max_grad_norm: clip_grad_norm(max_grad_norm, model, optimizer, scaler) scaler.step(optimizer) scaler.update()Scaler的底层实现会根据模型是否为 FSDP 自动选择缩放器:FSDP 模型使用torch.distributed.fsdp.sharded_grad_scaler.ShardedGradScaler(分片梯度缩放,分布式下梯度范数与缩放状态跨 rank 同步),非 FSDP 模型使用torch.cuda.amp.GradScaler(见 higgsfield/training/scaler.py)。注意该场景仅在precision="fp16"时使用,bf16 训练无需缩放。
六、监控:Wandb 集成
higgsfield 实验通过@experiment("...")装饰器定义(见 higgsfield/internal/experiment/decorator.py),装饰器自动为每个实验注入seed参数,并支持通过@param声明自定义实验参数(见 higgsfield/static/project/src/alpaca_bf16.py)。
Wandb 可以直接在项目内部使用,唯一的要求是:所有 Wandb 相关代码必须放在if params.rank == 0:条件下。因为在分布式训练中,如果每个 rank 都执行wandb.init,会造成重复的日志与资源浪费;只有 rank 0 负责初始化、记录与同步:
import wandb @experiment("alpaca") def train(params): ... if params.rank == 0: wandb.init( project="My Llama2", ) for epoch in range(1): for i, batch in enumerate(train_loader): optimizer.zero_grad() loss = model(batch) loss.backward() optimizer.step() if params.rank == 0: wandb.log({ "train/loss": loss.item(), })params.rank由 higgsfield 实验框架注入,代表当前进程在分布式集群中的全局 rank(相关参数机制见 higgsfield/internal/experiment/params.py 中的parse_kwargs_to_params)。
七、组合成一个完整实验
将以上各节组合起来,就得到了一个完整的 higgsfield 分布式训练实验。仓库中的 higgsfield/static/project/src/alpaca_bf16.py 是一个可以直接参考的完整示例,它演示了:
- 用
@experiment("alpaca_bf16")声明实验,并用@param("size", options=["7b", "13b", "70b"])、@param("num_epochs", default=1)声明可调参数; - 按
params.size选择Llama-2-7b/13b/70b模型,构建zero_stage=3、cpu_init_rank0=True、precision="bf16"的 FSDP 模型; - 构建 AdamW 优化器、StepLR 调度器与
Checkpoint; - 训练循环内每 30 步调用
checkpoint.save(epoch, i)保存检查点,训练结束后model.save_huggingface_model("my-alpaca")导出 HF 格式权重。
结合 README.md 中的说明,训练实验最终通过 GitHub Actions 工作流在分配好的节点上自动部署与运行(相关模板见 higgsfield/static/templates),开发者通过 GitHub 上的运行 UI 即可启动实验、查看日志并获取检查点。
结语
tutorial.md 的核心脉络——分布式模型、数据准备、优化、保存、训练稳定化、监控——构成了 higgsfield 面向 LLM 训练的最小可用 API 全集。得益于其"标准 PyTorch 工作流"设计,你完全可以在此基础上自由组合 DeepSpeed、Accelerate 或自研的 PyTorch 分片方案,将 higgsfield 作为大规模多节点训练的高效底座。
- 人工智能
- 大模型
- 深度学习
- 分布式训练
- 预训练
- 强化学习
【免费下载链接】higgsfield
Fault-tolerant, highly scalable GPU orchestration, and a machine learning framework designed for training models with billions to trillions of parameters
相关推荐
Jukebox训练实战:多GPU分布式训练配置与监控指南
Jukebox训练实战:多GPU分布式训练配置与监控指南 在音乐生成领域,Jukebox作为前沿的生成模型(项目描述:Code for the paper "J
人工智能大模型音乐生成音频预训练Oumi 本地训练实战指南:从单卡微调到多卡分布式训练与监控
Oumi 本地训练实战指南:从单卡微调到多卡分布式训练与监控 本文围绕 Oumi(Oumi OSS)的本地训练能力展开,完整讲解在个人笔记本或多 GPU 服务器
人工智能大模型预训练微调强化学习模型评测模型推理服务MCP 服务LLMOpsDeiT训练实战:从ImageNet数据准备到多GPU分布式训练
DeiT训练实战:从ImageNet数据准备到多GPU分布式训练 🚀 想要快速上手DeiT(Data efficient Image Transformers
计算机视觉深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考