基于改进YOLOv5的安全帽检测算法 | 引入Ghost卷积 + 添加CA注意力机制 + 更换Neck网络之BiFPN + 更换损失函数之WIoU

前言:Hello大家好,我是小哥谈。为了解决建筑工地、隧道、煤矿等施工场景中现有安全帽检测算法对于小目标密集目标以及复杂环境下的检测精度低的问题,设计实现了一种基于YOLOv5的改进目标检测算法,记为YOLOv5-GBCW。首先使用Ghost卷积对骨干网络进行重构,使得模型的复杂度有了显著降低;其次使用双向特征金字塔网络(BiFPN)加强特征融合,使得算法对小目标准确率提升;引入坐标注意力(Coordinate attention)模块,能够将注意力资源分配给关键区域,从而在复杂环境中降低背景的干扰;最后提出了WIoU作为边框损失函数,采用动态非单调聚焦机制并引入对锚框特征的计算,提升预测框的准确率,同时加速模型收敛。为了验证算法的可行性,以课题组收集的安全帽数据集为基础,选用了多种经典算法进行对比,并且进行了消融实验,探究各个改进模块的提升效果。实验结果表明:在复杂环境、密集场景和小目标场景下检测能力提升显著,并且同时满足安全帽检测精度和实时性的要求,给复杂施工环境下安全帽检测提供了一种新的方法。🌈

     目录

🚀1.基础概念

🚀2.网络结构

🚀3.添加步骤

🚀4.改进方法

🍀🍀步骤1:common.py文件修改

🍀🍀步骤2:yolo.py文件修改

🍀🍀步骤3:创建自定义yaml文件

🍀🍀步骤4:修改自定义yaml文件

🍀🍀步骤5:验证是否加入成功

🍀🍀步骤6:更换损失函数

🍀🍀步骤7:修改默认参数

🍀🍀步骤8:实际训练测试 

🚀5.实验分析

🍀🍀5.1 评价指标

🍀🍀5.2 消融实验

🚀1.基础概念

近几年来,作为机器学习领域的热点,深度学习在目标检测图像识别语义分割等应用十分广泛。目前,国内外学者也将深度学习技术应用于安全帽识别领域,相较于传统方法人工提取特征,深度学习能够利用卷积神经网络提取更加高层、有效的特征,极大地提高了安全帽识别的准确率和速度。基于深度学习的目标检测技术主要可以分为两类一类是基于候选区域的两阶段(Two-stage)检测算法另一类是基于回归的单阶段(One-stage)检测算法

两阶段检测算法需要先用特征提取器生成一系列候选框,并从每个候选框中提取特征,然后再使用区域分类器进行预测,两阶段算法主要包括: RCNNFaster RCNNSPP-Net等。而单阶段算法能够通过只提取一次特征从而完成物体的分类和位置预测,结构简单并且检测速度快,目前,安全帽检测中常用的算法包括YOLO系列算法SSD算法RetinaNet算法等。

本文主要以课题组近年来收集的各大工地、煤矿、隧道场景下的图片以及网络爬取的相关照片为基础,自建数据集,在YOLOv5的基础上进行改进,使其在不同施工场景中对安全帽下有着更好的检测效果。

YOLO算法作为目标检测单阶段的代表算法,自2016年由Joseph Redmon提出之后,经过有关人员的不断研究,发展出诸多版本,并在工业界和学术界有着良好的应用场景。YOLOv5由Ultralytics公司于2020年提出,相较于YOLOv4,配置更加方便,训练与推理时间进一步缩短,准确率也得到了提升。而YOLOv5本身也在不断地更新迭代,本文使用的是v6.0的版本。YOLOv5通过修改深度宽度两个缩放参数,可以得到五个不同大小的模型,分别是:YOLOv5n5s5m5l5x,模型大小依次增大,而准确率也在逐步提升。为了便于移动端设备以及边缘设备的部署,本研究采用兼顾速度和精度的YOLOv5s作为改进的基础模型。

