当前位置:   article > 正文

PP-OCRv3 文本识别模型转ncnn模型_paddle模型转 ncnn

paddle模型转 ncnn

1、下载PP-OCRv3

       https://github.com/PaddlePaddle/PaddleOCR

 2、将paddle模型转换成onnx模型

创建虚拟环境):paddle

base环境(使用onnx-sim进行简化)

(1) 转onnx命令(paddle环境):

  1. paddle2onnx --model_dir ./paddle_infere/
  2. --model_filename inference.pdmodel
  3. --params_filename inference.pdiparams
  4. --save_file ./rec_v3.onnx
  5. --opset_version 11

 (2)利用onnx-sim对onnx模型进行简化和优化(base环境)

命令:

  1. #简化
  2. python3 -m onnxsim ./rec_v3.onnx ./rec_v3-sim.onnx --overwrite-input-shape 1,3,48,320
  3. # 优化
  4. python3 -m onnxoptimizer rec_v3-sim.onnx rec_v3-sim-opt.onnx

3、将onnx模型转为ncnn模型

        a、下载ncnn  https://github.com/Tencent/ncnn

               本例中下载的版本为:ncnn-20221128-windows-vs2015

       b、将onnx转为ncnn模型

             命令:

  1. # 转换为ncnn
  2. onnx2ncnn.exe ./rec_v3-sim-opt.onnx ./rec_v3-sim-opt.param ./rec_v3-sim-opt.bin
  3. # 对ncnn进行优化
  4. ncnnoptimize.exe rec_v3-sim-opt.param rec_v3-sim-opt.bin rec_v3-sim-new-opt.param rec_v3-sim-new-opt.bin 0 (其中 0=float32, 1=float16)

onnx转ncnn模型运行结果:(部分op操作不支持)两个attention模块有个5d的reshpe导致出现了问题

 ncnn进行优化运行结果(不是paddleocrv3 官方识别模型的截图)

4、对模型进行修改不支持的操作

      (如需下述中的g步骤,请先进行g步骤在修改其他操作)

     (1)打开.param文件

     (2)修改不支持的操作

             a、两个reshape操作, ncnn不支持5d转换 (共2个),ncnn的reshape和permute目前已经支持4d操作

 

  1. 操作 层名 输入数量 输出数量 输入变量名 输出变量名
  2. # 改之前
  3. Reshape p2o.Reshape.87 1 1 p2o.Add.89 reshape2_0.tmp_0 0=120 1=3 2=-1
  4. Permute p2o.Transpose.1 1 1 reshape2_0.tmp_0 transpose_1.tmp_0
  5. Reshape p2o.Reshape.93 1 1 p2o.Add.109 reshape2_2.tmp_0 0=120 1=3 2=-1
  6. Permute p2o.Transpose.4 1 1 reshape2_2.tmp_0 transpose_4.tmp_0
  7. # 改之后
  8. Reshape p2o.Reshape.87 1 1 p2o.Add.89 reshape2_0.tmp_0 0=15 1=8 2=-1 11=3
  9. Permute p2o.Transpose.1 1 1 reshape2_0.tmp_0 transpose_1.tmp_0 0=8
  10. Reshape p2o.Reshape.93 1 1 p2o.Add.109 reshape2_2.tmp_0 0=15 1=8 2=-1 11=3
  11. Permute p2o.Transpose.4 1 1 reshape2_2.tmp_0 transpose_4.tmp_0 0=8
  12. 注解: 其中reshape: 0:宽(w) 1:高(h) 2:通道(c) 11:depth (ncnn框架中)

