0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

详谈PyTorch OCR模型的安卓端部署

电子设计 来源:电子设计 作者:电子设计 2020-12-08 23:07 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

文章转载于微信公众号:GiantPandaCV
作者: 阿呆

开发环境选择

  1. 本文操作系统为Windows,因为Windows上的安卓模拟器选择较多,并且真机调试也比较方便;
  2. 交叉编译在Windows和Ubuntu上都进行了尝试,都可行,但是如果是Ubuntu上交叉编译之后再挪到Windows的话,容易出幺蛾子;
  3. 我目前使用的最稳定的工具版本组合是:ndk18、androidstudio4.1、cmake3.10、gradle6.5、MinGW(CodeBlocks自带)。

1. PyTorch模型转NCNN

这一小节是介绍如何将自己重新训练过的PyTorch模型转成ncnn,如果没有重训练需求的话,可以直接跳过这一节。

(1) 整体步骤

理想情况下,从PyTorch转到ncnn只需要下面两步:

  • PyTorch转ONNX
torch.onnx._export(model,x,path,opset_version=11)  
  • ONNX转NCNN
./onnx2ncnnmodel.onnxmodel.parammodel.bin  

遇到问题的适合解决思路如下:

convert.png

下面介绍一下我在做ChineseOCRLite中的PSENet模型转换的过程中遇到的问题。

(2)实际操作的时候可能会遇到各种问题

问题1:ReLU6不支持

概述:ReLU6算子在转换的时候容易出现不支持的情况,需要使用其他算子替代

解决:使用torch.clamp替代(虽然ReLU6可以通过组合ReLU的方式实现,但是组合得到的ReLU6在NCNN中容易转换失败,不建议使用。)

defrelu6(x,inplace=True):  
returntorch.clamp(x,0,6)  

问题2:Resize算子转换问题

概述:因为各个框架对Resize算子的支持都不尽相同,在转换过程中总会出现一些问题,pytorch中的interpolate算子转换成ONNX之后变成很多零散的算子,如cast、shape等,这些在ncnn里面不支持。你可以选择手动修改文件,也可以使用下面这个自动的方法:

解决:使用onnx/_simplifier对onnx模型进行简化,可以合并这些零散的算子。

python-monnxsimmodel.onnxmodel_sim.onnx  

问题3:关于转ONNX及使用onnx/_simplifier过程中出现的一系列奇怪问题

概述:使用不同版本的ONNX可能会遇到不同的问题,比如提示conv层无输入等(具体错误名称记不清了)。

解决:下载最新ONNX源码编译安装(onnx/_simplifier中出现的一些错误也可以通过安装最新ONNX来解决)

gitclonehttps://github.com/onnx/onnx.git  
sudoapt-getinstallprotobuf-compilerlibprotoc-dev  
cdONNX  
pythonsetup.pyinstall  

问题4:模型输出结果的尺寸固定

概述:直接转换得到的onnx模型的Resize算子都是固定输出尺寸的,无论输入多大的图片都会输出同样大小的特征图,这无疑会影响到模型的精度及灵活性。

解决:修改NCNN模型的param文件,将Resize算子修改成按比例resize。

直接转换得到的param文件中的Interp算子是这样的:

Interp913119019130=21=1.000000e+002=1.000000e+003=6404=640  

从下面的ncnn源码中可以看到,0代表resize/_type,1和2分别是高和宽的缩放比例,3和4分别是输出的高和宽。

intInterp::load_param(constParamDict&pd)  
{  
resize_type=pd.get(0,0);  
height_scale=pd.get(1,1.f);  
width_scale=pd.get(2,1.f);  
output_height=pd.get(3,0);  
output_width=pd.get(4,0);  
return0;  
}  

我们只需将其修改成如下格式即可实现按比例resize:

Interp913119019130=11=4.000000e+002=4.000000e+00  

问题5:NCNN模型输出结果与ONNX模型不同

解决:逐层对比NCNN与onnx模型的输出结果

使用onnxruntime(Python)和NCNN(C++)分别提取每个节点的输出,进行对比。对于ncnn比较简单,可以使用

extractor.extract(node_name,preds);  

来提取不同节点的输出。

问题5衍生问题1:ONNX没有提供提取中间层输出的方法

解决:给要提取的层添加一个输出节点,代码如下:

deffind_node_by_name(graph,node_name):  
fornodeingraph.node:  
ifnode.output[0]==node_name:  
returnnode  
returnNone  
  
