BEV、tranformer算法总结

1 简介

Attention 机制由 Bengio 团队于 2014 年提出,并广泛应用在深度学习的各个领域。而 Google 提出的用于生成词向量的 Bert 在 NLP 的 11 项任务中取得了效果的大幅提升,Bert 正是基于双向 Transformer。
Transformer 是第一个完全依赖于 Self-Attention 来计算其输入和输出表示的模型,而不使用序列对齐的 RNN 或 CNN。更准确的讲,Transformer 由且仅由 self-Attention 和 Feed Forward Neural Network 组成。一个基于 Transformer 的可训练的神经网络可以通过堆叠 Transformer 的形式进行搭建,作者的实验是通过搭建编码器和解码器各 6 层,总共 12 层的 Encoder-Decoder,并在机器翻译中取得了 BLEU 值得新高。

transformer结构原理

整体结构

在这里插入图片描述

维度

为方便理解不考虑batch情况下,翻译任务中transformer输入维度是(lmax_seq_length * embedding_size),词语数量 * 词向量长度,最终的输出是(lmax_seq_length ,classes),因此,图像任务重把图像reshape拉长,送入transformer,通道数就相当于每个位置的向量长度。理解transformer的所有结构如位置编码、mask、attention等,都要带着这个维度的思想,输入输出就是目的,中间模块都是方法。

encoder decoder

Encoder 的结构由 Multi-Head Self-Attention 和 position-wise feed-forward network 组成,Encoder 的输入由 Input Embedding 和 Positional Embedding 求和组成。

Decoder 的结构由 Masked Multi-Head Self-Attention,Multi-Head Self-Attention 和 position-wise feed-forward network 组成。Decoder 的初始输入由 Output Embedding 和 Positional Embedding 求和得到。

上图左半边 Nx 框出来的部分是 Encoder 的一层,Transformer 中 Encoder 有 6 层。
上图右半边 Nx 框出来的部分是 Decoder 的一层,Transformer 中 Decoder 有 6 层。
在这里插入图片描述

self attention

Attention 常用的有两种,一种是加性注意力(Additive Attention),另一组是点乘注意力(Dot-product Attention),论文采用的是点乘注意力,这种注意力机制相比加法注意力机制,更快,同时更省空间。
The animal didn’t cross the street because it was too tired
我们可以思考一个问题,“it” 指代什么?是 “street” 还是 “animal” ? 对人来说,很容易就能知道是 “animal”,但是对于算法来说,并没有这么简单。
当编码 “it” 时,部分 Attention 集中于 “the animal”,并将其表示合并到 “it” 的编码中
在这里插入图片描述
Transformer 使用 Self-Attention,简单的解释:通过确定Q和K之间的相似程度来选择V!
在这里插入图片描述
使用 Self-Attention 有几个好处:
每一层的复杂度小
如果输入序列 n 小于表示维度 d 的话,Self-Attention 的每一层时间复杂度有优势。
当 n 比较大时,作者也给出了解决方案,Self-Attention 中每个词不是和所有词计算 Attention,而是只与限制的 r 个词进行 Attention 计算。
并行 Multi-Head Attention 和 CNN 一样不依赖前一时刻的计算,可以很好的并行,优于 RNN。
长距离依赖 优于 Self-Attention 是每个词和所有词计算 Attention,所以不管他们中间有多长距离,最大路径长度都只是 1,可以捕获长距离依赖关系。
上面讲到 Decoder 中有两种 Attention,一种是 Self-Attention,一种是 Context-Attention。

Context-Attention 也就是 Encoder 和 Decoder 之间的 Attention,也可以称之为 Encoder-Decoder Attention。

无论是Self-Attention 还是 Context-Attention,它们在计算 Attention 分数的时候,可以有很多选择:
additive attention
local-base
general
dot-product
scaled dot-product
那么我们的Transformer模型,采用的是哪种呢?答案是:scaled dot-product attention。
在这里插入图片描述
为什么要加这个缩放因子呢?论文里给出了解释:如果 dk 很小,加性注意力和点乘注意力相差不大,但是如果 dk 很大,点乘得到的值很大,如果不做 scaling,结果就没有加性注意力好,另外,点乘结果过大,使得经过 softmax 之后的梯度很小,不利于反向传播的进行,所以我们通过对点乘的结果进行scaling

