从高斯模糊到卷积再到diffusion模型
Table of Contents
卷积好有意思,于是就写了
#
高斯模糊
高斯模糊是一种模糊图像的算法,但你有没有想过算法具体是如何运作的?
让我们从高斯分布开始说起
大多数人都肯定听过正态分布,即随机变量的平均值的概率密度函数,自然界中的随机变量在样本增加后会逐渐收敛成正态分布。你们可能已经猜到了,高斯模糊的核心正是高斯分布。
一维高斯分布的概率密度函数为:
$$ G(x) = \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$
其中,μ 是均值,σ 是标准差。
对于图像处理,我们通常使用二维高斯分布: $$ G(x, y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2+y^2}{2\sigma^2}} $$ (这里假设中心点为 (0,0),即 μ=0)
想象一个 3 * 3 的网格,平铺到图片的左上角,网格与图片的像素对齐。现在有一种算法,将 3 * 3 网格中的9个像素的R G B值分别取平均值,处理结束后将这个平均值像素放到网格的正中心。我们完成了一次图像处理!接下来只要将所有像素都这样操作一遍,我们就能得到一张平均模糊后的图像!太神奇了!
而高斯模糊就是这样的操作,只不过使用了其它尺寸的网格,且平均方式是加权平均。想象将正态分布的图像沿y轴旋转,形成了一个凸起的平面。网格的加权方式就是采用这个平面对应点的高度作为权重,使用这样的方式进行加权平均。这个网格通常也称为高斯核。
#
卷积
刚才我们提到的那个网格其实叫卷积核(convolution kernel),简单来说,卷积核是一种滑动+计算的操作,通过设计不同的卷积核算法,我们就可以用来处理图像或提取图像的特征。例如一个3*3的网格,只不过这次 左边一列的权重为正,右边一列的权重为负。通过这个卷积核,我们就可以知道这个图像中哪些地方是左边缘,哪些地方是右边缘。
⚠️注意!计算机中的卷积和数学中的卷积原理相同,但计算机中的卷积没有翻转的操作,因为大家发现翻不翻转都一样!
我们再来讲讲数学中的卷积。想出卷积这个名字的人真是个天才! 数学中的卷积正如其名字所描述,对两组数进行操作时,将其中一组数字翻转过来,倒过来进行挨个相乘并相加。
离散卷积的通用数学定义(一维)为: $$ (f * g)[n] = \sum_{m=-\infty}^{\infty} f[m] g[n-m] $$ 或者,在有限信号且考虑翻转的情况下: $$ (f * g)[n] = \sum_{m} f[m] g[n-m] \quad \text{(注意 g 的索引是 n-m,体现翻转和滑动)} $$
让我们看一个例子:
将一维数组 [1, 2, 3, 4, 5]
使用卷积核 [-1, 0, 1]
进行卷积。首先,我们要将卷积核 卷过来,得到处理后的卷积核 [1, 0, -1]
。我们再把数组与卷积核对齐。进行运算
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
1 | 0 | -1 |
$$ \text{output}[0] = (1 \times 1) + (2 \times 0) + (3 \times -1) = 1 + 0 - 3 = -2 $$
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
1 | 0 | -1 |
$$ \text{output}[1] = (2 \times 1) + (3 \times 0) + (4 \times -1) = 2 + 0 - 4 = -2 $$
1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|
1 | 0 | -1 |
$$ \text{output}[2] = (3 \times 1) + (4 \times 0) + (5 \times -1) = 3 + 0 - 5 = -2 $$
最后,我们可以得到数组[-2, -2, -2]
,这就是经过卷积核计算后的结果。
值得注意的是,在这里我为了简化计算流程(计算机也是这么干的),两个数组完全对齐。在严谨的数学计算中,需要从数组的第一个数和卷积核的最后一个数开始卷积(或者根据定义调整边界)。
再提一嘴,你虽然不知道卷积是什么意思,但你肯定用过。回想一下多项式乘法中是不是用到了卷积的思想?例如 $$ P(x) = a_0 + a_1 x + a_2 x^2 $$
$$ Q(x) = b_0 + b_1 x $$
$$ R(x) = P(x) \times Q(x) = c_0 + c_1 x + c_2 x^2 + c_3 x^3 $$
其中系数 ck 的计算方式为: $$ c_k = \sum_{i=0}^{k} a_i b_{k-i} \quad (\text{假设 } a_i=0 \text{ for } i>2, b_j=0 \text{ for } j>1) $$ 例如:
- c0 = a0 b0
- c1 = a0 b1 + a1 b0
- c2 = a1 b1 + a2 b0
- c3 = a2 b1
发现了吗,R 的系数 [c0, c1, c2, c3]
是系数序列 [a0, a1, a2]
和 [b0, b1]
的卷积!
如果你想知道如何如何快速运算两个超大的多项式的乘积,你可以接着往下看。但我想先说说diffusion模型。
#
Diffusion
再来讲讲卷积的应用。其中最出名的就是diffusion模型,在这里我只想聊聊图片生成。
由于卷积捕捉图像特征的特性,人们很快就想到了将其运用到图像处理上。其中最著名的发明就是 U-Net。通过卷积核在图像上滑动并捕捉图像特征,计算机可以提取到图像特别之处再进行存储。通过 U-Net 的下采样(downsampling),可以增加卷积层的感受野(receptive field),让模型可以捕捉更大的上下文信息。
简单来说,diffusion模型是一个预测模型,我们人为创造一幅沙画,再通过吹气的方式为图像添加噪声,让模型学习噪声添加后的沙画和原本的沙画有什么区别。重复吹沙画好多次,我们就可以得到一幅完全混乱的图像,也称作高斯噪声(居然又是高斯!)。通过让模型学习不同的沙画,最后的模型就可以通过完全随机的噪声生成图像。这就是diffusion模型的原理。
接下来我想聊聊更有意思的
##
快速傅立叶变换 (FFT)
卷积定理提出,两个函数在时域(或空域)的卷积,等于它们各自进行傅立叶变换后在频域的乘积。反之亦然。
用公式表示卷积定理: $$ \mathcal{F}{f * g} = \mathcal{F}{f} \cdot \mathcal{F}{g} $$ 以及 $$ f * g = \mathcal{F}^{-1}{\mathcal{F}{f} \cdot \mathcal{F}{g}} $$ 其中, $\mathcal{F}$ 表示傅立叶变换 (Fourier Transform), $\mathcal{F}^{-1}$ 表示傅立叶反变换 (Inverse Fourier Transform), $*$ 表示卷积, $\cdot$ 表示逐点乘积。
很显然,大部分人都不知道这句话是什么意思。
简单来说,将两袋混合口味的糖果直接进行卷积很难,但通过傅立叶变换,就可以将这袋糖果拆开,告诉你有多少种口味,以及对应的糖果数量(对应频域信息)。将这两袋糖果的成分对应位置的成分量相乘,就得到了新的成分列表。通过傅立叶反变换,就可以将糖果再混合成一袋新的糖果。这个过程与卷积完全无关,但得到了与卷积完全一样的结果!
这个过程被称为快速傅立叶变换(Fast Fourier Transform),可以很快速地计算卷积。它可以将计算的复杂度从 O(N²) 降低到 O(N log N)。太神奇了!
对于diffusion模型中的大型计算,快速傅立叶变换极大地提高了计算效率!
数学真的是太神奇了