如何将PaddleDetection模型在树莓派4B上部署?
Posted 飞桨PaddlePaddle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将PaddleDetection模型在树莓派4B上部署?相关的知识,希望对你有一定的参考价值。
【飞桨开发者说】侯继旭,海南师范大学本三自动化专业在读,人工智能开发爱好者,曾获2019中国高校计算机大赛-人工智能创意赛海南省一等奖、2019年度海南省高等学校科学研究“人工智能”优秀成果奖
本项目以ssd_mobilenet_v1_voc算法为例,详细介绍了从准备数据集、到模型训练,并将模型部署到树莓派的全过程。缺训练数据的痛苦,相信做过模型训练的小伙伴们都深有感触。为了便于大家实战操作,训练数据统统提供!无需任何准备工作就可以体验全流程哈。
项目用到的开源工具包括百度的深度学习平台飞桨以及模型开发套件PaddleDetection、端侧部署工具Paddle Lite、百度一站式AI开发平台AI Studio和树莓派4B。可通过以下方式进行在线或者本地体验:
在线体验:
项目已在AI Studio上公开,包括数据集在内已经打包上传,代码可在线跑通,欢迎Fork!链接:https://aistudio.baidu.com/aistudio/projectdetail/331209
本地体验:
项目涉及的全部资料也都打包放在百度网盘(PaddleDetection、Paddle Lite Demo、Paddle Lite、opt),可下载到本地体验。
链接:https://pan.baidu.com/s/1IKT-ByVN9BaVxfqQC1VaMw 提取码:mdd1
数据集准备
本项目用的数据集格式是VOC格式,标注工具为labelimg,图像数据是手动拍摄获取。
-
点击Open Dir,打开文件夹,载入图片 -
点击Create RectBox,即可在图像上画框标注 -
输入标签,点击OK -
点击Save保存,保存下来的是XML文件
创建三个文件夹:Annotations、ImageSets、JPEGImages
在ImageSets下创建一个Main文件夹,并且在Mian文件夹下建立labellist.txt,里面存入标注的标签。
此labellist.txt文件复制一份与Annotations、ImageSets、JPEGImages同级位置放置。
其内容如下:
import os
import random
trainval_percent = 0.95 #训练集验证集总占比
train_percent = 0.9 #训练集在trainval_percent里的train占比
xmlfilepath = 'F:/Cola/Annotations'
txtsavepath = 'F:/Cola/ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
num= len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train= random.sample(trainval,tr)
ftrainval = open( 'F:/Cola/ImageSets/Main/trainval.txt', 'w')
ftest = open( 'F:/Cola/ImageSets/Main/test.txt', 'w')
ftrain = open( 'F:/Cola/ImageSets/Main/train.txt', 'w')
fval = open( 'F:/Cola/ImageSets/Main/val.txt', 'w')
for i in list:
name=total_xml[i][: -4]+ ' '
if i in trainval:
ftrainval. write(name)
if i in train:
ftrain. write(name)
else:
fval. write(name)
else:
ftest. write(name)
ftrainval. close()
ftrain. close()
fval. close()
ftest . close()
import os
import re
import random
devkit_dir = './'
output_dir = './'
def get_dir(devkit_dir, type):
return os. path.join(devkit_dir, type)
def walk_dir(devkit_dir):
filelist_dir = get_dir(devkit_dir, 'ImageSets/Main')
annotation_dir = get_dir(devkit_dir, 'Annotations')
img_dir = get_dir(devkit_dir, 'JPEGImages')
trainval_list = []
train_list = []
val_list = []
test_list = []
added = set()
for _, _, files in os.walk(filelist_dir):
for fname in files:
print(fname)
img_ann_list = []
if re. match( 'trainval.txt', fname):
img_ann_list = trainval_list
elif re. match( 'train.txt', fname):
img_ann_list = train_list
elif re. match( 'val.txt', fname):
img_ann_list = val_list
elif re. match( 'test.txt', fname):
img_ann_list = test_list
else:
continue
fpath = os. path.join(filelist_dir, fname)
for line in open(fpath):
name_prefix = line.strip().split()[ 0]
print(name_prefix)
added.add(name_prefix)
#ann_path = os. path.join(annotation_dir, name_prefix + '.xml')
ann_path = annotation_dir + '/' + name_prefix + '.xml'
print(ann_path)
#img_path = os. path.join(img_dir, name_prefix + '.jpg')
img_path = img_dir + '/' + name_prefix + '.jpg'
assert os. path.isfile(ann_path), 'file %s not found.' % ann_path
assert os. path.isfile(img_path), 'file %s not found.' % img_path
img_ann_list.append((img_path, ann_path))
print(img_ann_list)
return trainval_list, train_list, val_list, test_list
def prepare_filelist(devkit_dir, output_dir):
trainval_list = []
train_list = []
val_list = []
test_list = []
trainval, train, val, test = walk_dir(devkit_dir)
trainval_list.extend(trainval)
train_list.extend(train)
val_list.extend(val)
test_list.extend(test)
# print(trainval)
with open( os. path.join(output_dir, 'trainval.txt'), 'w') as ftrainval:
for item in trainval_list:
ftrainval. write(item[ 0] + ' ' + item[ 1] + ' ')
with open( os. path.join(output_dir, 'train.txt'), 'w') as ftrain:
for item in train_list:
ftrain. write(item[ 0] + ' ' + item[ 1] + ' ')
with open( os. path.join(output_dir, 'val.txt'), 'w') as fval:
for item in val_list:
fval. write(item[ 0] + ' ' + item[ 1] + ' ')
with open( os. path.join(output_dir, 'test.txt'), 'w') as ftest:
for item in test_list:
ftest. write(item[ 0] + ' ' + item[ 1] + ' ')
if __name__ == '__main__':
prepare_filelist(devkit_dir, output_dir)
将整个文件拷贝至 ./PaddleDetection/dataset/voc 下
num_classes: 3
def pascalvoc_label(with_background=True):
labels_map = {
'PepsiCola': 1,
'CocaCola': 2
}
if not with_background:
labels_map = {k: v - 1 for k, v in labels_map.items()}
return labels_map
创建项目
进入AI Studio创建项目
至此,创建项目完成。
环境配置
#安装Python依赖库
!pip install -r requirements.txt
#测试项目环境
! export PYTHONPATH=` pwd`: $PYTHONPATH
!python ppdet/modeling/tests/test_architectures.py
1. 设置环境变量
%env PYTHONPATH=/home/aistudio/PaddleDetection
2. 找到报错的文件添加以下代码
import sys
DIR = '/home/aistudio/PaddleDetection'
sys.path. append(DIR)
测试环境通过后,就可以开始训练了
开始训练
训练命令如下:
% cd home/aistudio/PaddleDetection/
!python -u tools/train.py -c configs/ssd/ssd_mobilenet_v1_voc.yml --use_tb=True -- eval
#测试,查看模型效果
% cd home/aistudio/PaddleDetection/
!python tools/infer.py -c configs/ssd/ssd_mobilenet_v1_voc.yml --infer_img=/home/aistudio/2001.jpg #infer_img输入需要预测图片的路径,看一下效果
模型转换
接下来,需要将原生模型转化为预测模型
!python -u tools/export_model.py -c configs/ssd/ssd_mobilenet_v1_voc.yml --output_dir=./inference_model_final
% cd /home/aistudio/
# 复制opt文件到相应目录下
!cp opt /home/aistudio/PaddleDetection/inference_model_final/ssd_mobilenet_v1_voc
# 进入预测模型文件夹
% cd /home/aistudio/PaddleDetection/inference_model_final/ssd_mobilenet_v1_voc
# 下载opt文件
# !wget https://github.com/PaddlePaddle/Paddle-Lite/releases/download/v2.3.0/opt
# 给opt加上可执行权限
!chmod +x opt
# 使用opt进行模型转化,将__model__和__params__转化为model.nb
!./opt --model_file=__model__ --param_file=__params__ --optimize_out_type=naive_buffer --optimize_out=./model
!ls
到目前为止,在AI Studio上的所有内容已经完成,生成了这个model.nb文件,就可将其部署在树莓派4B上使用。
预测库编译
Paddle Lite目前支持三种编译的环境:
-
Docker 容器环境 -
Linux(推荐 Ubuntu 16.04)环境 -
树莓派(推荐在树莓派上直接编译)
gcc、g++、git、make、wget、python
cmake(建议使用3.10或以上版本)
# 1. Install basic software
apt update
apt- get install -y --no-install-recomends
gcc g++ make wget python unzip
# 2. install cmake 3.10 or above
wget https://www.cmake.org/files/v3 .10/cmake -3.10 .3.tar.gz
tar -zxvf cmake -3.10 .3.tar.gz
cd cmake -3.10 .3
./configure
make
sudo make install
将 Paddle Lite 和 Paddle Lite Demo 移动至树莓派中,放在自己方便的目录下即可,在这里我的 Paddle Lite 放在了 /home/pi/ 下,将 Paddle Lite Demo 放在了 /home/pi/Desktop/ 下,并且将 /home/pi/Paddle/Paddle-Lite/lite/tools/build.sh 加上执行权限
cd /home/ pi/Paddle/Paddle-Lite
sudo ./lite/tools/build.sh
--build_extra=OFF
--arm_os=armlinux
--arm_abi=armv7hf
--arm_lang=gcc
tiny_publish
文件结构搭建
整体文件结构如下:
模型部署
接下来就是最后一步了,将模型放进文件中,稍作修改就大功告成了!
#!/bin/bash
# configure
#TARGET_ARCH_ABI=armv8 # for RK3399, set to default arch abi
TARGET_ARCH_ABI=armv7hf # for Raspberry Pi 3B
PADDLE_LITE_DIR=/home/pi/Desktop/Paddle-Lite-Demo/PaddleLite-armlinux-demo/object_detection_demo/Paddle-Lite
if [ "x$1" != "x" ]; then
TARGET_ARCH_ABI= $1
fi
# build
rm -rf build
mkdir build
cd build
cmake -DPADDLE_LITE_DIR= ${PADDLE_LITE_DIR} -DTARGET_ARCH_ABI= ${TARGET_ARCH_ABI} ..
make
#run
LD_LIBRARY_PATH= $LD_LIBRARY_PATH: ${PADDLE_LITE_DIR}/libs/ ${TARGET_ARCH_ABI} ./object_detection_demo ../models/model.nb ../labels/pascalvoc_label_list ../images/2001.jpg ./result.jpg
/home/ pi/Desktop/Paddle-Lite-Demo/PaddleLite-armlinux-demo/object_detection_demo/code
sudo ./run.sh
if (argc > 3) {
WARMUP_COUNT = 1;
REPEAT_COUNT = 5;
std:: string input_image_path = argv[ 3];
std:: string output_image_path = argv[ 4];
cv::Mat input_image = cv::imread(input_image_path);
cv::Mat output_image = process(input_image, word_labels, predictor);
cv::imwrite(output_image_path, output_image);
cv::imshow( "Object Detection Demo", output_image);
cv::waitKey( 0);
} else {
cv::VideoCapture cap( -1);
cap. set(cv::CAP_PROP_FRAME_WIDTH, 640);
cap. set(cv::CAP_PROP_FRAME_HEIGHT, 480);
if (!cap.isOpened()) {
return -1;
}
while ( 1) {
cv::Mat input_image;
cap >> input_image;
cv::Mat output_image = process(input_image, word_labels, predictor);
cv::imshow( "Object Detection Demo", output_image);
if (cv::waitKey( 1) == char( 'q')) {
break;
}
}
cap.release();
cv::destroyAllWindows();
}
#run
LD_LIBRARY_PATH= $LD_LIBRARY_PATH: ${PADDLE_LITE_DIR}/libs/ ${TARGET_ARCH_ABI} ./object_detection_demo ../models/ssd_mobilenet_v1_pascalvoc_for_cpu/best.nb ../labels/pascalvoc_label_list
#../images/2.jpg ./result.jpg
源代码如下:
cap. set(CV_CAP_PROP_FRAME_WIDTH, 640);
cap. set(CV_CAP_PROP_FRAME_HEIGHT, 480);
cap .set( cv ::CAP_PROP_FRAME_WIDTH, 640);
cap .set( cv ::CAP_PROP_FRAME_HEIGHT, 480);
-
Paddle Lite官方文档 https://paddle-lite.readthedocs.io/zh/latest/index.html -
PaddleDetection官方文档 https://github.com/PaddlePaddle/PaddleDetection -
系列文章:如何利用PaddleDetection做一个完整的项目 https://blog.csdn.net/yzl819819/article/details/104336990?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
有奖调研
以上是关于如何将PaddleDetection模型在树莓派4B上部署?的主要内容,如果未能解决你的问题,请参考以下文章