七万字详解paddle-openVINO【CPU】-从环境配置-模型部署全流程

七万字详解paddle-openVINO【CPU】-从环境配置-模型部署全流程

在这篇文章你将会接触到:paddle-openvino框架、两者在Linux、windows多种配置方式、使用LabelMe对paddle数据的标注转换与划分、图像分类/目标检测/实例分割/语义分割的数据格式、模型训练、训练参数调整、模型保存、模型压缩(裁剪量化)与模型导出(ONNX2)。
你将会接触到6个实战项目:paddle(人像分割- RGB遥感影像分割-多通道遥感影像分割-地块变化检测)和paddle with openvino(paddleyolo、paddleyolo3、paddleOCR )

期间参考了百余篇官方技术文档、借鉴了intel的优秀工程师张晶、许钰雯、彭家丽、贾志刚、庄建、杨亦诚、raymondlo、吴卓等八位工程师,百度飞桨工程师大佬毕然、孙高峰、周湘阳、刘威威的一些资料以及大量的paddle官方开源文献

目录

为什么要选择paddle+openVINO?

Paddlepaddle是国内百度推出的一款深度学习框架,Openvino是英特尔基于X86架构的芯片提出的一种部署方案。

飞桨主要解决的问题是AI开发者对于算力资源的巨大需求问题,飞桨提供了在线的云平台,你可以使用他们的算卡设备进行模型的训练与评估。

而openVINO解决对于主机上没有显卡或者算力不足的AI开发者的问题。

两个部分的联合,大大降低了AI开发者对于算力资源需求的门槛,从而实现较低成本的AI应用开发。使用飞桨训练的模型不能够直接部署到openVINO上,而是要经过两个转化。飞桨的模型导出ONNX模型,然后再将这个模型转换成为IR模型,才可以实现在openVINO上的部署。

会和TF、pytorch、caffe冲突吗?

这个部分不仅仅没有冲突,而且还有助于去理解这三个框架。飞桨的框架他的那很多语法都是和三者非常相似的,并且比较简单,容易上手。可以帮助你去在飞桨上理解一些在算法上比较复杂的架构。第二个是这三者也是可以在openVINO上部署的

三张图讲清openVINO-飞桨

这三张是来源于做Hackathon培训时三位intel工程师彭家丽、杨亦诚、raymondlo的资料,三张图就可以很好地把这个流程讲清晰。

1、openVINO部署流程

请添加图片描述

扫描二维码关注公众号,回复: 13771403 查看本文章

现在这个模型主要由构建、优化、部署工具去实现增量学习,基于我们开发者需要的数据对模型进行重新训练,可以实现我们对精度上和工业效率上的要求。既可以利用现有的open model zoo帮助我们的开发者,还可以基于主流的TF、pytorch、PP进行模型转化。

modeloptimizer和inference engine
在模型的优化阶段我们我们用到了两大核心组件,modeloptimizer和inference engine。前者主要是起到一个对第三方模型的一个转移和优化的作用,把它转化成为OPENVINO所支持的IR(intermediate representation.bin .xml)模型中间表达式。inference engine会读取这些IR模型表达式,并把它搭载到相应的硬件中,对它进行一个底层的优化,以及算子的合并和模型简化。部署是属于第三个阶段,在构建。

post-training optimization tool &deep learning workbench
比如post-training optimization tool主要是针对模型的一些特定的场景,做一些模型的量化和剪裁的工作。deep learning workbench是主要是可以基于一个可视化的web接口调节模型的一些精度,以及它的每个类的一个输入输出结果进行一个调优。

deep learning streaming
此之外呢,也集成了大量的第三方的一些工具。比如说deep learning streaming这样一个工具,帮助开发者去对decode和encode做串流的处理。openCL加速模型的前后处理以及一些优化加速和相对应的开发。

还有一些成品脚本是可以去对比应用模型的一个精度和性能的测试,以及相关性能的优化。

model server
那最后模型部署,是以服务器的形式部署在model server上的,只要通过request接口的形式去进行的调取这个模型的输出结果就能准确的获取到一个输出。(这个只是提一下,推荐大家使用百度的公有云服务器即可)

development manager
针对一些特定的这个边缘计算的场景,也提供了development manager。通过这个工具开发者就可以去针对工业领域的部署包进行一个剪裁。因为有的场景下,我们的开发者可能只需要cpu,不需要其他一些底层原厂的一些库,那我们可以把在部署的时候把这些库给它剔除掉,实现整个部署包的一个最小化。

最后整个软件也是支持在X86架构所有的硬件产品的部署。
请添加图片描述

2、paddlepaddle+OpenVINO

飞桨和openVINO两者之间的嵌套,其实就如上面的流程一样的,构建过程中我们使用paddle模型,然后将我们的飞桨模型通过转换器转换成IR模型,或者可以直接将一部分的飞桨模型部署到硬件上,从而实现了整个流程部署与开发。
请添加图片描述

openVINO软件架构

请添加图片描述

前端

openVINO软件架构可以分成这个前端和后端两个部分,那与之相对应的代码就是我们这个read_network函数接口和load_network这两个函数接口。那前端主要功能就是通过我们这个这个read_network接口去读取第三方模型并对其做一个解析,然后通过我们的一些通用的、优化的方式,对模型的一些layer进行一些优化.这些优化都是通用的,比如说基于比如说针对某些layer的比较稀疏的一些图进行一个图层融合,或者说把一些系统中的算子推理过程中可能不需要的,我们会把这个没有用的算子给他进行剔除。然后把转化好的模型转化成我们的CNNnetwork,也就是前端的功能。

那前端这个代码部分现在有主要有三个这样的构建方法。
首先可以基于我们的如下图左侧的这样一个参数接口,去自己手动去定一个模型的拓扑结构以及相应的参数,并把它转化成CNNnetwork的形式。

其次也通过modeloptimizer去转化一个第三方的模型,形成IR的模型中间表达式,并通过IR模型的进行一个读取和解析,直接去转化成这个CNNnetwork。

第三个也是最有挑战性的,通过paddle reader 组件直接把飞桨模型进行读取和加载。通过paddle converter这个组建一对一的映射到相对应算子中,实现对前端的支持,最后直接将paddle加载入CNNnetwork网络。

后端

通过load_network这个函数接口去指定模型要跑在哪一个硬件平台上。load_network这个函数接口会去加载刚才已经优化过的CNNnetwork,并把它去推到指定的硬件平台上去进行一个前端的推理。那在这个过程中会针对不同的硬件平台做一些定制化的优化,比如说我们会通过这个内存重排或者是一些并行推理,去实现一些深度优化,保证在指定平台上能达到一个最好的推理效能。通过这个接口也可以进行一些定制化的优化设定。比如说我们可以在这个接口上是指定在多个硬件平台上去运行,这样子可以实现对多数据流的支持。同时也可以实现异构推理这样一个模式,可以会同时去生成多个推理请求,然后把这些推理情况平均分配到不同的计算单元中,给多个任务进行同时的这样一个推理,提高整个网络的吞吐量。
请添加图片描述

这其中的困难主要有三部分

1、第一部分是不同环境的配置,现在主要是是WINDOWS系统和Linux系统的配置,苹果系统也可以用。
2、第二部分是对飞桨训练模型的掌握和导出与转化。
3、第三部分是如何将导出的模型进行转换成IR模型并部署到openVINO上。

(PS:如果对于应用已经熟练掌握后,可以尝试去做下不同模型的算子转化,这是非常底层的也是非常训练人基本功底的一个挑战,比如说PP-OPENVINO算子的转化等)

全流程的难点和重点就是这三个部分组成的,那我们就一次来解决这三个问题。

Paddlepaddle-PaddleX-openVINO安装与环境调配

先来简单介绍一下飞桨的架构组成吧,这个参考百度官方出品的“深度学习零基础时间”一书中一图,讲得十分清晰。对于不同的领域的学者都能够找到对应的体系,但是这里要说的是最核心的两个部分,一个是paddle,一个是paddleX,前者是最核心的框架,通过这个核心框架来使用其他的框架,而paddleX是开发的全流程工具,用来开发自己的AI模型。

请添加图片描述

PaddleX介绍

这里参考百度飞桨的官方技术文档点击深入了解

PaddleX可视化客户端基于PaddleX开发的可视化深度学习模型训练套件,目前支持训练视觉领域的图像分类、目标检测、实例分割和语义分割四大任务,同时支持模型裁剪、模型量化两种方式压缩模型。

PaddleX中的所有模型训练都可以总结为以下3个步骤
定义:过程、数据集和模型,就可以得到一个AI 模型
请添加图片描述

下面简单用代码展示一个开发的流程,但是这里不建议朋友们进行尝试,因为此时朋友的电脑中还没有安装paddlepaddle,但是可以帮助大家理解这个过程。

以蔬菜分类为例子演示PaddleX开发全流程

  1. 安装PaddleX

安装相关问题我们会在接下来详细讲述。

pip install paddlex -i https://mirror.baidu.com/pypi/simple
  1. 准备蔬菜分类数据集
wget https://bj.bcebos.com/paddlex/datasets/vegetables_cls.tar.gz
tar xzvf vegetables_cls.tar.gz
  1. 定义训练/验证图像处理流程transforms

因为训练时加入了数据增强操作,因此在训练和验证过程中,模型的数据处理流程需要分别进行定义。如下所示,代码在train_transforms中加入了RandomCrop和RandomHorizontalFlip两种数据增强方式, 更多方法可以参考官方的数据增强文档。

from paddlex.cls import transforms
train_transforms = transforms.Compose([
    transforms.RandomCrop(crop_size=224),
    transforms.RandomHorizontalFlip(),
    transforms.Normalize()
])
eval_transforms = transforms.Compose([
    transforms.ResizeByShort(short_size=256),
    transforms.CenterCrop(crop_size=224),
    transforms.Normalize()
])
  1. 定义dataset加载图像分类数据集

定义数据集,pdx.datasets.ImageNet表示读取ImageNet格式的分类数据集

train_dataset = pdx.datasets.ImageNet(
    data_dir='vegetables_cls',
    file_list='vegetables_cls/train_list.txt',
    label_list='vegetables_cls/labels.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.ImageNet(
    data_dir='vegetables_cls',
    file_list='vegetables_cls/val_list.txt',
    label_list='vegetables_cls/labels.txt',
    transforms=eval_transforms)
    
  1. 使用MobileNetV3_small_ssld模型开始训练

这里使用百度基于蒸馏方法得到的MobileNetV3预训练模型,模型结构与MobileNetV3一致,但精度更高。PaddleX内置了20多种分类模型

num_classes = len(train_dataset.labels)
model = pdx.cls.MobileNetV3_small_ssld(num_classes=num_classes)

model.train(num_epochs=20,
            train_dataset=train_dataset,
            train_batch_size=32,
            eval_dataset=eval_dataset,
            lr_decay_epochs=[4, 6, 8],
            save_dir='output/mobilenetv3_small_ssld',
            use_vdl=True)

  1. 训练过程使用VisualDL查看训练指标变化

训练过程中,模型在训练集和验证集上的指标均会以标准输出流形式输出到命令终端。当用户设定use_vdl=True时,也会使用VisualDL格式将指标打点到save_dir目录下的vdl_log文件夹,在终端运行如下命令启动visualdl并查看可视化的指标变化情况。

visualdl --logdir output/mobilenetv3_small_ssld --port 8001
服务启动后,通过浏览器打开https://0.0.0.0:8001或https://localhost:8001即可。

  1. 加载训练保存的模型预测

模型在训练过程中,会每间隔一定轮数保存一次模型,在验证集上评估效果最好的一轮会保存在save_dir目录下的best_model文件夹。通过如下方式可加载模型,进行预测。

import paddlex as pdx
model = pdx.load_model('output/mobilenetv3_small_ssld/best_model')
result = model.predict('vegetables_cls/bocai/100.jpg')
print("Predict Result: ", result)

预测结果输出如下,

Predict Result: Predict Result: [{'score': 0.9999393, 'category': 'bocai', 'category_id': 0}]

那么到现在,你就已经完成了一次AI模型的开发了,即使是再复杂的工业工程,都是这三个步骤的细化。