基于GhostNet的主干提取网络重构:

YOLOv5网络模型中包含了较多的Conv卷积模块C3模块,从而对输入图像进行特征提取、特征融合等操作,但是由于传统的卷积中存在着大量冗余的特征图,而特征图对模型的精度至关重要,在卷积过程中包含大量的网络参数,消耗了大量的计算资源,因此引入了Ghost卷积。Ghost卷积来自GhostNet,它将深层神经网络(DNN)中的一个普通卷积层分成两部分。首先通过普通卷积生成少量特征图,然后使用一系列简单的线性操作应用于生成的特征图,从而生成Ghost特征图,这样能够高效地减少特征冗余,它 是一个运行更快,参数量更轻量化的模块。因此,本文以此为基础,使用Ghost卷积替换了YOLOv5的部分普通卷积,轻量化后的模型在保证不明显降低准确率的情况下,使得计算量和参数量大量减小,提升了网络的运行速度。

注意力机制的引入:

在本文检测任务中,工地、隧道施工环境复杂,在检测安全帽时容易受到复杂背景的干扰,在原YOLOv5模型算法中易被遗漏,为了提升安全帽的检测精度,所以引入注意力机制。注意力机制(Attention mechanism) 类似于人眼的视觉注意力机制,能够在繁杂的全局图像中确定关键的区域,之后对该区域投入更多的注意力资源,从而获取更多有价值的细节信息,忽视背景信息的干扰。通过这种机制,能够在计算资源有限的条件下,将算力分配给重要的任务,从而提高任务处理的效率。在目标检测任务中,注意力机制也能起到效果,能够帮模型更好地聚焦关键特征,并且削弱无关信息在特征图上的权重,从而提高识别准确率。本文引入了坐标注意力模块(Coordinate attention,CA), 注意力机制被分解为两个并行(x和y方向)的一维特征编码过程。通过这种方式,可以沿着一个方向捕获长距离的依赖关系同时可以沿着另一个方向保留准确的位置信息,能够有效地将空间坐标信息聚集到生成的注意图中,CA注意力模块示意图如下图所示。

特征金字塔结构的改进:

回顾一下YOLO系列的特征提取网络,YOLOv3中采用的是FPN结构FPN是自上往下的,将高层特有的特征信息经过上采样的方法来进行特征融合,利用融合后得到的特征图进行预测,而这种结构难免会受到单项信息流的限制。而YOLOv4和v5采用的是改进后的PAN结构在FPN层后添加了一个自下往上的特征金字塔,FPN层自上往下传达强语义的特征,而特征金字塔则自下往上传达强定位特征,可以提高预测精度。然而PAN是一个跨尺度的特征融合网络,在当它融合不同的输入特征时,只是做了一个简单的归纳,并对不同尺度的特征仍给予相同的关注。由于安全帽通常是较小尺寸,可视化信息少,难以提取到有鉴别力的特征,为了解决该问题,本研究将双向特征金字塔网络(Bi-directional feature pyramid network, BiFPN)作为新的多尺度特征提取网络,替换掉了YOLOv5原有的PAN结构。

双向特征金字塔网络如图所示,它是一种更为复杂的加权双向特征金字塔提取结构该网络删除了PANet中只有一条输入边和输出边的低贡献结构节点,同时在同一尺度的输入节点到输出节点之间添加跃级连接,因此能够在不额外增加花销的同时融合更多的特征,并且BiFPN构建了带有自学习权重的特征融合模块,每一个模块包括双向(自顶向下和自底向上)路径的特征网络层,可以通过重复块的不断堆叠来进行更高级别的特征融合。

损失函数的改进:

原YOLOv5损失函数由定位损失函数—CIoU loss分类损失函数以及目标置信度损失函数 —BCE loss三者构成,而目标检测中的目标定位是 一项重要的任务,优秀的边界框损失函数可以帮助算法有效地训练并获得最佳权重,从而提高算法收敛速度和精确率。因此,在训练算法时选择一个适当的损失函数对于目标定位任务至关重要。在YOLOv5模型中,使用CIoU损失函数进行边界框回归,在损失值计算过程中考虑预测框与真实框的高宽比,有效解决了不重叠情况下为边界框提供移动方向的问题。然而,由于CIoU损失函数将所有损失变量作为整体进行计算,可能导致收敛速度慢、不稳定等现象,并且还未能考虑难易样本的不平衡问题。而在本次安全帽检测中存在着如遮挡、密集目标的难分类样本,因此直接采用CIoU损失函数检测效果不佳。针对该问题,本文提出了WIoU损失函数。


🚀2.网络结构

本文的改进是基于YOLOv5-6.0版本,关于其网络结构具体如下图所示:

经过改进后的网络结构图如下所示:


🚀3.添加步骤

针对本文的改进,具体步骤如下所示:👇

步骤1:common.py文件修改

步骤2:yolo.py文件修改

步骤3:创建自定义yaml文件

步骤4:修改自定义yaml文件

步骤5:验证是否加入成功

步骤6:更换损失函数

步骤7:修改默认参数

步骤8:实际训练测试


🚀4.改进方法

🍀🍀步骤1:common.py文件修改

common.py中添加CA注意力机制BiFPN模块代码,所要添加模块的代码如下所示,将其复制粘贴到common.py文件末尾的位置。

# CA注意力机制
# By CSDN 小哥谈
class h_sigmoid(nn.Module):def __init__(self, inplace=True):super(h_sigmoid, self).__init__()self.relu = nn.ReLU6(inplace=inplace)def forward(self, x):return self.relu(x + 3) / 6class h_swish(nn.Module):def __init__(self, inplace=True):super(h_swish, self).__init__()self.sigmoid = h_sigmoid(inplace=inplace)def forward(self, x):return x * self.sigmoid(x)class CoordAtt(nn.Module):def __init__(self, inp, oup, reduction=32):super(CoordAtt, self).__init__()self.pool_h = nn.AdaptiveAvgPool2d((None, 1))self.pool_w = nn.AdaptiveAvgPool2d((1, None))mip = max(8, inp // reduction)self.conv1 = nn.Conv2d(inp, mip, kernel_size=1, stride=1, padding=0)self.bn1 = nn.BatchNorm2d(mip)self.act = h_swish()self.conv_h = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)self.conv_w = nn.Conv2d(mip, oup, kernel_size=1, stride=1, padding=0)def forward(self, x):identity = xn, c, h, w = x.size()# c*1*Wx_h = self.pool_h(x)# c*H*1# C*1*hx_w = self.pool_w(x).permute(0, 1, 3, 2)y = torch.cat([x_h, x_w], dim=2)# C*1*(h+w)y = self.conv1(y)y = self.bn1(y)y = self.act(y)x_h, x_w = torch.split(y, [h, w], dim=2)x_w = x_w.permute(0, 1, 3, 2)a_h = self.conv_h(x_h).sigmoid()a_w = self.conv_w(x_w).sigmoid()out = identity * a_w * a_hreturn out# 更换Neck网络之BiFPN
# By CSDN 小哥谈
# 更换Neck网络之BiFPN
# 两个特征图add操作
class BiFPN_Add2(nn.Module):def __init__(self, c1, c2):super(BiFPN_Add2, self).__init__()# 设置可学习参数 nn.Parameter的作用是:将一个不可训练的类型Tensor转换成可以训练的类型parameter# 并且会向宿主模型注册该参数 成为其一部分 即model.parameters()会包含这个parameter# 从而在参数优化的时候可以自动一起优化self.w = nn.Parameter(torch.ones(2, dtype=torch.float32), requires_grad=True)self.epsilon = 0.0001self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0)self.silu = nn.SiLU()def forward(self, x):w = self.wweight = w / (torch.sum(w, dim=0) + self.epsilon)return self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1]))# 三个特征图add操作
class BiFPN_Add3(nn.Module):def __init__(self, c1, c2):super(BiFPN_Add3, self).__init__()self.w = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True)self.epsilon = 0.0001self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0)self.silu = nn.SiLU()def forward(self, x):w = self.wweight = w / (torch.sum(w, dim=0) + self.epsilon)# Fast normalized fusionreturn self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1] + weight[2] * x[2]))
🍀🍀步骤2:yolo.py文件修改

