Toybrick

人工智能开发系列(5) MTCNN开发与实现

395876134

版主

积分
1099
发表于 2019-4-1 17:14:02    查看: 86828|回复: 19 | [复制链接]    打印 | 显示全部楼层
本帖最后由 395876134 于 2019-8-9 16:25 编辑


本教程视频直播回看:


本教程基于RK3399pro开发板,使用fedora 28系统,另需usb鼠标、usb键盘、hdmi显示器、usb摄像头、串口线连接开发板
一. 搭建开发环境
安装rknn-toolkit及其依赖库,[url=http://t.rock-chips.com/wiki.php?mod=view&id=36]按照wiki教程安装环境

二、代码路径
原始代码:https://github.com/DuinoDu/mtcnn.git

本教程代码:https://github.com/chenshiqin/mtcnn.git

三、MTCNN算法流程
1、构建图像金字塔首先将图像进行不同尺度的变换,构建图像金字塔,以适应不同大小的人脸的进行检测。
2、P-Net:全称为ProposalNetwork,通过浅层的CNN快速生成候选窗口,该网络全部由卷积层实现,获取到候选人脸窗和人脸窗的回归向量 (bounding box regression vectors),基于人脸窗的回归向量对人脸窗进行校正,然后对所有人脸窗进行NMS(非极大值抑制),合并高度重叠的人脸窗。
3、R-Net:全称为Refine Network,其基本的构造是一个卷积神经网络,相对于第一层的P-Net来说,增加了一个全连接层,因此对于输入数据的筛选会更加严格。在图片经过P-Net后,会留下许多预测窗口,我们将所有的预测窗口送入R-Net,这个网络会滤除大量效果比较差的候选框,最后对选定的候选框进行校正和NMS,进一步优化预测结果
4、O-Net:全称为OutputNetwork,基本结构是一个较为复杂的卷积神经网络,相对于R-Net来说多了一个卷积层。O-Net的效果与R-Net的区别在于这一层结构会通过更多的监督来识别面部的区域,而且会对人的面部特征点进行回归,最终输出五个人脸面部特征点。
四、运用的主要公式
1、人脸检测这就是一个分类任务,使用交叉熵损失函数即可:

2、Bounding box regression这是一个回归问题,使用平方和损失函数:
3、人脸特征点定位这也是一个回归问题,目标是5个特征点与标定好的数据的平方和损失:
4、多任务训练不是每个sample都要使用这三种损失函数的,比如对于背景只需要计算交叉熵损失,不需要计算别的损失,这样就需要引入一个指示值指示样本是否需要计算某一项损失。最终的训练目标函数是:

5、非极大抑制NMS
五、问题点介绍
1、MTCNN算法可以接受任意尺度的图片吗?为什么需要金字塔转换?
因为第一阶段的P-NET是一个全卷积网络(Fully Convolutional Networks)
卷积、池化、非线性激活都是一些可以接受任意尺度矩阵的运算,而全连接运算是需要规定输入。我们的P-net网络结构没有全连接层,因此图片尺度可以是任意的;
由于图片中的人脸的尺度有大有小,目标检测本质上来说是目标区域内特征与模板权重的点乘操作;那么如果模板尺度与目标尺度匹配,自然会有很高的检测效果。
2、设置合适的最小人脸尺寸和缩放因子为什么可以优化计算效率?
minsize是指你认为图片中需要识别的人脸的最小尺寸(单位:px)。factor是指每次对边缩放的倍数
我们已经知道,第一阶段会多次缩放原图得到图片金字塔,目的是为了让缩放后图片中的人脸与P-NET训练时候的图片尺度(12px * 12px)接近。怎么实现呢?先把原图等比缩放`12/minsize`,再按缩放因子`factor`(例如0.5)用上一次的缩放结果不断缩放,直至最短边接近12。根据上述算法,minsize越大,生成的“金字塔”层数越少,resize和pnet的计算量越小。
3、为什么缩放因子factor官方选择0.709?
图片金字塔缩放时,默认把宽,高都变为原来的1/2,缩放后面积变为原来的1/4;如果认为1/4的缩放幅度太大,你会怎么办?把面积缩放为原来的1/2。对的,这是很直观的想法,所以这里的缩放因子0.709 ≈ sqrt(2)/2,这样宽高变为原来的sqrt(2)/2,面积就变为原来的1/2。
4、 为什么把图片输入模型的时候要对每个像素做(x – 127.5)/128的操作?
归一化操作,加快收敛速度。由于图片每个像素点上是[0, 255]的数,都是非负数,对每个像素点做(x – 127.5)/128,可以把[0,255]映射为(-1, 1)。有正有负的输入,收敛速度更快。训练时候输入的图片需要先做这样的预处理,推断的时候也需要做这样的预处理才行。
5、有什么优化方案?
如图所示,三个模型中,P-NET所占用的时间最多,MTCNN的推断是CPU密集型运算,如果图片超过1080,生成图像金字塔的过程可能是流程中最耗时的过程。因为金字塔结构,第一阶段需要计算很多尺度的图片。但超过1080的图片中,你需要识别的最小人脸真的需要12*12吗?minsize是不是也变大了?另外,如果你事先已经知道图片中人脸的大小,是不是可以调整一下minsize?结合你的实践场景可以思考下。
以耗时最大的第一阶段为主要优化的关键点:
①、第一阶段受输入图片尺寸影响较大,可以让minsize随图片尺寸而改变,大图用大minsize
②、图片金字塔的生成过程,对上一次的resize结果进行resize而不是对全图resize
③、网络越复杂,GPU相比CPU的提升越明显。MTCNN的三阶段都是很弱的网络,GPU的提升不太大。另外,MTCNN的第一阶段,图像金字塔会反反复复地很多次调用一个很浅层的P-NET网络,导致数据会反反复复地从内存COPY到显存,又从显存COPY到内存,而这个复制操作消耗很大,甚至比计算本身更耗时,可以考虑将第一个阶段用其它算法实现。
六、结果展示


七、通过RKNN转换时注意点
1、 rknn.config(channel_mean_value=‘127.5 127.5 127.5 128’, reorder_channel=‘2 1 0’,quantized_dtype='dynamic_fixed_point-8')
①、127.5 127.5 127.5 128是将rgb的数据归一化为[-1,1],此时通过rknn进行归一化处理,所以数据进入inference前不需要手动做归一化处理,dataset.txt里的图像也不需要归一化处理
②、如果rknn.config未做归一化处理,需要在inference前将数据进行归一化处理( im_data =(img-127.5)*0.0078125 ),且需要将模型中需要的不同尺寸的图片进行归一化处理,并保存。
2、 rknn.build(do_quantization=True, dataset='./dataset.txt')
①、do_quantization=True,是rknn进行量化处理,实际运行时速度更快;如果设置为false,几乎不损失精度,但是速度偏慢。
②、进行量化处理的时候, dataset.txt最好多点相片,覆盖模型可能的输入类型。
3、 rknn.inference(inputs=[im_data], data_type=‘uint8’,data_format='nchw')
①、data_type默认为uint8,如果此时传入的数据是float类型,结果反而更差
②、 caffe 数据类型是data_format=‘nchw’,channel first,其他的模型一般是’nhwc’,channel last
4、因为目前rknn不支持不固定维度的模型(不能在运行过程中改变模型维度),而pnet网络需要构建图片金字塔,所以根据图片大小,构建了9个P-Net的rknn;R-Net和O-Net中需要将前一个模型的数据导入,rknn 目前不支持多图片输入,所以目前是循环输入,将结果拼接到数组中。
八、项目展望
1、深入研究RKNN函数对模型精度的影响
2、优化代码:通过rga进行图像转换;并行运算,加快运行速度。(新的github代码已经使用多线程处理,解决卡顿的问题)
3、优化模型:减少图片进出npu次数(新的github代码已经使用图像拼接,加快速度)。
①、使用https://github.com/blaueck/tf-mtcnn 将三个模型融合在一起,减少与npu的交互时间。
4、根据对比前后图片相似度,解决框图会闪的问题(详见github代码)。
5、提高nms门限,删除rnet(详见github代码)



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

tof3d

中级会员

积分
210
发表于 2019-4-1 17:17:55 | 显示全部楼层
奶斯奶斯
回复

使用道具 举报

tof3d

中级会员

积分
210
发表于 2019-4-1 17:22:08 | 显示全部楼层
方便透露一下,你们的检测的速度吗,最小脸设置多大呢,多大图,你们测试的原作者张凯鹏的caffe 模型,matcaffe模型吗
回复

使用道具 举报

395876134

版主

积分
1099
 楼主| 发表于 2019-4-2 14:03:01 | 显示全部楼层
最小人脸设置为20*20,是caffe 模型。你可以看下源码!
回复

使用道具 举报

chuyee

中级会员

积分
352
发表于 2019-4-3 07:21:24 | 显示全部楼层
I can only get 3FPS with the github code. How to make it realtime?
回复

使用道具 举报

tof3d

中级会员

积分
210
发表于 2019-4-3 09:29:40 | 显示全部楼层
你们的模型是自己训练的吗,还是网上链接,可以给出地址吗
回复

使用道具 举报

395876134

版主

积分
1099
 楼主| 发表于 2019-4-3 10:37:19 | 显示全部楼层
tof3d 发表于 2019-4-3 09:29
你们的模型是自己训练的吗,还是网上链接,可以给出地址吗

开头就有给出源码地址了
回复

使用道具 举报

395876134

版主

积分
1099
 楼主| 发表于 2019-4-24 08:38:41 | 显示全部楼层
chuyee 发表于 2019-4-3 07:21
I can only get 3FPS with the github code. How to make it realtime?

It's just a demo, and you can optimize it.
回复

使用道具 举报

yaowei

中级会员

积分
375
发表于 2019-6-17 13:38:41 | 显示全部楼层
本帖最后由 yaowei 于 2019-6-17 13:42 编辑

我看repo里量化类型为什么选择的dynamic_fixed_point-8呢,一般选择和默认选择都是asymmetric_quantized-u8的吧
回复

使用道具 举报

395876134

版主

积分
1099
 楼主| 发表于 2019-6-19 09:13:36 | 显示全部楼层
yaowei 发表于 2019-6-17 13:38
我看repo里量化类型为什么选择的dynamic_fixed_point-8呢,一般选择和默认选择都是asymmetric_quantized-u8 ...

你可以试下,改成asymmetric_quantized-u8 效果如何
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

产品中心 购买渠道 开源社区 Wiki教程 资料下载 关于Toybrick


快速回复 返回顶部 返回列表