【深度学习】模型选择、过拟合与欠拟合

发布时间:2026/10/26 16:08:47

【深度学习】模型选择、过拟合与欠拟合 一、训练误差 vs 泛化误差训练误差Training Error模型在训练数据上的误差。泛化误差Generalization Error模型在从未见过的新数据上的误差。类比训练误差 平时做课堂练习的正确率泛化误差 期末考试的成绩。关键结论我们真正关心的是泛化误差而不是训练误差。因为我们训练模型不是为了在训练集上得高分而是为了处理将来遇到的新数据。二、验证数据集 vs 测试数据集为了正确地估计泛化误差我们需要把手里的数据拆成三份2.1 训练数据集Training Set用来训练模型参数。比如把全部数据的 60% 拿来。2.2 验证数据集Validation Set用来选择/评估模型、调超参数学习率、层数、Dropout 比例等。不能和训练数据混在一起否则失去意义。比如把 60% 训练集里再拿出 20% ~ 50% 作为验证集。# 从训练集中划分出验证集n_trainint(0.8*len(train_dataset))train_subtorch.utils.data.Subset(train_dataset,range(0,n_train))val_subtorch.utils.data.Subset(train_dataset,range(n_train,len(train_dataset)))# train_sub 用于训练val_sub 用于调参2.3 测试数据集Test Set只用一次的数据集最终评估性能用。在任何情况下都不能用来调超参数否则结果就是作弊。类比验证集 模拟考试可以反复做用来调整复习方向测试集 正式高考只考一次考完就定论了如果你拿高考真题来练手那高考成绩就毫无意义了为什么不能拿测试集调参因为一旦你根据测试集的结果调整了模型测试集就不再没见过了它的评估就失去了泛化意义——就像上过考场见过真题的人成绩已经不反映真实水平。三、K-折交叉验证K-Fold Cross Validation当数据不够多的时候单纯拿出一部分做验证集太浪费。这时用K-折交叉验证。3.1 算法过程算法K-折交叉验证把训练数据均匀分成 K 块For i 1, 2, …, K:使用第 i 块作为验证数据集其余 K-1 块合并作为训练数据集训练模型记录第 i 折的验证误差报告 K 个验证误差的平均值常用 K 5 或 K 10。数据分割示意K5 折1: [验证][训练][训练][训练][训练] 折2: [训练][验证][训练][训练][训练] 折3: [训练][训练][验证][训练][训练] 折4: [训练][训练][训练][验证][训练] 折5: [训练][训练][训练][训练][验证] ↑ 每折轮流当一次验证集3.2 代码实现importtorchfromtorch.utils.dataimportDataset,DataLoaderdefk_fold_cross_validation(dataset,k,train_fn): 对 dataset 做 K-折交叉验证。 train_fn: 训练函数接收 (train_loader, val_loader)返回验证集误差 total_lenlen(dataset)fold_sizetotal_len//k val_losses[]foriinrange(k):# 第 i 折的验证集索引val_indiceslist(range(i*fold_size,(i1)*fold_size))train_indiceslist(set(range(total_len))-set(val_indices))train_subtorch.utils.data.Subset(dataset,train_indices)val_subtorch.utils.data.Subset(dataset,val_indices)train_loaderDataLoader(train_sub,batch_size256,shuffleTrue)val_loaderDataLoader(val_sub,batch_size256,shuffleFalse)# 每一折重新训练一个模型val_losstrain_fn(train_loader,val_loader)val_losses.append(val_loss)print(f折{i1}: 验证误差 {val_loss:.6f})# 报告 K 个验证误差的平均returnfloat(torch.tensor(val_losses).mean())K5avg_lossk_fold_cross_validation(train_dataset,K,my_train_fn)print(f{K}-折平均验证误差 {avg_loss:.6f})3.3 K5 和 K10 怎么选选项优点缺点适用K5训练快每折训练 80% 数据验证集稍大偏差稍高数据中等追求速度K10每折训练 90% 数据更接近全量训练慢成本高数据少且珍贵追求精度原则数据越少、越珍贵K 越大数据很多时直接固定一个验证集就行不必交叉验证。四、多项式函数拟合实战我们用一个三次多项式做实验4.1 生成带噪声的真实数据importtorchimportmatplotlib.pyplotasplt n_train100# 训练样本n_test100# 测试样本# 真实函数y 1.2x - 3.4x^2 5.6x^3 5再加一点噪声deftrue_fn(x):return1.2*x-3.4*x**25.6*x**35# 生成 x 和带噪声的 yfeaturestorch.randn(n_trainn_test,1)noisetorch.normal(0,0.5,sizefeatures.shape)labelstrue_fn(features)noise# 用多项式特征扩展把一列 x 变成 [x, x^2, x^3, ...]defpoly_features(x,degree):returntorch.cat([x**iforiinrange(1,degree1)],1)# 我们用次数 3 的多项式特征去拟合和真实函数次数一致degree3poly_featurespoly_features(features,degree)4.2 三个模型对比欠拟合 / 合适 / 过拟合我们用三种模型容量来拟合——次数不足、刚好、过高模型用它拟合结果线性次数 1三次数据欠拟合三次多项式次数 3三次数据刚好合适高次多项式次数 e.g.7三次数据过拟合importtorchfromtorchimportnndeftrain_poly(degree,epochs500,lr1e-2):用指定次数的多项式模型去拟合三次函数的数据# 多项式特征features_polytorch.cat([features**iforiinrange(1,degree1)],1)n_train100train_ffeatures_poly[:n_train]train_llabels[:n_train]test_ffeatures_poly[n_train:]test_llabels[n_train:]# 线性模型对多项式特征做线性组合等价于多项式拟合netnn.Linear(degree,1,biasFalse)net.weight.data.normal_(0,0.01)lossnn.MSELoss()trainertorch.optim.SGD(net.parameters(),lrlr)forepochinrange(epochs):trainer.zero_grad()lloss(net(train_f),train_l)l.backward()trainer.step()train_lossloss(net(train_f),train_l).item()test_lossloss(net(test_f),test_l).item()returntrain_loss,test_lossfordegreein[1,3,7]:tr,tetrain_poly(degree)print(f次数{degree}: 训练误差{tr:.6f}| 泛化(测试)误差{te:.6f})五、过拟合与欠拟合欠拟合Underfitting模型过于简单训练误差都无法降低。连课堂例题都做不对。过拟合Overfitting模型过于复杂训练误差很低但泛化误差很高。把例题全背下来了换个问法就废。六、模型容量与 VC 维7.1 模型容量Model Capacity模型容量 模型拟合各种函数的能力。低容量模型难以拟合训练数据欠拟合。高容量模型可以记住所有训练数据但往往过拟合。两种极端都不好。我们的目标是容量刚好够拟合真实规律但又不会大到把噪声也背下来。7.2 VC 维VC Dimension怎么定量衡量模型容量一个常用指标就是VC 维。VC 维的定义一个模型最多能打散shatter多少个数据点——即不管这些点的标签怎么排列正/负模型都能找到一个参数把这组点完全分开。二维平面上的线性分类器VC 维 3。它最多能完全分开 3 个点任意正负组合都能用一条直线分开但 4 个点就不行了比如 XOR 布局。数据点越多、越分散需要的 VC 维越大。VC 维 3二维直线的例子3 个点无论正负怎么排总能画一条直线分开 → 能打散VC维至少34 个点存在排法如 XOR无法用直线分开 → 打不散所以 VC维 4结论二维线性分类器 VC 维 3直觉VC 维越大模型越能记但也越容易过拟合。而在我们的代码里多项式次数越高等价于 VC 维越高。八、触发过拟合的典型场景场景为什么容易过拟合训练数据太少模型把少量样本的噪声当成了规律模型参数太多容量过大拟合能力超过真实复杂度训练轮数过多epoch 过长越训越背训练集验证误差开始反弹特征维度远大于样本数如基因数据、图像展平向量八、应对过拟合的策略8.1 降低模型容量少几层网络 / 少几个隐藏单元高次多项式 → 降到合适的次数前面实验里次数 7 → 次数 38.2 数据增强Data Augmentation让数据变多变花降低对噪声的记忆# 图像随机翻转 旋转制造更多样本transformtorchvision.transforms.Compose([torchvision.transforms.RandomHorizontalFlip(),torchvision.transforms.RandomRotation(10),torchvision.transforms.ToTensor(),])8.3 正则化Regularization给损失函数加上对大权重的惩罚让模型不要太张狂。L2 正则化权重衰减 Weight Decay# 优化器自带 weight_decaytrainertorch.optim.SGD(net.parameters(),lr0.01,weight_decay0.05)# weight_decay 让每一步更新时权重都往 0 缩一点抑制过拟合8.4 Dropout训练时随机失活一部分神经元防止过度依赖某些特征netnn.Sequential(nn.Linear(784,256),nn.ReLU(),nn.Dropout(0.5),# 训练时随机丢弃 50% 神经元nn.Linear(256,128),nn.ReLU(),nn.Dropout(0.5),nn.Linear(128,10),)8.5 早停Early Stopping在验证误差开始回升的那一刻停止训练best_valfloat(inf)forepochinrange(num_epochs):train_one_epoch()val_lossevaluate(model,val_loader)ifval_lossbest_val:# 出现了更低的验证误差best_valval_loss torch.save(model.state_dict(),best.pt)# 存最好的# 如果连续 N 轮验证误差不再下降就早停ifno_improve_countpatience:break参考资料《动手学深度学习》第 4 章模型选择、欠拟合和过拟合Bishop, C. (2006). Pattern Recognition and Machine Learning.
延伸阅读

