正文内容 评论(0)
作者 Litchll
摘要:前言 在上一周的测试中,我们按照官方给的流程,使用EasyDl快速实现了一个具有性别检测功能的人脸识别系统,那么 今天,我们将要试一下通过Paddlepaddle从零开始,训练一个自己的多分类模型,并进行嵌入式部署。 整个训练 过程和模型在:https://aistudio.baidu.com/aistudio/projectDetail/61103 下面详细介绍模型训练...
前言
在上一周的测试中,我们按照官方给的流程,使用EasyDl快速实现了一个具有性别检测功能的人脸识别系统,那么
今天,我们将要试一下通过Paddlepaddle从零开始,训练一个自己的多分类模型,并进行嵌入式部署。 整个训练
过程和模型在:https://aistudio.baidu.com/aistudio/projectDetail/61103 下面详细介绍模型训练的过程.
数据集准备
我们使用CIFAR10数据集。CIFAR10数据集包含60,000张32x32的彩色图片,10个类别,每个类包含6,000张。其中
50,000张图片作为训练集,10000张作为验证集。
1.!mkdir ‐p /home/aistudio/.cache/paddle/dataset/cifar
2.# wget将下载的文件存放到指定的文件夹下,同时重命名下载的文件,利用‐O
3.!wget "http://ai‐atest.bj.bcebos.com/cifar‐10‐python.tar.gz" ‐O cifar‐10‐python.tar.gz
4.!mv cifar‐10‐python.tar.gz /home/aistudio/.cache/paddle/dataset/cifar/
模型结构
我们选择了以三个卷积层串联一个全连接层的输出,作为猫狗分类的预测,采用固定维度输入,输出为分类数
1.def convolutional_neural_network(img):
2.# 第一个卷积‐池化层
3.conv_pool_1 = fluid.nets.simple_img_conv_pool(
4.input=img, # 输入图像
5.filter_size=5, # 滤波器的大小
6.num_filters=20, # filter 的数量。它与输出的通道相同
7.pool_size=2, # 池化层大小2*2
8.pool_stride=2, # 池化层步长
9.act="relu") # 激活类型
10.# 第二个卷积‐池化层
11.conv_pool_2 = fluid.nets.simple_img_conv_pool(
12.input=conv_pool_1,
13.filter_size=5,
14.num_filters=50,
15.pool_size=2,
16.pool_stride=2,
17.act="relu")
18.# 第三个卷积‐池化层
19.conv_pool_3 = fluid.nets.simple_img_conv_pool(
20.input=conv_pool_2,
21.filter_size=5,
22.num_filters=50,
23.pool_size=2,
24.pool_stride=2,
25.act="relu")
26.# 以softmax为激活函数的全连接输出层,10类数据输出10个数字
27.prediction = fluid.layers.fc(input=conv_pool_3, size=10, act='softmax')
28.return prediction
训练&验证
接下来在Paddlepaddle fluid上,进行训练。整个训练代码见附件train.py 模型验证,采用附件predict.py的代码进
行验证与运行时间的测量,选取一张狗的图:dog.jpg (可以fork首页链接aistudio平台上的demo) 连续预测10000
次,输出如下:
1.CPU 运行结果为:预处理时间为0.0006270000000085929,预测时间为:16.246494
2.Out:
3.im_shape的维度: (1, 3, 32, 32)
4.The run time of image process is
5.0.0006270000000085929
6.The run time of predict is
7.16.246494
8.results [array([[5.0159363e‐04, 3.5942634e‐05, 2.5955746e‐02, 4.7745958e‐02,
9. 9.9251214e‐03, 9.0146154e‐01, 1.9564393e‐03, 1.2230080e‐02,
10. 4.7619540e‐08, 1.8753216e‐04]], dtype=float32)]
11.infer results: dog
1.GPU V100 运行结果为:预处理时间为0.0006390000000067175,预测时间为:15.903074000000018
2.Out:
3.im_shape的维度: (1, 3, 32, 32)
4.The run time of image process is
5.0.0006390000000067175
6.The run time of predict is
7.15.903074000000018
8.results [array([[5.0159392e‐04, 3.5942641e‐05, 2.5955772e‐02, 4.7746032e‐02,
9. 9.9251205e‐03, 9.0146142e‐01, 1.9564414e‐03, 1.2230078e‐02,
10. 4.7619821e‐08, 1.8753250e‐04]], dtype=float32)]
11.infer results: dog
可以看到,模型可以正确的识别出图片中的动物为狗,接下来,我们就要尝试将这个模型部署到Edgeboard上面。
模型导出
我们需要将模型保存为模型文件model以及权重文件params,可以采用如下Paddle的API进行保存如图所示,在AiStudio的左侧打开模型文件所在的文件夹,下载mlp-model、mlp-params两个文件。
在Edgeboard上部署模型,完成预测
1、新建工程文件夹,目录结构如下(可以仿照sample里的resnet、inception例程):
1.‐sample_image_catdog
2. ‐build
3. ‐image
4. ‐include
5. ‐paddlepaddle‐mobile
6. ‐...
7. ‐lib
8. ‐libpaddle‐mobile.so
9. ‐model
10. ‐mlp
11. ‐model
12. ‐params
13. ‐src
14. ‐fpga_cv.cpp
15. ‐main.cpp
2、将AiStudio上导出来的模型放置在model里的mlp文件夹,修改名字为model、params
3、新建 CMakeLists.txt
1.cmake_minimum_required(VERSION 3.5.1)
2.project(paddle_edgeboard)
3.set(CMAKE_CXX_STANDARD 14)
4.set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ‐pthread")
5.add_definitions(‐DPADDLE_MOBILE_FPGA_V1)
6.add_definitions(‐DPADDLE_MOBILE_FPGA)
7.set(PADDLE_LIB_DIR "${PROJECT_SOURCE_DIR}/lib" )
8.set(EASYDL_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include" )
9.set(PADDLE_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include/paddle‐mobile" )
10.set(APP_NAME "paddle_edgeboard" )
11.aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC)
12.find_package(OpenCV QUIET COMPONENTS core videoio highgui imgproc imgcodecs ml video)
13.include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
14.#list(APPEND Caffe_LINKER_LIBS ${OpenCV_LIBS})
15.message(STATUS "OpenCV found (${OpenCV_CONFIG_PATH}),${OpenCV_LIBS}")
16.#add_definitions(‐DUSE_OPENCV)
17.include_directories(${EASYDL_INCLUDE_DIR})
18.include_directories(${PADDLE_INCLUDE_DIR})
19.LINK_DIRECTORIES(${PADDLE_LIB_DIR})
20.add_executable(${APP_NAME} ${SRC})
21.target_link_libraries(${APP_NAME} paddle‐mobile)
22.target_link_libraries(${APP_NAME} ${OpenCV_LIBS} )
4、main.cpp
1.#include
<
iostream
>
2.#include "io/paddle_inference_api.h"
3.#include "math.h"
4.#include
<
stdlib.h
>
5.#include
<
unistd.h
>
6.#include
<
fstream
>
7.#include
<
ostream
>
8.#include
<
fstream
>
9.#include
<
iomanip
>
10.#include
<
typeinfo
>
11.#include
<
typeindex
>
12.#include
<
vector
>
13.#include
<
ctime
>
14.#include "fpga/KD/float16.hpp"
15.#include "fpga/KD/llapi/zynqmp_api.h"
16.using namespace paddle_mobile;
17.#include
<
opencv2/highgui.hpp
>
18.#include
<
opencv2/imgproc.hpp
>
19.using namespace cv;
20.cv::Mat sample_float;
21.static std::vector
<
std::string
>
label_list(10);
22.void readImage(std::string filename, float* buffer) {
23.Mat img = imread(filename);
24.if (img.empty()) {
25.std::cerr
<
<
"Can't read image from the file: "
<
<
filename
<
<
std::endl;
26.exit(1);
27.}
28.Mat img2;
29.resize(img, img2, Size(32,32));
30.img2.convertTo(sample_float, CV_32FC3);
31.int index = 0;
32.for (int row = 0; row
<
sample_float.rows; ++row) {
33.float* ptr = (float*)sample_float.ptr(row);
34.for (int col = 0; col
<
sample_float.cols; col++) {
35.float* uc_pixel = ptr;
36.// uc_pixel[0] ‐= 102;
37.// uc_pixel[1] ‐= 117;
38.// uc_pixel[1] ‐= 124;
39.float r = uc_pixel[0];
40.float g = uc_pixel[1];
41.float b = uc_pixel[2];
42.buffer[index] = b / 255.0;
43.buffer[index + 1] = g / 255.0;
44.buffer[index + 2] = r / 255.0;
45.// sum += a + b + c;
46.ptr += 3;
47.// DLOG
<
<
"r:"
<
<
r
<
<
" g:"
<
<
g
<
<
" b:"
<
<
b;
48.index += 3;
49.}
50.}
51.// return sample_float;
52.}
53.PaddleMobileConfig GetConfig() {
54.PaddleMobileConfig config;
55.config.precision = PaddleMobileConfig::FP32;
56.config.device = PaddleMobileConfig::kFPGA;
57.// config.model_dir = "../models/mobilenet/";
58.config.prog_file = "../model/mlp/model";
59.config.param_file = "../model/mlp/params";
60.config.thread_num = 4;
61.return config;
62.}
63.int main() {
64.clock_t startTime,endTime;
65.zynqmp::open_device();
66.std::cout
<
<
" open_device success "
<
<
std::endl;
67.PaddleMobileConfig config = GetConfig();
68.std::cout
<
<
" GetConfig success "
<
<
std::endl;
69.auto predictor =
70.CreatePaddlePredictor
<
PaddleMobileConfig,
71.PaddleEngineKind::kPaddleMobile
>
(config);
72.std::cout
<
<
" predictor success "
<
<
std::endl;
73.startTime = clock();//计时开始
74.float data[1 * 3 * 32 * 32] = {1.0f};
75.readImage("../image/cat.jpg", data);
76.endTime = clock();//计时结束
77.std::cout
<
<
"The run time of image process is: "
<
<
(double)(endTime ‐ startTime) /
78.CLOCKS_PER_SEC
<
<
"s"
<
<
std::endl;
79.PaddleTensor tensor;
80.tensor.shape = std::vector
<
int
>
({1, 3, 32, 32});
81.tensor.data = PaddleBuf(data, sizeof(data));
82.tensor.dtype = PaddleDType::FLOAT32;
83.std::vector
<
PaddleTensor
>
paddle_tensor_feeds(1, tensor);
84.PaddleTensor tensor_out;
85.tensor_out.shape = std::vector
<
int
>
({});
86.tensor_out.data = PaddleBuf();
87.tensor_out.dtype = PaddleDType::FLOAT32;
88.std::vector
<
PaddleTensor
>
outputs(1, tensor_out);
89.std::cout
<
<
" before predict "
<
<
std::endl;
90.predictor‐
>
Run(paddle_tensor_feeds, &outputs);
91.std::cout
<
<
" after predict "
<
<
std::endl;
92.// assert();
93.endTime = clock();//计时结束
94.std::cout << "The run time of predict is: " <<(double)(endTime ‐ startTime) / CLOCKS_PER_SEC
95.<
<
"s"
<
<
std::endl;
96.float* data_o = static_cast
<
float*
>
(outputs[0].data.data());
97.for (size_t j = 0; j
<
outputs[0].data.length() / sizeof(float); ++j) {
98.std::cout
<
<
"output["
<
<
j
<
<
"]: "
<
<
data_o[j]
<
<
std::endl;
99.}
100.int index = 0;
101.float max = 0.0;
102.for (int i = 0;i
<
10; i++) {
103.float val = data_o[i];
104.if (val
>
max) {
105.max = val
>
max ? val : max;
106.iindex = i;
107.}
108.}
109.label_list = {"airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse",
110."ship", "truck" };
111.std::cout
<
<
"Result"
<
<
" is "
<
<
label_list[index]
<
<
std::endl;
112.return 0;
113.}
5、编译运行
1.insmod /home/root/workspace/driver/fpgadrv.ko
2.cd /home/root/workspace/sample/sample_image_catdog
3.mkdir build
4.cd build
5.rm ‐rf *
6.cmake ..
7.make
8../paddle_edgeboard
修改main文件要预测的图像:
6、修改main文件后重复执行预测,可得结果如下:图像处理时间大概为:0.006秒,预测时间大概为:0.008秒
7、连续预测10000次所用时间为:23.7168
性能对比(连续预测10000次 单位:秒)
总结
优点:
1. EdgeBoard内置的Paddle-Mobile,可以与Paddle训练出来的模型进行较好的对接。
2. 预测速度上: Edge在预测小模型的时候,能与双核CPU和GPU在一个数量级,估计是模型较小,batch size也
为1,gpu,cpu的性能优势抵不过通信的开销,后续将进行大模型、高batch size的测试。
3. 提供的demo也足够简单,修改起来难度很低。
不足:
1. Paddle-Mobile相关文档具有一定门槛,且较为分散。初次使用的时候会走一些弯路出现问题的时候往往是个
黑盒,不易于定位。在这次进行模型训练的尝试中,出现过一次op不支持的情况,我们在官网上甚至没有找
到支持的op列表,这个在开发哥们的支持下升级版本后解决。如果后续能在稳定的固件版本下使用,并有比
较易用的sdk,开发门槛可能会进一步降低。