刚才我们提到,想要使用paddle X用户的电脑中就必须有paddlepaddle的环境(paddlepaddle-gpu或paddlepaddle(版本大于或等于1.8.1),那么接下来我来讲解一下不同环境下paddle的安装。

1、安装paddle paddle

首先每个用户的电脑环境都不一定相同,所以百度官方提供了如下页面的指导,打开下面的链接,选择你所属于的电脑环境,就可以获得相关安装指引,一般在十多分钟后就可以安装完成。
这里就以官方的指引为主了。

https://www.paddlepaddle.org.cn/install/quick?docurl=/documentation/docs/zh/install/pip/macos-pip.html
请添加图片描述

2.win/Mac/linux/anaconda/pip/pycocotools

安装paddleX

pip安装

下面是Windows安装命令

pip install paddlex -i https://mirror.baidu.com/pypi/simple

Anaconda安装

Anaconda是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。使用Anaconda可以通过创建多个独立的Python环境,避免用户的Python环境安装太多不同版本依赖导致冲突。
代码安装

git clone https://github.com/PaddlePaddle/PaddleX.git
cd PaddleX
git checkout release/1.3
python setup.py install

pycocotools安装问题

PaddleX依赖pycocotools包,如安装pycocotools失败,可参照如下方式安装pycocotools

Windows系统

Windows安装时可能会提示Microsoft Visual C++ 14.0 is required,从而导致安装出错,这个是时候需要下载VC build tools安装再执行如下pip命令
下载链接
https://go.microsoft.com/fwlink/?LinkId=691126

注意:安装完后,需要重新打开新的终端命令窗口

pip install cython
pip install git+https://gitee.com/jiangjiajun/philferriere-cocoapi.git#subdirectory=PythonAPI

Linux/Mac系统

Linux/Mac系统下,直接使用pip安装如下两个依赖即可

pip install cython  
pip install pycocotools
Next  Previous

3、openVINO安装与相关环境适配

如果是使用window操作系统的伙伴遇到困难可以参考之前写的一篇博客,里面有每步的截图。
博客链接

但是这里因为要和飞桨适配,所以下载的版本有一些特定的要求。这里推荐使用OpenVINO 2020.4与2021.1版本

注意:
由于PaddleX分割模型使用了ReSize-11 Op,OpenVINO 2021.1版本开始支持支持Resize-11 ,CPU下请务必下载OpenVINO 2021.1+版本
由于VPU在OpenVINO 2021.1版本下转换的分类模型会出现Range layer不支持的情况,VPU下请务必下载OpenVINO 2020.4版本

可以看下各大软硬设备对openVINO的支持
请添加图片描述

Windows安装openVINO

我们先来说下一些要装的环境
有什么问题如果看完后还是不懂,可以看下官方技术文档
https://docs.openvino.ai/latest/openvino_docs_install_guides_installing_openvino_windows.html

前置条件
Visual Studio 2019
OpenVINO 2020.4或者2021.1+
CMake 3.0+
python3.6+

还是再提醒一嘴:CPU下使用OpenVINO 2021.1+版本;VPU下请使用OpenVINO 2020.4版本

安装步骤

1、安装外部软件依赖项
2、安装OpenVINOTM工具包的英特尔®发行版
3、配置环境
4、配置模型优化器

第1步:安装外部软件依赖项

1、Microsoft Visual Studio* 2019 with MSBuild
https://visualstudio.microsoft.com/vs/older-downloads/#visual-studio-2019-and-other-products
2、CMake 3.14 or higher 64-bit
https://cmake.org/download/
3、Python - 64-bit
https://www.python.org/downloads/windows/

请添加图片描述

第2步:安装OpenVINOTM工具包核心组件的英特尔®发行版

1、从适用于Windows的OpenVINOTM工具包的英特尔®分发下载OpenVINOTM工具包包文件的英特尔®分发。从下拉菜单中选择适用于Windows的OpenVINOTM工具包的英特尔®发行版。

2、转到“Downloads”文件夹,双击中
w_openvino_toolkit_p_.exe,打开一个窗口,允许您选择安装目录和组件。

在这里插入图片描述

3、按照屏幕上的说明操作。注意以下信息,以防您必须完成其他步骤:

在这里插入图片描述

4、默认情况下,Intel®Distribution of OpenVINO™安装到以下目录,在文档的其他地方称为<INSTALL_DIR>: C:\Program Files (x86)\Intel\ openvino_。为了简单起见,还创建了一个最新安装的快捷方式:C:\Program Files (x86)\Intel\ openvino_2021。

5、可选:可以选择自定义来更改安装目录或要安装的组件。
在这里插入图片描述

单击“完成”以关闭安装向导。

单击“完成”以关闭安装向导后,将打开一个新的浏览器窗口,其中包含您正在阅读的文档(以防您没有安装),然后跳转到包含后续安装步骤的部分。
核心组件现已安装。继续下一节以安装其他依赖项。

第3步:配置环境

请添加图片描述

必须更新多个环境变量,然后才能编译和运行OpenVINOTM应用程序。打开命令提示符,然后运行setupvars.bat批处理文件以临时设置环境变量:

C:\程序文件 (x86)\Intel\openvino_2021\bin\setupvars.bat

注意:不建议运行配置命令的Windows PowerShell,改用命令提示符(cmd),这里我试过了,只能用终端,不是建议。

建议:关闭命令提示窗口时,OpenVINO工具包环境变量将被删除。作为一个选项,您可以手动永久设置环境变量。

第4步:配置模型优化器

Model Optimizer是基于Python的命令行工具,用于从流行的深度学习框架(如Caffe、TensorFlow*、Apache MXNet*、ONNX和Kaldi)导入训练有素的模型。

模型优化器是OpenVINO工具包英特尔发行的关键组件。对模型执行推断(ONNX和nGraph模型除外)需要通过模型优化器运行模型。当通过模型优化器转换预训练的模型时,输出是网络的中间表示(IR)。中间表示是一对描述整个模型的文件:

.xml:描述网络拓扑
.bin:包含权重和偏置二进制数据

1、在搜索窗口框中输入cmd打开命令提示符,然后按Enter键。在打开的窗口中输入命令:请添加图片描述

2、转到模型优化器先决条件目录。

cd C:\Program Files (x86)\Intel\openvino_2021\deployment_tools\model_optimizer\install_prerequisites

3、运行此批处理文件以配置Caffe、TensorFlow 2.x、MXNet、Kaldi*和ONNX的模型优化器:

install_prerequisites.bat

注意:安装完OpenVINO后需要手动添加OpenVINO目录到系统环境变量,否则在运行程序时会出现找不到dll的情况。以安装OpenVINO时不改变OpenVINO安装目录情况下为示例,
流程如下

我的电脑->属性->高级系统设置->环境变量

在系统变量中找到Path(如没有,自行创建),并双击编辑
新建,分别将OpenVINO以下路径填入并保存:

C:\Program File (x86)\IntelSWTools\openvino\inference_engine\bin\intel64\Release

C:\Program File (x86)\IntelSWTools\openvino\inference_engine\external\tbb\bin

C:\Program File (x86)\IntelSWTools\openvino\deployment_tools\ngraph\lib

请确保系统已经安装好上述基本软件,并配置好相应环境,下面所有示例以工作目录为 D:\projects演示。

window- paddle- openVINO勾连

这里使用c++下预测部署的方法

Step1: 下载PaddleX预测代码

打开win的终端,在在D盘下载预测代码

d:
mkdir projects
cd projects
git clone https://github.com/PaddlePaddle/PaddleX.git
cd PaddleX
git checkout release/1.3

说明:其中C++预测代码在PaddleX\deploy\openvino 目录,该目录不依赖任何PaddleX下其他目录。

Step2 软件依赖

提供了依赖软件预编译库:

gflas
opencv

下载完opencv后需要配置环境变量,如下流程所示- 我的电脑->属性->高级系统设置->环境变量 - 在系统变量中找到Path(如没有,自行创建),并双击编辑 - 新建,将opencv路径填入并保存,如D:\projects\opencv\build\x64\vc14\bin

Step3: 使用Visual Studio 2019直接编译CMake

打开Visual Studio 2019 Community,点击继续但无需代码
点击: 文件->打开->CMake 选择C++预测代码所在路径(例如D:\projects\PaddleX\deploy\openvino),并打开CMakeList.txt
点击:项目->CMake设置
点击浏览,分别设置编译选项指定OpenVINO、Gflags、NGRAPH、OPENCV的路径

请添加图片描述

设置完成后, 点击保存并生成CMake缓存以加载变量。 5. 点击生成->全部生成

Step4: 预测

上述Visual Studio 2019编译产出的可执行文件在out\build\x64-Release目录下,打开cmd,并切换到该目录:

D:
cd D:\projects\PaddleX\deploy\openvino\out\build\x64-Release

编译成功后,图片预测demo的入口程序为detector.exe,classifier.exe,segmenter.exe,用户可根据自己的模型类型选择,其主要命令参数说明如下:
请添加图片描述

测试:
在CPU下做单张图片的分类任务预测测试图片 /path/to/test_img.jpeg
直接在终端输入下行代码看看预测是否能成功

./classifier.exe --model_dir=/path/to/openvino_model --image=/path/to/test_img.jpeg --cfg_file=/path/to/PadlleX_model.yml

如果成功的话,恭喜你你已经可以在window系统下使用两者了。

Linux安装openVINO

如果看完后还是有一些不懂的地方,可以直接看下官方的技术文档。
https://docs.openvino.ai/latest/openvino_docs_install_guides_installing_openvino_linux.html

接下来说下Linux的安装步骤,相对来说比windows会简单:
1、安装OpenVINOTM工具包的英特尔®发行版
2、安装外部软件依赖项
3、配置环境
4、配置模型优化器

第1步:安装OpenVINOTM工具包核心组件的英特尔®发行版

从适用于Linux的OpenVINOTM工具包的英特尔®分发*OpenVINOTM工具包下载包文件的英特尔®分发。从下拉菜单中选择适用于Linux软件包的OpenVINOTM工具包的英特尔®发行版。

1、打开命令提示终端窗口。使用键盘快捷键:Ctrl+Alt+T
2、将目录更改为您下载Linux*软件包文件的OpenVINO工具包的英特尔分发。
3、如果您将软件包文件下载到当前用户的Downloads目录:

cd ~/下载/

默认情况下,该文件保存为l_openvino_toolkit_p_.tgz,例如l_openvino_toolkit_p_2021.4.689.tgz。

4、解压.tgz文件:

tar -xvzf l_openvino_toolkit_p_<version>.tgz

5、转到l_openvino_toolkit_p_目录:

cd l_openvino_toolkit_p_<版本>

6、选择安装选项,并将相关脚本作为根运行,以使用图形用户界面(GUI)安装向导或命令行指令(CLI)。GUI提供截图,CLI不提供截图。下面的信息也适用于CLI,对安装很有帮助,可以看到相同的选择和任务。

选项1:GUI安装向导:

sudo ./install_GUI.sh

选项2:命令行说明:

Sudo ./install.sh

选项3:命令行静音说明:

sudo sed -i's/decline/accept/g' silent.cfg
sudo ./install.sh -s silent.cfg

7、注意以下信息,以防必须完成其他步骤,看看有没有缺环境:
在这里插入图片描述
对于根或管理员:/opt/intel/openvino_/
对于普通用户:/home//intel/openvino_/
为了简单起见,还创建了最新安装的符号链接:/opt/intel/openvino_2021/或/home//intel/openvino_2021/

8、“完成”屏幕表示核心组件已安装:
在这里插入图片描述

单击“完成”关闭安装向导后,将使用此文档打开一个新的浏览器窗口。它跳转到包含后续安装步骤的部分。

默认情况下,OpenVINOTM的英特尔®发行版安装在以下目录中:

第2步:安装外部软件依赖项

如果将OpenVINOTM的英特尔®发行版安装到非默认目录,请将/opt/intel替换为安装软件的目录。
这些依赖项是以下条件所必需的:

英特尔优化的OpenCV库构建
深度学习推理引擎
深度学习模型优化器工具

1、转到install_dependencies目录:

cd /opt/intel/openvino_2021/install_dependencies

2、运行脚本下载和安装外部软件依赖项:

sudo -E ./install_openvino_dependencies.sh

安装依赖项后,继续下一节设置环境变量。

第3步:配置环境

必须更新多个环境变量,然后才能编译和运行OpenVINOTM应用程序。使用vi(如下)或首选编辑器设置以下持久环境变量:

1、在/home/中打开.bashrc文件:

vi ~/.bashrc

2、按i键切换到插入模式。

3、将以下行添加到文件末尾:

来源/opt/intel/openvino_2021/bin/setupvars.sh

4、保存并关闭文件:按Esc键并键入:wq。

5、要验证更改,请打开一个新的终端。您将看到[setupvars.sh] OpenVINO环境已初始化。

来源/opt/intel/openvino_2021/bin/setupvars.sh

设置了环境变量。接下来,将配置模型优化器。

第4步:配置模型优化器

由于CentOS不正式支持TensorFlow框架,因此无法在该操作系统上配置和运行TensorFlow的模型优化器。
*
Model Optimizer是基于Python的命令行工具,用于从流行的深度学习框架(如Caffe、TensorFlow
、Apache MXNet
、ONNX和Kaldi)导入训练有素的模型。

模型优化器是OpenVINO工具包英特尔发行的关键组件。对模型执行推断(ONNX和nGraph模型除外)需要通过模型优化器运行模型。当通过模型优化器运行预训练模型时,输出是网络的中间表示(IR)。中间表示是一对描述整个模型的文件:

.xml:描述网络拓扑
.bin:包含权重和偏置二进制数据

1、转到模型优化器先决条件目录:

cd /opt/intel/openvino_2021/deployment_tools/model_optimizer/install_prerequisites

2、运行脚本为Caffe、TensorFlow 2.x、MXNet、Kaldi和ONNX配置模型优化器:

sudo ./install_prerequisites.sh

如果已经安装好paddle和openVINO后,并配置好相应环境,下面所有示例以工作目录 /root/projects/演示。

预测部署测试

文档提供了c++下预测部署的方法,如果需要在python下预测部署请参考python预测部署

Step1 下载PaddleX预测代码

mkdir -p /root/projects
cd /root/projects
git clone https://github.com/PaddlePaddle/PaddleX.git
cd PaddleX
git checkout release/1.3

说明:其中C++预测代码在PaddleX/deploy/openvino 目录,该目录不依赖任何PaddleX下其他目录。

Step2 软件依赖

Step3中的编译脚本会一键安装第三方依赖软件的预编译包,用户不需要单独下载或编译这些依赖软件。

Step3: 编译

编译cmake的命令在scripts/build.sh中,若在树莓派(Raspbian OS)上编译请修改ARCH参数x86为armv7,若自行编译第三方依赖软件请根据Step1中编译软件的实际情况修改主要参数,其主要内容说明如下:

#openvino预编译库的路径
OPENVINO_DIR=$INTEL_OPENVINO_DIR/inference_engine
#gflags预编译库的路径
GFLAGS_DIR=$(pwd)/deps/gflags
#ngraph lib预编译库的路径
NGRAPH_LIB=$INTEL_OPENVINO_DIR/deployment_tools/ngraph/lib
#opencv预编译库的路径
OPENCV_DIR=$(pwd)/deps/opencv/
#cpu架构(x86或armv7)
ARCH=x86

执行build脚本:

sh ./scripts/build.sh

Step4: 预测

可以跑一下下面这个例子
linux系统在CPU下做单张图片的分类任务预测测试图片 /path/to/test_img.jpeg

./build/classifier --model_dir=/path/to/openvino_model --image=/path/to/test_img.jpeg --cfg_file=/path/to/PadlleX_model.yml

编译成功后,分类任务的预测可执行程序为classifier,检测任务的预测可执行程序为detector,分割任务的预测可执行程序为segmenter,其主要命令参数说明如下:
请添加图片描述

开始训练

将代码保存到本地后运行(代码下载链接位于上面的表格中),代码会自动下载训练数据并开始训练。如保存为deeplabv3p_mobilenetv2_x0.25.py,执行如下命令即可开始训练:

python deeplabv3p_mobilenetv2_x0.25.py

OpenVINO部署常见问题

转模型过程中出现”ModuleNotFoundError: No module named ‘mo’”

原因:该问题主要是因为在安装OpenVINO之后未初始化OpenVINO环境解决方案:找到OpenVINO初始化环境脚本,运行后即可以解决此问题

Linux系统初始化OpenVINO环境

1)root用户安装,以OpenVINO 2021.1版本为例,运行如下命令即可初始化

