当前位置: 首页 > news >正文

【视频讲解】顶级期刊即插即用模块代码共享计划·2024第一期:02:非相邻层次间语义信息渐进式特征融合策略(2024 1区Top | 浙江大学开源)代码实现

视频讲解

【布尔大学士】啊!浙大大学一区Top!15分钟速通非相邻层次间语义信息渐进式特征融合策略~~~~

Asymptotic Feature Pyramid Network for Labeling Pixels and Regions 用于标记像素和区域的渐近特征金字塔网络(2024-1区)

论文地址:https://arxiv.org/pdf/2306.15988

在这里插入图片描述

1、摘要

在视觉任务中,多尺度特征对于编码不同尺度的物体至关重要。经典的自上而下和自下而上的特征金字塔网络是多尺度特征提取的常用策略。然而,这些方法都存在特征信息丢失或退化的问题,从而影响了非相邻层次的融合效果。

本文提出了一种渐近特征金字塔网络(AFPN),用于解决经典特征金字塔网络中非相邻层次间信息损失或降级的问题。

AFPN通过融合相邻低层特征开始,并逐步将更高层次的特征纳入融合过程,从而避免了不同层次间的较大语义差距。此外,为了缓解多对象信息冲突,引入了自适应空间融合操作。

2、背景

2.1 引言与现有工作存在的问题

传统的物体检测方法通常只从图像中提取单一尺度的特征,这限制了不同大小或场景下的物体检测性能。为了有效地编码具有尺度变化的对象,多尺度特征提取变得至关重要。

  • 一种常见的策略是采用经典的自顶向下和自底向上的特征金字塔网络。然而,这些方法在非相邻层次之间的特征融合中可能会导致信息损失或降级。
  • 为了解决这一局限性,GraphFPN [18] 引入了图神经网络,以实现非相邻尺度特征之间的直接交互。然而,额外的图神经网络结构大大增加了模型的参数和计算量,得不偿失。现有的特征金字塔网络通常会将骨干网络中的高级特征向上采样为低级特征。
  • 现有的特征金字塔架构要求高级特征通过多个中间尺度传播,并在与低级特征融合之前与这些尺度的特征交互。然而,这种传播和交互过程可能会导致高级特征的语义信息或低级特征的详细信息丢失或退化。

2.2 启发来源

HRNet [25], [26]在特征提取过程中会保留低层次特征,并反复合并低层次特征和高层次特征,以生成更丰富的低层次特征。这种方法在人体姿态估计方面取得了卓越的成果。

HRNet如下图所示

论文名称: Deep High-Resolution Representation Learning for Human Pose Estimation
论文下载地址:https://arxiv.org/abs/1902.09212
在这里插入图片描述

)

3、创新点与解决问题

AFPN的主要贡献在于:

  1. 渐近融合:AFPN支持非相邻层次之间直接的特征融合,避免了信息传输和交互过程中的损失或降级。
  2. 自适应空间融合:在多层特征融合过程中引入自适应空间融合操作,以抑制不同层次特征间的信息矛盾。
  3. 实验结果:AFPN在Faster R-CNN和Dynamic R-CNN等两阶段检测器以及YOLOv5等单阶段检测器中都表现出显著的性能提升,特别是在大目标检测方面。

3.1 . Asymptotic Architecture

非相邻分层特征之间的语义差距大于相邻分层特征之间的语义差距,尤其是底部和顶部特征。这就导致直接使用非相邻层次特征的融合效果不佳。因此,直接使用 C2、C3、C4 和 C5 进行特征融合是不合理的。AFPN 的架构如图 2 所示。

在骨干网络自下而上的特征提取过程中,AFPN 对低层、高层和顶层特征进行渐进式融合。具体来说,AFPN 首先融合低层次特征,然后融合深层次特征,最后融合最顶层的特征,即最抽象的特征。

在这里插入图片描述

由于 AFPN 的架构是渐近式的,这将使不同层次特征的语义信息在渐近式融合过程中更加接近,从而缓解上述问题。例如,C2 和 C3 之间的特征融合可以缩小它们之间的语义差距。由于 C3 和 C4 是相邻的分层特征,因此 C2 和 C4 之间的语义差距会减小。