b、ncnn的squeeze不支持4d操作, 将squeeze 改为reshape即可。(总共6个)

  1. # 修改之前
  2. Squeeze p2o.Squeeze.0 1 1 p2o.Slice.3 transpose_1.tmp_0_slice_0 -23303=1,0
  3. Squeeze p2o.Squeeze.1 1 1 p2o.Slice.5 transpose_1.tmp_0_slice_1 -23303=1,0
  4. Squeeze p2o.Squeeze.2 1 1 p2o.Slice.7 transpose_1.tmp_0_slice_2 -23303=1,0
  5. # 修改之后
  6. Reshape p2o.Squeeze.0 1 1 p2o.Slice.3 transpose_1.tmp_0_slice_0 0=15 1=-1 2=8
  7. Reshape p2o.Squeeze.1 1 1 p2o.Slice.5 transpose_1.tmp_0_slice_1 0=15 1=-1 2=8
  8. Reshape p2o.Squeeze.2 1 1 p2o.Slice.7 transpose_1.tmp_0_slice_2 0=15 1=-1 2=8
  9. # 修改之前
  10. Squeeze p2o.Squeeze.3 1 1 p2o.Slice.11 transpose_4.tmp_0_slice_0 -23303=1,0
  11. Squeeze p2o.Squeeze.4 1 1 p2o.Slice.13 transpose_4.tmp_0_slice_1 -23303=1,0
  12. Squeeze p2o.Squeeze.5 1 1 p2o.Slice.15 transpose_4.tmp_0_slice_2 -23303=1,0
  13. # 修改之后
  14. Reshape p2o.Squeeze.3 1 1 p2o.Slice.11 transpose_4.tmp_0_slice_0 0=15 1=-1 2=8
  15. Reshape p2o.Squeeze.4 1 1 p2o.Slice.13 transpose_4.tmp_0_slice_1 0=15 1=-1 2=8
  16. Reshape p2o.Squeeze.5 1 1 p2o.Slice.15 transpose_4.tmp_0_slice_2 0=15 1=-1 2=8

c、将把attention中的Gemm修改为MatMul即可(总共4个)

  1. # 修改前
  2. Gemm p2o.MatMul.2 2 1 p2o.Mul.9 transpose_2.tmp_0 p2o.MatMul.3
  3. Gemm p2o.MatMul.4 2 1 softmax_0.tmp_0 transpose_1.tmp_0_slice_2 p2o.MatMul.5
  4. # 修改后
  5. MatMul p2o.MatMul.2 2 1 p2o.Mul.9 transpose_2.tmp_0 p2o.MatMul.3
  6. MatMul p2o.MatMul.4 2 1 softmax_0.tmp_0 transpose_1.tmp_0_slice_2 p2o.MatMul.5
  7. # 修改前
  8. Gemm p2o.MatMul.14 2 1 p2o.Mul.18 transpose_5.tmp_0 p2o.MatMul.15
  9. Gemm p2o.MatMul.16 2 1 softmax_1.tmp_0 transpose_4.tmp_0_slice_2 p2o.MatMul.17
  10. # 修改后
  11. MatMul p2o.MatMul.14 2 1 p2o.Mul.18 transpose_5.tmp_0 p2o.MatMul.15
  12. MatMul p2o.MatMul.16 2 1 softmax_1.tmp_0 transpose_4.tmp_0_slice_2 p2o.MatMul.17

 d、修改slice操作 (共6个)

  1. # 修改前
  2. Crop p2o.Slice.2 1 1 transpose_1.tmp_0_splitncnn_2 p2o.Slice.3 -23309=0 -23310=0
  3. Crop p2o.Slice.4 1 1 transpose_1.tmp_0_splitncnn_1 p2o.Slice.5 -23309=0 -23310=0
  4. Crop p2o.Slice.6 1 1 transpose_1.tmp_0_splitncnn_0 p2o.Slice.7 -23309=0 -23310=0
  5. # 修改之后
  6. Crop p2o.Slice.2 1 1 transpose_1.tmp_0_splitncnn_2 p2o.Slice.3 -23309=1,0 -23310=1,1 -23311=1,0
  7. Crop p2o.Slice.4 1 1 transpose_1.tmp_0_splitncnn_1 p2o.Slice.5 -23309=1,1 -23310=1,2 -23311=1,0
  8. Crop p2o.Slice.6 1 1 transpose_1.tmp_0_splitncnn_0 p2o.Slice.7 -23309=1,2 -23310=1,3 -23311=1,0
  9. # 修改之前
  10. Crop p2o.Slice.10 1 1 transpose_4.tmp_0_splitncnn_2 p2o.Slice.11 -23309=0 -23310=0
  11. Crop p2o.Slice.12 1 1 transpose_4.tmp_0_splitncnn_1 p2o.Slice.13 -23309=0 -23310=0
  12. Crop p2o.Slice.14 1 1 transpose_4.tmp_0_splitncnn_0 p2o.Slice.15 -23309=0 -23310=0
  13. # 修改之后
  14. Crop p2o.Slice.10 1 1 transpose_4.tmp_0_splitncnn_2 p2o.Slice.11 -23309=1,0 -23310=1,1 -23311=1,0
  15. Crop p2o.Slice.12 1 1 transpose_4.tmp_0_splitncnn_1 p2o.Slice.13 -23309=1,1 -23310=1,2 -23311=1,0
  16. Crop p2o.Slice.14 1 1 transpose_4.tmp_0_splitncnn_0 p2o.Slice.15 -23309=1,2 -23310=1,3 -23311=1,0
  17. # 注释: 09:satrts 10:ends 11:axis (onnx中的satrts ends axis steps)

 e、修改识别头CTC

