news 2026/9/10 21:10:59

如何用 annotated_deep_learning_paper_implementations 的 Zero3 显存优化微调 GPT-NeoX 小模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何用 annotated_deep_learning_paper_implementations 的 Zero3 显存优化微调 GPT-NeoX 小模型

如何用 annotated_deep_learning_paper_implementations 的 Zero3 显存优化微调 GPT-NeoX 小模型

【免费下载链接】annotated_deep_learning_paper_implementations🧑‍🏫 60+ Implementations/tutorials of deep learning papers with side-by-side notes 📝; including transformers (original, xl, switch, feedback, vit, ...), optimizers (adam, adabelief, sophia, ...), gans(cyclegan, stylegan2, ...), 🎮 reinforcement learning (ppo, dqn), capsnet, distillation, ... 🧠项目地址: https://gitcode.com/gh_mirrors/an/annotated_deep_learning_paper_implementations

annotated_deep_learning_paper_implementations(labml-nn)提供了一套 Zero-DP 显存优化实现(代码里叫Zero3),可以把 GPT-NeoX 的参数、梯度和优化器状态切分到多张 GPU 上,从而在显存装不下整模型时仍能做多卡微调。本文的任务就是:在多张 CUDA GPU 上,用仓库里的 finetune_neox.py 脚本,借助 Zero-DP 优化器对 GPT-NeoX 做偏差参数(bias)微调,并用filter_layers把模型缩到只加载部分层的小模型。前提是你有可用的多张 NVIDIA GPU 和 NCCL 支持,并且本地已经拿到 GPT-NeoX 的 checkpoint 文件。

环境与前提

先安装库依赖。仓库 readme.md 给出的安装方式是:

pip install labml-nn

除了依赖,还要满足三个前提,缺任一项脚本都跑不起来:

  • 多张 CUDA GPU + NCCL。脚本用torch.distributed.init_process_group('nccl', ...)组建进程组,每个 rank 绑定一张cuda:{rank}。脚本启动时会打印nccl可用性,需要先确认是True
  • GPT-NeoX checkpoint 文件已就位。层权重从本地数据路径加载(见 checkpoint.py),加载用的是torch.load,不会自动下载。该模块提供了download()(其__main__会执行download(),默认n_layers=44)用于拉取这些文件。
  • 训练文本会自动下载。text_dataset.py 首次运行会下载tiny_shakespeare语料,这块不用手动准备。

微调的对象是bias 参数。finetune.py 里FineTuneBiases把每个TransformerLayer整层设成requires_grad=False,再单独放开attention.output.biasattention.qkv_lin.biasffn.dense_h_h4.bias三个 bias 让它们可训练。这正好对应 Zero3 文档里“只实现 Zero-DP、支持只训练一部分参数”的说明。

用 Zero-DP 包住 GPT-NeoX 的每一层

脚本的 finetune_neox.html 文档里,模型和 optimizer 各用一个@option覆盖:

@option(Configs.model, 'Zero3') def _model(c: Configs): from labml_nn.scaling.zero3 import Zero3Layer, Zero3Sequential _ = c.fine_tuner # 确保 fine tuner 先把可训练参数设好 modules = [] for m in monit.iterate('Zero3', c.layers): modules.append(Zero3Layer(m.to(c.device), c.rank, c.world_size, c.device, c.dtype)) model = Zero3Sequential(modules) return model @option(Configs.optimizer, 'Zero3Adam') def _optimizer(c: Configs): from labml_nn.optimizers.adam_fp16 import AdamFP16 return AdamFP16(c.model.get_trainable_chunk(), lr=c.learning_rate)

这里要做两件事:

  1. 逐层包装c.layers是 GPT-NeoX 的各层,每层被Zero3Layer包住,再一起塞进Zero3Sequential。zero3 实现 中,Zero3Layer__init__里把该层的可训练/固定参数合并、按world_size切分并scatter到各设备,然后resize_(0)释放本地完整参数的显存;Zero3Sequential再为所有层挂上fetch_streambackup_stream以及前/后层指针。
  2. 只把分片喂给优化器get_trainable_chunk()返回的是当前 rank 上那一份可训练 shard,AdamFP16只对这一份分片维护状态,而不是完整参数。

这就是 Zero-DP 省显存的来源。index.html 给出的公式是:显存降到原模型的(2 + 2 + K)·Ψ / N_d,其中Ψ是参数量、N_d是分片数、K是每参数的优化器字节数;2 + 2指 16-bit 的参数与梯度,Adam 下K = 12(fp32 参数副本 + 两个 fp32 动量)。对应地,通信量是O(3Ψ),而普通数据并行是O(2Ψ)。这是文档给出的期望关系,不是某次跑出来的固定数值,实际占用随层数与N_d变化。

缩小模型:只加载部分层(filter_layers)

默认Configs继承自 PipelineParallelTrainerConf,会加载全部 44 层。要跑“小模型”,用 model.py 里LayerGeneratorfilter_layers参数——文档原文说明它是“用来测试只有更少层的更小模型版本”,并给了{0, 1}这种“只加载前两层”的示例(见 generate 文档)。

配置里c.layersfilter_layers透传进LayerGenerator(...).load(),所以可以直接在配置里指定一个子集,例如只加载前两个 transformer 层:

# 在 experiment.configs 的字典里追加这一项,把模型缩到只有指定层 'filter_layers': {0, 1}
  • 不写filter_layers(或为None)时加载全部层;
  • 写成set时,只加载集合里索引对应的层,层数越少显存越小。

