卷积的尺度特性与奇偶特性:从数学推导到工程应用
1. 这个标题背后其实藏着两个最容易被忽略的问题做信号处理也好写卷积神经网络也好大家每天都在跟卷积打交道但大部分人对卷积的理解停留在“加权求和”这一步输入一段信号拿一个核滑过去输出另一段信号。等真正开始调网络、设计滤波器、分析特征响应的时候问题就来了——输入稍微变个形输出就完全不认识了。我最早意识到“卷积的尺度特性”和“卷积的奇偶特性”这两个性质是在一次做多尺度边缘检测的实验里。当时我拿同一张图只是把它缩小了一半再用同一个卷积核去提边缘结果不仅边缘位置偏了响应幅度也彻底对不上。另一个问题出现在调试一个对称性很强的合成信号时输入明明是左右对称的经过一个卷积层之后输出却出现了明显的非对称分量。这两件事逼着我回头把卷积的数学性质重新捋了一遍才发现答案其实都在卷积定义里只是平时没人提醒你。这篇博文就是想把这两个性质讲透。尺度特性解决的是“输入被拉伸或压缩后卷积结果会怎么变”奇偶特性解决的是“输入和卷积核分别具有某种对称性时输出必然具有什么对称性”。这两个问题在图像金字塔、特征金字塔、边缘检测、空洞卷积、网络正则化这些工程场景里频繁出现。适合正在做信号处理、计算机视觉、卷积网络结构设计的人看也适合刚学完卷积定义、想知道“这东西到底有什么用”的学生。我尽量把推导过程写完整同时给出可以直接跑的验证代码和踩坑记录。2. 卷积的尺度特性时间轴被压缩时输出幅度为什么多了个 1/a2.1 先做个思维实验假设你有一段信号 f(t)还有一个卷积核 h(t)。现在把这两个函数在时间轴上都压缩 a 倍变成 f(at) 和 h(at)然后重新做一次卷积。你直觉上会觉得既然两个输入都变“窄”了卷积结果应该也变窄然后形状应该跟原来差不多。实际上卷积结果的时间轴确实被压缩了 a 倍但幅度也整体乘了一个因子 1/a。这个 1/a 是很多人第一次接触时最容易忽视的地方。它不是一个可以忽略的工程误差而是数学上必然出现的“测度因子”。你可以把它理解为积分变量换元时dt 变成了 du/a这个 a 的倒数被强制塞进了结果里。2.2 连续域的完整推导设两个缩放后的信号为f_a(t) f(at)h_a(t) h(at)按卷积定义展开(f_a * h_a)(t) ∫_{-∞}^{∞} f(aτ) h(a(t - τ)) dτ令 u aτ则 τ u/adτ du/a。当 a 0 时积分上下限不变于是(f_a * h_a)(t) (1/a) ∫_{-∞}^{∞} f(u) h(at - u) du (1/a) (f * h)(at)如果 a 0换元后积分上下限会翻转最后整体取绝对值所以统一写成(f_a * h_a)(t) (1/|a|) (f * h)(a t)这个式子就是连续卷积的尺度特性。注意这里有个容易搞混的点卷积核 h(t - τ) 里的 t 也要跟着换元最后得到的自变量是 a t而不是 t。这说明卷积结果“跟随”了输入的时间轴缩放但幅度被一个额外的倒数因子修正了。2.3 从傅里叶变换再看一遍逻辑会更清楚卷积定理说时域卷积等于频域乘积。我习惯用频域再验证一遍这样也能暴露推导中可能出错的细节。信号缩放 a 倍的傅里叶变换是F{f(at)} (1/|a|) F(ω/a)于是缩放后两个信号卷积的频谱为F{(f_a * h_a)} (1/|a|) F(ω/a) · (1/|a|) H(ω/a) (1/a²) F(ω/a) H(ω/a)再看 (1/|a|)(f * h)(at) 的傅里叶变换它等于 (1/|a|) 乘以一个自变量为 at 的函数 f * h 的频谱(1/|a|) · (1/|a|) (F·H)(ω/a) (1/a²) F(ω/a) H(ω/a)两边完全一致。这说明傅里叶视角下多出来的 1/a 其实来源于两次缩放各贡献了一个 1/|a|两者相乘得到 1/a²再和右侧的 1/a 相互抵消正好闭环。2.4 离散实现里的坑采样间隔必须跟着变上面的结论是连续域的。离散卷积处理的是序列信号“压缩 a 倍”只能通过重采样实现这时候坑就来了。如果你直接把离散序列每隔 a 个点抽一个得到 f_d[n] f[an]再把卷积核也这样抽取然后做离散卷积结果跟“先连续卷积再抽取”通常不是一回事。原因是下采样会发生频谱混叠高频信息被折叠进了低频区域离散卷积的结果会混入混叠成分。我之前踩过这个坑想验证尺度特性直接在 numpy 里把两个数组隔点抽取再卷积结果幅度比例怎么都不对。后来才意识到连续域里那个 1/a 是建立在“采样间隔也缩小 a 倍”的前提上的。正确做法是压缩信号后采样间隔要从 dt 变成 dt/a卷积算完再乘上新的 dt否则离散卷积只是“求和”没有密度的概念。在工程上这个性质最常见的两个延伸是多尺度特征提取。图像金字塔和特征金字塔FPN本质上就是对输入做不同尺度的缩放再用同一组卷积核提取特征。尺度特性解释了为什么同一组参数在不同尺度上响应不一样不仅目标大小变了输出能量也在按缩放比例变化。空洞卷积。空洞卷积通过在核元素之间插入零来扩大感受野等效核长度随扩张率线性增长。它不直接复现尺度特性但提供了一种在离散网络上近似模拟多尺度感受野的手段相当于用参数换尺度。3. 卷积的奇偶特性对称性会被卷积“改写”成什么样3.1 先记住这张表卷积的奇偶特性本质上回答一个问题当输入信号和卷积核分别具有某种中心对称性时输出信号的对称性是什么。结论可以整理成一张表输入信号卷积核卷积输出偶函数偶函数偶函数奇函数奇函数偶函数偶函数奇函数奇函数奇函数偶函数奇函数一句话总结同奇偶组合得到偶函数异奇偶组合得到奇函数。注意这里说的偶和奇都是关于时间轴原点的中心对称不是图像的左右对称那么简单。3.2 逐条推导关键是会做时间反转以“偶信号与奇核卷积得奇函数”为例。设 f(t) 为偶函数h(t) 为奇函数则(f * h)(-t) ∫_{-∞}^{∞} f(τ) h(-t - τ) dτ令 u -τ则 τ -udτ -du代入后积分上下限会翻转一次整理得到(f * h)(-t) ∫_{-∞}^{∞} f(-u) h(u - t) du因为 f 是偶函数f(-u) f(u)。而 h 是奇函数h(u - t) h(-(t - u)) -h(t - u)所以(f * h)(-t) -∫_{-∞}^{∞} f(u) h(t - u) du -(f * h)(t)这就证明了输出是奇函数。其余三种组合的推导完全一样只是奇偶替换的位置不同。我自己在推导“奇信号与奇核卷积得偶函数”时最容易出错的地方是 h(u - t) 的负号处理建议每一步都把 t 的反转代进去不要跳步。3.3 频域解释一条捷径但要注意符号细节如果觉得时域换元容易出错用频域能省不少事。实信号 f(t) 可以分解为偶部与奇部对应的频谱分别是实偶函数和虚奇函数。卷积定理说时域卷积等于频域乘法所以只要看两个频谱相乘的结果偶信号频谱是实偶函数奇信号频谱是虚奇函数。实偶 × 实偶 实偶对应时域偶函数。虚奇 × 虚奇 实偶两个虚数单位乘出负号两个奇函数相乘变成偶函数对应时域偶函数。实偶 × 虚奇 虚奇对应时域奇函数。这里有一个很多人查资料时会疑惑的点为什么虚奇 × 虚奇得到实偶而不是虚偶因为 (jA)(jB) -AB负号只是把幅度取反不改变偶函数性质两个奇函数相乘得到偶函数整体仍是实偶函数。搞懂这个前面那张四行表格就能直接默写出来。3.4 奇偶分解任意卷积可以拆成四块任何函数都可以唯一分解为偶部加奇部f(t) f_e(t) f_o(t)其中f_e(t) (f(t) f(-t)) / 2f_o(t) (f(t) - f(-t)) / 2卷积的线性性质允许我们把两个输入都拆开于是f * h (f_e f_o) * (h_e h_o) f_e * h_e f_o * h_e f_e * h_o f_o * h_o按照上一节的表f_e * h_e偶f_o * h_o偶f_e * h_o奇f_o * h_e奇两个偶函数相加还是偶两个奇函数相加还是奇所以任意卷积结果自然分成偶部和奇部。这个分解在工程上的意义在于如果你能确定输入信号是纯偶或纯奇或者你的卷积核是纯偶或纯奇那么输出对称性就直接确定了根本不用算完整卷积。3.5 工程应用边缘检测核为什么都是奇对称的把这个性质放到图像处理里很多设计选择就变得非常清晰。高斯平滑核是偶函数它对一个左右对称的亮度剖面做卷积输出仍然是偶函数。这意味着平滑操作不会引入位置偏移也不会产生方向性偏差。而边缘检测常用的一阶导数核比如高斯的一阶导数是奇函数。对同样对称的亮度剖面奇核卷积输出是奇函数在对称中心处必然过零两侧出现正负两瓣。这正是边缘检测需要的性质平坦区域输出为零边缘位置出现极性变化过零点正好对准阶跃边缘的中心。反过来如果你用一个偶核对阶跃边缘做卷积输出是一个对称的峰虽然也能定位边缘但对噪声更敏感而且无法区分上升沿和下降沿。理解了奇偶特性你就明白为什么各种边缘检测算子里平滑用偶核、差分用奇核这不是习惯而是数学在逼你这么做。4. 动手验证用一段代码把两个性质都看清楚4.1 验证奇偶特性直接看公式容易记混我每次教别人的时候都建议跑一段最小验证代码。下面这个例子构造一个偶信号高斯和一个奇核高斯导数卷积结果应当是奇函数。import numpy as np N 4001 t np.linspace(-6, 6, N) dt t[1] - t[0] # 偶信号高斯 f np.exp(-t**2) # 奇核高斯的一阶导 h -2.0 * t * np.exp(-t**2) # 离散卷积乘 dt 是因为离散求和近似连续积分 y np.convolve(f, h, modefull) * dt # 卷积结果的时间轴两个时间轴相加 t_y np.linspace(2 * t[0], 2 * t[-1], len(y)) # 找到零点位置检查 y 是否为奇函数 idx0 np.argmin(np.abs(t_y)) n min(idx0, len(y) - idx0 - 1) seg y[idx0 - n : idx0 n 1] # 奇函数应满足 y(t) y(-t) 0 residual np.max(np.abs(seg seg[::-1])) print(奇对称残差:, residual)这个残差在浮点精度范围附近就说明验证通过。你可以把 h 换成偶核比如高斯本身再验证偶信号与偶核卷积得到偶函数把 f 换成奇信号再测奇奇组合。多跑几组表格里的结论很快就变成直觉。4.2 验证尺度特性尺度特性的验证比奇偶容易出错关键就在采样间隔。下面这段代码把采样间隔的处理标出来了a 2.0 # 用更密的点模拟连续信号 t np.linspace(-4, 4, 20001) dt t[1] - t[0] f np.exp(-t**2) h -2.0 * t * np.exp(-t**2) y np.convolve(f, h, modefull) * dt # 缩放后信号时间轴压缩 a 倍采样间隔也缩小 a 倍 ta t * a fa np.exp(-(ta)**2) ha -2.0 * ta * np.exp(-(ta)**2) dt_a dt / a ya np.convolve(fa, ha, modefull) * dt_a # 两个卷积结果的时间轴 ty np.linspace(2 * t[0], 2 * t[-1], len(y)) tya np.linspace(2 * ta[0], 2 * ta[-1], len(ya)) # 把 ya 插值到“压缩后时间轴”的对应位置再与 (1/a) y(at) 比较 ya_interp np.interp(ty * a, tya, ya) y_expect (1.0 / a) * np.interp(ty, ty, y) # 这里仅作示例简化 print(最大误差:, np.max(np.abs(ya_interp - y_expect / a)))这段代码的重点是两个地方一是压缩信号时采样间隔必须同时除以 a二是比较时要把卷积结果的时间轴也按 a 倍映射回去。我在第一次写这个实验时忘了改采样间隔结果幅度比例差了整整 a 倍。后来又把时间轴映射写反了比对结果一塌糊涂。如果你跑出来的误差不是浮点级先检查这两步。4.3 离散卷积验证的两个常见错误离散卷积验证最常翻车的地方有两个。第一个是边界效应。np.convolve 的 full 模式会把两端的边界都算进去而离散序列的奇偶性要求序列关于索引中心对称。如果你的原始信号和核长度不是奇数或者中心点没对齐残差会明显偏大。解决办法是构造信号时让时间轴包含 0且采样点数为奇数并在比较时只取中心区域。第二个是忘记积分测度。离散卷积本质是求和不是积分。要模拟连续卷积的尺度特性必须乘以采样间隔 dt。很多人在连续域推导时能得到 1/a但代码里只做 np.convolve 不乘 dt结果就把 1/a 弄丢了。这不是理论错是实现错。5. 实际工程中的典型应用场景5.1 图像边缘检测与对称滤波器设计前面已经提到边缘检测用奇核、平滑用偶核。再补充一个实战细节在对称核的支持下卷积计算可以减半。如果你能确认卷积核是偶对称的那么对每个输出点只需要计算一半的加权和另一半直接复用。这个优化在一维滤波器里收益不明显但在二维大核、批处理场景下能省掉不少乘加运算。某些嵌入式平台上的卷积实现就是靠先判断核的对称性再选择快速路径来提速的。还有层归一化和数据增强的配合问题。如果你在训练时对输入做了水平翻转那么卷积核也应该相应做水平翻转后再卷积输出才能等价地翻转。这个操作背后的依据就是卷积对水平翻转一种奇偶变换的表现的响应规律。许多人在数据增强后发现模型行为不一致往往就是忘记了核也应该跟着做同样的空间变换。5.2 多尺度特征从拉普拉斯金字塔到特征金字塔尺度特性的工程价值最直观的体现就是多尺度表示。传统图像处理里的拉普拉斯金字塔是对图像逐级下采样再做差分。每一层相当于对原图做了一次尺度变化后的带通滤波。因为尺度变化会引入 1/a 的幅度修正所以金字塔重建时每一层都要乘回对应的缩放系数否则图像整体亮度会出现阶梯状误差。在卷积网络中特征金字塔网络FPN解决的是目标检测里大目标和小目标共存的问题。浅层特征分辨率高但语义弱深层特征语义强但分辨率低。FPN 把深层特征上采样后与浅层特征相加本质上是在做多尺度特征的融合。尺度特性在这里的启示是不同尺度的特征在叠加之前幅度标定很重要。如果不做任何归一化深层特征和浅层特征的能量差异会直接影响融合比例表现出来就是小目标检测不稳定。空洞卷积是另一个典型场景。同一个卷积核扩张率从 1 调到 2、4、8感受野呈指数增长而参数数量不变。它不严格等于尺度特性因为插入零并不会改变卷积核的能量密度但它确实提供了一种“用参数换尺度”的手段。我记得在一次语义分割实验中把最后一个阶段的普通卷积换成扩张率 2 的空洞卷积mIoU 涨了大概两个点代价只是多调一个超参数。理解尺度特性之后你就明白这种操作的本质是让同一组特征在不同感受野尺度下被重新观察而不是简单地加大卷积核。5.3 对称性正则化与卷积核分解奇偶特性在卷积网络里的另一个用法是正则化和参数压缩。如果一个任务本身具有对称性比如人脸关键点检测、车牌识别、对称物体分割那么可以约束卷积核向偶对称或奇对称方向学习。具体做法是把卷积核参数分解为偶部和奇部h_e (h flip(h)) / 2 h_o (h - flip(h)) / 2然后只让其中一部分参与梯度更新或者对另一部分做权值衰减。这样做的好处是网络输出的对称性有了数学保证不会因为训练数据不平衡而产生偏移。我还见过把核分解成偶部和奇部两个分支分别提取对称特征和反对称特征再融合的做法在某些对称性很强的数据集上效果比普通卷积更好。但这种做法也有代价过度约束会损失模型的表达能力。如果一个任务本身并不完全对称强制把核约束成偶对称等于砍掉了一半的假设空间。我的建议是只在确信先验对称性的任务上使用并且先用普通卷积跑一个 baseline再对比约束后的效果。如果两者接近说明对称先验合理如果约束后明显下降说明任务里其实存在非对称信息硬套先验只会帮倒忙。6. 常见问题与排查技巧速查表下面这个表是我在项目里反复用到的排查清单也回答一些高频疑问现象可能原因排查与解决思路验证尺度特性时幅度比例不是 1/a离散卷积没乘采样间隔或压缩后 dt 没改统一用 dt压缩信号后采样间隔除以 a再对比验证奇偶特性时残差过大时间轴没有包含原点或序列长度为偶数构造信号时保证 t 包含 0点数为奇数只比较中心区域数据增强翻转后模型输出不对翻转了输入但没有对应翻转卷积核对核做同样的翻转操作再卷积对称核在 FPGA / 嵌入式上验证性能没提升编译器或硬件库已经做了优化或核尺寸太小用大核 批量通道测试先对比乘加次数再压测多尺度特征融合后小目标反而更差不同尺度特征能量不一致对每层特征做归一化或学习自适应融合权重CNN 中加入对称性约束后效果变差任务本身存在非对称信息去掉约束或只对部分层施加约束另一个经常被问到的问题是这些性质在卷积神经网络里还能直接套用吗答案是部分可以但要小心。卷积层本身满足线性性和对称性但后面通常跟着批归一化和非线性激活函数。批归一化会对每个通道做仿射变换其中的 scale 不区分奇偶会破坏输出的纯奇偶性ReLU 更是直接把负半轴压到零任何奇函数经过 ReLU 都变成非奇非偶函数。所以在网络深层讨论奇偶性必须限定在“纯卷积部分”或者“没有非线性之前”的范围。我一般用奇偶特性做网络结构的可解释性分析时只看卷积层输出不会把 BN 和激活之后的特征也算进去。还有一点是关于离散序列长度的。卷积核长度为奇数时核的中心可以定义在索引 (N-1)/2 处奇偶性验证相对直观。长度是偶数时中心落在两个点之间需要额外考虑 0.5 个采样点的平移。很多资料里的性质推导默认是连续函数落到离散序列上你得多做一步中心对齐。这一步不做残差会一直很大却不是你代码的 bug。7. 我在实际项目里用过之后的一点体会这两个性质单独看都是卷积定义里的“小结论”但它们组合起来能帮你省掉大量无用的调试时间。我记得后来再做多尺度边缘检测时要预判某一层输出大概长什么样基本不用先把整张图跑一遍直接根据输入信号的对称性和缩放程度就能把输出曲线的形状、过零点位置、幅度范围都估算个八九不离十。这种“用手算验证网络行为”的能力在排查 bug 和设计消融实验时特别管用。最后分享一个小技巧当你面对一个复杂的卷积系统不要急着写大段代码。先把输入信号和卷积核按奇偶部分解把多出来的奇部、偶部分别过一遍系统再组合回去。你会发现很多看似随机的问题其实只是某一部分在尺度变换时多乘了一个系数或者某一部分的对称性被非线性激活打破了。把这些性质用熟练之后再回去看那些“调参调不出来”的模型心里会踏实很多。