0

0

FPN综述保姆级教程

P粉084495128

P粉084495128

发布时间:2025-07-24 11:33:12

|

1223人浏览过

|

来源于php中文网

原创

本文是fpn综述教程,先介绍fpn开山之作,含简介、相关工作、结构及基于resnet18的代码实现。还讲解了pafpn,其在fpn基础上增加自底向上路径,给出结构与代码。最后阐述bifpn,包括简介、结构及多特征图示例的代码实现。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

fpn综述保姆级教程 - php中文网

FPN综述教程(保姆级)

0 前言

  • 鸽了好久的项目,看平台对FPN介绍不多,我来捡个漏。
  • 带大家逐行coding

FPN综述保姆级教程 - php中文网

1 FPN开山

1.1 简介

论文链接Feature Pyramid Networks for Object Detection

  • 特征金字塔是识别系统中用于检测不同尺度目标的基本组件。但是最近的深度学习目标检测器已经开始因为内存与计算密集开始避免使用特征金字塔结构了。在本文中,作者通过利用深度卷积网络内在的多尺度、金字塔分级来构造具有少量额外成本的特征金字塔。开发了一种具有横向连接的自顶向下架构,用于在所有尺度上构建高级语义特征映射。这种称为特征金字塔网络(FPN)的架构在几个应用程序中作为通用特征提取器表现出了显著的改进,是多尺度目标检测的实用和准确的解决方案。

1.2 相关工作

FPN综述保姆级教程 - php中文网

  • 图a是一个特征图像金字塔结构,在传统的图像处理中经常用到,在检测不同尺度的目标时,将给定的图片首先缩放到不同的尺度,图中为4个不同的尺度,对于每个不同尺度的图片,分别使用算法进行预测。这样做的问题就是,如果生成多少个尺度我们就需要重新使用多少次预测算法这样做的效率非常低。
  • 图b就很像fast R-CNN中使用的方式,首先使用一个backbone提取特征图,然后在最终的特征图上进行预测,在这种情况下,对于小目标的检测任务通常就会表现比较差。
  • 图c和SSD(single shot multibox detector)算法很类似,在backbone不同阶段生成的特征图上,分别进行预测。
  • 图d就是FPN结构,和图c不同的是,它不是简单地在每个特征图上进行预测,而是将不同的特征图进行特征融合,然后用融合后的特征图来进行预测,根据这篇文章中的实验可以得出这样做确实有提高网络能力的效果。

1.3 FPN block(这里简短介绍一下理论,下面介绍代码)

FPN综述保姆级教程 - php中文网

  • step1:首先对每一个特征层得到的特征图进行一个1x1卷积操作,为了让每个特征图在进行融合的使用保持通道(channel)数一致。
  • step2:将高层次的特征图进行一次2倍上采样,让相邻的两个特征图可以进行融和(上采样方式采用邻近插值算法)
  • step3,将融和后的特征图通过3x3卷积进一步融合(这一步上图是没有体现的)
  • 为了防止大家迷糊,我这里对上图从新绘制个细节图如下(这里我采用的是resnet18作为特征提取网络)

FPN综述保姆级教程 - php中文网

1.4 代码

  • 这里将带大家逐行code(主讲FPN,resnet一笔带过)
In [1]
# 导入相关的包import paddleimport paddle.nn.functional as Fimport paddle.nn as nn
  • 下图为resnet的主要模块

FPN综述保姆级教程 - php中文网

Laraval 9 保姆级教程——相关课件
Laraval 9 保姆级教程——相关课件

Laraval 9 保姆级教程——相关课件

下载
In [2]
# 构建resnet18的基础模块# Identity模块表示没有任何操作class Identity(nn.Layer):
    def __init_(self):
        super().__init__()    def forward(self, x):
        return x# Block模块是构成resnet的主要模块# 通过判断步长(stride == 2)和通道数(in_dim != out_dim)# 判断indentity = self.downsample(h)中,self.downsample()下采样方式class Block(nn.Layer):
    def __init__(self, in_dim, out_dim, stride):
        super().__init__()        ## 补充代码
        self.conv1 = nn.Conv2D(in_dim, out_dim, 3, stride=stride, padding=1, bias_attr=False)
        self.bn1 = nn.BatchNorm2D(out_dim)
        self.conv2 = nn.Conv2D(out_dim, out_dim, 3, stride=1, padding=1, bias_attr=False)
        self.bn2 = nn.BatchNorm2D(out_dim)
        self.relu = nn.ReLU()        if stride == 2 or in_dim != out_dim:
            self.downsample = nn.Sequential(*[
                nn.Conv2D(in_dim,out_dim,1,stride=stride),
                nn.BatchNorm2D(out_dim)])        else:
            self.downsample = Identity()    def forward(self, x):
        ## 补充代码
        h = x
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x)
        indentity = self.downsample(h)
        x = x + indentity
        x = self.relu(x)        return x
