返回列表

3rd Place Solution

546. Google - Isolated Sign Language Recognition | asl-signs

开始: 2023-02-23 结束: 2023-05-01 音视频处理 数据算法赛
第三名解决方案

第三名解决方案

作者:Ruslan GrimovAndrew NesteroffGleb PapchikhinQingyao Shuai 发布日期:2023-05-02

我们基于公开笔记使用了六个一维卷积模型和两种版本的Transformer的集成。关键在于数据预处理、强化增强和集成

最初,我尝试基于上述公开Transformer开发自己的解决方案,但后来发现模型架构的重要性不如正确的数据处理和集成工作,因此我转向了更简单的架构,如多层一维卷积模型。我使用了Keras,并利用原生tflite层(如DepthwiseConv1D)的所有优势。我的典型模型如下所示:

do = 0.5

model = Sequential()
model.add(InputLayer(input_shape=(max_len, 61, 2)))
model.add(Reshape((max_len, 61*2)))

model.add(Conv1D(64, 1, strides=1, padding='valid', activation='relu'))
model.add(BatchNormalization())
model.add(DepthwiseConv1D(3, strides=1, padding='valid', depth_multiplier=1, activation='relu'))
model.add(BatchNormalization())

model.add(Conv1D(64, 1, strides=1, padding='valid', activation='relu'))
model.add(BatchNormalization())
model.add(DepthwiseConv1D(5, strides=2, padding='valid', depth_multiplier=4, activation='relu'))
model.add(BatchNormalization())

model.add(MaxPool1D(2, 2))

model.add(Conv1D(256, 1, strides=1, padding='valid', activation='relu'))
model.add(BatchNormalization())
model.add(DepthwiseConv1D(3, strides=1, padding='valid', depth_multiplier=1, activation='relu'))
model.add(BatchNormalization())

model.add(Conv1D(256, 1, strides=1, padding='valid', activation='relu'))
model.add(BatchNormalization())
model.add(DepthwiseConv1D(5, strides=2, padding='valid', depth_multiplier=4, activation='relu'))
model.add(BatchNormalization())

model.add(GlobalAvgPool1D())
model.add(Dropout(rate=do))

model.add(Dense(1024, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(rate=do))

model.add(Dense(1024, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(rate=do))

model.add(Dense(250, activation='softmax'))

后来,我的两位同事加入了我。我们有很多想法,例如使用合成数据。我们找到了这篇论文,编写了一个脚本,该脚本通过内部参数(关节旋转)和相机模型生成手的合成3D点,并尝试基于3D点使用模型预测手的内部参数。然后使用这个预训练模型来预处理数据。但遗憾的是,我们没有足够的时间完成它。

我们还尝试在额外数据(WLASL)上进行训练,发现该数据集使本地交叉验证分数提高了约0.005-0.007,但后来我们放弃了这个想法,在LB提交中未使用额外数据。

归一化

我们使用这些参考点进行归一化:ref = coords[:, [500, 501, 512, 513, 159, 386, 13,]]。 我们没有使用深度维度。

我们没有丢弃没有手的帧,但在TTA(测试时增强)中考虑了手的存在。

增强

  • 对每一帧全局应用随机旋转、平移和缩放
  • 为每个点添加随机小偏移
  • 部分组合——例如,我们从一个样本中取手,从另一个具有相同标签的样本中取嘴唇。这种增强显著提高了分数
  • CutMix——从不同类别的样本中取部分。对于手,我们使用0.7作为标签值,其他部分使用0.3

TTA(测试时增强)

  • 对短序列进行随机左右填充
  • 对于长帧序列,我们根据帧中手的存在情况以不同概率丢弃帧

对于不同的模型,我们使用了不同的点组合:双手/仅活动手、嘴唇、眼睛、姿态的顶部。对于一些模型,我们只使用了嘴唇/眼睛的每隔一个点。 对于只使用一只手的模型,我们确定视频中哪只手出现得更多,如果是左手,我们就镜像所有点及其坐标。 除了一个模型使用96帧外,其余所有模型都只使用了32帧

这些一维卷积模型快速且轻量,因此我们可以集成多达六个模型,并且仍有足够的空间和时间用于额外的模型和TTA。六个这样的模型的集成在公共LB上获得了0.7948的分数,在私有LB上获得了0.8711的分数。 然后我们决定与@sqqqqy合作,他一直在改进公开内核中的Transformer。他的解决方案如下:

1. Transformer模型

  • 我们的Transformer模型基于公开笔记,使用不同的序列归一化和更小的UNITS尺寸以减少模型参数。
  • 我们实现了两种基于Transformer的模型:第一种模型为每个部分学习独立的嵌入(与公开笔记相同),第二种模型使用整个xyz序列输入学习一个嵌入。
  • 第一种模型在1个种子下的分数为LB 0.77+,第二种模型在1个种子下的分数为LB 0.768

2. 预处理

  • 我们使用20个嘴唇点、32个眼睛点、42个手点(左手和右手)以及8个姿态点。
  • 输入序列使用肩膀、臀部、嘴唇和眼睛点进行归一化。
  • 将NaN值填充为0.0
  • 通过输入序列$(d_x, d_y, \sqrt{(d_x)^2+(d_y)^2})_t$学习运动嵌入,其中 $$(d_x, d_y)_t = xyz_t - xyz_{t-1}$$
  • 最终的嵌入是运动嵌入和xyz嵌入的拼接

3. 增强

  • 全局增强(对所有帧应用相同的增强),包括旋转(-10,10)、平移(-0.1,0.1)、缩放(0.8,1.2)、剪切(-1.0,1.0)、翻转(适用于某些手势)

  • 基于时间的增强(对某些帧应用增强),随机选择1-8帧进行仿射增强,随机丢弃帧(用0.0填充)

  • 这些增强显著提高了分数

4. 超参数

  • NUM_BLOCKS: 2
  • NUM_HEAD: 8
  • 学习率: 1e-3
  • 优化器: AdamW
  • 训练轮数: 100
  • 后期Dropout: 0.2-0.3
  • 标签平滑: 0.5

六个带有TTA的一维卷积模型与两个Transformer结合,使我们在本次比赛中获得了第三名。

同比赛其他方案