source /opt/intel/openvino_2021/bin/setupvars.sh

2)非root用户安装,以OpenVINO 2021.1版本、用户名为paddlex为例,运行如下命令即可初始化

source /home/paddlex/intel/openvino_2021/bin/setupvar.sh

Window系统初始化OpenVINO环境

以OpenVINO 2021.1版本为例,执行如下命令即可初始化OpenVINO环境

cd C:\Program Files (x86)\Intel\openvino_2021\bin\
setupvars.bat

paddlepaddle的训练

数据准备(数据标注、转换、划分)

使用Labelme标注
官网链接:
https://paddlex.readthedocs.io/zh_CN/release-1.3/data/annotation/labelme.html

LabelMe的安装和启动

LabelMe的安装和启动

LabelMe可用于标注目标检测、实例分割、语义分割数据集,是一款开源的标注工具。

  1. 安装Anaconda

推荐使用Anaconda安装python依赖,有经验的开发者可以跳过此步骤。安装Anaconda的方式可以参考文档。

在安装Anaconda,并创建环境之后,再进行接下来的步骤

  1. 安装LabelMe

进入Python环境后,执行如下命令即可

conda activate my_paddlex
conda install pyqt
pip install labelme
  1. 启动LabelMe

进入安装了LabelMe的Python环境,执行如下命令即可启动LabelMe

conda activate my_paddlex
labelme

图像分类

图像分类标注是一项最基础,最简单的标注任务,用户只需将属于同一类的图片放在同一个文件夹下即可,例如下所示目录结构,

MyDataset/ # 图像分类数据集根目录
|--dog/ # 当前文件夹所有图片属于dog类别
|  |--d1.jpg
|  |--d2.jpg
|  |--...
|  |--...
|
|--...
|
|--snake/ # 当前文件夹所有图片属于snake类别
|  |--s1.jpg
|  |--s2.jpg
|  |--...
|  |--...

数据划分
在模型进行训练时,我们需要划分训练集,验证集和测试集,因此需要对如上数据进行划分,直接使用paddlex命令即可将数据集随机划分成70%训练集,20%验证集和10%测试集

paddlex --split_dataset --format ImageNet --dataset_dir MyDataset --val_value 0.2 --test_value 0.1

划分好的数据集会额外生成labels.txt, train_list.txt, val_list.txt, test_list.txt四个文件,之后可直接进行训练。

目标检测

目标检测数据的标注推荐使用LabelMe标注工具,如先前并无安装,那么LabelMe的安装可参考LabelMe安装和启动
官网链接:
https://paddlex.readthedocs.io/zh_CN/release-1.3/data/annotation/labelme.html

注意:LabelMe不要在如下的路径以及文件名中出现中文字符!

准备工作
1、将收集的图像存放于JPEGImages文件夹下,例如存储在D:\MyDataset\JPEGImages
2、创建与图像文件夹相对应的文件夹Annotations,用于存储标注的json文件,如D:MyDataset\Annotations
3、打开LabelMe,点击”Open Dir“按钮,选择需要标注的图像所在的文件夹打开,则”File List“对话框中会显示所有图像所对应的绝对路径,接着便可以开始遍历每张图像,进行标注工作

目标框标注
1、打开矩形框标注工具(右键菜单->Create Rectangle),具体如下图所示
在这里插入图片描述
2、使用拖拉的方式对目标物体进行标识,并在弹出的对话框中写明对应label(当label已存在时点击即可, 此处请注意label勿使用中文),具体如下图所示,当框标注错误时,可点击左侧的“Edit Polygons”再点击标注框,通过拖拉进行修改,也可再点击“Delete Polygon”进行删除。
在这里插入图片描述
3、点击右侧”Save“,将标注结果保存到中创建的文件夹Annotations目录中
格式转换

LabelMe标注后的数据还需要进行转换为PascalVOC或MSCOCO格式,才可以用于目标检测任务的训练,创建D:\dataset_voc目录,在python环境中安装paddlex后,使用如下命令即可

paddlex --data_conversion --source labelme --to PascalVOC \
        --pics D:\MyDataset\JPEGImages \
        --annotations D:\MyDataset\Annotations \
        --save_dir D:\dataset_voc

数据集划分

转换完数据后,为了进行训练,还需要将数据划分为训练集、验证集和测试集,同样在安装paddlex后,使用如下命令即可将数据划分为70%训练集,20%验证集和10%的测试集

paddlex --split_dataset --format VOC --dataset_dir D:\MyDataset --val_value 0.2 --test_value 0.1

执行上面命令行,会在D:\MyDataset下生成labels.txt, train_list.txt, val_list.txt和test_list.txt,分别存储类别信息,训练样本列表,验证样本列表,测试样本列表

实例分割

准备工作

1、将收集的图像存放于JPEGImages文件夹下,例如存储在D:\MyDataset\JPEGImages
2、创建与图像文件夹相对应的文件夹Annotations,用于存储标注的json文件,如D:MyDataset\Annotations
3、打开LabelMe,点击”Open Dir“按钮,选择需要标注的图像所在的文件夹打开,则”File List“对话框中会显示所有图像所对应的绝对路径,接着便可以开始遍历每张图像,进行标注工作

目标边缘标注

1、打开多边形标注工具(右键菜单->Create Polygon)以打点的方式圈出目标的轮廓,并在弹出的对话框中写明对应label(当label已存在时点击即可,此处请注意label勿使用中文),具体如下提所示,当框标注错误时,可点击左侧的“Edit Polygons”再点击标注框,通过拖拉进行修改,也可再点击“Delete Polygon”进行删除。 ../../_images/detection2.png

2、点击右侧”Save“,将标注结果保存到中创建的文件夹Annotations目录中

格式转换
LabelMe标注后的数据还需要进行转换为MSCOCO格式,才可以用于实例分割任务的训练,创建保存目录D:\dataset_seg,在python环境中安装paddlex后,使用如下命令即可

paddlex --data_conversion --source labelme --to MSCOCO \
        --pics D:\MyDataset\JPEGImages \
        --annotations D:\MyDataset\Annotations \
        --save_dir D:\dataset_coco

数据集划分
转换完数据后,为了进行训练,还需要将数据划分为训练集、验证集和测试集,同样在安装paddlex后,使用如下命令即可将数据划分为70%训练集,20%验证集和10%的测试集

paddlex --split_dataset --format COCO --dataset_dir D:\MyDataset --val_value 0.2 --test_value 0.1

执行上面命令行,会在D:\MyDataset下生成train.json, val.json, test.json,分别存储训练样本信息,验证样本信息,测试样本信息

语义分割

准备工作

1、将收集的图像存放于JPEGImages文件夹下,例如存储在D:\MyDataset\JPEGImages
2、创建与图像文件夹相对应的文件夹Annotations,用于存储标注的json文件,如D:MyDataset\Annotations
3、打开LabelMe,点击”Open Dir“按钮,选择需要标注的图像所在的文件夹打开,则”File List“对话框中会显示所有图像所对应的绝对路径,接着便可以开始遍历每张图像,进行标注工作

目标边缘标注
1、打开多边形标注工具(右键菜单->Create Polygon)以打点的方式圈出目标的轮廓,并在弹出的对话框中写明对应label(当label已存在时点击即可,此处请注意label勿使用中文),具体如下提所示,当框标注错误时,可点击左侧的“Edit Polygons”再点击标注框,通过拖拉进行修改,也可再点击“Delete Polygon”进行删除。 ../../_images/detection2.png

2、点击右侧”Save“,将标注结果保存到中创建的文件夹Annotations目录中

格式转换
LabelMe标注后的数据还需要进行转换为SEG格式,才可以用于语义分割任务的训练,创建保存目录D:\dataset_seg,在python环境中安装paddlex后,使用如下命令即可

paddlex --data_conversion --source labelme --to SEG \
        --pics D:\MyDataset\JPEGImages \
        --annotations D:\MyDataset\Annotations \
        --save_dir D:\dataset_seg

数据集划分
转换完数据后,为了进行训练,还需要将数据划分为训练集、验证集和测试集,同样在安装paddlex后,使用如下命令即可将数据划分为70%训练集,20%验证集和10%的测试集

paddlex --split_dataset --format SEG --dataset_dir D:\MyDataset --val_value 0.2 --test_value 0.1

执行上面命令行,会在D:\MyDataset下生成train_list.txt, val_list.txt, test_list.txt,分别存储训练样本信息,验证样本信息,测试样本信息

数据格式

图像分类ImageNet

数据文件夹结构

在PaddleX中,图像分类支持ImageNet数据集格式。数据集目录data_dir下包含多个文件夹,每个文件夹中的图像均属于同一个类别,文件夹的命名即为类别名(注意路径中不要包括中文,空格)。 如下为示例结构

MyDataset/ # 图像分类数据集根目录
|--dog/ # 当前文件夹所有图片属于dog类别
|  |--d1.jpg
|  |--d2.jpg
|  |--...
|  |--...
|
|--...
|
|--snake/ # 当前文件夹所有图片属于snake类别
|  |--s1.jpg
|  |--s2.jpg
|  |--...
|  |--...

划分训练集验证集
为了用于训练,我们需要在MyDataset目录下准备train_list.txt, val_list.txt和labels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。点击下载图像分类示例数据集

注:也可使用PaddleX自带工具,对数据集进行随机划分,在数据集按照上面格式组织后,使用如下命令即可快速完成数据集随机划分,其中val_value表示验证集的比例,test_value表示测试集的比例(可以为0),剩余的比例用于训练集。

paddlex --split_dataset --format ImageNet --dataset_dir MyDataset --val_value 0.2 --test_value 0.1
labels.txt

labels.txt用于列出所有类别,类别对应行号表示模型训练过程中类别的id(行号从0开始计数),例如labels.txt为以下内容

dog
cat
snake

即表示该分类数据集中共有3个类别,分别为dog,cat和snake,在模型训练中dog对应的类别id为0, cat对应1,以此类推

train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的类别id,示例如下

dog/d1.jpg 0
dog/d2.jpg 0
cat/c1.jpg 1
... ...
snake/s1.jpg 2

其中第一列为相对对MyDataset的相对路径,第二列为图片对应类别的类别id

val_list.txt

val_list列出用于验证时的图片集成,与其对应的类别id,格式与train_list.txt一致

PaddleX数据集加载

示例代码如下,

import paddlex as pdx
from paddlex.cls import transforms
train_transforms = transforms.Compose([
    transforms.RandomCrop(crop_size=224), transforms.RandomHorizontalFlip(),
    transforms.Normalize()
])
eval_transforms = transforms.Compose([
    transforms.ResizeByShort(short_size=256),
    transforms.CenterCrop(crop_size=224), transforms.Normalize()
])
train_dataset = pdx.datasets.ImageNet(
                    data_dir='./MyDataset',
                    file_list='./MyDataset/train_list.txt',
                    label_list='./MyDataset/labels.txt',
                    transforms=train_transforms)
eval_dataset = pdx.datasets.ImageNet(
                    data_dir='./MyDataset',
                    file_list='./MyDataset/eval_list.txt',
                    label_list='./MyDataset/labels.txt',
                    transforms=eval_transforms)
Next  Previous

目标检测PascalVOC

数据集文件夹结构

在PaddleX中,目标检测支持PascalVOC数据集格式。建议用户将数据集按照如下方式进行组织,原图均放在同一目录,如JPEGImages,标注的同名xml文件均放在同一目录,如Annotations,示例如下

