• CVPR 2022 | ST-MR:“来自人类的恶意”


    这是一篇CVPR 2022 关于行人轨迹预测的文章,之所以取这个题目,是因为还没想好。
    论文链接:Graph-based Spatial Transformer with Memory Replay for Multi-future
    Pedestrian Trajectory Prediction

    代码链接: ST_MR model
    这篇文章比较晦涩难懂,读者如果看过原论文和代码,再来看看博客也许会给你提供新的思路。

    一、数据是怎样被处理的?

    在完整的写好这篇博客之前,,一定要首先观察数据。ST-MR模型在VIRAT/ActEV数据集上训练,在The Forking Paths Dataset数据集上测试。网上对VIRAT/ActEV数据集的中文介绍比较少,但是看过论文代码的朋友可能注意到,在数据处理这一步中,我们是针对一个场景一个场景进行处理的。举例来说,在vodeo_1这段视频中,应该有很多帧,每帧又会有许多人,每位行人又会有不同的运动轨迹,每条不同的运动轨迹之间又会有不同的交互。那模型怎么做才能够把数据进行分门别类的处理呢?实际在Social-STGCNN有说,但还是有些不太一样。一样的地方是,假设vedio_1这段视频中有20651帧,那我们需要将这么多的帧数赋一个帧ID。举例来说,第0帧的帧ID是0,第10帧的帧ID是1,第20帧的帧ID是2,…,第20650帧的帧ID是1433;你可能会疑惑说,第20651的帧ID应该是2065才对啊,怎么会是1433呢?这是因为在所给数据中帧数并不是连续间隔的,希望读者不会因此困惑。有了帧ID后,就要找出帧ID下所有的行人轨迹,注意,这里所有的行人的轨迹是可重复的。什么意思呢?假设在第0帧下有1个人,这个人可不是只存在于第0帧下,第10帧(帧ID=1)下也可以存在这位行人。OK,我想你明白我在说什么。总结来说,我们现在将数据处理成了什么模样呢?我们给每帧标注了对应的ID,并且找到了该帧下的所有行人。

    紧接着要做什么事呢?就是把上述处理的数据进一步处理成mini-batch,并给相应的mini-batch一个ID,我把它叫做mini-batch ID。那怎么处理成mini-batch呢?在帧ID上,我们以长度20为标准,步长为1进行Sample,这样长度为1433的帧ID就被处理成了1415个mini-batch。处理成mini-batch后,我们就要找出该mini-batch ID下有多少个行人,举例来说,mini-batch ID=0下有4个行人,mini-batch ID=1下有3个行人,… ,mini-batch ID=1415下有16个行人;但是这些个行人是不是都符合“该行人的尾帧对应的帧ID减去该行人首帧对应的帧ID要等于20”呢?显然,并不是mini-batch ID下所有行人都符合要求。所以进一步,得到mini-batch ID下符合要求的行人数。举例来说,mini-batch ID=0下有4个行人,但只有1个人符合要求,mini-batch ID=1下有3个行人,但只有2个人符合要求,… ,mini-batch ID=1415下有16个行人,但只有5位行人符合要求。

    到这里呢其实与在Social-STGCNN里描述的一致。但接下来ST-MR的处理有所不同。在得到符合要求的mini-batch行人数后,我们会对符合要求的行人添加特征。那添加哪些特征呢?首先是轨迹特征,它的维度大小是(ped_num, seq_len, coor);其次是场景特征,它的维度大小是(ped_num, seq_len, 1);紧接着是网格索引,它的维度大小是(ped_num, stride, seq_len, 1);最后是网格偏移,它的维度大小是(ped_num, stride, seq_len, 2)。需要说明的是,stride表示的是两种尺度,代码中给的是(2,4);1的理解是有两个方面:对于场景特征来说,有20行1列,这里的1就是表示1列,填入12种场景特征中的某一种; 对网格索引来说,这里的1实际上代表的在哪一个网格,也就是一分类。

    网格索引网格偏移特征是怎么得到的呢?

    要写明白这两个问题,首先先解释一下什么是网格索引。网格索引——顾名思义就是将给定的一段轨迹网格化,每一个网格从左上到右下的索引分别是0~W x H。在论文中网格有两种尺度,分别是36 x 18和18 x 9,但是在代码中实际上用的是32 x 18和16 x 9(怎么得到的呢?)。OK,为方便叙述,以1个人为例,给定该行人在20帧下的轨迹序列,每一帧其实就对应了一个时间维度下的grid,20帧就有20个grid,每个grid的大小为18 x 32(举例);那怎么得到每帧下的网格索引呢?首先,将20帧下的轨迹序列化,得到每一帧下行人的轨迹位于grid的哪一个网格。举例来说,frame = 0时,通过计算(怎么计算?)得到该帧下行人轨迹对应的gird网格为(index_x=1,index_y=13),那就找到frame = 0下的网格,(1,13)位置就被填入1代表这一帧下行人的位置(下图红色虚线处)。经过20帧,我们就将原来20帧下的行人轨迹(20, 2)映射到一个高为18、宽为32的网格图上,并得到该行人20帧下所对应的网格序列(20, 18 , 32,1);紧接着,我们还需要对时间维度上的grid进行Flatten操作,使其变为二维矩阵,得到该行人20帧下位于网格的哪个位置,如下图所示。
                                                                          数据处理
    对于网格偏移,可以这样理解:如果读者理解了上述的网格索引,回过头来看,所谓的网格索引实质上就是一个分类问题,只不过在数据处理中是由观测的真实轨迹“填”网格,在预测的时候就是“推理”网格。那现在有了20帧下的行人轨迹属于哪个网格,还得看看人家行人在某一帧下最终的轨迹位置所在网格的中心位置的偏差吧,那网格偏移就是干这件事的。用一句话解释就是,将行人20帧下的2维网格偏移坐标(怎么得到?)通过某种方式映射到一个高为18宽为32的图上去,这样做的目的是保证与网格索引维度的一致性,即(20,2)----->(20,18,32,2)

    接下来要解决的是上述遗留的三个问题:

    1. 网格大小18 x 32和9 x 16是怎么得到的呢?
      给定场景的高和宽分别为36,64,分别用一个2 x 2,stride = 2的卷积核与一个4 x 4,stride = 4的卷积核从上到下、从左到右的进行滑动,分别得到尺寸为18 x 32和9 x 16大小的网格图。

    2. 如何得到某帧下行人对应的网格序列呢?
      eg.frame = 0 , t r a j = ( x 0 , y 0 ) traj = (x_{0},y_{0}) traj=(x0,y0), then, i n d e x x = x 0 1920 36 index_x = \frac{x_{0}}{\frac{1920}{36}} indexx=361920x0 i n d e x y = y 0 1080 64 index_y = \frac{y_{0}}{\frac{1080}{64}} indexy=641080y0

    3. 网格偏移坐标怎么得到的呢?
      令网格中心坐标为 c e n t e r ( x ′ , y ′ ) center(x^{'},y^{'}) center(x,y),轨迹终点坐标为 t r a j ( x , y ) traj(x,y) traj(x,y),则网格偏移坐标为 t r a j ( x , y ) − c e n t e r ( x ′ , y ′ ) traj(x,y) - center(x^{'},y^{'}) traj(x,y)center(x,y)
      那网格中心坐标又是怎么得到的呢?

        for h, w in args.scene_grids:
          h_gap, w_gap = args.video_h*1.0/h, args.video_w*1.0/w  # h = 18 ,w = 32
          centers_x = np.cumsum([w_gap for _ in range(w)]) - w_gap/2.0
          centers_y = np.cumsum([h_gap for _ in range(h)]) - h_gap/2.0
          centers_xx = np.tile(np.expand_dims(centers_x, axis=0), [h, 1])  # numpy.tile(a,(2,1):把数组a沿行方向复制1倍,沿列方向复制2倍
          centers_yy = np.tile(np.expand_dims(centers_y, axis=1), [1, w])
          centers = np.stack((centers_xx, centers_yy), axis=-1)  # [H,W,2]  # 注意这里的dim=2指的是centers_xx, centers_yy
          args.scene_grid_centers.append(centers)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    Kubernetes教程(五)---Service 的几种访问方式
    MySQL及MySQLworkbench安装教程
    HDFS 高可用分布式环境搭建
    SpringMVC如何实现重定向和转发呢?
    Eslint配置
    基于BP神经网络的PID控制,基于单神经元的pid控制
    C++ AVL树
    网络管理基础
    Java项目在linux上部署步骤
    数据结构───顺序表(梦开始的地方)
  • 原文地址:https://blog.csdn.net/m0_57541899/article/details/126249397