资讯详情

资讯详情

机器学习数学要学多少?从线性代数到优化的实战指南

我做机器学习有些年头最常被问到的问题就是数学到底要学多少我的答案一直没变别急着背公式先弄清楚每个数学概念在实际训练循环里负责什么。带着这个问题去学你会发现线性代数不是在教你解方程微积分不是在教你求面积概率统计也不是在帮你做计算题。它们合在一起就是模型从数据里找规律时使用的那套内部语言。这篇文章不打算给你列一个长长的公式清单而是想把机器学习里绕不开的几个数学块拆开讲明白它们为什么出现在那里以及在实际的建模、训练、调试过程里到底怎么用。内容会尽量照顾新手也会夹杂一些我自己踩过的坑和现在仍然在用的自查经验。1. 矩阵与向量模型参数是怎么排兵布阵的1.1 维度、内积与特征空间先给自己换一双几何的眼睛要迈过数学这道坎我建议先理解一个重要事实向量空间并不是课程里的冰冷抽象它就是数据存放的地方。一个样本不管是用户画像、商品信息还是图像像素落到模型里都会变成一串数字。这串数字有长有短长度就是维度。把一堆样本按行叠起来就成了矩阵。矩阵乘法听起来是数组运算但它真正的意思是把输入空间中的点按照模型参数定义的规则投影到另一个空间里去。内积是这里最常用的操作。假设某样本有三个特征年龄、收入、活跃天数模型权重是[0.3, 0.5, 0.2]那么模型的打分就是三个维度分别相乘后相加。这不只是一个计算动作它的几何含义是样本特征方向和权重方向在多大程度上对齐。方向越一致内积越大模型就越倾向给出正向判断方向垂直内积接近零模型等于没有收到有效信号。这也是为什么很多模型的第一层都只是做加权求和。神经网络看似复杂早期核心动作并不玄奇先把样本投影到很多不同的方向上每个方向对应一个神经元再通过非线性变换把投影结果做组合。维度数量也直接影响模型的表达能力。特征从 3 个增加到 300 个空间的体积是指数级膨胀的样本会迅速变得稀疏。高维空间中点与点之间的距离大都差不多反而更容易让模型陷入什么都学不到。我自己做特征工程时有个习惯先用降维工具把样本投到二维平面里看一眼如果连续特征几乎堆成一团那多半不是模型的问题而是特征空间的设计本身有问题。1.2 特征值与矩阵分解降维工具真正在拆什么东西特征值和特征向量是线性代数里最容易被误解的内容之一。教科书上的定义是对于矩阵 A如果存在非零向量 v 使得Av λv那么 λ 就叫特征值v 就叫特征向量。听起来很抽象换一种说法就清楚了矩阵 A 作用到向量 v 上之后没有让 v 的方向发生改变只是按照比例 λ 拉长或缩短。换句话说v 是 A 的一个主轴方向矩阵在这个方向上的作用完全可以简化成一个数字 λ。降维工具大量使用这个性质。比如常常用于探索性数据分析的 PCA它在数学上做的事情就是求协方差矩阵的特征值与特征向量然后挑出特征值最大的几个方向。特征值大表示数据在这个方向上有明显的波动波动通常对应信息量。特征值小的方向数据几乎没什么动静去掉它们对整体结构的损失最小。工程里常犯的一个错误是数据没有标准化就直接做矩阵分解。如果某个特征量纲是元另一个量纲是年两者数值范围差出好几个数量级矩阵分解会自动偏向数值大的那个维度最终得到的主轴根本不能反映原始问题的真实结构。我因为这个原因走过弯路现在不论后续用什么模型都会先把连续特征做中心化和归一化再谈降维。奇异值分解SVD是特征分解的一种推广专门对付非方阵。很多推荐系统和文本主题模型背后的压缩逻辑本质上都在做类似的事情把一个超大矩阵拆成左奇异向量、奇异值、右奇异向量三块前三块保留最大奇异值的方向其余丢掉。这里的关键不是把矩阵变小了而是把矩阵里最响亮的信号和微弱噪声分离了。1.3 线性层的维度对齐一个矩阵乘法暴露模型结构深层模型里最常写的操作是线性变换H XW b。其中 X 是输入矩阵形状是(N, D)W 是权重矩阵形状是(D, H)H 是输出形状是(N, H)。矩阵乘法的规则是左边矩阵的列数必须等于右边矩阵的行数也就是内部的D要对齐。输出形状则看外部的N和H。这个规则不只是考试知识点它本身就是对模型结构最直观的一层约束。看到权重矩阵 W 的形状是(D, H)你立刻能知道这个线性层把 D 维的输入映射到了 H 维的输出空间。写代码时最常见的报错就是维度不匹配。很多新手朋友第一反应是我代码写错了但更准确的判断是公式和结构不匹配。有一次我写一个多分支结构某条路径的输出维度差了一个数框架直接报错。我把公式在本子上列出来(N, 256)乘(256, 128)得(N, 128)问题瞬间就定位在中间少了一次转置。这说明一个道理矩阵乘法背后的维数对齐是检查模型定义最便宜的工具先看数学对不对再去看代码。2. 微积分梯度与链式法则撑起整个训练循环2.1 梯度是多维的斜率梯度下降只是在逆坡而行微积分进入机器学习主角不是极限也不是凑积分而是导数和梯度。导数是一维函数的斜率表示输入变化一点点时输出会跟着变多少。到了多维情况每个方向都有一个偏导数把全部偏导数拼成一个向量就叫梯度。梯度的方向有一个非常具体的几何含义函数上升最快的方向。想一想这个含义带来的推论要让损失函数变小就应该沿着梯度的反方向去调整参数。这就是梯度下降法其他所有花哨的训练算法都是从这句话出发的。泰勒展开能把这个直觉补得更扎实。假设当前参数是 θ损失函数是L(θ)在它附近做一个近似的表达L(θ ε) ≈ L(θ) ε · ∇L(θ)这里的 ε 是参数变化量。想让L(θ ε)尽量小就要让ε和梯度∇L(θ)的方向相反也就是让ε -η·∇L(θ)其中的 η 就是学习率。学习率为什么重要也在这里体现η 太大参数直接越过谷底可能震荡甚至发散η 太小每次只走一丁点训练过程慢得让人失去耐心。以前我调试模型时会把梯度范数一并打印出来观察一段时间内梯度的大小是否稳定下降。梯度大得像信号弹一样就要检查是否爆掉了梯度长时间比正常情况小很多个数量级那就要考虑学习率调度或网络结构问题。比起盯着 loss 曲线猜来猜去看梯度分布更能定位问题的层。2.2 链式法则如何变成反向传播神经网络有多层结构输入从第一层一直传到最后一层损失函数在最后一层被计算出来。那么问题来了网络内部每一层都有参数怎么知道它们的梯度是多少答案就是链式法则。把链式法则想象成一条瀑布水从顶层流下来中间每个台阶都在改变水流的力度。损失对底层参数的导数等于损失对输出的导数乘上输出对那一层输出的导数再乘上那一层输出对更底层输入的导数一路乘下去。用两层模型举例。设定第一个线性层加激活函数a σ(W₁x b₁)第二层是线性输出z W₂a b₂损失用均方误差L (z - y)²。求 W₁ 的梯度时可以拆成这样∂L/∂W₁ ∂L/∂z · ∂z/∂a · ∂a/∂W₁。∂L/∂z是误差项∂z/∂a是 W₂∂a/∂W₁里面还包含激活函数的导数。这就是为什么激活函数必须能求导。如果在代码层面看不到自动微分实现细节那你至少可以记住反向传播不过是用链式法则把一个目标值沿网络反向逐层传播而已。我训练自定义模型时有个坚持了很久的习惯小模型先用纸笔手算一遍梯度再用自动微分框架的结果对照。大部分情况下是一致的一旦出现偏差往往就是公式里某个符号写错了比如该转置没有转置、或者激活函数导数漏了项。这个习惯帮我省下过很多在代码里翻来找去的时间。2.3 梯度消失、梯度爆炸与归一化之间的因果链训练深层网络时会撞上一个明显现象浅层参数几乎不动深层参数却震荡剧烈。如果从链式法则的乘法结构看就很好理解梯度一路从深层向浅层传播需要在每一层都乘一次激活函数的导数。当这些导数的绝对值普遍小于 1 时连乘会让数值指数级衰减传到浅层时几乎为零这就是梯度消失。反过来如果导数普遍大于 1连乘会让数值指数级增长梯度爆炸就来了。所以我经常劝别人看到梯度消失时不要急着调学习率。先想一想你的网络里是不是每条路径都必须经过很多层激活函数有没有更短的路径可以绕过中间层残差连接的数学动机就在于此它给梯度提供一条近道让信号不必依赖每个层连乘可以直接往回流动。归一化操作则是在控制每一层特征分布的尺度避免某些层的输出范围过大或过小从源头上减少了梯度进入危险区间的可能。换句话说梯度消失和梯度爆炸不只是数值问题它们是网络结构在数学层面的血压异常。不改结构只调学习率就像头痛医头往往不够。3. 概率与统计损失函数不是一个任意选择3.1 极大似然估计均方误差和交叉熵的来历很多新手会问为什么做回归用均方误差做分类用交叉熵这背后其实是同一个数学原理极大似然估计。先还原一件事模型预测的不是一个孤零零的数值而是在给定特征 x 的情况下对标签 y 的条件概率分布进行估计。我们不知道真实分布但观察到一堆样本思路应该是找一个参数使得这些样本出现的概率最大。如果假设预测值周围的误差服从正态分布那么把样本带入正态分布的概率密度函数再求对数你会发现在做常数无关项之后剩下需要最大化的恰好是负的均方误差。所以最小化均方误差等于在误差服从正态分布的假设下做极大似然估计。分类模型也类似。如果输出经过归一化处理变成各个类别的概率值那么最大化所有样本正确类别概率的朴素做法取对数之后就会化简成交叉熵。这也是为什么交叉熵被称为分类任务的默认损失它不是一拍脑袋定出来的而是与模型输出是类别概率这个设定天然匹配。理解这一层之后你会对自定义损失函数产生警觉。不是所有损失都有概率解释也不是随便写一个差值公式就能和模型结构自洽。每当你把损失改得神乎其技先问一个问题这个损失隐含了对数据分布怎样的假设如果回答不上来可能只是在凭感觉造数字而不是在训练模型。3.2 KL散度两个概率分布之间的距离感KL散度的中文常译成相对熵。它在数学上衡量的是一个概率分布 Q 在逼近另一个概率分布 P 时损失了多少信息。定义可以写成KL(P || Q) Σ P(x) · log(P(x) / Q(x))最小化 KL 散度本质上就是在让 Q 尽量贴近 P。在很多场景里P 是真实标签分布Q 是模型预测分布训练模型就是在减小两者之间的不对称距离。这个工具在模型压缩、知识迁移和生成模型里尤其常见。大致思路是先有一个表达能力强的原始模型希望用一个更小的模型去模仿它的行为小模型虽然无法在每个输出上都和原模型完全一致但可以最小化它与原模型输出分布之间的 KL 散度让两者不再差太多。需要特别留意的是KL 散度并不对称KL(P||Q)不一定等于KL(Q||P)。如果方向搞反优化的结果会完全不同。这也提醒我用散度类指标时要想清楚哪个是真实分布哪个是近似分布方向错了模型学出来的倾向也会跟着错。3.3 贝叶斯视角后验、先验与权重衰减统计学里有经典的两大流派频率派和贝叶斯派。频率派把参数看成某个确定但未知的数值贝叶斯派把参数也看成随机变量需要用先验分布来表达对参数的既有认知。贝叶斯公式的核心形式很简洁后验概率正比于似然乘先验概率。它的含义是看到数据之前你原本对参数有一个判断这个判断叫先验看到数据之后把似然和先验结合起来得到修正过的判断叫后验。这个视角在深度学习中有一个非常经典的对应L2 正则化也就是权重衰减。数学推导大致是这样如果给参数加上一个零均值的高斯先验那么在极大化后验概率的过程中对数概率密度会多出一项与‖θ‖²成正比的惩罚项。这一项最后落地的形式就是权重衰减。也就是说使用 L2 正则化和你心里默认为权重服从一个相对紧凑的高斯分布是同一件事。理解了这一点你就能回答一个经常被问的问题正则系数到底应该调多大它不是越低越好也不该越高越好。它相当于你在模型在训练数据上拟合得好不好和参数分布是否符合先验预期之间做的一次预算分配。预算紧权重被迫靠近零预算松模型更自由地去拟合数据。这样去理解正则化比单纯把它当成防过拟合的咒语要合理得多。4. 优化把模型训练看成一次有策略的搜索4.1 凸优化、非凸与局部最优的真实处境优化问题的目标是找一组参数让损失函数尽可能小。如果损失函数是凸函数那么任意局部最小值都是全局最小值。这个性质极为友好因为在凸函数里你不用担心走错方向后被一个低矮山谷困住。线性回归、逻辑回归等传统模型天然是凸优化问题理论能给你充分保证。深层神经网络的损失函数则普遍是非凸的存在很多局部最优解、鞍点甚至平坦区域。这也是为什么同样的模型和同样数据换个随机种子最后效果可能有明显差异。随机初始化本质上就是在给优化过程提供不同的起点看看哪个起点最终能被稳定地引向更好的区域。这几年大家的普遍感受是高维非凸问题里最让人头疼的未必是局部极小值而是鞍点和平坦平原。这些地方的梯度很小直接做梯度下降很容易停下来训练损失半天不动。应对方式也很多——更好的优化器、更合理的初始化、归一化、残差路径——说白了都是为了让搜索过程不容易在无意义的位置上提前卸力。4.2 动量与自适应学习率SGD 到 Adam 在解决什么问题最基础的随机梯度下降每次只用一小批数据计算梯度然后沿着反方向更新参数。它的优势是计算代价低、有天然的随机扰动缺点是不同维度参数收敛速度参差不齐损失函数在某个方向陡峭、另一个方向平缓时很容易来回震荡。动量思想是给更新过程加一个惯性如果过去几次梯度都在类似方向就让参数在这条方向上走得更快如果梯度方向反复横跳就自动减少震荡幅度。这种方式比单纯依赖当前梯度更稳。自适应学习率方法沿用了动量思路并按参数的历史梯度大小调整每个维度的更新步长。简单理解就是频繁出现大梯度的位置更新迈得小一点梯度长期很小的位置更新迈得大一点。这正是 Adam 这类优化器在大规模训练中受欢迎的原因——它省去了很多手工调整全局学习率的功夫。不过它也带来一个问题因为每个参数都有独立步长它对学习率整体放缩的反而不像动量那样敏感。实际把它调小一些有时反而能提升效果。我的经验是先用默认学习率跑通训练看见 loss 曲线形如坐过山车时就把学习率降一个数量级如果 loss 曲线还没怎么下降先别急着加学习率检查一下训练数据的尺度或 batch 大小再说很多时候问题压根不在优化器。4.3 拉格朗日乘子视角下的正则化很多教材会把正则化单独归于损失函数设计但从数学上看它本质上是约束优化。优化任务本来是无约束地最小化损失函数min L(θ)。权重衰减说的是希望参数的模长不能无限增大于是加了一个约束某个半径限制内寻找解。把约束写成一个条件再用拉格朗日乘子把它并进目标函数就会得到min L(θ) λ·‖θ‖²这跟前文提到的高斯先验结论完全对上了。拉格朗日乘子 λ 在这里扮演的是约束强度λ 越大允许的参数空间越小参数越被压缩向原点收缩λ 越小参数越自由几乎等价于没有约束。这种数学视角一旦建立你对正则项的各种变形也能更好理解。L1 正则之所以会让许多参数变成严格的零不是因为它的惩罚更大力而是因为它约束出的等高面形状天然更倾向于把解放在坐标轴上。数学结构不同行为就不同。这不光是一个记忆点更是模型设计时实实在在的取舍依据。5. 把数学拉进实际工程我的阅读与自查习惯5.1 读公式第一步不是背符号而是看维度很多朋友一见到公式就头大就是因为他们试图从第一个符号到最后一个符号逐字背下来。我的习惯完全不同先看维度再看结构。比如线性回归的闭式解θ (XᵀX)⁻¹Xᵀy。先看形状X 是 n×pXᵀX 是 p×p求逆之后还是 p×pXᵀy 是 p×1。两者相乘θ 就是 p×1恰好和参数维度一致。整个公式都成立。接下来再看它做了什么先把样本特征转置构造出一个参数空间下自相关的矩阵再乘以标签映射向量。你根本不需要背就能在需要的时候随时推理出来。读任何模型论文也一样。先确定输入张量和权重张量各自的形状再走一遍每个运算前后的形状变化。如果某一步形状对不上很可能是自己理解错了某个操作而不是作者写错了。这个习惯的回报率极高我强烈建议把它练成肌肉记忆。5.2 反复做三个能落地的手工验证数学是看会的更是算会的。分别掌握线性代数、微积分和概率论之间联系的最佳办法是做一组小规模的纸笔验证练习。第一个练习拿一个只有两三层的小网络手动推一下每个参数的梯度公式。不需要真的实现复杂模型重点是让链式法则从输入一路传播这件事变成自己亲手算过的过程。第二个练习把线性回归分别用闭式解和梯度下降各实现一遍观察两种方法得到的参数收敛差异。你可以直观感受到梯度下降不是一锤子买卖而是无数次走一步看一步坐标系尺度不同收敛速度天差地别。第三个练习手动构造一组带标签的样本分别观察均方误差和交叉熵在模型犯错时的梯度方向。你会发现它们对错得多严重的反应并不相同。这种手感在日后工程里选择损失函数时远比看任何资料都有用。5.3 用数学逻辑排查训练事故训练不收敛这个问题的排查过程本身也是一道数学题。我一般跟着梯度去走。先看梯度范数是不是异常巨大如果是考虑是不是学习率太大、数据范围没处理好、或者模型输出产生了极端值。再看梯度是不是已经很长时间无法下降如果每个维度的梯度都极小但这时的验证集损失依然很高那就要检查是不是网络太深导致梯度消失、激活函数选择不合适或者初始化尺度不对。最后再去看 loss 曲线的形状。如果 loss 在某个门槛附近反复抖动就是不往下走很可能是训练步长和损失曲面坡度之间不匹配这时调节学习率或批大小才有意义。这三步不涉及什么高深技巧但背后全是数学逻辑导数的尺度、梯度的方向、概率分布假设和优化曲面的几何。模型训练出问题时最先救你的往往不是你背过的哪条定理而是你对这些概念之间关系的那一层直观理解。我自己带新人的时候经常对他们讲数学不是关卡而是武器。模型写出来的那一刻数学就开始工作了模型训练不下去的那一刻数学就是第一块敲门砖。你不一定每次都用得到太深的公式但心里始终要有那幅坐标损失函数在哪里梯度指向哪里参数更新下一步落在哪里。画得出这张图你才算真正跟模型站在一起。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →