基于EfficientNet-Backbone改进YOLOv7的X光安检违禁品检测预警系统

1.研究背景与意义

项目参考AAAI Association for the Advancement of Artificial Intelligence

研究背景与意义:

近年来,随着恐怖主义和犯罪活动的增加,安全检查在公共场所和交通枢纽中变得越来越重要。在这些场所,X光安检设备被广泛应用于检测和识别携带违禁品的个人物品。然而,由于人工操作的限制和视觉疲劳的影响,传统的X光安检系统存在着漏检和误报的问题。因此,开发一种高效准确的X光安检违禁品检测预警系统对于提高安全性和减少人工成本具有重要意义。

目前,深度学习技术在计算机视觉领域取得了显著的进展,特别是在目标检测任务中。YOLO(You Only Look Once)是一种流行的实时目标检测算法,其速度快且准确度高。然而,YOLOv7作为YOLO系列的最新版本,仍然存在一些问题,如检测精度不高和对小目标的检测能力较弱。

为了提高X光安检违禁品检测预警系统的性能,本研究将基于EfficientNet-Backbone对YOLOv7进行改进。EfficientNet是一种高效的卷积神经网络结构,具有更好的特征提取能力和更少的参数量。通过将EfficientNet作为YOLOv7的骨干网络,我们可以提高系统的检测精度和对小目标的检测能力。

本研究的意义主要体现在以下几个方面:

首先,通过引入EfficientNet-Backbone,我们可以提高X光安检违禁品检测预警系统的性能。EfficientNet具有更好的特征提取能力,可以更准确地识别和定位违禁品。这将大大减少漏检和误报的情况,提高安全性和效率。

其次,基于EfficientNet-Backbone改进YOLOv7的X光安检违禁品检测预警系统具有实时性。传统的X光安检系统需要人工操作和观察,耗时且容易出错。而本系统通过深度学习算法实现自动化检测和预警,可以实时地对携带违禁品的个人物品进行识别和报警,提高安全性和效率。

此外,本研究还具有一定的应用前景。X光安检违禁品检测预警系统可以广泛应用于机场、车站、商场等公共场所,有效地提高安全性和保护人民的生命财产安全。同时,该系统还可以用于执法部门的违禁品查验和调查,提供有力的证据和支持。

综上所述,基于EfficientNet-Backbone改进YOLOv7的X光安检违禁品检测预警系统具有重要的研究意义和实际应用价值。通过提高检测精度和实时性,该系统可以有效地提高安全性和减少人工成本,为公共场所和交通枢纽的安全管理提供有力支持。

2.图片演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.视频演示

基于EfficientNet-Backbone改进YOLOv7的X光安检违禁品检测预警系统_哔哩哔哩_bilibili

4.系统功能说明

  1. 导入图像时,不用显示导入路径。把导入路径那一行,统一为“成功导入图像”。

  2. 检测结果展示,原始图像(左边显示)和检测结果(右边显示),并在两个图像下方显示标题,“原始图像”和“检测结果”。

  3. 下方对话框,显示中文类别,10个类别对应中文名称别分为:饮料瓶(drink bottle)、压力容器(pressure)、打火机(lighter)、刀具(knife)、小型电子设备(small electronic equipmen)、移动电源(powerbank)、伞(umbrella)、玻璃瓶(glass bottle)、剪刀(scissor)、笔记本电脑(laptop)。 5. 检测结果图像的框框,10个类别分为3种颜色的框。3个类别分别为:
    易燃易爆品:小型电子设备(small electronic equipmen)、移动电源(powerbank)、笔记本电脑(laptop)、打火机(lighter)、压力容器(pressure)。 尖锐物品:剪刀(scissor)、刀具(knife)、伞(umbrella)。 不明液体:饮料瓶(drink bottle)、玻璃瓶(glass bottle)。且类别文字也变成中文,中英文对照表见第4条。

  4. 下方对话框,显示类别不用一一列举,写个汇总,示例如下:
    “检测到2个饮料瓶、3个打火机、3把雨伞等等”。如未检测到,则展示“未检测到违禁品”。

5.核心代码讲解

5.1 common.py