MyDataset/ # 目标检测数据集根目录
|--JPEGImages/ # 原图文件所在目录
|  |--1.jpg
|  |--2.jpg
|  |--...
|  |--...
|
|--Annotations/ # 标注文件所在目录
|  |--1.xml
|  |--2.xml
|  |--...
|  |--...

划分训练集验证集

为了用于训练,我们需要在MyDataset目录下准备train_list.txt, val_list.txt和labels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。点击下载目标检测示例数据集

注:也可使用PaddleX自带工具,对数据集进行随机划分,在数据集按照上面格式组织后,使用如下命令即可快速完成数据集随机划分,其中val_value表示验证集的比例,test_value表示测试集的比例(可以为0),剩余的比例用于训练集。

paddlex --split_dataset --format VOC --dataset_dir MyDataset --val_value 0.2 --test_value 0.1
labels.txt

labels.txt用于列出所有类别,类别对应行号表示模型训练过程中类别的id(行号从0开始计数),例如labels.txt为以下内容

dog
cat
snake

表示该检测数据集中共有3个目标类别,分别为dog,cat和snake,在模型训练中dog对应的类别id为0, cat对应1,以此类推

train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的标注文件,示例如下

JPEGImages/1.jpg Annotations/1.xml
JPEGImages/2.jpg Annotations/2.xml
... ...

其中第一列为原图相对MyDataset的相对路径,第二列为标注文件相对MyDataset的相对路径

val_list.txt

val_list列出用于验证时的图片集成,与其对应的标注文件,格式与val_list.txt一致

PaddleX数据集加载

示例代码如下,

import paddlex as pdx
from paddlex.det import transforms

train_transforms = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.Normalize(),
    transforms.ResizeByShort(short_size=800, max_size=1333),
    transforms.Padding(coarsest_stride=32)
])

eval_transforms = transforms.Compose([
    transforms.Normalize(),
    transforms.ResizeByShort(short_size=800, max_size=1333),
    transforms.Padding(coarsest_stride=32),
])

train_dataset = pdx.datasets.VOCDetection(
                        data_dir='./MyDataset',
                        file_list='./MyDataset/train_list.txt',
                        label_list='./MyDataset/labels.txt',
                        transforms=train_transforms)
eval_dataset = pdx.datasets.VOCDetection(
                        data_dir='./MyDataset',
                        file_list='./MyDataset/val_list.txt',
                        label_list='MyDataset/labels.txt',
                        transforms=eval_transforms)
Next  Previous

实例分割MSCOCO

数据集文件夹结构

在PaddleX中,实例分割支持MSCOCO数据集格式(MSCOCO格式同样也可以用于目标检测)。建议用户将数据集按照如下方式进行组织,原图均放在同一目录,如JPEGImages,标注文件(如annotations.json)放在与JPEGImages所在目录同级目录下,示例结构如下

MyDataset/ # 实例分割数据集根目录
|--JPEGImages/ # 原图文件所在目录
|  |--1.jpg
|  |--2.jpg
|  |--...
|  |--...
|
|--annotations.json # 标注文件所在目录

划分训练集验证集

在PaddleX中,为了区分训练集和验证集,在MyDataset同级目录,使用不同的json表示数据的划分,例如train.json和val.json。点击下载实例分割示例数据集。

注:也可使用PaddleX自带工具,对数据集进行随机划分,在数据集按照上面格式组织后,使用如下命令即可快速完成数据集随机划分,其中val_value表示验证集的比例,test_value表示测试集的比例(可以为0),剩余的比例用于训练集。

paddlex --split_dataset --format COCO --dataset_dir MyDataset --val_value 0.2 --test_value 0.1

MSCOCO数据的标注文件采用json格式,用户可使用Labelme, 精灵标注助手或EasyData等标注工具进行标注,参见数据标注工具

PaddleX加载数据集

示例代码如下,

import paddlex as pdx
from paddlex.det import transforms

train_transforms = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.Normalize(),
    transforms.ResizeByShort(short_size=800, max_size=1333),
    transforms.Padding(coarsest_stride=32)
])

eval_transforms = transforms.Compose([
    transforms.Normalize(),
    transforms.ResizeByShort(short_size=800, max_size=1333),
    transforms.Padding(coarsest_stride=32),
])

train_dataset = pdx.dataset.CocoDetection(
                    data_dir='./MyDataset/JPEGImages',
                    ann_file='./MyDataset/train.json',
                    transforms=train_transforms)
eval_dataset = pdx.dataset.CocoDetection(
                    data_dir='./MyDataset/JPEGImages',
                    ann_file='./MyDataset/val.json',
                    transforms=eval_transforms)
Next  Previous

语义分割Seg

数据集文件夹结构

在PaddleX中,标注文件为png文件。建议用户将数据集按照如下方式进行组织,原图均放在同一目录,如JPEGImages,标注的同名png文件均放在同一目录,如Annotations,示例如下

MyDataset/ # 语义分割数据集根目录
|--JPEGImages/ # 原图文件所在目录
|  |--1.jpg
|  |--2.jpg
|  |--...
|  |--...
|
|--Annotations/ # 标注文件所在目录
|  |--1.png
|  |--2.png
|  |--...
|  |--...

语义分割的标注图像,如1.png,为单通道图像,像素标注类别需要从0开始递增(一般0表示background背景), 例如0, 1, 2, 3表示4种类别,标注类别最多255个类别(其中像素值255不参与训练和评估)。

划分训练集验证集

为了用于训练,我们需要在MyDataset目录下准备train_list.txt, val_list.txt和labels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。点击下载语义分割示例数据集

注:也可使用PaddleX自带工具,对数据集进行随机划分,在数据集按照上面格式组织后,使用如下命令即可快速完成数据集随机划分,其中val_value表示验证集的比例,test_value表示测试集的比例(可以为0),剩余的比例用于训练集。

paddlex --split_dataset --format Seg --dataset_dir MyDataset --val_value 0.2 --test_value 0.1
labels.txt

labels.txt用于列出所有类别,类别对应行号表示模型训练过程中类别的id(行号从0开始计数),例如labels.txt为以下内容

background
human
car

表示该检测数据集中共有3个分割类别,分别为background,human和car,在模型训练中background对应的类别id为0, human对应1,以此类推,如不知具体类别标签,可直接在labels.txt逐行写0,1,2…序列即可。

train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的标注文件,示例如下

JPEGImages/1.jpg Annotations/1.png
JPEGImages/2.jpg Annotations/2.png
... ...

其中第一列为原图相对MyDataset的相对路径,第二列为标注文件相对MyDataset的相对路径

val_list.txt

val_list列出用于验证时的图片集成,与其对应的标注文件,格式与val_list.txt一致

PaddleX数据集加载

示例代码如下,

import paddlex as pdx
from paddlex.seg import transforms

train_transforms = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.ResizeRangeScaling(),
    transforms.RandomPaddingCrop(crop_size=512),
    transforms.Normalize()
])

eval_transforms = transforms.Compose([
    transforms.ResizeByLong(long_size=512),
    transforms.Padding(target_size=512),
    transforms.Normalize()
])

train_dataset = pdx.datasets.SegDataset(
                        data_dir='./MyDataset',
                        file_list='./MyDataset/train_list.txt',
                        label_list='./MyDataset/labels.txt',
                        transforms=train_transforms)
eval_dataset = pdx.datasets.SegDataset(
                        data_dir='./MyDataset',
                        file_list='./MyDataset/val_list.txt',
                        label_list='MyDataset/labels.txt',
                        transforms=eval_transforms)

地块检测ChangeDet

数据集文件夹结构

在PaddleX中,标注文件为png文件。建议用户将数据集按照如下方式进行组织,同一地块不同时期的地貌原图均放在同一目录,如JPEGImages,标注的同名png文件均放在同一目录,如Annotations,示例如下

MyDataset/ # 语义分割数据集根目录
|--JPEGImages/ # 原图文件所在目录,包含同一物体前期和后期的图片
|  |--1_1.jpg
|  |--1_2.jpg
|  |--2_1.jpg
|  |--2_2.jpg
|  |--...
|  |--...
|
|--Annotations/ # 标注文件所在目录
|  |--1.png
|  |--2.png
|  |--...
|  |--...

同一地块不同时期的地貌原图,如1_1.jpg和1_2.jpg,可以是RGB彩色图像、灰度图、或tiff格式的多通道图像。语义分割的标注图像,如1.png,为单通道图像,像素标注类别需要从0开始递增(一般0表示background背景), 例如0, 1, 2, 3表示4种类别,标注类别最多255个类别(其中像素值255不参与训练和评估)。

划分训练集验证集

为了用于训练,我们需要在MyDataset目录下准备train_list.txt, val_list.txt和labels.txt三个文件,分别用于表示训练集列表,验证集列表和类别标签列表。

labels.txt

labels.txt用于列出所有类别,类别对应行号表示模型训练过程中类别的id(行号从0开始计数),例如labels.txt为以下内容

unchanged
changed

表示该检测数据集中共有2个分割类别,分别为unchanged和changed,在模型训练中unchanged对应的类别id为0, changed对应1,以此类推,如不知具体类别标签,可直接在labels.txt逐行写0,1,2…序列即可。

train_list.txt

train_list.txt列出用于训练时的图片集合,与其对应的标注文件,示例如下

JPEGImages/1_1.jpg JPEGImages/1_2.jpg Annotations/1.png
JPEGImages/2_1.jpg JPEGImages/2_2.jpg Annotations/2.png
... ...

其中第一列和第二列为原图相对MyDataset的相对路径,对应同一地块不同时期的地貌图像,第三列为标注文件相对MyDataset的相对路径

val_list.txt

val_list列出用于验证时的图片集成,与其对应的标注文件,格式与val_list.txt一致

paddle模型训练与参数调整

模型训练

图像分类

PaddleX共提供了20+的图像分类模型,可满足开发者不同场景的需求下的使用。

-Top1精度: 模型在ImageNet数据集上的测试精度
-预测速度:单张图片的预测用时(不包括预处理和后处理)
-“-”表示指标暂未更新
请添加图片描述

开始训练

将代码保存到本地后运行(代码下载链接位于上面的表格),代码会自动下载训练数据并开始训练。如保存为mobilenetv3_small_ssld.py,执行如下命令即可开始训练:

python mobilenetv3_small_ssld.py

目标检测

PaddleX目前提供了FasterRCNN和YOLOv3两种检测结构,多种backbone模型,可满足开发者不同场景和性能的需求。

-Box MMAP: 模型在COCO数据集上的测试精度
-预测速度:单张图片的预测用时(不包括预处理和后处理)
-“-”表示指标暂未更新

请添加图片描述

开始训练

将代码保存到本地后运行(代码下载链接位于上面的表格),代码会自动下载训练数据并开始训练。如保存为yolov3_mobilenetv1.py,执行如下命令即可开始训练:

python yolov3_mobilenetv1.py

实例分割

PaddleX目前提供了MaskRCNN实例分割模型结构,多种backbone模型,可满足开发者不同场景和性能的需求。

-Box MMAP/Seg MMAP: 模型在COCO数据集上的测试精度
-预测速度:单张图片的预测用时(不包括预处理和后处理)
-“-”表示指标暂未更新
请添加图片描述

开始训练

将代码保存到本地后运行(代码下载链接位于上面表格中),代码会自动下载训练数据并开始训练。如保存为mask_rcnn_r50_fpn.py,执行如下命令即可开始训练:

python mask_rcnn_r50_fpn.py

语义分割

PaddleX目前提供了DeepLabv3p、UNet、HRNet和FastSCNN四种语义分割结构,多种backbone模型,可满足开发者不同场景和性能的需求。

-mIoU: 模型在CityScape数据集上的测试精度
-预测速度:单张图片的预测用时(不包括预处理和后处理)
-“-”表示指标暂未更新

请添加图片描述
开始训练

将代码保存到本地后运行(代码下载链接位于上面的表格中),代码会自动下载训练数据并开始训练。如保存为deeplabv3p_mobilenetv2_x0.25.py,执行如下命令即可开始训练:

python deeplabv3p_mobilenetv2_x0.25.py

加载模型预测

图像分类

加载模型预测

PaddleX可以使用paddlex.load_model接口加载模型(包括训练过程中保存的模型,导出的部署模型,量化模型以及裁剪的模型)进行预测,同时PaddleX中也内置了一系列的可视化工具函数,帮助用户方便地检查模型的效果。

注意:使用paddlex.load_model接口加载仅用于模型预测,如需要在此模型基础上继续训练,可以将该模型作为预训练模型进行训练,具体做法是在训练代码中,将train函数中的pretrain_weights参数指定为预训练模型路径。

图像分类

点击下载如下示例代码中的模型

import paddlex as pdx
test_jpg = 'mobilenetv3_small_ssld_imagenet/test.jpg'
model = pdx.load_model('mobilenetv3_small_ssld_imagenet')
result = model.predict(test_jpg)
print("Predict Result: ", result)

结果输出如下:

Predict Result: [{'category_id': 549, 'category': 'envelope', 'score': 0.29062933}]

测试图片如下:
在这里插入图片描述

目标检测

点击下载如下示例代码中模型

import paddlex as pdx
test_jpg = 'yolov3_mobilenetv1_coco/test.jpg'
model = pdx.load_model('yolov3_mobilenetv1_coco')

#predict接口并未过滤低置信度识别结果,用户根据需求按score值进行过滤
result = model.predict(test_jpg)

