模型拆解(三):EGNet、FMFINet、MJRBM

文章目录

  • 一、EGNet
    • 1.1编码器:VGG16的扩展网络
  • 二、EMFINet
    • 2.1编码器:三分支并行卷积编码器
    • 2.2CFFM:级联特征融合模块
    • 2.3Edge Module:突出边缘提取模块
    • 2.4Bridge Module:桥接器
    • 2.5解码器:深度特征融合解码器
  • 三、MJRBM
    • 3.1编码器:VGG16双分支编码器
    • 3.2SBFEM:显著边界特征提取模块
    • 3.4分层注意力模块:HAM
    • 3.4Aggregation:聚合模块
    • 3.5JRBM:联合区域和边界模块
    • 3.6解码器:双分支解码器


一、EGNet

  论文:EGNet: Edge Guidance Network for Salient Object Detection
  论文链接:EGNet: Edge Guidance Network for Salient Object Detection
  代码链接:Github
  博客链接:CSDN

1.1编码器:VGG16的扩展网络

在这里插入图片描述

  • vgg.py
#创建网络基础部分
def vgg(cfg, i, batch_norm=False):layers = []in_channels = istage = 1for v in cfg:if v == 'M':stage += 1if stage == 6:layers += [nn.MaxPool2d(kernel_size=3, stride=2, padding=1)]else:layers += [nn.MaxPool2d(kernel_size=3, stride=2, padding=1)]else:if stage == 6:# conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=4, dilation=4, bias=False)conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)else:conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)if batch_norm:layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]else:layers += [conv2d, nn.ReLU(inplace=True)]in_channels = vreturn layers#创建网络扩展部分
class vgg_ex(nn.Module):def __init__(self, cfg, incs=512, padding=1, dilation=1):super(vgg_ex, self).__init__()self.cfg = cfglayers = []for v in self.cfg:# conv2d = nn.Conv2d(incs, v, kernel_size=3, padding=4, dilation=4, bias=False)conv2d = nn.Conv2d(incs, v, kernel_size=3, padding=padding, dilation=dilation, bias=False)layers += [conv2d, nn.ReLU(inplace=True)]incs = vself.ex = nn.Sequential(*layers)for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, 0.01)elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()def forward(self, x):x = self.ex(x)return xclass vgg16(nn.Module):def __init__(self):super(vgg16, self).__init__()#定义VGG16网络参数,数字代表卷积核数,'M'代表平均池化#tun:主网络的层配置#tun_ex:额外的层配置self.cfg = {'tun': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'], 'tun_ex': [512, 512, 512]}#需要提取特征的层索引self.extract = [8, 15, 22, 29] # [3, 8, 15, 22, 29]self.extract_ex = [5]#创建网络基础部分base,参数为self.cfg['tun'],输入通道数为3self.base = nn.ModuleList(vgg(self.cfg['tun'], 3))#创建网络扩展部分base_ex,参数为self.cfg['tun_ex'],输入通道数为512self.base_ex = vgg_ex(self.cfg['tun_ex'], 512)#权重初始化for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, 0.01)elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()def load_pretrained_model(self, model):self.base.load_state_dict(model)def forward(self, x, multi=0):#保存提取的特征tmp_x = []for k in range(len(self.base)):x = self.base[k](x)#若层索引在extract列表中,则将该层的输出特征图添加到tmp_x列表中if k in self.extract:tmp_x.append(x)#将主干网络输出x传递给扩展部分base_ex,并将其输出添加到tmp_x中x = self.base_ex(x)tmp_x.append(x)#multi == 1时返回仅包含第一个特征图的列表tmp_y;否则返回tmp_x中的所有提取特征图if multi == 1:tmp_y = []tmp_y.append(tmp_x[0])return tmp_yelse:return tmp_x

之后初始化模型时通过以下方式初始化:

config_vgg = {'convert': [[128,256,512,512,512],[64,128,256,512,512]], 'merge1': [[128, 256, 128, 3,1], [256, 512, 256, 3, 1], [512, 0, 512, 5, 2], [512, 0, 512, 5, 2],[512, 0, 512, 7, 3]], 'merge2': [[128], [256, 512, 512, 512]]}  # no convert layer, no conv6config_resnet = {'convert': [[64,256,512,1024,2048],[128,256,512,512,512]], 'deep_pool': [[512, 512, 256, 256, 128], [512, 256, 256, 128, 128], [False, True, True, True, False], [True, True, True, True, False]], 'score': 256, 'edgeinfo':[[16, 16, 16, 16], 128, [16,8,4,2]],'edgeinfoc':[64,128], 'block': [[512, [16]], [256, [16]], [256, [16]], [128, [16]]], 'fuse': [[16, 16, 16, 16], True], 'fuse_ratio': [[16,1], [8,1], [4,1], [2,1]],  'merge1': [[128, 256, 128, 3,1], [256, 512, 256, 3, 1], [512, 0, 512, 5, 2], [512, 0, 512, 5, 2],[512, 0, 512, 7, 3]], 'merge2': [[128], [256, 512, 512, 512]]}#接受参数base_model_cfg(网络配置), vgg(模型实例)创建编码器及两个合并层,返回vgg, merge1_layers, merge2_layers
def extra_layer(base_model_cfg, vgg):if base_model_cfg == 'vgg':config = config_vggelif base_model_cfg == 'resnet':config = config_resnetmerge1_layers = MergeLayer1(config['merge1'])merge2_layers = MergeLayer2(config['merge2'])return vgg, merge1_layers, merge2_layersif __name__ == '__main__':from torch.autograd import Variable#通过extra_layer()创建包含编码器架构及两个合并层的列表,列表内容用于初始化模型TUNnet = TUN(*extra_layer(vgg(base['tun'], 3), vgg(base['tun_ex'], 512), config['merge_block'], config['fuse'])).cuda()...

模型代码:

# TUN network
class TUN_bone(nn.Module):def __init__(self, base_model_cfg, base, merge1_layers, merge2_layers):super(TUN_bone, self).__init__()self.base_model_cfg = base_model_cfg#VGG版本的模型初始化if self.base_model_cfg == 'vgg':self.base = base# self.base_ex = nn.ModuleList(base_ex)self.merge1 = merge1_layersself.merge2 = merge2_layerselif self.base_model_cfg == 'resnet':self.convert = ConvertLayer(config_resnet['convert'])self.base = baseself.merge1 = merge1_layersself.merge2 = merge2_layersdef forward(self, x):x_size = x.size()[2:]conv2merge = self.base(x)        if self.base_model_cfg == 'resnet':            conv2merge = self.convert(conv2merge)up_edge, edge_feature, up_sal, sal_feature = self.merge1(conv2merge, x_size)up_sal_final = self.merge2(edge_feature, sal_feature, x_size)return up_edge, up_sal, up_sal_final
class MergeLayer1(nn.Module): # list_k: [[64, 512, 64], [128, 512, 128], [256, 0, 256] ... ]def __init__(self, list_k):super(MergeLayer1, self).__init__()self.list_k = list_ktrans, up, score = [], [], []for ik in list_k:if ik[1] > 0:trans.append(nn.Sequential(nn.Conv2d(ik[1], ik[0], 1, 1, bias=False), nn.ReLU(inplace=True)))up.append(nn.Sequential(nn.Conv2d(ik[0], ik[2], ik[3], 1, ik[4]), nn.ReLU(inplace=True), nn.Conv2d(ik[2], ik[2], ik[3], 1, ik[4]), nn.ReLU(inplace=True), nn.Conv2d(ik[2], ik[2], ik[3], 1, ik[4]), nn.ReLU(inplace=True)))score.append(nn.Conv2d(ik[2], 1, 3, 1, 1))trans.append(nn.Sequential(nn.Conv2d(512, 128, 1, 1, bias=False), nn.ReLU(inplace=True)))self.trans, self.up, self.score = nn.ModuleList(trans), nn.ModuleList(up), nn.ModuleList(score)self.relu =nn.ReLU()def forward(self, list_x, x_size):up_edge, up_sal, edge_feature, sal_feature = [], [], [], []num_f = len(list_x)tmp = self.up[num_f - 1](list_x[num_f-1])sal_feature.append(tmp)U_tmp = tmpup_sal.append(F.interpolate(self.score[num_f - 1](tmp), x_size, mode='bilinear', align_corners=True))for j in range(2, num_f ):i = num_f - jif list_x[i].size()[1] < U_tmp.size()[1]:U_tmp = list_x[i] + F.interpolate((self.trans[i](U_tmp)), list_x[i].size()[2:], mode='bilinear', align_corners=True)else:U_tmp = list_x[i] + F.interpolate((U_tmp), list_x[i].size()[2:], mode='bilinear', align_corners=True)tmp = self.up[i](U_tmp)U_tmp = tmpsal_feature.append(tmp)up_sal.append(F.interpolate(self.score[i](tmp), x_size, mode='bilinear', align_corners=True))U_tmp = list_x[0] + F.interpolate((self.trans[-1](sal_feature[0])), list_x[0].size()[2:], mode='bilinear', align_corners=True)tmp = self.up[0](U_tmp)edge_feature.append(tmp)up_edge.append(F.interpolate(self.score[0](tmp), x_size, mode='bilinear', align_corners=True)) return up_edge, edge_feature, up_sal, sal_feature        

https://github.com/JXingZhao/EGNet/blob/master/model.py
抽空再看,屎一样的代码!

二、EMFINet

  论文:Edge-Aware Multiscale Feature Integration Network for Salient Object Detection in Optical Remote Sensing Images(用于光学遥感图像中显著目标检测的边缘感知多尺度特征集成网络)
  论文链接:Edge-Aware Multiscale Feature Integration Network for Salient Object Detection in Optical Remote Sensing Images
  代码链接:Github
  博客链接:CSDN

2.1编码器:三分支并行卷积编码器

在这里插入图片描述
  三分支并行卷积编码器由 R e s N e t − 34 ResNet-34 ResNet34改造而来,以三幅不同分辨率的图像作为输入。原始 R e s N e t − 34 ResNet-34 ResNet34结构为:
在这里插入图片描述
EMFINet使用的卷积分支在此基础上进行了修改:

  • 1.将 c o n v 1 conv1 conv1修改为 3 × 3 3×3 3×3大小、步幅为1。
  • 2.将 c o n v 1 conv1 conv1后的最大池化层取消。

EMFINet卷积分支中各个模块定义如下:

  • 1.Conv-B1:conv1+conv2_x
  • 2.Conv-B2:conv3_x
  • 3.Conv-B3:conv4_x
  • 4.Conv-B4:conv5_x
  • 5.Conv-B5:最大池化( 2 × 2 2×2 2×2,stride=2,padding=0)+conv5中的三个基本残差块。
#model/EMFINet.py
class EMFINet(nn.Module):def __init__(self):super(EMFINet,self).__init__()#初始化ResNet34模型resnet = models.resnet34(pretrained=True)#-------------Multiscale Feature Extraction--------------#self.poola = nn.MaxPool2d(2,2,ceil_mode=True)self.poolb = nn.MaxPool2d(4,4,ceil_mode=True)#Conv-B1#conv1(修改后)self.preconv = nn.Conv2d(3,64,3,padding=1)self.prebn = nn.BatchNorm2d(64)self.prerelu = nn.ReLU(inplace=True)#conv2_xself.encoder1 = resnet.layer1#Conv-B2:conv3_xself.encoder2 = resnet.layer2#Conv-B3:conv4_xself.encoder3 = resnet.layer3#Conv-B4:conv5_xself.encoder4 = resnet.layer4#Conv-B5self.poolc = nn.MaxPool2d(2,2,ceil_mode=True)self.encoder5_1 = BasicBlock(512,512)self.encoder5_2 = BasicBlock(512,512)self.encoder5_3 = BasicBlock(512,512)...def forward(self,x):#最大分辨率,对应Convs-1score1_1 = x#使用最大池化下采样得到不同分辨率的图像作为输入#中间分辨率,对应Convs-2score2 = self.poola(score1_1)#最小分辨率,对应Convs-3score3 = self.poolb(score1_1)#-------------Multiscale Feature Extraction--------------##Convs-1#Conv-B1:conv1(修改后)+conv2_xscore1_1 = self.encoder1(self.prerelu(self.prebn(self.preconv(score1_1))))#Conv-B2:conv3_xscore1_2 = self.encoder2(score1_1)#Conv-B3:conv4_xscore1_3 = self.encoder3(score1_2)#Conv-B4:conv5_xscore1_4 = self.encoder4(score1_3)#Conv-B5score1_5 = self.poolc(score1_4)score1_5 = self.encoder5_1(score1_5)score1_5 = self.encoder5_2(score1_5)score1_5 = self.encoder5_3(score1_5)#Convs-2#Conv-B1:conv1(修改后)+conv2_xscore2 = self.encoder1(self.prerelu(self.prebn(self.preconv(score2))))#Conv-B2:conv3_xscore2 = self.encoder2(score2)#Conv-B3:conv4_xscore2 = self.encoder3(score2)#Conv-B4:conv5_xscore2 = self.encoder4(score2)#Conv-B5score2 = self.poolc(score2)score2 = self.encoder5_1(score2)score2 = self.encoder5_2(score2)score2 = self.encoder5_3(score2)#Convs-2score3 = self.encoder1(self.prerelu(self.prebn(self.preconv(score3))))#Conv-B1:conv1(修改后)+conv2_xscore3 = self.encoder2(score3)#Conv-B2:conv3_xscore3 = self.encoder3(score3)#Conv-B3:conv4_xscore3 = self.encoder4(score3)#Conv-B5score3 = self.poolc(score3)score3 = self.encoder5_1(score3)score3 = self.encoder5_2(score3)score3 = self.encoder5_3(score3)...

从三张遥感图像中提取了高级深度语义特征 { F 5 1 , F 5 2 , F 5 3 } \{F^1_5,F^2_5,F^3_5\} {F51,F52,F53},其中,分辨率最大的遥感图像中还提取了多级深度语义特征 { F 1 1 , F 2 1 , F 3 1 , F 4 1 } \{F^1_1,F^1_2,F^1_3,F^1_4\} {F11,F21,F31,F41}
  代码中的score1_1、score1_2、score1_3、score1_4、score1_5代表 { F 1 1 , F 2 1 , F 3 1 , F 4 1 , F 5 1 } \{F^1_1,F^1_2,F^1_3,F^1_4,F^1_5\} {F11,F21,F31,F41,F51},score2、score3代表 { F 5 2 , F 5 3 } \{F^2_5,F^3_5\} {F52,F53}

2.2CFFM:级联特征融合模块

