ARTICLE DETAIL

资讯详情

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

模型训练的本质:参数估计、MLE与MAP的数学原理与工程实践

模型训练的本质:参数估计、MLE与MAP的数学原理与工程实践 训练一个深度学习模型本质上是在做什么很多人第一反应是“调参数”“跑实验”“看 loss 曲线”。但往深里想一步你其实是在做一件事参数估计。给定一批样本我们要给模型找一组参数让它在某种统计准则下最大程度地解释这些数据。这句话听起来有点绕却是人工智能数学基础里最核心的一块拼图。搞清楚这一层你的模型训练就不再是玄学。这篇文章会把参数估计从数学原理拆到代码实现适合刚学完机器学习基础、想补数学课的人也适合已经跑过不少模型、但总觉得“差点理论基础”的工程师。我尽量用大白话讲每段都会落到实际训练里的某个现象上。1. 参数估计到底在解决什么问题1.1 模型训练的本质从数据里“猜”参数一个模型拆开来看只有两部分结构线性函数、神经网络、决策树这类和参数权重 w、偏置 b、阈值、卷积核等等。结构决定了模型的表达上限参数决定这个上限能不能真正落到你手头的数据上。训练的目的就是从有限样本中估算出一组能让模型表现好的参数。我最喜欢拿做菜来类比。菜谱就是模型结构写得很清楚了但盐放多少、火开多大必须根据具体食材和个人口味来调。没有数据就是盲猜有了数据就可以“看着来”。训练就是根据数据反馈去估计那撮盐的量。模型参数和这撮盐本质上没有区别它们都不是拍脑袋定的而是被数据“推”出来的。为什么非要说数学基础因为如果只靠试错调参你也能跑通一些简单任务但换个场景、换个数据分布就可能抓瞎。理解参数估计的原理以后你能判断什么时候该加正则、什么时候该换损失函数、为什么优化器不收敛、为什么线上指标和线下对不上。这种“判断力”才是老手和新手的差距不是谁手速快而是谁能在问题出现时更快定位原因。从工程上看模型训练的大部分时间其实都花在“试”和“调”上。可如果没有统计推断这根弦你永远是被动试有了它你是带着假说去验证效率完全两回事。1.2 概率视角样本背后的“隐藏分布”把训练数据想象成从一个未知分布 p(x, y) 里抽样出来的。模型要学的不是“记住这批样本”而是估计这个分布背后的规律。比如一张猫图片和对应的标签“猫”不是凭空出现的它背后有一个关于“什么是猫”的分布。模型训练的任务就是从有限的猫图中推断出这个规律而不是把这 1 万张图直接背下来。这个视角的转变非常重要。一旦接受“数据来自某个分布”这个假设你就会明白为什么同一个模型在不同数据集上表现不一样因为抽样不同数据分布不同为什么训练误差低不一定测试误差低因为你估计出来的参数可能太适应训练样本的噪声了。这些都是统计里的经典问题全都能翻译成参数估计的语言。市面上很多教程喜欢把训练叫“拟合函数”这个说法没错但容易让人忽略概率结构。我更建议大家把训练理解成“在假设空间里搜索一组参数使观测数据出现的可能性最大”。前者是几何视角后者是概率视角。几何视角能帮你想象 loss 曲面概率视角能帮你推导损失函数和正则项。两者都得有但后者对理解“为什么”帮助更大。1.3 一个贯穿全文的最小例子线性回归我尽量不堆公式先用最经典的线性回归 y wx b 说事。假设你要预测房价特征 x 是面积y 是房价。模型结构很简单可训练它的思路和训练一个大语言模型没有本质区别——都是找一组参数让预测尽量贴近真实数据。如果假设误差服从高斯分布那么“最小化均方误差”在数学上等价于对高斯噪声模型做最大似然估计。这句话很多教材都是一笔带过但它是连接损失函数设计和统计推断的桥梁。什么意思呢你训练回归模型时用的 MSE loss不是随便定的它背后其实藏着一个“噪声服从高斯分布”的假设。这个例子我会在后面反复用用它推导闭式解用手写梯度下降去迭代估计参数用 PyTorch 验证结果。只要这个例子吃透神经网络怎么训练、损失函数怎么设计、正则化为什么有效你都能串起来。不要小看线性回归神经网络最后一层做的事绝大多数情况下就是线性回归或线性分类。2. 主流参数估计流派MLE 与 MAP2.1 最大似然估计MLE让数据最“像”最大似然估计的思想特别朴素既然这批数据已经发生了那我就找一组参数让这些数据出现的概率最大。举抛硬币的例子。假设硬币正面概率是 p你抛了 10 次得到 8 次正面、2 次反面。那么 p 最合理的估计是多少是 0.8。因为在所有可能的 p 里p0.8 时观测到 8 正 2 反的可能性最大。这个例子看着简单但已经包含了 MLE 的全部逻辑。放到模型训练里参数 θ 的似然函数 L(θ) p(D|θ) 是所有样本概率的乘积。这里有个工程问题连乘出来的数值非常小容易下溢。所以实际操作都取对数把连乘变成连加得到对数似然。求最大值还是不太直观很多人习惯把负对数似然拿来最小化——这个最小化的目标就成了我们熟知的损失函数。所以你在框架里调用的那些 loss本质上就是在做最大似然估计。求解 MLE 通常有两条路。一是像线性回归那样对损失函数求导并令导数为零得到闭式解二是像神经网络那样用梯度下降迭代逼近。前者适合简单模型后者适合复杂模型。我后面分别演示。MLE 的局限也很明显它完全相信数据对参数的先验信息一概不管。数据少、噪声大的时候估计出来的参数会被拉到极端值。这时候就需要 MAP 出场。2.2 最大后验估计MAP给参数一个“先验”MAP 引入了贝叶斯视角。贝叶斯公式告诉我们在看到数据之前你对参数本来就有一些认识这叫先验 P(θ)看到数据后这个认识被修正为后验 P(θ|D)。MAP 想找的是让后验概率最大的那组参数。如果你嫌这个公式抽象可以这么理解MLE 是“数据说啥就是啥”MAP 是“数据说的同时我还要参考一下自己的常识”。常识可以来自你对业务的理解也可以单纯是为了防止参数过大。在实操中MAP 和“正则化”是一枚硬币的两面。给参数加一个均值为 0 的高斯先验拉出来就是 L2 正则加一个拉普拉斯先验就是 L1 正则。L2 会把参数往 0 收缩但不完全置零L1 会把一部分参数压成精确的 0形成稀疏解。所以下次你往 loss 里加 weight decay心里可以默念一句我这是在给参数做贝叶斯先验。你不再把正则当成一个拍脑袋的 trick而是理解它是控制参数估计方差的手段心态会很不一样。模型发生过拟合的时候你也不会只是机械地试着调 lambda而是知道它在怎么改变参数估计的偏好。2.3 贝叶斯估计不满足于一个点MLE 和 MAP 输出的都是“一个点”——一组确定的参数。贝叶斯估计更进一步它要求出参数完整的后验分布。这意味着模型不仅知道参数大致是多少还知道这个估计有多不确定。后验分布有什么用可以做预测的置信区间可以做主动学习——选择那些最不确定的样本去标注也可以在小样本场景下避免过拟合。代价也很大后验分布通常没有解析解得靠 MCMC 或变分推断去近似。训练一个千万参数的大模型还想算完整后验几乎是不现实的。所以实际工程里MLE 和 MAP 是绝对主力贝叶斯方法更多出现在小样本建模、强化学习探索策略这些特定场景。三种估计方法的对比我整理成一张表估计方法核心目标输出与正则化的关系计算成本MLE最大化似然 p(Dθ)单一参数点无内置正则MAP最大化后验 p(θD)单一参数点等价于添加对应先验的正则项贝叶斯估计求完整后验 p(θD)参数的概率分布天然融合先验与不确定性这张表能帮你快速判断大多数训练任务用 MLE 思路加正则化就够用只有当你对不确定性有硬需求时才值得为完整贝叶斯估计付出成本。3. 从参数估计到真正的模型训练3.1 损失函数就是负对数似然在深度学习框架里你随手调用的 loss 函数背后几乎都能追溯到某一个参数估计准则。MSE 对应高斯噪声假设的负对数似然交叉熵对应分类任务里类别分布的负对数似然。你每设计或选择一个损失函数其实都在对数据的噪声和生成方式做一次假设。这个视角有什么用第一损失函数不是随便选的。回归任务用 L1 损失相当于假设噪声服从拉普拉斯分布对离群点更鲁棒用 MSE则假设噪声是高斯的离群点会被平方项放大。所以遇到异常值多的数据你知道先换 L1 试试而不是盯着网络结构纠结。第二当训练效果不好你可以回头审视这个数据分布假设是否成立。比如你用 MSE 做回归但数据里有很多极端值loss 总是压不下去那不是模型不够强而是你的噪声假设和真实数据不匹配。这时你可以把极端值去掉或者换成 Huber loss。这个排查方向比盲目加网络层数有效得多。我特别想强调不理解这层关系你只会“用 API”理解了你才有资格说“设计训练方案”。你每次换 loss 函数本质上就是在修改你对“数据是怎么生成出来的”这个问题的回答。3.2 梯度下降怎么在参数空间里搜索很多参数的估计没有闭式解尤其是神经网络。梯度下降的思路很直观在参数空间里先随便站一个点沿着让损失下降最快的方向——也就是负梯度方向——迈一步重复足够多次就能走到一个较低的位置。更新公式很朴素θ ← θ − η·∇L(θ)。η 是步长也就是学习率。这个公式的核心是“方向 步长”。方向由梯度提供告诉你该往哪个方向调整参数步长决定你每一步迈多大。步长太大容易在山谷两边反复弹跳甚至飞出参数空间步长太小可能训练一天还在半山腰慢慢磨。这就是为什么学习率是训练里最重要的超参数之一。有人会问线性回归不是能直接用正规方程求解析解吗为什么还要梯度下降因为求逆的复杂度是特征维度的立方级别特征一多就扛不住。更别提神经网络的损失函数高度非线性根本不存在闭式解。梯度下降虽然不是唯一优化方法但它简单、可扩展、配合自动微分就能覆盖几乎所有深度学习模型所以成了事实标准。我这里想补充一句梯度下降得到的不一定是全局最优。深度神经网络的损失曲面非凸存在大量局部极值和鞍点。但实际经验告诉我们只要数据充足、结构合理、调参得当局部最优往往也够用。这就是工程和数学的区别——数学追求全局最优工程追求“好到能用”。3.3 批量、动量、Adam每次估计其实都带噪声实际训练里我们很少在整个数据集上计算精确梯度而是每次随机取一个小批量来估计梯度。这个“估计”字眼很关键小批量算出来的梯度只是真实梯度的一个带噪声近似。批量越小噪声越大但每次迭代越快批量越大梯度越准但单次成本越高。这个权衡贯穿整个训练过程。我一直觉得把批量梯度下降、随机梯度下降、mini-batch 梯度下降想成一套东西会清楚很多它们都是对真实梯度的估计差别只在估计用的样本量。使用随机梯度下降时loss 曲线会有明显震荡但整体在下降这很正常因为你在用带噪声的梯度做参数估计。动量是对梯度方向做了指数滑动平均相当于给参数估计加了个平滑能抑制震荡。Adam 更进一步同时估计梯度的一阶矩和二阶矩并分别做归一化。理解它们的数学本质之后你调优化器参数时就不会全靠乱试而是知道 beta1、beta2 控制的是对梯度均值和方差估计的衰减速度。很多人把优化器当成黑盒调参靠题库其实稍微懂一点就能自己判断该改哪个值。3.4 验证集和交叉验证估计泛化能力参数估计不只是训练集内部的事。你可能发现了模型在训练集上表现好不代表在没见过的新数据上好。为了避免“自我感觉良好”我们用验证集来估计模型的泛化能力。验证集上的表现是衡量训练出来的参数是否真正可用的直接依据。超参数也可以理解为一种“更高层的参数”。常见的调法有网格搜索、随机搜索、贝叶斯优化在一组候选值上分别训练用验证集表现选出最合适的。交叉验证则是把数据切分成多份轮流当验证集让你在数据量不大时得到更稳的估计。所有这些流程本质都是在做一个更谨慎的参数估计——只是估计对象从模型参数变成了超参数。这里有一个很容易踩的坑验证集信息泄露。要是你用验证集反复调参调得足够多验证集就不再是“没见过的新数据”它的泛化估计会偏乐观。这也是为什么大型比赛中还要保留一份完全没碰过的测试集。做参数估计时数据分层一定要守住否则你评估的不是模型的泛化能力而是“你在验证集上过拟合的程度”。4. 实操手写一个参数估计流程4.1 构造实验数据先造一组带噪声的线性数据真实参数是 w3、b2特征 x 在 [-2, 2] 上均匀采样给 y 加上标准差 0.5 的高斯噪声。代码很简单意义在于让你有一个“已知答案”的基准后续所有估计结果都能和真值对照。import numpy as np rng np.random.default_rng(42) x rng.uniform(-2, 2, 200) true_w, true_b, noise_std 3.0, 2.0, 0.5 y true_w * x true_b rng.normal(0, noise_std, 200)噪声不能设太小否则梯度下降估计过程太顺滑看不出统计现象。200 个点也不算多这样才能真实感受到有限样本下参数估计的不确定性。4.2 用 MLE 闭式解验证理论先说推导逻辑最小化 MSE 等价于对高斯噪声做 MLE。对 w 和 b 分别求偏导、令其为零解出参数。矩阵视角下结果就是正规方程 w (X^T X)^{-1} X^T y。X np.column_stack([x, np.ones_like(x)]) theta np.linalg.inv(X.T X) X.T y print(theta) # 大约输出 [2.96, 2.08]算出来的 w 和 b 会非常接近真实值但不完全相等。这里顺便说一句即使真实参数是 3 和 2样本噪声和有限数据量决定了任何估计方法都不可能完全还原。你看到的那一点点偏差不是 bug而是统计估计中正常的抽样误差。很多人第一次跑出这种结果时会纠结“为什么不是精确的 3.0 和 2.0”。答案很简单你只有 200 个带噪声的样本估计不出来精确真值。要减小偏差可以加大样本量或者降低噪声。这个直觉以后会一直陪伴你。4.3 用梯度下降迭代估计参数接下来手写一个简单梯度下降模拟神经网络训练的底层过程。损失函数对 w、b 的梯度可以手工推导∂L/∂w (2/N)Σ(f(x_i) - y_i)x_i∂L/∂b (2/N)Σ(f(x_i) - y_i)。每次迭代用全部样本算梯度然后更新参数。w, b 0.0, 0.0 lr 0.1 for step in range(200): pred w * x b grad_w 2 / len(x) * np.sum((pred - y) * x) grad_b 2 / len(x) * np.sum(pred - y) w - lr * grad_w b - lr * grad_b if step % 20 0: mse np.mean((pred - y) ** 2) print(step, round(mse, 4), round(w, 3), round(b, 3))最后 w 会收敛到和闭式解差不多的位置。梯度下降的本质就是一步步估计参数每一步都在利用损失函数的梯度信息修正估计方向。你会发现前几十步 loss 降得特别快后面越来越慢这是典型的收敛曲线特征。如果我把这个例子改成小批量采样或者一次只用一个样本更新你会看到参数路径变得曲折很多——那就是随机梯度下降和 mini-batch 梯度下降的直观感受。4.4 在 PyTorch 里验证既然写到这顺便用 PyTorch 搭一个微型线性模型让你看到框架背后的操作和手写没有本质区别。import torch import torch.nn as nn x_t torch.tensor(x, dtypetorch.float32).unsqueeze(1) y_t torch.tensor(y, dtypetorch.float32).unsqueeze(1) model nn.Linear(1, 1) optimizer torch.optim.SGD(model.parameters(), lr0.1) loss_fn nn.MSELoss() for step in range(200): pred model(x_t) loss loss_fn(pred, y_t) optimizer.zero_grad() loss.backward() optimizer.step() if step % 20 0: print(step, round(loss.item(), 4)) print(list(model.parameters()))整个训练循环就五个要素模型、优化器、损失函数、前向推理、反向传播。optimizer.step() 做的是参数估计里的迭代更新loss.backward() 计算出梯度告诉你下一步该往哪个方向修正参数。知道这层对应关系以后框架怎么封装都不影响你理解原理。第一次跑深度学习代码的人往往只盯着 loss 数字和 float 输出却不太清楚每一步在干嘛。我建议你把这段代码和上一节手写梯度下降对照着看一行行对应心里的脉络会清楚很多。4.5 实操中的三个观察多跑几组对比你会发现一些规律。第一学习率设成 1.0loss 可能直接发散参数震荡不停学习率设成 1e-4300 步可能还离真值很远。第二初始化如果从接近真实值开始训练快很多初始化太远可能需要很久才能绕回来。第三如果给 loss 加上一个固定大小的 L2 正则估计出的 w、b 会明显偏小因为正则把参数往 0 拖。这些现象单独看都挺简单但组合到一起就是模型训练调参的大部分日常。每个现象背后都对应一个参数估计的数学原理学习率控制更新步长初始化影响起点正则化改变最终解的位置。理解之后你就不会在遇到这些问题时一头雾水而是能直接说出该动哪个旋钮。5. 常见问题与排查技巧实录5.1 训练 loss 不下降先别急着改网络造成 loss 不下降的原因很多学习率设太小、梯度算错了、数据没有归一化、batch 里混进大量 NaN。一个实用的排查顺序是先看单个 batch 能不能过拟合再逐步放宽到全量数据。为什么先试单 batch 过拟合因为如果连一个 batch 都无法把 loss 压下去那大概率是代码 bug 或者模型结构有问题而不是数据量、正则强度这些因素。先把问题范围缩小再动手改参数。我见过太多人一遇到 loss 不降就换模型结构结果最后发现是学习率设成了 1e-8白白浪费半天。如果单 batch 能过拟合全量数据不行再从这些方向排查数据是否做了归一化batch 大小是否导致梯度噪声太大学习率是否需要随着 batch 增大而调整这里的核心思路是把参数估计的问题拆成方向、步长、数据质量三个子问题挨个验证。5.2 梯度爆炸和 NaN参数估计走上歧途训练过程中 loss 变成 NaN最常见原因是梯度过大导致参数更新过猛参数跳到损失函数极其陡峭或无效的区域。处理办法按优先级排降低学习率、做梯度裁剪、检查数据里有没有异常大值、考虑换更稳定的初始化。梯度裁剪特别说一下。在 RNN 或大模型这类训练里梯度范数偶尔会突然变得很大给梯度设一个上限相当于给参数估计加了个安全边界。这不是什么高级技巧而是很多训练框架默认提供的保护措施。遇到 NaN 时不要急着重跑。先查数据里的 NaN 和 inf这在我遇到的 case 里占比最高再查损失函数在那一步的数值是否合理最后才考虑数值稳定性、混合精度之类的问题。顺序反了很容易在错误方向上浪费时间。5.3 过拟合估计出来的参数太信数据模型在训练集上 loss 非常低验证集上却不理想说白了就是用有限的数据把参数估计到了“过度适配噪声”的程度。解决办法通常不止一个加数据、加正则、做数据增强、减小模型容量、用早停。这些方法背后其实都有参数估计的影子。正则就是 MAP 里的先验数据增强相当于向模型注入了对数据平移不变等先验知识早停则是限制迭代次数避免参数在训练后期的微小波动中越走越偏。把“过拟合”当成“参数估计方差太大”来理解看问题的格局会不一样。比如你用 L1 正则会发现权重矩阵变得稀疏很多参数被压到 0用 L2 正则权重整体变小但很少为 0。这就是不同先验假设对最终参数估计结果的不同影响。知道这个区别就不会在选正则项时人云亦云。5.4 数据分布漂移旧的参数估计不再适用模型上线后表现变差很多情况的根源不是代码而是数据分布变了。也就是说你之前基于训练集估计出来的参数放到新的真实分布上不再合适。这种情况在推荐、风控、广告这些场景里非常常见用户的兴趣和行为会随着时间改变。应对方法也不神秘持续监控特征分布和预测分布的指标发现漂移后及时重训把训练数据按时间加权让近期的样本对参数估计影响更大或者在模型中注入领域自适应模块。这一整套操作本质上都是在重新做一次参数估计只是数据源从静态变成了动态。这里想提醒一点线上效果掉点不要急着调参。先确认数据分布是不是变了再决定重训还是加自适应。如果没确认漂移就直接调模型往往治标不治本而且会把参数改得一团乱。5.5 排查速查表现象可能原因优先排查Loss 不降学习率太小 / 数据未归一化降学习率或做归一化训练出现 NaN梯度爆炸 / 数据含脏值梯度裁剪 / 清洗数据过拟合数据量不足 / 模型容量太大加正则 / 早停 / 数据增强线上掉点数据分布漂移分布监控 / 重训收敛速度慢初始化差 / 学习率过低换初始化 / 调学习率这张表很多时候可以当 debug 的 checklist 用。不用背遇到问题再回来看比频繁读文档管用。说实话我早年刚跑模型时也把“训练”当成黑盒看别人调什么我就调什么。后来把 MLE、MAP、梯度下降这些数学基础补上之后最大的变化不是调参更快而是面对一个训练失败的问题时我知道该从哪里下手分析。如果你也想把人工智能这条路走扎实建议把线性代数、概率统计和优化这三块数学基础啃一啃。它不会立刻提升你的模型精度但会决定你能在这条路上走多远。最后再分享一个我常用的实操小技巧遇到任何新模型先在小数据上把训练流程跑通确认 loss 能降、参数能被估计出来再放大到全量数据。这样每次你只面对一个变量排查问题的思路会清晰很多。参数估计这件事说白了就是不停地验证自己有没有理解对数据理解对模型。
返回列表