根据上述代码,我将其封装为以下类:


class AdaptiveConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, padding, stride):
        super(AdaptiveConv, self).__init__()
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, padding=padding, stride=stride)

    def forward(self, x):
        return self.conv(x)

class AttentionModule(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(AttentionModule, self).__init__()
        self.attention = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, kernel_size=..., padding=..., stride=...),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(out_channels, out_channels, kernel_size=..., padding=..., stride=...),
            nn.Sigmoid()
        )

    def forward(self, x):
        return x * self.attention(x)

class Classifier(nn.Module):
    def __init__(self, num_classes, num_anchors, in_channels):
        super(Classifier, self).__init__()
        self.num_classes = num_classes
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=num_classes * num_anchors, kernel_size=1)

    def forward(self, x):
        return self.conv(x).view(x.size(0), self.num_classes, -1)

class Regressor(nn.Module):
    def __init__(self, num_anchors, in_channels):
        super(Regressor, self).__init__()
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=4 * num_anchors, kernel_size=1)

    def forward(self, x):
        return self.conv(x).view(x.size(0), 4, -1)

在封装过程中,我将每个类的构造函数中的参数作为类的属性,并在forward方法中调用相应的nn.Module子类来实现具体的功能。

该工程中的common.py文件定义了几个神经网络模块,包括AdaptiveConv、AttentionModule、Classifier和Regressor。

AdaptiveConv模块是一个自适应卷积模块,它包含一个2D卷积层,可以根据输入特征图的尺寸进行自适应调整。

AttentionModule模块是一个注意力模块,它包含了一系列的卷积层和激活函数,用于计算输入特征图的注意力权重。

Classifier模块是一个分类器模块,它包含一个1x1的卷积层,用于将输入特征图映射到类别数乘以锚点数的通道数,并将结果reshape为(batch_size, num_classes, -1)的形状。

Regressor模块是一个回归器模块,它包含一个1x1的卷积层,用于将输入特征图映射到4乘以锚点数的通道数,并将结果reshape为(batch_size, 4, -1)的形状。

这些模块都是继承自nn.Module类,并且都实现了forward方法,用于定义模块的前向传播逻辑。

5.2 fit.py
import torch
import torch.nn as nn
from efficientnet_pytorch import EfficientNet

class CustomEfficientNet(nn.Module):
    def __init__(self, num_classes):
        super(CustomEfficientNet, self).__init__()
        self.efficientnet = EfficientNet.from_pretrained('efficientnet-b0')
        self.num_classes = num_classes
        self.fc = nn.Linear(self.efficientnet._fc.in_features, num_classes)

    def forward(self, x):
        x = self.efficientnet(x)
        x = self.fc(x)
        return x
    ......
5.2 model.py
import torch
from efficientnet_pytorch import EfficientNet
import torch.nn as nn

class YOLOv7(nn.Module):
    def __init__(self, num_classes, anchors):
        super(YOLOv7, self).__init__()
        self.backbone = EfficientNet.from_pretrained('efficientnet-b0')
        self.detect1 = DetectBlock(num_classes, anchors[0])
        self.detect2 = DetectBlock(num_classes, anchors[1])
        self.detect3 = DetectBlock(num_classes, anchors[2])

    def forward(self, x):
        features = self.backbone.extract_features(x)

        out1 = self.detect1(features[-1])
        out2 = self.detect2(features[-2])
        out3 = self.detect3(features[-3])

        # 将不同分辨率的特征图中的检测结果进行合并
        output = torch.cat([out1, out2, out3], dim=1)

        # 使用NMS算法进行去重和筛选
        detections = non_max_suppression(output)

        return detections

class DetectBlock(nn.Module):
    def __init__(self, num_classes, anchors):
        super(DetectBlock, self).__init__()
        self.adaptive_conv = AdaptiveConv()
        self.attention = AttentionModule()
        self.classifier = Classifier(num_classes, len(anchors))
        self.regressor = Regressor(len(anchors))

    def forward(self, x):
        x = self.adaptive_conv(x)
        x = self.attention(x)
        cls = self.classifier(x)
        reg = self.regressor(x)
        output = torch.cat([cls, reg], dim=1)
        return output
