Nonlocal均值滤波 → \rightarrow →Nonlocal attention → \rightarrow →Transformer的自注意力
目录
- Nonlocal均值滤波
- Nonlocal attention
- 矩阵表示,这只是为了实现。
- reshape
- 矩阵运算
- 相异度矩阵
- 相似度计算
- 1. Gaussian Function(高斯函数)
- 2. Embedded Gaussian(嵌入高斯)
- 3. Dot Product(点积)
- 4. Concatenation(拼接)
- 网络实现,这只是矩阵表示的网络实现
- Transformer的自注意力
- 计算过程
- 三点说明
- Multi-Head Attention
- 计算过程
- 自注意力在语音识别中的作用,相比RNN的优势
- 写在后面的话
Nonlocal均值滤波
上篇讲到了非局部均值滤波方法,何曾想2005年的这篇去噪滤波的论文居然能走这么远,成了Transformer的核心。
我可服那些从不思考为什么的人、那些别人说怎么做就怎么做的人,就没有觉得哪里不对劲?
非局部均值滤波方法之所以有效,这幅图很直观。双边滤波选择与中心像素灰度相似且距离较近的邻域进行加权平均;而非局部均值找到与中心像素周围区域具有相似纹理特征的远距离邻域(说自注意力远距离依赖就是这么来的)来进行加权平均的。虽然两者都利用了相似性原则来降低噪声影响,但是它们关注的重点不同——双边滤波侧重于局部空间关系,而非局部则注重全局纹理匹配。
当然这是有假设的。非局部均值是基于自相似性的假设,即图像中存在重复出现的模式或纹理。在非局部均值算法中,每个像素点的估计值是通过在整个图像中寻找与其周围区域具有高相似性的其他区域进行加权平均得到的,当然能够有效地消除高斯噪声,同时还尽可能地保留图像的结构信息。高明!
Non-local的本质是某一像素点处的响应是所有点处的特征加权和,权重为两点的相似度。假设有一个 5 × 5 5 \times 5 5×5 的图像块,计算其中心像素 p p p(蓝色点)与其他像素的相异度或相似度,对于在图像块内的每个像素 q q q,计算 D ( p , q ) = ∥ v p − v q ∥ 2 D(p, q) = \| v_p - v_q \|^2 D(p,q)=∥vp−vq∥2,使用高斯核函数 G ( p , q ) = e − D ( p , q ) h 2 G(p, q) = e^{-\frac{D(p, q)}{h^2}} G(p,q)=e−h2D(p,q)(绿色的那个矩阵)。图中的 ⊗ \otimes ⊗实际上是Kronnecker积的符号,这里表示点积(向量定义借用到矩阵,表示对应元素相乘再相加),点积的结果是中心像素 p p p的输出。但是,我们需要计算所有点的输出,怎么办呢?循环?矩阵工作室不喜欢,GPU不喜欢。我们过渡到下一节。
Nonlocal attention
矩阵表示,这只是为了实现。
一切为了利用GPU的并行计算功能。
reshape
在非局部注意力机制中,为了方便计算相似度并进行加权求和,首先需要对高维特征(如图像块)进行reshape。
假设输入特征图 X X X,其尺寸为 H × W × D H \times W \times D H×W×D,其中 H H H和 W W W是特征图的高度和宽度, D D D是特征数(通道数)。将特征图 X X Xreshape成一个二维矩阵 X ˊ \acute X Xˊ,其形状为 N × D N \times D N×D,其中, N = H W N=HW N=HW,这样每个行向量代表了一个位置的特征向量。
X ˊ = reshape ( X , ( H × W , D ) ) \acute X= \text{reshape}(X, (H \times W, D)) Xˊ=reshape(X,(H×W,D))
矩阵运算
- 计算相异度矩阵(模式识别中的基础概念,后面紧跟)
- 加权求和
分别讲解这两步的意义。
注:我很同情这样讲解nonlocal的人,但是这两幅图能够说明如何通过矩阵乘法实现。
相异度矩阵
相异度矩阵(Dissimilarity Matrix)用于表示数据点之间的相似度或距离。在非局部滤波(Non-local Means Filtering)中,相异度矩阵用于计算图像中不同像素块之间的相似度,进而确定权重。
相异度矩阵 D D D是一个 N × N N \times N N×N的矩阵,其中 N N N是数据点的数量。矩阵中的每个元素 D ( i , j ) D(i, j) D(i,j)表示数据点 i i i和数据点 j j j之间的相似度(或距离)。相似度可以是多种度量方式,常见的包括欧氏距离(高斯核欧氏距离)、余弦相似度等。
用鸢尾花数据集举例,观察相异度矩阵的样子。鸢尾花数据集150个样本,这个相异度矩阵是 150 × 150 150\times150 150×150。由于一类中的样本和其他类中的样本相似性弱,因此从相异度矩阵能看出三个类别。蓝色表示距离小,黄色表示距离大。这个数据集中1-50个样本是第一类,以此类推。
相似度计算
在Nonlocal attention中,相似度计算通过衡量不同位置(或元素)之间的相关性或相似度,为后续的加权求和提供权重信息。在nonlocal滤波中,常用的相异度计算方法是欧氏距离的平方,然而在网络中还没有办法实现范数距离,因此使用相似系数计算距离的系列,也就是计算内积,点这里。
以下是Nonlocal Network中给出的相似度计算公式:
1. Gaussian Function(高斯函数)
公式为:
f ( x i , x j ) = e x i T x j f(x_i, x_j) = e^{x_i^T x_j} f(xi,xj)=exiTxj
其中, x i x_i xi 和 x j x_j xj 分别表示两个位置(或元素)的特征向量。这个公式直接计算了特征向量之间的点积,并通过指数函数进行放大,以得到相似度权重。
2. Embedded Gaussian(嵌入高斯)
公式为:
f ( x i , x j ) = e θ ( x i ) T ϕ ( x j ) f(x_i, x_j) = e^{\theta(x_i)^T \phi(x_j)} f(xi,xj)=eθ(xi)Tϕ(xj)
其中, θ ( x i ) \theta(x_i) θ(xi) 和 ϕ ( x j ) \phi(x_j) ϕ(xj) 分别表示对 x i x_i xi 和 x j x_j xj 进行的线性变换(通常通过1x1卷积实现)。这种方法通过嵌入空间中的点积来计算相似度。
3. Dot Product(点积)
公式为:
f ( x i , x j ) = θ ( x i ) T ϕ ( x j ) f(x_i, x_j) = \theta(x_i)^T \phi(x_j) f(xi,xj)=θ(xi)Tϕ(xj)
与Embedded Gaussian类似,这种方法也使用了线性变换后的特征向量进行点积运算。
4. Concatenation(拼接)
公式为:
f ( x i , x j ) = ReLU ( w f T [ θ ( x i ) , ϕ ( x j ) ] ) f(x_i, x_j) = \text{ReLU}(w_f^T [\theta(x_i), \phi(x_j)]) f(xi,xj)=ReLU(wfT[θ(xi),ϕ(xj)])
其中, [ θ ( x i ) , ϕ ( x j ) ] [\theta(x_i), \phi(x_j)] [θ(xi),ϕ(xj)] 表示将 θ ( x i ) \theta(x_i) θ(xi) 和 ϕ ( x j ) \phi(x_j) ϕ(xj) 拼接成一个更长的向量, w f w_f wf 是一个可学习的权重向量。这种方法通过拼接和线性变换来捕捉不同位置之间的复杂关系,并通过ReLU函数引入非线性。
为了构建全局注意力图,还需要对计算得到的相似度进行归一化处理(如通过softmax函数),以确保权重之和为1。
强调:虽然是两两计算内积,但是两个矩阵的地位是不同的,对于每个Q,计算与K中所有点的内积,结果一行是每个Q,在K中对应的权系数,所有无论归一化,还是后面Transformer中除以 D k \sqrt{D_k} Dk 都是对行进行处理。
加权求和是将每一个向量(彩色条)用它对应的相似度(彩色点)作为权重相乘,并求和。这里如若对矩阵乘积运算很熟悉,了解它的几何意义,而不是只会计算,那对该矩阵运算想做什么一目了然。然而,上面引用的那个图的黄线和黄点也就是说明了如何进行矩阵运算。这里简单说明线性变换的几何意义。
线性变换相当于空间变换,也就是从一个空间变换到另一个空间,变换矩阵的每一行实际上是变换空间的基向量,左边的每一行(彩色点)实际上在新空间的表示系数,空间变换就是基向量的线性组合。如果你的线性代数老师没有讲线性变换的几何意义,那就让你的老师回家卖红薯去吧。这里用矩阵后乘表示。这不是现在的规范(看后面的话),但是被python搞混乱了,深度学习入行门槛低,实在头痛。还是MATLAB专业,支持MATLAB,支持矩阵实验室。
网络实现,这只是矩阵表示的网络实现
为了扩展,分别起了名字,即查询(Query)、键(Key)和值(Value),上面的两幅图上已经标出。Q表示待处理的点,K是需要衡量相似性的点,V是需要做加权平均的点。自注意力(例如Transformer)它们是同一值,尽管是不同的线性变换。一般K和V是同样的。很多的滥用。
Nonlocal的块中加了一个残差连接,残差学习的作用不用说了吧。
这幅图标出了对应的数学表达式,我就拿来用了。
Transformer的自注意力
Transformer 模型中的自注意力机制(Self-Attention)是其核心组件之一,它使得模型能够并行处理输入序列,并且有效地捕捉长距离依赖关系。自注意力机制通过计算输入序列中每个位置与其他位置之间的关系,生成注意力权重,从而对输入序列进行加权求和。
计算过程
-
输入表示:
- 输入序列通常表示为一个形状为 ( M , N , D ) (M, N, D) (M,N,D) 的张量,其中 M M M 是批量大小, N N N 是序列长度, D D D 是特征维度。
-
线性变换:
- 为了计算自注意力,首先对输入序列进行线性变换,生成三个不同的向量:查询向量(Query)、键向量(Key)和值向量(Value)。这些向量分别表示为 Q Q Q、 K K K 和 V V V。
Q = X W Q , K = X W K , V = X W V Q = XW_Q, \quad K = XW_K, \quad V = XW_V Q=XWQ,K=XWK,V=XWV
其中 X X X 是输入序列, W Q W_Q WQ、 W K W_K WK 和 W V W_V WV 是可学习的权重矩阵。
-
计算相异度矩阵:
- 计算查询向量和键向量之间的点积,得相异度矩阵 S S S。
S = Q K T D k S = \frac{QK^T}{\sqrt{D_k}} S=DkQKT
其中 D k D_k Dk 是键向量的维度,除以 D k \sqrt{D_k} Dk 是为了防止内积过大。每一行做。
-
应用 Softmax:
-应用 Softmax 函数对相异度矩阵 S S S行归一化 ,得注意力权重矩阵 A A A。A = softmax ( S ) A = \text{softmax}(S) A=softmax(S)
-
加权求和:
- 使用注意力权重矩阵 A A A 对值向量 V V V 进行加权求和,得到输出向量 O O O。
O = A V O = AV O=AV
三点说明
-
Self-Attention 的输入用矩阵 X X X进行表示,则可以使用线性变阵矩阵 W Q W_Q WQ、 W K W_K WK 和 W V W_V WV计算得到 Q, K, V。线性变换的目的是特征变换,类比PCA,目的是降维,比如降维为原来的 1 / 2 1/2 1/2。降维是模式识别的基本概念,学过模式识别的都知道它的作用。不同的是, W Q W_Q WQ、 W K W_K WK 和 W V W_V WV 是可学习的权重矩阵。
-
Transformer的自注意力中的相似度计算简单使用两点的点积,特征变换后的两点内积。
-
这个softmax归一化公式实际上写的有问题。公式中的 Softmax 是对相异度矩阵的每一行用Softmax进行归一化,即每一行的和都变为 1。代码中这样写没有问题,这个函数可以独立处理矩阵的每一维。那些不能区分数学语言和函数语言的人,我表示无能为力。
为什么用softmax进行归一化?softmax通过指数运算(exp函数)对输入值进行放大,从而放大了输入值之间的差异。**高斯滤波、双边滤波和非局部滤波的权重都是距离的(负)指数函数。**其实概率分布中很多都是指数函数,这说明什么呢?说明自然界中很多现象都适合用指数函数描述。
Multi-Head Attention
为了增强模型的表达能力,Transformer 使用多头注意力(Multi-Head Attention)。多头注意力通过将输入序列分成多个不同的子空间,分别计算注意力,然后将结果拼接起来,再进行一次线性变换。这实际上就是多次处理求个加权平均(类比模式识别中的集成学习、组合分类器,与dropout一样的出发点),增加稳定性而已。
计算过程
-
多头线性变换:
- 对输入序列进行多次线性变换,生成多个查询向量、键向量和值向量。
Q i = X W Q i , K i = X W K i , V i = X W V i Q_i = XW_{Q_i}, \quad K_i = XW_{K_i}, \quad V_i = XW_{V_i} Qi=XWQi,Ki=XWKi,Vi=XWVi
其中 i i i 表示第 i i i 个头。
-
多头注意力计算:
- 对每个头分别计算注意力权重和加权求和。
O i = softmax ( Q i K i T D k ) V i O_i = \text{softmax}\left(\frac{Q_i K_i^T}{\sqrt{D_k}}\right) V_i Oi=softmax(DkQiKiT)Vi
-
拼接和线性变换:
- 将所有头的输出拼接起来,再进行一次线性变换。
O = Concat ( O 1 , O 2 , … , O h ) W O O = \text{Concat}(O_1, O_2, \ldots, O_h) W_O O=Concat(O1,O2,…,Oh)WO
其中 h h h 是头的数量, W O W_O WO 是最终的线性变换矩阵。
Transformer中的图来自这里。
自注意力在语音识别中的作用,相比RNN的优势
在语音识别中,每一个单词都提取的特征向量,这样X, Q, K, V 的每一行都表示一个单词。
自注意力机制(Self-Attention)在语音识别任务中发挥着重要作用,尤其是在处理长序列数据时,相比传统的循环神经网络(RNN)具有明显的优势。
-
捕捉长距离依赖:
- RNN:RNN 通过隐藏状态传递信息,但在处理长序列时容易遇到梯度消失或梯度爆炸的问题,导致难以有效捕捉长距离依赖关系。
- 自注意力:自注意力机制可以直接计算任意两个位置之间的关系,不受序列长度的限制,能够有效捕捉长距离依赖关系,适用于处理长序列数据。
-
并行计算:
- RNN:RNN 是顺序计算的,每个时间步的计算依赖于前一个时间步的隐藏状态,这导致了计算效率低。
- 自注意力:自注意力机制可以并行计算,因为每个位置的注意力权重可以独立计算,可以充分利用 GPU的并行计算能力,大幅提高了计算效率。
-
建模复杂依赖:
- RNN:RNN 通过隐藏状态传递信息,但隐藏状态的容量有限,难以建模复杂的依赖关系。
- 自注意力:自注意力机制通过多头注意力(Multi-Head Attention)可以从多个不同的子空间中捕捉不同类型的依赖关系,增强了模型的表达能力。
-
内存效率:
- RNN:需要存储每个时间步的隐藏状态,内存消耗较大。
- 自注意力:只需要存储输入序列和注意力权重,内存消耗相对较低。
-
可解释性:
- RNN:隐藏状态的含义不明确,难以解释。
- 自注意力:注意力权重可以直接解释为不同位置之间的相关性,提高了模型的可解释性。
-
处理变长输入:
- RNN:RNN 需要对变长输入进行填充或截断,这可能导致信息丢失或引入噪声。
- 自注意力:自注意力机制可以自然地处理变长输入,不需要额外的填充或截断操作。
写在后面的话
在2000年前,矩阵乘法的规范是行向量表示(矩阵后乘),其实这种表示更符合信号变换的基向量展开公式,但是2000年后,规范就改为了列向量表示(矩阵前乘),在两年前MATLAB将最后没改部分也改成了列向量表示。虽然我不知道为什么改成列向量表示,我也无所谓规范是矩阵后乘还是矩阵前乘,但是规范才能让我们更方便交流,就像洗衣机的高度都是一样的,方便装修的道理是一样的。然而,python中矩阵向量乘积用的是行向量表示方式,又带回了2000年前,那些数学基础不好的,又表达不清楚的,就会让这个世界很混乱。
这是我很佩服的一人,对这段历史的说明。
这个图是以现在的规范,也就是列向量表示的,引用于下面的那本书。但是现在规范的很少,我懒得配套画图,前面的内容不得不屈从不规范的python。这本书站位高,很多问题都深入剖析了,极力推荐。