yolo.py文件中找到parse_model函数,在下图中所示位置添加CoordAtt,并且添加下列代码:

# 添加bifpn_add结构elif m in [BiFPN_Add2, BiFPN_Add3]:c2 = max([ch[x] for x in f])

具体添加位置如下图所示:

🍀🍀步骤3:创建自定义yaml文件

models文件夹中复制yolov5s.yaml,粘贴并重命名为:yolov5s_helmet.yaml具体如下图所示:

🍀🍀步骤4:修改自定义yaml文件

本步骤是修改yolov5s_helmet.yaml,根据改进后的网络结构图进行修改。

修改后的完整yaml文件如下所示:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# By CSDN 小哥谈
# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:- [10,13, 16,30, 33,23]  # P3/8- [30,61, 62,45, 59,119]  # P4/16- [116,90, 156,198, 373,326]  # P5/32# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args][[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2[-1, 1, GhostConv, [128, 3, 2]],  # 1-P2/4[-1, 3, C3, [128]],          # 2[-1, 1, GhostConv, [256, 3, 2]],  # 3-P3/8[-1, 6, C3, [256]],          # 4[-1, 1, GhostConv, [512, 3, 2]],  # 5-P4/16[-1, 9, C3, [512]],          # 6[-1, 1, GhostConv, [1024, 3, 2]],  # 7-P5/32[-1, 3, C3, [1024]],         # 8[-1, 1, CoordAtt, [1024]],        # 9[-1, 1, SPPF, [1024, 5]],  # 10]# YOLOv5 v6.0 BiFPN head
head:[[-1, 1, GhostConv, [512, 1, 1]], # 11[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 12[[-1, 6], 1, BiFPN_Add2, [256,256]],  # 13 cat backbone P4[-1, 3, C3, [512, False]],  # 14[-1, 1, GhostConv, [256, 1, 1]], # 15[-1, 1, nn.Upsample, [None, 2, 'nearest']], # 16[[-1, 4], 1, BiFPN_Add2, [128,128]],  # 17 cat backbone P3[-1, 3, C3, [256, False]],  # 18[-1, 1, GhostConv, [512, 3, 2]], # 19[[-1, 14, 6], 1, BiFPN_Add3, [256,256]],  # 20[-1, 3, C3, [512, False]],  # 21[-1, 1, GhostConv, [512, 3, 2]], # 22[[-1, 11], 1, BiFPN_Add2, [256,256]],  # 23 cat head P5[-1, 3, C3, [1024, False]],  # 24[[18, 21, 24], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)]
🍀🍀步骤5:验证是否加入成功

yolo.py文件里,将配置改为我们刚才自定义的yolov5s_helmet.yaml

修改1,位置位于yolo.py文件165行左右,具体如图所示:

修改2,位置位于yolo.py文件363行左右,具体如下图所示:

配置完毕之后,点击“运行”,结果如下图所示:

🍀🍀步骤6:更换损失函数

修改1,将utils/metrics.py文件中的下列代码:

def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):# Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)# Get the coordinates of bounding boxesif xywh:  # transform from xywh to xyxy(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_else:  # x1, y1, x2, y2 = box1b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + epsw2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps# Intersection areainter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \(torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)# Union Areaunion = w1 * h1 + w2 * h2 - inter + eps# IoUiou = inter / unionif CIoU or DIoU or GIoU:cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)  # convex (smallest enclosing box) widthch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)  # convex heightif CIoU or DIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1c2 = cw ** 2 + ch ** 2 + eps  # convex diagonal squaredrho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center dist ** 2if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)with torch.no_grad():alpha = v / (v - iou + (1 + eps))return iou - (rho2 / c2 + v * alpha)  # CIoUreturn iou - rho2 / c2  # DIoUc_area = cw * ch + eps  # convex areareturn iou - (c_area - union) / c_area  # GIoU https://arxiv.org/pdf/1902.09630.pdfreturn iou  # IoU