In [3]
# 搭建resnet18主干网络class ResNet18(nn.Layer):
    def __init__(self, in_dim=64):
        super().__init__()
        self.in_dim = in_dim        # stem layer
        self.conv1 = nn.Conv2D(in_channels=3,out_channels=in_dim,kernel_size=3,stride=1,padding=1,bias_attr=False)
        self.bn1 = nn.BatchNorm2D(in_dim)
        self.relu = nn.ReLU()        
        #blocks
        self.layers1 = self._make_layer(dim=64,n_blocks=2,stride=1)
        self.layers2 = self._make_layer(dim=128,n_blocks=2,stride=2)
        self.layers3 = self._make_layer(dim=256,n_blocks=2,stride=2)
        self.layers4 = self._make_layer(dim=512,n_blocks=2,stride=2)    def _make_layer(self, dim, n_blocks, stride):
        layer_list = []
        layer_list.append(Block(self.in_dim, dim, stride=stride))
        self.in_dim = dim        for i in range(1,n_blocks):
            layer_list.append(Block(self.in_dim, dim, stride=1))        return nn.Sequential(*layer_list)    def forward(self, x):
        # 创建一个存放不同尺度特征图的列表
        fpn_list = []

        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.layers1(x)        # x [2, 64, 64, 64]
        fpn_list.append(x)

        x = self.layers2(x)        # x [2, 128, 32, 32]
        fpn_list.append(x)

        x = self.layers3(x)        # x [2, 256, 16, 16]
        fpn_list.append(x)

        x = self.layers4(x)        # x [2, 512, 8, 8]
        fpn_list.append(x)        return fpn_list
In [4]
# FPN构建# fpn_list中包含以下特征维度,对应章节1.3中的图# C2 [2, 64, 64, 64]# C3 [2, 128, 32, 32]# C4 [2, 256, 16, 16]# C5 [2, 512, 8, 8]class FPN(nn.Layer):
    def __init__(self,in_channel_list,out_channel):
        super(FPN, self).__init__()
        self.inner_layer=[]  # 1x1卷积,统一通道数
        self.out_layer=[]  # 3x3卷积,对add后的特征图进一步融合
        for in_channel in in_channel_list:  
            self.inner_layer.append(nn.Conv2D(in_channel,out_channel,1))
            self.out_layer.append(nn.Conv2D(out_channel,out_channel,kernel_size=3,padding=1))    def forward(self,x):
        head_output=[]  # 存放最终输出特征图
        corent_inner=self.inner_layer[-1](x[-1])  # 过1x1卷积,对C5统一通道数操作
        head_output.append(self.out_layer[-1](corent_inner)) # 过3x3卷积,对统一通道后过的特征进一步融合,加入head_output列表
        print(self.out_layer[-1](corent_inner).shape)        
        for i in range(len(x)-2,-1,-1):  # 通过for循环,对C4,C3,C2进行
            pre_inner=corent_inner
            corent_inner=self.inner_layer[i](x[i])  # 1x1卷积,统一通道数操作
            size=corent_inner.shape[2:]  # 获取上采样的大小(size)
            pre_top_down=F.interpolate(pre_inner,size=size)  # 上采样操作(这里大家去看一下interpolate这个上采样api)
            add_pre2corent=pre_top_down+corent_inner  # add操作
            head_output.append(self.out_layer[i](add_pre2corent))  # 3x3卷积,特征进一步融合操作,并加入head_output列表
            print(self.out_layer[i](add_pre2corent).shape)        
        return head_output# head_output 中包含以下特征维度,对应章节1.3中的图# P5 [2, 256, 8, 8]# P4 [2, 256, 16, 16]# P3 [2, 256, 32, 32]# P2 [2, 256, 64, 64]