#可视化结果存储在./visualized_test.jpg, 见下图
pdx.det.visualize(test_jpg, result, threshold=0.3, save_dir='./')

在这里插入图片描述

实例分割

实例分割

点击下载如下示例代码中模型

import paddlex as pdx
test_jpg = 'mask_r50_fpn_coco/test.jpg'
model = pdx.load_model('mask_r50_fpn_coco')

# predict接口并未过滤低置信度识别结果,用户根据需求按score值进行过滤
result = model.predict(test_jpg)

# 可视化结果存储在./visualized_test.jpg, 见下图
pdx.det.visualize(test_jpg, result, threshold=0.5, save_dir='./')

在这里插入图片描述

语义分割

语义分割

点击下载如下示例代码中模型

import paddlex as pdx
test_jpg = './deeplabv3p_mobilenetv2_voc/test.jpg'
model = pdx.load_model('./deeplabv3p_mobilenetv2_voc')
result = model.predict(test_jpg)
# 可视化结果存储在./visualized_test.jpg,见下图右(左图为原图)
pdx.seg.visualize(test_jpg, result, weight=0.0, save_dir='./')

在上述示例代码中,通过调用paddlex.seg.visualize可以对语义分割的预测结果进行可视化,可视化的结果保存在save_dir下,见下图。其中weight参数用于调整预测结果和原图结果融合展现时的权重,0.0时只展示预测结果mask的可视化,1.0时只展示原图可视化。

训练参数调整

PaddleX所有训练接口中,内置的参数均为根据单GPU卡相应batch_size下的较优参数,用户在自己的数据上训练模型,涉及到参数调整时,如无太多参数调优经验,则可参考如下方式

1.num_epochs的调整

num_epochs是模型训练迭代的总轮数(模型对训练集全部样本过一遍即为一个epoch),用户可以设置较大的数值,根据模型迭代过程在验证集上的指标表现,来判断模型是否收敛,进而提前终止训练。此外也可以使用train接口中的early_stop策略,模型在训练过程会自动判断模型是否收敛自动中止。

2.batch_size和learning_rate

Batch Size指模型在训练过程中,前向计算一次(即为一个step)所用到的样本数量
如若使用多卡训练, batch_size会均分到各张卡上(因此需要让batch size整除卡数)
Batch Size跟机器的显存/内存高度相关,batch_size越高,所消耗的显存/内存就越高
PaddleX在各个train接口中均配置了默认的batch size(默认针对单GPU卡),如若训练时提示GPU显存不足,则相应调低BatchSize,如若GPU显存高或使用多张GPU卡时,可相应调高BatchSize。
如若用户调整batch size,则也注意需要对应调整其它参数,特别是train接口中默认的learning_rate值。如在YOLOv3模型中,默认train_batch_size为8,learning_rate为0.000125,当用户将模型在2卡机器上训练时,可以将train_batch_size调整为16, 那么同时learning_rate也可以对应调整为0.000125 * 2 = 0.00025
3.warmup_steps和warmup_start_lr

在训练模型时,一般都会使用预训练模型,例如检测模型在训练时使用backbone在ImageNet数据集上的预训练权重。但由于在自行训练时,自己的数据与ImageNet数据集存在较大的差异,可能会一开始由于梯度过大使得训练出现问题,这种情况下可以在刚开始训练时,让学习率以一个较小的值,慢慢增长到设定的学习率。warmup_steps和warmup_start_lr就是起到这个作用,模型开始训练时,学习率会从warmup_start_lr开始,在warmup_steps个batch数据迭代后线性增长到设定的学习率。

例如YOLOv3的train接口,默认train_batch_size为8,learning_rate为0.000125, warmup_steps为1000, warmup_start_lr为0.0;在此参数配置下表示,模型在启动训练后,在前1000个step(每个step使用一个batch的数据,即8个样本)内,学习率会从0.0开始线性增长到设定的0.000125。
4.lr_decay_epochs和lr_decay_gamma

lr_decay_epochs用于让学习率在模型训练后期逐步衰减,它一般是一个list,如[6, 8, 10],表示学习率在第6个epoch时衰减一次,第8个epoch时再衰减一次,第10个epoch时再衰减一次。每次学习率衰减为之前的学习率*lr_decay_gamma。

例如YOLOv3的train接口,默认num_epochs为270,learning_rate为0.000125, lr_decay_epochs为[213, 240],lr_decay_gamma为0.1;在此参数配置下表示,模型在启动训练后,在前213个epoch中,训练时使用的学习率为0.000125,在第213至240个epoch之间,训练使用的学习率为0.000125x0.1=0.0000125,在240个epoch之后,使用的学习率为0.000125x0.1x0.1=0.00000125
5.参数设定时的约束

根据上述几个参数,可以了解到学习率的变化分为WarmUp热身阶段和Decay衰减阶段,

Wamup热身阶段:随着训练迭代,学习率从较低的值逐渐线性增长至设定的值,以step为单位
Decay衰减阶段:随着训练迭代,学习率逐步衰减,如每次衰减为之前的0.1, 以epoch为单位
step与epoch的关系:1个epoch由多个step组成,例如训练样本有800张图像,train_batch_size为8, 那么每个epoch都要完整用这800张图片训一次模型,而每个epoch总共包含800//8即100个step
在PaddleX中,约束warmup必须在Decay之前结束,因此各参数设置需要满足下面条件

warmup_steps <= lr_decay_epochs[0] * num_steps_each_epoch

其中num_steps_each_epoch计算方式如下,

num_steps_each_eposh = num_samples_in_train_dataset // train_batch_size

因此,如若你在启动训练时,被提示warmup_steps should be less than…时,即表示需要根据上述公式调整你的参数啦,可以调整lr_decay_epochs或者是warmup_steps。

6.如何使用多GPU卡进行训练

在import paddlex前配置环境变量,代码如下

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0' # 使用0号GPU卡进行训练
# 注意paddle或paddlex都需要在设置环境变量后再import
import paddlex as pdx
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '' # 不使用GPU,使用CPU进行训练
import paddlex as pdx
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1,3' # 同时使用第0、1、3号GPU卡进行训练
import paddlex as pdx


模型保存

训练过程保存
PaddleX在模型训练过程中,根据train函数接口中的save_interval_epoch参数设置,每间隔相应轮数保存一次模型,模型目录中包含了model.pdparams, model.yml等文件。
在训练过程中保存的模型,可用于作为pretrain_weights继续训练模型,也可使用paddlex.load_model接口加载测试模型的预测和评估等。

部署模型导出
在前面提到的训练中保存的模型,如若要用于部署(部署可参阅PaddleX文档中的模型多端部署章节),需导出为部署的模型格式,部署的模型目录中包含__model__,params__和model.yml三个文件。
模型部署在Python层面,可以使用基于高性能预测库的python接口paddlex.deploy.Predictor,也可使用paddlex.load_model接口。
【总结】如若模型目录中包含model.pdparams,那说明模型是训练过程中保存的,部署时需要进行导出;部署的模型目录中需包含__model
,__params__和model.yml三个文件。

模型部署文件说明
model:保存了模型的网络结构信息
params: 保存了模型网络中的参数权重
model.yml:在PaddleX中,将模型的预处理,后处理,以及类别相关信息均存储在此文件中

模型导出为ONNX模型
PaddleX作为开放开源的套件,其中的大部分模型均支持导出为ONNX协议,满足开发者多样性的需求。
需要注意的是ONNX存在多个OpSet版本,下表为PaddleX各模型支持导出的ONNX协议版本。
请添加图片描述

模型压缩优化

模型裁剪

模型裁剪可以更好地满足在端侧、移动端上部署场景下的性能需求,可以有效得降低模型的体积,以及计算量,加速预测性能。PaddleX集成了PaddleSlim的基于敏感度的通道裁剪算法,用户可以在PaddleX的训练代码里轻松使用起来。

在本文档中展示了分类模型的裁剪过程,文档中代码以及更多其它模型的的裁剪代码可在Github中的tutorials/slim/prune目录获取。

使用方法

模型裁剪相对比我们普通训练一个模型,步骤会多出两步

1.采用正常的方式训练一个模型
2.对模型的参数进行敏感度分析
3.根据第2步得到的敏感度信息,对模型进行裁剪,并以第1步训练好的模型作为预训练权重,继续进行训练
具体我们以图像分类模型MobileNetV2为例,本示例中所有代码均可在Github的[tutorials/slim/prune/image_classification]中获得。

第一步 正常训练模型

此步骤中采用正常的代码进行模型训练,在获取本示例代码后,直接执行如下命令即可

python mobilenetv2_train.py

在训练完成后,我们以output/mobilenetv2/best_model保存的模型,继续接下来的步骤

第二步 参数敏感度分析

此步骤中,我们需要加载第一步训练保存的模型,并通过不断地遍历参数,分析各参数裁剪后在验证数据集上的精度损失,以此判断各参数的敏感度。敏感度分析的代码很简单, 用户可直接查看params_analysis.py。在命令行终端执行如下命令开始参数分析。

python params_analysis.py

在此步骤中,我们会得到保存的mobilenetv2.sensi.data文件,这个文件保存了模型中每个参数的敏感度,在后续的裁剪训练中,会根据此文件中保存的信息,对各个参数进行裁剪。同时,我们也可以对这个文件进行可视化分析,判断eval_metric_loss的大小设置与模型被裁剪比例的关系。(eval_metric_loss的说明见第三步)

模型裁剪比例可视化分析代码见slim_visualize.py,执行如下命令即可

python slim_visualize.py

可视化结果如下,该图表明,当我们将eval_metric_loss设为0.05时,模型将被裁剪掉65%;将eval_metric_loss设为0.10,模型将被裁剪掉68.0%。因此在实际使用时,我们可以根据自己的需求,去设置eval_metric_loss控制裁剪比例。

第三步 模型裁剪训练

在前两步,我们得到了正常训练保存的模型output/mobilenetv2/best_model和基于该保存模型得到的参数敏感度信息文件mobilenetv2.sensi.data,接下来则是进行模型裁剪训练。模型裁剪训练的代码第第一步基本一致,唯一区别在最后的train函数中,我们修改了pretrain_weights,save_dir,sensitivities_file和eval_metric_loss四个参数,如下所示

model.train(
	num_epoch=10,
	train_dataset=train_dataset,
	train_batch_size=32,
	eval_dataset=eval_dataset,
	lr_decay_epochs=[4,6,8],
	learning_rate=0.025,
	pretrain_weights='output/mobilenetv2/best_model',
	save_dir='output/mobilenetv2_prune',
	sensitivities_file='./mobilenetv2.sensi.data',
	eval_metric_loss=0.05,
	use_vdl=True)

具体代码见tutorials/slim/prune/image_classification/mobilenetv2_prune_train.py,执行如下命令即可

python mobilenetv2_prune_train.py
其中修改的4个参数函数如下

1、pretrain_weights: 预训练权重,在裁剪训练中,将其指定为第一步正常训练得到的模型路径
2、save_dir: 裁剪训练过程中,模型保存的新路径
3、sensitivities_file: 第二步中分析得到的各参数敏感度信息文件
4、请添加图片描述
eval_metric_loss: 可用于控制模型最终被裁剪的比例,见第二步中的可视化说明
裁剪效果

在本示例的数据集上,经过裁剪训练后,模型的效果对比如下,其中预测速度不包括图像的预处理和结果的后处理。从表中可以看到,对于本示例中的简单数据集,模型裁剪掉68%后,模型准确度没有降低,在CPU的单张图片预测用时减少了37%

模型量化

模型量化将模型的计算从浮点型转为整型,从而加速模型的预测计算速度,在移动端/边缘端设备上降低模型的体积。

注:量化后的模型,通过PaddleLite转换为PaddleLite部署的模型格式后,模型体积将会大幅压缩。如若量化后的模型仍是以服务端本地部署格式(文件包括__model__和__params__),那么模型的文件大小是无法呈现参数变化情况的。

使用方法

PaddleX中已经将量化功能作为模型导出的一个API,代码使用方式如下,本示例代码和模型数据均可通过GitHub项目上代码tutorials/slim/quant/image_classification获取得到

import paddlex as pdx
model = pdx.load_model('mobilenetv2_vegetables')
# 加载数据集用于量化
dataset = pdx.datasets.ImageNet(
                data_dir='vegetables_cls',
                file_list='vegetables_cls/train_list.txt',
                label_list='vegetables_cls/labels.txt',
                transforms=model.test_transforms)

# 开始量化
pdx.slim.export_quant_model(model, dataset,
			  batch_size=4,
			  batch_num=5,
	                  save_dir='./quant_mobilenet',
	                  cache_dir='./tmp')
	                  

在获取本示例代码后,执行如下命令即可完成量化和PaddleLite的模型导出

# 将mobilenetv2模型量化保存
python mobilenetv2_quant.py
# 将量化后的模型导出为PaddleLite部署格式
python paddlelite_export.py

量化效果

在本示例中,我们可以看到模型量化后的服务端部署模型格式server_mobilenet和quant_mobilenet两个目录中,模型参数大小并无变化。 但在使用PaddleLite导出后,mobilenetv2.nb和mobilenetv2_quant.nb大小分别为8.8M, 2.7M,压缩至原来的31%。

部署模型导出

在服务端部署模型时需要将训练过程中保存的模型导出为inference格式模型,导出的inference格式模型包括__model__、__params__和model.yml三个文件,分别表示模型的网络结构、模型权重和模型的配置文件(包括数据预处理参数等)。