5.3 train.py



class YOLOTrainer:
    def __init__(self, hyp, opt, device, tb_writer=None):
        self.hyp = hyp
        self.opt = opt
        self.device = device
        self.tb_writer = tb_writer
        self.logger = logging.getLogger(__name__)
        self.save_dir = Path(opt.save_dir)
        self.epochs = opt.epochs
        self.batch_size = opt.batch_size
        self.total_batch_size = opt.total_batch_size
        self.weights = opt.weights
        self.rank = opt.global_rank
        self.freeze = opt.freeze
        self.wdir = self.save_dir / 'weights'
        self.wdir.mkdir(parents=True, exist_ok=True)  # make dir
        self.last = self.wdir / 'last.pt'
        self.best = self.wdir / 'best.pt'
        self.results_file = self.save_dir / 'results.txt'
        self.plots = not opt.evolve  # create plots
        self.cuda = device.type != 'cpu'
        self.init_seeds(2 + self.rank)
        with open(opt.data) as f:
            self.data_dict = yaml.load(f, Loader=yaml.SafeLoader)  # data dict
        self.is_coco = opt.data.endswith('coco.yaml')
        self.loggers = {'wandb': None}  # loggers dict
        if self.rank in [-1, 0]:
            self.opt.hyp = self.hyp  # add hyperparameters
            run_id = torch.load(self.weights, map_location=self.device).get('wandb_id') if self.weights.endswith('.pt') and os.path.isfile(self.weights) else None
            wandb_logger = WandbLogger(self.opt, Path(self.opt.save_dir).stem, run_id, self.data_dict)
            self.loggers['wandb'] = wandb_logger.wandb
            self.data_dict = wandb_logger.data_dict
            if wandb_logger.wandb:
                self.weights, self.epochs, self.hyp = self.opt.weights, self.opt.epochs, self.opt.hyp  # WandbLogger might update weights, epochs if resuming
        self.nc = 1 if self.opt.single_cls else int(self.data_dict['nc'])  # number of classes
        self.names = ['item'] if self.opt.single_cls and len(self.data_dict['names']) != 1 else self.data_dict['names']  # class names
        assert len(self.names) == self.nc, '%g names found for nc=%g dataset in %s' % (len(self.names), self.nc, self.opt.data)  # check
        self.pretrained = self.weights.endswith('.pt')
        if self.pretrained:
            with torch_distributed_zero_first(self.rank):
                attempt_download(self.weights)  # download if not found locally
            ckpt = torch.load(self.weights, map_location=self.device)  # load checkpoint
            self.model = Model(self.opt.cfg or ckpt['model'].yaml, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
            exclude = ['anchor'] if (self.opt.cfg or self.hyp.get('anchors')) and not self.opt.resume else []  # exclude keys
            state_dict = ckpt['model'].float().state_dict()  # to FP32
            state_dict = intersect_dicts(state_dict, self.model.state_dict(), exclude=exclude)  # intersect
            self.model.load_state_dict(state_dict, strict=False)  # load
            self.logger.info('Transferred %g/%g items from %s' % (len(state_dict), len(self.model.state_dict()), self.weights))  # report
        else:
            self.model = Model(self.opt.cfg, ch=3, nc=self.nc, anchors=self.hyp.get('anchors')).to(self.device)  # create
        with torch_distributed_zero_first(self.rank):
            check_dataset(self.data_dict)  # check
        self.train_path = self.data_dict['train']
        self.test_path = self.data_dict['val']
        self.freeze = [f'model.{x}.' for x in (self.freeze if len(self.freeze) > 1 else range(self.freeze[0]))]  # parameter names to freeze (full or partial)
        for k, v in self.model.named_parameters():
            v.requires_grad = True  # train all layers
            if any(x in k for x in self.freeze):
                print('freezing %s' % k)
                v.requires_grad = False
        self.nbs = 64  # nominal batch size
        self.accumulate = max(round(self.nbs / self.total_batch_size), 1)  # accumulate loss before optimizing
        self.hyp['weight_decay'] *= self.total_batch_size * self.accumulate / self.nbs  # scale weight_decay
        self.logger.info(f"Scaled weight_decay = {self.hyp['weight_decay']}")
        self.pg0, self.pg1, self.pg2 = [], [], []  # optimizer parameter groups
        for k, v in self.model.named_modules():
            if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):
                self.pg2.append(v.bias)  # biases
            if isinstance(v, nn.BatchNorm2d):
                self.pg0.append(v.weight)  # no decay
            elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):
                self.pg1.append(v.weight)  # apply decay
            if hasattr(v, 'im'):
                if hasattr(v.im, 'implicit'):           
                    self.pg0.append(v.im.implicit)
                else:
                    for iv in v.im:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imc'):
                if hasattr(v.imc, 'implicit'):           
                    self.pg0.append(v.imc.implicit)
                else:
                    for iv in v.imc:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imb'):
                if hasattr(v.imb, 'implicit'):           
                    self.pg0.append(v.imb.implicit)
                else:
                    for iv in v.imb:
                        self.pg0.append(iv.implicit)
            if hasattr(v, 'imo'):
                if hasattr(v.imo, 'implicit'):