更换成:

class WIoU_Scale:''' monotonous: {None: origin v1True: monotonic FM v2False: non-monotonic FM v3}momentum: The momentum of running mean'''iou_mean = 1.monotonous = False_momentum = 1 - 0.5 ** (1 / 7000)_is_train = Truedef __init__(self, iou):self.iou = iouself._update(self)@classmethoddef _update(cls, self):if cls._is_train: cls.iou_mean = (1 - cls._momentum) * cls.iou_mean + \cls._momentum * self.iou.detach().mean().item()@classmethoddef _scaled_loss(cls, self, gamma=1.9, delta=3):if isinstance(self.monotonous, bool):if self.monotonous:return (self.iou.detach() / self.iou_mean).sqrt()else:beta = self.iou.detach() / self.iou_meanalpha = delta * torch.pow(gamma, beta - delta)return beta / alphareturn 1def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU=False, WIoU=False, Focal=False, alpha=1, gamma=0.5, scale=False, eps=1e-7):# Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)# Get the coordinates of bounding boxesif xywh:  # transform from xywh to xyxy(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_else:  # x1, y1, x2, y2 = box1b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)w1, h1 = b1_x2 - b1_x1, (b1_y2 - b1_y1).clamp(eps)w2, h2 = b2_x2 - b2_x1, (b2_y2 - b2_y1).clamp(eps)# Intersection areainter = (b1_x2.minimum(b2_x2) - b1_x1.maximum(b2_x1)).clamp(0) * \(b1_y2.minimum(b2_y2) - b1_y1.maximum(b2_y1)).clamp(0)# Union Areaunion = w1 * h1 + w2 * h2 - inter + epsif scale:self = WIoU_Scale(1 - (inter / union))# IoU# iou = inter / union # ori iouiou = torch.pow(inter/(union + eps), alpha) # alpha iouif CIoU or DIoU or GIoU or EIoU or SIoU or WIoU:cw = b1_x2.maximum(b2_x2) - b1_x1.minimum(b2_x1)  # convex (smallest enclosing box) widthch = b1_y2.maximum(b2_y2) - b1_y1.minimum(b2_y1)  # convex heightif CIoU or DIoU or EIoU or SIoU or WIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1c2 = (cw ** 2 + ch ** 2) ** alpha + eps  # convex diagonal squaredrho2 = (((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4) ** alpha  # center dist ** 2if CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47v = (4 / math.pi ** 2) * (torch.atan(w2 / h2) - torch.atan(w1 / h1)).pow(2)with torch.no_grad():alpha_ciou = v / (v - iou + (1 + eps))if Focal:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha)), torch.pow(inter/(union + eps), gamma)  # Focal_CIoUelse:return iou - (rho2 / c2 + torch.pow(v * alpha_ciou + eps, alpha))  # CIoUelif EIoU:rho_w2 = ((b2_x2 - b2_x1) - (b1_x2 - b1_x1)) ** 2rho_h2 = ((b2_y2 - b2_y1) - (b1_y2 - b1_y1)) ** 2cw2 = torch.pow(cw ** 2 + eps, alpha)ch2 = torch.pow(ch ** 2 + eps, alpha)if Focal:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2), torch.pow(inter/(union + eps), gamma) # Focal_EIouelse:return iou - (rho2 / c2 + rho_w2 / cw2 + rho_h2 / ch2) # EIouelif SIoU:# SIoU Loss https://arxiv.org/pdf/2205.12740.pdfs_cw = (b2_x1 + b2_x2 - b1_x1 - b1_x2) * 0.5 + epss_ch = (b2_y1 + b2_y2 - b1_y1 - b1_y2) * 0.5 + epssigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)sin_alpha_1 = torch.abs(s_cw) / sigmasin_alpha_2 = torch.abs(s_ch) / sigmathreshold = pow(2, 0.5) / 2sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - math.pi / 2)rho_x = (s_cw / cw) ** 2rho_y = (s_ch / ch) ** 2gamma = angle_cost - 2distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(gamma * rho_y)omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)if Focal:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha), torch.pow(inter/(union + eps), gamma) # Focal_SIouelse:return iou - torch.pow(0.5 * (distance_cost + shape_cost) + eps, alpha) # SIouelif WIoU:if Focal:raise RuntimeError("WIoU do not support Focal.")elif scale:return getattr(WIoU_Scale, '_scaled_loss')(self), (1 - iou) * torch.exp((rho2 / c2)), iou # WIoU https://arxiv.org/abs/2301.10051else:return iou, torch.exp((rho2 / c2)) # WIoU v1if Focal:return iou - rho2 / c2, torch.pow(inter/(union + eps), gamma)  # Focal_DIoUelse:return iou - rho2 / c2  # DIoUc_area = cw * ch + eps  # convex areaif Focal:return iou - torch.pow((c_area - union) / c_area + eps, alpha), torch.pow(inter/(union + eps), gamma)  # Focal_GIoU https://arxiv.org/pdf/1902.09630.pdfelse:return iou - torch.pow((c_area - union) / c_area + eps, alpha)  # GIoU https://arxiv.org/pdf/1902.09630.pdfif Focal:return iou, torch.pow(inter/(union + eps), gamma)  # Focal_IoUelse:return iou  # IoU

