模糊、回声、平均、掷骰子是同一件事
前三卷讲的都是「频域怎么看」和「看要付多少钱」。这一卷回答那个一直没问的问题:那我们为什么还要跑这一趟。答案是一条定理,而这一章先把定理的主角请出来——一个你每天都在用、但多半没意识到它有名字的运算。
掷两个骰子,求和的概率分布——你大概记得它是个三角形,7 最容易出(6/36)。
问:下面四件事里,哪几件和「求两个骰子的和的分布」用的是同一个运算?
① 把一张照片做高斯模糊 ② 给一段干声加混响 ③ 把两个多项式相乘 ④ 对一条时间序列做 5 点滑动平均
最短的入口:两个多项式相乘
小学的乘法竖式,中学的多项式展开:
(1 + 2x + 3x²) · (1 + x)
展开: 1·1 = 1 → x⁰ 的系数 1
1·x + 2x·1 = 3x → x¹ 的系数 3
2x·x + 3x²·1 = 5x² → x² 的系数 5
3x²·x = 3x³ → x³ 的系数 3
结果: 1 + 3x + 5x² + 3x³
只看系数: [1, 2, 3] ✻ [1, 1] = [1, 3, 5, 3]
「x² 的系数怎么来的」这个问题,答案是:把所有「下标加起来等于 2」的组合,乘起来再加起来。写成公式:
(a ✻ b)[k] = Σ a[i] · b[k − i]
i
念出来:**所有加起来等于 k 的组合,各自相乘,然后求和。**
这就是卷积。整章剩下的内容,都是这一句话在不同场合的样子。
四件事,同一句话
掷两个骰子
「和等于 7」有多少种?所有「a + b = 7」的组合。这不就是上面那句话吗——把两个 1/6 的均匀分布卷起来:
[1,1,1,1,1,1]/6 ✻ [1,1,1,1,1,1]/6 和: 2 3 4 5 6 7 8 9 10 11 12 次数: 1 2 3 4 5 6 5 4 3 2 1 (/36) P(和=7) = 6/36 = 0.166667
三角形不是巧合:方波卷方波等于三角波。三个骰子再卷一次,出来的形状已经明显像钟形了(最高点 27/216)——第 19 章会说明为什么这一定会发生。
滑动平均
「每个点换成它和前四个点的平均」,就是卷一个 [1,1,1,1,1]/5 的核。它的作用是压噪声,压多少?本机拿 65536 个高斯白噪声样本量了一遍:
核长 L 原始 σ 平均后 σ 理论值 1/√L
────────────────────────────────────────────────────
4 1.0009 0.5015 0.5000
9 1.0009 0.3344 0.3333
16 1.0009 0.2495 0.2500
100 1.0009 0.1007 0.1000
噪声按 √L 下降,这是所有「多测几次取平均」的理论依据。代价是把信号也抹平了——第 15 章会说清这个代价在频域里长什么样。
照片模糊
高斯模糊就是让每个像素变成「它自己和邻居的加权平均」,权重是一个高斯形状的小方块(叫卷积核)。二维卷积和一维完全一样,只是求和变成两重。
顺带一个实用的事实:高斯核是可分离的——先对每一行卷一个一维高斯,再对每一列卷一次,结果和二维卷积完全相同,但运算量从 O(k²) 降到 O(2k)。这是图形学里最常用的一个优化。
混响
在一个房间里拍一下手,录下来的那一长串衰减的回响,叫这个房间的脉冲响应。把任何一段干声和这个脉冲响应卷起来,听起来就像是在那个房间里录的。
这就是「卷积混响」这个产品类别的全部原理,而且它是字面意义上的卷积——插件的名字就叫这个。有人专门跑去悉尼歌剧院、维也纳金色大厅、废弃的水塔里拍一下手,把脉冲响应卖钱。
为什么这么多毫不相干的事情是同一个运算?因为它们都满足两条性质,而满足这两条的运算只有卷积这一种:
- 线性:两个输入叠加,输出也叠加(两个人同时说话,录到的是两段声音的和)。
- 时不变(或平移不变):输入晚三秒,输出也晚三秒,形状不变(房间的混响不会因为你早上拍手还是晚上拍手而改变)。
这两条合起来叫 LTI(线性时不变)。定理是:任何 LTI 系统,都可以完全由它的脉冲响应描述,而它对任意输入的作用,就是和脉冲响应做卷积。
证明的思路一句话:任何输入都可以拆成一串加权的冲激(这是平凡的——第 n 个采样值就是第 n 个冲激的权重);线性说明可以逐个处理再叠加;时不变说明每个冲激的响应都是同一个形状,只是位置不同。把这些平移过的形状按权重加起来——那就是卷积的定义。
三条路,同一个答案
卷积可以用完全不同的方式算,本机核对了一遍:
a = [3, 1, 4, 1, 5] b = [2, 7, 1] 按定义式直接算: 6 23 18 31 21 36 5 当作多项式相乘: 6 23 18 31 21 36 5 绕道频域算: 6 23 18 31 21 36 5 ✓ 直接算与频域路线的最大差:1.8 × 10⁻¹⁵
最后那条路就是下一章的全部内容,也是这本书真正的收款处。
卷积神经网络里的「卷积」,不是这一章的卷积。这一点值得单独说,因为它坑过很多人。
数学定义里,(a ✻ b)[k] = Σ a[i]·b[k−i],注意 b 的下标是倒着走的——这叫「翻转」。而 PyTorch、TensorFlow 里的 Conv2d 实现的是
Σ a[i] · b[k + i] ← 没有翻转
这在数学上叫互相关(cross-correlation),是第 16 章的主角。
为什么框架敢这么干?因为卷积核的权重是学出来的——网络完全可以学出一个翻转过的核,两种定义训出来的模型能力完全等价。所以这只是个命名上的历史遗留,不影响正确性。
但它在两个地方会咬人:一是你手写一个已知的核(比如 Sobel 边缘检测算子)扔进 Conv2d 时,方向会反;二是你想用第 14 章的 FFT 加速去替换框架的卷积时,必须记得翻转,否则结果整个错位。判据是:核是学出来的就无所谓,核是你自己写死的就必须确认方向。
卷积的定义式只有四行,值得亲手写一次:
def convolve(a, b):
out = [0.0] * (len(a) + len(b) - 1)
for i, x in enumerate(a):
for j, y in enumerate(b):
out[i + j] += x * y # 下标相加 —— 这就是全部
return out
print(convolve([1, 2, 3], [1, 1])) # [1, 3, 5, 3]
die = [1/6] * 6
two = convolve(die, die)
print([round(v * 36) for v in two]) # [1,2,3,4,5,6,5,4,3,2,1]
print('P(和=7) = %.6f' % two[5]) # 0.166667
three = convolve(two, die)
print('三个骰子最高点 = %d/216' % round(max(three) * 216)) # 27/216
注意那一行 out[i + j] += x * y:整个卷积就是这一行。「下标相加」这四个字,同时解释了多项式相乘、概率求和、图像模糊和混响。
再看噪声压制那张表:
import numpy as np
rng = np.random.default_rng(20260814)
noise = rng.standard_normal(65536)
for L in (4, 9, 16, 100):
y = np.convolve(noise, np.ones(L)/L, 'valid')
print(f'L={L:4d} σ {noise.std():.4f} → {y.std():.4f} 1/√L = {1/np.sqrt(L):.4f}')
python3 -c " def c(a,b): o=[0]*(len(a)+len(b)-1) for i,x in enumerate(a): for j,y in enumerate(b): o[i+j]+=x*y return o print(c([1,2,3],[1,1]))"
在线跑:python.org/shell,第一段纯标准库。想听卷积混响:Audacity 的「效果 → 混响」里有一项是卷积,随便找一个 impulse response 的 wav 文件试试。
- CNN 的名字。卷积神经网络之所以在图像上有效,核心就是这一章那两条性质:一只猫出现在图片左上角还是右下角,都应该被认出来(平移不变)。卷积是「平移不变的线性运算」的唯一形状,所以它不是一个可选的设计,是这个需求的逻辑后果。
- 大整数乘法。两个大数相乘,本质上是它们的数位序列做卷积(然后处理进位)。这就是为什么下一章那个「用 FFT 加速卷积」的技巧,能直接用来加速大整数乘法——Python 的
int在数字很大时、GMP 库、以及所有做密码学的地方,都在用这条路。你算 RSA 时 CPU 里跑的是傅里叶变换。 - 概率论。「两个独立随机变量之和的分布,是它们各自分布的卷积」是一条基本定理。这条路一直通到第 19 章的中心极限定理。
- 物理测量。任何仪器都有它的「响应函数」——望远镜的点扩散函数、质谱仪的峰形、光谱仪的狭缝函数。你测到的永远是「真实信号 ✻ 仪器响应」。做反卷积(把仪器响应除掉)是整个实验科学的一项日常工作,而它之所以难,是因为除法在有噪声时极不稳定。
- 移动平均线。股票图上的 MA20 就是卷一个长度 20 的矩形核。它「滞后」的原因在第 15 章会看得很清楚:那不是实现问题,是这个核的相位特性。
「卷积是信号处理里的一个技巧,用来做滤波。跟概率、跟多项式那些是不同的东西,只是长得像。」
不是长得像,是同一个。上面那段四行的 convolve 函数,喂给它两个概率分布就得到和的分布,喂给它两个多项式系数就得到乘积的系数,喂给它音频和脉冲响应就得到混响。一段代码,一个运算。
这种「看起来不相干的东西其实是同一个」在数学里通常意味着有一条更深的原因,这里的原因就是那条 LTI 定理:只要你要的操作是「线性 + 平移不变」,那么它必然是某个核的卷积,没有别的可能。所以凡是满足这两条的场合,卷积就会自动出现,无论那个场合叫概率、叫代数还是叫音频。
把这个认识倒过来用,是它真正值钱的地方:下次你遇到一个「线性 + 平移不变」的问题,直接去找它的核;找到了,第 14 章那条定理就会替你把它变成乘法。
正确答案是 D:四件全是,而且是同一段代码。
A、B、C 这三个错法是同一种:按「学科」分类,而不是按「运算」分类。骰子被归到概率,模糊被归到图形学,多项式被归到代数,混响被归到音频——这是四门课,于是看起来像四件事。而它们的共同点不在学科里,在那一行out[i+j] += x*y。
值得多说一句 C 里那个「多项式相乘是纯代数」。恰恰相反,多项式这条线是四条里最有用的一条:它给了卷积一个代数结构(卷积就是多项式环里的乘法),从而立刻送来三条性质——交换律(a ✻ b = b ✻ a)、结合律(连着模糊两次等于模糊一次,核是两个核的卷积)、分配律。这三条在信号处理里天天用,而它们的来源是代数。
还有一条更实际的:因为卷积就是多项式乘法,所以「快速多项式乘法」和「快速卷积」是同一个问题——这正是下一章的定理,以及第 17 章那个算法所要解决的事。
先把线索摆出来:卷积说到底是「把核平移到每个位置,按权重叠加」。而第 4 章测过,平移在频域里就是给每根谱线乘一个单位长度的复数;叠加在频域里还是叠加。「乘一个数再相加」——那不就是把一堆复数加权求和吗?
而当你把那堆权重和那堆复指数拼在一起看,会发现每一根谱线上发生的事情,恰好就是「核在那个频率上的值」乘「信号在那个频率上的值」。一个二重循环,塌缩成了逐点相乘。
这一章的一句话
卷积不是一个技巧,是「线性 + 平移不变」这六个字的唯一形状;所以模糊、混响、平均、掷骰子、多项式相乘会是同一个运算,而这不是巧合,是定理。
下一章是这本书的收款处:那条让前面十三章所有账单都变得值得的定理。先给一个数——两条 16384 长的序列做卷积,老老实实按定义算要 402 毫秒,绕道频域走一趟 2.1 毫秒,而两条路的结果相对误差是 8.4 × 10⁻¹³。