这个程序文件是一个用于训练模型的脚本。它导入了一些必要的库和模块,包括argparse、logging、numpy、torch等。然后,它定义了一个train函数,该函数接受一些超参数、选项和设备信息,并进行模型训练。在训练过程中,它会加载预训练模型、配置优化器和学习率调度器、冻结部分参数、创建数据加载器等。训练过程中还会进行日志记录、模型保存和评估等操作。整个训练过程会根据设备的类型进行并行化处理。

5.4 ui.py

class YOLOv7:
    def __init__(self):
        self.imgsz = 640
        self.model = None
        self.stride = None
        self.device = None
        self.half = None

    def load_model(self, weights_path):
        set_logging()
        self.device = select_device()
        self.half = self.device.type != 'cpu'
        self.model = attempt_load(weights_path, map_location=self.device)
        self.stride = int(self.model.stride.max())
        self.imgsz = check_img_size(self.imgsz, s=self.stride)
        self.model = TracedModel(self.model, self.device, 640)
        if self.half:
            self.model.half()

    def detect(self, image_path):
        img = cv2.imread(image_path)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = Image.fromarray(img)
        img = img.resize((self.imgsz, self.imgsz))
        img = np.array(img)
        img = torch.from_numpy(img).to(self.device)
        img = img.half() if self.half else img.float()
        img /= 255.0
        if img.ndimension() == 3:
            img = img.unsqueeze(0)
        pred = self.model(img, augment=False)[0]
        pred = non_max_suppression(pred, conf_thres=0.35, iou_thres=0.15)
        results = []
        for det in pred:
            for *xyxy, conf, cls in reversed(det):
                label = self.model.module.names[int(cls)]
                results.append([label, xyxy, float(conf)])
        return results

ui.py是一个使用PyQt5创建的用户界面程序。它使用了argparse、time、pathlib、cv2、torch等库来实现图像目标检测功能。程序中定义了一个函数draw_box_string,用于在图像上绘制边界框和文字。另外,程序还定义了一个函数det_yolov7,用于使用Yolov7模型进行目标检测。该函数接受一个图像路径作为输入,并返回检测结果。最后,程序定义了一个函数yolov7,用于解析命令行参数并调用det_yolov7函数进行目标检测。

5.5 models\experimental.py

该程序文件是一个模型定义文件,命名为models\experimental.py。该文件定义了一些实验性的模型组件和模型类。

文件中定义了以下模型组件:

  • CrossConv:交叉卷积下采样模块。
  • Sum:多个层的加权和模块。
  • MixConv2d:混合深度卷积模块。
  • Ensemble:模型集合模块。

文件中定义了以下模型类:

  • ORT_NMS:使用ONNX-Runtime进行非极大值抑制(NMS)操作的模块。
  • TRT_NMS:使用TensorRT进行非极大值抑制(NMS)操作的模块。
  • ONNX_ORT:包含ONNX-Runtime NMS操作的ONNX模块。
  • ONNX_TRT:包含TensorRT NMS操作的ONNX模块。
  • End2End:将模型和NMS操作组合成一个端到端的模块。

