由于之前工作中,训练数据集普遍较小 以及 开发板对模型的限制,所以对SE模块的使用较少,对它的插入位置不是很清楚,这样不利于日后对它的使用。故最近查了下使用案例,记录总结如下。
plain模型SE作者对SE模块在plain模型插入位置的建议是:在每个卷积的激活函数后面插入。这样一看会误以为在每个卷积层后面加个SE模块,一般是在每个block后面插入,下面结合实际的案例来做说明。
1. SE-Inception 模型

2. PP-LCNet 模型

由上面两张图可见,SE模块在plain模型的插入位置,一般在上个block的结尾 下一个block之前的位置插入。
skip connection 模型skip connection 模型指ResNet、MobileNet v2/v3这种具有shortcut操作的模型。现在的模型基本是这个结构,它与plain模型block最大的不同就是多了个恒等映射的分支(一些变种可能不是恒等映射分支,意思明白就好)。
(类)residual unit外部,SE的插入位置SE作者做了个实验,验证SE模块在residual unit外部时,放在哪个位置效果最好。这个实验虽然是用残差网络来做的,但是其他模型如MobileNet也可以借鉴,毕竟二者的思路是一致的。

验证结果如下,下图中的SE就是上图的 Standard SE block,其他名词含义与上图一致。

由上图可见,SE-POST block误差相对最大,所以作者建议:SE模块要加在两个分支汇合之前。
至于SE-PRE block、SE-Identity block的top1误差比Standard SE block还小,但SE作者最后并没有采用这种形式,而是用了Standard SE block(也即上图的SE)形式。我猜想可能是plain模型的思维惯性,即放在卷积后面。
在此还要说明一点,SE作者自己说过,这些插入位置什么的,不是SE论文的核心,所以他没做很多实验。他建议针对特定网络结构,针对性地插入SE模块,可能会得到更好的结果。所以SE-PRE block、SE-Identity block甚至SE-POST block都可以尝试一下。(反正深度学习是拿实验数据说话)
(类)residual unit内部,SE的插入位置SE作者还实验了下,把插入位置由下图的 “SE模块” 换到 "SE_3X3"处(3x3指的是block中间那个3x3卷积)。另外说下,下图就是SE-ResNet50的模型图,也就是作者最终选定的结构样式。

上面实验结果如下,可以发现二者的性能没什么差别,但因为ResNet的3x3卷积比下面1x1卷积的通道数更低,所以SE_3X3的参数量、计算量也更低。

MobileNet v3也借鉴了SE_3X3的添加位置,由下图可见,也是放在3x3卷积与1x1卷积之间。

此外,看git上MobileNet v3代码,会发现SE的插入位置还有个版本,该版本插入位置与SE-ResNet50一致,在unit最后一个卷积后面。这里估计是想减少点参数量及计算复杂度,毕竟MobileNet v3的3x3卷积比下面1x1卷积的通道数更高。实际使用时,两个位置都可以试试。
class Block(nn.Module):
'''expand + depthwise + pointwise'''
def __init__(self, kernel_size, in_size, expand_size, out_size, nolinear, semodule, stride):
"""
这块代码不重要,就不贴出来了,免得不好看博客
"""
def forward(self, x):
out = self.nolinear1(self.bn1(self.conv1(x)))
out = self.nolinear2(self.bn2(self.conv2(out)))
out = self.bn3(self.conv3(out))
if self.se != None: # 在 1x1卷积后面插入SE模块
out = self.se(out)
out = out + self.shortcut(x) if self.stride==1 else out
return out
自YOLO V5面世以来,针对其的改进也有添加SE模块的方式。纵观网上的博客,发现V5添加SE模块一般是在两个位置:
① 在C3-bottleneck中添加SE模块的,这样添加主要为了更好的做实验,参考博客;

另外,目前一般是加在bottleneck中第一个卷积block后面,参考上面的博客内容,也可以试试放在第二个卷积block后面。最后我们可以看到,无论是YOLO V5、MobileNet v3还是SE-ResNet50,添加SE模块都是以block为单位目标来添加的,这点与我们在博文开头处的观点倒是不谋而合。
② 在V5-backbone结尾处添加SE模块。
这个添加位置比较少见,我也是看这个参考博客才知道,博主表示 backbone结尾添加一个注意力机制 会好点。
# YOLOv5 backbone
backbone:
# [from, number, module, args]
[
[-1, 1, Focus, [64, 3]], # 0-P1/2 #1
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4 #2
[-1, 3, C3, [128]], #3
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8 #4
[-1, 9, C3, [256]], #5
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16 #6
[-1, 9, C3, [512]], #7
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 #8
[-1, 1, SPP, [1024, [5, 9, 13]]], #9
[-1, 3, C3, [1024, False]], # 9 #10
[-1, 1, SELayer, [1024, 4]], # SE模块加在block的外面,即 SE-POST block方式
]
想了一下,这点在SE论文里的SE-Inception也有体现。如下图:

SE模块这对我们使用SE模块,确实是个问题,每层都用不合适,选一层的话又不知道应该选哪层。SE作者为此做了个实验。
先看看作者做实验的模型,绿色的字体是我打的,让各位更明白模型每个stage在模型中的位置,其中每个feature map尺寸就是一个stage。中间与右边两列中括号里的fc,[xx, xx]就是SE模块。

作者做了组对比实验,分别只在SE_stage_2,SE_stage_3,SE_stage_4 插入SE模块,最后又给出所有stage(SE_ALL)插入SE模块的实验结果。可以看见,每层都加的效果是最好的(其参数量与计算量也最高),所以作者最后也是每个block都添加了SE模块。

但要注意的是,在模型的最后三个block(SE_stage_4)添加SE模块,会发现 性能-计算复杂度取到一个比较好的平衡,这点在PP-LCNet里也得到了呼应。如下图所示,PP-LCNet在模型最后的两个block添加SE模块(也是最后一个stage),也是取得了性能-计算复杂度平衡,故以后部署平台算力紧张时,可以考虑这种策略。

查看MobileNet v3论文,发现其对SE的用法也有点类似于前两者。据下图可知,MobileNet v3在其large与small版本的最后两个stage中都插入了SE模块。以后使用时,在模型最后两个stage添加SE模块性价比更高点,如果算力限制大,也可以试着只在最后一个stage添加SE模块。

抛砖引玉之作,如有遗漏、补充,还请各位看官不吝指出,谢谢。
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称