关于FPN的学习,拖了一周,记录一下,我先是看的论文,然后看的博客:https://blog.csdn.net/WZZ18191171661/article/details/79494534 阅读量比较高,博主讲的也比较清晰,记录一下。

1.第一点疑问,关于AP50的计算方式的疑问,参考链接:https://blog.csdn.net/qq_41994006/article/details/81051150,讲的比较清楚。

2.第二点疑问,关于图像金字塔和特征金字塔,首先明确这两个东西是不同的,这点我是看文章明白的,推荐大家把原论文基本原理部分看一遍。

3.关于横向连接,看了一篇博客是这么解释的,现在对横向连接有了第一个感觉就是怎么是这么融合的,ResNet每个阶段的输出和经过上采样之后的输出融合,对网络究竟影响在何处。

另外我想研究FPN用在目标检测领域,对于Anchor的理解,还需要进一步细化。

自底向上的过程实际上就是前馈神经网络的计算过程。以ResNet为例,对每个阶段提取最后一个residual block的输出(conv2,conv3,conv4和conv5)来构成特征金字塔,相对于输入图像,步长分别为4、8、16、32像素(不使用conv1是因为它占内存太大)。自顶向下的过程通过上采样完成,也就是把高层的feature map通过最近邻上采样使其尺寸*2。横向连接就是将上采样的高层feature map和自底向上产生的feature map(通过1*1的卷积操作来减少feature map的通道数)融合(元素加)。通过上述过程不断迭代产生最好的feature map,即C2。在每个合并的map上附加一个3*3卷积产生最终特征映射,以降低上采样的混叠效应。

关于FPN最好结合图片来理解最好,这是从我参考的博客里截取过来的。

原论文对应的部分贴在下边

原论文中提到参数共享对于性能影响不大,姑且这么认为(在RPN中测试)。

import torch.nn as nn
import torch.nn.functional as F
import math__all__ = ['FPN']class Bottleneck(nn.Module):expansion = 4def __init__(self, in_planes, planes, stride=1, downsample=None):print("---666---")super(Bottleneck, self).__init__()self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)self.bn1 = nn.BatchNorm2d(planes)self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(planes)self.conv3 = nn.Conv2d(planes, self.expansion * planes, kernel_size=1, bias=False)self.bn3 = nn.BatchNorm2d(self.expansion * planes)self.relu = nn.ReLU(inplace=True)self.downsample = downsampleself.stride = stridedef forward(self, x):residual = xout = self.conv1(x)out = self.bn1(out)out = self.relu(out)out = self.conv2(out)out = self.bn2(out)out = self.relu(out)out = self.conv3(out)out = self.bn3(out)if self.downsample is not None:residual = self.downsample(x)out += residualout = self.relu(out)return outclass FPN(nn.Module):def __init__(self, block, layers):super(FPN, self).__init__()self.inplanes = 64self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)self.bn1 = nn.BatchNorm2d(64)self.relu = nn.ReLU(inplace=True)self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# Bottom-up layersself.layer1 = self._make_layer(block, 64, layers[0]) # 第一步print(layers[0]) # 第四步,输出初始layers中的值self.layer2 = self._make_layer(block, 128, layers[1], stride=2)print(layers[1])self.layer3 = self._make_layer(block, 256, layers[2], stride=2)print(layers[2])self.layer4 = self._make_layer(block, 512, layers[3], stride=2)print(layers[3])# Top layerself.toplayer = nn.Conv2d(2048, 256, kernel_size=1, stride=1, padding=0)  # Reduce channels# Smooth layersself.smooth1 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)self.smooth2 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)self.smooth3 = nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1)# Lateral layersself.latlayer1 = nn.Conv2d(1024, 256, kernel_size=1, stride=1, padding=0)self.latlayer2 = nn.Conv2d(512, 256, kernel_size=1, stride=1, padding=0)self.latlayer3 = nn.Conv2d(256, 256, kernel_size=1, stride=1, padding=0)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, math.sqrt(2. / n))elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_()def _make_layer(self, block, planes, blocks, stride=1):downsample = Noneif stride != 1 or self.inplanes != block.expansion * planes:downsample = nn.Sequential(nn.Conv2d(self.inplanes, block.expansion * planes, kernel_size=1, stride=stride, bias=False),nn.BatchNorm2d(block.expansion * planes))layers = []layers.append(block(self.inplanes, planes, stride, downsample))# 该部分是将每个blocks的第一个residual结构保存在layers列表中。print(layers[0]) # zzf 第二步 之后又执行了一次初始化self.inplanes = planes * block.expansionfor i in range(1, blocks):layers.append(block(self.inplanes, planes))# 该部分是将每个blocks的剩下residual结构保存在layers列表中,这样就完成了一个blocks的构造。print(layers[1]) # 输出第二个结构# 这两行代码中都是通过Bottleneck这个类来完成每个residual的构建,接下来介绍Bottleneck类。return nn.Sequential(*layers)def _upsample_add(self, x, y):_, _, H, W = y.size()return F.upsample(x, size=(H, W), mode='bilinear') + ydef forward(self, x):# Bottom-upx = self.conv1(x)x = self.bn1(x)x = self.relu(x)c1 = self.maxpool(x)c2 = self.layer1(c1)c3 = self.layer2(c2)c4 = self.layer3(c3)c5 = self.layer4(c4)# Top-downp5 = self.toplayer(c5)p4 = self._upsample_add(p5, self.latlayer1(c4))p3 = self._upsample_add(p4, self.latlayer2(c3))p2 = self._upsample_add(p3, self.latlayer3(c2))# Smoothp4 = self.smooth1(p4)p3 = self.smooth2(p3)p2 = self.smooth3(p2)return p2, p3, p4, p5if __name__ == '__main__':net = FPN(Bottleneck, [2, 2, 2, 2])
# [2, 2, 2, 2]会影响layer对应的Sequential数目,如果等于2,那会输出(0)、(1)print(net)
# def FPN101():
#     return FPN(Bottleneck, [2, 2, 2, 2])