交换Squeeze 和 Transpose(onnx:图)

.param(图)

交换前:

交换后:

  1. # 交换前
  2. Squeeze p2o.Squeeze.6 1 1 swish_20.tmp_0 squeeze_0.tmp_0 -23300=1,1
  3. Permute p2o.Transpose.8 1 1 squeeze_0.tmp_0 transpose_8.tmp_0 0=1
  4. # 交换后
  5. Permute p2o.Transpose.8 1 1 swish_20.tmp_0 squeeze_0.tmp_0 0=3
  6. Squeeze p2o.Squeeze.6 1 1 squeeze_0.tmp_0 transpose_8.tmp_0 -23303=1,0

f、修改最后一层softmax层

  1. # 修改前
  2. Softmax p2o.Softmax.2 1 1 p2o.Add.129 softmax_2.tmp_0 0=1 1=1
  3. # 修改后
  4. Softmax p2o.Softmax.2 1 1 p2o.Add.129 softmax_2.tmp_0 0=-1 1=1

至此修改完成后,对模型进行测试(模型精度有损失)

g、将split、BinaryOp、sigmoid替换成Swish操作(共7处)(经测试:不替换也没问题,不影响精度)

 (上图206、229 不是paddleocrv3官方模型转换出来,已经进行了网络修改,需要根据自己转换后得到的layer count为准)

 替换后:

  1. 1
  2. # 替换前
  3. Split splitncnn_3 1 2 conv2d_309.tmp_0 conv2d_309.tmp_0_splitncnn_0 conv2d_309.tmp_0_splitncnn_1
  4. BinaryOp p2o.Mul.0 2 1 conv2d_309.tmp_0_splitncnn_1 p2o.helper.constant.42_splitncnn_6 p2o.Mul.1 0=2
  5. Sigmoid p2o.Sigmoid.0 1 1 p2o.Mul.1 p2o.Sigmoid.1
  6. BinaryOp p2o.Mul.2 2 1 conv2d_309.tmp_0_splitncnn_0 p2o.Sigmoid.1 swish_14.tmp_0 0=2
  7. # 替换后
  8. Swish p2o.Mul.0 1 1 conv2d_309.tmp_0 swish_14.tmp_0
  9. 注意: 最初时 layer count 为206层, 我们将4个操作换成了1个操作,减少了(4-13个操作,因此将param文件中的layer count 改为 203
  10. 2
  11. # 替换前
  12. Split splitncnn_4 1 2 conv2d_310.tmp_0 conv2d_310.tmp_0_splitncnn_0 conv2d_310.tmp_0_splitncnn_1
  13. BinaryOp p2o.Mul.3 2 1 conv2d_310.tmp_0_splitncnn_1 p2o.helper.constant.42_splitncnn_5 p2o.Mul.4 0=2
  14. Sigmoid p2o.Sigmoid.2 1 1 p2o.Mul.4 p2o.Sigmoid.3
  15. BinaryOp p2o.Mul.5 2 1 conv2d_310.tmp_0_splitncnn_0 p2o.Sigmoid.3 swish_15.tmp_0 0=2
  16. # 替换后
  17. Swish p2o.Mul.1 1 1 conv2d_310.tmp_0 swish_15.tmp_0
  18. 注意:将4个操作换成了一个操作,减少了(4-13个操作,因此将 layer count 203 改为layer count 200
  19. 7处替换完成后,运行
  20. ncnnoptimize.exe rec_v3-sim-opt.param rec_v3-sim-opt.bin rec_v3-sim-new-opt.param rec_v3-sim-new-opt.bin 0
  21. ncnnoptimize 工具,自动将无用的 MemoryData 删除,并且会自动帮你将最终的 blob count 设置为合适的数量, 所以前面步骤中不需要你自己改 blob count,也不用担心多出来的 MemoryData,都会帮你优化掉

参考链接:

ncnn部署PP-OCRv3之onnx篇 - 知乎 (zhihu.com)

手工优化ncnn模型结构 - 知乎 (zhihu.com)

FeiGeChuanShu/ncnn_paddleocr: Android paddleocr demo infer by ncnn (github.com)
ncnn框架量化工具过程记录笔记 - 知乎 (zhihu.com)

转载请注明出处

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/284920
推荐阅读
相关标签
  

闽ICP备14008679号