更多相关文章

2026/10/24 15:37:54

C++初阶——vector

目录 一 vector的介绍及使用 1、vector的介绍 2、vector的使用 二 vector在OJ中的使用 三 vector深度剖析及模拟实现 一、vector的介绍及使用 1、vector的介绍 std::vector是动态顺序数组,底层是一块连续堆内存;会自动扩容,下标随机访问O…

2026/10/24 8:56:14

DeepEvidence: Empowering Biomedical Discovery with Deep Knowledge Graph Research——通过深度知识图谱研究赋能生物医学发现

DeepEvidence 是一个专门针对生物医学知识图谱设计的“深度研究”AI智能体框架,旨在解决生物医学知识分散、异构、难以整合的痛点,通过系统化的知识图谱探索和推理,加速从药物发现到临床应用的完整生物医学研究生命周期。 一、研究背景与问题…

2026/10/26 7:24:40

【Day 11】Agent做错了怎么办?让它自己检查

摘要 try-except只能捕获代码崩溃,发现不了逻辑错误。本文实现Reflexion模式:执行后LLM自我评估,不通过则反思错因并存入记忆,带着反思重试。核心约80行,免费运行。 你让Agent算购物总价:3本书每本45元、2…

2026/10/26 16:04:21

端到端测试实践:从线上事故到Playwright自动化工程

