self attention-none local block与evcblock中的通用方法解释

原文链接:https://blog.youkuaiyun.com/weixin_45250844/article/details/103217032
参考以上内容有感:
在none local block当中实现了一个事情,就是对图片(或特征图)本身的值进行了变化,变化后的图内的特征间相关性强的部分就会更突出,比如对于一个人的特征,鞋的边缘在经过这个非局部操作后特征就会更突出
在这里插入图片描述
原本比较模糊,经过非局部操作后则明显多了,这可以很好的加强特征。
这种方法我认为是用于图像处理的,但是用的是深度学习self attention的思想与深度学习卷积的代码实现的。
代码:

    def forward(self, x):
        '''
        :param x: (b, c, t, h, w)
        :return:
        '''

        batch_size = x.size(0)

        g_x = self.g(x).view(batch_size, self.inter_channels, -1)

        g_x = g_x.permute(0, 2, 1)

        theta_x = x.view(batch_size, self.in_channels, -1)
        theta_x = theta_x.permute(0, 2, 1)

        if self.sub_sample:
            phi_x = self.phi(x).view(batch_size, self.in_channels, -1)
        else:
            phi_x = x.view(batch_size, self.in_channels, -1)

        f = torch.matmul(theta_x, phi_x)
        f_div_C = F.softmax(f, dim=-1)

        y = torch.matmul(f_div_C, g_x)
        y = y.permute(0, 2, 1).contiguous()
        y = y.view(batch_size, self.inter_channels, *x.size()[2:])
        W_y = self.W(y)
        z = W_y + x

        return z

当中最值得我们注意的是

#(6,3,10,10)
        g_x = self.g(x).view(batch_size, self.inter_channels, -1)
#-》(6,3,100)
        g_x = g_x.permute(0, 2, 1)
#-》(6,100,3)

这里我们对于一个特征图,尺寸比如是(6,3,10,10)最终变成(6,100,3)
然后再用同样的方法得到另外一组张量:


            phi_x = x.view(batch_size, self.in_channels, -1)

这组张量变化后尺寸也是(6,100,3)
然后再用矩阵乘法,相乘(其中 phi_x 不变化是为了得到转置的结果)

      f = torch.matmul(theta_x, phi_x)

最后相乘得到,像素点之间的相关性大小的一组矩阵,再用于与原图相乘得到非局部操作后的图像。

值得注意的是:
这里我们(无论是evcblock中想要获取边缘特征用到的lvc代码之中还是none local的操作的代码当中)都把HW这一维度和in_channel相转换了。
然后再去做后续操作。
一开始不太懂这个转换后的矩阵(batch,H
W,in_channels)代表了什么
现在我懂了,这个矩阵代表的意思是,我把所有像素点以一种编码的形式表示了出来,这个编码用于表示像素点本身的信息(信息包括我特征是啥,位置是啥等等,至于这里为什么表达了位置信息,我个人理解的是,一个像素点本身的编码表示是受制于他所存在的小范围的环境的,比如这一小块都是黑色的,那这一小块的像素点的特征向量本身都有着相关的数字联系,当再次遇到这种黑色的小块的时候,用已经训练好的权重,我们就更能提取出这些黑色小块的特征了,所以每个像素点本身的特征向量一定程度上表明了他大概率所处的环境是怎么样的,也就暗示了他的位置信息了,当然在后续论文的实验当中已经印证了这一点,确实是包含了位置信息的,有的论文已经依靠这个点实现了一些功能了),这个编码在nlp当中也有用到,这个编码从数学的角度看就是一个一维的特征向量。

那么问题来了,这个像素点的编码我们怎么获得呢,这些论文就给出了答案,我们直接进行一个pemute,把像素点在每个通道对应的值进行组合就可以表征这个像素点本身的特征向量(即编码)。

那么在之后的工作中,none local block的操作中得到了T=(batch,HW,in_channels)————所有像素点的特征向量的总和。进行转置后得到了T’=(batch,in_channels,HW).。
这里使T与T’相乘(这两个张量之间相乘就相当于任意一个像素点与其他所有的像素点的特征向量进行内积组合而成的一个新张量)得到了一个结果,文中说是像素点之间相关性的结果,这里可以参考transformer的内容去理解这部分(https://blog.youkuaiyun.com/qq_38890412/article/details/120601834)
简单来说,就是特征向量进行内积,特征向量之间进行内积后,如果相关性强,纳闷他们之间得到的内积的结果就会大一些,内积结果大,在与原图再相乘后,就会突出这两个特征之间的相关性,即文中一开始图中的效果。

同理,在evc中虽然没有做内积,但是额外加入了一个码本,获取了边缘特征,是一种更巧妙的提取特征的方法,非常建议细究一下这个代码,用到的方法很巧妙,不知道写这个代码的人脑子是咋长的,咋这厉害呢

### 多头自注意力机制的变体 #### 1. 局部多头自注意力 (Local Multi-Head Self-Attention) 局部多头自注意力限制了每个查询仅能关注其邻近位置的关键值对。这种设计减少了计算复杂度并提高了处理长序列的能力[^3]。 ```python class LocalMultiHeadSelfAttention(nn.Module): def __init__(self, d_model, num_heads, window_size=7): super(LocalMultiHeadSelfAttention, self).__init__() assert d_model % num_heads == 0 self.d_k = d_model // num_heads self.h = num_heads self.window_size = window_size def forward(self, Q, K, V): # 实现局部窗口内的自注意力机制 pass ``` #### 2. 稀疏多头自注意力 (Sparse Multi-Head Self-Attention) 稀疏多头自注意力通过引入稀疏连接模式来减少不必要的计算开销,从而提高效率。该方法允许模型专注于更少但更重要的部分[^4]。 ```python import torch.sparse as sparse def sparse_attention(Q, K, V, sparsity_pattern): # 使用给定的稀疏模式执行高效的矩阵乘法操作 scores = ... attention_weights = softmax(scores) output = torch.matmul(attention_weights, V) return output ``` #### 3. 可扩展多头自注意力 (Scalable Multi-Head Self-Attention) 可扩展版本旨在解决大规模数据集上的性能瓶颈问题。这类算法通常会采用分块或其他优化技术以降低内存占用和加速运算过程[^5]。 ```python from functools import partial def scalable_multihead_self_attention(query, key, value, block_fn=None): if not callable(block_fn): raise ValueError('Block function must be provided.') blocks = partition_into_blocks(query.size(-2), block_fn=query.size(-2)//8) outputs = [] for b in blocks: q_b, k_b, v_b = map(lambda t: select_block(t,b), [query,key,value]) out = multi_head_self_attention(q_b,k_b,v_b) outputs.append(out) final_output = combine_outputs(outputs) return final_output ``` #### 4. 相对位置编码多头自注意力 (Relative Position Encoding MHA) 此变种加入了相对位置信息作为额外输入特征之一,使得模型能够更好地捕捉到不同token之间的距离关系[^6]。 ```python def relative_position_encoding(length, max_distance=10): positions = torch.arange(max_distance * 2 + 1).float() sinusoid_table = get_sinusoid_encoding_table(positions, length) return sinusoid_table[max_distance-length//2 : max_distance+length//2] def mha_with_relative_pos_encodings(Q,K,V,RPE_matrix): # 将RPE矩阵融入到标准MHA公式中 pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值