先说一个反直觉的结论:Gemini 3 的超参数设置,最忌讳的就是把上一个开源模型的训练配置直接搬过来改两笔就跑。我接手这个项目的头一周,干的就是这种图省事的活,结果 loss 曲线像过山车,白天训着训着变 NaN,晚上换小的学习率又收敛得让人想睡觉。后来把文档里提过的所有超参数逐个对照实际训练过程捋了一遍,才算摸清楚这套模型真正吃哪一套配置。
这篇文章就把我捋出来的东西完整写下来:什么是 Gemini 3 里真正关键的超参数,每个参数控制在多少区间,不同显存规模的机器怎么抄作业,以及 loss 出问题的时候应该按什么顺序排查。无论你是第一次跑 Gemini 3 预训练,还是已经在微调阶段被参数折磨过,这份内容应该都帮得上忙。
1. 先别急着抄配置:Gemini 3 的超参数地图和大多数人的误区
1.1 三个层面的超参数同时存在,训练配置只是其中一层
很多人在理解“超参数”的时候,把它当成一个平面列表:学习率、batch size、weight decay、warmup steps……列完就完事。但 Gemini 3 这类大模型,一套能正常落地的训练配置里,其实同时叠着三个层面的参数,它们互相影响,只是平时被塞在同一个配置文件中,容易让人误以为是一回事。
第一个层面是优化器相关超参数,包括学习率、batch size、weight decay、梯度裁剪、学习率调度、warmup 比例。这是大多数人讨论“调参”时默认的范畴,也是影响训练曲线最直接的因素。
第二个层面是模型结构相关参数,比如上下文长度、Attention 层的分组方式、RoPE 位置编码的基频、dropout 比例。这些严格说不叫超参数,但它们在训练配置里以小写字母的形式出现,一旦改错,模型不是不收敛,而是直接结构变形。
第三个层面是训练策略类参数,包括梯度累积步数、检查点间隔、序列打包方式、数据采样比例、是否开梯度检查点(gradient checkpointing)、是否用流水线并行。这些参数不改变数学性质,但决定你“在有限显存下,到底能跑多大的有效批量”。
踩坑最容易发生的地方,恰恰是这三层参数被混在一起调。有人在 loss 震荡时反复调学习率,调了三天没用,最后发现是序列长度从 2048 偷偷变到了 8192,模型结构层的有效上下文变了,优化器层的参数根本没跟上。所以先画清楚这张地图,比记住任何一个数字都重要。
1.2 按敏感度把参数分成三档:“动不得”“可以微调”“大胆调”
我把 Gemini 3 训练中会遇到的所有参数,按“动了之后会不会引发连锁崩溃”分成三档。这不是学术分类,是我自己跑实验时总结出来的风险分级。
第一档“动不得”的,主要是模型结构层的核心参数:层数、注意力头数、隐藏层宽度、词表大小、归一化层的位置。这些在模型初始化时就决定了每一层的参数形状,改动等于重新造模型。实际训练中很少有人会去碰,但有一种情况很常见:从网上找了一个自称适配 Gemini 3 的 checkpoint,结果对方的头数设置和自己的 tokenizer 不匹配,加载权重时报错,不少人在这一步直接放弃。
第二档“可以微调”的,是优化器层的参数:学习率、batch size、weight decay、梯度裁剪、warmup 比例。这些参数不会改变模型结构,但会剧烈影响收敛行为。调这一档参数,是本文后面要讲的重点,也是“全攻略”的核心内容。
第三档“大胆调”的,是训练策略类参数:梯度累积步数、检查点策略、序列打包方式、数据混合比例、是否冻结 embedding 层。这类参数每个实验之间都可以改,改错了最多是训练效率下降,不会让梯度爆掉。
搞清楚这个分档之后,再去看任何一份 Gemini 3 训练配置,你就不会像没头苍蝇一样到处乱试。凡是从网上抄来的配置,先判断它的参数落在哪一档,再决定要不要动。
2. 从零配 Baseline:五个核心参数的推荐区间和它们背后的原理
2.1 学习率:Gemini 3 对学习率的敏感度超出你的预期
Gemini 3 的学习率选择,比很多同等量级的开源模型更挑剔。原因有二:一是它的词表倍数偏大,embedding 矩阵占据了大量参数,而 embedding 梯度天生噪声高,学习率稍微抬高,嵌入向量的更新就会互相打架;二是它的 DeepNorm 类结构对初始化尺度敏感,学习率一旦越过某个临界点,loss 不会平缓上升,而是直接漂移。
在 7B 参数规模下,我的推荐区间是1e-4 到 3e-4,使用 AdamW 优化器,配合线性 warmup。如果你训练的是 13B 以上规模,峰值学习率要往回收,0.8e-4 到 1.5e-4比较稳妥。这里有个反常识的点:很多人以为大规模模型需要更大的学习率来加速收敛,实际恰恰相反,参数越多,单一参数感受到的梯度越“稀薄”,学习率过高更容易造成局部剧烈震荡。
warmup 比例怎么定?通用经验是占总训练步数的 2% 到 5%。但如果你的总步数只有几千步,那 warmup 至少要有 200 步起步,否则学习率在模型还没站稳的时候就被推上去,前期很容易留下一个无法修复的坏初始状态。我一个习惯是:warmup steps = max(200, int(0.03 × total_steps)),这个公式在大多数场景下都够用。
学习率调度上,我推荐 cosine 衰减,它比线性衰减更符合大模型后期的收敛习惯。Gemini 3 的预训练里,后期 10% 步数主要是在“压实”而非“探索”,如果衰减过陡,会出现典型的“末尾冲刺式震荡”。
2.2 有效 batch size:真正决定梯度质量的是“有效批量”
很多人在配置里看到 batch size 就往下填,但对 Gemini 3 来说,单独看一个 batch size 没有意义,因为它背后还有一个有效批量(effective batch size)的概念。有效批量 = 单卡 batch size × 梯度累积步数 × 数据并行卡数 × 序列打包后的平均 tokens 数。
为什么这个概念这么重要?因为优化器更新模型时,看的是一次更新所覆盖的样本量,而不是单次前向传播的数据量。你用 4 张卡、每张卡 batch size 4、梯度累积 8 步,有效批量就是 4 × 4 × 8 = 128 条样本。只要这个数不变,单卡 batch size 从 4 改成 2,梯度累积从 8 改成 16,训练曲线几乎完全一致。
对于 7B 参数的 Gemini 3 预训练,我的一般建议是把有效批量控制在512 条样本附近,假设每条样本打包到 4096 token,那有效批量大约对应 200 万 token。这个量级可以让梯度估计足够稳定,又不会因为批量过大而陷入泛化下降。小批量(有效批量小于 128)在 Gemma 类结构上特别容易出现 loss 锯齿状震荡,那是因为梯度噪声太大,优化器在参数空间中反复横跳。
还有个容易踩的坑:很多人调整 batch size 后不调学习率。根据缩放经验,batch size 变成原来的 k 倍,学习率大致乘以 sqrt(k),但这只是起步方向,实际还要看梯度裁剪有没有在兜底。我记得一次实验里把有效批量从 256 涨到 1024,按公式把学习率从 2e-4 提到 4e-4,结果 loss 反而炸了。后来发现,Gemini 3 在较大批量下对学习率的容忍窗口更窄,最终我只提到了 2.8e-4。所以带 sqrt 公式时,务必留出回退空间。
2.3 权重衰减:不是每个参数都该被衰减
权重衰减(weight decay)是调节 L2 正则强度的参数,AdamW 优化器里把它和参数更新解耦了,才让这个参数变得可控。Gemini 3 默认推荐值是0.1,这个数值对大多数 7B-30B 规模的语言模型都适用。
但真正的问题不是“衰减多少”,而是“对谁衰减”。所有归一化层的 gamma 和 beta、所有 bias 项,以及 RoPE 位置编码的频率参数,都不应该参与权重衰减。它们的梯度信号本来就不该被往零方向拉。如果不做分组,直接对所有参数统一 weight decay,常见后果是训练后期 loss 下不去,模型表现“僵持”,怎么调学习率都没用。
参数分组是必须写进代码的一件事。下面是一段我在本地跑的 Python 风格配置,基于常见深度学习框架的命名习惯,把该衰减和不衰减的分开处理:
def build_param_groups(model, lr, weight_decay=0.1): decay = [] no_decay = [] decay_names = [] no_decay_names = [] for name, param in model.named_parameters(): if not param.requires_grad: continue if ("layernorm" in name or "rmsnorm" in name or "bias" in name or name.endswith(".freq")): no_decay.append(param) no_decay_names.append(name) else: decay.append(param) decay_names.append(name) return [ {"params": decay, "weight_decay": weight_decay, "lr": lr}, {"params": no_decay, "weight_decay": 0.0, "lr": lr}, ]调试的时候,把这分组打印出来看一眼最保险。我遇到过有人抄了配置但优化器只接收了一组参数,导致 bias 也被衰减,训练速度慢了 20%,loss 还略高。说到底,0.1 这个权重衰减值本身并不复杂,复杂的是“衰减作用域”是否正确。
2.4 梯度裁剪:max_grad_norm 的压线取值
梯度裁剪是整个超参数体系里最容易被忽略、又最能救命的参数。对 Gemini 3 来说,我推荐的默认值是max_grad_norm = 1.0,大多数 7B-70B 规模的预训练任务都能在这个取值下稳定运行。
为什么是 1.0,不是 10.0 或者 0.1?因为大模型里偶尔出现的极大梯度,往往只集中在少数几个参数上,这些尖峰式的梯度如果不裁剪,会把参数推出当前最优区域;反过来,把裁剪值压到 0.1 以下,又会把所有梯度的方向信息都按比例压缩,相当于给优化器蒙上一层滤镜,收敛会变慢。1.0 是“切断尖峰,但不动主干”的平衡点。
如果你的训练使用了混合精度,尤其是半精度,我会建议把裁剪值收到0.3 到 0.5之间,因为精度缩放的过程会放大数值误差,梯度范数本身就偏大。如果损失出现 NaN,但数据检查后没发现问题,优先顺序是:先降学习率,再降梯度裁剪值,两者一起降也可以。比例上没有硬性标准,我几次实测下来,学习率降到 70%、裁剪值从 1.0 改到 0.5,比单纯把学习率降到 50% 更能保留训练进度。
2.5 上下文长度与第二阶段长文本续训的取舍
Gemini 3 的上下文长度,在训练里其实扮演着双重角色:它既是一个结构参数(决定位置编码覆盖范围),又是一个显存参数(决定单条序列占用多少激活内存)。很少有人注意到,它在超参数列表里还影响了“有效批量”的计算口径。
我的建议是,预训练阶段不要一上来就拉长上下文。从 2048 起步训练到 loss 稳定,再把上下文长度翻倍到 4096 或 8192 做第二阶段续训。这样做的好处是,短上下文训练时的算力密度高,同样的 token 数量下能更快把语言能力铺开;长上下文续训只需要少量步数,模型就能学会长距离依赖。
进入长上下文阶段时,注意力计算量按序列长度的平方上涨,所以对应的 batch size 必须减半甚至减到四分之一。此时有效批量可能出现断崖,解决办法不是硬撑大 batch,而是适当调低学习率——比如短上下文阶段峰值是 2e-4,长上下文阶段改成 1e-4,给模型更保守的更新步长,防止注意力分布还没来得及适应就剧烈变化。
3. 按显存规模直接抄:单卡、单机多卡、多机训练的配置清单
3.1 24G 显存单卡:LoRA/QLoRA 的落地配置
我自己在 24G 显存单卡上跑 Gemini 3,基本只做 LoRA/QLoRA 微调,不做全量预训练。下面这一组配置是我多次实验后觉得比较省心的起点:
| 参数名 | 推荐值 | 说明 |
|---|---|---|
| LoRA rank | 64 | 任务数据量小就降到 16,数据量大再升到 128 |
| LoRA alpha | 128 | alpha 通常设为 rank 的 1 到 2 倍 |
| 微调学习率 | 2e-4 | 只更新 LoRA 参数时的常用学习率 |
| target_modules | 注意力层 q/k/v/o | 不要一上来就加 MLP 层 |
| 单卡 batch size | 2 | 再大容易爆显存 |
| 梯度累积步数 | 8 | 让有效批量达到 16 条样本以上 |
| 序列长度 | 4096 | 可伸缩,显存紧张就降到 2048 |
| weight decay | 0.05 | 比预训练阶段略低 |
| 梯度裁剪 | 1.0 | 默认值即可 |
单卡最核心的限制是“有效批量”很难堆大,而 LoRA 因为只更新少量参数,对批量大小的容忍度反而更高。我实测下来,有效批量在 8 到 32 之间,LoRA 微调的最终效果差别不大;但低于 4 的时候,模型表现会明显不稳定。
3.2 单机 4×80G:中规模继续预训练的配置与通信开销
如果手里有四张 80G 显存的卡,就可以跑 7B 规模的继续预训练了。下面是我跑 30B 到 100B token 时用的一套稳定配置:
| 参数名 | 推荐值 | 说明 |
|---|---|---|
| 数据并行卡数 | 4 | 7B 规模不需要张量并行 |
| 每卡 batch size | 2 | 每条序列 4096 token |
| 梯度累积 | 8 | 有效批量大约 256 条样本 |
| 峰值学习率 | 1.2e-4 | 比基准略低,稳定优先 |
| warmup steps | 300 | 约占总步数 3% |
| weight decay | 0.1 | 标准值 |
| 梯度裁剪 | 1.0 | 默认 |
| 序列长度 | 4096 | 前置阶段用 2048,此处翻倍 |
| 优化器 | AdamW | beta1=0.9, beta2=0.95 |
| epsilon | 1e-8 | 低精度下可以调到 1e-6 |
这里最容易被忽略的是通信开销的隐形成本。数据并行下每步都要做梯度同步,如果有效批量叠得过大,训练步数会变少,但每一步因为通信等待变长,总吞吐反而下降。我踩过一次坑:把每卡 batch size 从 2 调到 4,满心以为能翻倍吞吐,结果梯度同步压力变大,加上激活内存暴涨,实际每秒处理的 token 数反而掉了 30%。
在 4 卡规模下,一般不需要开张量并行。7B 模型每一层的参数量不大,张量并行的切分通信成本高于收益。真正需要关注的是把梯度累积和通信 overlap 打开,让梯度还在通信的时候,下一批数据已经开始前向计算。
3.3 多机多卡:容易被忽略的并发隐式超参
多机训练的情况更复杂,因为除了模型超参数,还要面对一批“并发隐式超参”。它们在配置里经常不起眼,但决定成败:
# 训练脚本里常被忽略的隐性配置示例 --zero-stage 2 --micro-batch-size 1 --tensor-parallel-size 8 --grad-sync-offload true --overlap-comm true --sequence-parallel true- zero-stage 2 适合中等规模,zero-stage 3 会把优化器状态切分到所有机器,显存省了,但通信量上了一个台阶。
- micro-batch-size 是流水线并行里单次送入的微批次,建议从 1 起步,显存有余量再往上加。
- tensor-parallel-size 在多机场景要谨慎。跨机通信带宽远低于机内,张量并行切分后,每次前向都要跨机传激活,速度可能不升反降。
- overlap-comm 打开后,梯度通信与计算重叠,吞吐提升明显,但要注意日志里显存占用会多一小块。
多机训练时,学习率和 batch size 的推荐区间和单机多卡一致,不要因为机器变多就盲目扩大有效批量。很多分布式训练翻车都不是数学参数错了,而是这些并发参数没调平衡,导致 GPU 利用率上不去。判断标准很简单:看训练日志里的“每秒处理 token 数”,如果它低于单机多卡的水平,先别改学习率,去调并发参数。
4. loss 异常别硬扛:一条从现象到根因的排查链路
4.1 loss 直接变 NaN:先查数据,再查学率,最后才怀疑精度
训练跑着跑着,loss 突然变成 NaN,是所有调参人最头皮发麻的瞬间。我总结了一套排查顺序,按优先级从高到低:
第一步查数据。检查数据里有没有 NaN 或 inf。大模型训练会把多个序列打包到一条样本里,如果一个字段里有脏数据,前向计算的 loss 就会直接变成非数。这个步骤很多人跳过,但概率其实不低,尤其是从公开数据集中清洗出来的语料,经常混入二进制乱码。
第二步查学习率的峰值。如果数据没问题,那就是峰值学习率太高了。Gemini 3 在某个 step 之后梯度会随机出现尖峰,学习率恰好踩在高位时,一个尖峰就能让权重更新位移过大,loss 直接失稳。把峰值学习率下调 30%,很多时候能救回来。
第三步查混合精度的缩放因子。低精度训练里,loss 变成 NaN 可能是因为缩放因子溢出。把 loss scaling 关闭、改成动态缩放,或者把优化器 epsilon 调大一个数量级,有时就解决了。
第四步才怀疑模型结构。如果以上都没问题,可能是某个结构参数与 checkpoint 不匹配。我看过最离奇的一次,是位置编码的频率初始化范围不一样,导致前向数值随序列长度指数膨胀。
排查的时候,不要连续改多个参数。我见过有人一次把学习率、batch size、weight decay 全改了,然后发现还是 NaN,根本不知道是哪个改动起了反作用。正确的做法是:每验证一步只动一个变量,跑 20 步,看 loss 的变化趋势再往下一步。
4.2 loss 反复震荡:有效批量不足比学率过高更常见
loss 不崩也不降,就在某个区间来回跳,这种情况我称之为“震荡型不收敛”。在 Gemini 3 上,我遇到最多的原因不是学习率过高,而是有效批量太小。
有效批量不足时,每个 batch 的梯度方向差异很大,优化器像在黑暗中走路,左脚一步偏左、右脚一步偏右,整体前进速度被噪声抵消掉。这时候把梯度累积步数往上加,让一次更新看到更多样本,loss 震荡的幅度通常会肉眼可见地收窄。
另一个震荡来源是学习率调度形状太激进。如果 cosine 衰减的周期太短,模型在前 80% 步数里一直保持高学习率,后期快速下降,就会出现尾段震荡。我的经验是把 warmup 稍微拉长,给模型更多时间在低学习率下站稳,震荡会缓解很多。
还需要看数据采样是否均匀。Gemini 3 如果同时混合了多个来源的数据,而某个来源的样本在某个阶段被集中抽到,那 loss 会周期性上升。这种情况不要调参,去看数据加载器是否做了 shuffle,以及是否是流式读取。
4.3 收敛慢到像被卡住:先分清“欠训练”和“平台期”
loss 一直在平缓下降,但幅速越来越慢,很多人会着急去调学习率。其实这里最容易犯的错误是误判:你看到的“收敛变慢”,很可能是模型进入了平台期,正在为下一轮能力突变积蓄力量。
判断方法很简单:把学习率临时提回原来的 1.5 倍,跑几个 step,观察 loss 是否明显下降。如果下降明显,说明确实是学习率衰减太快或批量太大导致的欠训练;如果 loss 还是平缓,那说明模型就是在稳定推进,不需要干预。
另一个有效做法是看 token 级困惑度,而不是只看 step 级的 loss。有时候 loss 曲线看起来平了,但验证集上某些能力类别的指标还在稳定上涨,这说明训练没有卡住,只是单一指标有盲区。我在训练到第 60B token 时就是被 step loss 的“平台”骗了,差点提前终止训练,后来看了子集指标才确认模型还在持续进步。
5. LoRA/QLoRA 微调:哪些参数要动,哪些参数干脆别碰
5.1 LoRA 四个参数的实际含义与推荐区间
LoRA 微调是大多数人真正会接触 Gemini 3 的场景,因为不需要几十张卡。它的核心参数其实就四个:rank、alpha、target_modules、dropout。
rank决定低秩矩阵的宽度。rank 太小,表达能力受限,任务学不透;rank 太大,参数量上去,显存和过拟合风险都上升。我的推荐区间是16 到 128。数据量在几千条时用 16 到 32,数据量超过十万条时再往 64 以上走。
alpha是一个缩放系数,它和 rank 共同决定 LoRA 分支的最终影响强度。alpha 不是学习率,不能直接套“越大越好”的思路。经验公式是 alpha 取 rank 的1 到 2 倍,比如 rank=64,alpha=128。如果任务需要更强拟合,可以先加 alpha 而不是先加 rank,因为 rank 变大带来的是参数量的平方级增加,而 alpha 只是线性放大。
target_modules决定在哪些模块上注入低秩分支。我建议先覆盖注意力层的 q/k/v/o 四个投影,这是 LoRA 微调收益最明显的部分。MLP 层的门控和上下投影要不要加,取决于任务类型:如果是复杂推理任务,加了 MLP 层能提高上限;如果只是简单指令跟随,加上反而容易过拟合。
LoRA 的 dropout 推荐取0.05 到 0.1,比全量微调高一点没关系,因为 LoRA 本身的参数空间小,一点正则就能起到稳定作用。
5.2 冻结策略:embedding 该不该一起调
微调 Gemini 3 时,embedding 层是否解冻,是个争议比较大的选择。我的判断标准很简单:微调数据和预训练分布差异大不大。
如果微调任务的数据风格和预训练语料差距很大,比如预训练语料是通用文本,而任务数据是某种专业代码或特殊格式,那 embedding 层应该解冻或者增加可学习的额外 embedding,否则模型连基本的输入表示都调整不了。
如果微调数据量很小,比如只有几万条,我强烈建议冻结 embedding 层。因为 embedding 参数量巨大,小数据量下更新它极易过拟合,而且会把原本稳定的表征空间打乱。一个经验值是:数据量少于 10 万条时,冻结 embedding;超过 10 万条时,可以尝试解冻并用更小的学习率(单独设为全量的 0.1 倍)。
5.3 微调阶段 dropout 的选择:和预训练完全相反的情况
预训练时把 dropout 调到 0 是常见操作,因为大规模数据本身就是最强的正则,dropout 只会浪费算力、拖慢收敛。但微调场景完全相反:数据量小,模型容量大,不控制 dropout 很容易过拟合。
在 LoRA 微调时,我会把注意力层的 dropout 保持在一个较低水平,比如0.05,分类头或 LM 头的 dropout 可以提到0.1到0.2。如果训练曲线的训练 loss 和验证 loss 开始分叉,优先加大 dropout,而不是降学习率。因为分叉说明是过拟合,降学习率只能拖慢训练,治标不治本。
另外,微调阶段千万不要动预训练位置编码的频率等结构参数。很多微调框架在加载 checkpoint 时提示“位置编码参数未使用”,这时不要强制修改,保持原来的配置即可。
6. 我的调参顺序,以及一次从“崩了”到“欠训练”的完整复盘
6.1 固定其它变量,先扫学习率:一个能直接改的搜索模板
我调 Gemini 3 的顺序非常固定:先固定 batch 和调度,扫峰值学习率;确定学习率后,再扫有效批量;两者稳定后,最后微调 weight decay 和梯度裁剪。这个顺序能最大程度减少变量之间的干扰。
扫学习率不需要太精细,用几档离散值就够:
learning_rate_candidates = [ 4e-5, 8e-5, 1.2e-4, 2e-4, 3e-4 ] for lr in learning_rate_candidates: config = baseline_config.copy() config["lr"] = lr trainer = build_trainer(config) trainer.train(max_steps=500) eval_loss = trainer.evaluate() print(f"lr={lr:.2e}, eval_loss={eval_loss:.4f}")跑 500 步的 warmup 版实验,观察验证集 loss,而不是训练 loss。训练 loss 一定越低越好的错觉会误导人,有时候学习率太高前期训练 loss 降得飞快,但验证集已经在恶化了。
确定学习率后,再扫有效批量。方法是在同样的总训练步数下,比较不同 batch size 的收敛速度。不要只看 loss,还要看“有效批量翻倍后,学习率是否同步调整”。很多搜索模板不会提醒你这一点,但如果你扫 batch 时不调学习率,结论基本没有参考价值。
6.2 一次 30B→100B tokens 训练中的参数演化记录
讲一次我实际经历的项目,模型规模 7B,任务是从 30B token 继续训练到 100B token,目标是在保持通用能力的前提下,显著提升一份长文本数据上的结构化推理能力。
第一阶段从 30B 到 60B,我沿用了网上流传的默认配置:峰值学习率 3e-4、有效批量 512 个样本、上下文长度 2048。结果训练了不到 2000 步,loss 就开始周期性暴跌又反弹。我当时第一反应是降低学习率,连续调到 1e-4,震荡反而更明显了。后来检查数据加载,发现是长文本和短文本被打包在同一条序列里,长度差异导致梯度方向混乱。把数据按长度分桶后,震荡立刻消失。这个坑提醒我:调参之前先检查数据预处理。
第二阶段从 60B 到 100B,我把上下文长度翻倍到 4096,做长文本续训。这时出现了更迷惑的现象:loss 几乎完全不下降,曲线像一条平线。按网上的通用说法,这像学习率过低或模型容量饱和。但我没有急于调参,而是用临时把学习率提到 2.5 倍做了几轮测试,发现 loss 有小幅下降,随后又回落。这说明模型状态正常,只是长上下文的注意力分布还在适应中。我保持学习率不变,又跑了 3000 步,loss 才开始进入正常下降通道。
最终这套训练的参数演化记录是这样的:
| 阶段 | 学习率 | 有效批量 | 上下文 | 备注 |
|---|---|---|---|---|
| 30B→60B 初期 | 3e-4 | 512 样本 | 2048 | 数据打包问题导致震荡 |
| 30B→60B 修正后 | 2e-4 | 512 样本 | 2048 | 稳定收敛 |
| 60B→100B 长文本续训 | 1.2e-4 | 256 样本 | 4096 | 初期平台期,保持配置后恢复 |
这次复盘的结论是:看似崩了的训练,很多时候不是超参数错了,而是观察的时间尺度太短。平台期可能是模型在完成内部表示的重新组织,急着调参反而会把模型从正在构建的稳定结构中推出去。
6.3 最后留下的两条护命经验
把这几年的调参体验浓缩成两条最想告诉后来者的话。
第一,每次实验只改一个变量,并且把改动前的完整配置存档。我见过太多人在遇到 loss 异常时,一边改学习率一边改 batch size 一边改权重衰减,最后问题解决了,但不知道是哪个改动起的作用,下次碰到同样问题还要重新踩一遍。建一个实验记录表,记录每个 run 的十个核心超参数,以及 loss 曲线的截图。这件事只需要十几秒,但能省下后面几十个小时的调试时间。
第二,不要迷信“标准配置”。网上流传的默认参数,来自各种不同的模型规模和训练数据,Gemini 3 自己的结构和数据配比决定了它有一组属于自己的参数区间。你拿到的 baseline,只是调参的起点,不是调参的终点。真正的调参,是在理解每个参数作用的基础上,用最短的时间找到适合你数据和任务的那组值。
最后再分享一个小技巧:训练前把warmup 和梯度裁剪先设好,永远不要等出问题再去补。这两个参数像安全带,平时感受不到存在,但一遇到陡峭梯度或数据异常,它们就是能把训练拉回来的最后一道防线。Gemini 3 的超参数设置没有一劳永逸的标准答案,但有了这份参数地图和排查链路,你会少走很多弯路。