基于PaddleX的YOLOv3废水水质判断
基于PaddleX的YOLOv3废水水质判断从0到EdgeBoard部署,包括自制数据集、数据加载和预处理、模型选择和调参、模型部署等步骤,同时总结了心得体会。
一、项目背景
利用无人机巡查河道,及时发现污染源是目前地表水监测的热点。通过搭载在无人机上的摄像头,手机上可以实时查看河道的水体图像。因此需要部署在手机端通过目标检测项目来实时判断图像中的水质是否达标。如果发现水质超标,则可以通过无人机进一步寻找污染源,以提升地表水监测能力。
本项目基于PaddleX的YOLOv3进行废水水质判断,
二、数据集简介
本项目从网页上收集了40个水质样品图片,然后使用labelImg对图片进行标注。labelImg的安装及使用请参见https://blog.csdn.net/python_pycharm/article/details/85338801
1.自制VOC数据集
在home目录下上传包含图片文件和标注文件的压缩包facemask.zip(考虑到尽量不修改老师源代码,因此连压缩包名字都与“口罩检测”项目一致,这样简化了代码修改),图片文件储存于JPEGImages,标注文件储存于Annotations。然后解压文件,具体代码如下:
#下载工具包,不用每次运行。使用github替代gitee也行,但很慢。
!git clone https://gitee.com/PaddlePaddle/PaddleDetection.git
#存入持久层
!mv PaddleDetection/ work/
#安装运行环境,每次打开都需要运行
!pip install -r work/PaddleDetection/requirements.txt
#解压自制数据集
!unzip -oq /home/aistudio/facemask.zip -d work/PaddleDetection/dataset/MaskVOCData
#安装paddleX
!pip install paddlex
#对数据集进行划分,注意train_value+val_value+test_value=1,因此代码中只需要标注评估集数据比例val_value和测试集数据比例test_value
!paddlex --split_dataset --format VOC --dataset_dir work/PaddleDetection/dataset/MaskVOCData/ --val_value 0.05 --test_value 0.15
#经过上述步骤,MaskVOCData文件夹多了labels.txt,test_list.txt,train_list.txt以及val_list.txt
%cd work/PaddleDetection/
#制作VOC数据集
#提取文件下img目录所有照片名不要后缀
import pandas as pd
import os
filelist = os.listdir("dataset/MaskVOCData/JPEGImages")
train_name = []
for file_name in filelist:
name, point ,end =file_name.partition('.')
train_name.append(name)
df = pd.DataFrame(train_name)
df.head(8)
df.to_csv('./train_all.txt', sep='\t', index=None,header=None)
!mkdir -p dataset/MaskVOCData/ImageSets/Main #创建多级目录
!mv train_all.txt dataset/MaskVOCData/ImageSets
!mv dataset/MaskVOCData/labels.txt dataset/MaskVOCData/label_list.txt
!cp dataset/MaskVOCData/label_list.txt dataset/MaskVOCData/ImageSets/
#备份VOC 数据集到home目录下
!cp -r dataset/MaskVOCData /home/aistudio/
! tar -cvf /home/aistudio/MaskVOCData.tar /home/aistudio/MaskVOCData/
#以下开始制作COCO数据集
!python tools/x2coco.py \
--dataset_type voc \
--voc_anno_dir dataset/MaskVOCData/Annotations \
--voc_anno_list dataset/MaskVOCData/ImageSets/train_all.txt \
--voc_label_list dataset/MaskVOCData/ImageSets/label_list.txt \
--voc_out_name ./dataset/annotations.json
!mv dataset/MaskVOCData dataset/MaskCOCOData
!mv ../../MaskVOCData dataset
!mkdir dataset/MaskCOCOData/annotations
!mv dataset/annotations.json dataset/MaskCOCOData/annotations
!rm dataset/MaskCOCOData/train_list.txt
!rm dataset/MaskCOCOData/val_list.txt
!rm dataset/MaskCOCOData/label_list.txt
!rm dataset/MaskCOCOData/test_list.txt
!rm -r dataset/MaskCOCOData/Annotations
!rm -r dataset/MaskCOCOData/ImageSets
!paddlex --split_dataset --format COCO --dataset_dir dataset/MaskCOCOData/annotations --val_value 0.05 --test_value 0.15
#备份COCO数据集到home目录下
!cp -r dataset/MaskCOCOData /home/aistudio/
! tar -cvf /home/aistudio/MaskCOCOData.tar /home/aistudio/MaskCOCOData/
2.数据加载和预处理
主要任务为图像数据增强,为后续训练提供基础
%cd /home/aistudio/work/PaddleDetection
import paddle
import paddlex as pdx
import numpy as np
import paddle.nn as nn
import paddle.nn.functional as F
import PIL.Image as Image
import cv2
import os
from random import shuffle
from paddlex.det import transforms as T
from PIL import Image, ImageFilter, ImageEnhance
import matplotlib.pyplot as plt # plt 用于显示图片
#这部分T是数据增强,不是全部使用才能提高map,只能选择合适的才能提高,所以需要调整,调整时就在原来的句子前加#
def preprocess(dataType="train"):
if dataType == "train":
transform = T.ComposedYOLOv3Transforms([
T.MixupImage(mixup_epoch=250), #对图像进行mixup操作,模型训练时的数据增强操作,目前仅YOLOv3模型支持该transform
T.RandomExpand(), #随机扩张图像
T.RandomDistort(brightness_range=1.2, brightness_prob=0.3), #以一定的概率对图像进行随机像素内容变换
T.RandomCrop(), #随机裁剪图像
T.ResizeByShort(), #根据图像的短边调整图像大小
T.Resize(target_size=608, interp='RANDOM'), #调整图像大小,[’NEAREST’, ‘LINEAR’, ‘CUBIC’, ‘AREA’, ‘LANCZOS4’, ‘RANDOM’]
T.RandomHorizontalFlip(), #以一定的概率对图像进行随机水平翻转
T.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225]) #对图像进行标准化(mean,std)
])
return transform
else:
transform = T.Compose([
T.Resize(target_size=608, interp='RANDOM'),
T.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])
])
return transform
train_transforms = preprocess(dataType="train")
eval_transforms = preprocess(dataType="eval")
# 定义训练和验证所用的数据集
# API地址:https://paddlex.readthedocs.io/zh_CN/develop/data/format/detection.html?highlight=paddlex.det
train_dataset = pdx.datasets.VOCDetection(
data_dir='./dataset/MaskVOCData',
file_list='./dataset/MaskVOCData/train_list.txt',
label_list='./dataset/MaskVOCData/label_list.txt',
transforms=train_transforms,
shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
data_dir='./dataset/MaskVOCData',
file_list='./dataset/MaskVOCData/val_list.txt',
label_list='./dataset/MaskVOCData/label_list.txt',
transforms=eval_transforms)
三、模型选择和调参
使用yolov3模型,这里使用MobileNetV1网络,便于部署在移动端,如下所示:
1.模型选择
#使用yolov3模型,具体信息可以查看work\PaddleDetection\configs里面的文件,这里使用MobileNetV1网络,便于部署在移动端
import matplotlib
matplotlib.use('Agg')
os.environ['CUDA_VISIBLE_DEVICES'] = '0'#0为GPU模式
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
#可使用VisualDL查看训练指标,参考https://paddlex.readthedocs.io/zh_CN/develop/train/visualdl.html
num_classes = len(train_dataset.labels)
# API说明: https://paddlex.readthedocs.io/zh_CN/release-1.3/appendix/model_zoo.html
model = pdx.det.YOLOv3(num_classes=num_classes, backbone='MobileNetV1')
2.模型参数调整
调整参数,包括训练轮数等,以提高训练效果
# 各参数介绍与调整说明:https://paddlex.readthedocs.io/zh_CN/release-1.3/appendix/parameters.html
model.train(
num_epochs=260,
train_dataset=train_dataset,
train_batch_size=8,
eval_dataset=eval_dataset,
learning_rate=0.000125,
warmup_steps=800, #默认值为1000,但代码运行时提示“warmup_steps should less than 852 or lr_decay_epochs[0] greater than 250, please modify 'lr_decay_epochs' or 'warmup_steps' in train function”
warmup_start_lr=0.0,
save_interval_epochs=20,
lr_decay_epochs=[213, 240],
lr_decay_gamma=0.1,
save_dir='output/yolov3_MobileNetV1',
use_vdl=True)
3.模型评估测试记录最优模型参数
模型在训练(对应train)时会自动输出每个循环的loss(损失函数)和相应的lr(学习率),
每20步(因为我设置了20步记录一次数据)就会评估(对应eval)计算bbox_map来判断模型的优劣。
同时程序会自动记录bbox_map大的情况相应的参数,作为best_model(存在于/home/aistudio/work/PaddleDetection/output/yolov3_MobileNetV1/best_model)
2021-08-22 17:00:46 [INFO] Downloading MobileNetV1_pretrained.tar from http://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV1_pretrained.tar
0%| | 0/16760 [00:00<?, ?KB/s]
100%|██████████| 16760/16760 [00:02<00:00, 6423.04KB/s]
2021-08-22 17:00:49 [INFO] Decompressing output/yolov3_MobileNetV1/pretrain/MobileNetV1_pretrained.tar...
2021-08-22 17:00:54 [INFO] Load pretrain weights from output/yolov3_MobileNetV1/pretrain/MobileNetV1_pretrained.
2021-08-22 17:00:55 [INFO] There are 135 varaibles in output/yolov3_MobileNetV1/pretrain/MobileNetV1_pretrained are loaded.
2021-08-22 17:00:59 [INFO] [TRAIN] Epoch=1/260, Step=2/4, loss=13592.521484, lr=0.0, time_each_step=2.36s, eta=0:41:24
2021-08-22 17:01:00 [INFO] [TRAIN] Epoch=1/260, Step=4/4, loss=12940.431641, lr=0.0, time_each_step=1.26s, eta=0:21:59
2021-08-22 17:01:00 [INFO] [TRAIN] Epoch 1 finished, loss=12729.964844, lr=0.0 .
。。。。。。。
2021-08-22 17:16:54 [INFO] [TRAIN] Epoch=260/260, Step=2/4, loss=3.226903, lr=1e-06, time_each_step=0.83s, eta=0:0:6
2021-08-22 17:16:54 [INFO] [TRAIN] Epoch=260/260, Step=4/4, loss=8.953383, lr=1e-06, time_each_step=0.82s, eta=0:0:4
2021-08-22 17:16:54 [INFO] [TRAIN] Epoch 260 finished, loss=5.416579, lr=1e-06 .
2021-08-22 17:16:54 [INFO] Start to evaluating(total_samples=2, total_steps=1)...
100%|██████████| 1/1 [00:01<00:00, 1.76s/it]
2021-08-22 17:16:56 [INFO] [EVAL] Finished, Epoch=260, bbox_map=54.545455 .
2021-08-22 17:16:56 [INFO] Model saved in output/yolov3_MobileNetV1/epoch_260.
2021-08-22 17:16:56 [INFO] Current evaluated best model in eval_dataset is epoch_180, bbox_map=100.0
4.模型预测
4.1 批量预测
使用model.predict接口来完成对大量数据集的批量预测。
#解压测试文件
!unzip -oq /home/aistudio/Test.zip -d /home/aistudio/Test
#使用未测试过的图片,进行批量预测
%cd /home/aistudio/work/PaddleDetection
model = pdx.load_model('output/yolov3_MobileNetV1/best_model')
image_dir = '/home/aistudio/Test'
images = os.listdir(image_dir)
for img in images:
image_name = image_dir +"/" +img
result = model.predict(image_name) # 进行预测操作
pdx.det.visualize(image_name, result, threshold=0.01, save_dir='/home/aistudio/Result') #定义预测结果输入参数,其中threshold为预测精度临界值,只有高于此值才显示预测结果
#展示模型推理结果
image_dir = '/home/aistudio/Test'
images = os.listdir(image_dir)
for img in images:
image_name = image_dir +"/" +img
yuanshi = Image.open(image_name)
plt.imshow(yuanshi) #根据数组绘制图像
plt.show() #显示图像
yuce=Image.open('/home/aistudio/Result/visualize_'+img)
plt.imshow(yuce) #根据数组绘制图像
plt.show() #显示图像
5.模型输出
根据https://ai.baidu.com/ai-doc/HWCE/ykqhhu7tm?qq-pf-to=pcqq.group#%E6%A8%A1%E5%9E%8B%E5%AF%BC%E5%87%BA 介绍输出模型。
并检验输出模型的性能
#输出模型
%cd /home/aistudio/work/PaddleDetection/
!paddlex --export_inference --model_dir=./output/yolov3_MobileNetV1/best_model --save_dir=./inference_model --fixed_input_shape=[416,416]
#使用之前的Test文档数据集测试所输出的模型的性能
%cd /home/aistudio/work/PaddleDetection
model = pdx.load_model('inference_model')
image_dir = '/home/aistudio/Test'
images = os.listdir(image_dir)
for img in images:
image_name = image_dir +"/" +img
result = model.predict(image_name) # 进行预测操作
pdx.det.visualize(image_name, result, threshold=0.01, save_dir='/home/aistudio/Result1') #定义预测结果输入参数,其中threshold为预测精度临界值,只有高于此值才显示预测结果
#展示所输出的模型推理结果
image_dir = '/home/aistudio/Test'
images = os.listdir(image_dir)
for img in images:
image_name = image_dir +"/" +img
yuanshi = Image.open(image_name)
plt.imshow(yuanshi) #根据数组绘制图像
plt.show() #显示图像
yuce=Image.open('/home/aistudio/Result1/visualize_'+img)
plt.imshow(yuce) #根据数组绘制图像
plt.show() #显示图像
#根据数组绘制图像
plt.show() #显示图像
yuce=Image.open('/home/aistudio/Result1/visualize_'+img)
plt.imshow(yuce) #根据数组绘制图像
plt.show() #显示图像
#根据结果发现,所输出的模型的识别能力有所下降
导出的文件,使用easyedge是能制作出一个app识别废水。感谢百度提供的Edgeboard开发板和usb摄像头,感谢AI Studio的大佬们,小弟下面继续完成部署。
6.Edgeboard部署
6.1实现PC与开发板的连接
1、本人使用usb线通过串口COM4实现PC与开发板连接,步骤如下:
(1)安装驱动:初次使用usb转串口设备需安装驱动 CP210x_Windows_Drivers,下载链接:https://cn.silabs.com/developers/usb-to-uart-bridge-vcp-drivers
(2)安装调试工具:下文以MobaXterm工具为例来介绍,工具下载:https://mobaxterm.mobatek.net/download.html 「尊重知识产权,遵守工具使用规范,推荐您使用正版软件」
(3)保证电脑已连接EdgeBoard的USB UART接口(接口位置请参考对应型号的硬件介绍),进入【控制面包->硬件和声音->设备管理器】查看设备管理器中映射的端口号,如图所示,端口号为COM4
(4)打开MobaXterm,点击Session,进入Session settings,选择Serial,Serial port选择映射出的端口,Speed为115200,Flow Control为None,点击OK,如下图所示
(5)配置完成后进入Session页面,给Edgeboard上电(按黑色按钮),会看到系统启动信息,待启动完成后输入用户名和密码root/root,即可进入设备系统。如下图所示
(6)打开MobaXterm,点击Session,进入Session settings,选择SFTP,Remote host填写开发板默认网关192.168.1.254,Username为root,其他默认,点击OK,如下图所示
2、本人使用网线连接开发板和PC,实现开发板上外网(毕竟程序运行时需要下载一些模块)
(1)设置网络连接,包括无线网络连接需要共享,以及网线端口的网址设置,如图
(2)使用PC下载tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl 到电脑
(3)把文件拉到SFTP页面中
(3)使用Serial页面,进入Downloads文件夹,执行安装的代码
6.2安装EdgeBoard管理系统
1、使用PC下载edge-management压缩包,然后把压缩包拉到SFTP页面中,
2、使用Serial页面,进入Downloads文件夹,执行安装的代码
然后等待安装,10分钟左右后安装完毕,会在页面输出提示 :
edge managment install success, please reboot your edgeboard
3、安装完毕,重启开发板(按黑色按钮)生效。
4、使用Microsoft Edge进入网址192.168.1.254:8899,使用admin作为密码登录
6.3下载模型所需文件
无论是直接部署,还是通过EasyEdge进行部署,都需要我们从AIstudio上下载以下几个文件:
1、标签文件
2、模型参数文件,并分别改名成"model"和"params"
3、用于测试的图片(或用作程序的封面图片)
6.4使用EdgeBoard管理系统完成部署
参考如下网页https://ai.baidu.com/ai-doc/HWCE/Zkqqbei1i
6.5根据官方PaddleLiteDemo完成部署
1、使用PC下载PaddleLiteDemo.zip
2、在PC端解压压缩包,然后把PaddleLiteDemo\Python内的core文件夹复制并粘贴到demo内
3、通过SFTP,把桌面的PaddleLiteDemo文件夹拉到开发板上
4、把下载的模型文件通过SFTP替换
5、在SFTP页面打开config.json,设置合适的预测阈值
6、单张图片预测
(1)Python预测
在Serial页面首先输入:
cd workspace/PaddleLiteDemo/Python/demo
然后设置预测结果输出路径位置,输入:
export PYTHONPATH=/home/root/workspace/PaddleLiteDemo/Python/
最后执行预测操作,输入:
python3 detection.py …/…/configs/detection/yolov3/image.json
(2)C++预测
在Serial页面依次输入划线指令
结果产生3个可执行文件:
classification : 分类示例
detection: 检测示例
segmentation: 分割示例
进入build目录(如果已经进入忽略这一操作)
cd workspace/PaddleLiteDemo/C++/build
执行模型配置进行预测
./detection …/…/configs/detection/yolov3/image.json
7、开启摄像头预测
(1)开启摄像头
这部分的驱动和摄像头测试程序,来源于郑先生(这个人也太优秀了吧~快来AI Studio看看~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/147378 )
通过SFTP,把桌面的driver文件夹中文件拉到开发板上
在Serial页面依次输入下图两个指令,安装驱动程序
运行摄像头测试程序,观察是否有图像坐标显示,测试完成按Ctrl+C退出
(2)Python预测
在Serial页面首先输入:
cd workspace/PaddleLiteDemo/Python/demo
然后设置预测结果输出路径位置,输入:
export PYTHONPATH=/home/root/workspace/PaddleLiteDemo/Python/
最后执行预测操作,输入:
python3 detection.py …/…/configs/detection/yolov3/usb_camera.json
(3)C++预测
进入build目录(如果已经进入忽略这一操作)
cd workspace/PaddleLiteDemo/C++/build
执行模型配置进行预测
./detection …/…/configs/detection/yolov3/usb_camera.json
四、效果展示
在EdgeBoard中根据PaddleLiteDemo部署模型,操作方便、效果也不错。
(1)单张图片预测
(2)摄像头预测
五、总结与升华
本项目所选用的数据集太简单,因此精确度不高:
(1)单张图片预测,阈值只能设置为0.05,才能勉强把排污口废水和河道湖水(合格水)区分出来
(2)使用摄像头,对电脑图片区分时,阈值若仍为0.05,效果不太好。需要把阈值降低到0.03才有结果显示。
对策:增加数据集的量,提高模型精度。
个人简介
我在AI Studio上获得青铜等级,点亮1个徽章,来互关呀~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/134639