修改2,将utils/loss.py文件中的红框部分注释掉。

说明:上图中我已经注释掉。 

然后将红框部分下面加入下列代码:

iou = bbox_iou(pbox, tbox[i], WIoU=True, scale=True)  # iou(prediction, target)if type(iou) is tuple:lbox += (iou[1].detach().squeeze() * (1 - iou[0].squeeze())).mean()iou = iou[0].squeeze()else:lbox += (1.0 - iou.squeeze()).mean()  # iou lossiou = iou.squeeze()
🍀🍀步骤7:修改默认参数

修改1,设置可学习权重,将下列代码放置在train.py文件(160行左右)

# 设置可学习权重g0, g1, g2 = [], [], []  # optimizer parameter groupsfor v in model.modules():# hasattr: 测试指定的对象是否具有给定的属性,返回一个布尔值if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):  # biasg2.append(v.bias)  # biasesif isinstance(v, nn.BatchNorm2d):  # weight (no decay)g0.append(v.weight)elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):g1.append(v.weight)# BiFPN_Concatelif isinstance(v, BiFPN_Add2) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter):g1.append(v.w)elif isinstance(v, BiFPN_Add3) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter):g1.append(v.w)

具体放置位置如下图所示:

修改2,在train.py文件中找到parse_opt函数,然后将第二行 '--cfg' 的default改为 ' models/yolov5s_helmet.yaml ',然后就可以开始进行训练了。🎈🎈🎈 

🍀🍀步骤8:实际训练测试 

在本步骤中,parse_opt函数中的参数'--weights'采用的是yolov5s.pt'--data'所采用的是helmet.yaml(作者提前创建的安全帽佩戴检测地址及分类信息,同学可自定义),然后设置'--epochs'100轮。相关参数设置完毕后,点击运行train.py文件,没有发生报错,模型正常训练,具体如下图所示:👇


🚀5.实验分析

🍀🍀5.1 评价指标

