多模态的动作识别 - Learning Video-Pose Embedding for Activities of Daily Living 的 论文解读 和 代码解析


前言

“察言观色”是正常人类的基本生活交流能力,对人类动作和行为的分析和理解是现代心理学的主要研究内容之一。
随着人工智能的发展和人类计算能力的提升,人体动作识别逐渐成为计算机视觉以及图像处理领域的研究热点之一,该方向不仅拥有重要的理论研究价值,还有着广泛的应用前景。其主要原因是人体动作识别在人机交互、健康监护、智能安防、视频分析等研究领域中的潜在应用价值。
多模态机器学习 Multi-Modal Machine Learning (MMML),旨在构建可以处理和关联来自多种模态信息的模型。
基于视觉的人体动作识别作为计算机视觉领域的研究热点,近
年来得到了研究者们的持续的关注。按照视觉传感器的不同,其又可以细分为基于 :
在这里插入图片描述


今天我们分享一篇基于RGB视频和骨架序列的动作识别论文 VPN: Learning Video-Pose Embedding for Activities of Daily Living,,为ECCV2020收录,在多模态的动作识别中达到了SOTA(最好的成绩),Github开源。

地址如下:
srijandas07/VPN: Pose driven attention mechanism
https://github.com/srijandas07/VPN

一、这篇论文讲了?

我的一句话总结:

用 从骨架信息 中学习到的 注意力权重 去对 原视频信息做一个加权处理。再用这个数据做分类。

二、详细说明

1.原文摘要翻译

在这篇文章中,我们关注的是日常生活活动Activities of Daily Living (ADL)认知的时空层面。ADL有两个特点:微妙的时空模式和(Ii)随时间变化的相似视觉模式。因此,ADL可能看起来非常相似,通常需要查看它们的细微细节来区分它们。由于目前的时空3D ConvNet过于僵化,无法捕捉动作中微妙的视觉模式,我们提出了一种新颖的视频-姿势网络:VPN。

该VPN的两个关键组成部分是空间嵌入和注意力网络

空间嵌入将3D姿势和RGB线索投影到共同的语义空间中。这使得动作识别框架能够利用这两种模式更好地学习时空特征。为了区分相似的动作,注意力网络提供了两个功能-
(1)利用人体拓扑的端到端可学习姿势骨干(an end-to-end learnable pose
backbone exploiting the topology of human body)
(2)在视频上提供联合时空注意力权重的耦合器。(a coupler to provide joint spatio-temporal attention weights across a video)
实验表明,VPN在大规模人类活动数据集NTU-RGB+D120及其子集NTU-RGBD60、丰田Smarthome和小规模人-物交互数据集Northwest UCLA上的动作分类性能优于最先进的结果。
在这里插入图片描述
图::我们的模型以RGB图像及其相应的三维姿势作为输入。RGB图像由视觉主干处理,生成时空特征映射(f)。提出的VPN以feature map(f)和三维姿态(P)为输入。VPN由两部分组成: 一个注意力网络和一个空间嵌入。
注意网络还包括一个姿势主干和一个时空耦合器(a Pose Backbone and a spatio-temporal Coupler)。
VPN计算一个模拟的特征映射f’。然后使用该调制特征图f’进行分类。

话不多说我们直接看代码:(示例):

