superGlue学习

superglue是用于图片匹配的深度学习网络,网络结构如下:
在这里插入图片描述
前半部分是把特征点(x,y,score)和descriptors组合成一种新的描述子f,
后半部分是两张图片用各自的f描述子进行匹配。

AGNN

1.keypoint encoder
将keypoint(x,y,score)转换为可以与descriptors直接相加的256维数据。使用的是5个多层感知器(全连接)
2.attentional aggregation
让特征在图片内和图片间反复和其他特征点产生联系。用的是自注意力机制和交叉注意力机制的图神经网络,图神经网络用的是消息传递机制更新下一层的节点。
整体流程如下:
在这里插入图片描述

我们把两张图片的所有特征点想象成一张大图的节点,这些节点之间有两种边,一种是与同一张图片内的节点之间的边,称为self-edge,一种是与另一张图片内的节点之间的边,称为cross-edge。消息传递机制更新节点,就是每个节点等于上一层他自己和与它相邻的节点的权重和。注意力机制就是通过两个节点的关系来反复更新这些权重,Attentional Aggregation。
在这里插入图片描述
我们判断两个节点的亲密程度,会直接用两个节点相乘,乘积越大越亲密。我感觉有点类似卷积,用卷积核去滑动相乘,值大的地方,认为与卷积核越相似,则该卷积核对应的特征提取出来了。可能认为自己乘以自己最大吧

因为我们有两种边,作者把节点的更新分成了两个部分。
1.self attentoin aggregation :就是图片内节点更新,输入des0,des0,des0,这三者是一样的(注意作者认为特征点之间全是相邻的),第一个是要更新的节点,第二个是用来求节点之间的权重的(也是相邻节点),第三个是相邻节点。这三者通过各自的线性映射后成为query,key,value(注意力机制里面的专业术语),querykey再softmax就得到与相邻节点的权重,再用该权重乘以value就得到了相邻节点对该节点的更新部分m,再与该节点自己本身x拼接成2562,再经过一个MLP变成256维(这里我理解的其实就是实现w1x + w2m+b),注意这里只是得到了一个delta值,最后des0=des0+delta。就是严格按照下面这个公式执行的。
在这里插入图片描述
2.cross attention aggregation:和上面是一样的,只是用的是图片间的相邻节点更新的。
如何更新m更详细的解释。
在这里插入图片描述
在这里插入图片描述

optimal mapper

在这里插入图片描述
optimal transport使用Sinkhorn Algorithm算法求解,我还没搞清楚。

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))
        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):
    """ Joint encoding of visual appearance and location using MLPs"""
    def __init__(self, feature_dim, layers):    #layers = [32, 64, 128, 256] feature_dim = 256 
        super().__init__()
        self.encoder = MLP([3] + layers + [feature_dim]) # FCN channels= [3,32,64,128,256,256] 5层的全连接
        nn.init.constant_(self.encoder[-1].bias, 0.0) #初始化bias

    def forward(self, kpts, scores):
        inputs = [kpts.transpose(1, 2), scores.unsqueeze(1)] # unsqueeze在scores加一个维度,和kpts搞成一样
        return self.encoder(torch.cat(inputs, dim=1)) # 把input展开变成维度为1,输入为3通道(x,y,score)

def attention(query, key, value):    # 即 m E→i
    dim = query.shape[1]
    scores = torch.einsum('bdhn,bdhm->bhnm', query, key) / dim**.5  #爱因斯坦求和,计算attetion weights = query^T*key 
    prob = torch.nn.functional.softmax(scores, dim=-1) 
    return torch.einsum('bhnm,bdhm->bdhn', prob, value), prob  # attetion weights * value

class MultiHeadedAttention(nn.Module):
    """ Multi-head attention to increase model expressivitiy """
    def __init__(self, num_heads: int, d_model: int): # num_heads=4 d_model=256(特征点的维数)
        super().__init__()
        assert d_model % num_heads == 0
        self.dim = d_model // num_heads #/为浮点数除法,返回浮点结果//表示整数除法,返回不大于结果的一个最大整数 = 64
        self.num_heads = num_heads # 4
        self.merge = nn.Conv1d(d_model, d_model, kernel_size=1) # 输入256通道输出256通道的全连接
        self.proj = nn.ModuleList([deepcopy(self.merge) for _ in range(3)])
        #加入到 nn.ModuleList 里面的 module 是会注册到整个网络上的 proj是个3层的FCN
    def forward(self, query, key, value):# query要更新的特征点 key value连接的特征点(同一个)
        batch_dim = query.size(0) #view()函数作用是将一个多行的Tensor,拼接成一行
        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各自经过1层的MLP输出 论文公式(5) 
        x, _ = attention(query, key, value) # 即 m E→i 论文公式(4)
        return self.merge(x.contiguous().view(batch_dim, self.dim*self.num_heads, -1))   #contiguous()深拷贝,把x展开再经过一层MLP

class AttentionalPropagation(nn.Module): #实现了一层所有节点(特征点)的更新
    def __init__(self, feature_dim: int, num_heads: int): #feature_dim=256 num_heads=4
        super().__init__()
        self.attn = MultiHeadedAttention(num_heads, feature_dim) #
        self.mlp = MLP([feature_dim*2, feature_dim*2, feature_dim]) #2层MLP[256*2 256*2 256]
        nn.init.constant_(self.mlp[-1].bias, 0.0)

    def forward(self, x, source):
        message = self.attn(x, source, source)
        return self.mlp(torch.cat([x, message], dim=1)) # 论文公式3 输入256*2 输出256 更新了x      
                          
class AttentionalGNN(nn.Module):
    def __init__(self, feature_dim: int, layer_names: list):  # 256 ['self', 'cross'] * 9=['self', 'cross','self', 'cross'...]9
        super().__init__()
        self.layers = nn.ModuleList([
            AttentionalPropagation(feature_dim, 4)
            for _ in range(len(layer_names))])  #2层AttentionalPropagation
        self.names = layer_names

    def forward(self, desc0, desc1):
        for layer, name in zip(self.layers, self.names): #做两次,一次自己和自己,一次自己和别人
            if name == 'cross':
                src0, src1 = desc1, desc0
            else:  # if name == 'self':
                src0, src1 = desc0, desc1
            delta0, delta1 = layer(desc0, src0), layer(desc1, src1)
            desc0, desc1 = (desc0 + delta0), (desc1 + delta1) #输出叠加再原来的des上
        return desc0, desc1
        

训练

在这里插入图片描述
我用户外的参数测试了几十种场景,从网上下很多图,superglue都能较好的匹配成功,我感觉不需要重新训练。

资源消耗

在这里插入图片描述

  • 13
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值