文件还定义了一个辅助函数attempt_load,用于加载模型权重。

总体来说,该程序文件定义了一些实验性的模型组件和模型类,用于构建和加载模型。

5.6 models\yolo.py
self.kpt_m = nn.ModuleList(nn.Conv2d(x, self.no_kpt * self.na, 1) for x in ch)  # output conv for keypoints
self.kpt_ia = nn.ModuleList(ImplicitA(x) for x in ch)
self.kpt_im = nn.ModuleList(ImplicitM(self.no_kpt * self.na) for _ in ch)

该程序文件定义了一些用于目标检测和关键点检测的模型类。其中包括了Detect类、IDetect类和IKeypoint类。

Detect类是一个继承自nn.Module的目标检测模型类,它包含了一些用于目标检测的操作和网络层。它的前向传播函数实现了目标检测的推理过程,包括对输入图像进行卷积操作、计算预测框的坐标和置信度等。它还包含了一些辅助函数,用于生成网格和转换预测结果。

IDetect类是Detect类的一个变种,它在Detect类的基础上添加了一些隐式操作。它的前向传播函数在卷积操作之前先进行隐式操作,然后再进行卷积操作。它还包含了一个fuse函数,用于将隐式操作和卷积操作融合在一起。

IKeypoint类是一个继承自nn.Module的关键点检测模型类,它包含了一些用于关键点检测的操作和网络层。它的前向传播函数实现了关键点检测的推理过程,包括对输入图像进行卷积操作、计算预测框的坐标和置信度以及关键点的坐标等。它还包含了一些辅助函数,用于生成网格和转换预测结果。

5.7 models_init_.py

抱歉,您提供的代码片段不足以构建一个完整的类。请提供更多的代码,以便我可以帮助您封装为类。

这个程序文件名为models_init_.py,代码内容为# init。根据文件名可以推测这是一个Python模块的初始化文件。根据代码内容可以看出这个文件可能只是一个占位符,没有实际的功能代码。在Python中,init.py文件通常用于标识一个目录为一个Python包,可以在包中放置其他模块文件。

6.系统整体结构

整体功能和架构概述:
该程序是一个用于X光安检违禁品检测预警系统的项目,基于YOLOv7模型进行改进。它包含了多个模块和工具文件,用于实现模型训练、目标检测、数据处理、日志记录等功能。

下表整理了每个文件的功能:

文件功能
common.py包含了一些通用的模型组件,如Conv和Bottleneck等
fit.py实现了模型训练的代码,包括加载预训练模型、配置优化器和学习率调度器等
model.py定义了模型的结构和前向传播逻辑
train.py进行模型训练的主程序,包括加载模型、配置优化器和学习率调度器、创建数据加载器等
ui.py提供用户界面,调用目标检测函数进行检测
models\common.py包含一些特殊的模块,如CSP模块和Ghost模块
models\experimental.py包含一些实验性的模型组件和模型类
models\yolo.py包含YOLOv7模型的定义和前向传播逻辑
models_init_.py标识models目录为一个Python包
utils\activations.py包含一些激活函数的定义
utils\add_nms.py包含非极大值抑制(NMS)操作的定义
utils\autoanchor.py包含自动锚点生成的相关函数和类
utils\datasets.py包含数据集加载和预处理的相关函数和类
utils\general.py包含一些通用的辅助函数
utils\google_utils.py包含一些与Google Colab相关的辅助函数
utils\loss.py包含模型损失函数的定义
utils\metrics.py包含模型评估指标的定义
utils\plots.py包含绘图相关的辅助函数
utils\torch_utils.py包含与PyTorch相关的辅助函数
utils_init_.py标识utils目录为一个Python包
utils\aws\resume.py包含恢复训练的相关函数和类
utils\aws_init_.py标识utils/aws目录为一个Python包
utils\wandb_logging\log_dataset.py包含将数据集日志记录到WandB的相关函数和类
utils\wandb_logging\wandb_utils.py包含与WandB日志记录相关的辅助函数和类
utils\wandb_logging_init_.py标识utils/wandb_logging目录为一个Python包

