概述为什么训练准确率高不等于模型好训练模型时经常会看到这样的现象train_acc 很高 val_acc 明显低 train_loss 持续下降 val_loss 先下降后上升这通常说明模型出现了过拟合。模型把训练集里的模式甚至噪声记住了但面对验证集或测试集时泛化不好。正则化的目标不是让训练 loss 最低而是让模型在未见数据上表现更稳。常见手段包括Dropout训练时随机丢弃部分神经元输出。weight_decay约束参数不要过大。数据增强让模型见到更多输入变化。早停验证集长期不提升时停止训练。减小模型容量降低过拟合能力。读完本文你应该能判断模型是否过拟合并能在 Paddle 中使用Dropout、weight_decay和早停策略控制过拟合。过拟合、欠拟合与正常学习先看三种训练状态状态训练集表现验证集表现常见原因欠拟合差差模型太小、训练不足、学习率不合适正常学习好好容量和正则化较合适过拟合很好较差模型太大、数据太少、正则不足可以用曲线理解正常学习 train_loss 下降val_loss 也下降 过拟合 train_loss 继续下降val_loss 开始上升 欠拟合 train_loss 和 val_loss 都高判断过拟合时不要只看一轮结果要看多个 epoch 的趋势。Dropout训练时随机关闭部分神经元Paddle 中使用dropoutpaddle.nn.Dropout(p0.5)官方文档说明Dropout 是一种正则化手段会在训练过程中按照概率p将部分神经元输出置为 0以减少神经元之间的共同适应。示例importpaddleimportpaddle.nnasnn paddle.seed(2026)xpaddle.ones([2,8],dtypefloat32)dropoutnn.Dropout(p0.5)dropout.train()y_traindropout(x)dropout.eval()y_evaldropout(x)print(train output:)print(y_train)print(eval output:)print(y_eval)训练模式下部分位置会被随机置零评估模式下Dropout 不再随机丢弃。关键点Dropout 是否生效取决于模型模式所以训练和评估时必须正确调用model.train()与model.eval()。Dropout 放在哪里MLP 中常见放法classMLP(nn.Layer):def__init__(self):super().__init__()self.netnn.Sequential(nn.Linear(2,64),nn.ReLU(),nn.Dropout(p0.3),nn.Linear(64,32),nn.ReLU(),nn.Dropout(p0.3),nn.Linear(32,2),)defforward(self,x):returnself.net(x)常见原则放在隐藏层激活之后更常见。不要放在最终 logits 后面。p不是越大越好。小模型或数据充分时Dropout 不一定带来提升。常见尝试p 0.1 p 0.3 p 0.5如果p太大模型可能欠拟合。weight_decay通过优化器约束参数权重衰减常用于限制参数过大。在 Paddle 优化器中可以设置optimizerpaddle.optimizer.Adam(learning_rate0.001,parametersmodel.parameters(),weight_decay1e-4,)直觉上训练目标变成不仅要分类正确 还希望参数不要过大过大的参数可能让模型对训练数据过度敏感。weight_decay会给这种倾向加一点惩罚。常见取值1e-5 1e-4 1e-3如果weight_decay太小效果可能不明显太大则可能让模型学不动。Dropout 与 weight_decay 的区别方法作用位置主要效果Dropout网络前向中的激活值减少神经元共同适应weight_decay优化器参数更新惩罚过大权重数据增强输入数据增加训练样本变化早停训练过程防止继续过拟合它们不是互斥关系可以组合使用。推荐顺序先跑无正则 baseline 观察是否过拟合 加入 weight_decay 必要时加入 Dropout 再考虑数据增强和早停不要一开始把所有正则化都加满否则很难知道是哪一个起作用。早停验证集不再提升就停止早停不是 Paddle 特有 API而是一种训练策略。基本逻辑记录 best_val_acc 如果验证集长期没有提升 停止训练示例best_val_acc0.0patience5bad_epochs0forepochinrange(100):train_loss,train_acctrain_one_epoch(model,train_loader,optimizer)val_loss,val_accevaluate(model,val_loader)ifval_accbest_val_acc:best_val_accval_acc bad_epochs0paddle.save(model.state_dict(),best_model.pdparams)else:bad_epochs1print(epoch:,epoch,val_acc:,val_acc,bad_epochs:,bad_epochs)ifbad_epochspatience:print(early stop at epoch:,epoch)break早停适合验证集指标已经停滞。训练时间有限。模型后期明显过拟合。完整示例带 Dropout 和 weight_decay 的 MLPimportpaddleimportpaddle.nnasnnimportpaddle.nn.functionalasFclassCircleDataset(paddle.io.Dataset):def__init__(self,num_samples,seed):super().__init__()paddle.seed(seed)self.xpaddle.rand([num_samples,2],dtypefloat32)*4.0-2.0radius_squarepaddle.sum(self.x**2,axis1)self.y(radius_square1.0).astype(int64)def__len__(self):returnself.y.shape[0]def__getitem__(self,index):returnself.x[index],self.y[index]classRegularizedMLP(nn.Layer):def__init__(self):super().__init__()self.netnn.Sequential(nn.Linear(2,64),nn.ReLU(),nn.Dropout(p0.3),nn.Linear(64,32),nn.ReLU(),nn.Dropout(p0.3),nn.Linear(32,2),)defforward(self,x):returnself.net(x)defaccuracy(logits,labels):predpaddle.argmax(logits,axis1)returnpaddle.mean((predlabels).astype(float32))deftrain_one_epoch(model,loader,optimizer):model.train()total_loss0.0total_acc0.0count0forbatch_x,batch_yinloader:logitsmodel(batch_x)lossF.cross_entropy(logits,batch_y)accaccuracy(logits,batch_y)loss.backward()optimizer.step()optimizer.clear_grad()total_lossfloat(loss.numpy())total_accfloat(acc.numpy())count1returntotal_loss/count,total_acc/countdefevaluate(model,loader):model.eval()total_acc0.0count0withpaddle.no_grad():forbatch_x,batch_yinloader:logitsmodel(batch_x)total_accfloat(accuracy(logits,batch_y).numpy())count1returntotal_acc/countdefmain():paddle.seed(2026)train_loaderpaddle.io.DataLoader(CircleDataset(512,2026),batch_size32,shuffleTrue)val_loaderpaddle.io.DataLoader(CircleDataset(512,2027),batch_size64,shuffleFalse)modelRegularizedMLP()optimizerpaddle.optimizer.Adam(learning_rate0.001,parametersmodel.parameters(),weight_decay1e-4,)best_val_acc0.0patience8bad_epochs0forepochinrange(100):train_loss,train_acctrain_one_epoch(model,train_loader,optimizer)val_accevaluate(model,val_loader)ifval_accbest_val_acc:best_val_accval_acc bad_epochs0paddle.save(model.state_dict(),best_regularized_mlp.pdparams)else:bad_epochs1print(epoch:,epoch,train_loss:,train_loss,train_acc:,train_acc,val_acc:,val_acc,best_val_acc:,best_val_acc,)ifbad_epochspatience:print(early stop at epoch:,epoch)breakif__name____main__:main()常见错误正则化排查清单错误一评估时忘记 model.eval包含 Dropout 的模型必须在验证和推理前切换model.eval()否则验证集结果会带随机性指标不稳定。错误二Dropout p 设置过大如果p0.8大部分激活都会被丢弃模型可能欠拟合。入门阶段先试0.1到0.5。错误三只看训练准确率正则化的目标是提升泛化。应同时看train_acc val_acc train_loss val_loss错误四weight_decay 过大如果训练集也学不好可能正则过强。尝试降低到1e-5或暂时关闭。错误五把正则化当成万能修复如果数据标签错了、输入 shape 错了、学习率过大正则化解决不了根因。调参建议先建立 baseline推荐流程无 Dropout、无 weight_decay训练 baseline。如果训练集和验证集都差先解决欠拟合。如果训练集好、验证集差加入weight_decay1e-4。再加入Dropout(p0.1 或 0.3)。观察验证集指标不要只看训练 loss。保存验证集最好的模型。建议练习观察过拟合和正则化效果减小训练集到 128 条观察是否更容易过拟合。把隐藏层改成 128观察训练集和验证集差距。加入Dropout(p0.3)观察验证集变化。加入weight_decay1e-4观察参数约束效果。实现早停并保存 best model。故意评估时不调用eval()观察指标波动。总结这一篇讲了 Paddle 中常见正则化思路过拟合表现为训练集好、验证集差。Dropout在训练时随机丢弃激活评估时需model.eval()。weight_decay通过优化器约束权重大小。早停根据验证集指标停止训练。正则化强度不是越大越好。调参要先建立 baseline再逐步加入策略。如果只能记住一句话那就是正则化不是为了让训练 loss 更低而是为了让模型在新数据上更可靠。