返回列表

35th place solution

665. CMI - Detect Behavior with Sensor Data | cmi-detect-behavior-with-sensor-data

开始: 2025-05-30 结束: 2025-09-02 健康管理与公共卫生 数据算法赛
第 35 名解决方案 - CMI 竞赛
作者: ba (brunoarpa)
排名: 第 35 名
发布时间: 2025-09-03
标题: 第 35 名解决方案
副标题: 架构是我主要改进的地方,但没有后处理,没有调参,也没有巨大的集成模型

介绍

恭喜获奖者,并感谢组织者准备了如此精彩的比赛。我非常感激能参加这次竞赛,在这里人们可以互相学习,分享想法和资源。有些 Notebook 非常有指导意义。其他的比如许多巨大的洗牌集成模型就没那么有用了,哈哈。

这是我的第二次 Kaggle 竞赛——我还是个初学者。我很高兴获得了第 35 名,虽然我对许多错过的地方感到有点沮丧。我也很高兴能在这个暑假期间学到这么多,尽管我本希望能投入更多的时间,以及更多的计算资源到这次比赛中。

我训练了两个模型,一个仅使用 IMU 数据,另一个使用所有数据(IMU+TOF+THM)。手势被用作标签,我没有做手势 + 方向标签,我不知道为什么,我就是没去看方向标签 :(

特征工程与预处理

原始四元数数据首先通过球面线性插值 (Slerp) 插值缺失值进行清洗,然后修复符号翻转以确保时间连续性。TOF 中的 -1 被填充为 300,因为 -1 意味着太远,信号没有返回。

我从这个模型 https://www.kaggle.com/code/jiazhuang/cmi-imu-only-lstm 获取了 IMU 特征,我只在那组特征中添加了四元数差分特征。

左右手归一化: acc_x, rot_y, 和 rot_z 必须乘以 -1 进行翻转。对于 TOF 和 THM,传感器 3 和 5 被交换,并垂直翻转。传感器 1,2,4 只是水平翻转。我认为这是对传感器数据应用的正确物理变换,我通过查看数据进行了检查,看起来也是正确的变换。

特定受试者校正: 'SUBJ_045235', 'SUBJ_019262' 这两个受试者将设备戴反了,所以我曾考虑移除他们,但最终决定进行正确的变换,并将 TOF 1 传感器设置为 Nan,因为向上看无法变换为向下看,但对于其他传感器——acc x, acc y, rot x 和 rot y 都乘以 -1 翻转,就像左右手传感器一样 (THM/TOF) 3 和 5 被交换,并且所有 (2,3,4,5) 传感器旋转了 180 度,这等同于垂直和水平翻转。这也似乎是正确的物理变换,数据也吻合,所以我没有移除这些受试者。

具有 'bad' 相位列值的序列被手动修正。

对于 TOF/THM:我使用了一个 2D CNN 从 8x8 TOF 图像中提取模式,然后与每个对应传感器的 TOF 和 THM 的均值、标准差、最大值和最小值连接,例如 TOF i 与 THM i。

模型架构

注意:全数据模型是建立在已经不错的 IMU 模型之上的,不是从头开始,所以很多东西是相似的。

两个模型都首先通过多分支 1D CNN 处理 IMU 数据:

self.feature_groups = {
    'raw_acc': ['acc_x', 'acc_y', 'acc_z'], 
    'raw_rot': ['rot_w', 'rot_x', 'rot_y', 'rot_z'],
    'linear_acc': ['linear_acc_x', 'linear_acc_y', 'linear_acc_z', 'linear_acc_mag'],
    'angular_vel': ['angular_vel_x', 'angular_vel_y', 'angular_vel_z'],
    'derivatives': ['acc_mag', 'rot_angle', 'acc_mag_jerk', 'rot_angle_vel',
                    'linear_acc_mag_jerk', 'angular_distance'],
    'rot_diff': ['q_diff_w', 'q_diff_x', 'q_diff_y', 'q_diff_z']
}

对于全数据模型,使用 Performer 在每个时间步融合来自 5 个 TOF 和 THM 传感器的数据。这个分支试图模拟不同传感器之间的空间关系。

来自 IMU 仅模型的 CNN,以及来自全数据模型 Performer 的输出,被输入到两个并行的 GRU 中,一个是过渡 GRU,一个是手势 GRU,基于训练数据的 'phase' 列,使用辅助损失进行相位预测并在推理期间使用。

来自两个 GRU 的最终隐藏状态使用基于 MLP 的注意力、最大池化和平均池化进行聚合,以获得用于分类头的最终向量。

训练

数据增强: 对于仅 IMU 模型,使用了 Mixup, 时间缩放,时间扭曲,时间平移(我忘了尝试缩放!)。参考代码:https://www.kaggle.com/code/alejopaullier/cmi-sequence-data-augmentation。对于全数据模型,只有抖动/高斯噪声有效,尽管我没有为 TOF 和 THM 尝试太多增强。

标准交叉熵损失,基于受试者分层的组 K 折交叉验证,我做了 10 个分割而不是 5 个,种子之间的方差更小,所以测试可能更准确一些,不过话说回来,我应该让模型更轻量级直到比赛后期,以便能运行更多测试。EMA 也有帮助。

我看到很多人做了超过 200 个 epoch,我不确定我是否做错了,但我只是使用了默认未调优的训练和在这个 Notebook https://www.kaggle.com/code/jiazhuang/cmi-imu-only-lstm 中看到的所有参数,所以我只有 20 的耐心值,训练了 50 个 epoch,学习率 0.001,我不是很清楚如何直观地改进超参数而不只是某种暴力调优。

推理

我只是做了折叠模型的 Logits 平均。抖动 TTA 将 LB 提高了 0.001,但太少了,所以我没有包含它。

无效尝试

  • 在 CNN 中添加膨胀,比如堆叠膨胀 CNN 或 TCN,都没用。扩展模型比如增加更多层或更高的模型维度似乎也没用。
  • 也没能让 MHA 在我的仅 IMU 模型上工作,尽管 Transformer 和后来的 Performer 对 TOF/THM 有效。
  • 我还尝试了对 IMU 中经常混淆的类别(如眉毛和睫毛拉扯,颈部脸颊捏)使用分层注意力,所以我尝试实现专家头,比如先分类到组,然后用专家头区分两个相似的手势。我努力尝试以不同方式推动这个想法,但 sadly 都没用。
  • 为了更好的池化,只有 MLP 注意力有效。
  • 对于我当前的架构,IMU 数据的统计特征就是不好。
  • TOF 的更多统计特征如偏度和峰度。
  • 更好的优化器,不知何故 Adam 比 AdamW 表现更好,尽管我担心这可能只是噪声/对验证集的过拟合。
  • 人口统计特征,甚至分箱也没用。我只将人口统计用于左右手。
  • 我尝试使用 FiLM 让人口统计数据动态重新缩放和偏移网络的内部特征,以便在 CNN 之后根据受试者特定特征改变模型对时间序列的处理。
  • 我也没能让图像模型表现良好。
  • Focal loss 没有产生改进也没有恶化 CV。
  • SWA 也没帮助,尽管我想我可能实现错了。
  • 将非目标类标签折叠成一个全局标签。
  • 在 IMU 多分支 CNN 中添加更多分支,比如每个特征一个分支,或所有在一个分支中,都没有比我之前展示的分支集更好。
  • 更多或更少的卷积核大小也没帮助,我猜公共 Notebook 中已经有很好的了。
  • 用 Nan 填充一些 TOF 传感器作为增强也没用,我不确定为什么,因为有些序列中确实发生了这种情况..
  • 用 Nan 填充 8x8 TOF 图像的一些补丁也没帮助。
  • 改变 IMU 增强,比如先做时间平移,然后抖动,没帮助,我并行做了前面提到的所有增强。
  • 任何类型的滤波器,比如 moth 的增强 Notebook 中分享的巴特沃斯滤波器,都没帮助。
  • 我想我做错了 PCA,尽管我不认为它会很好地工作。
  • 我尝试在推理期间基于高置信度伪标签的序列进行微调,但我再次认为我做错了或者我的模型不够好。很高兴这是一个正确的想法,因为我看到 daiwakun 在他分享的解决方案中使用了它。
  • 我认为 acc x 翻转 -1 不是完全准确,只是一个粗略估计,所以我想添加负的 acc x 作为一个新特征。
  • 6d 四元数表示也没帮助我,尽管我相信这更多是我的错而不是想法不好 :/
  • 集成对我来说真的没用,我想是因为我的模型不够多样化/不同。

结果

仅 IMU CV 0.842。全数据 10 折 CV 0.898。平均 CV 为 0.870,这与公共 LB 0.870 相当吻合。可惜私有 LB 较低,为 0.845,尽管我看到每个人的 LB 都至少下降了一点,我可能在验证集上过拟合了。

感谢阅读 :)

同比赛其他方案