使用NCNN的INT8量化方式进行推理

本文详细介绍了使用NCNN框架进行INT8量化的过程,包括编译NCNN、模型量化、验证效果、KL量化原理以及YOLOV4模型的量化推理。量化后模型的权重文件大小减小,但可能导致精度损失。通过分析,揭示了NCNN仅支持对称量化,以及在推理流程中的递归特点。
部署运行你感兴趣的模型镜像

本文以NCNN框架为例,实践量化在推理中的巨大作用,加深对神经网络量化的理解。NCNN当前版本只支对称量化,下面以INT8精度为例介绍NCNN的量化使用方式:

编译NCNN

mkdir build && cd build && cmake ../

进入到build/tools/darknet目录,将来源于darknet的模型文件和权重文件拷贝一份到这里:

wget -c https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.weights

转换过程如下:

./darknet2ncnn ./yolov4-tiny.cfg ./yolov4-tiny.weights

优化:

./ncnnoptimize /home/czl/ncnn/ncnn/build/tools/darknet/ncnn.param /home/czl/ncnn/ncnn/build/tools/darknet/ncnn.bin yolov4-tiny-opt.param yolov4-tiny-opt.bin 0

同时,也可以得到MAC算力信息:

生成的优化过的模型如下:

检测实战,未优化的模型推理结果:

优化后的模型推理结果:

这里的yolov4其实就是yolov4-tiny,程序中是可以选择:

下载量化校准表图片

下载官方给出的1000张ImageNet图像,很多同学没有梯子,下载慢,可以用下这个链接:

imagenet-sample-images-master.zip_yolov4ncnn-深度学习文档类资源-优快云下载ncnn量化int所需的校准图像yolov4ncnn更多下载资源、学习资料请访问优快云下载频道.https://download.youkuaiyun.com/download/weixin_45829462/18704213

图片内容包括:

进入到目录build/tools/quantize,创建images文件夹,之后将imagenet图片全部拷贝到此目录

之后,执行命令 find images/ -type f >imagelist.txt,创建图像文件列表。

之后执行命令:

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

这个过程可以类比acuity tools的模型量化阶段,也需要指定一些量化数据进行量化。

量化模型:

./ncnn2int8 yolov4-tiny-opt.param yolov4-tiny-opt.bin yolov4-tiny-int8.param yolov4-tiny-int8.bin yolov4-tiny.table

生成的yolov4-tiny-int8.bin即为量化后的权重文件,可以看到它的大小是量化前的 四分之一,这就是量化的一个优势,可以减小内存使用量。

验证量化效果:

修改examples/yolov4.cpp代码,使用上新创建的量化模型,同时调整推理参数,使用量化推理:

验证检测效果,主观上能够感受到检测精度方面还是有所损失的,不知道是否和我的操作有关。

对比上面同一张图像的推理效果,可以看到,int8量化会导致推理精度下降。

KL量化原理:

根据流程,貌似ncnn net对象可以得到网络卷积层的个数,然后根据网络推理的结果,得到每个卷积层的输出,之后计算直方图,得到概率信息,和原来的概率信息做kl-diverage散度计算,看信息损失度。根据net对象,可以得到每个卷积层的输入,输出blob,也就是tensor数据,根据这个思路,继续分析代码。

权重要不要进行KL散度量化?

答案是不需要,权重数据是确定性数据,没有不确定性,所以如果是对称量化的话,直接根据其绝对值大小除以量化范围得到scale即可。

在芯原的acuity 和IDE的处理中,也是同样的做法,权重的量化参数不依赖于dataset中的数据集。

而输入输出数据则不一样了,一者我们是用随机的量化图像数据进行仿真推理获取各层数据的,输出数据范围本身具有不确定性,而来量化图像数量也是不确定的。所以,要对量化各层的输出应用KL散度算法,确保产生的参数反量化后,各层的输出和真实值接近。

YOLOV4模型的NCNN导入量化推理

前面测试的是yolov4-tiny模型,通过代码我们知道,可以通过关闭YOLOV4-TINY宏使用大模型的YOLOV4进行推理,下面进行测试:

导入模型

./darknet2ncnn ./yolov4.cfg ./yolov4.weights

网络优化:

./../ncnnoptimize ./ncnn.param ./ncnn.bin yolov4-opt.param yolov4-opt.bin 0

测试:

./yolov4 ~/doudou.png

