文章目录
- 前言
- 一、这篇论文讲了?
- 二、详细说明
- 1.原文摘要翻译
- 2.读取读取I3d预训练模型,用于处理NTU中的视频信息,获得视频中的动作特征f。
- 3.使用GCNN提取骨骼点的空间和时间特征,获得h*
- 4.时空耦合器,用于生成时空注意力权重Ast(其实就是矩阵乘起来),得到atten_mask,Ast的维度为m × n × t。原文:Ast = inflate(As)◦inflate(At)
- 5.#将gcnn和i3d的模型要用输入形状append到model_inputs中,用于确定模型的输入,用于return model
- 6.论文中的SpatialEmbedding的处理,将视频动作特征f和骨骼点空间特征z1融合成embed_output,作为model的一个输出流
- 7.这一步我觉得是这个论文比较闪光的地方,用 从骨架信息中学习到的注意力权重 去对 原视频信息做一个加权处理,把加权后的原视频信息 和 原视频信息 相加 获得 added_features
- 总结
前言
“察言观色”是正常人类的基本生活交流能力,对人类动作和行为的分析和理解是现代心理学的主要研究内容之一。
随着人工智能的发展和人类计算能力的提升,人体动作识别逐渐成为计算机视觉以及图像处理领域的研究热点之一,该方向不仅拥有重要的理论研究价值,还有着广泛的应用前景。其主要原因是人体动作识别在人机交互、健康监护、智能安防、视频分析等研究领域中的潜在应用价值。
多模态机器学习 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。