def embed_model_spatio_temporal_gcnn(n_neuron, timesteps, num_nodes, num_features,
                                     graph_conv_filters_shape1, graph_conv_filters_shape2,
                                     num_filters, num_classes, n_dropout, protocol):
	#------------------------------------------------------------------#								 
	#读取I3d预训练模型,用于处理NTU中的视频信息,获得视频中的动作特征f。								 
    i3d = i3d_modified(weights = 'rgb_imagenet_and_kinetics')
    model_branch = i3d.i3d_flattened(num_classes = num_classes)
    '''
    if protocol == 'CS': # to be replaced with the values in the yaml file
       model_branch.load_weights('/data/stars/user/sdas/PhD_work/STA_appearance/NTU_CS/i3d/weights_ntu_aug_4/epoch_7.hdf5')
    else:
       model_branch.load_weights('/data/stars/user/sdas/PhD_work/CVPR20/NTU_120/I3D/weights_ntu_set_i3d_full_body/epoch_12.hdf5')
    '''
    optim = SGD(lr=0.01, momentum=0.9)
    model_branch.compile(loss='categorical_crossentropy', optimizer=optim, metrics=['accuracy'])
    print('Build model...')
	
	#------------------------------------------------------------------#
	#使用GCNN提取骨骼点的空间和时间特征,获得h*
    model_inputs=[]
    model_gcnn = GCNN_skeleton_t16(num_nodes, num_features, graph_conv_filters_shape1,
                               graph_conv_filters_shape2, num_filters, num_classes,
                               n_neuron, n_dropout, timesteps)#建立GCN模型
							   
    #------------------------------------------------------------------#
	#h*,即代码中的model_gcnn.get_layer('gcnn_out').output
    z1 = Dense(256, activation='tanh', name='z1_layer', trainable=True)(model_gcnn.get_layer('gcnn_out').output)#获得z1
    z2 = Dense(128, activation='tanh', name='z2_layer', trainable=True)(model_gcnn.get_layer('gcnn_out').output)#获得z2

    fc_main_spatial = Dense(49, activity_regularizer=attention_reg, kernel_initializer='zeros', bias_initializer='zeros',
                    activation='sigmoid', trainable=True, name='dense_spatial')(z1)#处理z1,获得空间特征fc_main_spatial
    fc_main_temporal = Dense(2, activity_regularizer=attention_reg, kernel_initializer='zeros',
                            bias_initializer='zeros',
                            activation='softmax', trainable=True, name='dense_temporal')(z2)#处理z2,即时间特征fc_main_temporal
	#注原文: The output feature h∗ of Pose Backbone follows two separate non-linear mapping functions to compute the spatial and temporal attention weights.
    
	#inflate_dense_spatial 为 设置参数,atten_mask_spatial 为 获得的空间注意权重( The dissociated attention weights),即论文中的As
	#原文中用的公式是:As = σ(z1);
	atten_mask_spatial = keras.layers.core.Lambda(inflate_dense_spatial, output_shape=(2, 7, 7, 1024))(fc_main_spatial)
    
	#inflate_dense_temporal 为 设置参数,atten_mask_temporal 为 获得的时间注意权重( The dissociated attention weights),即论文中的At
	#原文中用的公式是:AT = softmax(z2)
	atten_mask_temporal = keras.layers.core.Lambda(inflate_dense_temporal, output_shape=(2, 7, 7, 1024))(fc_main_temporal)
	
	# 一种时空耦合器,用于生成时空注意力权重Ast,即atten_mask,Ast的维度为m × n × t。原文:Ast = inflate(As)◦inflate(At)
    atten_mask = keras.layers.Multiply()([atten_mask_spatial, atten_mask_temporal])
    
	
	
    for l in model_branch.layers:
        l.trainable = True

    for layer in model_gcnn.layers:
        layer.trainable = True

    for i in model_gcnn.input:
        model_inputs.append(i)
    model_inputs.append(model_branch.input)#将gcnn和i3d的模型要用输入形状append到model_inputs中,用于确定模型的输入,用于return  model

	#------------------------------------------------------------------#
	#为论文中的f的处理
    flatten_video = Flatten(name='flatten_video')(model_branch.get_layer('Mixed_5c').output)
    embed_video = Dense(256, activation='sigmoid', trainable=True, name='dense_video')(flatten_video)
	
	#为论文中的z1的处理,为骨骼点的空间特征
    embed_skeleton = Dense(256, activation='sigmoid', trainable=True, name='dense_skeleton')(fc_main_spatial)
	
    #为论文中的SpatialEmbedding的处理,将视频动作特征f和骨骼点空间特征z1融合成embed_output,作为model的一个输出流
    embed_output = Merge(mode=lambda x: manhattan_distance(x[0], x[1]),
                          output_shape=lambda inp_shp: (inp_shp[0][0], 1), name='embed_output')([embed_video, embed_skeleton])
    
	#------------------------------------------------------------------#
	#这一步我觉得是这个论文比较闪光的地方,用 从骨架信息和视频信息中学习到的注意力权重 去对 原视频信息做一个加权处理
    multiplied_features = keras.layers.Multiply()([atten_mask, model_branch.get_layer('Mixed_5c').output])
	
    #把加权后的原视频信息 和 原视频信息 相加 获得 added_features
	added_features = keras.layers.Add()([multiplied_features, model_branch.get_layer('Mixed_5c').output])
    
	#------------------------------------------------------------------#
	#下面就是一些比较常规的操作,如AveragePooling3D,Dropout,bn等等
    x = AveragePooling3D((2, 7, 7), strides=(1, 1, 1), padding='valid', name='global_avg_pool'+'second')(added_features)
    x = Dropout(n_dropout)(x)
   
    x = conv3d_bn(x, num_classes, 1, 1, 1, padding='same', use_bias=True, use_activation_fn=False, use_bn=False, name='Conv3d_6a_1x1'+'second')

    x = Flatten(name='flatten'+'second')(x)
    predictions = Dense(num_classes, activation='softmax', name='action_output')(x)
	
	#------------------------------------------------------------------#
	#模型输入的张量形状是gcnn和i3d模型分别合在一起的形状,输出有两个, 分别是论文中的f’和SpatialEmbedding
    model = Model(inputs=model_inputs, outputs=[predictions, embed_output], name = 'spatial_temporal_attention')

    return model