目标检测任务中包括了目标分类定位,主要可以从检测精度检测速度模型复杂度三方面来评估模型好坏,检测精度方面一般包含精确率(Precision)召回率(Recall)mAP@0.5mAP@0.5: 0.95;检测速度方面包括每秒处理帧数(FPS);模型复杂度包括模型大小参数量计算量(GFLOPs)。在本文的检测分类任务中,需要识别的是已佩戴安全帽和未佩戴安全帽两种情况,可以看作二分类问题,把检测结果分为TP(真正例)FN(假反例)FP(假正例)TN(真反例)四种情况。结合本次检测任务,TP表示实际佩戴安全帽被正确检测,FN表示实际佩戴安全帽却被错误识别成未佩戴,FP表示实际未佩戴安全帽却被检测成佩戴,TN表示未实际佩戴安全帽被正确检测。

精度方面,精确率表示是识别结果是正例中有多少是实际正例的比例,即查准率; 召回率表示原始样本中的实际正例有多少被预测正确的比例,即查全率。

🍀🍀5.2 消融实验

为了验证本文算法的检测性能,以及探究各个改进模块的提升效果,进行了消融实验,实验结果如表6所示,引入Ghost模块后,能够对模型进行轻量化,相比于原网络,计算量降低了44.3%,只有8.1GFLOPs,而精度只有轻微下降。而引入CA 模块后能够聚焦关键特征,mAP@0.5相对于原网络提高了2.6%,由于增加了模型的复杂性,FPS降低了1.8帧。引入BiFPN改进特征金字塔同样对精度有提升,mAP@0.5提升了2.8%,但FPS降低了10.9 帧。本文算法结合了各模块的优点,mAP@0.5达到 了94.5%,并且检测速度也达到了124.6 FPS,满足实时检测的要求。

说明:

本节课根据文章《基于改进YOLOv5的安全帽检测算法》进行代码实现,网络结构稍有修改。

作者:侯公羽、陈钦煌、杨振华、张又文、张丹阳、李昊翔

期刊:工程科学学报,第 46 卷,第 2 期:329−342,2024 年 2 月


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/860565.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 | Leetcode C语言题解之第166题分数到小数

