Cephalometric Landmark Detection by Attentive Feature Pyramid Fusion and Regression-Voting阅读笔记

代码:https://github.com/runnanchen/Anatomic-Landmark-Detection
自己改了一点的:https://github.com/Nightmare4214/Anatomic-Landmark-Detection

摘要

不同的landmark需要不同级别的分辨率和语义,因此作者提出了一种特征金字塔融合注意力模块( attentivefeature pyramid fusion module,AFPF)。
此外作者结合了heatmap和位移图(offset maps)进行投票,来提高检测准确率

作者在ISBI Grand Challenges 2015上比sota高7%-11%, 还在其他数据集上测试了

引言

模型主要分为3部分:特征提取,AFPF,预测
特征提取使用的预训练VGG19

AFPF设计:
1.不同层的分辨率和语义不同,识别不同的landmark需要的信息也不同(边缘的需要高分辨率和具体的细节,中间区域的需要深层的语义),因此他们融合不同级别的特征
2.同样的特征,每个landmark对他的注意程度也不同,因此他们使用了自注意力机制

模型

Cephalometric Landmark Detection by Attentive Feature Pyramid Fusion and Regression-Voting阅读笔记_第1张图片

特征提取

普通的VGG-19(对应图中Feature extraction module的上半部分)

AFPF

首先是特征金字塔(对应图中Feature extraction module的下半部分)
下面是特征金字塔,将每个部分的特征,通过 1 ∗ 1 1*1 11卷积,将通道调成64,然后上采样到 200 ∗ 160 200*160 200160
最后按通道concat,得到 B ∗ 256 ∗ 200 ∗ 160 B*256*200*160 B256200160,也就是图中的 200 ∗ 160 ( 256 ) 200*160(256) 200160(256)

然后利用4个不同的空洞卷积,得到4个通道为64的,然后再融合,得到 F \mathbf{F} F
这一步是为了扩大感受野和融合不同尺度的特征

根据同样的特征,每个landmark对他的注意程度也不同,因此他们使用了自注意力机制,作者接下来使用了自注意力机制

k k k个landmark的注意力权重如下
a k = s o f t m a x ( W k 1 tanh ⁡ ( W k 2 F ~ ) ) a_k = \mathop{softmax}\left(\mathbf{W}_{k1} \tanh \left(\mathbf{W}_{k2}\tilde{\mathbf{F}}\right)\right) ak=softmax(Wk1tanh(Wk2F~))
其中 a k = ( a k 1 , a k 2 , a k 3 ) a_k = \left(\mathbf{a}_k^1, \mathbf{a}_k^2, \mathbf{a}_k^3\right) ak=(ak1,ak2,ak3),分别表示heatmap注意力,和两个offset的注意力,其中 a k i ∈ R c \mathbf{a}_k^i \in \mathbb{R}^c akiRc, 是一个长度为通道数的向量
F ~ \tilde{\mathbf{F}} F~ F \mathbf{F} F经过平均池化(8倍)和通道shape调整得到的

最后自注意力机制
F k = c ( a k ⊗ F ) F_k=c\left(a_k \otimes \mathbf{F}\right) Fk=c(akF)
其中 F k = ( F k 1 , F k 2 , F k 3 ) F_k = \left(\mathbf{F}_k^1, \mathbf{F}_k^2, \mathbf{F}_k^3\right) Fk=(Fk1,Fk2,Fk3)代表heatmap特征和offset特征, F k i \mathbf{F}_k^i Fki的大小与 F \mathbf{F} F一样, c c c是通道大小
代码实现如下

self.avgPool8t = nn.AvgPool2d(8, 8)
self.attentionLayer1 = nn.Sequential(
    nn.Linear(500, 128, bias=False),  # (B, 1, 256, 128)
    nn.BatchNorm2d(1, track_running_stats=False),
    nn.Tanh(),
    nn.Linear(128, config.landmarkNum * 3, bias=False),  # (B, 1, 256, config.landmarkNum * 3)
    nn.Softmax(dim=2)
)
moduleList = [nn.Conv2d(fnum * 4, 1, kernel_size=(1, 1), stride=1, padding=0) for _ in
                     range(config.landmarkNum * 3)]

