前言

在上一次的测试中,我们按照官方给的流程,使用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进行保存

  1. fluid.io.save_inference_model(model_save_dir,['images'],[predict], exe,params_filename="mlp" + '-params',model_filename="mlp" + '-model',)

如图所示,在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.  
  4. set(CMAKE_CXX_STANDARD 14)
  5. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")
  6.  
  7. add_definitions(-DPADDLE_MOBILE_FPGA_V1)
  8. add_definitions(-DPADDLE_MOBILE_FPGA)
  9.  
  10. set(PADDLE_LIB_DIR "${PROJECT_SOURCE_DIR}/lib" )
  11. set(EASYDL_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include" )
  12. set(PADDLE_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include/paddle-mobile" )
  13.  
  14. set(APP_NAME "paddle_edgeboard" )
  15.  
  16. aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC)
  17.  
  18. find_package(OpenCV QUIET COMPONENTS core videoio highgui imgproc imgcodecs ml video)
  19. include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
  20. #list(APPEND Caffe_LINKER_LIBS ${OpenCV_LIBS})
  21. message(STATUS "OpenCV found (${OpenCV_CONFIG_PATH}),${OpenCV_LIBS}")
  22. #add_definitions(-DUSE_OPENCV)
  23.  
  24. include_directories(${EASYDL_INCLUDE_DIR})
  25. include_directories(${PADDLE_INCLUDE_DIR})
  26. LINK_DIRECTORIES(${PADDLE_LIB_DIR})
  27.  
  28. add_executable(${APP_NAME} ${SRC})
  29. target_link_libraries(${APP_NAME} paddle-mobile)
  30. target_link_libraries(${APP_NAME} ${OpenCV_LIBS} )

4、main.cpp

  1. #include
  2. #include "io/paddle_inference_api.h"
  3. #include "math.h"
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include
  13. #include
  14. #include "fpga/KD/float16.hpp"
  15. #include "fpga/KD/llapi/zynqmp_api.h"
  16.  
  17. using namespace paddle_mobile;
  18.  
  19. #include
  20. #include
  21. using namespace cv;
  22.  
  23. cv::Mat sample_float;
  24.  
  25. static std::vector label_list(10);
  26.  
  27. void readImage(std::string filename, float* buffer) {
  28. Mat img = imread(filename);
  29. if (img.empty()) {
  30. std::cerr << "Can't read image from the file: " << filename << std::endl;
  31. exit(-1);
  32. }
  33.  
  34. Mat img2;
  35. resize(img, img2, Size(32,32));
  36.  
  37. img2.convertTo(sample_float, CV_32FC3);
  38.  
  39. int index = 0;
  40. for (int row = 0; row < sample_float.rows; ++row) {
  41. float* ptr = (float*)sample_float.ptr(row);
  42. for (int col = 0; col < sample_float.cols; col++) {
  43. float* uc_pixel = ptr;
  44. // uc_pixel[0] -= 102;
  45. // uc_pixel[1] -= 117;
  46. // uc_pixel[1] -= 124;
  47. float r = uc_pixel[0];
  48. float g = uc_pixel[1];
  49. float b = uc_pixel[2];
  50.  
  51. buffer[index] = b / 255.0;
  52. buffer[index + 1] = g / 255.0;
  53. buffer[index + 2] = r / 255.0;
  54.  
  55. // sum += a + b + c;
  56. ptr += 3;
  57. // DLOG << "r:" << r << " g:" << g << " b:" << b;
  58. index += 3;
  59. }
  60. }
  61. // return sample_float;
  62. }
  63.  
  64. PaddleMobileConfig GetConfig() {
  65. PaddleMobileConfig config;
  66. config.precision = PaddleMobileConfig::FP32;
  67. config.device = PaddleMobileConfig::kFPGA;
  68. // config.model_dir = "../models/mobilenet/";
  69. config.prog_file = "../model/mlp/model";
  70. config.param_file = "../model/mlp/params";
  71. config.thread_num = 4;
  72. return config;
  73. }
  74.  
  75. int main() {
  76. clock_t startTime,endTime;
  77.  
  78. zynqmp::open_device();
  79. std::cout << " open_device success " << std::endl;
  80. PaddleMobileConfig config = GetConfig();
  81. std::cout << " GetConfig success " << std::endl;
  82. auto predictor =
  83. CreatePaddlePredictor(config);
  84. std::cout << " predictor success " << std::endl;
  85.  
  86. startTime = clock();//计时开始
  87.  
  88. float data[1 * 3 * 32 * 32] = {1.0f};
  89. readImage("../image/cat.jpg", data);
  90.  
  91. endTime = clock();//计时结束
  92. std::cout << "The run time of image process is: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << std::endl;
  93.  
  94. PaddleTensor tensor;
  95. tensor.shape = std::vector({1, 3, 32, 32});
  96. tensor.data = PaddleBuf(data, sizeof(data));
  97. tensor.dtype = PaddleDType::FLOAT32;
  98. std::vector paddle_tensor_feeds(1, tensor);
  99.  
  100. PaddleTensor tensor_out;
  101. tensor_out.shape = std::vector({});
  102. tensor_out.data = PaddleBuf();
  103. tensor_out.dtype = PaddleDType::FLOAT32;
  104. std::vector outputs(1, tensor_out);
  105.  
  106. std::cout << " before predict " << std::endl;
  107.  
  108. predictor->Run(paddle_tensor_feeds, &outputs);
  109.  
  110. std::cout << " after predict " << std::endl;
  111. // assert();
  112.  
  113. endTime = clock();//计时结束
  114. std::cout << "The run time of predict is: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << std::endl;
  115.  
  116. float* data_o = static_cast(outputs[0].data.data());
  117. for (size_t j = 0; j < outputs[0].data.length() / sizeof(float); ++j) {
  118. std::cout << "output[" << j << "]: " << data_o[j] << std::endl;
  119. }
  120.  
  121. int index = 0;
  122. float max = 0.0;
  123. for (int i = 0;i < 10; i++) {
  124. float val = data_o[i];
  125. if (val > max) {
  126. max = val > max ? val : max;
  127. index = i;
  128. }
  129. }
  130.  
  131. label_list = {"airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse",
  132. "ship", "truck" };
  133. std::cout << "Result" << " is " << label_list[index] << std::endl;
  134.  
  135. return 0;
  136. }

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秒

总结

优点:

1、EdgeBoard内置的Paddle-Mobile,可以与Paddle训练出来的模型进行较好的对接。
2、预测速度上: Edge在预测小模型的时候,能与双核CPU和GPU在一个数量级,估计是模型较小,batch size也为1,gpu,cpu的性能优势抵不过通信的开销,后续将进行大模型、高batch size的测试。
3、提供的demo也足够简单,修改起来难度很低。
不足:

Paddle-Mobile相关文档具有一定门槛,且较为分散。初次使用的时候会走一些弯路出现问题的时候往往是个黑盒,不易于定位。在这次进行模型训练的尝试中,出现过一次op不支持的情况,我们在官网上甚至没有找到支持的op列表,这个在开发哥们的支持下升级版本后解决。如果后续能在稳定的固件版本下使用,并有比较易用的sdk,开发门槛可能会进一步降低。

 

作者:Litchll

Edgeboard试用 — 基于CIFAR10分类模型的移植的更多相关文章

  1. 基于Distiller的模型压缩工具简介

    Reference: https://github.com/NervanaSystems/distiller https://nervanasystems.github.io/distiller/in ...

  2. 笔记︱风控分类模型种类(决策、排序)比较与模型评估体系(ROC/gini/KS/lift)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 本笔记源于CDA-DSC课程,由常国珍老师主讲 ...

  3. 【AUC】二分类模型的评价指标ROC Curve

    AUC是指:从一堆样本中随机抽一个,抽到正样本的概率比抽到负样本的概率大的可能性! AUC是一个模型评价指标,只能用于二分类模型的评价,对于二分类模型,还有很多其他评价指标,比如logloss,acc ...

  4. NLP学习(2)----文本分类模型

    实战:https://github.com/jiangxinyang227/NLP-Project 一.简介: 1.传统的文本分类方法:[人工特征工程+浅层分类模型] (1)文本预处理: ①(中文) ...

  5. 风控分类模型种类(决策、排序)比较与模型评估体系(ROC/gini/KS/lift)

    python信用评分卡建模(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_ca ...

  6. 使用Keras基于RCNN类模型的卫星/遥感地图图像语义分割

    遥感数据集 1. UC Merced Land-Use Data Set 图像像素大小为256*256,总包含21类场景图像,每一类有100张,共2100张. http://weegee.vision ...

  7. 【tornado】系列项目(二)基于领域驱动模型的区域后台管理+前端easyui实现

    本项目是一个系列项目,最终的目的是开发出一个类似京东商城的网站.本文主要介绍后台管理中的区域管理,以及前端基于easyui插件的使用.本次增删改查因数据量少,因此采用模态对话框方式进行,关于数据量大采 ...

  8. 【tornado】系列项目(一)之基于领域驱动模型架构设计的京东用户管理后台

    本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的“高富帅”. 一.预备知识: 1.接口: python中并没有类似java等其它语言中的接口类型,但是python中 ...

  9. DL4NLP——词表示模型(二)基于神经网络的模型:NPLM;word2vec(CBOW/Skip-gram)

    本文简述了以下内容: 神经概率语言模型NPLM,训练语言模型并同时得到词表示 word2vec:CBOW / Skip-gram,直接以得到词表示为目标的模型 (一)原始CBOW(Continuous ...

随机推荐

  1. 进程交互还可以使用QSharedMemory

    官方例子: http://doc.qt.io/qt-5/qtcore-ipc-sharedmemory-example.html 查了一下,QSharedMemory没有自带任何信号.我的想法: 1. ...

  2. WCSTOMBS 函数不支持中文件的解决方法(设置代码页)

    代码页没有进行设置.需要调用locale.h 中定义的一个函数设置默认的代码页 _tsetlocale(LC_ALL,_T(""));//设置代码页  wcstombs(sendB ...

  3. 在不开启事件循环的线程中使用QTimer(QThread::run函数自带事件循环,在构造函数里创建线程,是一种很有意思的线程用法) good

    引入 QTimer是Qt自带的定时器类,QTimer运行时是依赖于事件循环的,简单来说,在一个不开启事件循环(未调用exec() )的线程中,QTimer是无法使用的.通过分析Qt源码可发现,调用QT ...

  4. ACL FAQ

    acl 下载地址:https://sourceforge.net/projects/acl/https://github.com/zhengshuxin/acl/http://git.oschina. ...

  5. [迟到的万圣节向]可怕的python

    什么?python简单易懂好学可读性高灵活耐用扩展好? 预测下面几个小段落的输出,来看看这个能过几关? ============================ Stage 1 预测下列输出 def ...

  6. Flume 简介及基本使用

    一.Flume简介 Apache Flume是一个分布式,高可用的数据收集系统.它可以从不同的数据源收集数据,经过聚合后发送到存储系统中,通常用于日志数据的收集.Flume 分为 NG 和 OG (1 ...

  7. spring cloud 系列第2篇 —— eureka 高可用注册中心的搭建 (F版本)

    源码仓库地址:https://github.com/heibaiying/spring-samples-for-all 一.项目结构 eureka-server为服务注册中心,负责服务的管理: eur ...

  8. Go 程序是怎样跑起来的

    目录 引入 编译链接概述 编译过程 词法分析 语法分析 语义分析 中间代码生成 目标代码生成与优化 链接过程 Go 程序启动 GoRoot 和 GoPath Go 命令详解 go build go i ...

  9. 以实现MongoDB副本集状态的监控为例,看Telegraf系统中Exec输入插件如何编写部署

    既有的Telegraf 关于MongoDB的输入插件很难实现对副本集节点状态的监控,副本集节点状态有 PRIMARY.SECONDARY.RECOVERYING.ARBITER 等.现在我们尝试通过  ...

  10. python小方法 随笔记

    1. 元组和列表的接收 s1,s2 = [,] print(s1,s2) # 执行结果: 1 2 s3,s4 = (,) print(s3,s4)# 执行结果: 3 4 2. 变量值的交换 a = b ...