作为测试和记录,就随便试一个数据集,AID数据集,AID数据集是一个遥感影像数据集,其包含 30 个类别的场景图像,其中每个类别有约 220 – 420 张,整体共计 10000 张,其中每张像素大小约为 600*600。
PaddleX全流程模型训练
-
PaddleX是基于飞桨核心框架、开发套件和工具组件的深度学习全流程开发工具。具备 全流程打通 、融合产业实践 、易用易集成 三大特点。这里是体验的PaddleX的GUI版本,当然咔咔写几句代码也是很简单的。
-
Win10平台,可以先在官网下载Win10版的GUI版本,安装上,进入界面,创建一个图像分类任务,名字描述路径开心就好。
-
完事儿之后会让你搞个数据集,这里可以直接选择我们下载好的AID数据集(网上到处都是),里面的文件结构刚刚好满足要求,导入,然后划分数据集,这里就按默认的吧,还可以看类别的分布,挺不错的。
-
然后就可以选择模型设置超参数了。里面支持了大部分工业上常用的模型,工业上基本使用的就是这些常用的。这里随便选了一个小小的MobileNetV3,轮数使用的10轮(懒得等),其他参数我都没动。
-
然后就干等这就是了。还能打开VisualDL看看学习情况。
-
2060还是挺快,6分钟就好了,验证集精度95%,差不多了,反正都是做实验的。这里还可以进行模型裁剪,没事点了一下,居然裁了30分钟,具体裁了啥也管,就酱吧。
-
然后保存出来,手贱又点了下量化,这个挺快的,分分钟。量化后精度稍微有所下降。裁剪和量化可以在略微降低精度的情况下大大减小占用的内存和推理时间,这里的可以去GitHub看看PaddleSlim
-
OK,这就是导出来的inference模型。里面就这,包括模型、参数和、包括一些配置啥的。
编译C++动态链接库
- 其实官方提供了一个平台部署的手册,只是部署出来是个exe,可以用cmd或者powershell带参数使用。作为新手,还是先跟着官方走一走。
- 写的挺详细的,跟着一走就搞定,里面有些坑也说了,比如CUDA最好按官方的预测库用9.0/10.0等等的,不要用10.1什么的,所以我就直接用的CPU的。这是跟着官方做出来的exe的使用效果。
- 好,现在需要编译成dll了,网上还是有几篇讲这个的,反正我跟着没一篇做出来了,但是都提供了很好的方向。我们就基于之前用官网手册做出来的那个Visual Studio 2019的界面,找到
CMakeLists.txt
,对其中做一点修改。由于我们这里是分类任务,所以修改的都是叫Classifier
的东东,其他的Segmenter(分割的)、Detector(识别的)都不用管。这里把Classifier那三行注释了,改成这三行,意思就是我不要exe了,我要dll。
# add_executable(classifier demo/classifier.cpp src/transforms.cpp src/paddlex.cpp)
# ADD_DEPENDENCIES(classifier ext-yaml-cpp)
# target_link_libraries(classifier ${DEPS})
add_library(classifier SHARED demo/classifier.cpp src/transforms.cpp src/paddlex.cpp)
ADD_DEPENDENCIES(classifier ext-yaml-cpp)
target_link_libraries(classifier ${DEPS})
- 完事还有个地方要改,就是
classifier.cpp
,如果是什么分割、识别、视频等等任务找到对应的cpp。因为他本来是个搞exe的,里面有个main,我们只需要改成一个预测的函数就OK了。把他的代码注释了,然后改一改(我是这样改的【本人C++很菜,学过一周的水平,一边百度一边改】),就是一个这个LoadModel函数,参数是图像路径和模型路径,返回一个预测结果。里面最坑的就是C++这个dll传入和返回在C#的类型,什么std:string、char*、IntPrt、StringBuilder什么的,搞了半天人都搞傻了!网上说啥的都有,最后这样确定是可以了。
#include <glog/logging.h>
#include <omp.h>
#include <algorithm>
#include <chrono>
#include <fstream>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
#include "include/paddlex/paddlex.h"
extern "C" __declspec(dllexport) const char* LoadModel(char* c_image_path, char* c_model_dir);
char res[50]; // 全局变量
__declspec(dllexport) const char* LoadModel(char* c_image_path, char* c_model_dir) {
// 类型转换
std::string image_path = c_image_path;
std::string model_dir = c_model_dir;
// 默认参数,不使用GPU
bool use_gpu = false;
bool use_trt = false;
bool use_mkl = true;
int mkl_thread_num = omp_get_num_procs();
int gpu_id = 0;
std::string key = "";
PaddleX::ClsResult result;
// 读取图片
cv::Mat im = cv::imread(image_path, 1);
// 加载模型和得到分类结果
PaddleX::Model model;
model.Init(model_dir, use_gpu, use_trt, use_mkl, mkl_thread_num, gpu_id, key);
model.predict(im, &result);
// 结果返回
strcpy_s(res, result.category.c_str());
return res;
}
-
这两个地方改完了就可以重新在CMake设置中
保存并生成CMake缓存以加载变量
,然后重新生成就OK,开心,在老地方看到dll了。
-
我们可以先用(按照网上的办法)确认下这个dll能不能用,用Python的
ctypes
即可,传入参数这儿经过百度看到的,怎么解析就没去看了,试了几个不行,一想最后也不是要用Python,就懒得管了,知道有输出就行了。【尴尬中间打错了,多打了一个’号,懒得重新截图】
得到的结果就酱。
本地C#窗体程序部署
-
随便拖个窗体,拉个按钮、显示框啥啥的,把东西都放在Debug那个目录下面。特别是用于预测的东东。
-
开始撸(复制粘贴)。不要问我啥啥托管非托管,搞不懂,反正就是看了很多大佬的最后发现这个得行。
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("classifier.dll", EntryPoint = "LoadModel", CharSet = CharSet.Ansi)]
public static extern IntPtr LoadModel(
[MarshalAs(UnmanagedType.LPStr)]string imgPath,
[MarshalAs(UnmanagedType.LPStr)]string modelPath
);
private void button1_Click(object sender, EventArgs e)
{
string imgPath = "airport_1.jpg";
string modelPath = "inference_model";
pictureBox1.ImageLocation = imgPath; // 加载图像显示
IntPtr result = LoadModel(imgPath, modelPath);
string result2 = Marshal.PtrToStringAnsi(result);
label2.Text = result2.ToString();
}
}
}
- 就酱就完了,但是中间有个坑,在cpp的生成的时候,默认的是X64的平台,而这个上面看着写的Any CPU,事实上,他是先用的X86的,所以代码会一直报一个我忘了的错,反正百度就是说什么64位和32位混用了。这里可以在配置里面设置下用X64就对了(他那个Any CPU下面有勾了那个首选32位,所以搞不到事)。
- 真的完事了,干了一天,试一试,运行,出界面。
点击打开图像(路径都写死了,哈哈,就是为了测试一下)
可以嘛,Airport张口就来。
收工,现在到明年这段时间该耍了,再看东西是狗