概述
这篇博客记录了对“眨眼两次检测”尝试加速的过程,主要计算是基于CPU的,我的CPU是Intel i5-5200U(u是低压版本,频率比较低,发热量低),之前的眨眼检测单是这一项花费大约70s,使用体验不好,之后我加入python多进程加速处理、租用性能好些的云主机计算(安装环境简洁的系统),使得计算效率大大提高,14s能完成一次后台的眨眼检测并返回结果,另外更新ffmpeg工具,进行django的一些设置,使得部署的系统能通过手机版谷歌浏览器访问,从而可以使用手机上摄像性能更高的摄像头来提高画面的清晰度,再加长检测时长(通过减缓动作的速度来降低误检率),最终使得检测的准确度得到提高
实现
前端修改
前端的实现基本没有改变,只是将媒体记录的时间由2s增加到了3s1
mediaRecorder.start(2000);
1
mediaRecorder.start(3000);
后台实现
多进程
在多进程加速的实现中,使用了python的multiprocessing模块,采用进程池进行分配管理,进程间通过共享内存来与主进程通信,首先,引入如下python包:1
2from multiprocessing import Manager
from multiprocessing import Pool
在主进程中修改检测函数来分配进程1
2
3
4
5
6
7
8
9
10
11
12pool = Pool(processes=24)
dict = Manager().dict()
files = glob.glob(os.path.join('.', "*.jpg"))
files.sort()
step = (len(files) + 23) // 24
jpgs = [files[i:i + step] for i in range(0, len(files), step)]
for f, i in zip(jpgs, range(len(jpgs))):
pool.apply_async(piece_state, (f, i * step, dict))
pool.close()
pool.join()
Pool(processes=24)函数指明进程池中有24个进程,如果需要分配的进程多于24个进程,则靠后的进程需要等待已分配的进程结束执行后释放资源方可继续进行进程分配,这样,相当于把原先的任务等分成了24份,这24个进程并行运算,可利用cpu的多核运算,也能更多的提高该应用的cpu占有率,那么,是不是我们加大进程池中的进程数,或改用python中的Process函数进行更多地分配进程数,就可以获得更好地执行效率了呢?答案是否定的,因为,进行进程分配也是需要消耗资源与时间的,而时间是我们提高效率的指标,我们需要的是降低单位图片的处理速度,我进行了多组尝试,最终确定了与我们这个应用相关的这种分配数量,可以看下运行结果
这里统计时间,我用的是time.clock()函数,它能只统计单个进程的执行时间
我用python自带的time.time()来统计应用总的运行时间(它代表应用从开始计时开始,到运行结束总的时间,是系统实际的运行时间,也就是实际应用场景的运行时间,包含了其他程序的运行时间),一般来说,我们系统中运行的程序越少,time.time()统计的时间就越接近我们这个应用的运行时间,该应用的cpu占有率也会更高,所以我选择将应用部署到相对简洁的云主机上,只部署了这一个应用1
dict = Manager().dict()
通过Manager().dict()可以使用进程间通信机制–共享内存,这样,每个进程完成的计算任务,最后可由主进程统一处理1
2files = glob.glob(os.path.join('.', "*.jpg"))
files.sort()
文件名读取后排序,是源于在将应用从windows10部署到Ubuntu上时,出现了乱序现象,控制台输出files后,发现windows10下python读取的文件是排好序的,Ubuntu下没有排序,为保持一致,需要进行排序1
2step = (len(files) + 23) // 24
jpgs = [files[i:i + step] for i in range(0, len(files), step)]
这段代码是将我们的图片处理任务等分成24个片段1
2
3
4for f, i in zip(jpgs, range(len(jpgs))):
pool.apply_async(piece_state, (f, i * step, dict))
pool.close()
pool.join()
这一段通过pool.apply_async(piece_state, (f, i step, dict))将每个进程的执行函数piece_state和参数(f, i step, dict)传递给进程池中的进程,再通过pool.join()让主进程等待所有子进程结束计算任务,以便主进程进行之后的数据整合
其他
云主机
我试了vultr的两台云主机,在新加坡的一台云主机,跑这个应用,检测一次眨眼动作需要19s;另一台跑这个应用进行一次眨眼检测需要14s,因为是云主机提供的虚拟服务,我无法查看到cpu的具体型号,不过看到它3级数据缓存还是很大的,能获得较好的运算能力,还是需要多方面配合,可通过该博客和这篇博客进行了解,根据后篇博客的描述,在这个服务器上,’cpu cores’ 为4,physical id 有一个,core id有4个,siblings的值为4,总共有4个processor。也就是说,这里的cpu为一个封装的处理器,有4个核,每个核上有一个逻辑处理器,当然,在不加虚拟化技术的前提下可以这样理解
ffmpeg
ffmpeg是一个多媒体框架,可完成多媒体文件的编/解码,转码,过滤、播放,我们在此处通过它将webm文件转换为mp4文件,再通过opencv获取帧数据,在将应用从本机(windows10)上转移到云主机(Ubuntu)时,曾出现过,对同样的视频文件获得不一样的检测数据,通过层层排查,发现除了windows与Ubuntu的一点文件排序的区别外,windows下的ffmpeg与Ubuntu下的ffmpeg版本也不一样,导致转码后出现了较大的不同,不过其官网对各个系统平台都有支持,文档比较完善,浏览官网可以找到统一的版本