论文:GaitSet: Regarding Gait as a Set for Cross-View Gait Recognition
Github:https://github.com/AbnerHqC/GaitSet
什么叫步态识别?
最强大脑中,水哥和小度,挑战的核桃计划项目,本质就是一个步态识别的例子。遗憾的是,水哥被小度完败。
论文提出了步态识别的新网络结构GaitSet,在CASIAB上达到了95.0%的rank-1准确性,在OU-MVLP上达到了87.1%的准确性。
GaitSet主要特点:
- 灵活,网络的输入图片除了大小需要固定为64*44这个约束外,不要求输入的时序图片必须具备时序顺序,同时对于个数也不要求,可以输入任意的个数,任意的姿态的,任意拍摄视角的轮廓图。
- 快速,网络直接学习步态的特征,而不是测量一系列的步态轮廓图序列和模板的相似性。通过对学习到的特征和数据库中的特征进行欧式距离的计算来进行识别。
- 刷新了CASIAB和OU-MVLP数据集。
步态识别的相关方法:
(1)将步态看作图像
将所有的步态轮廓图压缩成一幅图像,将步态识别看成一个图像匹配问题。很显然这种方法忽略了步态中的时序信息,也无法建模精细的空域信息。
(2)将步态看作视频序列
考虑直接从silhouette提取特征,使用LSTM方法或者3D-CNN方法或者双流法(two stream), 可以很好的建模步态中的时、空域信息,但其计算代价高昂也不易于训练。
3D-CNN
视频相对于图像多出了一个维度,而3D卷积正好可以用于处理这个维度,因此也非常适合视频分类任务,缺点是计算量比较大,下图展示了一个简单的3D模型。
LSTM:
视频和语音信号都是时序信号,而RNN和LSTM正是处理时序信号的模型。如下图所示,通过CNN对每一个视频帧提取特征,使用LSTM建模时序关系。
双流法(two stream)
双流法包含两个通道,一个是RGB图像通道,用于建模空间信息。一个是光流通道,用于建模时序信息。两者联合训练,并进行信息融合。
时序信息的提取方法,包括光流法,运动向量Motion Vector,mpegflow等。
ffmpeg自带的运动向量效果,效果类似于光流法,但是是基于block的,而光流是基于pixel的。光流效果更佳精细,运动向量速度更快。
ffplay -debug vis_mb_type mpi_sintel_final_alley_1.avi
ffplay -vismv pf mpi_sintel_final_alley_1.avi
数据集:
CASIA Gait Database(http://www.cbsr.ia.ac.cn/english/Gait%20Databases.asp)
该数据集包含了Dataset A ,Dataset B , Dataset C,Dataset D四个数据集
Dataset A:20个人,每个人包含3个角度,每个角度4张图
Dataset B:124个人,包含11个角度,包含正常走路的,背包的,穿夹克的
Dataset C:153个人,包含正常走路,慢走,快走,背包快走
Dataset D:88个人,包含了脚印的热量图
本文的训练使用Dataset B数据集,
对齐到64*64大小后的样子:
对齐流程如下,
(1)对轮廓图,依据每一行的像素和不为0的原则,找上边和下边。
(2)根据上边和下边对轮廓图进行切割
(3)对切割后的图进行resize操作,高度为64,宽度保持比例
(4)依据每一列的和最大的为中心线原则,找到中心线
(5)中心线左右各32像素进行切割,不够的补0
(6)得到对齐后的轮廓图
步态识别问题定义:
假设又N个人,每个人代表一个类别,每个人都具有自己的一种分布P。X表示每一个人的一系列的图片,y表示每一个人的类别标签。最终问题被定义为f函数。
F表示卷积网络
G表示排列不相关函数
H表示学习可区分的特征向量p
网络结构:
首先网络的输入为5个维度,num_of_people*frame_num*channel*height*width。其中,batch_size= num_of_people*frame_num。训练的时候可以输入多个人的多张图,测试的时候,输入一个人的多张图,也就是说测试的时候,num_of_people=1。
Triplet loss 的margin为0.2,包含了hard loss和full loss。
HPM的尺度scale为5,也就是(1+2+4+8+16)。
每一个batch的输入,类别数p=8,每个类别的帧数k=16,
通道数c1=c2=32,c3=c4=64,c5=c6=128。
输入图像大小为64*44*1,为灰度图,经过2次下采样操作,变为16*11。
先说网络的整体思想,感觉和人脸识别中度量学习很类似,基本思想都是分类,使用triplet loss。当然也是和而不同,区别就在于,
- GaitSet中加入了非严格时序维度的图片特征,并且将这个时序维度的特征做attention操作,压缩到batch维度,也就是SP操作。
- GaitSet中的一个人的一系列的图最终将高度和宽度维度压缩为1,2,4,8,16共31个维度的特征。也就是HPM模块。
另外一个上图中连续输入的图片是表现在batch维度的操作,虽然图中画了3行红色和蓝色相间的这样的操作,但是,实际上,只有一个分支,通过batch维度实现,也就是论文中说的这部分权值共享的意思。
其中,黄色部分分别表示,卷积+卷积+pooling操作,卷积+卷积操作
粉丝部分每行分别表示,卷积+卷积+pooling操作,卷积+卷积+pooling操作,卷积+卷积操作
+,表示对应维度的加法操作。
MGP模块表示Multilayer Global Pipeline (MGP),主要融合不同层的输出特征,增加模型的不同感受野的信息。
SP表示Set Pooling操作,
Z表示集合维度的特征,一个人表示一个集合,
V表示帧维度的特征
Π表示任意的组合
SP操作就表示为在set维度,也就是第二维frame_num这个维度进行全局的max,mean,median操作,然后再进行1*1卷积操作。
后续又对SP模块引入attention机制,
最终在SP操作后,再进行加法和max操作,得到最终的输出。
HPP操作表示Horizontal Pyramid Pooling (HPP),主要将height和width维度压缩为1,2,4,8,16这样的一个维度的尺度信息(scale),该操作可以帮助网络处理各个尺度的特征,可以融合局部和全局特征。HPP操作通过Global Max Pooling和Global Average Pooling实现。
HPM模块表示最终输出的特征向量,MGP模块和主网络模块分别经过HPP操作,宽度和高度这两个维度被压缩成1,2,4,8,16这样的1个维度,像下图的第一列的蓝色的h*w*c变成了第二列的蓝色的1*c,红色的h*w*c变成第二列的2*c,******。两个这样的31维度concat成62维度。channel维度不变,为D=128,然后再经过一个全连接操作,变成D=256维度。
Batch维度原本为num_of_people*frame_num,frame_num维度经过SP操作变为1,被squeeze掉后,batch维度就是num_of_people,也就是说训练的batch中有几个人,就输出几个对应的62*256的特征向量。测试的时候,因为只有1个人输入,所以输出1个62*256的特征向量。这个特征向量可以理解为,1个人对应62个全连接层的特征向量,每一个特征向量的维度为256维。
对于训练部分,则计算每个特征向量组成的矩阵和自己的转置的自相关矩阵,也就会得到anchor和p,anchor和n,相当于对batch内的所有样本都进行了组合。
Triplet Loss=max(d(a,p)−d(a,n)+margin,0)
实验结果:
在原论文triplet的基础上,增加softmax loss,使用2个loss联合训练,最终效果会更佳。
在model/network/triplet.py中增加下面代码:
#cross entropy
entropy_loss = torch.nn.functional.cross_entropy(input = feature.view(n*m,d), target = label.view(n*m))
pred = feature.view(n*m,d).max(1, keepdim=True)[1]
correct = pred.eq(label.view(n*m).view_as(pred)).sum().float()
accuracy = correct/(n*m+0.0001)
rerurn部分修改为,
return full_loss_metric_mean, hard_loss_metric_mean, mean_dist, full_loss_num ,entropy_loss,accuracy
model/model.py修改为,
(full_loss_metric, hard_loss_metric, mean_dist, full_loss_num ,entropy_loss,accuracy
) = self.triplet_loss(triplet_feature, triplet_label)
if self.hard_or_full_trip == 'hard':
loss = 0.5*hard_loss_metric.mean()+ 0.5*entropy_loss.mean()
elif self.hard_or_full_trip == 'full':
loss = 0.5*full_loss_metric.mean()+ 0.5*entropy_loss.mean()
而单独的使用softmax进行训练,分类的精度也很高,和triplet不相伯仲,但是最终测试,效果却很差。可见,triplet的重要性。
总结:
GaitSet更像一个基于黑白轮廓图的度量识别的网络。当然网络也考虑了时序的特征,但是总感觉这样的操作,更像是一个时序维度的attention机制,也就是单纯的把多个时序维度压缩为1个维度,而不像3d-cnn和lstm那样专注的学习时序的相关性更好。当然优点就是该方法具有时序无关性,同时接受任意时序个数的输入,得到一个特征向量。
可以考虑将其应用于基于视频的人脸识别。基于视频的人脸识别,人脸姿态多样化,人工选择正脸需要检测定位角度。各种问题都可以交给GaitSet完成。