检查你的模型文件夹,如果里面是model.pdparams, model.pdmodel和model.yml3个文件时,那么就需要按照下面流程进行模型导出
在安装完PaddleX后,在命令行终端使用如下命令将模型导出。可直接下载小度熊分拣模型来测试本文档的流程xiaoduxiong_epoch_12.tar.gz

paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./inference_model

请添加图片描述

使用TensorRT预测时,需固定模型的输入大小,通过–fixed_input_shape来制定输入大小[w,h]。

注意:

1、分类模型的固定输入大小请保持与训练时的输入大小一致;
2、检测模型模型中YOLO系列请保存w与h一致,且为32的倍数大小;3、RCNN类无此限制,按需设定即可指定[w,h]时,w和h中间逗号隔开,不允许存在空格等其他字符。
4、需要注意的,w,h设得越大,模型在预测过程中所需要的耗时和内存/显存占用越高;设得太小,会影响模型精度

paddlex --export_inference --model_dir=./xiaoduxiong_epoch_12 --save_dir=./inference_model --fixed_input_shape=[640,960]

飞桨实例演示

人像分割模型

本教程基于PaddleX核心分割模型实现人像分割,开放预训练模型和测试数据、支持视频流人像分割、提供模型Fine-tune到Paddle Lite移动端及Nvidia Jeston嵌入式设备部署的全流程应用指南。

预训练模型和测试数据

预训练模型

本案例开放了两个在大规模人像数据集上训练好的模型,以满足服务器端场景和移动端场景的需求。使用这些模型可以快速体验视频流人像分割,也可以部署到移动端或嵌入式设备进行实时人像分割,也可以用于完成模型Fine-tuning。

请添加图片描述
1、Checkpoint Parameter为模型权重,用于Fine-tuning场景,包含__params__模型参数和model.yaml基础的模型配置信息。
2、Inference Model和Quant Inference Model为预测部署模型,包含__model__计算图结构、__params__模型参数和model.yaml基础的模型配置信息。
其中Inference Model适用于服务端的CPU和GPU预测部署,Qunat 3、3、Inference Model为量化版本,适用于通过Paddle Lite进行移动端等端侧设备部署。

关于预测锯齿问题

在训练完模型后,可能会遇到预测出来结果存在『锯齿』的问题,这个可能存在的原因是由于模型在预测过程中,经历了原图缩放再放大的过程,如下流程所示,

原图输入 -> 预处理transforms将图像缩放至目标大小 -> Paddle模型预测 -> 预测结果放大至原图大小

对于这种原因导致的问题,可以手动修改模型中的model.yml文件,将预处理中的目标大小调整到更高优化此问题,如在本文档中提供的人像分割server端模型中model.yml文件内容,修改target_size至1024*1024(这样也会带来模型预测所需的资源更多,预测速度更慢)

Model: DeepLabv3p
Transforms:
- Resize:
    interp: LINEAR
    target_size:
    - 512
    - 512

修改为

Model: DeepLabv3p
Transforms:
- Resize:
    interp: LINEAR
    target_size:
    - 1024
    - 1024

预训练模型的存储大小和推理时长如下所示,其中移动端模型的运行环境为cpu:骁龙855,内存:6GB,图片大小:192*192
请添加图片描述

执行以下脚本下载全部的预训练模型:

~下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

~下载预训练模型的代码位于PaddleX/examples/human_segmentation,进入该目录:

cd PaddleX/examples/human_segmentation

~执行下载

python pretrain_weights/download_pretrain_weights.py

测试数据

supervise.ly发布了人像分割数据集Supervisely Persons, 本案例从中随机抽取一小部分数据并转化成PaddleX可直接加载的数据格式,运行以下代码可下载该数据、以及手机前置摄像头拍摄的人像测试视频video_test.mp4.

下载测试数据的代码位于PaddleX/xamples/human_segmentation,进入该目录并执行下载:

python data/download_data.py

快速体验视频流人像分割

前置依赖

PaddlePaddle >= 1.8.0
Python >= 3.5
PaddleX >= 1.0.0
安装的相关问题参考PaddleX安装

下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

视频流人像分割和背景替换的执行文件均位于PaddleX/examples/human_segmentation,进入该目录:

cd PaddleX/examples/human_segmentation

光流跟踪辅助的视频流人像分割

本案例将DIS(Dense Inverse Search-basedmethod)光流跟踪算法的预测结果与PaddleX的分割结果进行融合,以此改善视频流人像分割的效果。运行以下代码进行体验,以下代码位于PaddleX/xamples/human_segmentation:

通过电脑摄像头进行实时分割处理

python video_infer.py --model_dir pretrain_weights/humanseg_mobile_inference

对离线人像视频进行分割处理

python video_infer.py --model_dir pretrain_weights/humanseg_mobile_inference --video_path data/video_test.mp4

视频分割结果如下所示:
请添加图片描述

人像背景替换

本案例还实现了人像背景替换功能,根据所选背景对人像的背景画面进行替换,背景可以是一张图片,也可以是一段视频。人像背景替换的代码位于PaddleX/xamples/human_segmentation,进入该目录并执行:

通过电脑摄像头进行实时背景替换处理, 通过’–background_video_path’传入背景视频

python bg_replace.py --model_dir pretrain_weights/humanseg_mobile_inference --background_image_path data/background.jpg

对人像视频进行背景替换处理, 通过’–background_video_path’传入背景视频

python bg_replace.py --model_dir pretrain_weights/humanseg_mobile_inference --video_path data/video_test.mp4 --background_image_path data/background.jpg

对单张图像进行背景替换

python bg_replace.py --model_dir pretrain_weights/humanseg_mobile_inference --image_path data/human_image.jpg --background_image_path data/background.jpg

背景替换结果如下:

请添加图片描述
注意:

视频分割处理时间需要几分钟,请耐心等待。
提供的模型适用于手机摄像头竖屏拍摄场景,宽屏效果会略差一些。

模型Fine-tune

前置依赖

PaddlePaddle >= 1.8.0
Python >= 3.5
PaddleX >= 1.0.0
安装的相关问题参考PaddleX安装

下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

人像分割训练、评估、预测、模型导出、离线量化的执行文件均位于PaddleX/examples/human_segmentation,进入该目录:

cd PaddleX/examples/human_segmentation

模型训练

使用下述命令进行基于预训练模型的模型训练,请确保选用的模型结构model_type与模型参数pretrain_weights匹配。如果不需要本案例提供的测试数据,可更换数据、选择合适的模型并调整训练参数。

# 指定GPU卡号(以0号卡为例)
export CUDA_VISIBLE_DEVICES=0
# 若不使用GPU,则将CUDA_VISIBLE_DEVICES指定为空
# export CUDA_VISIBLE_DEVICES=
python train.py --model_type HumanSegMobile \
--save_dir output/ \
--data_dir data/mini_supervisely \
--train_list data/mini_supervisely/train.txt \
--val_list data/mini_supervisely/val.txt \
--pretrain_weights pretrain_weights/humanseg_mobile_params \
--batch_size 8 \
--learning_rate 0.001 \
--num_epochs 10 \
--image_shape 192 192

其中参数含义如下:

–model_type: 模型类型,可选项为:HumanSegServer和HumanSegMobile
–save_dir: 模型保存路径
–data_dir: 数据集路径
–train_list: 训练集列表路径
–val_list: 验证集列表路径
–pretrain_weights: 预训练模型路径
–batch_size: 批大小
–learning_rate: 初始学习率
–num_epochs: 训练轮数
–image_shape: 网络输入图像大小(w, h)
更多命令行帮助可运行下述命令进行查看:

python train.py --help

注意:可以通过更换–model_type变量与对应的–pretrain_weights使用不同的模型快速尝试。

评估

使用下述命令对模型在验证集上的精度进行评估:

python eval.py --model_dir output/best_model \
--data_dir data/mini_supervisely \
--val_list data/mini_supervisely/val.txt \
--image_shape 192 192

其中参数含义如下:

–model_dir: 模型路径
–data_dir: 数据集路径
–val_list: 验证集列表路径
–image_shape: 网络输入图像大小(w, h)

预测

使用下述命令对测试集进行预测,预测可视化结果默认保存在./output/result/文件夹中。

python infer.py --model_dir output/best_model \
--data_dir data/mini_supervisely \
--test_list data/mini_supervisely/test.txt \
--save_dir output/result \
--image_shape 192 192

其中参数含义如下:

–model_dir: 模型路径
–data_dir: 数据集路径
–test_list: 测试集列表路径
–image_shape: 网络输入图像大小(w, h)

模型导出

在服务端部署的模型需要首先将模型导出为inference格式模型,导出的模型将包括__model__、__params__和model.yml三个文名,分别为模型的网络结构,模型权重和模型的配置文件(包括数据预处理参数等等)。在安装完PaddleX后,在命令行终端使用如下命令完成模型导出:

paddlex --export_inference --model_dir output/best_model \
--save_dir output/export

其中参数含义如下:

–model_dir: 模型路径
–save_dir: 导出模型保存路径

RGB遥感影像分割

本案例基于PaddleX实现遥感影像分割,提供滑动窗口预测方式,以避免在直接对大尺寸图片进行预测时显存不足的发生。此外,滑动窗口之间的重叠程度可配置,以此消除最终预测结果中各窗口拼接处的裂痕感。

前置依赖

Paddle paddle >= 1.8.4
Python >= 3.5
PaddleX >= 1.1.4
安装的相关问题参考PaddleX安装

下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

该案例所有脚本均位于PaddleX/examples/remote_sensing/,进入该目录:

cd PaddleX/examples/remote_sensing/

数据准备

本案例使用2015 CCF大数据比赛提供的高清遥感影像,包含5张带标注的RGB图像,图像尺寸最大有7969 × 7939、最小有4011 × 2470。该数据集共标注了5类物体,分别是背景(标记为0)、植被(标记为1)、道路(标记为2)、建筑(标记为3)、水体(标记为4)。

本案例将前4张图片划分入训练集,第5张图片作为验证集。为增加训练时的批量大小,以滑动窗口为(1024,1024)、步长为(512, 512)对前4张图片进行切分,加上原本的4张大尺寸图片,训练集一共有688张图片。在训练过程中直接对大图片进行验证会导致显存不足,为避免此类问题的出现,针对验证集以滑动窗口为(769, 769)、步长为(769,769)对第5张图片进行切分,得到40张子图片。

运行以下脚本,下载原始数据集,并完成数据集的切分:

python prepare_data.py

模型训练

分割模型选择Backbone为MobileNetv3_large_ssld的Deeplabv3模型,该模型兼备高性能高精度的优点。运行以下脚本,进行模型训练:

python train.py

也可以跳过模型训练步骤,直接下载预训练模型进行后续的模型预测和评估:

wget https://bj.bcebos.com/paddlex/examples/remote_sensing/models/ccf_remote_model.tar.gz
tar -xvf ccf_remote_model.tar.gz

模型预测

直接对大尺寸图片进行预测会导致显存不足,为避免此类问题的出现,本案例提供了滑动窗口预测接口,支持有重叠和无重叠两种方式。

无重叠的滑动窗口预测
在输入图片上以固定大小的窗口滑动,分别对每个窗口下的图像进行预测,最后将各窗口的预测结果拼接成输入图片的预测结果。由于每个窗口边缘部分的预测效果会比中间部分的差,因此每个窗口拼接处可能会有明显的裂痕感。

该预测方式的API接口详见overlap_tile_predict,使用时需要把参数pad_size设置为[0, 0]。

有重叠的滑动窗口预测
在Unet论文中,作者提出一种有重叠的滑动窗口预测策略(Overlap-tile strategy)来消除拼接处的裂痕感。对各滑动窗口预测时,会向四周扩展一定的面积,对扩展后的窗口进行预测,例如下图中的蓝色部分区域,到拼接时只取各窗口中间部分的预测结果,例如下图中的黄色部分区域。位于输入图像边缘处的窗口,其扩展面积下的像素则通过将边缘部分像素镜像填补得到。

请添加图片描述

相比无重叠的滑动窗口预测,有重叠的滑动窗口预测策略将本案例的模型精度miou从80.58%提升至81.52%,并且将预测可视化结果中裂痕感显著消除,可见下图中两种预测方式的效果对比。

请添加图片描述

运行以下脚本使用有重叠的滑动窗口进行预测:

python predict.py

模型评估

在训练过程中,每隔10个迭代轮数会评估一次模型在验证集的精度。由于已事先将原始大尺寸图片切分成小块,此时相当于使用无重叠的大图切小图预测方式,最优模型精度miou为80.58%。运行以下脚本,将采用有重叠的大图切小图的预测方式,重新评估原始大尺寸图片的模型精度,此时miou为81.52%。

python eval.py

多通道遥感影像分割

遥感影像分割是图像分割领域中的重要应用场景,广泛应用于土地测绘、环境监测、城市建设等领域。遥感影像分割的目标多种多样,有诸如积雪、农作物、道路、建筑、水源等地物目标,也有例如云层的空中目标。

本案例基于PaddleX实现多通道遥感影像分割,涵盖数据分析、模型训练、模型预测等流程,旨在帮助用户利用深度学习技术解决多通道遥感影像分割问题。

前置依赖

Paddle paddle >= 1.8.4
Python >= 3.5
PaddleX >= 1.1.4
安装的相关问题参考PaddleX安装

