此帖记录一下在视觉感知项目中的一些曲折经历。
机子是NVIDIA Jetson AGX,具体型号未知。
单独启用一个ros结点做目标跟踪,因为deepsort多了一个网络,延时可能比较高,遂用了更简单的sort。
第一次在agx上跑了一下,发现延迟非常高,纯sort的耗时在30ms以上,有些帧甚至达到60+ms,这肯定不正常啊。
首先分析各模块耗时:
主机 | agx | |
---|---|---|
kf_predict | 0.46 | 4.04 |
assignment | 0.15 | 1.27 |
kf_update | 0.24 | 30.05 |
pop | 0.11 | 1.89 |
note: 以上结果统计的不够严谨,但是大体能表征一下趋势。
对新出现的检测框我忘了统计了,就是一个初始化的时间,应该不是sort时间长的主要原因(次要原因应该都称不上)。
通过对比,发现agx的耗时正常来说应该是我用的主机的10倍左右,但是kf_update时间异常,查了一下self.kf这个类,发现都是用的filterpy这个库,遂点进去查看。
from filterpy.kalman import KalmanFilter
发现主机和agx上的kalman类文件竟然不完全一样,推测可能是python版本的问题导致库不同(主机上是py3.8,agx上是py3.6)。
注意观察py3.6上的库多了一部分计算,尝试删去这部分之后kf_update部分节约了十几ms,后来我直接把py3.8的类复制到agx上调用,kf_update部分直接从30.05 -> 11.6ms,这只是第一步。
虽然速度有了大大提升,但是有时仍然会因为cpu性能或者其他原因导致每帧延迟掉到15fps以下(这是/neuvition的发布频率),虽然我设置了接收器消息队列长度为1,但仍然不能及时接收到最新消息,导致图像持续滞后(不知道为啥,希望大佬指教一番),这次的主要原因仍然是kf_update。
我又分析了一下kf_update内部的计算过程,除了一次求逆外都是矩阵乘法,按理说不应该这么慢。重点来了,问题恰恰出在了求逆矩阵上,源码里直接用 np.linalg.inv() 求逆矩阵,在一次KalmanFilter.update 中占了足足三分之一的时间(罪大恶极)。
找到问题就好解决了,想到deepsort中KalmanFilter.update用了cholesky矩阵分解加快求解,把 S^T K^T =(PHT)T 通过求S的逆,变成了AX=B的问题,可以显著提高速度。
将
self.SI = self.inv(self.S)
self.K = dot(PHT, self.SI)
改为
chol_factor, lower = scipy.linalg.cho_factor(
self.S, lower=True, check_finite=False)
self.K = scipy.linalg.cho_solve(
(chol_factor, lower), PHT.T,
check_finite=False).T
单个track的kf_update不便于比较,这里我直接放整个sort的结果:
速度有了质的飞跃,这就是第二步。
该说不说,deepsort相比于sort在KalmanFilter上有了很大改进,自带一个类文件,不用担心因为python自带的filterpy.kalman库版本不一样导致的效率不同,同时逆运算通过trick获得了极大的速度提升。
经过前两步的加速,sort结点已经完全达到了使用要求,于是没有采用其他加速方法,设想中可以再利用numba来加速kalmanfilter的矩阵运算或者是sort中的iou计算。
此外,若sort中需要夹杂其他任务,如车牌检测,则最好用多线程并行处理,以此保证sort的速度,详情可参见我的另一篇博客python threading多线程实例。