改进yolo11-FocusedLinearAttention等200+全套创新点大全:【无人零售】自动售卖机饮料检测系统源码&数据集全套
1.图片效果展示
项目来源 人工智能促进会 2024.11.03
注意:由于项目一直在更新迭代,上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可能为老版本,新版本在老版本的基础上升级如下:(实际效果以升级的新版本为准)
(1)适配了YOLOV11的“目标检测”模型和“实例分割”模型,通过加载相应的权重(.pt)文件即可自适应加载模型。
(2)支持“图片识别”、“视频识别”、“摄像头实时识别”三种识别模式。
(3)支持“图片识别”、“视频识别”、“摄像头实时识别”三种识别结果保存导出,解决手动导出(容易卡顿出现爆内存)存在的问题,识别完自动保存结果并导出到tempDir中。
(4)支持Web前端系统中的标题、背景图等自定义修改。
另外本项目提供训练的数据集和训练教程,暂不提供权重文件(best.pt),需要您按照教程进行训练后实现图片演示和Web前端界面演示的效果。
2.视频效果展示
2.1 视频效果展示
3.背景
研究背景与意义
随着科技的迅猛发展和消费者购物习惯的改变,无人零售逐渐成为现代商业的一种新兴模式。无人零售自动售卖机以其便捷性和高效性,受到了越来越多消费者的青睐。然而,自动售卖机在商品管理和库存监控方面仍面临诸多挑战,尤其是在饮料产品的实时检测与识别方面。为了解决这一问题,基于改进YOLOv11的饮料检测系统应运而生。
YOLO(You Only Look Once)系列模型以其快速且准确的目标检测能力而广泛应用于各种计算机视觉任务。YOLOv11作为该系列的最新版本,进一步提升了检测精度和速度,适合在资源有限的自动售卖机环境中进行实时处理。针对饮料产品的检测,研究团队选取了包含2200张图像的“soda bottles”数据集,数据集中涵盖了多种知名饮料品牌,如可口可乐、芬达和雪碧等。该数据集的单一类别特性,使得模型在训练过程中能够集中精力于特定对象的识别,从而提高检测的准确性。
本研究的意义在于,通过改进YOLOv11模型,构建一个高效的饮料检测系统,不仅能够实时监控自动售卖机内的饮料库存,还能通过数据分析优化补货策略,提升运营效率。此外,该系统的成功实施将为无人零售行业提供一种可行的技术解决方案,推动无人零售的进一步发展。同时,基于深度学习的目标检测技术在其他领域的应用也将得到启示,具有广泛的推广价值。通过本项目的研究,期望能够为无人零售行业的智能化转型提供坚实的技术支持。
4.数据集信息展示
4.1 本项目数据集详细数据(类别数&类别名)
nc: 3
names: [‘coca-cola’, ‘fanta’, ‘sprite’]
该项目为【目标检测】数据集,请在【训练教程和Web端加载模型教程(第三步)】这一步的时候按照【目标检测】部分的教程来训练
4.2 本项目数据集信息介绍
本项目数据集信息介绍
本项目所使用的数据集名为“soda bottles”,专门用于训练和改进YOLOv11模型,以实现无人零售自动售卖机中的饮料检测系统。该数据集包含三种主要类别的饮料,分别是可口可乐(coca-cola)、芬达(fanta)和雪碧(sprite)。这些类别的选择不仅反映了市场上最受欢迎的饮料品牌,也为模型的训练提供了丰富的样本,确保其在实际应用中的准确性和可靠性。
数据集的构建过程经过精心设计,确保每个类别的样本数量均衡且多样化,以便模型能够有效学习到不同饮料的特征。数据集中包含了各种环境下的饮料图像,包括不同的光照条件、拍摄角度和背景,这些因素都可能影响模型的识别能力。因此,数据集中的图像涵盖了多种场景,以增强模型的泛化能力,确保其在实际应用中能够准确识别和分类。
此外,数据集还经过了详细的标注,每张图像中的饮料瓶都被精确框定,提供了必要的位置信息。这一过程不仅提高了数据集的质量,也为YOLOv11模型的训练提供了坚实的基础。通过使用“soda bottles”数据集,我们期望能够提升无人零售自动售卖机的饮料检测精度,从而优化消费者的购物体验,推动无人零售技术的发展。
综上所述,“soda bottles”数据集为本项目提供了丰富的训练素材和高质量的标注信息,确保了模型在实际应用中的有效性和准确性,为无人零售领域的创新与发展奠定了坚实的基础。
5.全套项目环境部署视频教程(零基础手把手教学)
5.1 所需软件PyCharm和Anaconda安装教程(第一步)
5.2 安装Python虚拟环境创建和依赖库安装视频教程(第二步)
6.改进YOLOv11训练教程和Web_UI前端加载模型教程(零基础手把手教学)
6.1 改进YOLOv11训练教程和Web_UI前端加载模型教程(第三步)
按照上面的训练视频教程链接加载项目提供的数据集,运行train.py即可开始训练
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
项目数据集下载链接
7.原始YOLOv11算法讲解
YOLO11简介
YOLO11源码地址:https://github.com/ultralytics/ultralytics
Ultralytics
YOLO11是一款尖端的、最先进的模型,它在之前YOLO版本成功的基础上进行了构建,并引入了新功能和改进,以进一步提升性能和灵活性。YOLO11设计快速、准确且易于使用,使其成为各种物体检测和跟踪、实例分割、图像分类以及姿态估计任务的绝佳选择。
YOLO11创新点如下:
YOLO 11主要改进包括:增强的特征提取
:YOLO 11采用了改进的骨干和颈部架构,增强了特征提取功能,以实现更精确的目标检测。优化的效率和速度
:优化的架构设计和优化的训练管道提供更快的处理速度,同时保持准确性和性能之间的平衡。更高的精度,更少的参数
:YOLO11m在COCO数据集上实现了更高的平均精度(mAP),参数比YOLOv8m少22%,使其在不影响精度的情况下提高了计算效率。跨环境的适应性
:YOLO 11可以部署在各种环境中,包括边缘设备、云平台和支持NVIDIA GPU的系统。广泛的支持任务
:YOLO 11支持各种计算机视觉任务,如对象检测、实例分割、图像分类、姿态估计和面向对象检测(OBB)。
YOLO11不同模型尺寸信息:
YOLO11 提供5种不同的型号规模模型,以满足不同的应用需求:
Model| size (pixels)| mAPval 50-95| Speed CPU ONNX (ms)| Speed T4 TensorRT10
(ms)| params (M)| FLOPs (B)
—|—|—|—|—|—|—
YOLO11n| 640| 39.5| 56.1 ± 0.8| 1.5 ± 0.0| 2.6| 6.5
YOLO11s| 640| 47.0| 90.0 ± 1.2| 2.5 ± 0.0| 9.4| 21.5
YOLO11m| 640| 51.5| 183.2 ± 2.0| 4.7 ± 0.1| 20.1| 68.0
YOLO11l| 640| 53.4| 238.6 ± 1.4| 6.2 ± 0.1| 25.3| 86.9
YOLO11x| 640| 54.7| 462.8 ± 6.7| 11.3 ± 0.2| 56.9| 194.9
模型常用训练超参数参数说明:YOLOv11 模型的训练设置包括训练过程中使用的各种超参数和配置
。这些设置会影响模型的性能、速度和准确性。关键的训练设置包括批量大小、学习率、动量和权重衰减。此外,优化器、损失函数和训练数据集组成的选择也会影响训练过程。对这些设置进行仔细的调整和实验对于优化性能至关重要。
以下是一些常用的模型训练参数和说明:
参数名 | 默认值 | 说明 |
---|---|---|
model |
None |
指定用于训练的模型文件。接受指向 .pt 预训练模型或 .yaml
|
配置文件。对于定义模型结构或初始化权重至关重要。 | ||
data |
None |
数据集配置文件的路径(例如 |
coco8.yaml ).该文件包含特定于数据集的参数,包括训练数据和验证数据的路径、类名和类数。 |
||
epochs |
100 |
训练总轮数。每个epoch代表对整个数据集进行一次完整的训练。调整该值会影响训练时间和模型性能。 |
patience |
100 |
在验证指标没有改善的情况下,提前停止训练所需的epoch数。当性能趋于平稳时停止训练,有助于防止过度拟合。 |
batch |
16 |
批量大小,有三种模式:设置为整数(例如,’ Batch =16 ‘), 60% GPU内存利用率的自动模式(’ Batch |
=-1 ‘),或指定利用率分数的自动模式(’ Batch =0.70 ')。 | ||
imgsz |
640 |
用于训练的目标图像尺寸。所有图像在输入模型前都会被调整到这一尺寸。影响模型精度和计算复杂度。 |
device |
None |
指定用于训练的计算设备:单个 GPU (device=0 )、多个 GPU (device=0,1 )、CPU |
(device=cpu ),或苹果芯片的 MPS (device=mps ). |
||
workers |
8 |
加载数据的工作线程数(每 RANK 多 GPU 训练)。影响数据预处理和输入模型的速度,尤其适用于多 GPU 设置。 |
name |
None |
训练运行的名称。用于在项目文件夹内创建一个子目录,用于存储训练日志和输出结果。 |
pretrained |
True |
决定是否从预处理模型开始训练。可以是布尔值,也可以是加载权重的特定模型的字符串路径。提高训练效率和模型性能。 |
optimizer |
'auto' |
为训练模型选择优化器。选项包括 SGD , Adam , AdamW , NAdam , |
RAdam , RMSProp 等,或 auto 用于根据模型配置进行自动选择。影响收敛速度和稳定性 |
||
lr0 |
0.01 |
初始学习率(即 SGD=1E-2 , Adam=1E-3 ) .调整这个值对优化过程至关重要,会影响模型权重的更新速度。 |
lrf |
0.01 |
最终学习率占初始学习率的百分比 = (lr0 * lrf ),与调度程序结合使用,随着时间的推移调整学习率。 |
各损失函数作用说明:定位损失box_loss
:预测框与标定框之间的误差(GIoU),越小定位得越准;分类损失cls_loss
:计算锚框与对应的标定分类是否正确,越小分类得越准;动态特征损失(dfl_loss)
:DFLLoss是一种用于回归预测框与目标框之间距离的损失函数。在计算损失时,目标框需要缩放到特征图尺度,即除以相应的stride,并与预测的边界框计算Ciou
Loss,同时与预测的anchors中心点到各边的距离计算回归DFLLoss。
8.200+种全套改进YOLOV11创新点原理讲解
8.1 200+种全套改进YOLOV11创新点原理讲解大全
由于篇幅限制,每个创新点的具体原理讲解就不全部展开,具体见下列网址中的改进模块对应项目的技术原理博客网址【Blog】(创新点均为模块化搭建,原理适配YOLOv5~YOLOv11等各种版本)
改进模块技术原理博客【Blog】网址链接
8.2 精选部分改进YOLOV11创新点原理讲解
这里节选部分改进创新点展开原理讲解(完整的改进原理见上图和改进模块技术原理博客链接【如果此小节的图加载失败可以通过****或者Github搜索该博客的标题访问原始博客,原始博客图片显示正常】
Context_Grided_Network(CGNet)简介
参考该博客提出的一种轻量化语义分割模型Context Grided Network(CGNet),以满足设备的运行需要。
CGNet主要由CG块构建而成,CG块可以学习局部特征和周围环境上下文的联合特征,最后通过引入全局上下文特征进一步改善联合特征的学习。
下图给出了在Cityscapes数据集上对现有的一些语义分割模型的测试效果,横轴表示参数量,纵轴表示准确率(mIoU)。可以看出,在参数量较少的情况下,CGNet可以达到一个比较好的准确率。虽与高精度模型相去甚远,但在一些对精度要求不高、对实时性要求比较苛刻的情况下,很有价值。
高精度模型,如DeepLab、DFN、DenseASPP等,动不动就是几十M的参数,很难应用在移动设备上。而上图中红色的模型,相对内存占用较小,但它们的分割精度却不是很高。作者认为主要原因是,这些小网络大多遵循着分类网络的设计思路,并没有考虑语义分割任务更深层次的特点。
空间依赖性和上下文信息对提高分割精度有很大的作用。作者从该角度出发,提出了CG block,并进一步搭建了轻量级语义分割网络CGNet。CG块具有以下特点:
学习局部特征和上下文特征的联合特征;
通过全局上下文特征改进上述联合特征;
可以贯穿应用在整个网络中,从low level(空间级别)到high level(语义级别)。不像PSPNet、DFN、DenseASPP等,只在编码阶段以后捕捉上下文特征。;
只有3个下采样,相比一般5个下采样的网络,能够更好地保留边缘信息。
CGNet遵循“深而薄”的原则设计,整个网络又51层构成。其中,为了降低计算,大量使用了channel-wise conv.
小型语义分割模型:
需要平衡准确率和系统开销
进化路线:ENet -> ICNet -> ESPNet
这些模型基本都基于分类网络设计,在分割准确率上效果并不是很好
上下文信息模型:
大多数现有模型只考虑解码阶段的上下文信息并且没有利用周围的上下文信息
注意力机制:
CG block使用全局上下文信息计算权重向量,并使用其细化局部特征和周围上下文特征的联合特征
Context Guided Block
CG block由4部分组成:
此外,CG block还采用了残差学习。文中提出了局部残差学习(LRL)和全局残差学习(GRL)两种方式。 LRL添加了从输入到联合特征提取器的连接,GRL添加了从输入到全局特征提取器的连接。从直观上来说,GRL比LRL更能促进网络中的信息传递(更像ResNet~~),后面实验部分也进行了测试,的确GRL更能提升分割精度。
CGNet的通用网络结构如下图所示,分为3个stage,第一个stage使用3个卷积层抽取特征,第二和第三个stage堆叠一定数量的CG block,具体个数可以根据情况调整。最后,通过1x1 conv得到分割结果。
下图是用于Cityscapes数据集的CGNet网络细节说明:输入尺寸为3680680;stage1连续使用了3个Conv-BN-PReLU组合,首个组合使用了stride=2的卷积,所以得到了1/2分辨率的feature map;stage2和stage3分别使用了多个CG block,且其中使用了不同大小的膨胀卷积核,最终分别得到了1/4和1/8的feature map。
需注意:
stage2&3的输入特征分别由其上一个stage的首个和最后一个block组合给出(参考上图的绿色箭头);
输入注入机制,图中未体现,实际使用中,作者还将输入图像下采样1/4或1/8,分别给到stage2和stage3的输入中 ,以进一步加强特征传递。
channel-wise conv。为了缩减参数数量,在局部特征提取器和周围上下文特征提取器中使用了channel-wise卷积,可以消除跨通道的计算成本,同时节省内存占用。但是,没有像MobileNet等模型一样,在depth-wise卷积后面接point-wise卷积(11 conv),作者解释是,因为CG block需要保持局部特征和周围上下文特征的独立性,而11 conv会破坏这种独立性,所以效果欠佳,实验部分也进行了验证。
个人感觉此处应该指的是depth-wise卷积?
官方Git中对该部分的实现如下:
9.系统功能展示
图9.1.系统支持检测结果表格显示
图9.2.系统支持置信度和IOU阈值手动调节
图9.3.系统支持自定义加载权重文件best.pt(需要你通过步骤5中训练获得)
图9.4.系统支持摄像头实时识别
图9.5.系统支持图片识别
图9.6.系统支持视频识别
图9.7.系统支持识别结果文件自动保存
图9.8.系统支持Excel导出检测结果数据
10. YOLOv11核心改进源码讲解
10.1 kan_conv.py
以下是对代码的核心部分进行提炼和详细注释的结果:
import torch
import torch.nn as nn
class KANConvNDLayer(nn.Module):
def __init__(self, conv_class, norm_class, input_dim, output_dim, spline_order, kernel_size,
groups=1, padding=0, stride=1, dilation=1,
ndim: int = 2, grid_size=5, base_activation=nn.GELU, grid_range=[-1, 1], dropout=0.0):
super(KANConvNDLayer, self).__init__()
# 初始化参数
self.inputdim = input_dim # 输入维度
self.outdim = output_dim # 输出维度
self.spline_order = spline_order # 样条的阶数
self.kernel_size = kernel_size # 卷积核大小
self.padding = padding # 填充
self.stride = stride # 步幅
self.dilation = dilation # 膨胀
self.groups = groups # 分组数
self.ndim = ndim # 维度(1D, 2D, 3D)
self.grid_size = grid_size # 网格大小
self.base_activation = base_activation() # 基础激活函数
self.grid_range = grid_range # 网格范围
# 初始化dropout层
self.dropout = None
if dropout > 0:
if ndim == 1:
self.dropout = nn.Dropout1d(p=dropout)
elif ndim == 2:
self.dropout = nn.Dropout2d(p=dropout)
elif ndim == 3:
self.dropout = nn.Dropout3d(p=dropout)
# 检查分组参数的有效性
if groups <= 0:
raise ValueError('groups must be a positive integer')
if input_dim % groups != 0:
raise ValueError('input_dim must be divisible by groups')
if output_dim % groups != 0:
raise ValueError('output_dim must be divisible by groups')
# 初始化基础卷积层
self.base_conv = nn.ModuleList([conv_class(input_dim // groups,
output_dim // groups,
kernel_size,
stride,
padding,
dilation,
groups=1,
bias=False) for _ in range(groups)])
# 初始化样条卷积层
self.spline_conv = nn.ModuleList([conv_class((grid_size + spline_order) * input_dim // groups,
output_dim // groups,
kernel_size,
stride,
padding,
dilation,
groups=1,
bias=False) for _ in range(groups)])
# 初始化归一化层
self.layer_norm = nn.ModuleList([norm_class(output_dim // groups) for _ in range(groups)])
# 初始化PReLU激活函数
self.prelus = nn.ModuleList([nn.PReLU() for _ in range(groups)])
# 生成样条网格
h = (self.grid_range[1] - self.grid_range[0]) / grid_size
self.grid = torch.linspace(
self.grid_range[0] - h * spline_order,
self.grid_range[1] + h * spline_order,
grid_size + 2 * spline_order + 1,
dtype=torch.float32
)
# 使用Kaiming均匀分布初始化卷积层权重
for conv_layer in self.base_conv:
nn.init.kaiming_uniform_(conv_layer.weight, nonlinearity='linear')
for conv_layer in self.spline_conv:
nn.init.kaiming_uniform_(conv_layer.weight, nonlinearity='linear')
def forward_kan(self, x, group_index):
# 基础卷积的前向传播
base_output = self.base_conv[group_index](self.base_activation(x))
# 扩展输入维度以进行样条操作
x_uns = x.unsqueeze(-1)
target = x.shape[1:] + self.grid.shape
grid = self.grid.view(*list([1 for _ in range(self.ndim + 1)] + [-1, ])).expand(target).contiguous().to(x.device)
# 计算样条基
bases = ((x_uns >= grid[..., :-1]) & (x_uns < grid[..., 1:])).to(x.dtype)
# 计算多阶样条基
for k in range(1, self.spline_order + 1):
left_intervals = grid[..., :-(k + 1)]
right_intervals = grid[..., k:-1]
delta = torch.where(right_intervals == left_intervals, torch.ones_like(right_intervals),
right_intervals - left_intervals)
bases = ((x_uns - left_intervals) / delta * bases[..., :-1]) + \
((grid[..., k + 1:] - x_uns) / (grid[..., k + 1:] - grid[..., 1:(-k)]) * bases[..., 1:])
bases = bases.contiguous()
bases = bases.moveaxis(-1, 2).flatten(1, 2)
# 通过样条卷积层进行前向传播
spline_output = self.spline_conv[group_index](bases)
x = self.prelus[group_index](self.layer_norm[group_index](base_output + spline_output))
# 应用dropout
if self.dropout is not None:
x = self.dropout(x)
return x
def forward(self, x):
# 将输入按组分割并进行前向传播
split_x = torch.split(x, self.inputdim // self.groups, dim=1)
output = []
for group_ind, _x in enumerate(split_x):
y = self.forward_kan(_x.clone(), group_ind)
output.append(y.clone())
y = torch.cat(output, dim=1) # 合并输出
return y
# KANConv3DLayer, KANConv2DLayer, KANConv1DLayer 类分别继承自 KANConvNDLayer
# 这些类的构造函数只需传入相应的卷积和归一化类
class KANConv3DLayer(KANConvNDLayer):
def __init__(self, input_dim, output_dim, kernel_size, spline_order=3, groups=1, padding=0, stride=1, dilation=1,
grid_size=5, base_activation=nn.GELU, grid_range=[-1, 1], dropout=0.0):
super(KANConv3DLayer, self).__init__(nn.Conv3d, nn.InstanceNorm3d,
input_dim, output_dim,
spline_order, kernel_size,
groups=groups, padding=padding, stride=stride, dilation=dilation,
ndim=3,
grid_size=grid_size, base_activation=base_activation,
grid_range=grid_range, dropout=dropout)
class KANConv2DLayer(KANConvNDLayer):
def __init__(self, input_dim, output_dim, kernel_size, spline_order=3, groups=1, padding=0, stride=1, dilation=1,
grid_size=5, base_activation=nn.GELU, grid_range=[-1, 1], dropout=0.0):
super(KANConv2DLayer, self).__init__(nn.Conv2d, nn.InstanceNorm2d,
input_dim, output_dim,
spline_order, kernel_size,
groups=groups, padding=padding, stride=stride, dilation=dilation,
ndim=2,
grid_size=grid_size, base_activation=base_activation,
grid_range=grid_range, dropout=dropout)
class KANConv1DLayer(KANConvNDLayer):
def __init__(self, input_dim, output_dim, kernel_size, spline_order=3, groups=1, padding=0, stride=1, dilation=1,
grid_size=5, base_activation=nn.GELU, grid_range=[-1, 1], dropout=0.0):
super(KANConv1DLayer, self).__init__(nn.Conv1d, nn.InstanceNorm1d,
input_dim, output_dim,
spline_order, kernel_size,
groups=groups, padding=padding, stride=stride, dilation=dilation,
ndim=1,
grid_size=grid_size, base_activation=base_activation,
grid_range=grid_range, dropout=dropout)