请注意,以上是根据文件名和一些常见的模块功能进行的推测,具体的功能可能需要根据代码实现来确认。

7.数据集的采集&标注和整理

图片的收集

首先,我们需要收集所需的图片。这可以通过不同的方式来实现,例如使用现有的公开数据集X-raygates。

在这里插入图片描述

labelImg是一个图形化的图像注释工具,支持VOC和YOLO格式。以下是使用labelImg将图片标注为VOC格式的步骤:

(1)下载并安装labelImg。
(2)打开labelImg并选择“Open Dir”来选择你的图片目录。
(3)为你的目标对象设置标签名称。
(4)在图片上绘制矩形框,选择对应的标签。
(5)保存标注信息,这将在图片目录下生成一个与图片同名的XML文件。
(6)重复此过程,直到所有的图片都标注完毕。

在这里插入图片描述

由于YOLO使用的是txt格式的标注,我们需要将VOC格式转换为YOLO格式。可以使用各种转换工具或脚本来实现。

下面是一个简单的方法是使用Python脚本,该脚本读取XML文件,然后将其转换为YOLO所需的txt格式。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import xml.etree.ElementTree as ET
import os

classes = []  # 初始化为空列表

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

def convert(size, box):
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)

def convert_annotation(image_id):
    in_file = open('./label_xml\%s.xml' % (image_id), encoding='UTF-8')
    out_file = open('./label_txt\%s.txt' % (image_id), 'w')  # 生成txt格式文件
    tree = ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        cls = obj.find('name').text
        if cls not in classes:
            classes.append(cls)  # 如果类别不存在,添加到classes列表中
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

xml_path = os.path.join(CURRENT_DIR, './label_xml/')

# xml list
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
    label_name = img_xml.split('.')[0]
    print(label_name)
    convert_annotation(label_name)

print("Classes:")  # 打印最终的classes列表
print(classes)  # 打印最终的classes列表

整理数据文件夹结构

我们需要将数据集整理为以下结构:

-----data
   |-----train
   |   |-----images
   |   |-----labels
   |
   |-----valid
   |   |-----images
   |   |-----labels
   |
   |-----test
       |-----images
       |-----labels

确保以下几点:

所有的训练图片都位于data/train/images目录下,相应的标注文件位于data/train/labels目录下。
所有的验证图片都位于data/valid/images目录下,相应的标注文件位于data/valid/labels目录下。
所有的测试图片都位于data/test/images目录下,相应的标注文件位于data/test/labels目录下。
这样的结构使得数据的管理和模型的训练、验证和测试变得非常方便。

模型训练
 Epoch   gpu_mem       box       obj       cls    labels  img_size
 1/200     20.8G   0.01576   0.01955  0.007536        22      1280: 100%|██████████| 849/849 [14:42<00:00,  1.04s/it]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:14<00:00,  2.87it/s]
             all       3395      17314      0.994      0.957      0.0957      0.0843

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 2/200     20.8G   0.01578   0.01923  0.007006        22      1280: 100%|██████████| 849/849 [14:44<00:00,  1.04s/it]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|██████████| 213/213 [01:12<00:00,  2.95it/s]
             all       3395      17314      0.996      0.956      0.0957      0.0845

 Epoch   gpu_mem       box       obj       cls    labels  img_size
 3/200     20.8G   0.01561    0.0191  0.006895        27      1280: 100%|██████████| 849/849 [10:56<00:00,  1.29it/s]
           Class     Images     Labels          P          R     mAP@.5 mAP@.5:.95: 100%|███████   | 187/213 [00:52<00:00,  4.04it/s]
             all       3395      17314      0.996      0.957      0.0957      0.0845

8.EfficientNet骨干网络

EfficientNet架构

EficientNet的主要思路是使用神经网络架构搜索来找到一个既高效又准确的网络结构。该方法同时考虑网络的深度、宽度和分辨率,使用弱化的约束和搜索算法来生成—系列不同规模的网络。
具体来说,EficientNet使用一个称为Compound Scaling的方法来调整网络的深度、宽度和分辨率。Compound Scaling的核心思想是通过对网络的每个维度进行缩放来平衡准确率和计算复杂度。在Compound Scaling中,网络的深度、宽度和分辨率是通过一个共同的缩放因子来调整的,即:
在这里插入图片描述

