论文解析二: SuperGlue 同时进行特征匹配以及滤除外点的网络

1.SuperGlue摘要

​ 本文提出了一种能够同时进行特征匹配以及滤除外点的网络。其中特征匹配是通过求解可微分最优化转移问题( optimal transport problem)来解决;本文基于注意力机制提出了一种将2D特征点以及聚合机制,这使得SuperGlue能够同时感知潜在的3D场景以及进行特征匹配。该网络能够在GPU上达到实时,预期能够集成到slam算法中位置如下图

在这里插入图片描述

​ 在经典的SLAM框架中,前端进行特征提取,后端进行非线性优化,而中间非常重要的一步就是特征匹配,传统的特征匹配通常是结合最近邻、RASANC等一些算法进行处理,SuperGlue的推出是SLAM算法端到端深度学习的一个重要里程碑

2.SuperGlue网络结构

在这里插入图片描述

​ 整个框架由两个主要模块组成,注意力GNN以及最优匹配层

​ 先进入注意力GNN网络,通过Keypoint Encoder(关键点编码器)关键点位置p以及视觉描述符d映射到单个向量中(该向量可以理解为特征匹配向量),随后利用Self(自我注意力)以及Cross(交叉注意力)(重复L)来创建更强大的表示向量f

​ 随后进入最优匹配层,通过计算特征匹配向量的内积得到score matrix(M*N的得分矩阵),用dustbin score进行扩充,然后通过Sinkhorn算法(迭代T次)找到最佳的部分分配。

2.1 Attentional Graph Neural Network( 注意图神经网络)

2.1.1 KeyPoint Encoder :解决 同时进行特征匹配以及滤除外点的网络

​ 假定有A,B两张图像,分别检测出M和N个特征点,分别记为A = {1,2…M} 和 B = {1,2…N} ,每个特征点由(p,d)表示,其中pi = (x,y,c)为第i个特征点(归一化)后的位置(x,y)和置信度(c)。di为第i个特征点的特征向量。我们首先对输入网络的特征点和特征向量进行编码:
在这里插入图片描述

​ 其作用就是特征点的位置和特征向量编码进同一个特征 ,使得网络在进行匹配时能够同时考虑到特征描述和位置的相似性。

self.kenc = KeypointEncoder(self.descriptor_dim, self.keypoint_encoder)#关键点编码器(KeypointEncoder)实例化
desc0 = desc0 + self.kenc(kpts0, data['scores0'])
desc1 = desc1 + self.kenc(kpts1, data['scores1'])#对于两组关键点数据kpts0和kpts1,分别调用self.kenc对其进行编码处理,并将编码结果累加到描述子desc0和desc1中,以更新描述子的信息。这样可以有效地将关键点信息融入到描述子中,提高描述子的表征能力
#多层感知机MLP 1*1卷积+BN+ReLU
def MLP(channels: list, do_bn=True):
    """ Multi-layer perceptron """
    n = len(channels)
    layers = []
    #遍历每一层
    for i in range(1, n):
        layers.append(
            #添加一维卷积层
            nn.Conv1d(channels[i - 1], channels[i], kernel_size=1, bias=True))
        #如果不是最后一层,则添加批归一化和ReLU激活函数
        if i < (n-1):
            if do_bn:
                layers.append(nn.BatchNorm1d(channels[i]))
            layers.append(nn.ReLU())
    return nn.Sequential(*layers)
class KeypointEncoder(nn.Module):
    """ 关键点编码器(KeypointEncoder),联合使用MLP对特征点的位置和特征进行编码"""
    def __init__(self, feature_dim, layers):
        """
        初始化关键点编码器
        参数:
            feature_dim (int): 特征维度
            layers (list): 包含隐藏层维度的列表
        """
        super().__init__()
        self.encoder = MLP([3] + layers + [feature_dim])
        nn.init.constant_(self.encoder[-1].bias, 0.0)
    def forward(self, kpts, scores):
        """
        前向传播函数
        参数:
            kpts (Tensor): 关键点张量,形状为(N, K, 2),N为样本数,K为关键点个数,每个关键点有2维坐标信息
            scores (Tensor): 分数张量,形状为(N, K),N为样本数,K为关键点个数
        返回:
            Tensor: 编码后的特征张量
        """
        inputs = [kpts.transpose(1, 2), scores.unsqueeze(1)]
        return self.encoder(torch.cat(inputs, dim=1))
2.1.2 Attentional Aggregation

在这里插入图片描述

message = self.attn(x, source, source)
self.attn = MultiHeadedAttention(num_heads, feature_dim)
"""
    实现注意力机制
    参数:
        query (Tensor): 查询张量,形状为(B, Dq, H, N),B为批量大小,Dq为查询维度,H为头数,N为序列长度
        key (Tensor): 键张量,形状为(B, Dk, H, M),Dk为键维度,M为序列长度
        value (Tensor): 值张量,形状为(B, Dv, H, M),Dv为值维度
    返回:
        Tuple[Tensor, Tensor]: 经过注意力加权后的值张量和注意力分布张量
"""
def attention(query, key, value):
    dim = query.shape[1]
    scores = torch.einsum('bdhn,bdhm->bhnm', query, key) / dim**.5
    prob = torch.nn.functional.softmax(scores, dim=-1)
    return torch.einsum('bhnm,bdhm->bdhn', prob, value), prob
class MultiHeadedAttention(torch.jit.ScriptModule):
    """ 定义了一个多头注意力的类,用于增强模型的表达能力 """
    prob: List[torch.Tensor]

    def __init__(self, num_heads: int, d_model: int):
        super().__init__()
        assert d_model % num_heads == 0
        self.dim = d_model // num_heads
        self.num_heads = num_heads
        self.merge = nn.Conv1d(d_model, d_model, kernel_size=1)
        self.proj = nn.ModuleList([deepcopy(self.merge) for _ in range(3)]) # 对应不同的W
        self.prob = []

    @torch.jit.script_method
    def forward(self, query, key, value):
        batch_dim = query.size(0)
        query, key, value = [l(x).view(batch_dim, self.dim, self.num_heads, -1)
                             for l, x in zip(self.proj, (query, key, value))] # 通过卷积提取query、key、value
        x, prob = attention(query, key, value) # 进行attention计算
        self.prob.append(prob)
        return self.merge(x.contiguous().view(batch_dim, self.dim*self.num_heads, -1)) # 合并多头结果

在这里插入图片描述

self.gnn = AttentionalGNN(self.descriptor_dim, self.GNN_layers)
desc0, desc1 = self.gnn(desc0, desc1)
class AttentionalPropagation(torch.jit.ScriptModule):
    def __init__(self, feature_dim: int, num_heads: int):
        super().__init__()
        # 初始化时创建一个MultiHeadedAttention实例,用于进行多头注意力计算
        self.attn = MultiHeadedAttention(num_heads, feature_dim)
        # 创建一个MLP(多层感知机)实例,用于后续信息融合
        self.mlp = MLP([feature_dim*2, feature_dim*2, feature_dim])
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unknown To Known

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值