另外还需安装gdal, 使用pip安装gdal可能出错,推荐使用conda进行安装:

conda install gdal
下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

该案例所有脚本均位于PaddleX/examples/channel_remote_sensing/,进入该目录:

cd PaddleX/examples/channel_remote_sensing/  

数据准备

遥感影像的格式多种多样,不同传感器产生的数据格式也可能不同。PaddleX现已兼容以下4种格式图片读取:

tif
png
img
npy
标注图要求必须为单通道的png格式图像,像素值即为对应的类别,像素标注类别需要从0开始递增。例如0,1,2,3表示有4种类别,255用于指定不参与训练和评估的像素,标注类别最多为256类。

本案例使用L8 SPARCS公开数据集进行云雪分割,该数据集包含80张卫星影像,涵盖10个波段。原始标注图片包含7个类别,分别是cloud, cloud shadow, shadow over water, snow/ice, water, land和flooded。由于flooded和shadow over water2个类别占比仅为1.8%和0.24%,我们将其进行合并,flooded归为land,shadow over water归为shadow,合并后标注包含5个类别。

数值、类别、颜色对应表:

请添加图片描述

请添加图片描述

执行以下命令下载并解压经过类别合并后的数据集:

mkdir dataset && cd dataset
wget https://paddleseg.bj.bcebos.com/dataset/remote_sensing_seg.zip
unzip remote_sensing_seg.zip
cd ..

其中data目录存放遥感影像,data_vis目录存放彩色合成预览图,mask目录存放标注图。

数据分析

遥感影像往往由许多波段组成,不同波段数据分布可能大相径庭,例如可见光波段和热红外波段分布十分不同。为了更深入了解数据的分布来优化模型训练效果,需要对数据进行分析。

参考文档数据分析对训练集进行统计分析,确定图像像素值的截断范围,并统计截断后的均值和方差。

模型训练

本案例选择UNet语义分割模型完成云雪分割,运行以下步骤完成模型训练,模型的最优精度miou为78.38%。

设置GPU卡号
export CUDA_VISIBLE_DEVICES=0
运行以下脚本开始训练
python train.py --data_dir dataset/remote_sensing_seg \
--train_file_list dataset/remote_sensing_seg/train.txt \
--eval_file_list dataset/remote_sensing_seg/val.txt \
--label_list dataset/remote_sensing_seg/labels.txt \
--save_dir saved_model/remote_sensing_unet \
--num_classes 5 \
--channel 10 \
--lr 0.01 \
--clip_min_value 7172 6561 5777 5103 4291 4000 4000 4232 6934 7199 \
--clip_max_value 50000 50000 50000 50000 50000 40000 30000 18000 40000 36000 \
--mean 0.15163569 0.15142828 0.15574491 0.1716084  0.2799778  0.27652043 0.28195933 0.07853807 0.56333154 0.5477584 \
--std  0.09301891 0.09818967 0.09831126 0.1057784  0.10842132 0.11062996 0.12791838 0.02637859 0.0675052  0.06168227 \
--num_epochs 500 \
--train_batch_size 3

也可以跳过模型训练步骤,下载预训练模型直接进行模型预测:

wget https://bj.bcebos.com/paddlex/examples/multi-channel_remote_sensing/models/l8sparcs_remote_model.tar.gz
tar -xvf l8sparcs_remote_model.tar.gz

模型预测

运行以下脚本,对遥感图像进行预测并可视化预测结果,相应地也将对应的标注文件进行可视化,以比较预测效果。

export CUDA_VISIBLE_DEVICES=0
python predict.py

可视化效果如下所示:
请添加图片描述

数值、类别、颜色对应表:

请添加图片描述

地块变化检测

本案例基于PaddleX实现地块变化检测,将同一地块的前期与后期两张图片进行拼接,而后输入给语义分割网络进行变化区域的预测。在训练阶段,使用随机缩放尺寸、旋转、裁剪、颜色空间扰动、水平翻转、竖直翻转多种数据增强策略。在验证和预测阶段,使用滑动窗口预测方式,以避免在直接对大尺寸图片进行预测时显存不足的发生。

前置依赖

Paddle paddle >= 1.8.4
Python >= 3.5
PaddleX >= 1.2.2
安装的相关问题参考PaddleX安装

下载PaddleX源码:

git clone https://github.com/PaddlePaddle/PaddleX
cd PaddleX
git checkout release/1.3

该案例所有脚本均位于PaddleX/examples/change_detection/,进入该目录:

cd PaddleX/examples/change_detection/

数据准备

本案例使用Daifeng Peng等人开放的Google Dataset, 该数据集涵盖了广州部分区域于2006年至2019年期间的房屋建筑物的变化情况,用于分析城市化进程。一共有20对高清图片,图片有红、绿、蓝三个波段,空间分辨率为0.55m,图片大小有1006x1168至4936x5224不等。

由于Google Dataset仅标注了房屋建筑物是否发生变化,因此本案例是二分类变化检测任务,可根据实际需求修改类别数量即可拓展为多分类变化检测。

本案例将15张图片划分入训练集,5张图片划分入验证集。由于图片尺寸过大,直接训练会发生显存不足的问题,因此以滑动窗口为(1024,1024)、步长为(512, 512)对训练图片进行切分,切分后的训练集一共有743张图片。以滑动窗口为(769, 769)、步长为(769,769)对验证图片进行切分,得到108张子图片,用于训练过程中的验证。

运行以下脚本,下载原始数据集,并完成数据集的切分:

python prepare_data.py

切分后的数据示意如下:

请添加图片描述

注意:

tiff格式的图片PaddleX统一使用gdal库读取,gdal安装可参考gdal文档。若数据是tiff格式的三通道RGB图像,如果不想安装gdal,需自行转成jpeg、bmp、png格式图片。
label文件需为单通道的png格式图片,且标注从0开始计数,标注255表示该类别不参与计算。例如本案例中,0表示unchanged类,1表示changed类。

模型训练

由于数据量较小,分割模型选择较好兼顾浅层细节信息和深层语义信息的UNet模型。运行以下脚本,进行模型训练:

python train.py

本案例使用0,1,2,3号GPU卡完成训练,可根据实际显存大小更改训练脚本中的GPU卡数量和train_batch_size的设置值,按train_batch_size的调整比例相应地调整学习率learning_rate,例如train_batch_size由16减少至8时,learning_rate则由0.1减少至0.05。此外,不同数据集上能获得最优精度所对应learning_rate可能有所不同,可以尝试调整。

也可以跳过模型训练步骤,直接下载预训练模型进行后续的模型评估和预测:

wget https://bj.bcebos.com/paddlex/examples/change_detection/models/google_change_det_model.tar.gz
tar -xvf google_change_det_model.tar.gz

模型评估

在训练过程中,每隔10个迭代轮数会评估一次模型在验证集的精度。由于已事先将原始大尺寸图片切分成小块,相当于使用无重叠的滑动窗口预测方式,最优模型精度:

请添加图片描述

category分别对应unchanged和changed两类。

运行以下脚本,将采用有重叠的滑动窗口预测方式,重新评估原始大尺寸图片的模型精度,此时模型精度为:

请添加图片描述

python eval.py

滑动窗口预测接口说明详见API说明,已有的使用场景可参考RGB遥感分割案例。可根据实际显存大小修改评估脚本中tile_size,pad_size和batch_size。

模型预测

执行以下脚本,使用有重叠的滑动预测窗口对验证集进行预测。可根据实际显存大小修改评估脚本中tile_size,pad_size和batch_size。

python predict.py

预测可视化结果如下图所示:
请添加图片描述

OpenVINO模型转换

将Paddle模型转换为OpenVINO的Inference Engine

1、环境依赖

Paddle2ONNX 0.4
ONNX 1.6.0+
PaddleX 1.3+
OpenVINO 2020.4+

说明:PaddleX安装请参考PaddleX , OpenVINO安装请参考OpenVINO,ONNX请安装1.6.0以上版本否则会出现转模型错误, Paddle2ONNX请安装0.4版本。
注意:安装OpenVINO时请务必安装官网教程初始化OpenVINO运行环境,并安装相关依赖,否则会出现”No module named mo”等问题

请确保系统已经安装好上述基本软件,下面所有示例以工作目录 /root/projects/演示。

2、导出inference模型

paddle模型转openvino之前需要先把paddle模型导出为inference格式模型,导出的模型将包括__model__、__params__和model.yml三个文件名,导出命令如下

paddlex --export_inference --model_dir=/path/to/paddle_model --save_dir=./inference_model --fixed_input_shape=[w,h]

注意:需要转OpenVINO模型时,导出inference模型请务必指定–fixed_input_shape参数来固定模型的输入大小,且模型的输入大小需要与训练时一致。 PaddleX客户端在发布模型时没有固定输入大小,因此对于可视化客户端,请找到任务所在目录,从里面的output文件夹找到best_model模型目录,将此目录使用如上命令进行固定shape导出即可。

3、导出OpenVINO模型

mkdir -p /root/projects
cd /root/projects
git clone https://github.com/PaddlePaddle/PaddleX.git
cd PaddleX
git checkout release/1.3
cd deploy/openvino/python

python converter.py --model_dir /path/to/inference_model --save_dir /path/to/openvino_model --fixed_input_shape [w,h]

转换成功后会在save_dir下出现后缀名为.xml、.bin、.mapping三个文件转换参数说明如下:

请添加图片描述

paddle- openVINO部署实例

openvino-yolo

对象检测示例代码

这个演示是如何在OpenVINO上运行PaddlePaddle YoloV3检测算法。
首先如果你想对这些有一个更深入的理解,可以看下下面三个链接。

YOLOV3Model Configuration(模型配置):
https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.1/configs/yolov3

PPYOLO Annotation Data(数据):
https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.2/docs/tutorials/config_annotation/ppyolo_r50vd_dcn_1x_coco_annotation.md

PPYOLO Model Configuration:
https://github.com/PaddlePaddle/PaddleDetection/tree/release/2.1/configs/ppyolo

import os, sys, os.path
import numpy as np
import cv2
from openvino.inference_engine import IENetwork, IECore, ExecutableNetwork
from IPython import display
from PIL import Image, ImageDraw
import urllib, shutil, json
import yaml
from yaml.loader import SafeLoader

下载和导出百度型号- YOLOV3和PPYOLO

这个需要一些时间,要确保按照官网中read me中的安装说明将PaddleDetection GitHub安装在openvino-paddlepaddle-demo目录中。
下面是官网的链接
Reference on Baidu Model Exporting: https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.1/deploy/EXPORT_MODEL.md

#Get the YOLOV3
PADDLE_DET_PATH="../../PaddleDetection"
YML_CONFIG="configs/yolov3/yolov3_darknet53_270e_coco.yml"
PRETRAINED="yolov3_darknet53_270e_coco.pdparams"
OUTPUT_DIR="models"
if(not os.path.isfile("models/yolov3_darknet53_270e_coco/model.pdmodel")):
    print("Download and Export Model... This may take a while...")
    ! python $PADDLE_DET_PATH/tools/export_model.py -c $PADDLE_DET_PATH/$YML_CONFIG -o use_gpu=false weights=https://paddledet.bj.bcebos.com/models/$PRETRAINED  "TestReader.inputs_def.image_shape=[3,608,608]" --output_dir=$OUTPUT_DIR
else:
    print("Model is already downloaded")

结果显示模型已经下载了
Model is already downloaded

#Get the PPYOLO (experimental)
PADDLE_DET_PATH="../../PaddleDetection"
YML_CONFIG="configs/ppyolo/ppyolo_r50vd_dcn_1x_coco.yml"
PRETRAINED="ppyolo_r50vd_dcn_1x_coco.pdparams"
OUTPUT_DIR="models"
if(not os.path.isfile("models/ppyolo_r50vd_dcn_1x_coco/model.pdmodel")):
    print("Download and Export Model... This may take a while...")
    ! python $PADDLE_DET_PATH/tools/export_model.py -c $PADDLE_DET_PATH/$YML_CONFIG -o use_gpu=false weights=https://paddledet.bj.bcebos.com/models/$PRETRAINED  "TestReader.inputs_def.image_shape=[3,608,608]" --output_dir=$OUTPUT_DIR
else:
    print("Model is already downloaded")

Model is already downloaded

#Helper functions
def image_preprocess(input_image, size):
    img = cv2.resize(input_image, (size,size))
    img = np.transpose(img, [2,0,1]) / 255
    img = np.expand_dims(img, 0)
    ##NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    img_mean = np.array([0.485, 0.456,0.406]).reshape((3,1,1))
    img_std = np.array([0.229, 0.224, 0.225]).reshape((3,1,1))
    img -= img_mean
    img /= img_std
    return img.astype(np.float32)
def draw_box(img, results, label_text, scale_x, scale_y):
    for i in range(len(results)):
        #print(results[i])
        bbox = results[i, 2:]
        label_id = int(results[i, 0])
        score = results[i, 1]
        if(score>0.20):
            xmin, ymin, xmax, ymax = [int(bbox[0]*scale_x), int(bbox[1]*scale_y), 
                                      int(bbox[2]*scale_x), int(bbox[3]*scale_y)]
            cv2.rectangle(img,(xmin, ymin),(xmax, ymax),(0,255,0),3)
            font = cv2.FONT_HERSHEY_SIMPLEX
            label_text = label_list[label_id];
            cv2.rectangle(img, (xmin, ymin), (xmax, ymin-70), (0,255,0), -1)
            cv2.putText(img, "#"+label_text,(xmin,ymin-10), font, 1.2,(255,255,255), 2,cv2.LINE_AA)
            cv2.putText(img, str(score),(xmin,ymin-40), font, 0.8,(255,255,255), 2,cv2.LINE_AA)
    return img