接下来分步骤解析

2.读取读取I3d预训练模型,用于处理NTU中的视频信息,获得视频中的动作特征f。

代码如下(示例):

#------------------------------------------------------------------#								 
	#读取I3d预训练模型,用于处理NTU中的视频信息,获得视频中的动作特征f。								 
    i3d = i3d_modified(weights = 'rgb_imagenet_and_kinetics')
    model_branch = i3d.i3d_flattened(num_classes = num_classes)
    '''
    if protocol == 'CS': # to be replaced with the values in the yaml file
       model_branch.load_weights('/data/stars/user/sdas/PhD_work/STA_appearance/NTU_CS/i3d/weights_ntu_aug_4/epoch_7.hdf5')
    else:
       model_branch.load_weights('/data/stars/user/sdas/PhD_work/CVPR20/NTU_120/I3D/weights_ntu_set_i3d_full_body/epoch_12.hdf5')
    '''
    optim = SGD(lr=0.01, momentum=0.9)
    model_branch.compile(loss='categorical_crossentropy', optimizer=optim, metrics=['accuracy'])
    print('Build model...')

在这里插入图片描述

读取预训练i3d模型。


3.使用GCNN提取骨骼点的空间和时间特征,获得h*

代码如下(示例):

   ##------------------------------------------------------------------#
	#使用GCNN提取骨骼点的空间和时间特征,获得h*
    model_inputs=[]
    model_gcnn = GCNN_skeleton_t16(num_nodes, num_features, graph_conv_filters_shape1,
                               graph_conv_filters_shape2, num_filters, num_classes,
                               n_neuron, n_dropout, timesteps)#建立GCN模型

在这里插入图片描述

其中GCNN_skeleton_t16() 这个函数有关图卷积的操作,后面有机会再详细解析。

我们使用GCNS学习三维人体关节之间的空间关系the spatial relationships


4.时空耦合器,用于生成时空注意力权重Ast(其实就是矩阵乘起来),得到atten_mask,Ast的维度为m × n × t。原文:Ast = inflate(As)◦inflate(At)

代码如下(示例):

    #------------------------------------------------------------------#
	#h*,即代码中的model_gcnn.get_layer('gcnn_out').output
    z1 = Dense(256, activation='tanh', name='z1_layer', trainable=True)(model_gcnn.get_layer('gcnn_out').output)#获得z1
    z2 = Dense(128, activation='tanh', name='z2_layer', trainable=True)(model_gcnn.get_layer('gcnn_out').output)#获得z2

    fc_main_spatial = Dense(49, activity_regularizer=attention_reg, kernel_initializer='zeros', bias_initializer='zeros',
                    activation='sigmoid', trainable=True, name='dense_spatial')(z1)#处理z1,获得空间特征fc_main_spatial
    fc_main_temporal = Dense(2, activity_regularizer=attention_reg, kernel_initializer='zeros',
                            bias_initializer='zeros',
                            activation='softmax', trainable=True, name='dense_temporal')(z2)#处理z2,即时间特征fc_main_temporal
	#注原文: The output feature h∗ of Pose Backbone follows two separate non-linear mapping functions to compute the spatial and temporal attention weights.
    
	#inflate_dense_spatial 为 设置参数,atten_mask_spatial 为 获得的空间注意权重( The dissociated attention weights),即论文中的As
	#原文中用的公式是:As = σ(z1);
	atten_mask_spatial = keras.layers.core.Lambda(inflate_dense_spatial, output_shape=(2, 7, 7, 1024))(fc_main_spatial)
    
	#inflate_dense_temporal 为 设置参数,atten_mask_temporal 为 获得的时间注意权重( The dissociated attention weights),即论文中的At
	#原文中用的公式是:AT = softmax(z2)
	atten_mask_temporal = keras.layers.core.Lambda(inflate_dense_temporal, output_shape=(2, 7, 7, 1024))(fc_main_temporal)
	
	# 一种时空耦合器,用于生成时空注意力权重Ast,即atten_mask,Ast的维度为m × n × t。原文:Ast = inflate(As)◦inflate(At)
    atten_mask = keras.layers.Multiply()([atten_mask_spatial, atten_mask_temporal])

在这里插入图片描述

inflate_dense_spatial,inflate_dense_spatial 两个为对应的Lambda的设置函数
(As and At ) are classically trained as in [44] to get the most important body part and key frames for an action.
As 和 At 分别代表了最重要的身体骨骼点 和 动作中最关键的一帧。


5.#将gcnn和i3d的模型要用输入形状append到model_inputs中,用于确定模型的输入,用于return model

