公司动态

从公开训练日志看懂大模型训练:Loss曲线与梯度范数详解

📅 2026/8/28 13:53:55
从公开训练日志看懂大模型训练:Loss曲线与梯度范数详解
过去很多团队训练大模型外部能看到的通常只有一张模型卡、几个评测指标和一段含糊的“使用了 XX TB 高质量语料”。模型中间是怎么训练的、Loss 曲线长什么样、数据配比怎么调几乎是一个黑盒。最近社区讨论度很高的一个 535B 大模型项目把训练过程几乎“直播”了三个月训练代码、数据配比、日志脚本以及每个 step 的 Loss 曲线都公开了出来。吴恩达也在社交平台上公开认可这种开放做法。这件事对很多想深入了解大模型训练的开发者来说是一份难得的真实样本。这篇文章不是来追热点的而是想借着这次公开训练把背后几个关键技术点拆开讲清楚大模型训练日志里的 Loss、学习率、梯度范数分别代表什么一条“正常”的 Loss 曲线应该怎么读数据清洗、数据配比、评测集隔离这些工程细节到底有多重要我们自己在本地做小规模训练、微调时怎么复刻这套记录方式训练中常见的 Loss 不下降、NaN、显存不足等问题怎么排查。如果你正准备进入大模型训练方向或者已经开始做微调但总觉得“看不懂训练过程”这篇文章值得收藏后慢慢看。1. 从“黑盒”到“直播”公开训练到底公开了什么1.1 传统预训练为什么不透明大模型预训练成本极高535B 这种规模的模型一次完整训练涉及的数据清洗、并行策略、分布式通信、断点续训都非常复杂。大部分商业模型只会公布最终权重和评测结果中间过程属于核心资产不会对外开放。这就带来一个问题社区里绝大多数开发者只会“用模型”不太清楚“训模型”的真实过程。一旦遇到 Loss 不降、训练崩溃、显存溢出这类问题往往只能靠经验猜测。1.2 公开代码、数据、Loss 的意义这次公开训练的核心亮点是三件事同时开放训练代码数据加载、模型结构、分布式策略、日志记录全部可见数据信息数据来源、清洗规则、去重方式、各领域配比有迹可循Loss 实时曲线训练过程中的 Loss、学习率、梯度范数等指标定期对外公布。这三样东西放在一起相当于把一个大型预训练项目的“手术过程”完整展示出来。对于学习者来说价值非常大你可以看到真实训练中 Loss 的波动幅度而不是教科书里那条平滑下降的曲线你可以学习到数据配比如何影响模型能力你可以模仿他们的日志记录方式用在小规模训练和微调任务中。1.3 对普通开发者的价值很多人会想535B 模型我又不可能复现看这些有什么用其实换个角度就明白了。大模型训练和小规模训练在核心逻辑上是一致的都是数据进去、Loss 出来、优化器更新参数。差别只是规模、并行策略和工程复杂度。把公开训练日志当成“病例库”遇到类似曲线形态时就知道大概是什么问题这才是普通开发者能带走的东西。2. 训练背后的规模、数据与显存2.1 535B 参数意味着什么535B 参数约等于 5350 亿个参数。这是一个非常大的规模。作为对比很多开源模型还停留在 7B、13B、70B 的级别。参数规模直接影响三件事显存占用参数越多优化器状态、梯度、激活值占用的显存越大数据需求参数越多需要更多高质量 token 才能充分训练否则模型欠拟合训练成本535B 规模通常需要成千上万张加速卡训练时长以月为单位。这也是为什么这次“公开训练三个月”能引起关注——不是每个团队都有机会跑这种量级的实验但围观整个过程不需要付费。2.2 数据是大模型训练的“隐形天花板”很多时候模型效果不好不是模型结构不够强而是数据不够干净、配比不够合理。公开训练中数据部分的价值往往比模型结构更大。通过公开信息你能看到数据如何从原始网页文本清洗成可用语料重复数据如何被去重不同领域代码、数学、百科、多语种的数据按什么比例混合评测集如何与训练集隔离避免污染。这些经验可以直接迁移到微调和垂直领域模型训练中。2.3 全参训练与微调对显存要求的区别很多初学者容易把“全参预训练”和“微调”混在一起。实际上两者对显存的要求差别非常大。训练方式显存压力说明全参预训练极高需要保存参数、梯度、优化器状态535B 规模需要大规模分布式集群全参微调较高依然需要更新全部参数显存占用接近预训练LoRA 微调较低冻结原模型只训练低秩矩阵显存压力大幅下降QLoRA 微调更低在 LoRA 基础上对基座模型做量化单卡可以尝试较大模型所以并不是所有“训练”都需要超大规模算力。我们平时做垂直领域适配大多数场景用 LoRA 或 QLoRA 就够了。公开训练日志里包含的 Loss 监控方法在微调中同样适用。3. 看懂训练日志Loss 曲线与关键指标3.1 Loss 是什么为什么重要Loss 是模型预测结果与真实标签之间的差距。训练过程本质上就是通过优化器不断降低 Loss让模型输出越来越接近目标分布。对于大语言模型最常用的损失函数是交叉熵损失Cross Entropy Loss也就是让模型在正确 token 位置上的预测概率尽可能高。Loss 越低说明模型在训练数据上的拟合程度越高。但要注意Loss 低不代表模型一定好用。如果训练数据存在污染、配比失衡或者模型过拟合Loss 曲线可能很漂亮评测效果却很一般。所以 Loss 是训练过程的“温度计”不是最终“成绩单”。3.2 一条真实训练日志包含什么公开训练日志的典型字段通常包括字段含义step当前训练步数tokens_seen已经见过的 token 总数loss当前批次的平均损失grad_norm梯度范数用于观察梯度是否爆炸learning_rate当前学习率throughput每秒处理的 token 数量time当前时间或运行时长梯度范数是一个容易被忽略但非常重要的指标。如果梯度范数突然变得非常大说明梯度可能爆炸了需要降低学习率或者增加梯度裁剪。3.3 什么样的 Loss 曲线算正常没有“标准答案”但常见情况是快速下降期训练刚开始Loss 从较高位置快速下降缓慢下降期训练中期Loss 下降速度变慢曲线进入平滑区间平台期训练后期Loss 在小范围内波动整体趋于平稳。如果训练集规模足够且没有过拟合Loss 在平台期小幅波动是正常的。随着训练数据量继续增加Loss 可能还会继续缓慢下降。需要警惕的异常形态曲线形态可能原因排查方向Loss 一直不下降学习率过低/数据问题/模型结构 bug检查数据、调大学习率Loss 突然变成 NaN梯度爆炸/学习率过高/数据含 NaN加梯度裁剪检查数据Loss 剧烈震荡学习率过大/批次大小太小降低学习率增大 batch size训练 Loss 下降但评测变差过拟合或数据污染增加数据多样性检查评测集Loss 后期突然上升学习率调度异常/数据问题检查 LR schedule 和数据顺序3.4 读取与绘制训练日志Python 示例公开训练日志通常以 JSONL 或 CSV 格式提供。下面我们用一个简单的脚本读取 CSV 并绘制 Loss 曲线。# 文件路径plot_loss.py import pandas as pd import matplotlib.pyplot as plt # 读取训练日志 df pd.read_csv(training_log.csv) print(df.head()) # 中文显示避免出现方框 plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS, DejaVu Sans] plt.rcParams[axes.unicode_minus] False # 创建子图 fig, axes plt.subplots(1, 3, figsize(15, 4)) # Loss 曲线 axes[0].plot(df[step], df[loss], linewidth0.6) axes[0].set_xlabel(Step) axes[0].set_ylabel(Loss) axes[0].set_title(训练 Loss 曲线) axes[0].grid(True, alpha0.3) # 学习率曲线 axes[1].plot(df[step], df[learning_rate], colororange, linewidth0.8) axes[1].set_xlabel(Step) axes[1].set_ylabel(Learning Rate) axes[1].set_title(学习率曲线) axes[1].grid(True, alpha0.3) # 梯度范数曲线 axes[2].plot(df[step], df[grad_norm], colorgreen, linewidth0.6) axes[2].set_xlabel(Step) axes[2].set_ylabel(Grad Norm) axes[2].set_title(梯度范数曲线) axes[2].grid(True, alpha0.3) plt.tight_layout() plt.savefig(training_curve.png, dpi150) print(图像已保存为 training_curve.png)这段代码把三张最重要的小图放在一起Loss、学习率、梯度范数。实际看日志时这三张图配合观察比单独看 Loss 更容易发现问题。4. 数据公开背后的工程细节4.1 数据清洗与去重训练语料不能直接从网上抓下来就用。原始网页文本中包含大量 HTML 标签、重复段落、无意义字符需要经过多轮清洗。常见清洗步骤包括去除 HTML 标签和不可见字符按语言进行识别和过滤去除重复段落和近似重复样本过滤质量过低的短文本屏蔽个人隐私信息和有害内容。这些操作在大模型训练中看起来不起眼但对最终模型效果影响巨大。数据里一旦混入大量重复文本模型容易出现复读机现象评测时也可能因为过拟合而表现异常。4.2 数据配比与课程学习不同领域的数据对模型能力的贡献不同。比如代码数据能提升逻辑推理能力数学数据能提升计算能力百科数据能提升知识密度。公开训练数据配比的意义在于如果你发现某个能力短板可以通过调整数据比例来干预。训练中还可以使用“课程学习”策略先让模型学简单的通用文本再逐步加入更复杂的代码和数学数据。这种策略会直接影响 Loss 曲线的形态也解释了为什么真实训练曲线不是一路平滑下降而是会出现阶段性的波动。4.3 数据污染与评测集隔离数据污染是指评测集中的样本混入训练集导致评测分数虚高。公开训练项目通常会强调评测集隔离因为一旦污染所有评测结果都不再可信。我们在自己训练小模型时也要养成习惯训练集、验证集、测试集严格分开。验证集可以用于调参但测试集只能在最终评估时使用一次。这个习惯越早养越好。4.4 数据备份与版本管理训练数据同样需要版本管理。很多团队会把数据管道跑出来的结果保存成多个按时间戳命名的版本并备份到独立存储。备份策略可以参考以下建议原始数据一份、清洗后数据一份、按领域拆分的数据一份备份到不同物理位置避免单点故障记录每个版本的数据量、清洗规则、配比信息在训练日志中记录数据版本号保证可复现。千万不要小看备份。大模型训练一旦中途发现某个数据清洗步骤有问题如果没有备份回滚成本非常高。5. 从公开训练到本地实践一个最小可复现流程5.1 本地复现的挑战535B 模型不可能在个人电脑上复现但我们可以把“记录 Loss 日志、观察训练曲线、保存 checkpoint”这套流程搬到小规模任务中。本地环境建议操作系统Ubuntu 20.04 / 22.04Windows 也可以但推荐 LinuxPython3.10 或更高版本深度学习框架PyTorch 2.xGPUNVIDIA 显卡显存至少 8GB推荐 16GB 以上日志工具TensorBoard 或直接写 CSV 文件。5.2 用 PyTorch 写一个最小训练循环下面是一个完整的训练脚本用一个小型 MLP 在随机生成的数据上训练并把每个 step 的 Loss、学习率、梯度范数写入 CSV。# 文件路径minimal_train.py import torch import torch.nn as nn import torch.optim as optim import pandas as pd from torch.utils.data import DataLoader, TensorDataset # 固定随机种子方便复现 torch.manual_seed(42) # 生成随机数据集输入 20 维输出 5 类 X torch.randn(1000, 20) y torch.randint(0, 5, (1000,)) dataset TensorDataset(X, y) dataloader DataLoader(dataset, batch_size32, shuffleTrue) # 定义一个简单的三层 MLP model nn.Sequential( nn.Linear(20, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 5) ) # 损失函数和优化器 criterion nn.CrossEntropyLoss() optimizer optim.AdamW(model.parameters(), lr1e-3) # 训练 3 个 epoch记录日志 log_records [] global_step 0 for epoch in range(3): for batch_x, batch_y in dataloader: optimizer.zero_grad() outputs model(batch_x) loss criterion(outputs, batch_y) loss.backward() # 计算梯度范数 grad_norm 0.0 for p in model.parameters(): if p.grad is not None: grad_norm p.grad.norm().item() ** 2 grad_norm grad_norm ** 0.5 # 梯度裁剪防止梯度爆炸 nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) optimizer.step() # 记录日志 log_records.append({ step: global_step, epoch: epoch, loss: loss.item(), grad_norm: grad_norm, learning_rate: optimizer.param_groups[0][lr] }) global_step 1 if global_step % 10 0: print(fStep {global_step}, Loss: {loss.item():.4f}, Grad Norm: {grad_norm:.4f}) # 保存为 CSV方便后续绘图 log_df pd.DataFrame(log_records) log_df.to_csv(training_log.csv, indexFalse) print(日志已保存到 training_log.csv)这段代码虽然跑的是随机数据但训练循环的结构和 535B 大模型使用的核心流程是一致的前向传播、计算 Loss、反向传播、梯度裁剪、优化器更新、记录日志。5.3 用 Trainer 微调开源模型并留存日志如果你已经有开源模型权重想直接做微调推荐使用 Hugging Face Transformers 的 Trainer API。它内置了日志记录和 checkpoint 保存机制非常适合本地实践。下面是一个结构示意具体需要根据你的数据集调整# 文件路径finetune_example.py示例片段 from transformers import Trainer, TrainingArguments, AutoModelForSequenceClassification, AutoTokenizer model_name bert-base-uncased # 实际使用时替换为你的模型 tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForSequenceClassification.from_pretrained(model_name, num_labels2) training_args TrainingArguments( output_dir./results, # 输出目录 evaluation_strategysteps, eval_steps50, logging_dir./logs, # 日志目录 logging_steps10, # 每 10 步记录一次 save_strategysteps, save_steps100, # 每 100 步保存 checkpoint learning_rate2e-5, per_device_train_batch_size8, num_train_epochs3, fp16True, # 混合精度训练节省显存 load_best_model_at_endTrue, ) trainer Trainer( modelmodel, argstraining_args, train_datasettrain_dataset, eval_dataseteval_dataset, tokenizertokenizer, ) trainer.train()Trainer 会自动把 Loss 写入 TensorBoard 日志训练完成后在logging_dir目录下运行tensorboard --logdir./logs就能看到 Loss 曲线。5.4 从 Loss 日志到断点续训训练大模型时断点续训是保命功能。Trainer 中可以通过resume_from_checkpointTrue从最近一次保存的 checkpoint 继续训练trainer.train(resume_from_checkpointTrue)在自定义训练循环中保存 checkpoint 也只需要在训练过程中定期执行# 文件路径checkpoint_example.py片段 import torch save_path ./checkpoints/model_step_1000.pt checkpoint { model_state_dict: model.state_dict(), optimizer_state_dict: optimizer.state_dict(), step: global_step, loss: loss.item() } torch.save(checkpoint, save_path)恢复训练时再把这些状态加载回来即可。对于 535B 这种规模的模型checkpoint 管理是专门的工程模块但我们小规模训练时提前养成保存状态字典的习惯能省掉很多不必要的重跑时间。6. 大模型训练常见问题与排查清单6.1 Loss 不下降这是训练中最常见的问题。可能原因学习率太低参数更新幅度太小数据没有正确打乱模型学到的是顺序信息标签与输入不匹配模型结构存在 bug例如激活函数导致梯度消失。排查方法先用一个很小的 batch 做过拟合测试看看 Loss 能不能降到很低打印输入和标签的形状确认数据没问题尝试将学习率调大 5 到 10 倍检查 Loss 计算是否正确尤其是 padding 部分是否被 mask 掉。6.2 Loss 变成 NaNLoss 变为 NaN 通常意味着数值稳定性被打破了。可能原因学习率过高导致参数更新过大梯度爆炸尤其是深层模型数据中存在 NaN 或无穷值混合精度训练时 FP16 溢出。排查方法降低学习率增加梯度裁剪例如max_norm1.0检查数据中是否有 NaN如果使用了 FP16尝试切换为 BF16 或 FP32。6.3 Loss 震荡幅度过大Loss 小幅波动是正常的但如果震荡剧烈通常和优化参数有关。可能原因学习率过大batch size 太小数据中存在大量困难样本。解决思路降低学习率增大 batch size使用学习率预热warmup策略确保数据 shuffle。6.4 训练 Loss 下降但评测效果变差这大概率是过拟合或数据污染问题。处理建议增加训练数据多样性增加 Dropout 或正则化检查评测集是否和训练集重复如果评测集过小结果本身可能不稳定。6.5 显存不足OOM本地训练最常遇到的错误就是 CUDA out of memory。处理建议按优先级减小 batch size使用梯度累积模拟更大 batch size开启混合精度训练FP16 / BF16使用 LoRA 或 QLoRA 等参数高效微调方法释放未使用的显存缓存例如torch.cuda.empty_cache()。6.6 数据加载成为瓶颈训练时 GPU 使用率很低但 Loss 计算很慢可能是数据加载卡住了。改进方法使用DataLoader的num_workers参数增加子进程使用pin_memoryTrue将数据转换成内存映射格式减少随机读取开销提前做好空白清洗避免每次迭代都做重复解析。问题现象常见原因解决思路Loss 不降学习率过低 / 数据问题做小 batch 过拟合测试Loss NaN梯度爆炸 / 学习率过高降学习率 梯度裁剪Loss 震荡大学习率大 / batch 小预热 降学习率评测变差过拟合 / 评测集污染增加数据多样性OOMbatch 太大减小 batch / 混合精度GPU 利用率低数据加载慢增加 num_workers7. 工程化最佳实践7.1 日志记录要规范训练日志不是给自己看的还要方便团队排查和后续复现。推荐统一记录环境信息CUDA 版本、PyTorch 版本、GPU 型号数据信息数据版本、token 数量、配比信息训练信息学习率、batch size、梯度累积步数、warmup 比例实时指标Loss、grad norm、learning rate、tokens seen。每次实验保存一份完整配置避免三个月后自己都看不明白。7.2 Checkpoint 策略要合理不要只保存最后一个 checkpoint。建议按时间间隔保留多个最近 5 个 checkpoint 全保留更早的按一定间隔采样保留checkpoint 中同时保存 optimizer state否则无法断点续训定期测试 checkpoint 能否正常加载和推理。7.3 评估集隔离要严格训练集、验证集、测试集必须严格隔离。最好在数据清洗阶段就把评测集单独抽离避免后续数据管道误用。评测集污染是很多模型“看起来很强一上线就露馅”的核心原因。公开训练项目有专门的评测团队负责隔离我们个人实验也要有这个意识。7.4 分布式训练注意事项如果涉及多卡训练还需要关注使用 Distributed Data Parallel 时确保每张卡的数据不重复学习率要随总 batch size 调整日志输出要统一汇总到主进程避免多个进程重复打印梯度同步会产生通信开销需要平衡 batch size 和通信频率。很多公开训练日志里会包含 throughput 和通信利用率这些都是分布式调优的重要参考。7.5 安全与合规训练数据中如果包含用户隐私、敏感内容一定要在清洗阶段过滤掉。涉及生产环境或内部数据时还需要遵守数据使用规范提前获得授权。即使是公开数据集也要注意数据集本身的许可证。商用项目尤其要谨慎不要默认“公开可下载”就等于“可自由商用”。8. 给不同阶段开发者的学习路线8.1 新手阶段先学会“读曲线”如果你刚开始接触大模型训练不急着复现复杂模型。可以先做两件事训练一个小模型记录每天的 Loss 曲线把第 3.4 节的绘图脚本跑通学会从曲线中判断训练状态。这是成本最低的入门方式也是理解公开训练日志的基础。8.2 中级阶段跑通微调和参数高效微调接下来可以尝试在开源模型上做微调实验用 Hugging Face Transformers 微调一个 1 亿参数左右的模型对比全参微调、LoRA、QLoRA 的显存占用和训练速度学会用 TensorBoard 观察 Loss、学习率、精度等指标尝试调整数据配比观察 Loss 变化和下游评测效果。如果网络条件受限下载模型时可以配置国内镜像加速地址但具体模型需根据任务选择。8.3 进阶阶段读源码、改进数据管线当你对训练循环足够熟悉后可以开始看大模型训练框架的源码例如 DeepSpeed、Megatron-LM、Hugging Face Accelerate。重点看分布式数据并行怎么实现梯度累积和混合精度怎么集成大规模 checkpoint 怎么切分和恢复数据管道怎么做高性能加载。同时也可以尝试自己复现公开训练日志中的数据清洗流程。数据管线的优化往往比模型结构调整带来更稳定的收益。8.4 写在最后535B 大模型的公开训练是一次很不错的“开源教学案例”。它把过去少数团队才看得到的训练细节暴露在阳光下让我们这些普通开发者有机会近距离观察原来大规模训练并不是一条平滑下降的曲线原来梯度范数会突然飙升原来数据配比对模型能力的影响如此直接。如果你也想真正进入大模型训练这个方向不用一上来就想复现几百 B 的模型。先下载一份公开的训练日志用 pandas 读进来用 matplotlib 把 Loss、学习率、梯度范数画出来看看它在一个又一个 step 里是怎么变化的。这一步做完你对“训练大模型”这件事的理解会比单纯刷十篇新闻稿都更扎实。