Multi-Head Attention

论文提出,由于不同的 Attention 的权重侧重点不一样,所以将这个任务交给不同的 Attention 一起做,最后取综合结果会更好,有点像 CNN 中的 Keynel。

文章表示,将 Q、K、V 通过一个线性映射后,分成 h 份,对没分进行 Scaled Dot-Product Attention 效果更好, 再把这几个部分 Concat 起来,过一个线性层的效果更好,可以综合不同位置的不同表征子空间的信息。
在这里插入图片描述

Mask

Transformer 模型里面涉及两种 Mask。分别是 Padding Mask 和 Sequence Mask。
其中,Padding Mask 在所有的 Scaled Dot-Product Attention 里面都需要用到,而 Sequence Mask 只有在 Decoder 的 Self-Attention 里面用到。
所以,我们之前 Scaled Dot-Product Attention 的 forward 方法里面的参数 attn_mask 在不同的地方会有不同的含义。

Padding Mask

什么是 Padding Mask 呢?回想一下,我们的每个批次输入序列长度是不一样的。我们要对输入序列进行对齐!就是给在较短的序列后面填充 0。因为这些填充的位置,其实是没什么意义的,所以我们的 Attention 机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。

具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 Softmax,这些位置的概率就会接近 0 !
而我们的 Padding Mask 实际上是一个张量,每个值都是一个 Boolen,值为 False 的地方就是我们要进行处理的地方(图像应用中一般都是对齐的,所以全false)。

def padding_mask(seq_k, seq_q):
    # seq_k 和 seq_q 的形状都是 [B,L]
    len_q = seq_q.size(1)
    # `PAD` is 0
    pad_mask = seq_k.eq(0)
    # shape [B, L_q, L_k]
    pad_mask = pad_mask.unsqueeze(1).expand(-1, len_q, -1)  
    return pad_mask

Sequence mask

文章前面也提到,Sequence Mask 是为了使得 Decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。
那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为 1,下三角的权值为 0,对角线也是 0。把这个矩阵作用在每一个序列上,就可以达到我们的目的啦。
在这里插入图片描述
本来 Mask 只需要二维的矩阵即可,但是考虑到我们的输入序列都是批量的,所以我们要把原本 2 维的矩阵扩张成 3 维的张量,看上面attention的图,mask是用在softMax()计算概率之前的,在这也比较容易理解

def sequence_mask(seq):
    batch_size, seq_len = seq.size()
    mask = torch.triu(torch.ones((seq_len, seq_len), dtype=torch.uint8),
                    diagonal=1)
    mask = mask.unsqueeze(0).expand(batch_size, -1, -1)  # [B, L, L]
    return mask

回到本小结开始的问题,attn_mask 参数有几种情况?分别是什么意思?

对于decoder的self-attention,里面使用到的scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个 mask 相加作为attn_mask。
其他情况,attn_mask 一律等于 padding mask。
至此,Mask 相关的问题解决了。

Positional encoding

注意力Attention这种操作具有排列不变性,输入元素位置的变动不会对注意力结果产生影响,从而模型无法感知位置信息,而在自然语言处理场景,字/词的顺序位置关系信息尤为重要(图像也是),同样的字词不同的顺序可能导致句子的语言完全不一样
因为 Transformer 利用 Attention 的原因,少了对序列的顺序约束,这样就无法组成有意义的语句。为了解决这个问题,Transformer 对位置信息进行编码。
在这里插入图片描述

pos 指词语在序列中的位置,偶数位置,使用正弦编码,奇数位置,使用余弦编码。

上述公式解释:给定词语的位置 pos,我们可以把它编码成 d_model 维的向量!也就是说,位置编码的每一个维度对应正弦曲线,波长构成了从 2π 到 1000*2π 的等比序列。
上面的位置编码是绝对位置编码。但是词语的相对位置也非常重要。这就是论文为什么要使用三角函数的原因!