self.moduleList = nn.ModuleList(moduleList)
# self.moduleList = nn.Conv2d(fnum * 4 * config.landmarkNum * 3, config.landmarkNum * 3, kernel_size=(1, 1),
#                             stride=1, padding=0, groups=config.landmarkNum * 3)

# 注意力权重
def getAttention(self, bone, fnum):  # (B,256,200,160)
        batch, channel = bone.shape[:2]
        bone = self.avgPool8t(bone).view(batch, channel, -1)  # (B,256,200,160)->(B,256,25,20)->(B,256,500)
        bone = bone.unsqueeze(1)  # (B, 1, 256, 500)
        y = self.attentionLayer1(bone).squeeze(1).transpose(-1, -2)  # (B, 1, 256, 57)->(B, 256, 57)->(B, 57, 256)
        return y
# 自注意力
def predictionWithAttention(self, bone, attentions):  # (B, 256, 200, 160), (B, 57, 256)
    batch, featureNum, channelNum = attentions.shape  # B, 57, 256
    # simple option
    # attentionMaps = torch.einsum('bchw,bdc->bdchw', bone, attentions)
    # attentionMaps = attentionMaps.view(batch, featureNum * channelNum, self.higth, self.width)
    # attentionMaps = nn.Conv2d(featureNum * channelNum, featureNum, kernel_size=(1, 1), stride=1, padding=0,
    #                           groups=featureNum)(attentionMaps)
    attentionMaps = []
    for i in range(featureNum):
        attention = attentions[:, i, :]  # (B, 256)
        attention = attention.view(batch, channelNum, 1, 1)  # (B, 256, 1, 1)
        attentionMap = attention * bone * channelNum
        attentionMaps.append(self.moduleList[i](attentionMap))  # [(B, 1, 200, 160)]

    attentionMaps = torch.concat(attentionMaps, dim=1)  # (B, 57, 200, 160)
    return attentionMaps

# Attentive Feature Pyramid Fusion
bone = self.dilated_block(bone)  # (B,256,200,160)
attention = self.getAttention(bone, self.fnum * 4)  # (57, 256)
y = self.Upsample4(self.predictionWithAttention(bone, attention))

Regression-Voting

作者的监督信号是heatmap和offset
heatmap就是普通的以 R R R为半径的高斯heatmap,offset是每个坐标到对应landmark的水平距离和垂直距离
x方向的offset用公式表示就是
O k ( x i ) = l k − x i R \mathbf{O}_k\left(x_i\right) = \frac{l_k - x_i}{R} Ok(xi)=Rlkxi
其中 l k l_k lk是真实landmark

在计算损失的时候,作者只计算以 R R R为半径的圆,而不是整个图
heatmap损失是交叉熵,offset损失是l1, 权重 2 3 h e a t m a p + 1 3 o f f s e t \frac{2}{3} heatmap + \frac{1}{3}offset 32heatmap+31offset

测试阶段
x i x_i xi的权重为
M k ( x i ) = ∑ x j ∈ A k 1 { ∥ x j + ⌊ O k ( x j ) × R ⌋ − x i ∥ = 0 } M_k\left(x_i\right)=\sum_{x_j \in \mathbf{A}_k} \mathbb{1}\left\{\left\|x_j+\left\lfloor \mathbf{O}_k\left(x_j\right) \times R\right\rfloor-x_i\right\|=0\right\} Mk(xi)=xjAk1{xj+Ok(xj)×Rxi=0}
其中 A k \mathbf{A}_k Ak为以 R R R为半径的圆
可以这么理解, O k ( x j ) × R = l k − x j \mathbf{O}_k\left(x_j\right) \times R=l_k-x_j Ok(xj)×R=lkxj
忽略向下取整,那么 ∥ x j + ⌊ O k ( x j ) × R ⌋ − x i ∥ = ∥ l k − x i ∥ \left\|x_j+\left\lfloor \mathbf{O}_k\left(x_j\right) \times R\right\rfloor-x_i\right\|=\|l_k - x_i\| xj+Ok(xj)×Rxi=lkxi
也就是判断 x i x_i xi是否为真实的landmark l k l_k lk

最后取权重最大的点

你可能感兴趣的:(深度学习,深度学习,人工智能,机器学习)