ncnn 优化量化

问题:发现推理时间过长,需要优化

当前正在做人脸检测部署,发现检测速度有点吓人,以下监测的时间

gpu:

cpu:

gpu推理大概整体时间200多毫秒,cpu推理时间300多毫秒,这里暂时没去考虑内存了。只考虑效率。

用的insightface的det_10g 和w600k_r50模型,一个用于检测人脸框,一个用于对齐人脸特征。

其实主要的时间集中在了检测框步长8的步骤。

现在我的主要思路是基于ncnn的量化来进行优化,看看是否满足效果。

解决方案:量化

那就看看ncnn如何量化的,官方文档:ncnn/docs/how-to-use-and-FAQ/quantized-int8-inference.md at master · Tencent/ncnn · GitHub

发现了如下步骤,我也编译了一个window版本

https://download.csdn.net/download/p731heminyang/89216707?spm=1001.2014.3001.5503

版本是:ncnn-20240410

1、优化模型:

使用ncnnoptimize 工具,进行优化,至于工具如何来,可以看具体编译教程ncnn/docs/how-to-build/how-to-build.md at master · Tencent/ncnn · GitHub

./ncnnoptimize mobilenet.param mobilenet.bin mobilenet-opt.param mobilenet-opt.bin 0

后面的数字:0表示fp32,1表示fp16,还有65535的 我看了下代码,其实也是代表1

2、生成量化表【静态】

如果需要静态量化,需要生成量化表

这里需要准备图片数据文件,我这边用的voc的数据集

图片格式:一行一个就行了

把所有的图片路径保存到文档里面

./ncnn2table mobilenet-opt.param mobilenet-opt.bin imagelist.txt mobilenet.table mean=[104,117,123] norm=[0.017,0.017,0.017] shape=[224,224,3] pixel=BGR thread=8 method=kl

这边mean和norm是代码里知道的,用于做图片的归一化处理,这个在代码的前置处理事必须得,看看代码就知道是多少了

我的是mean=[127.5,127.5,127.5] norm=[0.0078125,0.0078125,0.0078125]

shape是自己的入参是多少,

  • shape 是模型的 blob 形状,[w,h] 或 [w,h,c] ,我这边是图片大小[640,640,3]

pixel 是模型的像素格式,图像像素在转换之前会转换为这种类型Extractor::input()

一般是BGR和RGB,我这边是转换了RGB,一般opencv用的就是BGR,正常使用的是RGB

  • method 是训练后量化算法,目前支持 kl 、aciq和eq

以下是我的

./ncnn2table det_10g_sim.param det_10g_sim.bin imagelist.txt det_10g_sim.table mean=[127.5,127.5,127.5] norm=[0.0078125,0.0078125,0.0078125] shape=[640,640,3] pixel=GRB thread=8 method=kl

但是为嘛 ncnn2table  量化老不成功,后面通过定位代码,不知道是不是新版本的问题,在加载模型初始化之后,权重就会被置为空,而量化还会去获取权重,所以导致无法获取到量化表,没有深入去看了, 这里做了一个处理,就是清空了之后再把权重赋值回去。

在net.cpp里面修改,在 int cret = layer->create_pipeline(opt1);前后保存权重信息

修改如下