注意:filter_layers只影响加载哪些已存在的层文件,这些层的 checkpoint 文件仍需先在本地(见上一节的download())。

配置项与启动方式

脚本在 finetune_neox.py 里用experiment.configs灌入运行时参数:

experiment.configs(conf, { 'model': 'Zero3', 'optimizer': 'Zero3Adam', 'device': device, 'rank': rank, 'world_size': world_size, 'learning_rate': 3e-4, 'max_seq_len': 128, 'batch_size': 16, })

其中:

  • model/optimizer选中的是上面两个@option'Zero3''Zero3Adam');
  • devicerankworld_sizemain里按当前进程填好;
  • learning_ratemax_seq_lenbatch_size是脚本选定的训练值(覆盖基类默认);epochs沿用TrainerConf默认 16;
  • 需要小模型时,在此字典里加'filter_layers': {0, 1}

多卡启动由torch.multiprocessing.spawn负责,脚本对本机每张 GPU 起一个进程

n_gpu = torch.cuda.device_count() # 每张 GPU 起一个进程;跨多台机器需要额外的 launcher torch.multiprocessing.spawn(main, args=(n_gpu,), nprocs=n_gpu, join=True)

于是world_size就等于本机 GPU 数,rankspawn的下标(0 .. n_gpu-1)。每个进程在main里先初始化分布式、再绑定cuda:{rank}

torch.distributed.init_process_group('nccl', timeout=datetime.timedelta(seconds=30), init_method=init_method, # 默认 'tcp://localhost:23456' rank=rank, world_size=world_size) device = torch.device(f'cuda:{rank}') torch.cuda.set_device(device)

文档明确提醒:本机一卡一进程用spawn即可,跨多台机器时需要另外的 launcher——默认脚本不覆盖多机场景。

判断运行是否正常

按顺序看这几个信号即可确认 Zero-DP 微调真的在多卡上跑起来:

  1. 启动配置日志。脚本入口会用inspect打印每张 GPU 名称、n_gpusmpinccl。先确认ncclTruen_gpus与你的卡数一致——否则 NCCL 进程组建不起来。
  2. Distributed段完成init_process_group('nccl')成功、随后逐层构建Zero3Layer模型(脚本特意在进训练循环前触发conf.model,为了让日志更清晰)。
  3. 每个 step 有 loss/acc 记录。训练循环走 trainer.py 的train_epoch()tracker每步记录loss.trainacc.train;本脚本writers={'screen', 'labml'},即屏幕和 labml 面板都能看到 loss 随 step 变化。
  4. 显存按分片占用。每张卡只保留自己那份 shard,文档给出的期望占用是(2 + 2 + K)·Ψ / N_d,卡数越多单卡占用越低。

看到 NCCL 可用、Distributed段跑完、loss.train随 step 更新,即说明多卡 Zero-DP 微调成功运行;显存是否低于普通数据并行,可用你机器上的实际占用对照上面的公式判断,而不是去比对某个固定数字。

这套实现的边界

用之前先认清 index.html 明确写出的限制:

  • 虽然名字叫Zero3只实现了 Zero-DP 部分,没有实现针对残余显存的 Zero-R 优化。
  • 支持只训练一部分参数——这也决定了它天然贴合“只调 bias”这种场景,而不是全参训练。
  • 通信量O(3Ψ)高于普通数据并行的O(2Ψ),多卡间有额外通信开销。
  • 必须NCCL;一卡一进程用spawn即可,多机要自备 launcher。

filter_layers调小、world_size调大,是仓库文档给出、且都落到当前脚本上的两个直接手段:前者减少要切分的层数,后者增加分片数从而摊薄单卡显存。

【免费下载链接】annotated_deep_learning_paper_implementations🧑‍🏫 60+ Implementations/tutorials of deep learning papers with side-by-side notes 📝; including transformers (original, xl, switch, feedback, vit, ...), optimizers (adam, adabelief, sophia, ...), gans(cyclegan, stylegan2, ...), 🎮 reinforcement learning (ppo, dqn), capsnet, distillation, ... 🧠项目地址: https://gitcode.com/gh_mirrors/an/annotated_deep_learning_paper_implementations

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

企业IT管理误区与数字化转型实践指南

1. 企业IT管理的认知误区解析 "上了系统就等于做好了IT管理"——这个观点在不少企业管理者中普遍存在,尤其是传统行业数字化转型过程中尤为明显。作为从业15年的IT咨询顾问,我见过太多企业投入重金部署各类系统后,却发现运营效率不…

作者头像 李华
网站建设 2026/9/10 21:05:53

昇腾GE矩阵乘法API

aclblasGemmEx 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow …

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

MySQL MGR高可用集群部署与优化实战

1. MySQL MGR高可用集群概述MySQL Group Replication(简称MGR)是MySQL官方在5.7版本推出的原生高可用解决方案。与传统的基于binlog的主从复制不同,MGR采用Paxos协议实现多主节点间的数据一致性,提供了自动故障检测、成员管理、冲…

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

用 semaphore 限制 Go 项目单机并发数的一次流量控制优化实践

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:人工智能学习网 背景 在一次 Go 项目的性能优化中,我遇到了一个典型但容易被忽视的问题: 并发开太猛,单机反而跑得更慢…

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

OpenCore Legacy Patcher 3 步给老旧 Mac 装上最新 macOS 完整指南

OpenCore Legacy Patcher 3 步给老旧 Mac 装上最新 macOS 完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher OpenCore Legacy Patcher 是一个 Python 编…

作者头像 李华