In [ ]
model = ResNet18()# print(model)# [64,128,256,512]表示输入特征通道数的列表(C2-C5的通道数列表),256表示过FPN后最终通道数(P2-P5的通道数)fpn=FPN([64,128,256,512],256)
x = paddle.randn([2, 3, 64, 64])
fpn_list = model(x)
out = fpn(fpn_list)# print(list(reversed(out)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:653: UserWarning: When training, we now always track global mean and variance.
  "When training, we now always track global mean and variance.")
[2, 256, 8, 8]
[2, 256, 16, 16]
[2, 256, 32, 32]
[2, 256, 64, 64]

2 PAFPN

2.1 简介

  • 论文链接Path Aggregation Network for Instance Segmentation
  • PANet在FPN的自上向下的路径之后又添加了一个自底向上的路径,通过这个路径PANet得到 (N1-N4) 共4个Feature Map。PANet的融合模块如下图所示

FPN综述保姆级教程 - php中文网

  • 这里有个小改动,在特征图合并时,使用张量连接(concat)代替了原论文中的捷径连接(shortcut connection),yolov4也是这么干的,如下图所示,

FPN综述保姆级教程 - php中文网

  • PAFPN全貌如下图所示

FPN综述保姆级教程 - php中文网

  • 因为采用张量连接(concat)操作,产生特征图的通道数是捷径连接(shortcut connection)产生的2倍(如本节图2所示),所以上图(本节图3)中采用1x1卷积用于统一通道数,后采用3x3卷积进一步融合。
In [ ]
# 构建一个用于下采样的卷积池化模块class ConvNormLayer(nn.Layer):
    def __init__(self, in_channel, out_channel, kernel_size, stride, padding=1):
        super(ConvNormLayer, self).__init__()
        self.conv = nn.Conv2D(in_channel, out_channel, kernel_size, stride, padding)
        self.norm = nn.BatchNorm2D(out_channel)    def forward(self, inputs):
        out = self.conv(inputs)
        out = self.norm(out)        return out
In [ ]
# PAFPN构建# fpn_list中包含以下特征维度,对应章节2.1中的图# C2 [2, 64, 64, 64]# C3 [2, 128, 32, 32]# C4 [2, 256, 16, 16]# C5 [2, 512, 8, 8]class PAFPN(nn.Layer):
    def __init__(self,in_channel_list,out_channel):
        super(PAFPN, self).__init__()
        self.fpn = FPN(in_channel_list, out_channel)
        self.bottom_up = ConvNormLayer(out_channel, out_channel, 3, 2)  # 2倍下采样模块
        self.inner_layer=[]  # 1x1卷积,统一通道数,处理P3-P5的输出,这里要注意P2和P3-P5的输入通道是不同的,可以看2.1图3,
        self.out_layer=[]  # 3x3卷积,对concat后的特征图进一步融合
        for i in range(len(in_channel_list)):            if i==0:  
                self.inner_layer.append(nn.Conv2D(out_channel, out_channel,1))  # 处理P2
            else:
                self.inner_layer.append(nn.Conv2D(out_channel*2, out_channel,1))  # 处理P3-P5
            self.out_layer.append(nn.Conv2D(out_channel,out_channel,kernel_size=3,padding=1))    def forward(self,x):
        head_output=[]  # 存放最终输出特征图
        fpn_out = self.fpn(x)  # FPN操作
        print('------------FPN--PAFPN--------------')  # PAFPN操作分割线
        corent_inner=self.inner_layer[0](fpn_out[-1])  # 过1x1卷积,对P2统一通道数操作
        head_output.append(self.out_layer[0](corent_inner))  # 过3x3卷积,对统一通道后过的特征进一步融合,加入head_output列表
        print(self.out_layer[0](corent_inner).shape)        for i in range(1,len(fpn_out),1):
            pre_bottom_up = corent_inner
            pre_concat = self.bottom_up(pre_bottom_up)  # 下采样
            pre_inner = paddle.concat([fpn_out[-1-i],pre_concat], 1)  # concat
            corent_inner=self.inner_layer[i](pre_inner)  # 1x1卷积压缩通道
            head_output.append(self.out_layer[i](corent_inner))  # 3x3卷积进一步融合
            print(self.out_layer[i](corent_inner).shape)        
        return head_output# head_output 中包含以下特征维度,对应章节1.3中的图# N2 [2, 256, 64, 64]# N3 [2, 256, 32, 32]# N4 [2, 256, 16, 16]# N5 [2, 256, 8, 8]