defadd_extra_output_node(model,target_node,output_name):  
extra_output=helper.make_empty_tensor_value_info(output_name)  
target_output=target_node.output[0]  
identity_node=helper.make_node("Identity",inputs=[target_output],outputs=[output_name],name=output_name)  
model.graph.node.append(identity_node)  
model.graph.output.append(extra_output)  
returnmodel  

修改模型之后再使用

out=sess.run([output_name],{"input.1":img.astype(np.float32)})  

就可以获取到模型的中间层输出了。

问题5衍生问题2:发现最后一个Resize层的输出有差异

解决:参考chineseocr/_lite里面的代码把mode由bilinear改成了nearest(这里错误的原因可能是wenmuzhou/PSENet.pytorch中的模型最后一个F.interpolate中的align/_corners参数设置成了True。据说NCNN只实现了align/_corners为False的情况)。

这里修改之后的模型跟原模型之间是会有少许误差的,如果误差不可接受,就要重新训练才行。

2. 交叉编译opencv与ncnn

交叉编译工作可以在windows上进行,使用的是MinGW + cmkae3.10 + AndroidNDK18。可以参考Windows下编译OpenCV android(https://www.cnblogs.com/zhxmdefj/p/13094954.html)

没有windows C++环境的话,也可以选择在linux上进行。

如果是在linux交叉编译,然后复制到windows的话,需要修改一下opencv中cmake配置文件中的路径。

(1)android ndk下载

最初选择的是r20b,因为和CMake之间的兼容问题,切换到了18b。

wgethttps://dl.google.com/android/repository/android-ndk-r18b-linux-x86_64.zip?hl=zh_cn  
mvandroid-ndk-r18b-linux-x86_64.zip?hl=zh_cnandroid-ndk-r18b-linux-x86_64.zip  
unzipandroid-ndk-r18b-linux-x86_64.zip  

(2)编译opencv

利用android中提供的android.toolchain.cmake 工具链可以快速的编译opencv的arm版。

这里选择的arm平台是armeabi-v7a,便于在老旧手机上运行。

folde  
if[[!-d"$folder"]];then  
echo"$foldernotfound,creatingfolder..."  
mkdirbuild_arm  
fi  
cdbuild_arm  
cmake/  
-DCMAKE_TOOLCHAIN_FILE=/  
/home/dai/soft/android-ndk-r18b/build/cmake/android.toolchain.cmake/  
-DANDROID_NDK=/home/dai/soft/android-ndk-r18b/  
-DCMAKE_BUILD_TYPE=Release/  
-DBUILD_ANDROID_PROJECTS=OFF/  
-DBUILD_ANDROID_EXAMPLES=OFF/  
-DANDROID_ABI=armeabi-v7a/  
-DANDROID_NATIVE_API_LEVEL=21..  
make-j4  

(3)编译ncnn

编译选项参考ncnn wiki(https://github.com/Tencent/nc...

folde  
if[[!-d"$folder"]];then  
echo"$foldernotfound,creatingfolder..."  
mkdirbuild_arm  
fi  
cdbuild_arm  
cmake/  
-DCMAKE_TOOLCHAIN_FILE=/  
/home/dai/soft/android-ndk-r18b/build/cmake/android.toolchain.cmake/  
-DANDROID_AB/  
-DANDROID_ARM_NEON=ON/  
-DANDROID_PLATFORM=android-14/  
..  
make-j4  

(4)chineseocr/_lite的PC端测试

与ncnn有关的代码位于ncnn/_project目录下。在有opencv和ncnn库的基础上,可以先在pc端跑一下识别代码。

cdncnn_project/ocr  
mkdirbuild_arm  
cdbuild_arm  
cmake..  
make-j4  

编译完成之后

./TextRecognition../test1.jpg  

可以看到输出结果:

psenet前向时间:0.462291s  
psenetdecode时间:0.0604791s  
boxzie10  
预测结果:  
一  
统  
;名  
称  
丹正珍  
类住  
型  
有限责  
所  
中山市  
角度检测和文字识别总时间:1.52042s  

3. NCNN模型的安卓端部署

因为代码较长,这一部分只介绍把PC端代码迁移到安卓端的思路,想看详细代码的同学请移步文末的Github地址。

迁移的整体思路如下图所示:


android/_flow.png

下面一一介绍图中内容

UI界面

这个demo的UI界面中至少应包含三个元件:

Button——用于选择相册图片

ImageView——用于展示图片及文本检测框

TextView——用于展示识别结果

界面截图如下(TextView在没有文字的时候是不显示的):


UI.jpg

界面res/layout/activity/_main.xml文件修改。

Java部分

模型推理是在C++中完成的,Java部分的代码主要是利用安卓的API实现图片读取、文本检测框绘制和结果展示等功能。

需要传入到C++函数的内容包括Bitmap图片和AssetManager对象。

从C++接收到的是一个包含文本框和识别结果的字符串。

C++部分

C++负责模型推理,推理代码与PC端无异,只是安卓端的文件读取与PC端不同,需要修改文件读取代码,比如crnn的模型加载代码就需要改成下面的样子:

intmodel::init(AAssetManager*mgr,conststd::stringcrnn_param,conststd::stringcrnn_bin)  
{  
intret1=crnn.load_param(mgr,crnn_param.c_str());  
intret2=crnn.load_model(mgr,crnn_bin.c_str());  
LOGI("ret1is%d,ret2is%d",ret1,ret2);  
return(ret1||ret2);  
}  

另外还需要把Java部分传过来的Bitmap转换成cv::Mat,代码如下:

//convertbitmaptomat  
int*data=NULL;  
AndroidBitmapInfoinfo={0};  
AndroidBitmap_getInfo(env,bitmap,&info);  
AndroidBitmap_lockPixels(env,bitmap,(void**)&data);  
  
//这里偷懒只写了RGBA格式的转换  
LOGI("infoformatRGBA?%d",info.format==ANDROID_BITMAP_FORMAT_RGBA_8888);  
cv::Mattest(info.height,info.width,CV_8UC4,(char*)data);//RGBA  
cv::Matimg_bgr;  
cvtColor(test,img_bgr,CV_RGBA2BGR);  

最终识别结果

最终得到的demo识别结果如下图所示:

result.jpg

本项目完整代码请移步github:

https://github.com/Arctanxy/D...

推荐阅读

更多嵌入式AI技术干货请关注嵌入式AI专栏。

审核编辑:符乾江
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • AI
    AI
    +关注

    关注

    89

    文章

    38091

    浏览量

    296582
  • 深度学习
    +关注

    关注

    73

    文章

    5590

    浏览量

    123903
  • pytorch
    +关注

    关注

    2

    文章

    813

    浏览量

    14698
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    vision board部署模型到openmv的代码导致连接超时怎么解决?

    在env终端中勾选了tiflte support后烧录mdk到板子上后就开始显示连接不到 无法部署模型
    发表于 09-19 07:59

    ALINX VD100低功耗侧大模型部署方案,运行3B模型功耗仅5W?!

    模型能运行≠用户体验好。 IDC 预测,到 2026 年,全球超过 50% 的企业 AI 工作负载将部署在边缘设备上。在 AI 部署逐渐从云端转向边缘的趋势下,越来越多智能终端开始
    的头像 发表于 09-03 14:58 472次阅读
    ALINX VD100低功耗<b class='flag-5'>端</b>侧大<b class='flag-5'>模型</b><b class='flag-5'>部署</b>方案,运行3B<b class='flag-5'>模型</b>功耗仅5W?!

    Arm方案 基于Arm架构的边缘侧设备(树莓派或 NVIDIA Jetson Nano)上部署PyTorch模型

    本文将为你展示如何在树莓派或 NVIDIA Jetson Nano 等基于 Arm 架构的边缘侧设备上部署 PyTorch 模型
    的头像 发表于 07-28 11:50 2497次阅读

    Say Hi to ERNIE!Imagination GPU率先完成文心大模型部署

    ImaginationTechnologies宣布率先完成百度文心大模型(ERNIE4.5开源版)在其GPU硬件上的部署。适配完成后,开发者可在搭载ImaginationGPU的设备上实现高效
    的头像 发表于 07-01 08:17 772次阅读
    Say Hi to ERNIE!Imagination GPU率先完成文心大<b class='flag-5'>模型</b>的<b class='flag-5'>端</b>侧<b class='flag-5'>部署</b>

    如何实现与恩智浦i.MX RT1170的无线投屏与控制

    Scrcpy是一款免费开源的软件,支持将屏幕投影到其他设备,并支持被投屏设备对的反向控制。基于ADB工具,
    的头像 发表于 06-26 09:53 1937次阅读
    如何实现<b class='flag-5'>安</b><b class='flag-5'>卓</b>与恩智浦i.MX RT1170的无线投屏与控制

    如何使用Docker部署模型

    随着深度学习和大模型的快速发展,如何高效地部署这些模型成为了一个重要的挑战。Docker 作为一种轻量级的容器化技术,能够将模型及其依赖环境打包成一个可移植的容器,极大地简化了
    的头像 发表于 05-24 16:39 796次阅读

    使用OpenVINO优化并部署飞桨PP-OCRv4模型

    算法,在此基础上打造产业级特色模型系列:PP-OCR、PP-Structure和PP-ChatOCR,打通了模型训练、压缩、部署全流程
    的头像 发表于 04-03 18:07 2249次阅读
    使用OpenVINO优化并<b class='flag-5'>部署</b>飞桨PP-OCRv4<b class='flag-5'>模型</b>

    AI大模型部署正当时:移远端侧AI大模型解决方案,激活场景智能新范式

    在AI技术飞速发展的当下,AI大模型的应用正从云端向侧加速渗透。 作为全球领先的物联网整体解决方案供应商,移远通信凭借深厚的技术积累与前瞻性的战略布局,在AI大模型
    发表于 03-27 11:26 424次阅读
    AI大<b class='flag-5'>模型</b><b class='flag-5'>端</b>侧<b class='flag-5'>部署</b>正当时:移远端侧AI大<b class='flag-5'>模型</b>解决方案,激活场景智能新范式

    AI大模型部署正当时:移远端侧AI大模型解决方案,激活场景智能新范式

    在AI技术飞速发展的当下,AI大模型的应用正从云端向侧加速渗透。作为全球领先的物联网整体解决方案供应商,移远通信凭借深厚的技术积累与前瞻性的战略布局,在AI大模型
    的头像 发表于 03-26 19:05 988次阅读
    AI大<b class='flag-5'>模型</b><b class='flag-5'>端</b>侧<b class='flag-5'>部署</b>正当时:移远端侧AI大<b class='flag-5'>模型</b>解决方案,激活场景智能新范式

    K230D部署模型失败的原因?

    MicroPython部署的无法正常运行,采用C++版本的无法实现部署 尝试解决过程 1.考虑到可能是固件不匹配的问题,重新烧录了流程(生成模型后给的readme)中要求的固件,依旧无法成功
    发表于 03-11 06:19

    使用OpenVINO™ 2021.4将经过训练的自定义PyTorch模型加载为IR格式时遇到错误怎么解决?

    使用 OpenVINO™ 2021.4 将经过训练的自定义 PyTorch 模型加载为 IR 格式时遇到错误: RuntimeError: [ GENERAL_ERROR ] Failed
    发表于 03-05 08:40

    自制 AirTag,支持/鸿蒙/PC/Home Assistant,无需拥有 iPhone

    苹果的 AirTag 很贵,虽然某强北有平价代替品,但是仍需要苹果设备才能绑定,才能查看位置。不支持/鸿蒙/PC ,也不支持集成到 Home Assistant 中。 AirTag
    发表于 02-25 11:22

    如何在C#中部署飞桨PP-OCRv4模型

    《超4万6千星的开源OCR黑马登场,PaddleOCR凭什么脱颖而出?》收到了读者热烈反响c,很多读者提出:如何在C#中部署飞桨PP-OCRv4模型?本文从零开始详细介绍整个过程。
    的头像 发表于 02-17 10:58 2648次阅读
    如何在C#中<b class='flag-5'>部署</b>飞桨PP-OCRv4<b class='flag-5'>模型</b>

    使用OpenVINO C# API轻松部署飞桨PP-OCRv4模型

    ​ 作者:算力魔方创始人/英特尔创新大使刘力 《超4万6千星的开源OCR黑马登场,PaddleOCR凭什么脱颖而出?》 收到了读者热烈反响,很多读者提出:如何在C#中部署飞桨PP-OCRv4模型
    的头像 发表于 02-12 10:42 2019次阅读
    使用OpenVINO C# API轻松<b class='flag-5'>部署</b>飞桨PP-OCRv4<b class='flag-5'>模型</b>

    AI模型部署边缘设备的奇妙之旅:目标检测模型

    以及边缘计算能力的增强,越来越多的目标检测应用开始直接在靠近数据源的边缘设备上运行。这不仅减少了数据传输延迟,保护了用户隐私,同时也减轻了云端服务器的压力。然而,在边缘部署高效且准确的目标检测模型
    发表于 12-19 14:33