关于代码的初步理解:

关于维度的输入输出我还没搞懂,目前已经知道的是代码执行的顺序

1,初始化,会运行Bottleneck,打印出---666---

2,会跳转到

self.layer1 = self._make_layer(block, 64, layers[0]) # 第一步

往下调用_make_layer函数

layers.append(block(self.inplanes, planes, stride, downsample))

此时的输出是

Bottleneck((conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace)(downsample): Sequential((0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))
)

3,然后在_make_layer里面继续执行,会返回执行Bottleneck,输出---666---

4,继续向下执行

  for i in range(1, blocks):layers.append(block(self.inplanes, planes))

会输出

Bottleneck((conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1), bias=False)(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(relu): ReLU(inplace)
)

继续执行第四步

  self.layer1 = self._make_layer(block, 64, layers[0]) # 第一步print(layers[0]) # 第四步,输出初始layers中的值

此时输出一个2,这是由于layers的初始化数组是[2,2,2,2]。

暂时先这么多,待补充

其他参考链接:

1.https://blog.csdn.net/baidu_30594023/article/details/82623623

2.http://www.mamicode.com/info-detail-2602526.html

3.https://blog.csdn.net/Jason_mmt/article/details/82662306 (下一步研究)

后续继续补充...

FPN相关问题学习记录相关推荐

  1. python3 获取京东冰箱的相关数据(学习记录)

    程序说明:这个程序可以爬取京东冰箱的相关数据,采用cookie登录(不登录可能获取不到数据),因为没有用selenium进行模拟爬取,所以只获取了首页的前26条数据,要想用获取全部数据,就可以用sel ...

  2. 三维场景注记的配置相关(学习记录)

    此研究已结束,根据遗传算法进行三维场景注记的优化配置,需求代码与帮助可联系作者 1.注记是否丢失 2.注记是否压盖其他注记 注记是否压盖要素(大概是点要素相关,暂时先不理会) 注记是否不可见?(注记丢 ...

  3. Flash相关知识学习记录(以W25Q128为例)

    Flash读写特性: flash的特性是,写数据只能将1写为0,0不能写为1.擦除数据是将所有数据都写为1.因此如果想在已经数据的flash上写入新的数据,则必须先擦除. 解:数据在Flash内存单元 ...

  4. Android Launch Mode的学习记录

    我理解的Task实际上就是Activity堆栈,由于Task里面都是以Activity为单位的,所以一个Task里可以包含来自不同App的Activity,这里把跟Task相关的学习记录下. 关于La ...

  5. 学习记录:二层网络环路相关

    学习记录 上周实习过程中由于对此相关内容不熟悉,造成了事故.由此对相关内容加强学习,特此记录. 目录 学习记录 一.交换机相关 二.网络环路的产生 三.网络环路的影响 四.如何避免网络环路 五.二层环 ...

  6. 视频播放压缩的相关知识点:I帧、P帧、B帧、RTMP协议、RTSP协议、GB28181协议等学习记录

    I帧.P帧.B帧.RTMP协议.RTSP协议.GB28181协议等学习记录 引言 1. I帧.P帧.B帧 1.1 P帧 1.2 B帧 1.3 I帧 2.ONVIF协议与GB28181协议,RTMP与R ...

  7. 生信 反相蛋白质阵列 RPPA的相关学习记录

    反相蛋白质阵列 RPPA的相关学习记录 其基本原理是通过特异性抗体对凝胶电泳处理过的细胞或生物组织样品进行着色.通过分析着色的位置和着色深度获得特定蛋白质在所分析的细胞或组织中表达情况的信息. RPP ...

  8. 2023.2.3,周五【图神经网络 学习记录17】二部图——BiNE算法:显式关系,隐式关系;新的随机游走方式 特点:随机游走次数 是跟节点中心性相关的,在随机游走的过程中 添加一个停止随机游走的概率

    声明:仅学习使用~ 前情提要: 2023.2.2,周四[图神经网络 学习记录16]异构图Graph Embedding算法--GATNE(异构图多属性 多边 类型算法),不建议普通PC跑-PyChar ...

  9. Twain的学习记录和基于Qt的相关开源项目详解

    Twain学习记录和基于Qt的开源项目详解 twpp-qml 适用于 C++11 及更高版本的便携式.仅标头 TWAIN 框架. 原项目作者使用Qtwidget基于Twain静态传输一张图片 我基于h ...

最新文章

  1. iOS7 企业应用无法安装应用程序 因为证书无效的解决方案
  2. rest接口_深度干货 | 测试REST服务接口
  3. lxrun不是内部或外部命令_在Win10 安装 WSL的Linux子系统,解决cmd中执行lxrun时提示“不是内部或外部命令”...
  4. 关于模拟器Hyper-v中的Wp8网络连接问题
  5. Java数组在方法区吗,Java数组的操作方法
  6. 构建Electron的常见问题(Mac)
  7. 什么是交叉编译?个人对交叉编译的理解
  8. 2013计算机应用基础试题及答案,《计算机应用基础》2013年9月统考模拟练习题(完整试卷版含答案)...
  9. Mysql调优ref_【总结】mysql调优
  10. 使用Setup Factory如何制作程序安装包
  11. 开源BI工具对比(二):宜信 davinci
  12. 各国/地区 语言缩写和国际域名缩写
  13. Excel数据透视表如何创建?
  14. 波形发生器设计c语言文件,波形发生器设计方案.doc
  15. gitbook:epub电子书制作教程
  16. Python绘制美女乘风破浪词云舞蹈视频
  17. longest-consecutive-sequence(最长连续序列)
  18. 【python ++ opencv + pytorch 】车牌提取、分割、识别
  19. 微信指纹服务器,华为公布10月底完成微信指纹适配,网友:等了三年终于有结果...
  20. AIDA64如何设置小屏监控 AIDA64监控CPU功耗

热门文章

  1. pycharm设置中文
  2. Python中替换元素
  3. X86,X86_32,X86_64
  4. 禁止logback输出状态信息
  5. UTF-8 's format
  6. LVGL(2)Visual Studio模拟器使用
  7. c语言代码中调用系统命令行.sh shell脚本,linux shell system传参
  8. c/c++入门教程 - 1.基础c/c++ - 1.0 Visual Studio 2019安装环境搭建
  9. NavigatorContent使用皮肤
  10. Linux性能优化实战:应用的CPU使用率100%,我该怎么办(05)