问题:发现推理时间过长,需要优化
当前正在做人脸检测部署,发现检测速度有点吓人,以下监测的时间
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
虽然没有解决我的问题,但是量化已经完成了