设置模型

可以在两个不同的模型之间切换-默认是PPYolo来对比两个模型的性能

#PPYolo3
#pdmodel_path = "models/yolov3_darknet53_270e_coco"

#PPYolo (experimental)
pdmodel_path = "models/ppyolo_r50vd_dcn_1x_coco"

pdmodel_file = pdmodel_path + "/model.pdmodel"
pdmodel_config = pdmodel_path + "/infer_cfg.yml"
device = 'CPU'

#load the data from config, and setup the parameters
label_list=[]
with open(pdmodel_config) as f:
    data = yaml.load(f, Loader=SafeLoader)
label_list = data['label_list'];

将PaddlePaddle预训练模型加载到OpenVINO推理引擎(IE)中

ie = IECore()
net = ie.read_network(pdmodel_file)

net.reshape({'image': [1, 3, 608, 608], 'im_shape': [
            1, 2], 'scale_factor': [1, 2]})

exec_net = ie.load_network(net, device)
assert isinstance(exec_net, ExecutableNetwork)

加载图像并运行推理步骤

input_image = cv2.imread("horse.jpg")
test_image = image_preprocess(input_image, 608)
test_im_shape = np.array([[608, 608]]).astype('float32')
test_scale_factor = np.array([[1, 2]]).astype('float32')
#print(test_image.shape)

inputs_dict = {'image': test_image, "im_shape": test_im_shape,
               "scale_factor": test_scale_factor}

output = exec_net.infer(inputs_dict)
result_ie = list(output.values())


result_image = cv2.imread("horse.jpg")
scale_x = result_image.shape[1]/608*2
scale_y = result_image.shape[0]/608
result_image = draw_box(result_image, result_ie[0], label_list, scale_x, scale_y)
_,ret_array = cv2.imencode('.jpg', result_image) 
i = display.Image(data=ret_array)            
display.display(i)

cv2.imwrite("yolo-output.png",result_image) 

在这里插入图片描述

实时摄像头演示

下面的示例显示了在摄像头上运行YoloV3。这个模型确实更复杂,因此可以提供更好的mAP。也考虑其他的模型,如mobilenet,如果你想权衡性能和准确性。

Source: https://github.com/PaddlePaddle/PaddleDetection

def YoloVideo(VideoIndex=0, scale=0.5):
    #PPYolo3
    pdmodel_path = "models/yolov3_darknet53_270e_coco"

    pdmodel_file = pdmodel_path + "/model.pdmodel"
    pdmodel_config = pdmodel_path + "/infer_cfg.yml"
    device = 'CPU'

    #load the data from config, and setup the parameters
    label_list=[]
    with open(pdmodel_config) as f:
        data = yaml.load(f, Loader=SafeLoader)
    label_list = data['label_list'];
    
    ie = IECore()
    net = ie.read_network(pdmodel_file)

    net.reshape({'image': [1, 3, 608, 608], 'im_shape': [
                1, 2], 'scale_factor': [1, 2]})

    exec_net = ie.load_network(net, device)
    assert isinstance(exec_net, ExecutableNetwork)
    
    try:
        cap = cv2.VideoCapture(VideoIndex)
    except:
        print("Cannot Open Device")
        del exec_net
    try:
        ret, frame = cap.read()
        
        while(ret==True):
            # Capture frame-by-frame
            ret, frame = cap.read()
            
            if not ret:
                # Release the Video Device if ret is false
                cap.release()
                # Message to be displayed after releasing the device
                print ("Released Video Resource")
                break
            #frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            half_frame = cv2.resize(frame, (0, 0), fx = scale, fy = scale)
             
            #Processing the Frame
            test_image = image_preprocess(half_frame, 608)
            test_im_shape = np.array([[608, 608]]).astype('float32')
            test_scale_factor = np.array([[1, 2]]).astype('float32')
            #print(test_image.shape)
            inputs_dict = {'image': test_image, "im_shape": test_im_shape,
                           "scale_factor": test_scale_factor}

            output = exec_net.infer(inputs_dict)
            result_ie = list(output.values())
            
            result_image = half_frame.copy()
            #result_image = cv2.resize(result_image, (int(608*1.0),int(608*1.0)))
            scale_x = result_image.shape[1]/608*2
            scale_y = result_image.shape[0]/608
            
            result_image = draw_box(result_image, result_ie[0], label_list, scale_x, scale_y)
            
            #convert to jpg for performance results
            _,ret_array = cv2.imencode('.jpg', result_image) 
            i = display.Image(data=ret_array)            
            
            display.display(i)
            display.clear_output(wait=True)
    except KeyboardInterrupt:
        # Release the Video Device
        cap.release()
        # Message to be displayed after releasing the device
        print("Released Video Resource from KeyboardInterrupt")
        del exec_net
    pass

运行Webcam Feed

请按下停止按钮,以正确终止。

YoloVideo(1, 0.75)
Released Video Resource from KeyboardInterrupt

openvino-PaddleOCR

手写识别古诗

这个演示出自博士吴卓(OpenVINO Edge AI软件布道者- Intel)
的一个开源项目,演示了如何在OpenVINO上运行PaddleOCR (Lite)模型。我们现在可以直接从mobilenetv3模型读取而不需要任何转换,而不是将mobilenetv3模型导出到ONNX,然后通过OpenVINO优化器创建中间表示(IR)格式。

如果有什么出错的地方,可以参考这里

通过OpenVINO运行Paddle Detection

import os, os.path
import sys
import json
import urllib.request
import cv2
import numpy as np
import paddle
import math
import time

from openvino.inference_engine import IENetwork, IECore, ExecutableNetwork
from IPython import display
from PIL import Image, ImageDraw
import copy

import logging
import imghdr
from shapely.geometry import Polygon
import pyclipper

from pre_post_processing import *

加载图片

def image_preprocess(input_image, size):
    img = cv2.resize(input_image, (size,size))
    img = np.transpose(img, [2,0,1]) / 255
    img = np.expand_dims(img, 0)
    ##NormalizeImage: {mean: [0.485, 0.456, 0.406], std: [0.229, 0.224, 0.225], is_scale: True}
    img_mean = np.array([0.485, 0.456,0.406]).reshape((3,1,1))
    img_std = np.array([0.229, 0.224, 0.225]).reshape((3,1,1))
    img -= img_mean
    img /= img_std
    return img.astype(np.float32)
# Test images provided include 1 handwritten Chinese image and 1 printed Chinese image
image_file = "handwritten_simplified_chinese_test.jpg"

ii = cv2.imread(image_file)
test_image = image_preprocess(ii,640)
Load the Network
model_dir = "./inference/ch_ppocr_mobile_v2.0_det_infer"
model_file_path = model_dir + "/inference.pdmodel"
params_file_path = model_dir + "/inference.pdiparams"
# initialize inference engine
ie = IECore()
# initialize inference engine
net = ie.read_network(model_file_path)

# pdmodel might be dynamic shape, this will reshape based on the input
input_key = list(net.input_info.items())[0][0] # 'inputs'
net.reshape({input_key: test_image.shape})

exec_net = ie.load_network(net, 'CPU') 
assert isinstance(exec_net, ExecutableNetwork)
#perform the inference step
det_start_time = time.time()
output = exec_net.infer({input_key: test_image})
det_stop_time = time.time()
result_ie = list(output.values())
det_infer_time = det_stop_time - det_start_time

对PaddleDetection的推理结果进行后处理

ori_im = ii.copy()
data = {'image': ii}

data_resize = DetResizeForTest(data)
data_norm = NormalizeImage(data_resize)
data_list = []
keep_keys =  ['image', 'shape']
for key in keep_keys:
    data_list.append(data[key])
img, shape_list = data_list

shape_list = np.expand_dims(shape_list, axis=0)
pred = result_ie[0]      
if isinstance(pred, paddle.Tensor):
    pred = pred.numpy()
pred = pred[:, 0, :, :]
segmentation = pred > 0.3

boxes_batch = []
for batch_index in range(pred.shape[0]):
    src_h, src_w, ratio_h, ratio_w = shape_list[batch_index]

    mask = segmentation[batch_index]
    boxes, scores = boxes_from_bitmap(pred[batch_index], mask,src_w, src_h)
    boxes_batch.append({'points': boxes})

post_result = boxes_batch
dt_boxes = post_result[0]['points']
dt_boxes = filter_tag_det_res(dt_boxes, ii.shape)

在openvino 上运行飞浆识别

# Processing detection results for Recognition

dt_boxes = sorted_boxes(dt_boxes)
img_crop_list = []

for bno in range(len(dt_boxes)):
    tmp_box = copy.deepcopy(dt_boxes[bno])
    img_crop = get_rotate_crop_image(ori_im, tmp_box)
    img_crop_list.append(img_crop)

预处理输送给Paddle识别的图像

def resize_norm_img(img, max_wh_ratio):
        rec_image_shape = [3, 32, 320]
        imgC, imgH, imgW = rec_image_shape
        assert imgC == img.shape[2]
        character_type = "ch"
        if character_type == "ch":
            imgW = int((32 * max_wh_ratio))
        h, w = img.shape[:2]
        ratio = w / float(h)
        if math.ceil(imgH * ratio) > imgW:
            resized_w = imgW
        else:
            resized_w = int(math.ceil(imgH * ratio))
        resized_image = cv2.resize(img, (resized_w, imgH))
        resized_image = resized_image.astype('float32')
        resized_image = resized_image.transpose((2, 0, 1)) / 255
        resized_image -= 0.5
        resized_image /= 0.5
        padding_im = np.zeros((imgC, imgH, imgW), dtype=np.float32)
        padding_im[:, :, 0:resized_w] = resized_image
        return padding_im

Load the Network

model_dir = "./inference/ch_ppocr_mobile_v2.0_rec_infer"
model_file_path = model_dir + "/inference.pdmodel"
params_file_path = model_dir + "/inference.pdiparams"

ie = IECore()
net = ie.read_network(model_file_path)

开始识别古诗词

img_num = len(img_crop_list)
# Calculate the aspect ratio of all text bars
width_list = []
for img in img_crop_list:
    width_list.append(img.shape[1] / float(img.shape[0]))
# Sorting can speed up the recognition process
indices = np.argsort(np.array(width_list))
rec_res = [['', 0.0]] * img_num
rec_batch_num = 6
batch_num = rec_batch_num
rec_processing_times = 0
for beg_img_no in range(0, img_num, batch_num):
    end_img_no = min(img_num, beg_img_no + batch_num)
    norm_img_batch = []
    max_wh_ratio = 0
    for ino in range(beg_img_no, end_img_no):
        h, w = img_crop_list[indices[ino]].shape[0:2]
        wh_ratio = w * 1.0 / h
        max_wh_ratio = max(max_wh_ratio, wh_ratio)
    for ino in range(beg_img_no, end_img_no):
        norm_img = resize_norm_img(img_crop_list[indices[ino]],max_wh_ratio)
        norm_img = norm_img[np.newaxis, :]
        norm_img_batch.append(norm_img)

    norm_img_batch = np.concatenate(norm_img_batch)
    norm_img_batch = norm_img_batch.copy()
    
    # pdmodel might be dynamic shape, this will reshape based on the input
    input_key = list(net.input_info.items())[0][0] # 'inputs'
    net.reshape({input_key: norm_img_batch.shape})

    #load the network on CPU
    start_time = time.time()
    exec_net = ie.load_network(net, 'CPU') 
    stop_time = time.time()
    assert isinstance(exec_net, ExecutableNetwork)
    
    rec_processing_times += stop_time - start_time

    for index in range(len(norm_img_batch)):
        output = exec_net.infer({input_key: norm_img_batch})
    result_ie = list(output.values())
    preds = result_ie[0]
    postprocess_op = build_post_process(postprocess_params)
    rec_result = postprocess_op(preds)
    for rno in range(len(rec_result)):
        rec_res[indices[beg_img_no + rno]] = rec_result[rno]

final_stop_time = time.time()
processing_time = final_stop_time - det_start_time
print("The total prediction and processing time is ", processing_time)

The total prediction and processing time is 0.3596353530883789

print("The total inference time for detection is ", det_infer_time)
print("The total inference time for recognition is ", rec_processing_times)

The total inference time for detection is 0.030055999755859375
The total inference time for recognition is 0.127180814743042

可视化检测和识别结果

src_im = draw_text_det_res(dt_boxes, image_file)
img_name_pure = os.path.split(image_file)[-1]
img_path = "det_res_{}".format(img_name_pure)
cv2.imwrite(img_path, src_im)

#Visualization Paddle Detection results
_,ret_array = cv2.imencode('.jpg', src_im) 
i = display.Image(data=ret_array)            
display.display(i)

在这里插入图片描述

#Visualization Paddle Recognition results, format
print(rec_res)

[(‘结庐在人境品无车马喧’, 0.7947357), (‘问君何能尔心远地自偏采前’, 0.78279454), (‘东鹤下您然见南山山气日夕’, 0.8802729), (‘佳飞鸟相与还此中有真意欲’, 0.8675663), (‘辩已意言’, 0.38597608)]

猜你喜欢

转载自blog.csdn.net/weixin_47567401/article/details/122709970
今日推荐