在这里插入图片描述
  用于将不同分辨率遥感图像提取的高级深度语义特征 { F 5 1 , F 5 2 , F 5 3 } \{F^1_5,F^2_5,F^3_5\} {F51,F52,F53}融合,得到增强后的深度语义特征:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中, C o n v Conv Conv包含三个卷积层,每个都带有BN、ReLU。

#model/EMFINet.py
class EMFINet(nn.Module):def __init__(self):...#-------------Cascaded feature fusion module--------------##part 1self.cat_conv11 = nn.Conv2d(512,512,3,padding=1)self.cat_bn11 = nn.BatchNorm2d(512)self.cat_relu11 = nn.ReLU(inplace=True)self.cat_conv12 = nn.Conv2d(512,512,3,padding=1)self.cat_bn12 = nn.BatchNorm2d(512)self.cat_relu12 = nn.ReLU(inplace=True)self.cat_conv13 = nn.Conv2d(512,512,3,padding=1)self.cat_bn13 = nn.BatchNorm2d(512)self.cat_relu13 = nn.ReLU(inplace=True)#part 2self.cat_conv21 = nn.Conv2d(512,512,3,padding=1)self.cat_bn21 = nn.BatchNorm2d(512)self.cat_relu21 = nn.ReLU(inplace=True)self.cat_conv22 = nn.Conv2d(512,512,3,padding=1)self.cat_bn22 = nn.BatchNorm2d(512)self.cat_relu22 = nn.ReLU(inplace=True)self.cat_conv23 = nn.Conv2d(512,512,3,padding=1)self.cat_bn23 = nn.BatchNorm2d(512)self.cat_relu23 = nn.ReLU(inplace=True)#part 3self.cat_conv31 = nn.Conv2d(512,512,3,padding=1)self.cat_bn31 = nn.BatchNorm2d(512)self.cat_relu31 = nn.ReLU(inplace=True)self.cat_conv32 = nn.Conv2d(512,512,3,padding=1)self.cat_bn32 = nn.BatchNorm2d(512)self.cat_relu32 = nn.ReLU(inplace=True)self.cat_conv33 = nn.Conv2d(512,512,3,padding=1)self.cat_bn33 = nn.BatchNorm2d(512)self.cat_relu33 = nn.ReLU(inplace=True)...#-------------Label output--------------#self.label_outconv1 = nn.Conv2d(512,1,1,padding=0)self.label_outconv2 = nn.Conv2d(512,1,1,padding=0)self.label_outconv3 = nn.Conv2d(512,1,1,padding=0)self.label_outconv4 = nn.Conv2d(512,1,1,padding=0)self.label_outconv5 = nn.Conv2d(256,1,1,padding=0)self.label_outconv6 = nn.Conv2d(128,1,1,padding=0)self.label_outconv7 = nn.Conv2d(64,1,1,padding=0)self.label_outconv8 = nn.Conv2d(64,1,1,padding=0)self.label_outconv9 = nn.Conv2d(1024,1,1,padding=0)def forward(self,x):...#-------------Cascaded feature fusion module--------------##将F35输入Conv得到F'35score3 = self.cat_relu11(self.cat_bn11(self.cat_conv11(score3)))score3 = self.cat_relu12(self.cat_bn12(self.cat_conv12(score3)))score3 = self.cat_relu13(self.cat_bn13(self.cat_conv13(score3)))#将F'35上采样到F25大小并相加score3_up1 = self.upscore2(score3)score2 = score3_up1 + score2#得到F'25score2 = self.cat_relu21(self.cat_bn21(self.cat_conv21(score2)))score2 = self.cat_relu22(self.cat_bn22(self.cat_conv22(score2)))score2 = self.cat_relu23(self.cat_bn23(self.cat_conv23(score2)))#将F35、F'25上采样到F15大小并相加score2_up = self.upscore2(score2)score3_up2 = self.upscore4(score3)score1_5 = score2_up + score3_up2 + score1_5#得到F'15score1_5 = self.cat_relu31(self.cat_bn31(self.cat_conv31(score1_5)))score1_5 = self.cat_relu32(self.cat_bn32(self.cat_conv32(score1_5)))score1_5 = self.cat_relu33(self.cat_bn33(self.cat_conv33(score1_5)))....#-------------Label output--------------##深度监督F'35label1_out = self.label_outconv1(score3)label1_out = self.upscore64(label1_out)#深度监督F'25label2_out = self.label_outconv2(score2)label2_out = self.upscore32(label2_out)#深度监督F'15label3_out = self.label_outconv3(score1_5)label3_out = self.upscore16(label3_out)...#-------------Return--------------#return torch.sigmoid(edge_out), torch.sigmoid(label1_out), torch.sigmoid(label2_out), torch.sigmoid(label3_out), torch.sigmoid(labelbdg_out), \torch.sigmoid(label4_out), torch.sigmoid(label5_out), torch.sigmoid(label6_out), torch.sigmoid(label7_out), torch.sigmoid(label8_out)

2.3Edge Module:突出边缘提取模块

在这里插入图片描述
在这里插入图片描述
  边缘提取模块用于从低级深度特征 F 2 1 F^1_2 F21和高级深度特征 F ^ 5 1 \hat{F}^1_5 F^51中生成显著边缘图 E E E。计算公式:
在这里插入图片描述
  之后将突出边缘特征图E调整为与多尺度深度特征相同大小,得到 E j , j ∈ { 1 , 2 , 3 , 4 , 5 } E_j,j∈\{1,2,3,4,5\} Ej,j{1,2,3,4,5},并将其与多尺度深度特征进行融合。公式:
在这里插入图片描述
其中。 [ , ] [,] [,]表Concat操作。为准确生成突出边缘特征图E,模型采用深度监督的方式来指导突出边缘的提取。即,将突出边缘特征图E卷积、上采样、sigmoid处理来获取突出边缘图,再使用交叉熵损失函数来监督。

#model/EMFINet.py
class EMFINet(nn.Module):def __init__(self):...#-------------Edge--------------##Edge Moduleself.up_conv = nn.Conv2d(512,128,3,dilation=8, padding=8)self.up_bn = nn.BatchNorm2d(128)self.edge_conv = nn.Conv2d(128,128,3,padding=1)self.edge_bn = nn.BatchNorm2d(128)self.edge_relu = nn.ReLU(inplace=True)...#-------------Edge output--------------##128通道转为1通道,生成显著边缘图self.edge_outconv1 = nn.Conv2d(128,1,1,padding=0)def forward(self,x):...#-------------Edge--------------##8倍上采样F'1_5score1_5_up = self.upscore8(score1_5)score1_5_up = self.up_bn(self.up_conv(score1_5_up))#元素求和、Conv、BN、ReLUscore_edge = score1_2 +score1_5_upscore_edge = self.edge_relu(self.edge_bn(self.edge_conv(score_edge)))...#-------------Edge output--------------##生成显著边缘图并两倍上采样edge_out = self.edge_outconv1(score_edge)edge_out = self.upscore2(edge_out)#-------------Return--------------##返回显著边缘图用于深度监督return torch.sigmoid(edge_out), torch.sigmoid(label1_out), torch.sigmoid(label2_out), torch.sigmoid(label3_out), torch.sigmoid(labelbdg_out), \torch.sigmoid(label4_out), torch.sigmoid(label5_out), torch.sigmoid(label6_out), torch.sigmoid(label7_out), torch.sigmoid(label8_out)

2.4Bridge Module:桥接器