题目: 题解: struct HashMapNode {int key;int val;UT_hash_handle hh; };struct HashMapNode* hashMap NULL;int hashMapAdd(int key, int val) {struct HashMapNode* node;HASH_FIND_INT(hashMap, &key, node);if(node ! NULL){return node->…

fiddler抓https包

1,安装fiddler省略 2,下载证书步骤:tools-options-https 点击确认,点击OK,点击是 把证书安装到谷歌浏览器上步骤:点击谷歌浏览器右上角的设置,在搜索框中搜索证书,点击“证书管理”…

从0搭建一个vue项目,不使用脚手架从html到vue

前言 从最开始学习web网页开始,搭建一个网页只需要创建一个html文件对其进行编写dom标签语言即可;后来分离了html,css和js,搭建一个网页开始需要文件夹,文件夹包含了这3类文件以及静态文件,图片&#xff0c…

【会议征稿】2024年应用计算智能、信息学与大数据国际会议(ACIIBD 2024,7月26-28)

2024年应用计算智能、信息学与大数据国际学术会议(ACIIBD 2024)将于2024年7月26-28日在中国广州举办。会议将聚焦于计算智能及其应用、信息、大数据等相关的研究领域, 广泛邀请国内外知名专家学者,共同探讨相关学科领域的最新发展…

26.高级特性(上)

目录 一、不安全的Rust二、不安全的超能力2.1 概念2.2 解引用裸指针2.3 调用不安全的函数或方法2.3 创建不安全代码的安全抽象2.4 使用extern函数调用外部代码2.5 访问或修改可变静态变量2.6 实现不安全trait2.7 访问联合体中的字段 三、高级trait3.1 关联类型在trait定义中指定…

【昇思初学入门】第七天打卡-模型训练

训练模型 学习心得 构建数据集。这通常包括训练集、验证集(可选)和测试集。训练集用于训练模型,验证集用于调整超参数和监控过拟合,测试集用于评估模型的泛化能力。 (mindspore提供数据集https://www.mindspore.cn/d…

使用Python和NLTK进行NLP分析的高级指南

在本文中,将利用数据集来比较和分析自然语言。 本文涵盖的基本构建块是: WordNet和同义词集相似度比较树和树岸命名实体识别 WordNet和同义词集 WordNet是NLTK中的大型词汇数据库语料库。WordNet维护与名词,动词,形容词&#…

Unity 弧形图片位置和背景裁剪

目录 关键说明 Unity 设置如下 代码如下 生成和部分数值生成 角度转向量 计算背景范围 关键说明 效果图如下 来自红警ol游戏内的截图 思路:确定中心点为圆的中心点 然后 计算每个的弧度和距离 Unity 设置如下 没什么可以说的主要是背景图设置 代码如下 …

攻克PS之路——Day1(A1-A8)

#暑假到了,作为可能是最后一个快乐的暑假,我打算学点技能来傍身,首先,开始PS之旅 这个帖子作为我跟着B站up主学习PS的记录吧,希望我可以坚持下去! 学习的链接在这里:A02-PS软件安装&#xff0…

基于SSM+VUE的网上订餐系统(带1w+文档)

基于SSMVUE的网上订餐系统(带1w文档) 网上订餐系统的数据库里面存储的各种动态信息,也为上层管理人员作出重大决策提供了大量的事实依据。总之,网上订餐系统是一款可以真正提升管理者的办公效率的软件系统。 项目简介 基于SSMVUE的网上订餐系统(带1w文档…

亚马逊云科技官方活动:一个月拿下助理架构师SAA+云从业者考试认证(送半价折扣券)

为了帮助大家考取AWS SAA和AWS云从业者认证,小李哥争取到了大量考试半价50%折扣券,使用折扣券考试最多可省75刀(545元人民币)。 领取折扣券需要加入云师兄必过班群,在群中免费领取。目前必过班群招募到了超过200名小伙伴,名额有限…

从0到1使用vite搭建react项目保姆级教程(持续更新中)

一、vite创建react项目 要使用Vite创建一个React项目,你需要按照以下步骤操作: 1、确保你已经安装了Node.js(建议使用最新的稳定版本)。 2、 使用npm命令安装Vite CLI工具,再来创建项目 npm create vitelatest my-vi…

解决ChatGPT遇到“抱歉,我无法完成你的请求”问题

在使用ChatGPT时,可能会遇到这样的问题:当多次重复输入相同的内容时,系统会返回 抱歉,我无法完成你的请求 。本文将解释为什么会出现这种情况,并提供一些避免这种情况的解决方法。 为什么会出现“抱歉,我…

TSLANet:时间序列模型的新构思

实时了解业内动态,论文是最好的桥梁,专栏精选论文重点解读热点论文,围绕着行业实践和工程量产。若在某个环节出现卡点,可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技(Mamba,xLSTM,KAN)…

2024-6-20 Windows AndroidStudio SDK(首次加载)基础配置,SDK选项无法勾选,以及下载失败的一些解决方法

2024-6-20 Windows AndroidStudio SDK(首次加载)基础配置,SDK选项无法勾选,以及下载失败的一些解决方法 注意:仅仅是SDK这种刚安装时的配置的下载,不要和开源库的镜像源扯到一起!!!! 最近想玩AndroidStudio的JNI开发, 想着安装后…

Java三层框架的解析

引言:欢迎各位点击收看本篇博客,在历经很多的艰辛,我也是成功由小白浅浅进入了入门行列,也是收货到很多的知识,每次看黑马的JavaWeb课程视频,才使一个小菜鸡见识到了Java前后端是如何进行交互访问的&#x…

项目实训-vue(十二)

项目实训-vue(十二) 文章目录 项目实训-vue(十二)1.概述2.处理进度可视化 1.概述 本篇博客将记录我在图片上传页面中的工作。 2.处理进度可视化 除了导航栏之外,我们还需要对上传图片以及图片处理的过程以及流程进行…

数据结构-----【链表:刷题】

-------------------------------------------基础题参照leetcode---------------------------------------------------------------------------------------------------------- 【2】两数相加 /*** Definition for singly-linked list.* struct ListNode {* int val;…