ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

modded-nanogpt 短赛道 140.7s 记录剖析:Backout 残差回退机制与标量参数收敛调优实战

modded-nanogpt 短赛道 140.7s 记录剖析:Backout 残差回退机制与标量参数收敛调优实战 人工智能大模型预训练分布式训练模型优化深度学习【免费下载链接】modded-nanogptNanoGPT (124M) in 90 seconds项目地址https://gitcode.com/GitHub_Trending/mo/modded-nanogpt点击查看免费下载导读本文以 records/track_1_short/2025-10-04_Backout/README.md 为核心文档完整解析 modded-nanogpt 短赛道track 1中Backout这次提交的三项关键改动新增的残差流回退backout机制、紧跟上一记录的超参数收敛调整迭代步数、冷却比例、Adam beta1以及将可学习标量参数从 72 个精简到 64 个的性能优化。读完本文你将理解为什么标准 Transformer 的残差流需要上下文与预测两职分离、如何通过逐层 lambda 系数选择回退层以及参数总数恰好能被 GPU 数整除这一系统级优化细节为什么能同时降低训练损失波动并缩短 1.8 秒运行时间。一、背景残差流承担的双重职责冲突标准 Transformer 中每一层 Transformer block 都会把自身输出累加到残差流residual stream上。modded-nanogpt 的 Block 实现见 records/track_1_short/2025-10-04_Backout/514e7581-fbd4-4338-a3e4-e556f9c958ce.txt也是典型写法def forward(self, x: Tensor, x0: Tensor, lambdas: Tensor, attn_args: AttnArgs): x lambdas[0] * x lambdas[1] * x0 if self.attn is not None: x x self.attn(norm(x), attn_args) if self.mlp is not None: x x self.mlp(norm(x)) return x原文档指出这种结构下残差流上的每一份贡献必须同时服务两个目的为下游层提供上下文context中间层计算出的特征需要继续向前传递供后续层加工直接参与最终预测final prediction残差流末端会接 lm_head 计算 logits。问题在于有些信息对下游上下文很有价值但对最终预测没有直接用处。如果这些仅供上下文使用的中间层贡献被保留到最后一层就会污染 logits模型不得不额外学习一套抵消逻辑浪费容量和训练步数。Backout 的思路很直接既然前若干层贡献主要服务于下游上下文那么在进入 lm_head 之前把这些贡献按一个可学习的系数回退/减掉back out只留下真正与预测相关的部分。这正是 原文档 所实现的上游 PR #138by snimu的核心思想只是针对短赛道做了进一步调参。二、Backout 机制的层选择用逐层 lambda 系数说话实现 Backout 前作者先做了一个per_layer 版本的实验为每一层单独分配一个回退系数训练后观察这些系数的大小以此判断哪些层的残差贡献应被回退。原文档给出了实测得到的系数序列[0.5400, 0.4613, 0.4364, 0.3429, 0.2675, 0.3030, 0.2023, 0.3761, -0.0741, -0.2164, -0.2905]这个序列的信息量很大前 8 层索引 0~7系数均为正数值从 0.20 到 0.54 不等说明这些层的残差贡献在最终预测阶段应被显著削弱回退第 9~11 层索引 8~10系数为负说明深层贡献应当保留甚至增强它们才是预测相关信息的主来源。基于此作者选定第 8 层之后执行回退在 forward 循环中当i 8时快照当前残差流x_backout x最后在 lm_head 之前执行if i 8: x_backout x # back out contributions from first 8 layers that are only required for downstream context and not direct prediction x - backout_lambda * x_backout x norm(x) logits self.lm_head(x)其中backout_lambda是一个可学习标量初始化为0.5由 Adam 优化器训练。对应到记录中的完整训练脚本514e7581-fbd4-4338-a3e4-e556f9c958ce.txt 中GPT.forward流程为x_backout None for i in range(1, len(self.blocks)): ... x self.blocksi if i n: skip_connections.append(x) if i 8: x_backout x # backout contributions from first 8 layers ... x - backout_lambda * x_backout x norm(x) logits self.lm_head(x) logits 30 * torch.sigmoid(logits / 7.5) # tanh softcapping这里还顺带能看到当时模型栈的其他组件smear 门控token embed 前向平移一个位置、U-net 式 skip connection、block lambdas 残差混合、QK norm、YaRN 窗长调度等Backout 是叠加在这些机制之上的最后一环。三、超参数收敛调整2380 → 2290 步的收紧紧随上一个记录146.9s本次提交在优化超参上做了三处收敛调整目标是以更少的步数达到同等或更低的验证损失超参数旧值新值说明num_iterations23802290总训练迭代步数减少 90 步cooldown_frac0.40.45学习率冷却阶段占总训练的比例延长冷却时间Adambeta10.70.65一阶矩衰减系数调低这三项在记录脚本的Hyperparametersdataclass 与优化器初始化中均有对应实现514e7581-fbd4-4338-a3e4-e556f9c958ce.txtclass Hyperparameters: train_batch_size: int 2048 * 16 * 8 train_max_seq_len: int 128 * 16 num_iterations: int 2290 # number of iterations to run iteration_extension 40 # final cooldown window size extension cooldown_frac: int 0.45 # fraction of training spent cooling down the learning rate momentum_cd_steps 50 block_size: int 128 ws_schedule: tuple (3, 7, 11)学习率调度为先稳后降的线性冷却def get_lr(step: int): x min(0.9999, step / args.num_iterations) lr 1.0 if x 1 - args.cooldown_frac: w (1 - x) / args.cooldown_frac lr w * 1.0 (1 - w) * 0.1 # 从 1.0 线性降到 0.1 return lr把cooldown_frac从 0.4 提高到 0.45意味着学习率更早开始、也更平缓地进入衰减段——这通常有利于在训练末尾稳出更低的验证损失是短赛道冲刺阶段常见的收敛手段。动量侧也有配套调度update_optimizer_params前 300 步把 Muon 动量从 0.85 线性升温到 0.95最后 50 步momentum_cd_steps再从 0.95 回落到 0.85Adam 部分则采用betas(0.65, 0.95), eps1e-8, lr0.008Muon 部分lr0.06, momentum0.95两个优化器分管理不同参数组scalars/embed/head 走DistAdamhidden matrix 与 gate 走Muon。值得注意的是训练循环里 Adam 采取隔步更新策略if step % 2 0: optimizer2.step()Muon 每步都更新这种错峰调度也是当时压榨每毫秒的手段之一。四、标量参数清理72 → 64一次整除性驱动的提速本次提交的第三项改动是清理多余的 lambda 参数把标量参数self.scalars从 72 个降到 64 个原文档给出的理由是修复了训练中的 hiccups/卡顿并节省了 1.8 秒。新的scalars构造如下原文档完整保留的代码pad (-num_layers * 5 - 2) % dist.get_world_size() self.scalars nn.Parameter( torch.cat( [ -1.5 * torch.ones(num_layers), # skip_weights - σ(-1.5) ≈ 0.18 *[ torch.tensor([1.0, 0.0]) for _ in range(num_layers) ], # block lambdas *[ torch.tensor([0.5, 0.5]) for _ in range(num_layers) ], # SA lambdas torch.zeros(1), # smear_lambda 0.5 * torch.ones(1), # backout_lambda torch.ones(pad), ] ) )按num_layers12、8 GPU 计算skip_weights 12 block lambdas 24 SA lambdas 24 smear_lambda 1 backout_lambda 1 pad 2 64即每个 GPU 恰好分到 8 个标量参数原来 72 个对应每 GPU 9 个。其中pad (-12*5-2) % 8 2保证整个参数张量长度能被world_size8整除从而适配分布式 Adam 的 reduce-scatter / all-gather 切分。作者还做了一个对照实验尝试进一步把参数数压到 56删掉 6 个多余的 skip 与 2 个 padding运行时间反而略升。结论被总结为标量参数总数取 64每 GPU 8 个时 Adam 表现优于 56每 GPU 7 个或 72每 GPU 9 个。这本质上是一个分布式优化器参数分片对齐的系统级细节——因为 DistAdam 在step()中按world_size对参数做reduce_scatter_tensor切分参数数量恰好是 GPU 数的整数倍时每个 rank 分得的切片形状完全一致、无需额外补齐kernel 与集合通信都能处于最高效的形态scalars.lr_mul 5.0即这些标量以 5 倍学习率训练。五、计时与验证统计显著性检验的实战用法短赛道提交以固定验证损失目标3.28下谁更快为评价标准因此本次提交给出了 5 次重复运行的验证损失与墙钟时间并用统计检验证明确实优于 3.28 阈值import scipy.stats import torch losses [3.2772, 3.2796, 3.2781, 3.2783, 3.2769] times [140.626, 140.678, 140.693, 140.718, 140.769] print(p%.4f % scipy.stats.ttest_1samp(losses, 3.28, alternativeless).pvalue) # p0.0070 print(losses:, torch.std_mean(torch.tensor(losses))) # losses: (tensor(0.0011), tensor(3.2780)) print(time:, torch.std_mean(torch.tensor(times))) # time: (tensor(0.0525), tensor(140.6968))结果解读单样本 t 检验alternativeless检验平均损失 3.28得到p 0.0070在 0.01 显著性水平下拒绝原假设即平均损失显著低于 3.285 次运行损失均值3.2780、标准差仅 0.0011稳定性很好5 次墙钟时间均值140.6968 秒约 140.7s、标准差 0.0525 秒波动极小对照上一记录的 3 次计时为[147.189, 146.906, 146.690]约 146.9s本次一次性推进了约 6 秒。记录目录中的实际运行日志也印证了这一点514e7581-fbd4-4338-a3e4-e556f9c958ce.txt 末尾step:2250/2330 val_loss:3.2909 train_time:135812ms step_avg:60.36ms ... step:2330/2330 val_loss:3.2781 train_time:140693ms step_avg:60.38ms peak memory allocated: 29226 MiB reserved: 44076 MiB训练共2290 40iteration_extension 2330步最终验证损失 3.2781总时长 140.693 秒与 README 中列出的 5 次统计完全一致。六、运行环境与复现方式从运行日志头部可以确认这次记录的执行环境硬件8× NVIDIA H100 80GB HBM3单机 8 卡NCCL软件Python 3.10.12、PyTorch 2.10.0.dev20250926cu126、Triton 3.5.0、NVIDIA 驱动 570.148.08CUDA 12.8数据fineweb10B 训练/验证.bintrain_batch_size 2048*16*8每卡 token 数由grad_accum_steps 8 // world_size推导模型GPT-2 尺寸vocab_size50257、num_layers12、num_heads6、head_dim128、model_dim768词表向上取整到 128 的倍数50304embedding/head 用 bf16lm_head 走 FP8 自定义算子。复现入口与当前仓库保持一致run.shtorchrun --standalone --nproc_per_node8 train_gpt.py注意records/track_1_short/2025-10-04_Backout/目录下的.txt文件是自包含的完整训练脚本快照每个文件 3900 行从 FP8 自定义算子、PolarExpress、Muon/DistAdam 优化器、模型定义到训练主循环全部内联任何一次提交都可以独立回放而仓库当前主干 track_1_short/train_gpt.py 与 track_1_short/model/ 是持续演进的规范化版本后续记录又在此基础上进一步发展例如后续提交对 skip/backout 相关系数做了更复杂的吸收与重构。因此研究本次 Backout 提交时应以该记录目录内的快照为准。七、小结一次机制 调度 系统三位一体的冲刺回看这次 140.7s 记录其提升来自三个互不相同的层面缺一不可机制层Backout 让残差流从上下文与预测的双重职责中解脱出来通过逐层 lambda 系数的实证观测确定回退前 8 层这一最佳分界调度层num_iterations2380→2290、cooldown_frac0.4→0.45、Adambeta10.7→0.65以更少的步数、更长的冷却换取同等甚至更好的收敛系统层标量参数 72→64让每个 GPU 恰好分到 8 个参数规避分布式 Adam 分片的不齐整既消除训练卡顿又省下 1.8 秒。对关注 LLM 训练速度优化的开发者而言这三条路径残差流职责分离的架构洞察、用统计检验锚定收敛目标的验证方法论、以及参数总数对齐 GPU 数的分布式细节都具有直接的可迁移价值。赞分享人工智能大模型预训练分布式训练模型优化深度学习【免费下载链接】modded-nanogptNanoGPT (124M) in 90 seconds项目地址https://gitcode.com/GitHub_Trending/mo/modded-nanogpt点击查看免费下载相关推荐TypeSpec Java 客户端生成器修复 Javadoc 中 */* 内容类型导致的注释提前终止问题TypeSpec Java 客户端生成器修复 Javadoc 中 / 内容类型导致的注释提前终止问题 导读 本文基于 TypeSpec 仓库中的变更日志 .c人工智能大模型预训练分布式训练模型优化深度学习llm.c 基线复现记录Modded-NanoGPT 速度竞赛的起跑线与验证基准llm.c 基线复现记录Modded NanoGPT 速度竞赛的起跑线与验证基准 导读 本文解读 Modded NanoGPT https://link.gi人工智能大模型预训练分布式训练模型优化深度学习modded-nanogpt 记录复盘BOS 对齐数据加载与学习率冷却再调优2025-07-12 BosAlignmodded nanogpt 记录复盘BOS 对齐数据加载与学习率冷却再调优2025 07 12 BosAlign 本篇以 modded nanogpt人工智能大模型预训练分布式训练模型优化深度学习上一篇ncmdumpGUI3分钟解锁网易云音乐ncm文件让音乐真正属于你下一篇AMD Ryzen处理器深度调校从新手到专家的SMU调试工具实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表