基于PaddleDetection中的PP-HumanV2之安防重点场景异常行为识别–抽烟、打电话
1. 项目场景说明
安全是一个一直都很热门的话题,由于个人不重视安全问题,造成了许多重大事故,不但为个人的生命和财产安全带来威胁,而且为他人和社会造成不小的隐患。如在商场打电话,导致儿童丢失,加油站吸烟,导致加油站起火爆炸等许多由这些异常行为引起的安全事故。
智慧安防是智慧城市中不可缺少的一部分,利用智慧化的手段解决抽烟、打电话等这些异常行为带来的安全隐患变得尤为重要。急需通过智慧化解决的问题有:
-
如何充分利用现有的各种场所中的监控设备,对行人的异常行为进行实时的监控。
-
如何在减少人工的前提下,更及时的发现问题,解决问题。
-
如何有效监督行人文明出行,减少由于异常行为带来的安全隐患。
传统的控烟技术手段主要以烟雾传感器为主,当传感器检测到烟雾时产生报警。但是管理人员无法对其高效的管理,不能及时取证,无法追溯,没有形成一个有效的闭环,导致控烟效果不佳,并且还会出现漏报、误报。
AI抽烟行为识别算法都是基于视觉的,包括视频和图像,必须要看得见,才能进行分析。抽烟的捕捉主要是通过检测人和烟,以及它们之间的位置关系来判断的。一般抽烟要不拿在手上,要不正在抽,会有一些比较明显的特征。通过识别匹配这些特征,捕捉到抽烟行为。
AI识别危险区域吸烟、打电话行为系统广泛应用于仓库、公园、加油站、厨房、森林、商场、地铁站以及消防楼道等一系列禁烟场所、防火防爆场所。
读者可以通过本项目熟悉AI项目的落地流程,了解解决问题的思路。帮助大家了解AI项目应用于实际工程项目的步骤,吸引更多智慧安防感兴趣的开发者使异常行为算法更准确和解决问题的方法更多样。😊
项目面临的挑战:
-
环境复杂但精度要求高: 目标尺寸小,外形不规则,还有遮挡、堆叠、抖动、光线、天气等多种情况都容易影响识别精度。
-
大量干扰下容易造成误检: 行人较密集时会造成更大的干扰。导致行人异常行为分析时的准确率变差。
2. 技术方案选型
针对以上的难点和挑战,我们的解决方案和选型思路如下:
PP-Human v2发布,行为识别、人体属性识别、流量计数、跨镜跟踪四大产业特色功能全面升级,覆盖行人检测、跟踪、属性三类核心算法能力,提供保姆级全流程开发及模型优化策略。
PP-Hunamn中的行为识别具有以下四个特点
-
功能丰富:支持摔倒、打架、抽烟、打电话、人员闯入五种高频异常行为识别;
-
鲁棒性强:对光照、视角、背景环境无限制;
-
性能高:与视频识别技术相比,模型计算量大幅降低,支持本地化与服务化快速部署;
-
训练速度快:仅需15分钟即可产出高精度行为识别模型。
本项目中把 PP-YOLOE 列为候选模型,主要是看中他的体积小、速度快、精度较高的优势,非常适合本项目的部署环境和性能要求。同时,飞桨提供的预训练模型也可以最大程度上提升模型的收敛速度和精度。
部署和检测结果的进一步处理,我们留到后续的章节,结合实例详细介绍。
3. 安装说明
环境要求:
-
PaddlePaddle = 2.3.1
-
Python = 3.7
-
PaddleDetection - develop
# 1.克隆PaddleDetection仓库
%cd work
# github仓库
# !git clone https://github.com/PaddlePaddle/PaddleDetection.git -b develop
# gitee仓库(下载速度较快)
# !git clone https://gitee.com/PaddlePaddle/PaddleDetection.git -b develop
# 2.安装项目所需依赖
# 每次启动项目后都需要先执行
%cd ./PaddleDetection
!pip install -r requirements.txt
# 3.编译安装paddledet
# 每次启动项目后都需要先执行
!python setup.py install
# 测试安装
!python ppdet/modeling/tests/test_architectures.py
4. 数据准备
此 Demo 中使用的为其中一部分。示例图片如下:
本案例数据集为COCO格式,此格式的数据集将所有训练图像的标注都存放到 train.json 文件中。数据以字典嵌套的形式存放。train.json 文件中包含 annotations 字典,表示标注文件中目标物体的标注信息列表,每个元素是一个目标物体的标注信息。如下为其中一个目标物体的标注信息:
category_id:1
0:97.0181345931
1:332.7033243081
2:7.5943999555
3:16.4545332369
id:0
image_id:0
iscrowd:0
area:124.96230648208665
# %cd dataset/
# !unzip /home/aistudio/data/data163503/smoking_data.zip
# !unzip /home/aistudio/data/data163504/make_phone_call_data.zip
# 数据集划分
# !pip install paddlex==2.1.0 -i https://mirror.baidu.com/pypi/simple
# !paddlex --split_dataset --format COCO --dataset_dir dataset/smoking/ --val_value 0.2 --test_value 0.1
5. 模型选择
PaddleDetection 提供了非常丰富的目标检测模型,但是我们需要从项目实际情况出发,选择适合部署条件的模型。项目要求模型体积小、精度高、速度达标,因此我们将候选模型锁定在 PP-YOLOE 这个模型上。
基于PP-YOLOE模型的香烟检测模型,是实现PP-Human中的基于检测的行为识别方案的一环,如何在PP-Human中使用该模型进行吸烟行为识别,可参考PP-Human行为识别模块。该模型检测类别仅包含香烟一类。
6. 模型训练
在本案例中,可以总结为如下5个步骤,其中需要根据评估和预测的结果,对模型进行反复的优化和再训练:
6.1 ppyoloe_crn_s_80e_smoking_visdrone的配置
ppyoloe_crn_s_80e_smoking_visdrone的配置文件,由 1 个入口配置文件,和4个相关联的子配置文件组成。入口配置文件位于:
**/home/aistudio/work/PaddleDetection/configs/pphuman/ppyoloe_crn_s_80e_smoking_visdrone.yml**
相关的 4 个子配置文件为:
_BASE_: [
'../runtime.yml',
'../ppyoloe/_base_/optimizer_300e.yml',
'../ppyoloe/_base_/ppyoloe_crn.yml',
'../ppyoloe/_base_/ppyoloe_reader.yml',
]
接下来我们从子配置文件开始,依次说明每个配置文件的用途和需要修改的部分。
6.1.1 数据集配置文件
设置数据集的配置信息。根据本案例的情况,请按照如下内容进行修改 num_classes、image_dir、anno_path、dataset_dir:
metric: COCO
num_classes: 1
TrainDataset:
!COCODataSet
image_dir: ""
anno_path: train.json
dataset_dir: dataset/smoking
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']
EvalDataset:
!COCODataSet
image_dir: ""
anno_path: val.json
dataset_dir: dataset/smoking
TestDataset:
!ImageFolder
anno_path: test.json
dataset_dir: dataset/smoking
6.1.2 运行时配置文件 runtime.yml
用于设置运行时的参数,主要包括:
use_gpu: 是否使用GPU训练
use_xpu: 是否使用XPU训练
log_iter: 显示训练信息的间隔
save_dir: 模型保存路径
snapshot_epoch: 保存模型的间隔
# Exporting the model: 与导出模型相关的设置
这里我们暂且保留默认值,不做修改即可。
6.1.3 模型网络参数 ppyoloe_crn.yml
用于设置模型的网络参数,也包括预训练集的加载,这里为了可以快速开始实际训练,我们也暂时保留默认的参数,不做修改。
6.1.4 训练优化参数 optimizer_300e.yml
主要说明了学习率和优化器的配置。其中比较重要的参数是训练轮数 epoch 和 学习率 base_lr。同样,我们暂时不在这里修改,稍后再设置。
6.1.5 数据读取器配置参数 ppyoloe_reader.yml
主要说明了在训练时读取数据集的配置参数,其中比较重要的有:
sample_transforms / batch_transforms: 数据增强算子
batch_size: 批量大小
worker_num: 并发加载子进程数
resize: 读取后的预处理大小
按照前文提到的数据增强策略,我们需要在这里修改相关参数,在 TrainReader 中的 sample_transforms 部分增加图片剪裁和颜色扰动 2 个增强算子,如下:
TrainReader:
sample_transforms:
- Decode: {}
- RandomCrop: {}
- RandomFlip: {prob: 0.5}
- RandomDistort: {}
- CropImage: {}
- ColorDistort: {}
6.1.6 修改入口配置文件ppyoloe_crn_s_80e_smoking_visdrone.yml
这是控制模型训练的主配置文件,其中设置的参数会覆盖掉子配置文件中的相关参数。这也是为什么我们之前在子配置文件中基本保留了默认配置而不做修改,原因就在于,在主配置文件内集中修改参数,可以更方便的修改训练参数,避免要修改的参数过于分散。
按如下内容修改主配置文件的内容:
_BASE_: [
'../runtime.yml',
'../ppyoloe/_base_/optimizer_300e.yml',
'../ppyoloe/_base_/ppyoloe_crn.yml',
'../ppyoloe/_base_/ppyoloe_reader.yml',
]
log_iter: 100
snapshot_epoch: 10
weights: output/ppyoloe_crn_s_80e_smoking_visdrone/model_final
pretrain_weights: https://paddledet.bj.bcebos.com/models/ppyoloe_crn_s_80e_visdrone.pdparams
depth_mult: 0.33
width_mult: 0.50
TrainReader:
batch_size: 16
LearningRate:
base_lr: 0.01
epoch: 80
LearningRate:
base_lr: 0.01
schedulers:
- !CosineDecay
max_epochs: 80
- !LinearWarmup
start_factor: 0.
epochs: 1
PPYOLOEHead:
static_assigner_epoch: -1
metric: COCO
num_classes: 1
TrainDataset:
!COCODataSet
image_dir: ""
anno_path: smoking_train_cocoformat.json
dataset_dir: dataset/smoking
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']
EvalDataset:
!COCODataSet
image_dir: ""
anno_path: smoking_test_cocoformat.json
dataset_dir: dataset/smoking
TestDataset:
!ImageFolder
anno_path: smoking_test_cocoformat.json
dataset_dir: dataset/smoking
其中:
- Batch Size指模型在训练过程中,前向计算一次(即为一个step)所用到的样本数量
- Batch Size跟机器的显存/内存高度相关,batch_size越高,所消耗的显存/内存就越高
- step与epoch的关系:1个epoch由多个step组成,例如训练样本有800张图像,train_batch_size为8, 那么每个epoch都要完整用这800张图片训一次模型,而每个epoch总共包含800//8即100个step
6.2 开始训练
# GPU 单卡训练
# %cd ~/work/PaddleDetection
!export CUDA_VISIBLE_DEVICES=0 # windows和Mac下不需要执行该命令
!python tools/train.py -c configs/pphuman/ppyoloe_crn_s_80e_smoking_visdrone.yml
说明:这里为了加快演示速度,在主配置文件里将 epoch 次数设置为 3,纯粹为了演示加速。后面的演示,会使用在 Demo 数据集上训练了 300 个 epoch 的模型,保存位置在:
PaddleDetection/output/ppyoloe_crn_s_80e_smoking_visdrone/model_final
7. 模型评估
# GPU单卡评估
!export CUDA_VISIBLE_DEVICES=0 # windows和Mac下不需要执行该命令
!python tools/eval.py -c configs/pphuman/ppyoloe_crn_s_80e_smoking_visdrone.yml -o weights=output/ppyoloe_crn_s_80e_smoking_visdrone/model_final
8. 模型预测
模型预测也很简单,一行代码搞定,其中最常用的参数有:
–output_dir: 保存检测结果的文件夹,默认保存在output文件夹。
–draw_threshold: 可视化时分数的阈值,默认大于0.5的box会显示出来。
–save_results: 将图片的预测结果保存到json文件中,与预测结果图片在同一文件夹下。
!python tools/infer.py -c configs/pphuman/ppyoloe_crn_s_80e_smoking_visdrone.yml --infer_img=testImage/demo.jpg -o weight=./output/ppyoloe_crn_s_80e_smoking_visdrone/model_final/model_final.pdparams
W0815 18:30:13.383178 3213 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0815 18:30:13.389372 3213 gpu_resources.cc:91] device: 0, cuDNN Version: 7.6.
[08/15 18:30:14] ppdet.utils.checkpoint INFO: Finish loading model weights: output/ppyoloe_crn_s_80e_smoking_visdrone/model_final.pdparams
[08/15 18:30:14] ppdet.data.source.category WARNING: anno_file 'test.json' is None or not set or not exist, please recheck TrainDataset/EvalDataset/TestDataset.anno_path, otherwise the default categories will be used by metric_type.
[08/15 18:30:14] ppdet.data.source.category WARNING: metric_type: COCO, load default categories of COCO.
100%|█████████████████████████████████████████████| 1/1 [00:01<00:00, 1.52s/it]
[08/15 18:30:16] ppdet.engine INFO: Detection bbox results save in output/demo.jpg
如果大家训练的模型在自己的测试图片上表现不是很好的话,大概率是因为本案例能提供的样本数太有限了。有兴趣的同学可以自己多找些图片,用更多的图片再训练一下模型。因为数据量对模型效果的影响是最大的。
9. 模型导出
在模型训练过程中保存的模型文件是包含前向预测和反向传播的过程,在实际的工业部署则不需要反向传播,因此需要将模型进行导成部署需要的模型格式。 导出后的模型会保存在:
output_inference/ppyoloe_crn_s_80e_smoking_visdrone/
包含如下文件:
- infer_cfg.yml
- model.pdiparams
- model.pdiparams.info
- model.pdmodel
导出后的文件,将用于后续的模型部署。
# 导出模型
!python tools/export_model.py -c configs/pphuman/ppyoloe_crn_s_80e_smoking_visdrone.yml -o weight=output/ppyoloe_crn_s_80e_smoking_visdrone/model_final.pdparms
!pip install onnx==1.13.0
!pip install paddle2onnx==1.0.5
!paddle2onnx --model_dir=/home/aistudio/Smoking_Detection/output_inference/ppyoloe_crn_s_80e_smoking_visdrone/ \
--model_filename model.pdmodel \
--params_filename model.pdiparams \
--opset_version 16 \
--save_file ppyoloe_crn_s_80e_smoking_visdrone.onnx
[Paddle2ONNX] Start to parse PaddlePaddle model...
[Paddle2ONNX] Model file path: /home/aistudio/Smoking_Detection/output_inference/ppyoloe_crn_s_80e_smoking_visdrone/model.pdmodel
[Paddle2ONNX] Paramters file path: /home/aistudio/Smoking_Detection/output_inference/ppyoloe_crn_s_80e_smoking_visdrone/model.pdiparams
[Paddle2ONNX] Start to parsing Paddle model...
[Paddle2ONNX] Use opset_version = 16 for ONNX export.
[WARN][Paddle2ONNX] [multiclass_nms3: multiclass_nms3_0.tmp_1] [WARNING] Due to the operator multiclass_nms3, the exported ONNX model will only supports inference with input batch_size == 1.
[Paddle2ONNX] PaddlePaddle model is exported as ONNX format now.
2023-05-11 16:35:08 [INFO] ===============Make PaddlePaddle Better!================
2023-05-11 16:35:08 [INFO] A little survey: https://iwenjuan.baidu.com/?code=r8hu2s
!pip install onnxruntime
import onnxruntime as rt
import cv2
import numpy as np
sess = rt.InferenceSession("/home/aistudio/ppyoloe_crn_s_80e_smoking_visdrone.onnx")
img = cv2.imread("/home/aistudio/Smoking_Detection/testImage/demo.jpg")
org_img = img
im_shape = np.array([[float(img.shape[0]), float(img.shape[1])]]).astype('float32')
print(im_shape)
img = cv2.resize(img, (640,640))
scale_factor = np.array([[float(640/img.shape[0]), float(640/img.shape[1])]]).astype('float32')
img = img.astype(np.float32) / 255.0
input_img = np.transpose(img, [2, 0, 1])
image = input_img[np.newaxis, :, :, :]
output_dict = ["reshape2_83.tmp_0","tile_3.tmp_0"]
inputs_dict = {
'im_shape': im_shape,
'image': image,
'scale_factor': scale_factor
}
result = sess.run(output_dict, inputs_dict)
for item in result[0]:
if item[1] > 0.5:
if item[0] == 0:
cv2.rectangle(org_img, (int(item[2]), int(item[3])), (int(item[4]), int(item[5])), (255,0,0), 2)
cv2.putText(org_img, "visdrone", (int(item[2]), int(item[3])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)
# elif item[0] == 1:
# cv2.rectangle(org_img, (int(item[2]), int(item[3])), (int(item[4]), int(item[5])), (0,255,0), 2)
# cv2.putText(org_img, "vest", (int(item[2]), int(item[3])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)
# elif item[0] == 2:
# cv2.rectangle(org_img, (int(item[2]), int(item[3])), (int(item[4]), int(item[5])), (0,0,255), 2)
# cv2.putText(org_img, "worker", (int(item[2]), int(item[3])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)
cv2.imwrite("/home/aistudio/work/result.png", org_img)
[[529. 290.]]
o/work/result.png", org_img)
[[529. 290.]]
---------------------------------------------------------------------------
InvalidArgument Traceback (most recent call last)
/tmp/ipykernel_346/3528762000.py in <module>
15 'scale_factor': scale_factor
16 }
---> 17 result = sess.run(output_dict, inputs_dict)
18 for item in result[0]:
19 if item[1] > 0.5:
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/onnxruntime/capi/onnxruntime_inference_collection.py in run(self, output_names, input_feed, run_options)
198 output_names = [output.name for output in self._outputs_meta]
199 try:
--> 200 return self._sess.run(output_names, input_feed, run_options)
201 except C.EPFail as err:
202 if self._enable_fallback:
InvalidArgument: [ONNXRuntimeError] : 2 : INVALID_ARGUMENT : Invalid Feed Input Name:im_shape
## 10.使用PP-Humanv2实现行人抽烟和打电话识别
### 10.1 配置文件说明:
PP-Human相关配置位于deploy/pphuman/config/infer_cfg.yml中,存放模型路径,完成不同功能需要设置不同的任务类型。
功能及任务类型对应表单如下:
| 输入类型 | 功能 |任务类型 |配置项 |
| :--------: | :--------: | :--------: |:--------: |
|图片 |属性识别| 目标检测 属性识别 |DET ATTR|
|单镜头视频 |属性识别 |多目标跟踪 属性识别 |MOT ATTR|
|单镜头视频 |行为识别 |多目标跟踪 关键点检测 行为识别| MOT KPT ACTION|
本项目应用到的是:
* 抽烟识别:基于人体id的目标检测
* 打电话识别:基于人体id的图像分类
### 10.2 执行模型预测
### 场景一 :抽烟识别
**配置说明**
配置文件中相关的参数如下:
* ID_BASED_DETACTION: # 基于检测的行为识别模型配置
* model_dir: output_inference/ppyoloe_crn_s_80e_smoking_visdrone # 模型所在路径
* batch_size: 8 # 预测批大小
* threshold: 0.4 # 识别为对应行为的阈值
* display_frames: 80 # 显示帧数。当识别到对应动作时,在对应人物ID中显示状态的持续时间。
* enable: False # 是否开启该功能
**使用方法**
从模型库中下载行人检测/跟踪、抽烟行为识别两个预测部署模型并解压到./output_inference路径下;默认自动下载模型,如果手动下载,需要修改模型文件夹为模型存放路径。
修改配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中ID_BASED_DETACTION下的enable为True;
仅支持输入视频,启动命令如下:
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu
### 场景二 :打电话识别
**配置说明**
配置文件中相关的参数如下:
* ID_BASED_CLSACTION: # 基于分类的行为识别模型配置
* model_dir: output_inference/PPHGNet_tiny_calling_halfbody # 模型所在路径
* batch_size: 8 # 预测批大小
* threshold: 0.45 #识别为对应行为的阈值
* display_frames: 80 # 显示帧数。当识别到对应动作时,在对应人物ID中显示状态的持续时间。
* enable: False # 是否开启该功能
**使用方法**
从模型库中下载行人检测/跟踪、打电话行为识别两个预测部署模型并解压到./outputinference路径下;默认自动下载模型,如果手动下载,需要修改模型文件夹为模型存放路径。
修改配置文件deploy/pipeline/config/infer_cfg_pphuman.yml中ID_BASED_CLSACTION下的enable为True;
仅支持输入视频,启动命令如下:
python deploy/pipeline/pipeline.py --config deploy/pipeline/config/infer_cfg_pphuman.yml --video_file=test_video.mp4 --device=gpu
**使用TensorRT加速预测**
NVIDIA TensorRT是一个高性能的深度学习预测库。PP-Human v2同样支持了使用TensorRT加速模型的预测,并且整个步骤十分简单快速。您可以参考以下步骤实现:
安装适配TensorRT的Paddle, 通过下载链接直接下载对应环境的Paddle whl包进行安装。或是参照指导文档使用docker或自编译方式准备适配TensorRT的Paddle环境。
在上述两个场景的Python预测命令中,直接增加--run_mode=trt_fp16即可。
本案例旨在通过一个实际的项目带大家熟悉PP-human v2从数据集建立、到模型训练优化、到最终部署的完整的快速落地流程,并在这个过程中了解分析问题、解决问题的思路。结合飞桨提供的全生态的AI套件提升项目的实践体验和效率。
值得一提的是,在数据准备阶段,需要的是耐心。在模型优化阶段需要的是大胆的尝试。希望这些经验能对大家今后的实际项目操作有所帮助。
本案例用到的套件如下:
* PaddleDetection
* PaddleX
请点击[此处](https://ai.baidu.com/docs#/AIStudio_Project_Notebook/a38e5576)查看本环境基本用法. <br>
Please click [here ](https://ai.baidu.com/docs#/AIStudio_Project_Notebook/a38e5576) for more detailed instructions.