在这里插入图片描述
  桥接器包含了四个膨胀卷积,膨胀率 r ∈ { 2 , 4 , 8 , 16 } r∈\{2,4,8,16\} r{2,4,8,16},为扩大感受野并捕获全局上下文特征,从输入的高级深度语义特征 F ^ 5 1 \hat{F}^1_5 F^51中提取了四个深度特征 F e a 2 、 F e a 4 、 F e a 8 、 F e a 16 Fea2、Fea4、Fea8、Fea16 Fea2Fea4Fea8Fea16并进行串联(用 c c c表示)。

class EMFINet(nn.Module):def __init__(self):super(EMFINet,self).__init__()...#-------------Bridge--------------##四个膨胀卷积+BNself.bdg_conv1 = nn.Conv2d(512,128,3,dilation=2, padding=2)self.bdg_bn1 = nn.BatchNorm2d(128)self.bdg_conv2 = nn.Conv2d(512,128,3,dilation=4, padding=4)self.bdg_bn2 = nn.BatchNorm2d(128)self.bdg_conv3 = nn.Conv2d(512,128,3,dilation=8, padding=8)self.bdg_bn3 = nn.BatchNorm2d(128)self.bdg_conv4 = nn.Conv2d(512,128,3,dilation=16, padding=16)self.bdg_bn4 = nn.BatchNorm2d(128)...def forward(self,x):...#-------------Bridge--------------##提取多尺度上下文信息Fea2 = self.bdg_bn1(self.bdg_conv1(score1_5))Fea4 = self.bdg_bn2(self.bdg_conv2(score1_5))Fea8 = self.bdg_bn3(self.bdg_conv3(score1_5))Fea16 = self.bdg_bn4(self.bdg_conv4(score1_5))#多尺度融合score_bdg = torch.cat((Fea2,Fea4,Fea8,Fea16,score1_5),1)...#深度监督labelbdg_out = self.label_outconv9(score_bdg)labelbdg_out = self.upscore16(labelbdg_out)...#-------------Return--------------#return torch.sigmoid(edge_out), torch.sigmoid(label1_out), torch.sigmoid(label2_out), torch.sigmoid(label3_out), torch.sigmoid(labelbdg_out), \torch.sigmoid(label4_out), torch.sigmoid(label5_out), torch.sigmoid(label6_out), torch.sigmoid(label7_out), torch.sigmoid(label8_out)

2.5解码器:深度特征融合解码器

在这里插入图片描述
  深度特征聚合模块(Deep Feature Aggregation Module)将多尺度深度特征图 F i E , i ∈ { 1 , 2 , 3 , 4 , 5 } F^E_i,i∈\{1,2,3,4,5\} FiE,i{1,2,3,4,5}转换为显著性图。共包含了五个解码器 D e c o d e r − B i , i ∈ { 1 , 2 , 3 , 4 , 5 } Decoder-Bi,i∈\{1,2,3,4,5\} DecoderBi,i{1,2,3,4,5},每个解码器都由三个卷积模块 D B i − j , j ∈ { 1 , 2 , 3 } DBi-j,j∈\{1,2,3\} DBij,j{1,2,3}组成,每个卷积模块都包含卷积层、BN、ReLU。解码过程为:
在这里插入图片描述
在这里插入图片描述

class EMFINet(nn.Module):def __init__(self):super(EMFINet,self).__init__()...#-------------deep feature aggregation module--------------##self.pool5 = nn.MaxPool2d(8,8,ceil_mode=True)self.mconv5 = nn.Conv2d(1024 + 128,1024,3,padding=1)self.mbn5 = nn.BatchNorm2d(1024)self.mrelu5 = nn.ReLU(inplace=True)self.convd5_1 = nn.Conv2d(1024,512,3,padding=1)self.bnd5_1 = nn.BatchNorm2d(512)self.relud5_1 = nn.ReLU(inplace=True)self.convd5_2 = nn.Conv2d(512,512,3,padding=1)self.bnd5_2 = nn.BatchNorm2d(512)self.relud5_2 = nn.ReLU(inplace=True)self.convd5_3 = nn.Conv2d(512,512,3,padding=1)self.bnd5_3 = nn.BatchNorm2d(512)self.relud5_3 = nn.ReLU(inplace=True)#stage 4self.pool4 = nn.MaxPool2d(4,4,ceil_mode=True)self.mconv4 = nn.Conv2d(512 + 128,512,3,padding=1)self.mbn4 = nn.BatchNorm2d(512)self.mrelu4 = nn.ReLU(inplace=True)self.convd4_1 = nn.Conv2d(1024,512,3,padding=1)self.bnd4_1 = nn.BatchNorm2d(512)self.relud4_1 = nn.ReLU(inplace=True)self.convd4_2 = nn.Conv2d(512,512,3,padding=1)self.bnd4_2 = nn.BatchNorm2d(512)self.relud4_2 = nn.ReLU(inplace=True)self.convd4_3 = nn.Conv2d(512,256,3,padding=1)self.bnd4_3 = nn.BatchNorm2d(256)self.relud4_3 = nn.ReLU(inplace=True)#stage 3self.pool3 = nn.MaxPool2d(2,2,ceil_mode=True)self.mconv3 = nn.Conv2d(256 + 128,256,3,padding=1)self.mbn3 = nn.BatchNorm2d(256)self.mrelu3 = nn.ReLU(inplace=True)self.convd3_1 = nn.Conv2d(512,256,3,padding=1)self.bnd3_1 = nn.BatchNorm2d(256)self.relud3_1 = nn.ReLU(inplace=True)self.convd3_2 = nn.Conv2d(256,256,3,padding=1)self.bnd3_2 = nn.BatchNorm2d(256)self.relud3_2 = nn.ReLU(inplace=True)self.convd3_3 = nn.Conv2d(256,128,3,padding=1)self.bnd3_3 = nn.BatchNorm2d(128)self.relud3_3 = nn.ReLU(inplace=True)#stage 2self.mconv2 = nn.Conv2d(128 + 128,128,3,padding=1)self.mbn2 = nn.BatchNorm2d(128)self.mrelu2 = nn.ReLU(inplace=True)self.convd2_1 = nn.Conv2d(256,128,3,padding=1)self.bnd2_1 = nn.BatchNorm2d(128)self.relud2_1 = nn.ReLU(inplace=True)self.convd2_2 = nn.Conv2d(128,128,3,padding=1)self.bnd2_2 = nn.BatchNorm2d(128)self.relud2_2 = nn.ReLU(inplace=True)self.convd2_3 = nn.Conv2d(128,64,3,padding=1)self.bnd2_3 = nn.BatchNorm2d(64)self.relud2_3 = nn.ReLU(inplace=True)#stage 1self.up1 = nn.Upsample(scale_factor=2, mode='bilinear',align_corners=True)self.mconv1 = nn.Conv2d(64 + 128,64,3,padding=1)self.mbn1 = nn.BatchNorm2d(64)self.mrelu1 = nn.ReLU(inplace=True)self.convd1_1 = nn.Conv2d(128,64,3,padding=1)self.bnd1_1 = nn.BatchNorm2d(64)self.relud1_1 = nn.ReLU(inplace=True)self.convd1_2 = nn.Conv2d(64,64,3,padding=1)self.bnd1_2 = nn.BatchNorm2d(64)self.relud1_2 = nn.ReLU(inplace=True)self.convd1_3 = nn.Conv2d(64,64,3,padding=1)self.bnd1_3 = nn.BatchNorm2d(64)self.relud1_3 = nn.ReLU(inplace=True)...def forward(self,x):#-------------deep feature aggregation module--------------##Decoder-B5:融合桥接器输出score_bdg与边缘提取模块输出score_edge##concate and convolutiont = self.pool5(score_edge)t = torch.cat((t,score_bdg),1)t = self.mrelu5(self.mbn5(self.mconv5(t)))##Decoder-B5scored5 = self.relud5_1(self.bnd5_1(self.convd5_1(t)))scored5 = self.relud5_2(self.bnd5_2(self.convd5_2(scored5)))scored5 = self.relud5_3(self.bnd5_3(self.convd5_3(scored5)))##上采样,作为Decoder-B4的输入scored5_up = self.upscore2(scored5)#Decoder-B4:融合F14与边缘提取模块输出score_edget = self.pool4(score_edge)t = torch.cat((t,score1_4),1)t = self.mrelu4(self.mbn4(self.mconv4(t)))##Decoder-B4scored4 = torch.cat((scored5_up,t),1)scored4 = self.relud4_1(self.bnd4_1(self.convd4_1(scored4)))scored4 = self.relud4_2(self.bnd4_2(self.convd4_2(scored4)))scored4 = self.relud4_3(self.bnd4_3(self.convd4_3(scored4)))##上采样,作为Decoder-B3的输入scored4_up = self.upscore2(scored4)#Decoder-B3:融合F13与边缘提取模块输出score_edget = self.pool3(score_edge)t = torch.cat((t,score1_3),1)t = self.mrelu3(self.mbn3(self.mconv3(t)))##Decoder-B3scored3 = torch.cat((scored4_up,t),1)scored3 = self.relud3_1(self.bnd3_1(self.convd3_1(scored3)))scored3 = self.relud3_2(self.bnd3_2(self.convd3_2(scored3)))scored3 = self.relud3_3(self.bnd3_3(self.convd3_3(scored3)))##上采样,作为Decoder-B2的输入scored3_up = self.upscore2(scored3)#Decoder-B2:融合F12与边缘提取模块输出score_edget = torch.cat((score1_2,score_edge),1)t = self.mrelu2(self.mbn2(self.mconv2(t)))##Decoder-B2scored2 = torch.cat((scored3_up,t),1)scored2 = self.relud2_1(self.bnd2_1(self.convd2_1(scored2)))scored2 = self.relud2_2(self.bnd2_2(self.convd2_2(scored2)))scored2 = self.relud2_3(self.bnd2_3(self.convd2_3(scored2)))##上采样,作为Decoder-B1的输入scored2_up = self.upscore2(scored2)#Decoder-B3:融合F11与边缘提取模块输出score_edget = self.up1(score_edge)t = torch.cat((score1_1,t),1)t = self.mrelu1(self.mbn1(self.mconv1(t)))##Decoder-B1scored1 = torch.cat((scored2_up,t),1)scored1 = self.relud1_1(self.bnd1_1(self.convd1_1(scored1)))scored1 = self.relud1_2(self.bnd1_2(self.convd1_2(scored1)))scored1 = self.relud1_3(self.bnd1_3(self.convd1_3(scored1)))...#-------------Label output--------------##深度监督编码器5的输出label4_out = self.label_outconv4(scored5)label4_out = self.upscore16(label4_out)#深度监督编码器4的输出label5_out = self.label_outconv5(scored4)label5_out = self.upscore8(label5_out)#深度监督编码器3的输出label6_out = self.label_outconv6(scored3)label6_out = self.upscore4(label6_out)#深度监督编码器2的输出label7_out = self.label_outconv7(scored2)label7_out = self.upscore2(label7_out)#深度监督编码器1的输出(无需上采样)label8_out = self.label_outconv8(scored1)#-------------Return--------------#return torch.sigmoid(edge_out), torch.sigmoid(label1_out), torch.sigmoid(label2_out), torch.sigmoid(label3_out), torch.sigmoid(labelbdg_out), \torch.sigmoid(label4_out), torch.sigmoid(label5_out), torch.sigmoid(label6_out), torch.sigmoid(label7_out), torch.sigmoid(label8_out)

