本文以Bubbliiing的YoloX代码进行注意力机制的增加,原博文参考以下。
https://blog.csdn.net/weixin_44791964/article/details/120476949?spm=1001.2014.3001.5502
在此感谢b导的视频,以及对我学习过程中的帮助。

在darknet.py文件中加入以下代码。
'''注意力模块'''
class ChannelAttention(nn.Module):
def __init__(self, in_planes, ratio=16):
super(ChannelAttention, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.max_pool = nn.AdaptiveMaxPool2d(1)
self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
self.relu = nn.ReLU()
self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
out = self.sigmoid(avg_out + max_out)
return out
class SpatialAttention(nn.Module):
def __init__(self, kernel_size=7):
super(SpatialAttention, self).__init__()
assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
padding = 3 if kernel_size == 7 else 1
self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avg_out = torch.mean(x, dim=1, keepdim=True)
max_out, _ = torch.max(x, dim=1, keepdim=True)
x = torch.cat([avg_out, max_out], dim=1)
x = self.conv(x)
return self.sigmoid(x)
class CBAM(nn.Module):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, ratio=16, kernel_size=7): # ch_in, ch_out, number, shortcut, groups, expansion
super(CBAM, self).__init__()
self.channel_attention = ChannelAttention(c1, ratio)
self.spatial_attention = SpatialAttention(kernel_size)
def forward(self, x):
out = self.channel_attention(x) * x
out = self.spatial_attention(out) * out
return out
class SE(nn.Module):
def __init__(self, c1, r=16):
super(SE, self).__init__()
self.avgpool = nn.AdaptiveAvgPool2d(1)
self.l1 = nn.Linear(c1, c1 // r, bias=False)
self.relu = nn.ReLU(inplace=True)
self.l2 = nn.Linear(c1 // r, c1, bias=False)
self.sig = nn.Sigmoid()
def forward(self, x):
b, c, _, _ = x.size()
y = self.avgpool(x).view(b, c)
y = self.l1(y)
y = self.relu(y)
y = self.l2(y)
y = self.sig(y)
y = y.view(b, c, 1, 1)
return x * y
'''注意力模块'''
基于MobileNet网络,我考虑在每一个bottleneck中引入se注意力机制。
class Bottleneck(nn.Module):
# Standard bottleneck
def __init__(self, in_channels, out_channels, shortcut=True, expansion=0.5, depthwise=False, act="silu",):
super().__init__()
hidden_channels = int(out_channels * expansion)
Conv = DWConv if depthwise else BaseConv
self.conv1 = BaseConv(in_channels, hidden_channels, 1, stride=1, act=act)
self.conv2 = Conv(hidden_channels, out_channels, 3, stride=1, act=act)
self.use_add = shortcut and in_channels == out_channels
'''注意力机制'''
self.se = SE(hidden_channels)
def forward(self, x):
'''注意力机制'''
y = self.conv2(self.se(self.conv1(x)))
# y = self.conv2(self.conv1(x))
if self.use_add:
y = y + x
return y
并在darknet.py中,输入到特征金字塔部分的80,80,256;40,40,512;20,20,1024的三个有效特征层分别加入CBAM注意力机制。
class CSPDarknet(nn.Module):
def __init__(self, dep_mul, wid_mul, out_features=("dark3", "dark4", "dark5"), depthwise=False, act="silu",):
super().__init__()
assert out_features, "please provide output features of Darknet"
self.out_features = out_features
Conv = DWConv if depthwise else BaseConv
base_channels = int(wid_mul * 64) # 64
base_depth = max(round(dep_mul * 3), 1) # 3
# -----------------------------------------------#
# 引入cbam注意力机制
# -----------------------------------------------#
self.cbam1 = CBAM(base_channels * 4)
self.cbam2 = CBAM(base_channels * 8)
self.cbam3 = CBAM(base_channels * 16)
self.stem = Focus(3, base_channels, ksize=3, act=act)
self.dark2 = nn.Sequential(
Conv(base_channels, base_channels * 2, 3, 2, act=act),
CSPLayer(base_channels * 2, base_channels * 2, n=base_depth, depthwise=depthwise, act=act),
)
self.dark3 = nn.Sequential(
Conv(base_channels * 2, base_channels * 4, 3, 2, act=act),
CSPLayer(base_channels * 4, base_channels * 4, n=base_depth * 3, depthwise=depthwise, act=act),
)
self.dark4 = nn.Sequential(
Conv(base_channels * 4, base_channels * 8, 3, 2, act=act),
CSPLayer(base_channels * 8, base_channels * 8, n=base_depth * 3, depthwise=depthwise, act=act),
)
self.dark5 = nn.Sequential(
Conv(base_channels * 8, base_channels * 16, 3, 2, act=act),
SPPBottleneck(base_channels * 16, base_channels * 16, activation=act),
CSPLayer(base_channels * 16, base_channels * 16, n=base_depth, shortcut=False, depthwise=depthwise, act=act),
)
def forward(self, x):
outputs = {}
x = self.stem(x)
outputs["stem"] = x
x = self.dark2(x)
outputs["dark2"] = x
#---------------------------------------------------------#
# dark3的输出为80, 80, 256,是一个有效特征层,引入cbam模块
#---------------------------------------------------------#
x = self.dark3(x)
x1 = self.cbam1(x)
outputs["dark3"] = x1
#--------------------------------------------------------#
# dark4的输出为40, 40, 512,是一个有效特征层,引入cbam模块
#--------------------------------------------------------#
x = self.dark4(x)
x2 = self.cbam2(x)
outputs["dark4"] = x2
#--------------------------------------------------------#
# dark5的输出为20, 20, 1024,是一个有效特征层,引入cbam模块
#--------------------------------------------------------#
x = self.dark5(x)
x3 = self.cbam3(x)
outputs["dark5"] = x3
return {k: v for k, v in outputs.items() if k in self.out_features}
在特征金字塔中每个上采样和下采样之后使用注意力机制。
在nets/yolo.py中的YOLOPAFPN类加入以下代码。
in_channels = [256, 512, 1024]
'''注意力机制'''
self.cbam1 = CBAM(c1 = int(in_channels[1] * width))
self.cbam2 = CBAM(c1 = int(in_channels[0] * width))
self.cbam3 = CBAM(c1 = int(in_channels[0] * width))
self.cbam4 = CBAM(c1 = int(in_channels[1] * width))
TypeError: empty() received an invalid combination of arguments - got (tuple, dtype=NoneType, device=NoneType), but expected one of:
在对应的采样部分加入
P5_upsample = self.cbam1(P5_upsample)
P4_upsample = self.cbam2(P4_upsample)
P3_downsample = self.cbam3(P3_downsample)
P4_downsample = self.cbam4(P4_downsample)
训练即可,只增加了少量的运算量。
学习发现大佬的darknet.py文件里已经集成了DW卷积,但是没有使用。
class DWConv(nn.Module):
def __init__(self, in_channels, out_channels, ksize, stride=1, act="silu"):
super().__init__()
self.dconv = BaseConv(in_channels, in_channels, ksize=ksize, stride=stride, groups=in_channels, act=act,)
self.pconv = BaseConv(in_channels, out_channels, ksize=1, stride=1, groups=1, act=act)
def forward(self, x):
x = self.dconv(x)
return self.pconv(x)
DW卷积是否开启使用是由depthwise参数控制的。
我这里使用yolo_x.pth进行训练,想使用DW卷积大大减少参数量(具体可以达到接近50%的参数量减少)。
修改nets/yolo.py中的
depthwise = True if phi == 'x' else False
并且在train.py中修改
phi = 'x'
即可。
train.py中修改为True,注意版本号。
# fp16 是否使用混合精度训练
# 可减少约一半的显存、需要pytorch1.7.1以上
fp16 = True
在net/yolo.py中更改
'''mode有更改,有'nearest', 'linear', 'bilinear', 'bicubic' and trilinear'''
self.upsample = nn.Upsample(scale_factor=2, mode='bilinear')
因为在bottleneck中引入了se注意力模块,因此无法直接读取.pth与训练权重,因此直接从头开始训练。
train.py脚本里model_path设置为空。
model_path = ''
Freeze_Train设置成False
Freeze_Train = False
yolo.training.py中修改class IOUloss
class IOUloss(nn.Module):
def __init__(self, reduction="none", loss_type="iou"):
super(IOUloss, self).__init__()
self.reduction = reduction
self.loss_type = loss_type
def forward(self, pred, target):
assert pred.shape[0] == target.shape[0]
# pred,target为xywh格式
pred = pred.view(-1, 4)
target = target.view(-1, 4)
# tl:top_left, br:bottom_right
tl = torch.max(
(pred[:, :2] - pred[:, 2:] / 2), (target[:, :2] - target[:, 2:] / 2)
)
br = torch.min(
(pred[:, :2] + pred[:, 2:] / 2), (target[:, :2] + target[:, 2:] / 2)
)
# torch.prob为算矩阵乘积,pred[:, 2:]为wh,算出来为面积
area_p = torch.prod(pred[:, 2:], 1)
area_g = torch.prod(target[:, 2:], 1)
# en应该是一个比例吧!交集所占两个框所接最小外界矩形面积的比例
en = (tl < br).type(tl.type()).prod(dim=1)
# torch.prod(br - tl, 1)为最小外接矩形的面积,giou需要用到
area_i = torch.prod(br - tl, 1) * en
# 并集的面积
area_u = area_p + area_g - area_i
iou = (area_i) / (area_u + 1e-16)
if self.loss_type == "iou":
loss = 1 - iou ** 2
elif self.loss_type == "giou":
c_tl = torch.min(
(pred[:, :2] - pred[:, 2:] / 2), (target[:, :2] - target[:, 2:] / 2)
)
c_br = torch.max(
(pred[:, :2] + pred[:, 2:] / 2), (target[:, :2] + target[:, 2:] / 2)
)
# 最小外接矩形的面积
area_c = torch.prod(c_br - c_tl, 1)
# area_c.clamp(1e-16)意义为将area_c的值下限设为1e-16,防止报错
giou = iou - (area_c - area_u) / area_c.clamp(1e-16)
# giou.clamp(min=-1.0, max=1.0)将giou值域限制为(-1,1),实际上giou的值也就是这个值
loss = 1 - giou.clamp(min=-1.0, max=1.0)
# 尝试加入diou,ciou
elif self.loss_type == 'diou':
c_tl = torch.min(
(pred[:, :2] - pred[:, 2:] / 2), (target[:, :2] - target[:, 2:] / 2)
)
c_br = torch.max(
(pred[:, :2] + pred[:, 2:] / 2), (target[:, :2] + target[:, 2:] / 2)
)
# 最大外界矩形对角线长度c^2
w_c = (c_br - c_tl)[:, 0]
h_c = (c_br - c_tl)[:, 1]
c = w_c ** 2 + h_c ** 2
# 中心点距离平方d^2
w_d = (pred[:, :2] - target[:, :2])[:, 0]
h_d = (pred[:, :2] - target[:, :2])[:, 1]
d = w_d ** 2 + h_d ** 2
# 求diou
diou = iou - d/c
loss = 1 - diou.clamp(min=-1.0, max=1.0)
elif self.loss_type == 'ciou':
c_tl = torch.min(
(pred[:, :2] - pred[:, 2:] / 2), (target[:, :2] - target[:, 2:] / 2)
)
c_br = torch.max(
(pred[:, :2] + pred[:, 2:] / 2), (target[:, :2] + target[:, 2:] / 2)
)
# 最大外界矩形对角线长度c^2
w_c = (c_br - c_tl)[:, 0]
h_c = (c_br - c_tl)[:, 1]
c = w_c ** 2 + h_c ** 2
# 中心点距离平方d^2
w_d = (pred[:, :2] - target[:, :2])[:, 0]
h_d = (pred[:, :2] - target[:, :2])[:, 1]
d = w_d ** 2 + h_d ** 2
# 求diou
diou = iou - d / c
w_gt = target[:, 2]
h_gt = target[:, 3]
w = pred[:, 2]
h = pred[:, 3]
with torch.no_grad():
arctan = torch.atan(w_gt / h_gt) - torch.atan(w / h)
v = (4 / (math.pi ** 2)) * torch.pow(arctan, 2)
s = 1 - iou
alpha = v / (s + v)
ciou = diou - alpha * v
loss = 1-ciou.clamp(min=-1.0, max=1.0)
if self.reduction == "mean":
loss = loss.mean()
elif self.reduction == "sum":
loss = loss.sum()
return loss
具体GIoU、DIoU、CIoU有什么改进可以参考我的一篇博文。
https://blog.csdn.net/shayinzzh/article/details/124336574
yolo_training.py文件中修改如下:
self.iou_loss = IOUloss(reduction="none", loss_type="ciou")
想使用什么种类的iou修改loss_type即可。
在summary.py中使用s模型
m = YoloBody(80, 's').to(device)
参数量为
Total params: 9,083,365
Trainable params: 9,083,365
Non-trainable params: 0
使用DW卷积之后,报错
RuntimeError: CUDA out of memory.
使用DW卷积就是减少参数量,为什么会报显存不足的问题,很难理解。
理解:代替普通Conv2D的是DW卷积和PW卷积,相当于两层卷积代替一层卷积,虽然网络的参数量减少了,但是网络层数加深了,因此运行会报显存不足的问题。
在summary.py中使用tiny模型
参数量为
Total params: 5,120,709
Trainable params: 5,120,709
Non-trainable params: 0
使用DW卷积之后
Total params: 2,078,853
Trainable params: 2,078,853
Non-trainable params: 0
正常运行,可见使用DW卷积可以大大减少可训练的参数量。
具体对精度的影响还未测试。
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐
在python中,我们可以使用多处理模块。如果Perl和Ruby中有类似的库,你会教它吗?如果您能附上一个简短的示例,我将不胜感激。 最佳答案 ruby:WorkingwithmultipleprocessesinRubyConcurrencyisaMythinRubyPerl:HarnessingthepowerofmulticoreWhyPerlIsaGreatLanguageforConcurrentProgramming此外,Perl的线程是native操作系统线程,因此您可以使用它们来利用多核。
我正在使用Ruby-Tk为OSX开发一个桌面应用程序,我想为该应用程序提供一个AppleEvents接口(interface)。这意味着应用程序将定义它将响应的AppleScript命令的字典(对应于发送到应用程序的Apple事件),并且用户/其他应用程序可以使用AppleScript命令编写Ruby-Tk应用程序的脚本。其他脚本语言支持此类功能——Python通过位于http://appscript.svn.sourceforge.net/viewvc/appscript/py-aemreceive/的py-aemreceive库和Tcl通过位于http://tclae.source
Method#unbind返回对该方法的UnboundMethod引用,稍后可以使用UnboundMethod#bind将其绑定(bind)到另一个对象.classFooattr_reader:bazdefinitialize(baz)@baz=bazendendclassBardefinitialize(baz)@baz=bazendendf=Foo.new(:test1)g=Foo.new(:test2)h=Bar.new(:test3)f.method(:baz).unbind.bind(g).call#=>:test2f.method(:baz).unbind.bind(h).
目录文章信息写在前面Background&MotivationMethodDCNV2DCNV3模型架构Experiment分类检测文章信息Title:InternImage:ExploringLarge-ScaleVisionFoundationModelswithDeformableConvolutionsPaperLink:https://arxiv.org/abs/2211.05778CodeLink:https://github.com/OpenGVLab/InternImage写在前面拿到文章之后先看了一眼在ImageNet1k上的结果,确实很高,超越了同等大小下的VAN、RepLK
显示等待需要用到两个类:WebDriverWait和expected_conditions两个类WebDriverWait:指定轮询间隔、超时时间等expected_conditions:指定了很多条件函数(也可以自定义条件函数)具体可以参考官网:selenium.webdriver.support.expected_conditions—Selenium4.5documentationfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimpor
Ruby2.3在Array和Hash上引入了一种新方法,称为dig。我在有关新版本的博客文章中看到的示例是做作和令人费解的:#Hash#diguser={user:{address:{street1:'123Mainstreet'}}}user.dig(:user,:address,:street1)#=>'123Mainstreet'#Array#digresults=[[[1,2,3]]]results.dig(0,0,0)#=>1我没有使用三层嵌套平面数组。什么是这将如何有用的现实示例?更新事实证明,这些方法解决了最常见的Ruby问题之一。下面的问题大约有20个重复项,所有这些问
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。社区在12个月前审查了是否重新打开此问题,并将其关闭:原始关闭原因未解决最近学习了Ruby编程语言,总的来说是一门很好的语言。但是我很惊讶地发现它并不像我预期的那么简单。更准确地说,“最小惊喜规则”在我看来并不是很受尊重(当然这是相当主观的)。例如:x=trueandfalseputsx#displaystrue!和著名的:puts"zeroistrue
我收到错误AWS::S3::Errors::InvalidRequest不支持您提供的授权机制。请使用AWS4-HMAC-SHA256.当我尝试将文件上传到新法兰克福地区的S3存储桶时。所有适用于USStandard区域。脚本:backup_file='/media/db-backup_for_dev/2014-10-23_02-00-07/slave_dump.sql.gz's3=AWS::S3.new(access_key_id:AMAZONS3['access_key_id'],secret_access_key:AMAZONS3['secret_access_key'])s3_