为了对齐维度并为特征融合做准备,我们利用 1×1 卷积和双线性插值方法对特征进行上采样。另一方面,我们根据所需的下采样率,使用不同的卷积核和跨度进行下采样。例如,我们使用步长为 2 的 2×2 卷积来实现 2 倍降采样,使用步长为 4 的 4×4 卷积来实现 4 倍降采样,使用步长为 8 的 8×8 卷积来实现 8 倍降采样。

特征融合后,我们继续使用四个残差块学习特征,这与 ResNet [36] 类似。每个残差块由两个 3 × 3 卷积组成。由于 YOLO 只使用三级特征,因此不存在 8 次上采样和 8 次下采样。

3.2 . Adaptive spatial fusion

在多层次特征融合过程中,我们利用 ASFF [32],为不同层次的特征分配不同的空间权重,从而增强关键层次的重要性,并减轻来自不同对象的矛盾信息的影响。如图 3 所示,我们对三个层次的特征进行融合。

在这里插入图片描述

4、实验

MS COCO

如表 I 所示,当输入图像尺寸为 640×640 时,我们的方法取得了很好的性能,AP 为 39.0%,甚至超过了一些更大分辨率的模型。

在这里插入图片描述

PASVAL VOC

在这里插入图片描述

Two-stage Detectors

在这里插入图片描述

One-stage Detectors

AFPN 在 YOLOv5 上取得了更好的性能,同时使用了更少的参数。

在这里插入图片描述

Fusion Operation

为了研究自适应空间融合操作在我们的 AFPN 中的功效,我们在消融研究中用另外两种融合操作(即元素相加和元素相联)取代了自适应空间融合操作。我们的实验采用了以 ResNet50 为骨干的 Faster R-CNN 框架。

在这里插入图片描述

Number of Blocks

为了确定最佳块数,对不同数量的块进行了实验并记录了相应的性能指标,如表 X 所示。实验结果表明,在 AFPN 中,当块数从 1 增加到 4 时,AP 明显增加了 1.2%。然而,当区块数增加到 5 和 6 时,模型的准确度开始下降。同样,在 LightAFPN 中,当块的数量从 1 增加到 2 时,精度有所提高,但当块的数量增加到 3 时,精度略有下降,当块的数量增加到 4 时,与最佳的 2 块数量相比,精度下降了 0.3%。

因此得出结论:虽然增加块数可以提高模型的准确性,但过多的块数会导致准确性下降。基于这些结论,为 AFPN 选择了 4 个残差块,为 LightAFPN 选择了 2 个轻量级块,从而实现了最佳性能。

5、结论

在本文中,我们提出了渐近特征金字塔网络(AFPN)来解决非相邻层级之间的间接交互导致的信息丢失和退化问题。我们的 AFPN 使用渐近方式进行特征融合和自适应空间融合操作,以在融合过程中提取更多有用信息。

对于轻量级 AFPN,我们进一步提出了受重新参数化启发的轻量级渐近特征金字塔网络(LightAFPN)。与 AFPN 相比,它具有更少的参数、更少的计算和更快的推理速度。

大量实验结果表明,与各种检测和分割框架中的基线方法相比,我们的方法具有更优异的性能。未来,我们将探索我们的方法在其他视觉任务中的适用性。

6、即插即用代码