三、MJRBM

  论文:ORSI Salient Object Detection via Multiscale Joint Region and Boundary Model(用于光学遥感影像显著性目标检测的多尺度联合区域和边界模型)
  论文链接:ORSI Salient Object Detection via Multiscale Joint Region and Boundary Model
  代码链接:Github
  博客链接:CSDN

3.1编码器:VGG16双分支编码器

在这里插入图片描述
  双分支结构的设计思想参考了级联部分解码器,两个分支的作用如下:

  • 1.第一个分支:通过PPM模块(见论文Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition)提取语义信息,并将其与VGG-16第二个模块的输出结合,以提取边界特征。
  • 2.第二个分支:通过分层注意力模块(HAM,Hierarchical Attention Module)提取多尺度特征,并通过联合区域和边界模块(JRBM,Joint Region and Boundary Model)来联合优化边界和区域特征。

在这里插入图片描述
  上图中D即为VGG-16架构。在代码中并未包含模型中 V G G 3 − 2 VGG3-2 VGG32模块的定义,而 V G G 4 − 2 、 V G G 5 − 2 VGG4-2、VGG5-2 VGG42VGG52实则是VGG4-1、VGG5-1$的重复。

#model/vgg.py
class B2_VGG(nn.Module):# VGG16 with two branches# pooling layer at the front of blockdef __init__(self):super(B2_VGG, self).__init__()#VGG1conv1 = nn.Sequential()#conv3- 64conv1.add_module('conv1_1', nn.Conv2d(3, 64, 3, 1, 1))conv1.add_module('relu1_1', nn.ReLU(inplace=True))#conv3- 64conv1.add_module('conv1_2', nn.Conv2d(64, 64, 3, 1, 1))conv1.add_module('relu1_2', nn.ReLU(inplace=True))self.conv1 = conv1#VGG2conv2 = nn.Sequential()#maxpoolconv2.add_module('pool1', nn.AvgPool2d(2, stride=2))#conv3- 128conv2.add_module('conv2_1', nn.Conv2d(64, 128, 3, 1, 1))conv2.add_module('relu2_1', nn.ReLU())#conv3- 128conv2.add_module('conv2_2', nn.Conv2d(128, 128, 3, 1, 1))conv2.add_module('relu2_2', nn.ReLU())self.conv2 = conv2#VGG3_1conv3 = nn.Sequential()#maxpoolconv3.add_module('pool2', nn.AvgPool2d(2, stride=2))#conv3- 256conv3.add_module('conv3_1', nn.Conv2d(128, 256, 3, 1, 1))conv3.add_module('relu3_1', nn.ReLU())#conv3- 256conv3.add_module('conv3_2', nn.Conv2d(256, 256, 3, 1, 1))conv3.add_module('relu3_2', nn.ReLU())#conv3- 256conv3.add_module('conv3_3', nn.Conv2d(256, 256, 3, 1, 1))conv3.add_module('relu3_3', nn.ReLU())self.conv3 = conv3#VGG4_1conv4_1 = nn.Sequential()#maxpoolconv4_1.add_module('pool3_1', nn.AvgPool2d(2, stride=2))#conv3- 512conv4_1.add_module('conv4_1_1', nn.Conv2d(256, 512, 3, 1, 1))conv4_1.add_module('relu4_1_1', nn.ReLU())#conv3- 512conv4_1.add_module('conv4_2_1', nn.Conv2d(512, 512, 3, 1, 1))conv4_1.add_module('relu4_2_1', nn.ReLU())#conv3- 512conv4_1.add_module('conv4_3_1', nn.Conv2d(512, 512, 3, 1, 1))conv4_1.add_module('relu4_3_1', nn.ReLU())self.conv4_1 = conv4_1#VGG5_1conv5_1 = nn.Sequential()#maxpoolconv5_1.add_module('pool4_1', nn.AvgPool2d(2, stride=2))#conv3- 512conv5_1.add_module('conv5_1_1', nn.Conv2d(512, 512, 3, 1, 1))conv5_1.add_module('relu5_1_1', nn.ReLU())#conv3- 512conv5_1.add_module('conv5_2_1', nn.Conv2d(512, 512, 3, 1, 1))conv5_1.add_module('relu5_2_1', nn.ReLU())#conv3- 512conv5_1.add_module('conv5_3_1', nn.Conv2d(512, 512, 3, 1, 1))conv5_1.add_module('relu5_3_1', nn.ReLU())self.conv5_1 = conv5_1#VGG4_2conv4_2 = nn.Sequential()conv4_2.add_module('pool3_2', nn.AvgPool2d(2, stride=2))#conv3- 512conv4_2.add_module('conv4_1_2', nn.Conv2d(256, 512, 3, 1, 1))conv4_2.add_module('relu4_1_2', nn.ReLU())#conv3- 512conv4_2.add_module('conv4_2_2', nn.Conv2d(512, 512, 3, 1, 1))conv4_2.add_module('relu4_2_2', nn.ReLU())#conv3- 512conv4_2.add_module('conv4_3_2', nn.Conv2d(512, 512, 3, 1, 1))conv4_2.add_module('relu4_3_2', nn.ReLU())self.conv4_2 = conv4_2#VGG5_2conv5_2 = nn.Sequential()conv5_2.add_module('pool4_2', nn.AvgPool2d(2, stride=2))#conv3- 512conv5_2.add_module('conv5_1_2', nn.Conv2d(512, 512, 3, 1, 1))conv5_2.add_module('relu5_1_2', nn.ReLU())#conv3- 512conv5_2.add_module('conv5_2_2', nn.Conv2d(512, 512, 3, 1, 1))conv5_2.add_module('relu5_2_2', nn.ReLU())#conv3- 512conv5_2.add_module('conv5_3_2', nn.Conv2d(512, 512, 3, 1, 1))conv5_2.add_module('relu5_3_2', nn.ReLU())self.conv5_2 = conv5_2#加载预训练权重pre_train = torch.load('./model/CPD.pth')self._initialize_weights(pre_train)def forward(self, x):x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)x1 = self.conv4_1(x)x1 = self.conv5_1(x1)x2 = self.conv4_2(x)x2 = self.conv5_2(x2)#返回VGG5_1、VGG5_2的输出return x1, x2#初始化权重def _initialize_weights(self, pre_train):...

  在模型代码中:

#model/CPD_models.py
class JRBM(nn.Module):def __init__(self, channel=32):super(JRBM, self).__init__()#加载编码器架构self.vgg = B2_VGG()...def forward(self, x):#VGG1x1 = self.vgg.conv1(x)#VGG2x2 = self.vgg.conv2(x1)#VGG3_1x3 = self.vgg.conv3(x2)x3_1 = x3#VGG4_1x4_1 = self.vgg.conv4_1(x3_1)#VGG5_1x5_1 = self.vgg.conv5_1(x4_1)...#VGG3_2x3_2 = self.HA(attention.sigmoid(), x3)#VGG4_2x4_2 = self.vgg.conv4_2(x3_2)#VGG5_2x5_2 = self.vgg.conv5_2(x4_2)...

3.2SBFEM:显著边界特征提取模块

在这里插入图片描述
  显著边界特征提取模块(Salient Boundary Feature Extraction Module)由PPM模块(用于获取全局信息的金字塔池模块,见论文Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition,在代码中定义为GGM模块)和两个卷积模块组成。用于从高级特征图中捕获全局信息来定位显著对象、从低级特征图中获取显著边界信息,来指导显著目标边界特征的生成。PPM模块代码实现:

#model/BGM_PPM.py
class GGM(nn.Module):  # get global featuredef __init__(self, in_channels):super(GGM, self).__init__()self.branch0 = nn.Sequential(nn.Conv2d(in_channels, in_channels, 3, 1, 1),nn.ReLU())self.branch1 = nn.Sequential(nn.AdaptiveAvgPool2d((3, 3)),nn.Conv2d(in_channels, in_channels, 1, 1),nn.ReLU())self.branch2 = nn.Sequential(nn.AdaptiveAvgPool2d((5, 5)),nn.Conv2d(in_channels, in_channels, 1, 1),nn.ReLU())self.branch3 = nn.Sequential(nn.AdaptiveAvgPool2d((1, 1)),nn.Conv2d(in_channels, in_channels, 1, 1),nn.ReLU())self.con = nn.Conv2d(in_channels * 4, in_channels, 3, 1, 1)for m in self.modules():if isinstance(m, nn.Conv2d):m.weight.data.normal_(std=0.01)m.bias.data.fill_(0)def forward(self, x):x0 = self.branch0(x)x1 = self.branch1(x)x1 = F.upsample(x1, x0.size()[2:], mode='bilinear', align_corners=True)x2 = self.branch2(x)x2 = F.upsample(x2, x0.size()[2:], mode='bilinear', align_corners=True)x3 = self.branch3(x)x3 = F.upsample(x3, x0.size()[2:], mode='bilinear', align_corners=True)x = self.con(torch.cat((x0, x1, x2, x3), 1))return x

  模型代码:

class JRBM(nn.Module):def __init__(self, channel=32):super(JRBM, self).__init__()...self.HA = HA()self.glob = GGM(512)self.upsample2 = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)self.upsample4 = nn.Upsample(scale_factor=4, mode='bilinear', align_corners=False)self.upsample8 = nn.Upsample(scale_factor=8, mode='bilinear', align_corners=False)self.glob_vgg2 = nn.Sequential(nn.Conv2d(512 + 128, 128, 3, 1, 1),nn.ReLU(),nn.Conv2d(128, 128, 3, 1, 1),nn.ReLU(),nn.Conv2d(128, channel, 3, 1, 1))self.conv3 = nn.Conv2d(channel, 1, 1)def forward(self, x):...#输入PPM模块提取全局信息x_glob = self.glob(x5_1)        #out_channel=512#融合语义信息、细节信息,通过glob_vgg2模块改变通道数(以作为两个解码器JRBM的输入)x_edge = self.glob_vgg2(torch.cat((self.upsample8(x_glob),x2),1))   #out_channel=channel...#将通道数降为1,生成显著边缘图x_edge_pre = self.conv3(x_edge)...#返回显著边缘图作损失函数return self.upsample4(attention),self.upsample2(x_edge_pre), self.upsample4(detection)

3.4分层注意力模块:HAM

在这里插入图片描述
  分层注意力模块(HAM,Hierarchical Attention Module)使用不同膨胀率的卷积核获取多尺度信息,并将结果直接串联。由于不同的感受野获得的特征无法区分细微的特征,因此突出的物体具有空间不一致。故将特征图输入到通道注意力模块(见Dual Attention Network for Scene Segmentation)中以解决此问题。