量化:

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

量化结果:

修改YOLOV4.cpp程序:

./yolov4 ~/doudou.png

yolov4大模型的NCNN量化推理实践成功,从上面量化表的生成过程可以看出,我们对参数的设置并没有按照网络的实际尺寸设置,但是似乎并没有对结果造成太多影响,推理大致还是正确的,原因上可能也是因为,即便设置的图像尺寸不对,但是量化参数产生过程也会根据错误的尺寸生成SCALE参数,这个参数和最有值之间不会偏差太大,毕竟也是参考同样的数据集产生的,所以最终的推理结果精度会受到影响,但是不会导致推理的完全错误。

如何调试NCNN

modify the CMakefileList in top file:

SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")

then you get the execuable files with debug info.

code format with astyle:

quantilize和dequantize执行时序:

for a inference session, the network extract function is the key recurisve funtion to run the network.

NCNN inference invocation is network.extract, it is a rescurisive impl. you can test like this:

and bottom blob is a input tensor for specify netowrk, top blob is the output blob for specify netowork.

NCNN模型文件分析

模型文件的第一行是魔数,第二行的两个数字分别是层数和BLOB(我的理解是tensor)数。

NCNN KL量化分析

理论分析看下面博客

模型量化中的KL散度扫盲_papaofdoudou的博客-优快云博客_kl三度我是万万没想到,最后还是入了算法的坑,虽然和正经数学,信息学相关专业的同学没法比,充其量算是半个爱好者,但是逐渐愿意投入时间思考这方面的问题,对于一个年近不惑的中年人来说,不知道是幸还是不幸。今天扫盲的是KL散度算法,在神经网络前向传递的过程中,KL三度算法用来评估各层量化前后的信息损失。下面一段文字来自于网文摘抄,觉得不错,至少感觉假以时日,自己可以理解,权且贴在这里:K-L散度,全称是Kullback-Leibler Divergence,是一种量化两种概率分布P和Q之间差异的方式,又叫相对https://blog.youkuaiyun.com/tugouxp/article/details/122566431?spm=1001.2014.3001.5502

for (int i = 0; i < image_count; i++){

}

可以分析一下,针对每张图片,找到层的输出tensor,然后将通道的数据除以最大值,之后乘BIN数,目的是得到此数据归属的BIN,之后对对应的BIN加1,表示当前数据归属此BIN,对于多通道的TENSOR,则所有通道共用一个BIN序列和最大值,这说明NCNN不支持PER CHANNEL 量化。

当计算出所有TENSOR的BINS分布后,在将其累加到stat,stat每个输出TENSOR有一个。从这里看,bottom表示输出吧。

由于NCNN仅支持INT8对对称量化,所以对于量化来说,仅仅需要一个缩放系数即可,KL算法的关键就是找到这个缩放系数,通过找到一个介于128和2048的threshold,表示BIN为此值时信息损失最小,据此得到浮点threshold对应值,此值对应量化的127,即可得到缩放系数scale. 如下图所示:

clip_distribution:

这段代码的操作如下图所示:

从图示中可以明显看出变量名命名为clip_distritution的原因了吧。

关于不同BINS下的直方图的生成方式,可以参考如下图:

ceil and floor

NCNN推理的流程特点:

总体上,NCNN的推理是一个递归处理的过程,有点类似于下面的第归程序

#include <stdio.h>
#include <stdlib.h>

void print_array(unsigned char *a, int n)
{
	if(n > 0)
	{
		print_array(a,n-1);
	}

	printf("[%d]: %d.\n", n, a[n]);

	return;
}

int main(void)
{
	int i;
	unsigned char array[10];

	for(i = 0; i < 10; i ++)
		array[i] = i;

    print_array(array, 9);
	return 0;
}


总结:

NCNN目前没有实现非对称量化,只实现了对陈量化一种形式,此信息经过NCNN原作者NIHUI大佬确认如此,并且根据TOOLS目录的实现,只有tools/quantize/ncnn2table.cpp,ncnn2int8.cpp一个量化工具。


结束!

您可能感兴趣的与本文相关的镜像

Yolo-v5

Yolo-v5

Yolo

YOLO(You Only Look Once)是一种流行的物体检测和图像分割模型,由华盛顿大学的Joseph Redmon 和Ali Farhadi 开发。 YOLO 于2015 年推出,因其高速和高精度而广受欢迎

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值