其中,dl表示网络深度,u表示网络宽度,r表示输入图像的分辨率,α.β、y是缩放因子,d是一个控制网络规模的超参数。
在这个基础上,EificientNet使用了一种称为MBConv的块作为网络的基本构建单元。MBConv块中包含一个深度可分离卷积层
(Depthwise Separable Convolution)和一个线性变换层,其中深度可分离卷积层是一种先对每个通道进行卷积,再对所有通道进行融合的卷积方式。使用深度可分离卷积层可以大大减少网络参数和计算量,提高模型的效率。
最终,EficientNet可以生成一系列不同规模的网络,包括EfficientNet-BO、B1、B2、B3、B4、B5和B6等。这些网络在ImageNe分类和coCO检测等任务上表现出了优秀的性能。

EfficientNet在目标检测中的应用

EficientNet已经被广泛应用于各种目标检测任务中。与其他骨干网络相比,EficientNet在保持相同计算复杂度的前提下,可以提高目标检测的准确性。以下是EfficientNet在目标检测中的应用。
EficientNet作为目标检测模型的骨干网络,可以提取输入图像的特征信息,并将其输入到后续的目标检测模块中。在使用EficientNet作为骨干网络的目标检测模型中,可以通过增加模型的深度、宽度和分辨率等方面来提高模型的准确性。同时,由于EficientNet在计算资源有限的情况下可以提高模型的准确率,因此可以加速模型的训练和推理速度,降低计算成本。
下面以使用EfficientNet作为骨干网络的目标检测模型RetinaNet为例,介绍EfficientNet在目标检测中的具体应用。

RetinaNet是一种基于FocalLoss的单阶段目标检测模型,采用了EfficientNet作为骨干网络。在RetinaNet中,EficientNet被用于提取输入图像的特征信息,并将其送入到后续的目标检测模块中。具体来说,EificientNet会通过一系列的卷积、池化等操作,将输入图像转化为一组高维特征向量。
RetinaNet的目标检测模块由两个子网络组成,分别是回归子网络和分类子网络。其中,回归子网络用于预测目标框的位置和大小,分类子网络用于预测目标框中物体的类别。这两个子网络都是基于EficientNet提取的特征向量构建的,因此可以通过对EficientNet的优化来提高RetinaNet的检测准确率。
RetinaNet乘用了Focal Loss来解决目标检测中正负样本不平衡的问题。具体来说,Focal Loss将一些难以分类的样本〈(如背景噪声、小目标等)的损失函数进行放缩,从而使得这些样本的贡献变得更小。这样可以有效提高模型对难以分类的样本的识别能力。
通过使用EficientNet作为骨干网络,可以提高目标检测模型的准确性和速度,减少计算成本。在实际应用中,可以根据任务需求选择不同版本的EfficientNet模型,以达到更好的性能和效果。

EfficientNet分辨率的缩放

EficientNet的一个重要特点是可以通过改变网络的深度、宽度和分辨率等超参数来调整网络的复杂度和准确性。其中,分辨率的缩放是一种常用的调整方法,可以根据输入图像的大小和任务需求,灵活地调整网络的分辨率,从而提高网络的准确性和速度。
在EficientNet中,分辨率的缩放是通过对网络的输入分辨率进行调整来实现的。具体来说,可以将输入图像的分辨率缩小或放大一定比例,然后将缩放后的图像送入网络中进行训练或推理。一般来说,较小的输入分辨率可以提高模型的速度和计算效率,但会降低模型的准确性;而较大的输入分辨率可以提高模型的准确性,但会增加计算成本和模型大小。

EfficientNet深度与宽度的缩放

除了分辨率的缩放外,EficientNet还可以通过改变网络的深度和宽度来调整网络的复杂度和准确性。其中,深度和宽度的缩放可以通过改变网络中的卷积层数和卷积核数量来实现。在EfficientNet中,深度和宽度的缩放可以通过调整网络的超参数来实现。具体来说,
EficientNet使用了一组复合系数来控制网络深度和宽度的缩放比例。这些复合系数被用于计算每个网络层中的卷积核数量和扩张比例。通过调整这些复合系数,可以在保持网络计算量不变的情况下增加或减少网络的深度和宽度,以达到更好的性能和效果。