#model/CPD_models.py
class HAM(nn.Module):def __init__(self, in_channel, out_channel):super(HAM, self).__init__()self.relu = nn.ReLU(True)#普通卷积self.branch0 = nn.Sequential(nn.Conv2d(in_channel, out_channel, 1),)#膨胀卷积(r=3)self.branch1 = nn.Sequential(nn.Conv2d(in_channel, out_channel, 1),nn.Conv2d(out_channel, out_channel, kernel_size=(1, 3), padding=(0, 1)),nn.Conv2d(out_channel, out_channel, kernel_size=(3, 1), padding=(1, 0)),nn.Conv2d(out_channel, out_channel, 3, padding=3, dilation=3))#膨胀卷积(r=5)self.branch2 = nn.Sequential(nn.Conv2d(in_channel, out_channel, 1),nn.Conv2d(out_channel, out_channel, kernel_size=(1, 5), padding=(0, 2)),nn.Conv2d(out_channel, out_channel, kernel_size=(5, 1), padding=(2, 0)),nn.Conv2d(out_channel, out_channel, 3, padding=5, dilation=5))#膨胀卷积(r=7)self.branch3 = nn.Sequential(nn.Conv2d(in_channel, out_channel, 1),nn.Conv2d(out_channel, out_channel, kernel_size=(1, 7), padding=(0, 3)),nn.Conv2d(out_channel, out_channel, kernel_size=(7, 1), padding=(3, 0)),nn.Conv2d(out_channel, out_channel, 3, padding=7, dilation=7))#膨胀卷积(r=9)self.branch4 = nn.Sequential(nn.Conv2d(in_channel, out_channel, 1),nn.Conv2d(out_channel, out_channel, kernel_size=(1, 9), padding=(0, 4)),nn.Conv2d(out_channel, out_channel, kernel_size=(9, 1), padding=(4, 0)),nn.Conv2d(out_channel, out_channel, 3, padding=9, dilation=9))self.conv_cat = nn.Conv2d(5*out_channel, out_channel, 3, padding=1)self.conv_res = nn.Conv2d(in_channel, out_channel, 1)#通道注意力模块self.channel_attention = CAM_Module(out_channel)self.conv1 = nn.Conv2d(out_channel,out_channel,3,1,1)for m in self.modules():if isinstance(m, nn.Conv2d):m.weight.data.normal_(std=0.01)m.bias.data.fill_(0)def forward(self, x):#依次进行膨胀卷积x0 = self.branch0(x)x1 = self.branch1(x)x2 = self.branch2(x)x3 = self.branch3(x)x4 = self.branch4(x)#融合膨胀结果x_cat = torch.cat((x0, x1, x2, x3, x4), 1)#卷积后得到特征图Ax_cat = self.conv_cat(x_cat)#通道注意力增强x_cat = self.channel_attention(x_cat)x_cat = self.conv1(x_cat)#残差连接x = self.relu(x_cat + self.conv_res(x))return x

3.4Aggregation:聚合模块

在这里插入图片描述
在这里插入图片描述
  MJRBM模型中的Aggregation模块用于聚合三个JRBM模块的输出,其先使用高层特征来优化低层特征,然后将多层特征串联起来做出最终预测。

#model/CPD_models.py
class BasicConv2d(nn.Module):def __init__(self, in_planes, out_planes, kernel_size,stride=1, padding=0, dilation=1, groups=1, bias=False):super(BasicConv2d, self).__init__()self.basicconv = nn.Sequential(nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride,padding=padding, dilation=dilation, groups=groups, bias=bias),nn.BatchNorm2d(out_planes),nn.ReLU(inplace=True))def forward(self, x):return self.basicconv(x)class aggregation_add(nn.Module):def __init__(self, channel):super(aggregation_add, self).__init__()self.relu = nn.ReLU(True)self.upsample = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)self.conv_upsample1 = BasicConv2d(channel, channel, 3, padding=1)self.conv_upsample2 = BasicConv2d(channel, channel, 3, padding=1)self.conv_upsample3 = BasicConv2d(channel, channel, 3, padding=1)self.conv_upsample4 = BasicConv2d(channel, channel, 3, padding=1)self.conv_upsample5 = BasicConv2d(channel, channel, 3, padding=1)self.conv_concat2 = BasicConv2d(2*channel, 2*channel, 3, padding=1)self.conv_concat3 = BasicConv2d(3*channel, 3*channel, 3, padding=1)self.conv4 = BasicConv2d(3*channel, 3*channel, 3, padding=1)self.conv5 = nn.Conv2d(3*channel, 1, 1)def forward(self, x1, x2, x3):#深层特征x1_1 = x1#使用x1_1优化x2_1x2_1 = self.conv_upsample1(self.upsample(x1)) * x2#使用x1_1、x2_1优化x3_1x3_1 = self.conv_upsample2(self.upsample(self.upsample(x1))) \+ self.conv_upsample3(self.upsample(x2)) * x3#特征融合x3_2 = torch.cat((x3_1, self.conv_upsample4(self.upsample(self.upsample(x1_1))), self.conv_upsample5(self.upsample(x2_1))), 1)x = self.conv4(x3_2)x = self.conv5(x)return x

3.5JRBM:联合区域和边界模块

在这里插入图片描述
  联合区域和边界模块(JRBM,Joint Region and Boundary Module),在获得多尺度显著区域特征和边界特征后,共同优化边界特征和显著区域特征。最后将二者融合,输入到融合模块Aggregation中。在上图中, β β β为输入的边界特征, γ γ γ为输入的区域特征,由于二者当中均可能存在噪声,因此采用门机制实现自适应选择:
在这里插入图片描述
由于区域特征与对象边界特征之间存在如下逻辑关系:
在这里插入图片描述
因此在实际实现中使用乘法操作代表 ∧ ∧ 、Concat操作代表 ∨ ∨ 来获取增强后的显著区域特征与边界特征,并将二者融合得到增强后的显著区域特征:
在这里插入图片描述
在这里插入图片描述

#JRBM
class BGModel(nn.Module):def __init__(self, channel,e1_stride, e2_stride):super(BGModel, self).__init__()self.relu = nn.ReLU()self.conv0 = nn.Conv2d(channel, channel, 5, e1_stride, 2)self.gamma = nn.Conv2d(channel, channel, 5, e2_stride, 2)self.conv1 = nn.Conv2d(channel, channel, 5, 1, 2)self.conv2 = nn.Conv2d(channel, channel, 3, 1, 1)self.conv3 = nn.Conv2d(channel*2, channel, 3, 1, 1)self.conv4 = nn.Conv2d(2*channel, channel, 3, 1, 1)self.edge_pre = nn.Conv2d(channel, 1, 1)self.fea_pre = nn.Conv2d(channel, 1, 1)#权重初始化for m in self.modules():...def forward(self, y, x):  # x= feature, y=edge#门函数,过滤显著区域噪声x = x * F.sigmoid(x)x = self.conv1(x)#门函数,过滤显著边界噪声y = y * F.sigmoid(y)y = self.relu(self.conv0(y))y = self.relu(self.gamma(y))#增强显著边界edge = self.relu(self.conv2( x * y))e_pre = self.edge_pre(edge)#增强显著区域fea = self.relu(self.conv3(torch.cat((x,y),1)))f_pre = self.fea_pre(fea)#显著边界与显著区域融合x = self.conv4(torch.cat((edge, fea),1))return x

3.6解码器:双分支解码器

