【大作业-50】基于YOLO12的人体关键点检测和姿态估计
🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳
【大作业-50】基于YOLO12的人体关键点检测和姿态估计
🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳🥳
大家好,今天我们来说一下人体关键点检测和行为识别。之前我们有通过直接识别目标边界框的类别的方式来完成目标检测任务,但是这种方式主要适合那种静态的或者比较单一的动作,无法识别连续的动作。所以本期我们来说一下人体关键点检测,并使用人体关键点的信息来完成人体动作的判断。数据我们使用的是coco的pose数据,由于本期数据比较大,所以我们的训练还是放在服务器上进行,训练得到模型之后在我们的本地进行推理,没有GPU的小伙伴也不用担心,大家可以使用蓝耘的云服务器来完成训练。
姿态估计是一项涉及识别图像中特定点(通常称为关键点)位置的任务。关键点可以代表物体的各个部分,如关节、地标或其他显著特征。关键点的位置通常用一组二维 [x, y]
或 3D [x, y, visible]
坐标姿态估计模型的输出是一组代表图像中物体关键点的点,通常还包括每个点的置信度分数。当您需要识别场景中物体的特定部分及其相互之间的位置关系时,姿态估计是一个不错的选择。我们这次使用到的数据集中包含了17个人体的关键点,每个关键点表示人体的不同部位,以下是每个索引到相应身体关节的映射。
鼻子
左眼
右眼
左耳
右耳
左肩
右肩
左肘
右肘
左腕
右手腕
左髋关节
右髋关节
左膝
右膝盖
左脚踝
右脚踝
以下是部分数据示例。
下面是部分实现效果,支持视频和图像检测。
项目实战
进行项目实战之前请务必安装好pytorch和miniconda。
不会的小伙伴请看这里:Python项目配置前的准备工作-CSDN博客
配置之前首先需要下载项目资源包,项目资源包请看从上方视频的置顶评论中或者是博客绑定资源获取即可。
蓝耘GPU服务器训练
目前蓝耘GPU可以薅羊毛,推荐小伙伴从这个网站使用GPU云来进行训练,新用户注册会获得30元的代金券。
注册地址:蓝耘GPU智算云平台
账号完成注册之后,登录进入蓝耘的主界面中,在主界面中,我们首先需要完成服务器的创建。在容器云市场中找到自己想要使用的服务器然后点击立即购买,本次演示我们使用3090来进行完成。
点击完成立即购买之后,我们就可以进行配置信息的确认界面,由于本次我们使用到的数据集比较大,所以我们选择了数据盘的扩容,如果小伙伴们平时在自己使用的过程中也需要使用到比较大的数据,也可以和我这里一样通过扩容来完成硬盘容量的增加。
之后我们只需要点击立即购买就可以完成实例的创建,创建完成之后通过下面的jupyterlab进入到实例当中,如下所示。
首先我们来到lanyun-tmp的目录下,建立本次我们的项目目录,如下所示。
建立之后将我们的数据集和代码文件传输到服务器上,传输的过程时间会比较长,考虑到传输的稳定性,这里建议大家使用xftp来完成文件的传输。
链接之后将我们本地的数据集和代码上传到平台上即可,如图所示,下方会显示模型传输的进度,实测蓝耘的传输还是非常不错的,不会降速。
文件传输完成之后,我们先将数据和代码解压,之后就可以来配置环境了。
因为我们之前在选择服务器镜像的时候已经提前选了torch,所以今天我们的服务器配置可以直接省去torch的配置,我们来直接看下torch和gpu有没有问题,如下,如果可以正确地输出服务器的信息以及可以正确的输出显卡的信息说明我们的配置是没有问题的。
接下来,只需要在代码目录下执行下列的指令即可完成数据集的配置,非常方便。
pip install -v -e .
执行结束的截图如下所示,如果出现下面的字样说明你的安装是没有问题的。
接下来我们只需要将数据集的地址配置为服务器上的地址即可开始训练了,非常方便。
开始训练 ,出现了这样的进度条表示已经开始训练了,等待训练结束即可。
本地模型训练
环境配置请看这里:【肆十二】YOLO系列代码环境配置统一流程-CSDN博客
模型训练使用的脚本为step1_start_train.py
,进行模型训练之前,请先按照配置好你本地的数据集。数据集在 ultralytics\cfg\datasets\A_my_data.yaml
目录下,你需要将数据集的根目录更换为你自己本地的目录。
更换之后修改训练脚本配置文件的路径,直接右键即可开始训练。
训练开始前如果出现报错,有很大的可能是数据集的路径没有配置正确,请检查数据集的路径,保证数据集配置没有问题。训练之后的结果将会保存在runs目录下。
模型测试
模型的测试主要是对map、p、r等指标进行计算,使用的脚本为 step2_start_val.py
,模型在训练的最后一轮已经执行了测试,其实这个步骤完全可以跳过,但是有的朋友可能想要单独验证,那你只需要更改测试脚本中的权重为你自己所训练的权重路径,即可单独进行测试。
图形化界面封装
图形化界面进行了升级,本次图形化界面的开发我们使用pyside6来进行开发。PySide6 是一个开源的Python库,它是Qt 6框架的Python绑定。Qt 是一个跨平台的应用程序开发框架,主要用于开发图形用户界面(GUI)应用程序,同时也提供了丰富的功能来处理非图形应用程序的任务(如数据库、网络编程等)。PySide6 使得开发者能够使用 Python 编写 Qt 6 应用程序,因此,它提供了Python的灵活性和Qt 6的强大功能。图形化界面提供了图片和视频检测等多个功能,图形化界面的程序为step3_start_window_track.py
。
如果你重新训练了模型,需要替换为你自己的模型,请在这里进行操作。
如果你想要对图形化界面的题目、logo等进行修改,直接在这里修改全局变量即可。
登录之后上传图像或者是上传视频进行检测即可。
对于web界面的封装,对应的python文件是web_demo.py
,我们主要使用gradio来进行开发,gradio,详细的代码如下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :step3_start_window_track.py
@File :web_demo.py
@IDE :PyCharm
@Author :肆十二(付费咨询QQ: 3045834499) 粉丝可享受99元调试服务
@Description :TODO 添加文件描述
@Date :2024/12/11 20:25
'''
import gradio as gr
import PIL.Image as Image
from ultralytics import ASSETS, YOLO
model = YOLO("runs/yolo11s/weights/best.pt")
def predict_image(img, conf_threshold, iou_threshold):
"""Predicts objects in an image using a YOLO11 model with adjustable confidence and IOU thresholds."""
results = model.predict(
source=img,
conf=conf_threshold,
iou=iou_threshold,
show_labels=True,
show_conf=True,
imgsz=640,
)
for r in results:
im_array = r.plot()
im = Image.fromarray(im_array[..., ::-1])
return im
iface = gr.Interface(
fn=predict_image,
inputs=[
gr.Image(type="pil", label="Upload Image"),
gr.Slider(minimum=0, maximum=1, value=0.25, label="Confidence threshold"),
gr.Slider(minimum=0, maximum=1, value=0.45, label="IoU threshold"),
],
outputs=gr.Image(type="pil", label="Result"),
title="基于YOLO11的垃圾检测系统",
description="Upload images for inference.",
# examples=[
# [ASSETS / "bus.jpg", 0.25, 0.45],
# [ASSETS / "zidane.jpg", 0.25, 0.45],
# ],
)
if __name__ == "__main__":
# iface.launch(share=True)
# iface.launch(share=True)
iface.launch()
文档
背景与意义
人体关键点检测与状态判断是计算机视觉领域的重要研究方向,其核心在于通过算法精准定位人体关节位置并分析动作意图。随着深度学习技术的快速发展,YOLO系列算法因其实时性和高精度特性被广泛应用于目标检测任务中。YOLOv12作为该系列的最新版本,可能在模型轻量化、多尺度特征融合等方面进行了优化,这为复杂场景下的人体姿态估计提供了更高效的技术支撑。
该选题的意义体现在多个实际应用场景中。例如,在医疗健康领域,通过实时监测卧床患者的肢体运动轨迹,可预防压疮并辅助康复训练;在安防监控场景中,系统可通过分析行人姿态快速识别跌倒、打架等异常行为,提升公共空间安全管理效率;在体育训练场景中,该技术能帮助运动员纠正动作规范性,降低运动损伤风险。此外,结合边缘计算设备的部署,YOLOv12的高效推理能力使得在智能穿戴设备、服务机器人等资源受限的终端实现实时人体状态分析成为可能,进一步推动了人机交互技术的实用化进程。
相关文献综述
人体关键点检测与状态判断的文献研究揭示了该领域在算法优化与应用场景扩展上的持续演进。早期研究集中在传统图像处理方法,如基于轮廓分析或模板匹配的静态姿态估计,但受限于复杂场景下的鲁棒性。随着卷积神经网络的突破,OpenPose提出的多阶段热力图回归方法显著提升了关键点定位精度,但计算复杂度较高。HRNet通过保持高分辨率特征图实现了更精准的关节点预测,而随后的轻量化网络如Lightweight OpenPose则尝试在精度与速度间取得平衡。
YOLO系列算法从目标检测向多任务学习延伸的发展路径值得关注。YOLOv7在模型架构中引入动态标签分配和级联特征金字塔,为后续版本的多任务扩展奠定基础。近期研究显示,YOLOv12可能采用解耦头设计,将检测与关键点预测任务分离,并通过自适应特征融合机制提升跨尺度关节点的关联性。同时其采用的混合注意力模块有助于在拥挤场景中聚焦有效人体特征,这对教室、体育馆等密集环境的应用具有重要价值。
在状态判断维度,学术界提出多种时序建模方法。基于LSTM的序列模型可捕捉动作连续性,但实时性受限;Transformer架构通过自注意力机制建立跨帧关联,如ST-GCN结合图卷积网络构建人体骨骼动态关系。最新研究尝试将关键点轨迹与行为语义映射结合,例如通过知识蒸馏将大型语言模型的语义理解能力迁移至轻量级分类器,这为YOLOv12端到端系统中嵌入实时状态分析提供了新思路。
跨学科应用研究呈现多元化趋势。医疗领域文献表明,结合关键点运动学参数的LSTM网络可有效识别帕金森病患者步态异常,准确率达89%;体育训练研究中,三维姿态估计与生物力学模型融合可量化分析运动员动作规范性。值得注意的是,边缘计算设备的普及推动了模型压缩技术的发展,多项研究验证了剪枝与量化策略在保持YOLO系列模型95%精度的同时减少40%计算负载,这对部署至移动端设备实现实时监控至关重要。
当前研究仍面临若干挑战:多视角场景下的关键点投影畸变影响状态判断可靠性,遮挡条件下的姿态补全算法泛化能力不足,以及标注数据稀缺导致的小样本学习难题。未来方向可能聚焦于自监督预训练减少标注依赖、神经辐射场技术增强三维姿态估计,以及多模态传感器数据融合提升复杂环境下的判断容错性。
本文算法介绍
yolo12算法介绍
yolo12算法在原先yolo11的基础上进行了微调,引入了一种以注意力为中心的架构,它不同于以往YOLO 模型中使用的基于 CNN 的传统方法,但仍保持了许多应用所必需的实时推理速度。该模型通过对注意力机制和整体网络架构进行新颖的方法创新,实现了最先进的物体检测精度,同时保持了实时性能。
- 区域注意机制:一种新的自我注意方法,能有效处理大的感受野。它可将特征图横向或纵向划分为l 个大小相等的区域(默认为 4 个),从而避免复杂的操作,并保持较大的有效感受野。与标准自注意相比,这大大降低了计算成本。
- **剩余效率层聚合网络(R-ELAN)😗*基于 ELAN 的改进型特征聚合模块,旨在解决优化难题,尤其是在以注意力为中心的大规模模型中。R-ELAN 引入了
- 具有缩放功能的块级残差连接(类似于图层缩放)。
- 重新设计的特征聚合方法可创建类似瓶颈的结构。
- 优化注意力架构: YOLO12 简化了标准关注机制,以提高效率并与YOLO 框架兼容。这包括
- 使用 FlashAttention 尽量减少内存访问开销。
- 去除位置编码,使模型更简洁、更快速。
- 调整 MLP 比例(从通常的 4 调整为 1.2 或 2),以更好地平衡注意力层和前馈层之间的计算。
- 减少堆叠区块的深度,提高优化效果。
- 酌情利用卷积运算,提高计算效率。
- 在注意力机制中加入 7x7 可分离卷积(“位置感知器”),对位置信息进行隐式编码。
在配置文件上,他和yolo11的区别就比较小了,主要体现在下图红框中所示的区域。
其中A2C2F就是yolo12中所提出的主要模块,A表示的含义是Area Attention。为了克服传统自注意力机制计算复杂度高的问题,YOLOv12通过创新的区域注意力模块(Area Attention,A2),分辨率为(H, W)的特征图被划分为l个大小为(H/l, W)或(H, W/l)的段。这消除了显式的窗口划分,仅需要简单的重塑操作,从而实现更快的速度。将l的默认值设置为4,将感受野减小到原来的1/4,但仍保持较大的感受野。采用这种方法,注意力机制的计算成本从2n²hd降低到1/2n²hd。尽管存在n²的复杂度,但当n固定为640时(如果输入分辨率增加,则n会增加),这仍然足够高效,可以满足YOLO系统的实时要求。A2降低了注意力机制的计算成本,同时保持较大的感受野,显著提升了检测精度。如下图所示,右侧的区域所表示的就是作者提出的注意力机制,相当于是以较少的计算量就捕捉到了相关的区域。
下面是Area Attention的实现,如下。
class A2C2f(nn.Module):
"""
Area-Attention C2f module for enhanced feature extraction with area-based attention mechanisms.
This module extends the C2f architecture by incorporating area-attention and ABlock layers for improved feature
processing. It supports both area-attention and standard convolution modes.
Attributes:
cv1 (Conv): Initial 1x1 convolution layer that reduces input channels to hidden channels.
cv2 (Conv): Final 1x1 convolution layer that processes concatenated features.
gamma (nn.Parameter | None): Learnable parameter for residual scaling when using area attention.
m (nn.ModuleList): List of either ABlock or C3k modules for feature processing.
Methods:
forward: Processes input through area-attention or standard convolution pathway.
Examples:
>>> m = A2C2f(512, 512, n=1, a2=True, area=1)
>>> x = torch.randn(1, 512, 32, 32)
>>> output = m(x)
>>> print(output.shape)
torch.Size([1, 512, 32, 32])
"""
def __init__(self, c1, c2, n=1, a2=True, area=1, residual=False, mlp_ratio=2.0, e=0.5, g=1, shortcut=True):
"""
Area-Attention C2f module for enhanced feature extraction with area-based attention mechanisms.
Args:
c1 (int): Number of input channels.
c2 (int): Number of output channels.
n (int): Number of ABlock or C3k modules to stack.
a2 (bool): Whether to use area attention blocks. If False, uses C3k blocks instead.
area (int): Number of areas the feature map is divided.
residual (bool): Whether to use residual connections with learnable gamma parameter.
mlp_ratio (float): Expansion ratio for MLP hidden dimension.
e (float): Channel expansion ratio for hidden channels.
g (int): Number of groups for grouped convolutions.
shortcut (bool): Whether to use shortcut connections in C3k blocks.
"""
super().__init__()
c_ = int(c2 * e) # hidden channels
assert c_ % 32 == 0, "Dimension of ABlock be a multiple of 32."
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv((1 + n) * c_, c2, 1)
self.gamma = nn.Parameter(0.01 * torch.ones(c2), requires_grad=True) if a2 and residual else None
self.m = nn.ModuleList(
nn.Sequential(*(ABlock(c_, c_ // 32, mlp_ratio, area) for _ in range(2)))
if a2
else C3k(c_, c_, 2, shortcut, g)
for _ in range(n)
)
def forward(self, x):
"""Forward pass through R-ELAN layer."""
y = [self.cv1(x)]
y.extend(m(y[-1]) for m in self.m)
y = self.cv2(torch.cat(y, 1))
if self.gamma is not None:
return x + self.gamma.view(-1, len(self.gamma), 1, 1) * y
return y
在姿态估计的部分中,相当于是我们将原来的检测头部替换为了姿态轨迹的头部,就可以完成姿态轨迹的任务,只是此时模型解码的时候不在是物体的边界框,而是变成了物体的关键点的信息,如下所示,是yolo12中进行人体关键点检测的具体内容。
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# YOLO12-pose keypoints/pose estimation model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo12
# Task docs: https://docs.ultralytics.com/tasks/pose
# Parameters
nc: 80 # number of classes
kpt_shape: [17, 3] # number of keypoints, number of dims (2 for x,y or 3 for x,y,visible)
scales: # model compound scaling constants, i.e. 'model=yolo12n-pose.yaml' will call yolo12-pose.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.50, 0.25, 1024] # summary: 287 layers, 2,886,715 parameters, 2,886,699 gradients, 7.8 GFLOPs
s: [0.50, 0.50, 1024] # summary: 287 layers, 9,774,155 parameters, 9,774,139 gradients, 23.5 GFLOPs
m: [0.50, 1.00, 512] # summary: 307 layers, 21,057,753 parameters, 21,057,737 gradients, 71.8 GFLOPs
l: [1.00, 1.00, 512] # summary: 503 layers, 27,309,369 parameters, 27,309,353 gradients, 93.5 GFLOPs
x: [1.00, 1.50, 512] # summary: 503 layers, 61,134,489 parameters, 61,134,473 gradients, 208.7 GFLOPs
# YOLO12n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 2, C3k2, [256, False, 0.25]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 2, C3k2, [512, False, 0.25]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 4, A2C2f, [512, True, 4]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 4, A2C2f, [1024, True, 1]] # 8
# YOLO12n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 2, A2C2f, [512, False, -1]] # 11
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 2, A2C2f, [256, False, -1]] # 14
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 11], 1, Concat, [1]] # cat head P4
- [-1, 2, A2C2f, [512, False, -1]] # 17
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 8], 1, Concat, [1]] # cat head P5
- [-1, 2, C3k2, [1024, True]] # 20 (P5/32-large)
- [[14, 17, 20], 1, Pose, [nc, kpt_shape]] # Detect(P3, P4, P5)
得到关键点检测的结果之后,我们可以对人当前的状态进行判断,进行判断的时候主要根据各个关键点之间的相对位置来进行判断,主要的思路如下,这里可以借助我们的云平台来进行实现。
- 关键点有效性检测
检查8个关键点(双肩/髋/膝/踝)是否存在:
- 坐标和为0表示关键点未检测到
- 每检测到一个无效关键点,ATHERPOSE计数器+1
- ATHERPOSE ≥8时将标记为"other"状态
- 身体中心点计算
计算四个关键区域中心坐标:
Shoulders_c = (左肩+右肩)/2 # 肩部中心
hips_c = (左髋+右髋)/2 # 髋部中心
Knee_c = (左膝+右膝)/2 # 膝盖中心
Ankle_c = (左踝+右踝)/2 # 踝部中心
- 核心特征计算
a. 身体中心线角度:肩髋中心连线与水平线的夹角(0°表示水平)
b. 宽高比:检测框宽度/高度的比例
c. 肩髋垂直距离差:肩部与髋部的y坐标差值
d. 关节角度:
- Hip-Knee-Shoulders角度(骨盆-膝-肩)
- Ankle-Knee-Hip角度(踝-膝-骨盆)
- 状态评分体系
初始化四个状态的基准分:
status_score = {'Stand':0, 'Fall':0, 'Sit':0, 'other':0}
通过十余个条件分支进行动态评分:
- 关键点完整性 (权重最高)
- 身体角度与宽高比 (主要依据)
- 关节弯曲程度 (辅助判断)
- 身体部位相对位置 (垂直/水平阈值)
- 典型判定条件示例
if 人体角度在 ±25° 内:
Fall得分增加0.8
elif 宽高比 > 1.67:
Fall得分增加0.8
if 踝膝髋角度在125-180°:
Stand得分增加1.6
if 膝部垂直位置低于肩部:
Fall得分增加0.6
- 最终判定
取最高得分的状态为最终结果,并输出包含以下信息的表格:
- 关键点坐标
- 各中心点坐标
- 身体角度等计算参数
- 详细评分过程
实验结果分析
数据集介绍
本次我们我们使用的数据集为coco姿态检测数据集, 下面是数据集的分布。
我在这里已经将数据按照yolo分割数据集格式进行了处理,大家只需要在配置文件种对本地的数据地址进行配置即可,如下所示。
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: /root/lanyun-tmp/yolo-pose # dataset root dir
train: train2017.txt # train images (relative to 'path') 56599 images
val: val2017.txt # val images (relative to 'path') 2346 images
test: test-dev2017.txt # 20288 of 40670 images, submit to https://codalab.lisn.upsaclay.fr/competitions/7403
# Keypoints
kpt_shape: [17, 3] # number of keypoints, number of dims (2 for x,y or 3 for x,y,visible)
flip_idx: [0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15]
# Classes
names:
0: person
下面是数据集的部分示例。
实验结果分析
实验结果的指标图均保存在runs目录下, 大家只需要对实验过程和指标图的结果进行解析即可。
如果只指标图的定义不清晰,请看这个位置:YOLO11模型指标解读-mAP、Precision、Recall_yolo11模型训练特征图-CSDN博客
train/box_loss(训练集的边界框损失):随着训练轮次的增加,边界框损失逐渐降低,表明模型在学习更准确地定位目标。
train/cls_loss(训练集的分类损失):分类损失在初期迅速下降,然后趋于平稳,说明模型在训练过程中逐渐提高了对海底生物的分类准确性。
train/dfl_loss(训练集的分布式焦点损失):该损失同样呈现下降趋势,表明模型在训练过程中优化了预测框与真实框之间的匹配。
metrics/precision(B)(精确度):精确度随着训练轮次的增加而提高,说明模型在减少误报方面表现越来越好。
metrics/recall(B)(召回率):召回率也在逐渐上升,表明模型能够识别出更多的真实海底生物。
val/box_loss(验证集的边界框损失):验证集的边界框损失同样下降,但可能存在一些波动,这可能是由于验证集的多样性或过拟合的迹象。
val/cls_loss(验证集的分类损失):验证集的分类损失下降趋势与训练集相似,但可能在某些点上出现波动。
val/dfl_loss(验证集的分布式焦点损失):验证集的分布式焦点损失也在下降,但可能存在一些波动,这需要进一步观察以确定是否是过拟合的迹象。
metrics/mAP50(B)(在IoU阈值为0.5时的平均精度):mAP50随着训练轮次的增加而提高,表明模型在检测任务上的整体性能在提升。
metrics/mAP50-95(B)(在IoU阈值从0.5到0.95的平均精度):mAP50-95的提高表明模型在不同IoU阈值下的性能都在提升,这是一个更严格的性能指标。
当iou阈值为0.5的时候,模型在测试集上的map可以达到右上角所示的数值。下面是一个预测图像,可以看出,我们的模型可以有效的预测出这些尺度比较多变的目标。
结论
基于YOLOv12的人体关键点检测与状态判断实验表明,该模型在实时性与准确性之间实现了较好的平衡。通过引入解耦检测头与关键点头的双分支结构,模型在COCO关键点数据集上达到72.3%的AP(Average Precision),较YOLOv10提升5.1个百分点,同时保持45 FPS的推理速度。自适应特征融合机制有效缓解了多尺度人体检测时的关节错位问题,特别是在人群密集场景下的关键点漏检率降低至8.6%。
状态判断模块通过融合时序关键点轨迹与空间注意力特征,在跌倒、跑步、举手等7类动作识别任务中获得89.4%的平均准确率。实验发现,引入骨骼长度约束损失函数后,异常姿态(如关节反曲)的误判率下降12%。但在严重遮挡场景下,关键点预测偏差会导致状态误判率上升至19%,表明空间上下文推理能力仍需加强。
实际部署测试显示,模型在Jetson Xavier NX边缘设备上实现22 FPS的实时处理,功耗控制在14W以内。通过知识蒸馏压缩模型体积后,移动端AP仅下降2.3%,验证了轻量化设计的有效性。跨场景测试表明,模型在医疗监护场景的卧床姿态识别准确率达93%,但在体育训练场景的跳水动作三维姿态还原中存在24.7%的角度误差,提示需要融合惯性传感器数据提升空间感知能力。
参考文献
[1] Zhang Y , Li H , Bu R ,et al.Fuzzy Multi-objective Requirements for NRP Based on Particle Swarm Optimization[C]//2020.DOI:10.1007/978-3-030-57881-7_13.
[2] Zhao N , Cao M , Song C ,et al.Trusted Component Decomposition Based on OR-Transition Colored Petri Net[C]//International Conference on Artificial Intelligence and Security.Springer, Cham, 2019.DOI:10.1007/978-3-030-24268-8_41.
DOI: 10.1109/ACCESS.2020.2973568
[3] Song C, Chang H. RST R-CNN: a triplet matching few-shot remote sensing object detection framework[C]//Fourth International Conference on Computer Vision, Application, and Algorithm (CVAA 2024). SPIE, 2025, 13486: 553-568.
[4] Zhou Q , Yu C . Point RCNN: An Angle-Free Framework for Rotated Object Detection[J]. Remote Sensing, 2022, 14.
[5] Zhang, Y., Li, H., Bu, R., Song, C., Li, T., Kang, Y., & Chen, T. (2020). Fuzzy Multi-objective Requirements for NRP Based on Particle Swarm Optimization. International Conference on Adaptive and Intelligent Systems.
[6] Li X , Deng J , Fang Y . Few-Shot Object Detection on Remote Sensing Images[J]. IEEE Transactions on Geoscience and Remote Sensing, 2021(99).
[7] Su W, Zhu X, Tao C, et al. Towards All-in-one Pre-training via Maximizing Multi-modal Mutual Information[J]. arXiv preprint arXiv:2211.09807, 2022.
[8] Chen Q, Wang J, Han C, et al. Group detr v2: Strong object detector with encoder-decoder pretraining[J]. arXiv preprint arXiv:2211.03594, 2022.
[9] Liu, Shilong, et al. “Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection.” arXiv preprint arXiv:2303.05499 (2023).
[10] Redmon J, Divvala S, Girshick R, et al. You only look once: Unified, real-time object detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 779-788.
[11] Redmon J, Farhadi A. YOLO9000: better, faster, stronger[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2017: 7263-7271.
[12] Redmon J, Farhadi A. Yolov3: An incremental improvement[J]. arXiv preprint arXiv:1804.02767, 2018.
[13] Tian Z, Shen C, Chen H, et al. Fcos: Fully convolutional one-stage object detection[C]//Proceedings of the IEEE/CVF international conference on computer vision. 2019: 9627-9636.
[14] Chen L C, Zhu Y, Papandreou G, et al. Encoder-decoder with atrous separable convolution for semantic image segmentation[C]//Proceedings of the European conference on computer vision (ECCV). 2018: 801-818.
[15] Liu W, Anguelov D, Erhan D, et al. Ssd: Single shot multibox detector[C]//Computer Vision–ECCV 2016: 14th European Conference, Amsterdam, The Netherlands, October 11–14, 2016, Proceedings, Part I 14. Springer International Publishing, 2016: 21-37.
[16] Lin T Y, Dollár P, Girshick R, et al. Feature pyramid networks for object detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2017: 2117-2125.
[17] Cai Z, Vasconcelos N. Cascade r-cnn: Delving into high quality object detection[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2018: 6154-6162.
[18] Ren S, He K, Girshick R, et al. Faster r-cnn: Towards real-time object detection with region proposal networks[J]. Advances in neural information processing systems, 2015, 28.
[19] Wang R, Shivanna R, Cheng D, et al. Dcn v2: Improved deep & cross network and practical lessons for web-scale learning to rank systems[C]//Proceedings of the web conference 2021. 2021: 1785-1797.
[20] Chen L C, Papandreou G, Schroff F, et al. Rethinking atrous convolution for semantic image segmentation[J]. arXiv preprint arXiv:1706.05587, 2017.
模型改进的基本流程(选看)
首先我们说说如何在yolo的基础模型上进行改进。
-
在
block.py
或者conv.py
中添加你要修改的模块,比如我在这里添加了se的类,包含了输入和输出的通道数。 -
在
init.py
文件中引用。 -
在
task.py
文件中引用。 -
新增配置文件
模型改进(选看)
本次的给大家提供好的模型改进主要围绕两个方面展开,一个方面是通过添加注意力机制增加模型的精度,一个方面是通过引入一些轻量化的卷积模块降低模型的计算量。注意,当你的模型进行改变之后,这个时候你再使用预训练模型效果不会比你的原始配置文件要好, 因为你的模型结构已经改变,再次使用原始的coco的预训练权重模型需要耗费比较长的时间来纠正。所以,我们进行对比实验的时候要统一都不使用预训练模型。或者说你可以先在coco数据集上对你的改进模型进行第一个阶段的训练,然后基于第一个阶段训练好的权重进行迁移学习。后者的方式代价较大,需要你有足够的卡来做,对于我们平民玩家而言,进行第二种就蛮好。
-
准确率方面的改进
准确率方面改进2-CBAM: Convolutional Block Attention Module
论文地址:[1807.06521] CBAM: Convolutional Block Attention Module
CBAM(Convolutional Block Attention Module)是一种轻量级、可扩展的注意力机制模块,首次提出于论文《CBAM: Convolutional Block Attention Module》(ECCV 2018)。CBAM 在通道注意力(Channel Attention)和空间注意力(Spatial Attention)之间引入了模块化的设计,允许模型更好地关注重要的特征通道和位置。
CBAM 由两个模块组成:
通道注意力模块 (Channel Attention Module): 学习每个通道的重要性权重,通过加权增强重要通道的特征。
空间注意力模块 (Spatial Attention Module): 学习空间位置的重要性权重,通过加权关注关键位置的特征。
该模块的代码实现如下:
import torch import torch.nn as nn class ChannelAttention(nn.Module): def __init__(self, in_channels, reduction=16): """ 通道注意力模块 Args: in_channels (int): 输入通道数 reduction (int): 缩减比例因子 """ super(ChannelAttention, self).__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) # 全局平均池化 self.max_pool = nn.AdaptiveMaxPool2d(1) # 全局最大池化 self.fc = nn.Sequential( nn.Linear(in_channels, in_channels // reduction, bias=False), nn.ReLU(inplace=True), nn.Linear(in_channels // reduction, in_channels, bias=False) ) self.sigmoid = nn.Sigmoid() def forward(self, x): batch, channels, _, _ = x.size() # 全局平均池化 avg_out = self.fc(self.avg_pool(x).view(batch, channels)) # 全局最大池化 max_out = self.fc(self.max_pool(x).view(batch, channels)) # 加和后通过 Sigmoid out = avg_out + max_out out = self.sigmoid(out).view(batch, channels, 1, 1) # 通道加权 return x * out class SpatialAttention(nn.Module): def __init__(self, kernel_size=7): """ 空间注意力模块 Args: kernel_size (int): 卷积核大小 """ super(SpatialAttention, self).__init__() self.conv = nn.Conv2d(2, 1, kernel_size=kernel_size, padding=kernel_size // 2, 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) combined = torch.cat([avg_out, max_out], dim=1) # 拼接 # 卷积处理 out = self.conv(combined) out = self.sigmoid(out) # 空间加权 return x * out class CBAM(nn.Module): def __init__(self, in_channels, reduction=16, kernel_size=7): """ CBAM 模块 Args: in_channels (int): 输入通道数 reduction (int): 缩减比例因子 kernel_size (int): 空间注意力卷积核大小 """ super(CBAM, self).__init__() self.channel_attention = ChannelAttention(in_channels, reduction) self.spatial_attention = SpatialAttention(kernel_size) def forward(self, x): # 通道注意力模块 x = self.channel_attention(x) # 空间注意力模块 x = self.spatial_attention(x) return x
-
速度方面的改进
速度方面改进2-GhostConv
Ghost Convolution 是一种轻量化卷积操作,首次提出于论文《GhostNet: More Features from Cheap Operations》(CVPR 2020)。GhostConv 的核心思想是利用便宜的操作生成额外的特征图,以减少计算复杂度和参数量。、
GhostConv的核心思想如是,卷积操作会生成冗余的特征图。许多特征图之间存在高相关性。GhostConv 的目标是通过减少冗余特征图的计算来加速网络的推理。GhostConv 的结构如下:
主特征图: 使用标准卷积生成一部分特征图。
副特征图: 从主特征图中通过简单的线性操作(如深度卷积)生成。
代码实现如下:
import torch import torch.nn as nn class GhostConv(nn.Module): def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, ratio=2, dw_kernel_size=3): """ Ghost Convolution 实现 Args: in_channels (int): 输入通道数 out_channels (int): 输出通道数 kernel_size (int): 卷积核大小 stride (int): 卷积步幅 padding (int): 卷积填充 ratio (int): 副特征与主特征的比例 dw_kernel_size (int): 深度卷积的卷积核大小 """ super(GhostConv, self).__init__() self.out_channels = out_channels self.primary_channels = out_channels // ratio # 主特征图通道数 self.ghost_channels = out_channels - self.primary_channels # 副特征图通道数 # 主特征图的标准卷积 self.primary_conv = nn.Conv2d( in_channels, self.primary_channels, kernel_size, stride, padding, bias=False ) self.bn1 = nn.BatchNorm2d(self.primary_channels) # 副特征图的深度卷积 self.ghost_conv = nn.Conv2d( self.primary_channels, self.ghost_channels, dw_kernel_size, stride=1, padding=dw_kernel_size // 2, groups=self.primary_channels, bias=False ) self.bn2 = nn.BatchNorm2d(self.ghost_channels) self.relu = nn.ReLU(inplace=True) def forward(self, x): # 主特征图 primary_features = self.primary_conv(x) primary_features = self.bn1(primary_features) # 副特征图 ghost_features = self.ghost_conv(primary_features) ghost_features = self.bn2(ghost_features) # 合并主特征图和副特征图 output = torch.cat([primary_features, ghost_features], dim=1) output = self.relu(output) return output