In [ ]
model = ResNet18()# print(model)# [64,128,256,512]表示输入特征通道数的列表(C2-C5的通道数列表),256表示过FPN后最终通道数(P2-P5的通道数)pafpn=PAFPN([64,128,256,512],256)
x = paddle.randn([2, 3, 64, 64])
fpn_list = model(x)
out = pafpn(fpn_list)
[2, 256, 8, 8]
[2, 256, 16, 16]
[2, 256, 32, 32]
[2, 256, 64, 64]
------------FPN--PAFPN--------------
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]

3 BiFPN

3.1 简介

  • 论文链接EfficientDet: Scalable and Efficient Object Detection
  • BiFPN ,在 PANet 简化版的基础上,若输入和输出结点是同一 level 的,则添加一条额外的边,在不增加 cost 的同时融合更多的特征。(注意, PANet 只有一条 top-down path 和一条 bottom-up path ,而本文作者是将 BiFPN 当作一个 feature network layer 来用的,重复多次。如下图所示

FPN综述保姆级教程 - php中文网

3.1 BiFPN block

  • 下图为 BiFPN block

FPN综述保姆级教程 - php中文网

  • 论文中从EfficientNet中取了P3~P7的5个scale的feature map作为BiFPN的输入,但是EfficientNet只有1/8~1/32的三个scale。官方通过Downsample来得到1/64和1/128的feature map。同时官方中用的max_pooling做的降采样。这里为尽量跟官方类似,将resnet获取的4个(C2-C5),其中的C5进行降采样,最终获得5个对应上图的(P3-P7)
  • 在第一层BiFPN中P5和P4节点的两个输出为不同tensor(图中根本看不出来~)。在官方代码中,上图中的彩色节点的输入都会经过Resample的过程,而Resample会在输入channel数与输出channel数不等时添加1x1conv,所以就导致了第一层BiFPN中P5和P4节点的两个输出为不同tensor。
  • 上图的彩色节点由separable conv BN与activation组成,每个彩色节点由Sepconv_BN_Swish组成。

3.2 代码实现步骤图

FPN综述保姆级教程 - php中文网

  • 图中各个模块说明:(这里没有对原论文加入注意力机制进行实现,只是实现了模型结构,并略微改进了构建方式)
  • C(2-5)到P(3-7)下采样块 C_to_P:将C(2-5)四个特征图变为P(3-7)五个特征图(原论文是将3个变为5个,下采样方法一样),图中的P(3-7)块没有任何操作,只是个标识
  • 1x1和3x3卷积模块Sepconv_BN_Swish:构建3.1节每个彩色节点模块
  • 绿色块BiFPN_block1:这里跟原论文代码构建方式不同,原论文是通过一层层进行搭建,这样限定了输入必须是五个特征图,本项目的搭建方式可以实现n个(3
  • 蓝色块BiFPN_block2:接受BiFPN_block1传出特征图,同样连接方式采用concat方式,下采样采用最大池化方式
  • 橙色块BiFPN_block:表示BiFPN_block1、BiFPN_block2共同组合一个BiFPN_block模块,这里第一个BiFPN_block与第二个BiFPN_block输出特征图通道略有不同,后续BiFPN_block(3、4....)特征通道数均与第二个BiFPN_block相同
  • Identity:Identity模块不作任何处理输入=输出(这里使用是方便简化代码的构建)
In [5]
# 构建每个彩色节点模块,由3x3和1x1卷积构成class Sepconv_BN_Swish(nn.Layer):
    def __init__(self, in_channels, out_channels=None):
        super(Sepconv_BN_Swish, self).__init__()        if out_channels is None:
            out_channels = in_channels
        self.depthwise_conv = nn.Conv2D(in_channels, in_channels, kernel_size=3, stride=1, padding=1)
        self.pointwise_conv = nn.Conv2D(in_channels, out_channels, kernel_size=1, stride=1)
        self.norm = nn.BatchNorm2D(out_channels)
        self.act = nn.Swish()    def forward(self, inputs):
        out = self.depthwise_conv(inputs)
        out = self.pointwise_conv(out)
        out = self.norm(out)
        out = self.act(out)        return out
In [20]
# 由(C2-C5)产生(P3-P7),操作是将C5降采样# C2 [2, 64, 64, 64]# C3 [2, 128, 32, 32]# C4 [2, 256, 16, 16]# C5 [2, 512, 8, 8]class C_to_P(nn.Layer):
    def __init__(self,inputs_size=8):  # inputs_size是C5的size
        super(C_to_P, self).__init__()
        self.max_pool = nn.AdaptiveMaxPool2D(inputs_size//2)    def forward(self, inputs):
        output=[]  # 存放最终输出特征图(P3-P7)
        output = inputs
        out = self.max_pool(inputs[-1])  # 最大池化用于下采样
        output.append(out)        return output# P3 [2, 64, 64, 64]# P4 [2, 128, 32, 32]# P5 [2, 256, 16, 16]# P6 [2, 512, 8, 8]# P7 [2, 512, 4, 4]
In [24]
# BiFPN_block1实现的操作是(5->3)这层的操作class BiFPN_block1(nn.Layer):
    def __init__(self,in_channel_list,out_channel):
        super(BiFPN_block1, self).__init__()
        self.block1_layer=[]  #  用于3个存放彩色节点模块和1个Identity(以5个特征图为例)
        for i in range(len(in_channel_list)-2): 
            if i == 0:
                in_channel =  in_channel_list[-1-i] + in_channel_list[-2-i]            else:
                in_channel = out_channel + in_channel_list[-2-i]
            self.block1_layer.append(Sepconv_BN_Swish(in_channel,out_channel))
        self.block1_layer.append(Identity())    def forward(self,x):
        print('----block1----')
        head_output = []  # 存放最终输出特征图
        channel_list = []  # 存放block1_layer操作后通道变化
        feat_size = []  # 存放特征图尺寸的列表
        head_output.append(x[-1])
        channel_list.append(x[-1].shape[1])
        feat_size.append(x[-1].shape[2])        print(x[-1].shape)        for i in range(len(x)-1):
            size = x[-2-i].shape[2:]            if i == 0:  # 看3.2图,上采样输入在第一次是P7,后三次是过3x3和1x1卷积
                pre_upsampling = x[-1]            else:
                pre_upsampling = N_layer  # N_layer来自第一次循环产生的
            upsampling = F.interpolate(pre_upsampling,size=size)  # 上采样操作
            pre_N = paddle.concat([upsampling,x[-2-i]], 1)  #  concat链接
            N_layer = self.block1_layer[i](pre_N)  #  过3x3和1x1卷积,最后一个是Identity(看本代码块12行)
            if i < len(x)-2:  # P(4,5,6)跨层连接,P7无跨层连接操作
                pre_block2 = paddle.concat([N_layer,x[-2-i]],1)            else:
                pre_block2 = N_layer
            head_output.append(pre_block2)
            channel_list.append(pre_block2.shape[1])
            feat_size.append(pre_block2.shape[2])            print(pre_block2.shape)        
        return channel_list, head_output, max(feat_size)  # max(feat_size)获取所有特征图的最大size,用于block2中的下采样
In [25]
# BiFPN_block2实现的操作是(3->5)这层的操作class BiFPN_block2(nn.Layer):
    def __init__(self,in_channel_list,out_channel, max_size):
        super(BiFPN_block2, self).__init__()
        self.block2_layer=[]  # 用于5个存放彩色节点模块
        for i in range(len(in_channel_list)): 
            if i == 0:
                in_channel = in_channel_list[-1]            else:
                in_channel = in_channel_list[-1-i] + out_channel
            self.block2_layer.append(Sepconv_BN_Swish(in_channel,out_channel))
        downsampling_size = max_size  # P3 size(特征图最大size),用于下采样
        self.max_pool=[]        for i in range(len(in_channel_list)-1):  # 用于4个下采样模块
            self.max_pool.append(nn.AdaptiveMaxPool2D(downsampling_size//2))
            downsampling_size = downsampling_size//2

    def forward(self,x):
        print('----block2----')
        head_output=[]  # 存放最终输出特征图
        corent_block2 = self.block2_layer[0](x[-1])
        head_output.append(corent_block2)        print(corent_block2.shape)        for i in range(len(x)-1):
            downsampling = self.max_pool[i](corent_block2)  # 获取上层下采样结果
            pre_block2 = paddle.concat([downsampling,x[-2-i]],1)  # 将下采样结果和block1的输出concat
            corent_block2 = self.block2_layer[1+i](pre_block2)  # 过3x3和1x1卷积
            head_output.append(corent_block2)            print(corent_block2.shape)        
        return head_output
In [14]
# 将BiFPN_block1和将BiFPN_block2合并class BiFPN_block(nn.Layer):
    def __init__(self,in_channel_list,out_channel):
        super(BiFPN_block, self).__init__()
        self.out_channel = out_channel
        self.bifpn_block1 = BiFPN_block1(in_channel_list, out_channel)    def forward(self,x):
        block1_channel_list, out, max_size = self.bifpn_block1(x)
        bifpn_block2 = BiFPN_block2(block1_channel_list, self.out_channel, max_size)
        out = bifpn_block2(out)        
        return out
In [15]
# 将BiFPN_block构建为num个,这里需要注意第一个BiFPN_block和第二个BiFPN_block输入特征图通道数的区别,# 后续(3、4...)输入特征图通道数均和第二个BiFPN_block相同class BiFPN(nn.Layer):
    def __init__(self,in_channel_list0,out_channel,num):
        super(BiFPN, self).__init__()
        self.bifpn_layer=[]
        in_channel_list1=[]        for i in range(len(in_channel_list0)):
            in_channel_list1.append(out_channel)        for i in range(num):            if i==0:
                in_channel_list = in_channel_list0            else:
                in_channel_list = in_channel_list1
            self.bifpn_layer.append(BiFPN_block(in_channel_list,out_channel))    def forward(self,x):
        out = x        for layer in self.bifpn_layer:            print('--------bifpn_layer--------')
            out = layer(out)        
        return out
In [26]
# 以5个特征图为例model = ResNet18()
x = paddle.randn([2, 3, 64, 64])
fpn_list = model(x)
c_to_p = C_to_P()
out = c_to_p(fpn_list)
in_channel_list = [64,128,256,512,512]
out_channel = 256bifpn_num = 3bifpn = BiFPN(in_channel_list,out_channel,bifpn_num)
out = bifpn(out)
--------bifpn_layer--------
----block1----
[2, 512, 4, 4]
[2, 768, 8, 8]
[2, 512, 16, 16]
[2, 384, 32, 32]
[2, 320, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
--------bifpn_layer--------
----block1----
[2, 256, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
--------bifpn_layer--------
----block1----
[2, 256, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
In [27]
# 以4个特征图为例model = ResNet18()
x = paddle.randn([2, 3, 64, 64])
fpn_list = model(x)
in_channel_list = [64,128,256,512]
out_channel = 256bifpn_num = 5bifpn = BiFPN(in_channel_list,out_channel,bifpn_num)
out = bifpn(fpn_list)
--------bifpn_layer--------
----block1----
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 384, 32, 32]
[2, 320, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
--------bifpn_layer--------
----block1----
[2, 256, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
--------bifpn_layer--------
----block1----
[2, 256, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
--------bifpn_layer--------
----block1----
[2, 256, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
--------bifpn_layer--------
----block1----
[2, 256, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----block2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
In [21]
# 以6个特征图为例model = ResNet18()
x = paddle.randn([2, 3, 64, 64])
fpn_list = model(x)
c_to_p1 = C_to_P(inputs_size=8)
out = c_to_p1(fpn_list)
c_to_p2 = C_to_P(inputs_size=4)
out = c_to_p2(out)
in_channel_list = [64,128,256,512,512,512]
out_channel = 256bifpn_num = 5bifpn = BiFPN(in_channel_list,out_channel,bifpn_num)
out = bifpn(out)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:653: UserWarning: When training, we now always track global mean and variance.
  "When training, we now always track global mean and variance.")
--------bifpn_layer--------
----1----
[2, 512, 2, 2]
[2, 768, 4, 4]
[2, 768, 8, 8]
[2, 512, 16, 16]
[2, 384, 32, 32]
[2, 320, 64, 64]
----2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
[2, 256, 2, 2]
--------bifpn_layer--------
----1----
[2, 256, 2, 2]
[2, 512, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
[2, 256, 2, 2]
--------bifpn_layer--------
----1----
[2, 256, 2, 2]
[2, 512, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
[2, 256, 2, 2]
--------bifpn_layer--------
----1----
[2, 256, 2, 2]
[2, 512, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
[2, 256, 2, 2]
--------bifpn_layer--------
----1----
[2, 256, 2, 2]
[2, 512, 4, 4]
[2, 512, 8, 8]
[2, 512, 16, 16]
[2, 512, 32, 32]
[2, 512, 64, 64]
----2----
[2, 256, 64, 64]
[2, 256, 32, 32]
[2, 256, 16, 16]
[2, 256, 8, 8]
[2, 256, 4, 4]
[2, 256, 2, 2]

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

38

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

83

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

97

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

223

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

458

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

169

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

246

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

34

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 4.9万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号