在这里插入图片描述
  MJRBM模型以VGG-16作为编码器提取特征,使用双解码器架构来得到显著性图。

  • 解码器1:网络只能得到粗略的显著目标,在遥感图像的复杂场景中很难准确分割。
  • 解码器2:通过整体关注有效地整合了骨干网的多级特征,从而减少了噪声的干扰,得到了更准确、更统一的显著图。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58772.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【传知代码】图像处理解决种子计数方法

文章目录 一、背景及意义介绍研究背景农业考种需求传统计数方法的局限性人工计数仪器设备计数 研究意义提高育种效率提高计数准确性广泛的适用性数据存档与分析便利 二、概述三、材料与数据准备以及方法介绍整体流程图像采集图像预处理形态学操作腐蚀运算开运算 图像二值化种子…

【酒店管理与推荐系统】Python+Django网页界面平台+推荐算法+管理系统网站

一、介绍 酒店管理系统。基于Python开发&#xff0c;前端使用HTML、CSS、BootStrap等技术搭建页面&#xff0c;后端使用Django框架处理用户响应请求&#xff0c;主要功能如下&#xff1a; 分为普通用户和管理员两个角色普通用户&#xff1a;登录、注册、查看房间详情、收藏、…

List 列表基础用法

List 列表基础用法 列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同&#xff0c;它支持数字&#xff0c;字符串甚至可以包含列表&#xff08;所谓嵌套&#xff09;。 列表是写在方括号 [] 之间、用逗号分隔开的元素列表。 和字符串一样&#xff0c;列表…

C#/.NET/.NET Core技术前沿周刊 | 第 11 期(2024年10.21-10.31)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

redis7学习笔记

文章目录 1. 简介1.1 功能介绍1.1.1 分布式缓存1.1.2 内存存储和持久化(RDBAOF)1.1.3 高可用架构搭配1.1.4 缓存穿透、击穿、雪崩1.1.5 分布式锁1.1.6 队列 1.2 数据类型StringListHashSetZSetGEOHyperLogLogBitmapBitfieldStream 2. 命令2.1 通用命令copydeldumpexistsexpire …

动态规划-回文串系列——516.最长回文子序列

1.题目解析 题目来源&#xff1a;516.最长回文子序列——力扣 测试用例 2.算法原理 1.状态表示 求某段字符的最长回文子序列长度需要知道原来的长度以及判断后续的值是否能与之前的回文子序列构成新的回文子序列&#xff0c;因此一维dp表显然无法满足要求&#xff0c;那么就需…

基于STM32的智能门锁控制系统设计

引言 本项目基于STM32微控制器设计了一个智能门锁控制系统&#xff0c;用户可以通过密码输入或指纹识别来控制门锁的开关。该系统集成了键盘、指纹传感器、舵机等外设&#xff0c;实现了门锁的安全、便捷控制&#xff0c;同时也具备了较强的扩展性。该项目展示了STM32在安防领…

基于 FMEA软件的智能制造质量控制策略_SunFMEA软件

【大家好&#xff0c;我是唐Sun&#xff0c;唐Sun的唐&#xff0c;唐Sun的Sun。一站式数智工厂解决方案服务商】 在智能制造的大背景下&#xff0c;制造业正经历着深刻的变革&#xff0c;质量控制也面临着新的挑战和机遇。FMEA&#xff08;失效模式与影响分析&#xff09;作为一…

躺平成长-运营日记-第三天

开源竞争&#xff1a; &#xff08;自己没有办法完全掌握技术的时候就开源掉&#xff0c;培养出更多的技术依赖&#xff0c;让更多的人完善你的技术&#xff0c;那么这不就是在砸罐子吗&#xff1f;一个行业里面你不去砸罐子&#xff0c;其他人就会砸罐子&#xff0c;你不如先砸…

中文文本分类 pytorch实现

前言 使用pytorch实现了TextCNN&#xff0c;TextRNN&#xff0c;FastText&#xff0c;TextRCNN&#xff0c;BiLSTM_Attention&#xff0c;DPCNN&#xff0c;Transformer&#xff0c;开箱即用。 中文数据集 我从THUCNews&#xff1a;THUCTC: 一个高效的中文文本分类工具中抽取…

JAVA利用方法实现四道题

目录 1.给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回-1 2.计算字符串最后一个单词的长度&#xff0c;单词以空格隔开。&#xff08;注&#xff1a;字符串末尾不以空格为结尾&#xff09; 3.如果在将所…

前端三件套(HTML + CSS + JS)

前言&#xff1a; 前端三件套&#xff0c;会用就行 毕竟在后面学习JavaWeb&#xff0c;以及在学习vue的时候也有帮助 前端三件套&#xff1a; HTML 定义网页的结构和内容。CSS 负责网页的样式和布局。JavaScript 添加动态交互和功能。 使用到的工具是Visual Studio Code 即…

Android -- [SelfView] 自定义圆盘指针时钟

Android – [SelfView] 自定义圆盘指针时钟 ps:简约圆盘指针时钟&#xff0c;颜色可调、自由搭配&#xff1b;支持阿拉伯数字、罗马数字刻度显示&#xff1b;效果图 使用&#xff1a; <!-- 自定义属性参考 attrs.xml 文件 --> <com.nepalese.harinetest.player.Virg…

边缘计算【智能+安全检测】系列教程--agx orin解决RTC时间问题

因为是离线运行&#xff0c;首要问题是时间不准确&#xff0c;就在主板上加装了纽扣电池&#xff0c;但是会有一系列问题&#xff0c;比如无法将RTC时间回写到系统时间&#xff0c;或者无法将系统时间写到RTC中等等一些列问题。为解决这些问题&#xff0c;一劳永逸的方式&#…

智能家居10G雷达感应开关模块,飞睿智能uA级别低功耗、超高灵敏度,瞬间响应快

在当今科技飞速发展的时代&#xff0c;智能家居已经逐渐成为人们生活中不可或缺的一部分。从智能灯光控制到智能家电的联动&#xff0c;每一个细节都在为我们的生活带来便利和舒适。而在众多智能家居产品中&#xff0c;10G 雷达感应开关模块以其独特的优势&#xff0c;正逐渐成…

【源码+文档】基于SpringBoot+Vue旅游网站系统【提供源码+答辩PPT+参考文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Python Matplotlib:基本图表绘制指南

Python Matplotlib&#xff1a;基本图表绘制指南 Matplotlib 是 Python 中一个非常流行的绘图库&#xff0c;它以简单易用和功能丰富而闻名&#xff0c;适合各种场景的数据可视化需求。在数据分析和数据科学领域&#xff0c;Matplotlib 是我们展示数据的有力工具。本文将详细讲…

开源库 FloatingActionButton

开源库FloatingActionButton Github:https://github.com/Clans/FloatingActionButton 这个库是在前面这个库android-floating-action-button的基础上修改的&#xff0c;增加了一些更强大和实用的特性。 特性&#xff1a; Android 5.0 以上点击会有水波纹效果 可以选择自定义…

【Hello World 】

【Hello World 】! C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 几乎每一个程序员都是从Hello World!开始自己的程序人生&#xff0c;作为一个初学编程的小朋友&#xff0c;也需要先编程来输出Hello Wo…

从实验室到生活:超分子水凝胶湿电发电机的应用之路

大家好&#xff01;今天来了解一种新型的绿色湿电发电机&#xff08;MEG&#xff09;——《Green moisture-electric generator based on supramolecular hydrogel with tens of milliamp electricity toward practical applications》发表于《nature communications》&#xf…