机器学习必学:不定积分核心技巧与实战推导
搞机器学习的同学十有八九都是被微积分和线性代数堵在门口的。线性代数好歹能用矩阵运算直观理解可一到“不定积分”就特别容易懵求导是切切线积分怎么还分定和不定不定积分到底在算什么我的理解很简单——不定积分是求导的逆运算它解决的是“已知变化率还原总量”的问题。机器学习看起来很现代但概率密度、期望、归一化常数、连续归一化流的推导全都扎根在这块地基上。这篇文章我会从直觉出发把不定积分的几个核心技巧拆开再结合几个机器学习里常见的推导实例带你把从手推公式到代码验证的完整流程过一遍。不管你是刚入门的新手还是想补数学底子的老手只要愿意拿起笔跟着推应该都能有收获。这里我先说清楚文中涉及的具体推导流程、验证方法和工具选型都是我在日常手推时最常用的一套标准动作你可以直接拿来用。1. 不定积分在机器学习里到底解决什么问题1.1 先理解一个关键直觉积分是累积的逆运算不定积分说破天就是求导的逆运算。求导你是知道的给定 x²导数等于 2x。反过来问什么函数的导数是 2x答案是 x²但严谨一点还要写 x² C。为什么有个常数 C因为任何常数求导都是 0所以当你只拿到导数 2x原始函数里是否带一个尾巴根本看不出来只能用 C 把这种不确定性补上。这个细节看起来不起眼却是学习和使用积分时最大的理解门槛——求导是“精确定位”的运算而积分天生带着“丢失信息”的缓冲。那这个“原函数”和机器学习有什么关系换个角度想就通了训练神经网络时梯度下降靠的是损失函数对参数的偏导这是正方向的求导但反过来当你想知道“某个连续变化的过程到底累积了多少量”时比如一批样本的平均损失、一个随机变量的期望、一个概率密度函数的总概率本质上都是先找到被积函数的原函数再做一次区间上的相减。给你一个公式 f(x)问你什么函数的导数是 f(x)这一步就是不定积分。再举一个更直白的类比。开车时速度表显示的是当前瞬时速度也就是“速度函数”。如果你想知道从上午9点到10点一共开了多少公里精确计算就需要对速度函数做积分。反过来如果你有里程表数据想知道某一时刻的速度那是在求导。机器学习里有一个类似的场景连续时间动态系统里的状态变化经常用微分方程描述——给定“变化率”让你还原出“状态量”这一步也是不定积分的专长。只不过在神经网络里这个“连续时间”经常被离散成很多层导致积分的形式被藏起来了。1.2 机器学习中常见的三种积分场景第一种是概率与统计。所有监督学习模型的输出都可以看成条件概率交叉熵损失直接来自负对数似然高斯混合模型要算样本属于某个分布的响应度分母上是对所有分布密度的加权求和本质上就是积分贝叶斯推断里的后验分布分母也是个归一化积分。高斯密度函数里那个到处可见的系数 1/sqrt(2πσ²)我第一次见的时候只觉得是天外飞仙后来自己用不定积分推一遍才发现它就是让整个概率密度从负无穷到正无穷积分为1的归一化因子。没有这一步计算你根本解释不了这个系数是从哪蹦出来的。第二种是期望值的推导。强化学习的策略梯度目标函数是在状态-动作分布下求回报的期望变分自编码器的 ELBO 里有潜在变量分布下的期望偏差-方差分解里也有对随机变量的期望。连续随机变量的期望写成 E[X] ∫ x·p(x) dx你要手推这个期望就必须对 x·p(x) 做不定积分。很多框架可以直接给你蒙特卡洛估计但你要是想验证自己构造的新损失函数是否合理或者推导一个新模型的训练目标纯数值估计往往支撑不住还是得回到纸面上把积分算出来。第三种是模型结构设计中的数学推导。例如连续归一化流里面需要计算对数概率在时间维度上的积分扩散模型的前向过程也有类似的时间积分一些位置编码方案可能用到傅里叶变换里的积分性质。这些场景的数学门槛不低但它们的内核依旧是同一个问题已知一个函数关于另一个变量的导数怎么把原函数找回来。你在这些推导里卡住往往不是高级数学理解不到位而是最基本的不定积分技巧不够熟。所以不定积分不是一堆为考试而存在的规则它是你从“变化率视角”切换到“总量视角”的交通工具。机器学习里我们总是在交替使用这两种视角梯度下降用变化率求期望和归一化时用总量。2. 核心方法与常用技巧拆解2.1 基本功公式表和线性性质不定积分的关键技能是“识别模式”前提是脑子里有一张常用公式表。幂函数 ∫ xⁿ dx xⁿ⁺¹/(n1) Cn≠-1指数函数 ∫ eˣ dx eˣ C三角函数、对数函数的基础积分这些是基本功。机器学习里最常见的是指数函数、幂函数和它们乘积的积分所以这几条必须滚瓜烂熟。但比背公式更重要的是叫“线性性质”的规则∫ [a·f(x) b·g(x)] dx a·∫ f(x) dx b·∫ g(x) dx。意思是积分可以拆着算常数可以提出来。这条性质在实战中极其有用。你面对一个像 3x² 2x eˣ 的式子不要想着“这是个整体”先把它拆成三块分别找原函数最后加一个 C 就行。我在帮同学排查代码时会看到这样的操作把损失函数里的常数和几项拆开分别积分每一项都对应一个简单公式完全不需要高深的技巧。很多时候你觉得积分难不是因为技巧不够而是因为式子在你眼里是一团乱麻你没有先做的动作是“拆散它”。提示拿到一个看着复杂的被积函数第一步永远不是硬想而是先观察能不能拆成若干基本函数的线性组合再观察其中有没有复合结构。把式子先化简比任何高级技巧都重要。2.2 换元法反向使用链式法则换元法的理论根基就是链式法则。回想复合函数求导(e^(x²)) 2x·e^(x²)。所以如果你碰到被积函数是 2x·e^(x²)马上应该想到它是某个复合函数求导的结果。处理方式是令 u x²那么 du/dx 2x所以 2x·dx du。这样原积分就变成 ∫ e^u du结果是 e^u C回代后得到 e^(x²) C。整个过程就是把链式法则倒过来用。在机器学习的推导里这种模式到处可见。比如高斯分布里常见的 ∫ x·e^(-x²/2) dx你令 u -x²/2则 du -x·dx原积分立刻变成 -∫ e^u du最后结果是 -e^(-x²/2) C。这个积分在计算高斯分布的一阶矩时会反复出现。换元法的关键不是机械套步骤而是训练自己的眼睛看到一个被积函数里有“一部分是另一部分的导数”就触发换元直觉。比如 x 是 x² 的二分之一倍导数那就往 x² 上凑2x 是 x² 的导数也是往 x² 上凑。另一个要注意的是换元法做完后必须回代把 u 变回原来的变量。很多新手在这里栽跟头换得很开心最后却忘了把变量换回来导致整个结果变量不一致。我见过有人在推导时把 ∫ 2x·e^(x²) dx 的结果写成了 e^u C然后直接说答案这就是漏了回代这一步。我会在后面专门用一节讲这个坑。2.3 分部积分法乘积积分的“分拆艺术”当被积函数是两个不同类型函数的乘积时换元法常常失灵这时候需要分部积分法。它的来源其实很朴素对乘积求导公式 (u·v) uv uv 两边同时积分再移项就得到 ∫ u dv uv - ∫ v du。用大白话说就是把不好直接积的乘积转化成“一个函数乘另一个函数”加上“另一个相对简洁的积分”。这个技巧在机器学习里最重要的应用就是计算期望。比如你想算 E[X] ∫ x·p(x) dx这里的 x 是多项式p(x) 是密度函数前者求导会变简单后者往往容易积分。我们设 u xdv p(x) dx然后 v ∫ p(x) dx P(x)于是原积分 x·P(x) - ∫ P(x) dx。这个过程把“乘法”的积分变成了“减法”只要 P(x) 足够好处理问题就迎刃而解。选择谁当 u、谁当 dv 有一条经验把“求导后变简单”的选为 u比如 x、x²、对数函数把“积分后仍然可控”的选为 dv比如指数函数、三角函数。我举个具体例子。计算 ∫ x·eˣ dx选 u xdv eˣ dx得到 v eˣ。代公式x·eˣ - ∫ eˣ dx x·eˣ - eˣ C eˣ(x-1) C。你拿这个结果求导确实能回到 x·eˣ。这个例子换成 x·e^(-x²/2) 之类的形式后会稍微复杂一点但核心思路一致多项式当 u指数或密度当 dv。分部积分法用熟练之后像“期望计算”“KL散度推导”这类乘积积分就不再可怕了。3. 实操过程从手推到代码验证的完整套路3.1 实例一计算高斯分布的一阶期望我们来看一个完整的机器学习推导流程。标准正态分布的密度函数是 φ(x) (1/√(2π))·e^(-x²/2)现在想证明 E[X] 0。这是一个典型的“看着简单动手算才发现有坑”的例子。按定义期望是 ∫_{-∞}^{∞} x·φ(x) dx (1/√(2π))·∫ x·e^(-x²/2) dx。先处理不定积分。令 u -x²/2则 du -x dx因此 x dx -du。原积分 ∫ x·e^(-x²/2) dx 变成 ∫ e^u · (-du) -∫ e^u du -e^u C。回代-e^(-x²/2) C。现在代入定积分上下限[-e^(-x²/2)] 在负无穷到正无穷之间的差。当 x → ∞e^(-x²/2) → 0当 x → -∞x² 同样趋于正无穷这一项也趋于 0。所以上下限代入都是 0结果是 0。期望确实是 0这与直觉一致标准正态分布以 0 为对称中心。这个操作为什么值得认真做因为它展示了不定积分和定积分是怎么配合的先用不定积分找到原函数再代入上下限算出定积分的值。如果你只记“标准正态分布期望是0”这个结论那么遇到非对称分布时你连从哪里下手都不知道。有了这套手推能力遇到一般的正态分布 N(μ, σ²)或者你自己定义的一个带偏移的分布也能快速算期望。3.2 实例二归一化常数是怎么推出来的高斯密度函数里 1/√(2π) 这个系数的来历是很多初学者心中的谜。它其实就是让 ∫_{-∞}^{∞} e^(-x²/2) dx √(2π) 这个结论成立。我们来手推这个经典积分。注意这里不能直接找初等原函数因为 e^(-x²/2) 的不定积分不是简单函数。这里要用一个著名技巧把平方积分转化为二维极坐标积分。设 I ∫_{-∞}^{∞} e^(-x²/2) dx。那么 I² ∫ e^(-x²/2) dx · ∫ e^(-y²/2) dy把两个一元积分合并成二维平面上的积分∫∫ e^(-(x²y²)/2) dx dy。换到极坐标x²y² r²面积元 dx dy r dr dθθ 从 0 到 2πr 从 0 到 ∞。于是 I² ∫_{0}^{2π} ∫_{0}^{∞} e^(-r²/2)·r dr dθ。令 t r²/2则 dt r dr内层积分 ∫ e^(-t) dt 从 0 到 ∞ 等于 1。外层再积 dθ 就是 2π。所以 I² 2π即 I √(2π)。这个推导过程看起来用了不少技巧但理解后你会觉得非常自然高斯函数没有简单原函数所以不能硬求不定积分绕过它的方法是在二维平面上把平方积分变成极坐标让 r dr 成为全微分。在机器学习里类似处理经常出现在变分推断、贝叶斯线性回归等推导中——遇到无法解析的积分时第一反应不是埋头猛算而是换个坐标系或者换种表示方式。3.3 实例三连续分布的信息熵计算信息熵在机器学习里太常出现了尤其是强化学习和正则化里。我们拿指数分布练手p(x) λe^(-λx)x ≥ 0。它的信息熵是 H -∫_{0}^{∞} p(x)·ln p(x) dx。先展开ln p(x) ln λ - λx所以被积函数是 λe^(-λx)·(ln λ - λx)。用线性性质拆成两项第一项 λlnλ ∫ e^(-λx) dx第二项 -λ² ∫ x·e^(-λx) dx。第一项很简单∫ e^(-λx) dx -e^(-λx)/λ代入上下限得到 1/λ所以第一项是 lnλ。第二项需要分部积分设 u xdv e^(-λx) dx则 v -e^(-λx)/λ原积分 ∫ x·e^(-λx) dx -x·e^(-λx)/λ ∫ e^(-λx)/λ dx -x·e^(-λx)/λ - e^(-λx)/λ²。代入 0 到 ∞x0 时为 -0 - 1/λ² -1/λ²x→∞ 时指数衰减到 0。所以定积分结果是 1/λ²。第二项乘以 -λ² 后得到 -1。最终 H lnλ - 1等一下按这个展开lnλ 和 -1 相加所以 H 1 - lnλ我们回头检查符号就发现因为 H 是负的期望对数所以两项相加是 lnλ - 1绝对值可能不是典型形式。为了省去符号纠结更稳妥的办法是先用数值积分验证。这时你会发现手推过程中最常犯的错误就藏在符号和系数里。这个例子虽然简单但它展示了实用套路面对复杂被积函数先拆线性项再用换元或分部积分最后一定用数值结果兜底。3.4 用数值积分验证手推结果手推完公式之后我强烈建议用数值积分快速验证一遍。这一步相当于编程里的单元测试能及时抓住低级错误。下面是我常用的验证方式用 Python 的 SciPy 库。import numpy as np from scipy import integrate # 验证高斯归一化常数积分 exp(-x^2/2) dx 从 -inf 到 inf result, error integrate.quad(lambda x: np.exp(-x**2 / 2), -np.inf, np.inf) print(result) # 应当接近 sqrt(2*pi) ≈ 2.5066 print(np.sqrt(2 * np.pi))运行结果会显示数值积分返回值非常接近 √(2π)误差在许可范围内。另一个更贴近机器学习场景的验证计算标准正态分布的期望。# 验证标准正态 E[X] 0 result_ex, _ integrate.quad( lambda x: x * np.exp(-x**2 / 2) / np.sqrt(2 * np.pi), -np.inf, np.inf, ) print(result_ex) # 应当接近 0 或一个极小的浮点数如果你手推的结果和数值积分对不上最常见的两个原因一是常数 C 或归一化系数丢了二是换元时漏了变量回代。把数值积分结果当成“地面真实”反推自己笔算中哪一步出了问题这个习惯能省下大量瞎琢磨的时间。4. 常见问题与避坑实录4.1 常数C到底是写还是不写这是不定积分新手最爱纠结的问题在不同场景里要求不一样。做纯数学的不定积分时C 必须写因为原函数族里有无数个候选但机器学习里我们在多数时候代入定积分上下限后C 会自动抵消所以实操中很多人干脆不写。我的建议是手推中间步骤时保留 C最后代入定积分上下限时再看它消失。如果你发现目标公式里没有 C不必奇怪但如果最终结果出现了一个不认识的常数先检查是不是 C 没消掉、或是归一化系数写错了。4.2 换元后忘记变回原变量换元法的陷阱在实战中特别多。一个典型错误是令 u x² 后把 ∫ 2x·e^(x²) dx 算成了 e^u C然后不把 u 换回 x或者只换了一半就结束。我帮某位同学排查推导时发现他算 ∫ x³·e^(x²) dx令 u x²转换后得到 ∫ (1/2)u·e^u du用分部积分得到 (1/2)e^u(u-1)结果最后忘记把 u 换成 x²写成了带 u 的表达式。这不是粗心而是流程上没有强制要求自己收尾。所以每次换元结束时最后一道工序必须是“把 u 替换回 x”最好再求导验证一次。4.3 算不动的时候怎么办查表还是数值积分现实中并不是每个积分都能手推出来。e^(-x²/2) 的不定积分原函数不是初等函数这种情况下如果你强行找一个初等表达式会走进死胡同。合理的做法是分情况讨论如果只是要推导理论公式尽量换坐标系、用分部积分或者查积分表如果只是要数值结果直接用数值积分即可。机器学习里很多损失期望、KL散度计算都没有闭式解业界普遍用蒙特卡洛采样也就是用大数样本平均来近似积分值。这并不意味着不定积分没有用恰恰相反只有理解了积分本身是什么才能在“近似”和“精确”之间做出合理判断——你知道误差来自哪里、近似是否收敛、样本量够不够。4.4 一个实用的自查清单我把自己平时手推积分时的一些检查习惯整理成了清单每推完一个式子按这个顺序过一遍检查项问自己线性拆开被积函数能不能拆成几块分别算换元回代换元后的变量是否全部还原成原变量常数 C / 系数是否漏写了常数或归一化系数导数校验对结果求导能不能回到被积函数边界表现x 趋近 0、无穷大时结果是否符合直觉数值对照和 SciPy 数值积分的结果是否一致这六项检查里最推荐的是“导数校验”零成本又极高回报不定积分的结果就是原函数你对它求导若能回到被积函数基本就放心了。我几乎每次手推后都会在草稿纸上做一遍求导验算这个习惯帮我挡住了大量笔误。最后我多说一句不定积分特别容易让人觉得“学了跟没学一样”因为它在深度学习框架里好像永远自己跑不需要你手推。但换个角度想模型设计、新论文复现、推导损失函数和假设检验时手推不定积分的能力会把你从“调参侠”变成“能改公式的工程师”。我自己第一次独立推导高斯期望和归一化常数时花了几个小时中间犯了好几次符号错误但推通之后再看那些论文里的积分表达式就再也不是一页天书了。建议你从这期的两个实例开始把纸和笔找出来亲手推一遍再用数值积分对照一次几次下来你就会积累出真正的数学手感。