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,一经查实,立即删除!

相关文章

「TypeScript系列」TypeScript 对象及对象的使用场景

文章目录 一、TypeScript 对象1. 对象字面量2. 类实例化3. 使用接口定义对象形状4. 使用类型别名定义对象类型5. 使用工厂函数创建对象 二、TypeScript 对象属性及方法1. 对象属性2. 对象方法3. 访问器和修改器(Getters 和 Setters) 三、TypeScript 对象…

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

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

Jenkins - Pipeline try catch

Jenkins - Pipeline try catch 引言try catch 引言 Jenkins pipeline 脚本,有时因某些异常而中断执行,导致整个 pipeline job 都失败。为了整个 Job 能继续运行,我们需要处理某些异常。 try catch 当在 Jenkins Pipeline 中使用 try-catch…

基于redis的分布式锁解决token续期冲突的问题

场景:用户登录状态存储到redis,2小时后过期。在过期前的30分钟如果用户进行操作,则对登录状态进行续期,续期后仍有2小时时限,并更换新的token。在微服务模式下,如果两个服务同时请求续期,则会返…

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

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

【代码随想录37期】Day18 找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树

找树左下角的值 class Solution { public:int findBottomLeftValue(TreeNode *root) {TreeNode *node;queue<TreeNode *> q;q.push(root);while (!q.empty()) {node q.front(); q.pop();if (node->right) q.push(node->right);if (node->left) q.push(node-&…

机械臂学习笔记

目录 python 像素坐标系转空间坐标系 基于yolov7得并联机械臂实时抓取 KINOVA Gen3 lite机械臂上 UR5机械臂仿真平台 勤牛智能 Mirobot六自由度机械臂 Python SDK 调用示例 6自由度 c的 彭志辉 开源的&#xff1a; 搜索&#xff1a;机械臂 language:Python python 像…

【Linux-并发与竞争】

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

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

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

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

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

JQuery从入门到精通2万字面试题

目录 解释jQuery库中的$()函数是什么? 如何使用jQuery选择页面上的所有 元素?

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

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

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

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

AIGC行业现在适合进入吗?

AIGC行业现在适合进入吗 人工智能生成内容&#xff08;AIGC&#xff0c;Artificial Intelligence Generated Content&#xff09;行业近年来迅速崛起&#xff0c;尤其在自然语言处理、图像生成和内容创作等方面取得了显著的进展。要判断当前是否适合进入AIGC行业&#xff0c;需…

C++ 实现深度优先搜索(DFS)的简单示例代码

C 实现深度优先搜索&#xff08;DFS&#xff09;的简单示例代码 #include <iostream> #include <vector> #include <stack>/**C 实现深度优先搜索&#xff08;DFS&#xff09;的简单示例代码。这段代码演示了如何在一个无向图中使用 DFS 进行遍历。 首先&am…

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

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

Android14音频进阶之dump各阶段音频数据<Tee Sink方案>(七十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP…

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

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

假设有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?

假设有n个台阶&#xff0c;一次只能上1个台阶或2个台阶&#xff0c;请问走到第n个台阶有几种走法&#xff1f; 为方便读者理解题意&#xff0c;这里举例说明如下 &#xff0c;假如有3个台阶&#xff0c;那么总计就有三种走法&#xff1a;第一种为每次上1个台阶&#xff0c;上3…

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

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