if (layer->type == "Convolution"){//test const ncnn::Convolution *p = (const ncnn::Convolution *)layer;weight_data1 = p->weight_data.clone();//fprintf(stderr,"load 00001addr[%ld] end Convolution[%s] data:[%ld] weight_data:[%d,%d,%d]\n",p,p->name.c_str(), p->weight_data.data,p->weight_data.w,p->weight_data.h,p->weight_data.c);}if (layer->type == "ConvolutionDepthWise"){const ncnn::ConvolutionDepthWise* p = (const ncnn::ConvolutionDepthWise*)layer;weight_data1 = p->weight_data.clone();}if (layer->type == "InnerProduct"){const ncnn::InnerProduct* p = (const ncnn::InnerProduct*)layer;weight_data1 = p->weight_data.clone();}int cret = layer->create_pipeline(opt1);if (layer->type == "Convolution"){//testncnn::Convolution *p = ( ncnn::Convolution *)layer;p->weight_data = weight_data1;// fprintf(stderr,"load 00002addr[%ld] end Convolution[%s] data:[%ld] weight_data:[%d,%d,%d]\n",p,p->name.c_str(), p->weight_data.data,p->weight_data.w,p->weight_data.h,p->weight_data.c);}if (layer->type == "ConvolutionDepthWise"){ncnn::ConvolutionDepthWise* p = ( ncnn::ConvolutionDepthWise*)layer;p->weight_data = weight_data1;}if (layer->type == "InnerProduct"){ncnn::InnerProduct* p = ( ncnn::InnerProduct*)layer;p->weight_data = weight_data1;}

编译之后继续跑,顺利量化

可以看到当前目录下,出现了det_10g_sim.table 那么就是成功了

如果有多重输入的,官方也提到了,就是是输入的可以保护多个,用逗号隔开就行。如下

./ncnn2table mobilenet-opt.param mobilenet-opt.bin imagelist-bgr.txt,imagelist-depth.txt mobilenet.table mean=[104,117,123],[128] norm=[0.017,0.017,0.017],[0.0078125] shape=[224,224,3],[224,224,1] pixel=BGR,GRAY thread=8 method=kl

3、量化【静态量化】

得到量化表之后可以可以进行量化,拿到上面的向量表det_10g_sim.table

我的ncnn2int8.ex 目录已经添加到环境变量,所以可以直接执行,如果没添加那么带上全路径,并且exe不能省略

ncnn2int8 det_10g_sim.param det_10g_sim.bin det_10g_sim_int8.param det_10g_sim_int8.bin det_10g_sim.table

生成了int8的量化包

测试后发现了新问题:

测试验证发现最终输出的形状不对。比如输出80x80 变成了78x78

这是怎么回事,通过定位代码,发现量化的代码没有修改了,比如卷积算子,type大于6的都没管了,所以后面添加的一些填充啥的都没了,后面修改代码也没解决。

后面对比量化后的param发现,其实基本都是在每个参数后面添加了一个8=多少,当成一个量化系数,量化后结构都没有变化,那不是意味着可以通过在原始的param上面对比量化的param,看看哪些有8=的参数就行,增加了这种想法,后面发现手工太麻烦,就做了一个工具来自动识别添加。

思路:就是识别每一行是否有8=的参数,有的话,就追加在原始param对应的行后面,经过测试发现成功了,测试也没问题,权重参数文件不需要动,选择量化后的就行。

测试验证功能没问题

不过怪事,经过测试发现速度没有提升反而有点增加,有时候测试速度反而增加了,权重大小倒是由16M到了4M,所以减少了内存,估计此模型已经难以通过此方式提升速度了。

额,感觉没达到预期,只能看看小模型或者识别框架替代了

4、量化【动态】

直接不通过量化表进行量化(测试了下,代码里面就不支持),官方说支持,但是最新代码已经限制了参数小于此参数就报错,具体代码 ncnn2int8.cpp 下面

优化修改后:

就可以了

./ncnn2int8 rnn-model.param rnn-model.bin rnn-model-int8.param rnn-model-int8.bin

虽然没有解决我的问题,但是量化已经完成了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle实践|内置函数之字符串函数

📫 作者简介:「六月暴雪飞梨花」,专注于研究Java,就职于科技型公司后端工程师 🏆 近期荣誉:华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 🔥 三连支持:欢迎 ❤️关注…

C++模板——函数模板和类模板

目录 泛型编程 函数模板 函数模板概念 函数模板的定义和语法 函数模板的工作原理 函数模板的实例化 隐式实例化 显示实例化 函数模板的匹配原则 类模板 类模板的定义格式 类模板的实例化 泛型编程 什么是泛型编程? 泛型编程(Generic Pr…

【Linux-并发与竞争】

Linux-并发与竞争 ■ 原子操作■ 原子操作简介■ 原子整形操作 API 函数■ 原子位操作 API 函数■ 示例一:原子操作实验,使用原子变量来实现对实现设备的互斥访问 ■ 自旋锁■ 自旋锁 API 函数■ 死锁■ 最好的解决死锁方法就是获取锁之前关闭本地中断&a…

LeetCode 124 —— 二叉树中的最大路径和

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 二叉树的问题首先我们要想想是否能用递归来解决,本题也不例外,而递归的关键是找到子问题。 我们首先来看看一棵最简单的树,也就是示例 1。这样的一棵树总共有六条路径&#xf…

docker如何拉取nginx最新镜像并运行

要拉取Docker Hub上的最新Nginx镜像,您可以使用以下命令: docker pull nginx 这个命令会从Docker Hub下载最新版本的Nginx镜像。如果您想要拉取特定版本的Nginx镜像,可以指定版本号,例如: docker pull nginx:1.18.0 拉…

详细分析tcping的基本知识以及用法

目录 前言1. 安装配置2. 基本知识3. Demo 前言 针对ping的基本知识推荐阅读:详细分析ping的基本知识以及常见网络故障的诊断(图文解析) 1. 安装配置 针对Window的下载如下: 安装路径:tcping官网 下载tcping.exe&a…

《微服务王国的守护者:Spring Cloud Dubbo的奇幻冒险》

5. 经典问题与解决方案 5.3 服务追踪与链路监控 在微服务架构的广袤宇宙中,服务间的调用关系错综复杂,如同一张庞大的星系网络。当一个请求穿越这个星系,经过多个服务节点时,如何追踪它的路径,如何监控整个链路的健康…

VUE3 学习笔记(3):VUE模板理念、属性绑定、条件渲染、列表渲染

准备 1.清空不必要的项目文件 项目/src/assets/ 目录文件清空 项目/src/components/ 目录文件清空 删除main.js 的css引用 App.vue 代码如下 <template> </template> <script>//注意这里默认有一个setup 去掉 </script> 运行一下无错误提示就可以了…

Cohere继Command-R+之后发布大模型Aya-23,性能超越 Gemma、Mistral 等,支持中文

前言 近年来&#xff0c;多语言大模型&#xff08;MLLM&#xff09;发展迅速&#xff0c;但大多数模型的性能依然存在显著差距&#xff0c;尤其是在非英语语言方面表现不佳。为了推动多语言自然语言处理技术的发展&#xff0c;Cohere团队发布了新的多语言指令微调模型家族——…

机器学习预测-CNN手写字识别

介绍 这段代码是使用PyTorch实现的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于在MNIST数据集上进行图像分类。让我一步步解释&#xff1a; 导入库&#xff1a;代码导入了必要的库&#xff0c;包括PyTorch&#xff08;torch&#xff09;、神经网络模块&#xff0…

shell脚本实战--批量修改文件名

字符串截取 先来了解一下shell字符串相关操作的变量 # 从开头删除匹配最短 ## 从开头删除匹配最长 % 从结尾削除匹配最短 %% 从结尾删除匹配最长#指定字符内容截取 a*c 匹配开头为a&#xff0c;中间任意个字符&#xff0c;结尾为c的字符串 a*C 匹配…

Java—集合Collection(一)

Java—集合Collection&#xff08;一&#xff09; 一、Collection集合1、方法add、addAll2、声明集合特别注意1&#xff1a;添加对象时需要创建对象类 3、总结4、判断方法4.1、总结 5、删除6、总结7、集合的其他方法8、所有代码演练 存放单个数据内容&#xff0c;声明一个变量&…

netcat一键开始瑞士军刀模式(KALI工具系列六)

目录 1、KALI LINUX简介 2、netcat工具简介 3、在KALI中使用netcat 3.1 目标主机IP&#xff08;win&#xff09; 3.2 KALI的IP 4、命令示例 4.1 测试某IP的端口是否打开 4.2 TCP扫描 4.3 UDP扫描 4.4 端口刺探 4.5 直接扫描 5、即时通信 5.1 单击对话互联 5.2 传…

新能源锂电池行业创业的财富方案,锂电池回收高阶课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89292234 更多资源下载&#xff1a;关注我。 实战攻略 12年锂电池回收行业经验与坑全收录 课程内容&#xff1a; 001-课程介绍.mp4 002-锂电池的全种类认识.mp4 003-废品锂电池到级片粉末价值估算,mp…

Go微服务: Http服务注册在Consul的示例(非Go-Micro)

概述 现在&#xff0c;我们使用consul客户端的api来把Http服务注册到consul上&#xff0c;非Go-Micro的形式其实&#xff0c;consul官方提供了对应的接口调用来实现&#xff0c;golang中的consul/api包对其进行了封装我们使用consul/api来进行展示 目录结构 gitee.com/go-mi…

设计模式7——建造者模式

写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用&#xff0c;主要是下面的UML图可以起到大作用&#xff0c;在你学习过一遍以后可能会遗忘&#xff0c;忘记了不要紧&#xff0c;只要看一眼UML图就能想起来了。同时也请大家多多指教。 建造者模式&#xff08;Builde…

VMware ESXi 7.0 U3q 发布 - 领先的裸机 Hypervisor

VMware ESXi 7.0 U3q 发布 - 领先的裸机 Hypervisor VMware ESXi 7.0 Update 3 Standard & All Custom Image for ESXi 7.0U3 Install CD 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-7-u3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出…

3小时-入门短视频创作:短视频创作入门必修(15节视频课)

课程目录 1、先导课.mp4 2、建立视听思维.mp4 3、口语化.mp4 4、具象化.mp4 5、建立选题思维.mp4 6、2个小白好上手的选题技巧.mp4 7、建立开场思维.mp4 8、3个口播视频方能开场套路.mp4 9、建立脚本结构思维.mp4 10、爆款口指的3大结构.mp4 11、建立标题思维.mp4 …

https为何安全?

HTTPS&#xff08;超文本传输安全协议&#xff09;是一种用于安全通信的网络协议&#xff0c;它在HTTP协议的基础上通过SSL/TLS&#xff08;安全套接层/传输层安全&#xff09;协议来加密数据&#xff0c;以保护网络数据的传输安全。 TLS/SSL 基础概念 概念源自百度百科&…

内存的基本知识与连续分配管理

目录 一. 内存的基础知识1.1. 什么是内存1.2 指令的工作原理1.2.1 装入的三种方式 - 绝对装入1.2.2 可重定位装入1.2.3 动态重定位装入1.3 从写程序到程序运行 二. 基本内存管理的概念三. 覆盖与交换3.1 覆盖技术3.2 交换技术 四. 连续分配管理方式4.1 单一连续分配4.2 固定分区…