解释:
我们需要一个有界又连续的函数,最简单的,正弦函数sin就可以满足这一点
由于sin是周期函数,因此从纵向来看,如果函数的频率偏大,引起波长偏短,则不同t下的位置向量可能出现重合的情况
那现在我们对位置向量再提出一个要求,不同的位置向量是可以通过线性转换得到的。这样,我们不仅能表示一个token的绝对位置,还可以表示一个token的相对位置,所有使用sin和cos一组三角函数

位置编码与attention中的key或query维度相同,在attention之前,会直接加到key或query上(看着petr代码是这样)
看transformer的图,位置编码的确是加到特征上的,因此位置编码必须有界,并且最好周期性。

代码理解

nn.MultiheadAttention

forward(query, key, value, key_padding_mask=None, need_weights=True, 
attn_mask=None, average_attn_weights=True)

q k v的维度都是三维(num_queries, batch, embed_dims),应用在图像中一般是(w * h, batch, channel)

detr

这是一篇2D目标检测算法,使用了transformer,petr使用借鉴了很多这里是方法,如预测头、loss、transformer结构等

整体结构

在这里插入图片描述

  • backbone 部分就是用 CNN (ResNet-50)去提取图像特征,得到 2048×25×34 大小的特征图(长和宽变为1/32),然后经过一个 1x1 Conv 降低一下通道数,得到特征尺寸为 256×25×34
  • 将 CNN 特征加上一个同尺寸的位置编码(固定,尺寸为256×25×34 ),拉直为 850×256 ,送入 Transformer Encoder,输出850×256 的特征;
  • 将得到的全局图像特征送入 Transformer Decoder,另一个输入的是 learned object query,尺寸是 100×256 ,256 对应特征尺寸,100 是要出框的个数 。在解码时,learned object query和全局图像特征不停地做across attention,最终得到的特征尺寸的为100×256
    – 这里的object query相当于之前的anchor/proposal,是一个硬性条件,告诉模型最后只得到100个输出
    – learned object query是可学习的positional embedding,与模型参数一起根据梯度进行更新
  • 100个输出通过检测头(目标检测中常用的全连接层FFN),输出100个预测框(xcenter​,ycenter​,w,h)和对应的类别。使用二分图匹配方式输出最终的预测框,然后计算预测框和真实框的损失,梯度回传,更新网络。
    –分类loss采用的是交叉熵损失,针对所有predictions;bbox loss采用了L1 loss和giou loss,针对匹配成功的predictions

除此之外,还有部分细节

  • Transformer-encode/decoder都有6层
  • 除第一层外,每层Transformer encoder里都会先计算object query的self-attention,主要是为了移除冗余框。这些query交互之后,大概就知道每个query会出哪种框,互相之间不会再重复(见实验)
  • decoder加了auxiliary loss,即6层decoder,每层的100×256输出,都送入FFN得到输出,然后去计算loss,这样模型收敛更快。每层FFN共享参数

detr transformer

在这里插入图片描述
Transformer中的Encoder

  • 作用:对feature map进行位置编码和self attention,通过自注意力聚合feature map全局的特征
  • 结构:self_attention、normalization、feed forward network、normalization
  • 输入:
    query:输入query,是展平后的feature map [W_feat * H_feat, B, 256],如果是petr,展平还要乘上相机数据量
    value、key:在self attention中,k和v是由q算出,因此输入为None
    query_key_padding_mask:feature map的有效padding mask [B, W_featH_feat]
    query_positional_embedding:feature map的位置编码 [W_feat
    H_feat, B, 256]
  • 输出:
    encoder_out:输出经过自注意力的展平feature map [W_feat*H_feat, B, 256]

Transformer中的Decoder:

  • 作用:
    第一部分是对object query进行self attention,使得每个object query关注不同的obejct信息
    第二部分是将object query与encoder_out进行cross attention,让object query在feature map上找到不同的obejct
  • 结构:
    self attention(self_attention、normalization)
    cross attention(cross_attention、normalization、feed forward network、normalization)
  • 输入输出维度:可参考petr decoder章节介绍

以下是detr的代码解读,暂时还不理解,尤其transformer各阶段的维度 添加链接描述