from collections import OrderedDictimport torch
import torch.nn as nn
import torch.nn.functional as F# 论文:https://arxiv.org/pdf/2306.15988
# 题目:Asymptotic Feature Pyramid Network for Labeling Pixels and Regions(2024-1区)
# 中文:用于标记像素和区域的渐近特征金字塔网络(2024-1区)def BasicConv(filter_in, filter_out, kernel_size, stride=1, pad=None):# 如果没有指定填充(pad),则根据卷积核的大小计算默认的填充if not pad:# 当卷积核大小为奇数时,计算两边对称的填充值pad = (kernel_size - 1) // 2 if kernel_size else 0else:# 如果指定了填充,则使用指定的填充值pad = pad# 使用nn.Sequential创建一个有序字典形式的序列模型return nn.Sequential(OrderedDict([# 卷积层("conv", nn.Conv2d(in_channels=filter_in, out_channels=filter_out,kernel_size=kernel_size, stride=stride, padding=pad, bias=False)),# 批量归一化层("bn", nn.BatchNorm2d(num_features=filter_out)),# ReLU激活函数("relu", nn.ReLU(inplace=True)),]))class BasicBlock(nn.Module):def __init__(self, filter_in, filter_out):# 初始化父类 nn.Modulesuper(BasicBlock, self).__init__()# 定义第一个卷积层self.conv1 = nn.Conv2d(in_channels=filter_in, out_channels=filter_out, kernel_size=3, padding=1)# 定义第一个批量归一化层self.bn1 = nn.BatchNorm2d(num_features=filter_out, momentum=0.1)# 定义 ReLU 激活函数self.relu = nn.ReLU(inplace=True)# 定义第二个卷积层self.conv2 = nn.Conv2d(in_channels=filter_out, out_channels=filter_out, kernel_size=3, padding=1)# 定义第二个批量归一化层self.bn2 = nn.BatchNorm2d(num_features=filter_out, momentum=0.1)def forward(self, x):# 保存输入作为残差连接residual = x# 第一层卷积 + 批量归一化 + ReLU 激活out = self.conv1(x)out = self.bn1(out)out = self.relu(out)# 第二层卷积 + 批量归一化out = self.conv2(out)out = self.bn2(out)# 残差连接out += residual# 最后一次 ReLU 激活out = self.relu(out)# 返回最终输出return outclass Upsample(nn.Module):def __init__(self, in_channels, out_channels, scale_factor=2):super(Upsample, self).__init__()# 定义上采样层,先进行1x1卷积调整通道数,再进行双线性插值上采样self.upsample = nn.Sequential(BasicConv(in_channels, out_channels, 1),  # 1x1卷积nn.Upsample(scale_factor=scale_factor, mode='bilinear')  # 上采样)def forward(self, x):# 通过上采样层x = self.upsample(x)return xclass Downsample_x2(nn.Module):def __init__(self, in_channels, out_channels):super(Downsample_x2, self).__init__()# 定义下采样层,使用步长为2的卷积实现2倍下采样self.downsample = nn.Sequential(BasicConv(in_channels, out_channels, 2, 2, 0)  # 2x2卷积,步长2)def forward(self, x):# 通过下采样层x = self.downsample(x)return xclass Downsample_x4(nn.Module):def __init__(self, in_channels, out_channels):super(Downsample_x4, self).__init__()# 定义下采样层,使用步长为4的卷积实现4倍下采样self.downsample = nn.Sequential(BasicConv(in_channels, out_channels, 4, 4, 0)  # 4x4卷积,步长4)def forward(self, x):# 通过下采样层x = self.downsample(x)return xclass Downsample_x8(nn.Module):def __init__(self, in_channels, out_channels):super(Downsample_x8, self).__init__()# 定义下采样层,使用步长为8的卷积实现8倍下采样self.downsample = nn.Sequential(BasicConv(in_channels, out_channels, 8, 8, 0)  # 8x8卷积,步长8)def forward(self, x):# 通过下采样层x = self.downsample(x)return xclass ASFF_2(nn.Module):def __init__(self, inter_dim=512):super(ASFF_2, self).__init__()self.inter_dim = inter_dimcompress_c = 8# 定义两个压缩卷积层self.weight_level_1 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_2 = BasicConv(self.inter_dim, compress_c, 1, 1)# 定义权重融合层self.weight_levels = nn.Conv2d(compress_c * 2, 2, kernel_size=1, stride=1, padding=0)# 定义融合后的卷积层self.conv = BasicConv(self.inter_dim, self.inter_dim, 3, 1)def forward(self, input1, input2):# 对两个输入特征图进行压缩level_1_weight_v = self.weight_level_1(input1)level_2_weight_v = self.weight_level_2(input2)# 将压缩后的特征图拼接levels_weight_v = torch.cat((level_1_weight_v, level_2_weight_v), 1)# 计算每个级别的权重levels_weight = self.weight_levels(levels_weight_v)levels_weight = F.softmax(levels_weight, dim=1)# 根据权重融合特征图fused_out_reduced = input1 * levels_weight[:, 0:1, :, :] + \input2 * levels_weight[:, 1:2, :, :]# 通过卷积层进一步处理融合后的特征图out = self.conv(fused_out_reduced)return outclass ASFF_3(nn.Module):def __init__(self, inter_dim=512):super(ASFF_3, self).__init__()self.inter_dim = inter_dimcompress_c = 8# 定义三个压缩卷积层self.weight_level_1 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_2 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_3 = BasicConv(self.inter_dim, compress_c, 1, 1)# 定义权重融合层self.weight_levels = nn.Conv2d(compress_c * 3, 3, kernel_size=1, stride=1, padding=0)# 定义融合后的卷积层self.conv = BasicConv(self.inter_dim, self.inter_dim, 3, 1)def forward(self, input1, input2, input3):# 对三个输入特征图进行压缩level_1_weight_v = self.weight_level_1(input1)level_2_weight_v = self.weight_level_2(input2)level_3_weight_v = self.weight_level_3(input3)# 将压缩后的特征图拼接levels_weight_v = torch.cat((level_1_weight_v, level_2_weight_v, level_3_weight_v), 1)# 计算每个级别的权重levels_weight = self.weight_levels(levels_weight_v)levels_weight = F.softmax(levels_weight, dim=1)# 根据权重融合特征图fused_out_reduced = input1 * levels_weight[:, 0:1, :, :] + \input2 * levels_weight[:, 1:2, :, :] + \input3 * levels_weight[:, 2:, :, :]# 通过卷积层进一步处理融合后的特征图out = self.conv(fused_out_reduced)return outclass ASFF_4(nn.Module):def __init__(self, inter_dim=512):super(ASFF_4, self).__init__()self.inter_dim = inter_dimcompress_c = 8# 定义四个压缩卷积层self.weight_level_0 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_1 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_2 = BasicConv(self.inter_dim, compress_c, 1, 1)self.weight_level_3 = BasicConv(self.inter_dim, compress_c, 1, 1)# 定义权重融合层self.weight_levels = nn.Conv2d(compress_c * 4, 4, kernel_size=1, stride=1, padding=0)# 定义融合后的卷积层self.conv = BasicConv(self.inter_dim, self.inter_dim, 3, 1)def forward(self, input0, input1, input2, input3):# 对四个输入特征图进行压缩level_0_weight_v = self.weight_level_0(input0)level_1_weight_v = self.weight_level_1(input1)level_2_weight_v = self.weight_level_2(input2)level_3_weight_v = self.weight_level_3(input3)# 将压缩后的特征图拼接levels_weight_v = torch.cat((level_0_weight_v, level_1_weight_v, level_2_weight_v, level_3_weight_v), 1)# 计算每个级别的权重levels_weight = self.weight_levels(levels_weight_v)levels_weight = F.softmax(levels_weight, dim=1)# 根据权重融合特征图fused_out_reduced = input0 * levels_weight[:, 0:1, :, :] + \input1 * levels_weight[:, 1:2, :, :] + \input2 * levels_weight[:, 2:3, :, :] + \input3 * levels_weight[:, 3:, :, :]# 通过卷积层进一步处理融合后的特征图out = self.conv(fused_out_reduced)return outimport torch.nn as nnclass BlockBody(nn.Module):def __init__(self, channels=[64, 128, 256, 512]):# 初始化父类 nn.Modulesuper(BlockBody, self).__init__()# 定义四个1x1卷积层,用于通道调整self.blocks_scalezero1 = nn.Sequential(BasicConv(channels[0], channels[0], 1),)self.blocks_scaleone1 = nn.Sequential(BasicConv(channels[1], channels[1], 1),)self.blocks_scaletwo1 = nn.Sequential(BasicConv(channels[2], channels[2], 1),)self.blocks_scalethree1 = nn.Sequential(BasicConv(channels[3], channels[3], 1),)# 定义2倍下采样和2倍上采样操作self.downsample_scalezero1_2 = Downsample_x2(channels[0], channels[1])self.upsample_scaleone1_2 = Upsample(channels[1], channels[0], scale_factor=2)# 定义两个特征融合模块 ASFF_2self.asff_scalezero1 = ASFF_2(inter_dim=channels[0])self.asff_scaleone1 = ASFF_2(inter_dim=channels[1])# 定义两个残差块序列self.blocks_scalezero2 = nn.Sequential(BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),)self.blocks_scaleone2 = nn.Sequential(BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),)# 定义多个上采样和下采样操作self.downsample_scalezero2_2 = Downsample_x2(channels[0], channels[1])self.downsample_scalezero2_4 = Downsample_x4(channels[0], channels[2])self.downsample_scaleone2_2 = Downsample_x2(channels[1], channels[2])self.upsample_scaleone2_2 = Upsample(channels[1], channels[0], scale_factor=2)self.upsample_scaletwo2_2 = Upsample(channels[2], channels[1], scale_factor=2)self.upsample_scaletwo2_4 = Upsample(channels[2], channels[0], scale_factor=4)# 定义三个特征融合模块 ASFF_3self.asff_scalezero2 = ASFF_3(inter_dim=channels[0])self.asff_scaleone2 = ASFF_3(inter_dim=channels[1])self.asff_scaletwo2 = ASFF_3(inter_dim=channels[2])# 定义三个残差块序列self.blocks_scalezero3 = nn.Sequential(BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),)self.blocks_scaleone3 = nn.Sequential(BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),)self.blocks_scaletwo3 = nn.Sequential(BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),)# 定义多个上采样和下采样操作self.downsample_scalezero3_2 = Downsample_x2(channels[0], channels[1])self.downsample_scalezero3_4 = Downsample_x4(channels[0], channels[2])self.downsample_scalezero3_8 = Downsample_x8(channels[0], channels[3])self.upsample_scaleone3_2 = Upsample(channels[1], channels[0], scale_factor=2)self.downsample_scaleone3_2 = Downsample_x2(channels[1], channels[2])self.downsample_scaleone3_4 = Downsample_x4(channels[1], channels[3])self.upsample_scaletwo3_4 = Upsample(channels[2], channels[0], scale_factor=4)self.upsample_scaletwo3_2 = Upsample(channels[2], channels[1], scale_factor=2)self.downsample_scaletwo3_2 = Downsample_x2(channels[2], channels[3])self.upsample_scalethree3_8 = Upsample(channels[3], channels[0], scale_factor=8)self.upsample_scalethree3_4 = Upsample(channels[3], channels[1], scale_factor=4)self.upsample_scalethree3_2 = Upsample(channels[3], channels[2], scale_factor=2)# 定义四个特征融合模块 ASFF_4self.asff_scalezero3 = ASFF_4(inter_dim=channels[0])self.asff_scaleone3 = ASFF_4(inter_dim=channels[1])self.asff_scaletwo3 = ASFF_4(inter_dim=channels[2])self.asff_scalethree3 = ASFF_4(inter_dim=channels[3])# 定义四个残差块序列self.blocks_scalezero4 = nn.Sequential(BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),BasicBlock(channels[0], channels[0]),)self.blocks_scaleone4 = nn.Sequential(BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),BasicBlock(channels[1], channels[1]),)self.blocks_scaletwo4 = nn.Sequential(BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),BasicBlock(channels[2], channels[2]),)self.blocks_scalethree4 = nn.Sequential(BasicBlock(channels[3], channels[3]),BasicBlock(channels[3], channels[3]),BasicBlock(channels[3], channels[3]),BasicBlock(channels[3], channels[3]),)def forward(self, x):# 解包输入特征图x0, x1, x2, x3 = x# 通过1x1卷积层调整通道x0 = self.blocks_scalezero1(x0)x1 = self.blocks_scaleone1(x1)x2 = self.blocks_scaletwo1(x2)x3 = self.blocks_scalethree1(x3)# 特征融合:ASFF_2scalezero = self.asff_scalezero1(x0, self.upsample_scaleone1_2(x1))scaleone = self.asff_scaleone1(self.downsample_scalezero1_2(x0), x1)# 通过残差块序列x0 = self.blocks_scalezero2(scalezero)x1 = self.blocks_scaleone2(scaleone)# 特征融合:ASFF_3scalezero = self.asff_scalezero2(x0, self.upsample_scaleone2_2(x1), self.upsample_scaletwo2_4(x2))scaleone = self.asff_scaleone2(self.downsample_scalezero2_2(x0), x1, self.upsample_scaletwo2_2(x2))scaletwo = self.asff_scaletwo2(self.downsample_scalezero2_4(x0), self.downsample_scaleone2_2(x1), x2)# 通过残差块序列x0 = self.blocks_scalezero3(scalezero)x1 = self.blocks_scaleone3(scaleone)x2 = self.blocks_scaletwo3(scaletwo)# 特征融合:ASFF_4scalezero = self.asff_scalezero3(x0, self.upsample_scaleone3_2(x1), self.upsample_scaletwo3_4(x2), self.upsample_scalethree3_8(x3))scaleone = self.asff_scaleone3(self.downsample_scalezero3_2(x0), x1, self.upsample_scaletwo3_2(x2), self.upsample_scalethree3_4(x3))scaletwo = self.asff_scaletwo3(self.downsample_scalezero3_4(x0), self.downsample_scaleone3_2(x1), x2, self.upsample_scalethree3_2(x3))scalethree = self.asff_scalethree3(self.downsample_scalezero3_8(x0), self.downsample_scaleone3_4(x1), self.downsample_scaletwo3_2(x2), x3)# 通过残差块序列scalezero = self.blocks_scalezero4(scalezero)scaleone = self.blocks_scaleone4(scaleone)scaletwo = self.blocks_scaletwo4(scaletwo)scalethree = self.blocks_scalethree4(scalethree)# 返回最终融合后的特征图return scalezero, scaleone, scaletwo, scalethreeclass AFPN(nn.Module):def __init__(self,in_channels=[256, 512, 1024, 2048],  # 输入特征图的通道数列表out_channels=256):  # 输出特征图的通道数super(AFPN, self).__init__()# 设置是否使用半精度浮点数 fp16self.fp16_enabled = False# 定义1x1卷积层,用于调整输入特征图的通道数self.conv0 = BasicConv(in_channels[0], in_channels[0] // 8, 1)self.conv1 = BasicConv(in_channels[1], in_channels[1] // 8, 1)self.conv2 = BasicConv(in_channels[2], in_channels[2] // 8, 1)self.conv3 = BasicConv(in_channels[3], in_channels[3] // 8, 1)# 定义 BlockBody 模块,用于多尺度特征融合self.body = nn.Sequential(BlockBody([in_channels[0] // 8, in_channels[1] // 8, in_channels[2] // 8, in_channels[3] // 8]))# 定义1x1卷积层,用于调整输出特征图的通道数到统一的 `out_channels`# in_channels[0] // 8 的目的是为了减少输入特征图的通道数,从而达到降低计算复杂度、减少模型参数以及优化特征表示的目的。self.conv00 = BasicConv(in_channels[0] // 8, out_channels, 1)self.conv11 = BasicConv(in_channels[1] // 8, out_channels, 1)self.conv22 = BasicConv(in_channels[2] // 8, out_channels, 1)self.conv33 = BasicConv(in_channels[3] // 8, out_channels, 1)self.conv44 = nn.MaxPool2d(kernel_size=1, stride=2)  # 用于生成额外的下采样特征图# 初始化权重for m in self.modules():if isinstance(m, nn.Conv2d):  # 如果是卷积层nn.init.xavier_normal_(m.weight, gain=0.02)  # 使用 Xavier 正态分布初始化权重elif isinstance(m, nn.BatchNorm2d):  # 如果是批量归一化层torch.nn.init.normal_(m.weight.data, 1.0, 0.02)  # 初始化权重为正态分布torch.nn.init.constant_(m.bias.data, 0.0)  # 初始化偏置为常数0def forward(self, x):# 解包输入特征图x0, x1, x2, x3 = x# 通过1x1卷积层调整输入特征图的通道数x0 = self.conv0(x0)x1 = self.conv1(x1)x2 = self.conv2(x2)x3 = self.conv3(x3)# 通过 BlockBody 模块进行多尺度特征融合out0, out1, out2, out3 = self.body([x0, x1, x2, x3])# 通过1x1卷积层调整输出特征图的通道数out0 = self.conv00(out0)out1 = self.conv11(out1)out2 = self.conv22(out2)out3 = self.conv33(out3)# 生成额外的下采样特征图out4 = self.conv44(out3)# 返回最终的融合后的特征图return out0, out1, out2, out3, out4if __name__ == "__main__":# 创建实例,输入通道数为 32block = AFPN()# 创建随机输入张量 1,形状为 [batch_size, channels, height, width]input1 = torch.rand(16, 256, 200, 200)# 创建随机输入张量 2,形状与输入张量 1 相同input2 = torch.rand(16, 512, 100, 100)# 创建随机输入张量 3,形状为 [batch_size, channels, height, width]input3 = torch.rand(16, 1024, 50, 50)# 创建随机输入张量 4,形状与输入张量 1 相同input4 = torch.rand(16, 2048, 25, 25)# 应用 Model 实例处理输入张量x = (input1, input2,input3, input4)output = block(x)output1, output2, output3, output4,output5 = output# 打印输出张量的形状print(output1.size())print(output2.size())print(output3.size())print(output4.size())print(output5.size())print("抖音、B站、小红书、CSDN同号")print("布尔大学士 提醒您:代码无误~~~~")

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【SpringMVC】详细介绍SpringMVC的执行流程
  • 基于JSP、java、Tomcat三者的项目实战--校园交易平台系统--(实习,答辩皆可用到)--万字爆更
  • Python酷库之旅-第三方库Pandas(075)
  • rabbitmq出现Management API returned status code 500 -
  • 用爬虫玩转石墨文档(下)
  • LeetCode_sql_day15(262.行程与用户)
  • Node.js 常用命令集合
  • Linux的Chrome、Firefox浏览器无法加载简书的图片
  • 算法第一天
  • 【Linux】解锁进程地址空间奥秘,高效环境变量的实战技巧
  • Elasticsearch 文档操作:增加、删除与查询
  • 白骑士的Matlab教学高级篇 3.4 App设计
  • 成都教育新地标,跃享未来小店,抖音见证信任力
  • Vue3 搭建前端工程,并使用idea配置项目启动
  • Axios取消请求,以及全局取消请求封装
  • [LeetCode] Wiggle Sort
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 230. Kth Smallest Element in a BST
  • Angular 4.x 动态创建组件
  • CentOS6 编译安装 redis-3.2.3
  • CentOS7 安装JDK
  • ECS应用管理最佳实践
  • JAVA 学习IO流
  • JavaScript类型识别
  • nginx 负载服务器优化
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 从零开始的无人驾驶 1
  • 聊一聊前端的监控
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 一文看透浏览器架构
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​2020 年大前端技术趋势解读
  • #1015 : KMP算法
  • #Lua:Lua调用C++生成的DLL库
  • #pragma pack(1)
  • $(function(){})与(function($){....})(jQuery)的区别
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (SpringBoot)第七章:SpringBoot日志文件
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (二开)Flink 修改源码拓展 SQL 语法
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (三)uboot源码分析
  • (十三)Flask之特殊装饰器详解
  • (四)进入MySQL 【事务】
  • (一)WLAN定义和基本架构转
  • (转)Oracle存储过程编写经验和优化措施
  • .Family_物联网
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET IoC 容器(三)Autofac
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性