1. 从一次“全部通过”的线上事故说起我做过最冤的一个线上事故,就是下单流程的回归测试全部通过了,结果用户实际下单后库存没扣。排查到最后,原因是第三方支付回调里加了一个状态判断,单测覆盖了,接口测试也覆盖了&am…

2026/10/26 16:04:21

Linux内存管理机制:从物理内存到虚拟地址空间

1. Linux内存管理全景图:从硬件到内核的协作机制 当我们在Linux终端敲下 free -m 命令时,屏幕上显示的那些内存数字背后,隐藏着一套精密的协同工作机制。作为在Linux系统开发领域深耕多年的从业者,我经常需要深入内存管理子系统…

2026/10/26 16:04:21

从零构建工业级人脸识别系统:YOLOv8实战指南

1. 项目概述:从零构建完整的人脸识别检测系统这个项目最吸引人的地方在于它提供了一套完整的解决方案闭环——从数据标注、模型训练到前端展示的全流程工具链。作为一名长期从事计算机视觉开发的工程师,我深知在实际项目中最大的痛点往往不是算法本身&am…

2026/10/26 16:04:21

NRBO优化KELM-Adaboost的风电功率预测Matlab实战

做风电数据时序预测的朋友,很多都卡在同一个问题上:单一模型精度不够,调参又全靠手动试,跑一次实验一整天就没了。前段时间我实践完一套基于牛顿拉夫逊优化算法NRBO优化集成学习结合核极限学习机KELM-Adaboost的风电功率预测方案&…

2026/10/26 16:04:20

ISAR四点目标仿真:range-doppler成像原理与工程验证

简介:本资源是面向雷达信号处理初学者的ISAR成像入门实践包,聚焦逆合成孔径雷达成像核心原理与距离-多普勒成像方法,特别适用于高校电子/通信/雷达方向本科生及入门级科研人员理解点目标建模、回波仿真与图像重构全流程。压缩包共2个文件&…

2026/10/26 15:59:20

APP开发全流程:从发布到盈利的实战指南

1. 自研APP发布与盈利全景图 独立开发者想要在移动互联网时代分一杯羹,APP的发布与盈利是必须跨越的两座大山。作为经历过3款APP从开发到盈利全周期的从业者,我深刻体会到:发布不是简单上传应用商店,盈利也不只是接入广告那么简单…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/26 0:20:17

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/26 0:00:48

Nested Learning:解决AI灾难性遗忘的分层记忆架构

1. 为什么AI需要"记忆"能力?在传统深度学习模型中,我们常遇到一个根本性问题:模型在处理新任务时,往往会完全遗忘之前学到的知识。这种现象被业界称为"灾难性遗忘"(Catastrophic Forgetting)。想象一下&#…

2026/10/26 0:00:48

企业级大模型应用:OCR预处理、Dify编排与DeepSeek落地实战

1. 这不是“用大模型”,而是重构工作流的起点“大模型的应用和工具”——这八个字现在被贴在无数技术分享、招聘JD、内部立项书的标题栏里,但绝大多数人点进去后看到的,是零散的API调用示例、几个开源UI截图、或者一句“接入LLM就能降本增效”…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