代码如下(示例):

   for l in model_branch.layers:
        l.trainable = True

    for layer in model_gcnn.layers:
        layer.trainable = True

    for i in model_gcnn.input:
        model_inputs.append(i)
    model_inputs.append(model_branch.input)

6.论文中的SpatialEmbedding的处理,将视频动作特征f和骨骼点空间特征z1融合成embed_output,作为model的一个输出流

代码如下(示例):

    #------------------------------------------------------------------#
	#为论文中的f的处理
    flatten_video = Flatten(name='flatten_video')(model_branch.get_layer('Mixed_5c').output)
    embed_video = Dense(256, activation='sigmoid', trainable=True, name='dense_video')(flatten_video)
	
	#为论文中的z1的处理,为骨骼点的空间特征
    embed_skeleton = Dense(256, activation='sigmoid', trainable=True, name='dense_skeleton')(fc_main_spatial)
	
    #为论文中的SpatialEmbedding的处理,将视频动作特征f和骨骼点空间特征z1融合成embed_output,作为model的一个输出流
    embed_output = Merge(mode=lambda x: manhattan_distance(x[0], x[1]),
                          output_shape=lambda inp_shp: (inp_shp[0][0], 1), name='embed_output')([embed_video, embed_skeleton])

在这里插入图片描述
在这里插入图片描述

inflate_dense_spatial,inflate_dense_spatial 两个为对应的Lambda的设置函数


7.这一步我觉得是这个论文比较闪光的地方,用 从骨架信息中学习到的注意力权重 去对 原视频信息做一个加权处理,把加权后的原视频信息 和 原视频信息 相加 获得 added_features

代码如下(示例):

    #------------------------------------------------------------------#
	#这一步我觉得是这个论文比较闪光的地方,用 从骨架信息和视频信息中学习到的注意力权重 去对 原视频信息做一个加权处理
    multiplied_features = keras.layers.Multiply()([atten_mask, model_branch.get_layer('Mixed_5c').output])
	
    #把加权后的原视频信息 和 原视频信息 相加 获得 added_features
	added_features = keras.layers.Add()([multiplied_features, model_branch.get_layer('Mixed_5c').output])

在这里插入图片描述
model_branch.get_layer(‘Mixed_5c’).output 为上图中的 f
atten_mask 为 Ast


## 8.下面就是一些比较常规的操作,如AveragePooling3D,Dropout,bn,dense分类等等,最后返回模型

代码如下(示例):

   #------------------------------------------------------------------#
	#下面就是一些比较常规的操作,如AveragePooling3D,Dropout,bn等等
    x = AveragePooling3D((2, 7, 7), strides=(1, 1, 1), padding='valid', name='global_avg_pool'+'second')(added_features)
    x = Dropout(n_dropout)(x)
   
    x = conv3d_bn(x, num_classes, 1, 1, 1, padding='same', use_bias=True, use_activation_fn=False, use_bn=False, name='Conv3d_6a_1x1'+'second')

    x = Flatten(name='flatten'+'second')(x)
    predictions = Dense(num_classes, activation='softmax', name='action_output')(x)
	
	#------------------------------------------------------------------#
	#模型输入的张量形状是gcnn和i3d模型分别合在一起的形状,输出有两个, 分别是论文中的f’和SpatialEmbedding
    model = Model(inputs=model_inputs, outputs=[predictions, embed_output], name = 'spatial_temporal_attention')

    return model

在这里插入图片描述

最后返回模型,VPN模型构建完成!!

在这里插入图片描述
最后,model = Model(inputs=model_inputs, outputs=[predictions, embed_output], name = ‘spatial_temporal_attention’)
在这里插入图片描述

model实际上是有两个output的,分别是predictions 和 embed_output,所以最后构建的loss函数要对这两者进行加权处理,
分别是:1,“action_output”: “categorical_crossentropy” ;2,“embed_output”: “mean_squared_error”,

才能得到最后的总的LOSS函数,最后再使用SGD最优化方法来降低函数的loss。


总结

这篇文章核心的要点还是对attention的运用,用 从骨架信息 中学习到的 **注意力权重** 去对 原视频信息做一个加权处理。再用这个数据做分类。 本质上还是attention的运用,不仅对视频原视频数据做了attention,还对骨架中的骨骼点,骨骼点序列中的关键帧做了attention处理。 而其中骨骼点数据处理过程比较复杂,用了GCN,等等,为了只是提取一个简单的Ast权重,我个人认为这是不是会增加很多的计算复杂度?但是我看到原论文好像没有做分析 ,欢迎大家讨论。。 而且如果最后骨骼点序列仅提取权重,感觉会损失部分骨骼点的信息,是否有更好方法进行信息的利用?如用其它多模态融合的方法进行改良...抛砖引玉
  • 8
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值