在这里插入图片描述
在上面的代码中,我们首先使用from_pretrained方法加载预训练的EfficientNet模型,并将其保存在model变量中。接着我们使用from_name方法创建一个新的EfficientNet模型,将深度和宽度分别缩小了一半,并将其保存在new_model变量中。最后,我们输出新模型的结构。
通过上面的示例代码,我们可以看到如何使用EfficientNet在PyTorch中实现深度和宽度的缩放。实际上,我们可以通过调整width_coefficient和depth_coefficient这两个超参数来控制模型的深度和宽度,以适应不同的任务需求。同时,由于EfficientNet在保持模型复杂度不变的情况下可以提高模型的准确率,因此可以通过缩小深度和宽度来减少计算成本,提高模型的效率。

9.YOLOv7的网络结构

骨干网络

在这里插入图片描述

YOLOv7使用了EfficientNet作为骨干网络,具有以下几个优点

1.高效性:EfficientNet是一种高效的卷积神经网络,可以在计算资源有限的情况下提高模型的准确率。2.多尺度处理:EfficientNet可以通过不同的深度、宽度和分辨率等参数来处理不同大小的目标。
3.自适应卷积: YOLOv7使用了自适应卷积来适应不同大小的目标,并可以在不同分辨率的特征图上执行卷积操作,从而提高了模型的感知能力。
4.注意力机制:YOLO7使用了注意力机制来增强模型对不同区域的感知能力,从而可以更好地处理复杂场景和不同尺度的目标。
5.多级特征融合: YOLOv7采用了特征金字塔来处理不同大小的目标,可以在不同尺度的特征图上进行检测,并且使用了多级特征融合来提高模型的检测精度。

下面是YOLOv7中EfficientNet的具体应用过程

1.输入图像经过EfficientNet骨干网络,提取高级特征,得到一系列不同分辨率的特征图。
⒉特征图分别送入不同的检测分支中进行检测。每个分支都包含一个自适应卷积层和一个注意力模块,以及分类子网络和回归子网络3.自适应卷积层可以根据目标大小自适应地调整卷积核的大小,从而更好地处理不同大小的目标。注意力模块可以增强模型对不同区域的感知能力,提高模型的检测精度。
4.分类子网络用于预测检测框中物体的类别,回归子网络用于预测检测框的位置和大小。
5.为了处理不同大小的目标使用了特征金字塔和多级特征融合。特征金字塔可以在不同尺度的特征图上进行检测,从而可以检测不同大小的目标。多级特征融合可以将不同尺度的特征图融合在一起,提高模型的检测精度。
6.将不同分辨率的特征图中的检测结果进行合并,并使用非极大值抑制(NMS)算法进行去重和筛选,得到最终的检测结果。

10.系统整合

下图完整源码&数据集&环境部署视频教程&自定义UI界面

在这里插入图片描述

参考博客《基于EfficientNet-Backbone改进YOLOv7的X光安检违禁品检测预警系统》

12.参考文献


[1]康佳楠,张良.多通道区域建议的多尺度X光安检图像检测[J].计算机工程与应用.2022,58(1).DOI:10.3778/j.issn.1002-8331.2008-0345 .

[2]张友康,苏志刚,张海刚,等.X光安检图像多尺度违禁品检测[J].信号处理.2020,(7).DOI:10.16798/j.issn.1003-0530.2020.07.008 .

[3]苏志刚,姚少卿.基于语义分割的多目标违禁品识别算法[J].信号处理.2020,(11).DOI:10.16798/j.issn.1003-0530.2020.11.017 .

[4]姚少卿,苏志刚.基于轻量化分割网络的违禁品识别算法[J].激光与光电子学进展.2021,(2).DOI:10.3788/LOP202158.0210022 .

[5]郭守向,张良.Yolo-C:基于单阶段网络的X光图像违禁品检测[J].激光与光电子学进展.2021,58(8).67-76.

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值