petr

代码理解

petr_head.py中
position_encoding()是transformer中的位置编码,采用三角函数,对masks进行位置编码得到pos_embed,这里的embed也经过了一个自适应结构(FC+Relu+FC),然后送入transformer
position_encoder()实际上是论文中的position embedding,FC+Relu+FC
在这里插入图片描述
position_embeding()是3D PE的完整过程,包括2D左边转3D坐标(根据四元数),坐标归一化等等,该函数最后调用上述position_encoder()对坐标自适应。上图中的3D Coordinates维度是(H, W, D * 4, N),D是深度,N是相机路数,4是3D坐标维度(x,y,z,1)

PETRHead中forward(),pos_embed是最后的3D PE数据,对pos_embed进一步处理,加上位置编码信息(位置编码函数的输入是masks),再进行进一步的自适应(卷积),这样3d PE数据中也包含了mask和位置编码信息

petr transf中query是需要输入的(用于解码模块的cross attention),query的维度是(100*256),256和input数据维度(B N 256 w h)有关,100是回归的目标个数

3D PE

上图比较清晰的显示了3D PE的过程,论文中的Fig4说明了,同一位置在不同相机中的3D PE特征点具有高度的相似性,证明了3D PE在不同相机下建立了3D空间的联系。

query 生成

采用了类似Anchor-DETR的方式,在3D世界坐标系空间中,采用0-1均匀分布的方式初始化了一系列可学习的anchor 点,然后将这些点输入到一个带有2个线性层的MLP小网络中生成初始化的queries Q0。简言之均匀分布的3D anchor坐标+MLP自适应,作为Q0

decoder(沿用detr)

For the decoder network, we follow the standard transformer decoder in DETR, which includes L decoder layers(只有解码模块,没有编码模块). Here, we formulate the interaction process in decoder layer as
在这里插入图片描述
每一层的解码,在cross attention中,query都和具有3D位置信息的图像特征(图像特征+3D位置编码)进行融合计算,这样更新后的query就越来越具备更抽象化的表征能力,进一步用于预测3D目标。
没有编码模块:参考detr,transformer编码模块输入输出维度一样,如果有的话,输入是展平的含3D信息的图像特征(n * h * w, bs, c),其中n是相机路数,编码模块输入输出特征一样,因此petr直接把图像特征展平当做了decoder的输入,送入解码模块的cross attention
通detr的decoder一样,每层都是一个self attention + cross attention
self attention:q k v均来自query,维度为(M,bs,C)即(100,bs,256)
cross attenrion:q来自上一层的query(100,bs,256),k和v来自展平的含3D信息的图像特征(n * h * w, bs, c)

petr代码中,transformer的最终输出是(3,100,bs,256),实际上是三个decoder层的特征都输出来了,都用来回归目标并计算loss,推理的时候是这样吗,暂时没看到

head and loss(沿用detr3D)

在这里插入图片描述
bbox回归的方式是 cx cy cz w l h,分别是中心点以及长宽高。有一个细节,回归出来的特征,表示x y z的三个通道,再计算loss之前,又加了一次reference_points(这个是torch.embeding.weight,维度是100 * 3,也是embeding的码表,位置编码就是对码表进行三角函数位置编码,变成100 * 384,然后进过一个卷积变成100 * 256,然后送入的transformer),为什么又加了一次这个码表,可能作者认为detr这种暴利的目标回归方式,没有和位置的对应关系(比如anchor或heatmap,都是某个cell负责回归位于这个cell上的目标),所以这里有加上了这个码表,有对应位置的意思吧

petr dataset

dataset继承自MMDetection3D的custom3Ddataset,里面有一个比较重要的数据是self.data_infos,是一个list,存储了所有的数据。
需要改写custom3Ddataset的load_annotations(ann_file_path)方法,加载自己的数据,包括图片路径,内外参、bbox真值(自车坐标)等。基类会自动调用这个函数,加载所有的训练文件。
需要改写geda_data_info(index)函数,返回特定index,包括N张图片路径,其对应的内外参以及bbox真值等

MMDetection3D代码介绍

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值