# Child Mind Institute - Detect Sleep States (2023) > Last updated: 2026-01-23 > Source count: 1 --- ### Child Mind Institute - Detect Sleep States (2023) **竞赛背景:** - **主办方**:Child Mind Institute - **目标**:从手腕佩戴的加速度计数据中检测睡眠事件(入睡 onset 和觉醒 wakeup) - **应用场景**:睡眠健康监测、可穿戴设备、睡眠质量分析 - **社会意义**:自动化睡眠监测,减少人工标注成本,改善睡眠障碍诊断 **任务描述:** 从 5 秒间隔的加速度计时间序列数据中检测两类事件: - **Onset**:入睡时刻 - **Wakeup**:觉醒时刻 **数据集规模:** - 总样本数:~500 个多日记录 - 数据点:每个 series 最多 17280 步(24 小时 × 12 步/分钟 × 60 分钟) - 特征:anglez(手臂角度)、enmo(加速度计信号) - 标注:每夜 1 个 onset + 1 个 wakeup 事件 **数据特点:** 1. **稀疏标注**:17280 步中仅有 2 步有标签(0.01%) 2. **标签偏移**:真实事件总是发生在 hh:mm:00 整分钟时刻 3. **周期性模式**:存在 24 小时周期性重复的数据(未标注事件) 4. **评估容差**:多个 tolerance 窗口(1, 3, 5, 7.5, 10, 12.5, 15, 20, 25, 30 分钟) **评估指标:** - **Average Precision (AP)**:多 tolerance 平均 - 对每个 tolerance 窗口,计算最高置信度匹配的 AP - 最终分数 = 各 tolerance AP 的平均 × 各类别 AP 的平均 **竞赛约束:** - 提交格式:series_id, step, event, score - 每个系列最多预测多个事件(需后处理筛选) - 事件必须成对(onset + wakeup) **最终排名:** - 1st Place: shimacos vs sakami vs kami - Private LB: **0.852** - 2nd Place: K-Mat - Private LB: ~0.850 - 3rd Place: cucutzik - Private LB: ~0.849 - 总参赛队伍:1,877 支 **技术趋势:** - 几乎所有前排方案使用**两阶段建模**:5秒概率预测 → 1分钟精化 - **分钟偏差处理**是关键涨分点:事件总是发生在整分钟 - **未标注事件检测**:利用周期性识别缺失标签 - **后处理优化**:针对 tolerance 指标的 greedy search - **Daily Normalization**:按天归一化 2nd level 预测 **关键创新:** - **15/45秒技巧** (1st Place):针对 tolerance 边缘优化 - **两阶段建模** (1st, 2nd):5秒检测 + 1分钟精化 - **Error Modeling** (2nd Place):将差分变化转为分类任务 - **数据增强** (3rd Place):序列反转提升 CV +0.01 **后续影响:** - 该竞赛推动可穿戴设备睡眠监测技术发展 - 前排方案广泛开源,成为事件检测任务的参考 - 后处理优化策略被后续竞赛采用 #### 前排方案详细技术分析 **1st Place - shimacos vs sakami vs kami (kami, sakami0000, shimacos)** 核心技巧: - **15/45秒技巧**:针对 tolerance 边缘优化,事件可能发生在整点前/后 15/45 秒 - **两阶段建模**:Stage 1(5秒概率预测)→ Stage 2(1分钟精化) - **Daily Normalization**:按天归一化 2nd level 预测,减少个体差异 - **Greedy Post-Processing**:针对 AP 指标优化,选择最佳事件对 - **衰减目标**:按 tolerance_steps 加权 + epoch 衰减 实现细节: - Stage 1:LSTM + MLP,输出 5 秒间隔的概率预测 - Stage 2:基于 Stage 1 预测,在 1 分钟窗口内精化事件位置 - 考虑事件必须在整分钟时刻(label shift 0) - 最终 Private LB:0.852 **2nd Place - K-Mat** 核心技巧: - **Error Modeling**:将差分变化转为分类任务(上升/下降/平稳) - **序列反转数据增强**:提升 CV +0.01 - **集成策略**:多个模型的不同配置集成 - **后处理优化**:考虑事件对的约束条件 实现细节: - 输入特征:anglez + enmo + 时间戳特征 - 模型架构:LSTM + Attention 机制 - Error Modeling:预测信号变化模式,辅助事件检测 - 最终 Private LB:~0.850 **3rd Place - cucutzik** 核心技巧: - **序列反转数据增强**:镜像序列,增加数据多样性 - **未标注事件利用**:利用周期性模式识别未标注事件 - **时间窗口滑动**:多尺度窗口检测事件 - **事件对约束**:确保 onset 和 wakeup 成对出现 实现细节: - 数据增强:时间序列反转,保持标签一致性 - 模型集成:3-5 个不同随机种子的模型 - 后处理:基于置信度和时间约束筛选事件对 - 最终 Private LB:~0.849 **4th Place - RSI (Recurring Sleep Inertia)** 核心技巧: - **周期性模式检测**:自动识别 24 小时周期性睡眠模式 - **多时域建模**:5 秒、30 秒、5 分钟多尺度预测 - **事件链预测**:预测 onset-wakeup 事件链而非单独事件 - **置信度校准**:温度缩放校准预测概率 实现细节: - 周期性检测:FFT 频谱分析识别 24 小时周期 - 多尺度模型:不同时间窗口的 LSTM 集成 - 事件链:onset → [sleep] → wakeup 约束 - 最终 Private LB:~0.848 **5th Place - Andris (Andris Apinis)** 核心技巧: - **特征工程自动化**:时域、频域、时频域特征自动提取 - **XGBoost 集成**:梯度提升树处理统计特征 - **深度学习混合**:LSTM + XGBoost 混合架构 - **滑动窗口集成**:多窗口大小预测融合 实现细节: - 特征:统计特征(均值、方差、峰度)+ 频域特征(FFT 功率谱) - XGBoost:100+ 棵树,max_depth=8 - 混合架构:LSTM 处理时序 + XGBoost 处理特征 - 滑动窗口:[30s, 60s, 120s, 300s] - 最终 Private LB:~0.847 **6th Place - CPMP (Cyprien) 设为 0 start_gt = max(0, best_idx - tol_step) end_gt = min(len(remaining_predictions), best_idx + tol_step) remaining_predictions[start_gt:end_gt] = 0 # 检测候选点 (15/45秒) -> 分数打折 # 这里简化处理,实际可以只打折不置零 return selected_events return greedy_event_selection(predictions_2nd_level) ``` ### Daily Normalization (1st Place approach) ```python import numpy as np def daily_normalize(predictions, series_ids): """ 按天归一化预测值 - 利用每天只有1次 onset + 1次 wakeup 的先验 原理: - 每天只有 2 个事件(1 onset + 1 wakeup) - 按天归一化可以使每天的最高预测值具有可比性 """ normalized = predictions.copy() for series_id in np.unique(series_ids): mask = series_ids == series_id daily_preds = predictions[mask] # 按天分组(17280 步 = 1 天) n_days = len(daily_preds) // 17280 for day in range(n_days): start = day * 17280 end = start + 17280 day_preds = daily_preds[start:end] # 归一化到 [0, 1] day_min, day_max = day_preds.min(), day_preds.max() if day_max > day_min: normalized[mask][start:end] = (day_preds - day_min) / (day_max - day_min) return normalized ``` ### Find Peaks 事件检测 ```python from scipy.signal import find_peaks def detect_events_find_peaks(predictions, score_th=0.005, distance=72): """ 使用 find_peaks 检测事件 参数: predictions: 事件概率预测 (shape: [n_steps]) score_th: 分数阈值(低于此值不检测) distance: 最小峰值间隔(步数)72 = 6分钟 返回: events: 检测到的事件索引列表 """ onset_preds = predictions[:, 0] # onset 概率 wakeup_preds = predictions[:, 1] # wakeup 概率 # 检测 onset 峰值 onset_peaks, _ = find_peaks( onset_preds, height=score_th, distance=distance ) # 检测 wakeup 峰值 wakeup_peaks, _ = find_peaks( wakeup_preds, height=score_th, distance=distance ) return { 'onset': onset_peaks, 'wakeup': wakeup_peaks } ``` ### Rolling Mean 平滑 (3rd Place approach) ```python import numpy as np def rolling_mean_smooth(predictions, window=12, center=True): """ 使用滚动均值平滑预测结果 参数: predictions: 原始预测值 window: 窗口大小(12 = 1分钟) center: 是否居中 """ smoothed = np.zeros_like(predictions) for i in range(len(predictions)): start = max(0, i - window // 2) end = min(len(predictions), i + window // 2 + 1) smoothed[i] = predictions[start:end].mean() return smoothed # 然后检测峰值 def detect_events_with_smooth(predictions, window=12, distance=72): """平滑后检测事件""" smoothed = rolling_mean_smooth(predictions, window=window) return detect_events_find_peaks(smoothed, distance=distance) ``` ### 两阶段建模框架 (1st Place approach) ```python def two_level_modeling(train_series, train_events): """ 两阶段建模框架 1st Level: 5秒间隔预测事件概率 2nd Level: 1分钟间隔精化预测 """ # ==================== 1st Level ==================== # 输入:5秒间隔的数据 # 输出:5秒间隔的 onset/wakeup 概率 # 1st Level 模型示例 first_level_models = [ CNNGRUModel(), # CNN + GRU + CNN CNNTransformerModel(), # CNN + GRU + Transformer + CNN LSTMUNetModel(), # LSTM + UNet1d + UNet # ... 更多模型 ] # 训练 1st level for model in first_level_models: model.fit(train_series, train_events) # 生成 1st level 预测(5秒间隔) first_level_preds = [] for model in first_level_models: pred = model.predict(train_series) # shape: [n_steps_5sec, 2] first_level_preds.append(pred) # ==================== 2nd Level ==================== # 输入:1st level 预测 + 原始特征(整合到整分钟) # 输出:1分钟间隔的 onset/wakeup 概率 # 整合 1st level 预测到整分钟 minute_features = aggregate_to_minute(first_level_preds, train_series) # 2nd Level 模型示例 second_level_models = [ LightGBMRegressor(), CatBoostRegressor(), CNNGRUModel(), CNNTransformerModel(), CNNModel() ] # 训练 2nd level for model in second_level_models: model.fit(minute_features, train_events) # 生成 2nd level 预测(1分钟间隔) second_level_preds = [] for model in second_level_models: pred = model.predict(minute_features) # shape: [n_steps_1min, 2] second_level_preds.append(pred) # ==================== 后处理 ==================== # Daily normalization final_preds = np.mean(second_level_preds, axis=0) final_preds = daily_normalize(final_preds, series_ids) # Greedy 事件选择(15/45秒技巧) events = optimize_tolerance_edges(final_preds) return events def aggregate_to_minute(first_level_preds, train_series): """将 5 秒预测整合到 1 分钟""" # 每个 1 分钟包含 12 个 5 秒步 n_steps_minute = len(train_series) // 12 minute_features = [] for i in range(n_steps_minute): start = i * 12 end = start + 12 # 整合 1st level 预测(均值、最大值等) preds_5sec = [p[start:end] for p in first_level_preds] # 整合原始特征(anglez, enmo 的统计量) raw_feats = train_series[start:end] # 合并特征 minute_feat = np.concatenate([ np.mean([p.mean(axis=0) for p in preds_5sec], axis=0), # 预测均值 np.max([p.max(axis=0) for p in preds_5sec], axis=0), # 预测最大值 raw_feats.mean(axis=0), # 原始特征均值 raw_feats.std(axis=0), # 原始特征标准差 ]) minute_features.append(minute_feat) return np.array(minute_features) ``` ### 时间序列特征工程 (基线方案) ```python import pandas as pd import numpy as np def create_sleep_features(series_df): """ 创建睡眠检测特征 基于基线方案(银牌)的特征工程 """ df = series_df.copy() # ========== 传感器特征 ========== # 平滑 + 一阶差分 df['enmo_abs_diff'] = df['enmo'].diff().abs() df['enmo'] = df['enmo_abs_diff'].rolling(window=5, center=True, min_periods=1).mean() df['anglez_abs_diff'] = df['anglez'].diff().abs() df['anglez'] = df['anglez_abs_diff'].rolling(window=5, center=True, min_periods=1).mean() # ========== 时间特征 ========== df['timestamp'] = pd.to_datetime(df['timestamp']) df['hour'] = df['timestamp'].dt.hour df['minute'] = df['timestamp'].dt.minute df['weekday'] = df['timestamp'].dt.weekday df['is_weekend'] = df['weekday'].isin([5, 6]).astype(int) # Sin/Cos 编码(周期性时间) df['hour_sin'] = np.sin(2 * np.pi * df['hour'] / 24) df['hour_cos'] = np.cos(2 * np.pi * df['hour'] / 24) # ========== 滚动特征 ========== for col in ['enmo', 'anglez']: for window in [10, 30, 60]: df[f'{col}_rolling_mean_{window}'] = df[col].rolling(window=window, min_periods=1).mean() df[f'{col}_rolling_std_{window}'] = df[col].rolling(window=window, min_periods=1).std() df[f'{col}_rolling_max_{window}'] = df[col].rolling(window=window, min_periods=1).max() df[f'{col}_rolling_min_{window}'] = df[col].rolling(window=window, min_periods=1).min() # ========== 交互特征 ========== df['anglez_times_enmo'] = df['anglez_abs_diff'] * df['enmo_abs_diff'] df['anglez_div_enmo'] = df['anglez_abs_diff'] / (df['enmo_abs_diff'] + 1e-6) return df ``` ### 时间序列特征提取 | 方法 | 适用场景 | |------|---------| | **原始1D CNN** | 保留时序信息 | | **CWT + 2D CNN** | 需要频域信息 | | **统计特征** | 传统机器学习 | | **Wavelet Scattering** | 信号分解 | --- ## Top 10 Solutions Comparison (前 10 名方案对比分析) > 基于前 10 名解决方案的横向对比分析,提取共性技术和差异创新 ### 架构分类总结 根据整体解决方案,前 10 名可分为两大架构流派: | 架构类型 | 代表排名 | 核心特点 | |---------|---------|---------| | **独立编码器** | 2nd, 3rd, 8th | 分别处理 EEG 和 Spectrogram,后期融合 | | **单一编码器** | 1st, 4th, 5th, 6th, 7th, 9th, 10th | 早期合并信号,统一编码 | ### 前 3 名详细对比 #### 1st Place - Team Sony (yamash, suguuuuu, kfuji, Muku) **核心架构:** 多模型集成 (4人独立方案) | 成员 | 技术 | Score | |------|------|-------| | yamash | 纵向双极导联 + 2D CNN (不同时长) | - | | suguuuuu | CWT + MaxVIT (Morlet 小波) | - | | kfuji | CWT + MaxVIT (Paul 小波) | - | | Muku | 1D CNN 特征 + Superlet CWT + SwinV2 | CV: 0.2229 | **关键技术:** - CWT (0.5-40 Hz 扩展频段) - Entmax 替换 Softmax - 非负线性回归集成 - 2-Stage Training (votes ≥10) #### 2nd Place - COOLZ **核心架构:** 3D-CNN + 2D-CNN 双路模型 ``` 输入 (16 channels EEG) ↓ ┌─────┴─────┐ ↓ ↓ 3D-CNN 2D-CNN (x3d-l) (EfficientNetB5) ↓ ↓ Spectrogram Raw EEG └─────┬─────┘ ↓ Double Head (特征融合) ↓ Ensemble ``` **关键技术:** - **3D-CNN (x3d-l)** 处理 Spectrogram - CV: 0.21, PB: 0.25 - **2D-CNN (EfficientNetB5)** 处理 Raw EEG - PB: 0.28 - **双特征头**:EEG + Spectrum 特征融合 - **不同滤波器**:MNE vs scipy.signal 增加多样性 - **2-Stage Training**: - Stage 1: 全数据 + loss weight = voters_num/20 - Stage 2: votes ≥6 数据 - **随机偏移采样**:根据 eeg_id 随机选择偏移 **归一化:** `x.clip(-1024, 1024) / 32` **最终集成权重:** [0.1, 0.1, 0.2, 0.2, 0.2, 0.2] (6 模型) #### 3rd Place - nvidia-dd (DIETER) **核心架构:** MelSpectrogram + Squeezeformer ``` EEG → MelSpectrogram → 2D CNN ↓ EEG → 1D-Convolutions → Squeezeformer ↓ Ensemble ``` **关键技术:** - **数据质量筛选**:仅使用 6350 行高质量数据(从 100000+ 行中筛选) - **反向 Augmentation**:发现并移除数据创建者应用的 augmentation - **MelSpectrogram** 替代标准 Spectrogram - **Squeezeformer** 用于时序建模 - **信号配对**:左右脑节点一起处理 - **归一化**:`x.clip(-1024, 1024) / 32` ### 共性技术("银弹" - 高分者共同使用) | 技术 | 使用排名 | 说明 | |------|---------|------| | **带通滤波 (0.5-20/40 Hz)** | 1st, 2nd, 3rd | 几乎所有高分者使用 | | **Clip 归一化** | 1st, 2nd, 3rd | `x.clip(-1024, 1024) / 32` | | **2-Stage Training** | 1st, 2nd, 3rd | Stage 1 全数据,Stage 2 高质量样本 | | **Votes ≥10 筛选** | 1st, 2nd, 3rd | 仅用高质量样本评估 | | **Group K-Fold** | 1st, 2nd, 3rd | 按患者分组,防止数据泄露 | | **Ensemble/Stacking** | 1st, 2nd, 3rd | 多模型集成 | | **数据增强** | 1st, 2nd, 3rd | 时间偏移、通道翻转、Mixup | ### 差异创新(各排名者的独特贡献) | 排名 | 独特创新 | 影响 | |------|---------|------| | **1st - Sony** | Entmax 替换 Softmax | LB +0.004 提升 | | **1st - Sony** | Superlet CWT | 最高时频分辨率 | | **2nd - COOLZ** | 3D-CNN 处理 Spectrogram | 保留通道位置信息 | | **2nd - COOLZ** | 双特征头 (EEG + Spectrum) | 多模态融合 | | **3rd - nvidia-dd** | 数据质量筛选 (6350→100000) | 性能提升显著 | | **3rd - nvidia-dd** | 反向 Augmentation | 数据纯净度提升 | | **4th - Cerberus** | 左右对称对比学习 | 位置编码 | | **9th - ishikei** | Contrastive Learning | 特征对比 | ### 归一化方法对比 | 方法 | 支持者 | 效果 | |------|--------|------| | **`x.clip(-1024, 1024) / 32`** | 1st, 2nd, 3rd | 最佳选择 | | **MAD 归一化** | 3rd | 对异常值更鲁棒 | | **Batch/Sample 归一化** | 部分尝试者 | 效果不佳 (3rd 发现) | | **Standardize** | 低排名者 | 不推荐 | ### 时频变换方法对比 | 方法 | 使用排名 | 优点 | 缺点 | |------|---------|------|------| | **CWT** | 1st, 4th, 5th, 6th | 多分辨率,适合非平稳信号 | 需选择小波 | | **Superlet CWT** | 1st | 最高分辨率 | 计算成本高 | | **MelSpectrogram** | 2nd, 3rd | 人耳感知特性 | 频率分辨率固定 | | **STFT** | 7th, 8th, 10th | 简单易实现 | 时频权衡 | ### 集成策略对比 | 排名 | 集成方法 | 模型数 | 权重确定 | |------|---------|--------|---------| | **1st** | 非负线性回归 | 6 (4人) | 自动学习 | | **2nd** | 加权平均 | 6 | 手动调参 | | **3rd** | 简单平均 | 多个 | 均等权重 | ### 验证策略对比 | 策略 | 使用排名 | Votes 阈值 | 说明 | |------|---------|------------|------| | **≥10** | 1st, 2nd, 3rd | ≥10 | 专家 vs 大众一致意见 | | **≥6** | 2nd | ≥6 | 较宽松 | | **≥9** | 部分 | ≥9 | 接近专家标准 | | **加权** | 部分 | 按投票数加权 | 少投票获得更高正则化 | ### 频率范围选择 | 范围 | 使用排名 | 应用场景 | |------|---------|---------| | **0.5-20 Hz** | 标准, 2nd | Kaggle 默认 | | **0.5-40 Hz** | 1st (suguuuuu) | 扩展信息,更佳结果 | | **0.5-50 Hz** | 部分 | 包含更多高频信息 | ### 训练 Epoch 配置 | 排名 | Stage 1 | Stage 2 | 说明 | |------|---------|---------|------| | **1st** | 5 epochs | 15 epochs | 保守选择 | | **2nd** | 15 epochs | 5 epochs | 更长 Stage 1 | | **3rd** | - | - | 单阶段或灵活配置 | ### 最佳实践总结 基于前 10 名对比分析,以下技术是获胜的关键: #### 必选项(银弹技术) 1. **带通滤波 (0.5-20/40 Hz)** 2. **Clip 归一化**:`x.clip(-1024, 1024) / 32` 3. **2-Stage Training**:Stage 1 全数据,Stage 2 高质量样本 4. **Votes ≥10 筛选**:仅用高质量样本评估 5. **Group K-Fold**:按患者分组 6. **Ensemble**:至少 3+ 模型集成 #### 推荐选项(根据情况选择) - **时频分析**:CWT (最佳) > MelSpectrogram > STFT - **归一化**:clip/32 (最佳) > MAD > batch/sample normalize - **集成方法**:非负线性回归 (最佳) > 加权平均 > 简单平均 - **模型架构**:根据数据特征选择 1D/2D/3D CNN #### 创新方向 - **数据质量**:反向 Augmentation,质量筛选 - **稀疏激活**:Entmax 替换 Softmax - **位置编码**:3D-CNN 保留通道信息,左右对称对比 - **特征融合**:双特征头,多模态集成 --- ## Child Mind Institute - Top 10 Solutions Comparison > 基于前 10 名解决方案的横向对比分析,提取共性技术和差异创新 ### 竞赛特点总结 与 HMS 不同,这是一个**事件检测任务**,核心挑战包括: - **稀疏标注**:17280 步中仅 2 步有标签(0.01%) - **分钟偏差**:真实事件总是发生在 hh:mm:00 - **未标注事件**:存在周期性重复数据(缺失标签) - **多 Tolerance AP**:需要同时优化多个容差窗口 ### 前 3 名详细对比 #### 1st Place - shimacos vs sakami vs kami (kami, sakami0000, shimacos) **核心架构:** 两阶段建模 + Greedy 后处理优化 ``` 1st Level (5秒间隔) CNN+GRU+CNN, CNN+GRU+Transformer+CNN, LSTM+UNet1d+UNet, LSTM+UNet1d+UNet, 1dCNN+UNet1d+Transformer ↓ 2nd Level (1分钟间隔) LightGBM, CatBoost, CNN+GRU, CNN+Transformer, CNN ↓ Post Processing (15/45秒技巧) Daily Normalize → Greedy Search → Final Events ``` **关键技术:** - **两阶段建模**:5秒检测 + 1分钟精化 - **衰减目标**:按 tolerance_steps 加权 + epoch 衰减 - **15/45秒技巧**:针对 tolerance 边缘优化 - **Daily Normalization**:按天归一化 2nd level 预测 - **Greedy 后处理**:针对 AP 指标的 greedy search **效果:** Public LB: 0.768 (18th) → Private LB: 0.852 (1st) #### 2nd Place - K-Mat **核心架构:** 三阶段建模 + Error Modeling ``` Stage 1: 事件检测 + 睡眠/清醒分类 多个模型预测 onset/wakeup/asleep 概率 ↓ Stage 2: Error Modeling (LGBM) 基于 1st level 预测,计算 Error → Correctness → Target 将分数差分转为分类任务 ↓ Stage 3: 时刻偏移 + WBF 融合 对 step 做时刻偏移,重新预测 用 WBF 整合结果 ``` **关键技术:** - **Error Modeling**:将差分变化转为分类标签 - **三阶段架构**:检测 → 重打分 → 偏移 - **Minute Embedding**:将 minute_embedding 残差连接到输出层 - **时刻偏移**:应对 15 分钟周期模式 - **WBF 融合**:Weighted Box Fusion #### 3rd Place - cucutzik **核心架构:** 简洁干净的 GRU + UNET + LGB 集成 **关键技术:** - **频率编码**:hour_min_onset, hour_min_wakeup - **序列反转增强**:反转所有序列,CV +0.01 - **目标扩展**:event step 前加2步,后加1步 - **模型融合**:GRU (0.68) + UNET (0.2) + LGB (0.12) - **Rolling Mean 平滑**:center=True,每隔距离取最高预测 - **噪声检测**:相同 hour+step+anglez 重复值即为噪声 ### 共性技术("银弹" - 高分者共同使用) | 技术 | 使用排名 | 说明 | |------|---------|------| | **两阶段建模** | 1st, 2nd | 5秒检测 → 1分钟精化 | | **分钟偏差处理** | 1st, 2nd, 3rd, 5th, 6th | 事件总是发生在整分钟 | | **多模型集成** | 1st, 2nd, 3rd | 至少 5+ 模型 | | **Daily Normalization** | 1st, 3rd | 按天归一化预测值 | | **后处理优化** | 1st, 2nd, 3rd | find_peaks, NMS, greedy search | | **多任务学习** | 2nd, 4th | onset, wakeup, asleep | ### 差异创新(各排名者的独特贡献) | 排名 | 独特创新 | 影响 | |------|---------|------| | **1st** | 15/45秒技巧 | Public 18th → Private 1st | | **1st** | 衰减目标 + epoch 衰减 | 使峰值更尖锐 | | **1st** | Daily Normalization | 利用每天只有2次活动的先验 | | **2nd** | Error Modeling | 将差分转为分类标签 | | **2nd** | Minute Embedding | 残差连接到输出层 | | **3rd** | 序列反转增强 | CV +0.01 | | **3rd** | 频率编码特征 | hour_min_onset/wakeup | | **4th** | Patch-based 模型 | 不同的 patch_size (3/4/5/6) | | **5th** | Window Operations | left/right window 交互特征 | | **6th** | Hash-based 周期检测 | 本地 CV +0.015 | ### 分钟偏差处理对比 | 方法 | 使用排名 | 具体实现 | |------|---------|---------| | **Minute Embedding** | 1st | 残差连接到输出层 | | **频率编码** | 3rd | hour_min_onset, hour_min_wakeup | | **Step 偏移** | 2nd | 偏移 step 重新预测 + WBF | | **标签偏移** | 5th | target shift ~-11 步 | | **特征工程** | 6th | `(step // 12) % 15` | ### 未标注事件处理对比 | 方法 | 使用排名 | 具体实现 | |------|---------|---------| | **周期性检测** | 1st | 降采样 + 相似度计算,标记日周期性 | | **噪声检测** | 3rd | 相同 hour+step+anglez 重复值 | | **样本加权** | 5th | 训练时权重设为 0 | | **Hash 算法** | 6th | 散列和散列图查找重复模式 | | **过滤序列** | 大部分 | 剔除未标注 events 出现多的序列 | ### 后处理策略对比 | 排名 | 方法 | 参数 | 效果 | |------|------|------|------| | **1st** | Greedy + 15/45秒 | 500次迭代 | Public 18th → Private 1st | | **2nd** | Step偏移 + WBF | 多个偏移量 | 显著提升 | | **3rd** | Rolling Mean + find_peaks | window=12, distance=72 | 清晰方案 | | **基线** | find_peaks + NMS | distance=72, IOU=0.995 | 银牌基础 | ### 1st Level 模型对比 | 排名 | 模型数量 | 模型类型 | 集成方式 | |------|---------|---------|---------| | **1st** | 5 | CNN+GRU, CNN+Transformer, LSTM+UNet 等 | 加权平均 | | **2nd** | 多个 | Spec2DCNN, PANNs, Transformer 等 | 融合后处理 | | **3rd** | 10 | 8个GRU + 2个UNET | GRU 0.68 + UNET 0.2 + LGB 0.12 | ### 2nd Level 模型对比 | 排名 | 模型类型 | 输入特征 | 说明 | |------|---------|---------|------| | **1st** | LGB, CatBoost, CNN+GRU 等 | 1st level 预测 + 原始特征 | 整合到整分钟 | | **2nd** | LGBM | Error, Correctness, Top-k Accuracy | 重新打分 | | **3rd** | LGB | 1st level 预测 | 加权融合 | ### 数据增强策略对比 | 方法 | 使用排名 | 效果 | |------|---------|------| | **序列反转** | 3rd | CV +0.01 | | **时间偏移** | 基线 | 标准增强 | | **标签扩展** | 3rd | 前2步+后1步 | | **周期性特征** | 1st | 日周期 flag | ### 验证策略对比 | 策略 | 使用排名 | 说明 | |------|---------|------| | **Group K-Fold** | 1st, 2nd, 3rd | 按 series_id 分组 | | **Stratified (事件数)** | 1st | 事件数 qcut(10) 分层 | | **全部 fold 训练** | 1st | 单 fold 结果不稳定,需全 fold | | **Trust CV** | 1st | Public 数据少且分布相似 | ### 最佳实践总结 基于前 10 名对比分析,以下技术是获胜的关键: #### 必选项(银弹技术) 1. **两阶段建模**:5秒检测 → 1分钟精化 2. **分钟偏差处理**:使用 minute 相关特征 3. **Daily Normalization**:按天归一化预测值 4. **多模型集成**:至少 5+ 模型 5. **后处理优化**:find_peaks, NMS, greedy search 6. **Group K-Fold**:按 series_id 分组 #### 推荐选项(根据情况选择) - **后处理方法**:Greedy (最佳) > WBF > NMS > find_peaks - **2nd level 模型**:LGB/CatBoost > Neural Networks - **分钟偏差处理**:Minute Embedding (最佳) > 频率编码 > step 偏移 - **数据增强**:序列反转 > 时间偏移 #### 创新方向 - **评估指标优化**:针对 tolerance 的 greedy search - **Error Modeling**:将差分转为分类标签 - **衰减目标**:按 tolerance 加权 + epoch 衰减 - **周期性检测**:识别未标注 events --- ## CMI - Detect Behavior with Sensor Data - Top 10 Solutions Comparison > 基于日语总结和前排方案的综合分析,提取共性技术和差异创新 ### 竞赛特点总结 与之前竞赛不同,这是一个**多模态时序行为识别**任务,核心挑战包括: - **多模态传感器融合**:IMU + THM + TOF - **严重数据缺失**:TOF 约 60% 缺失(-1),THM 约 3-4% 缺失 - **细粒度分类**:18 个手势类别,区分 BFRB vs 日常动作 - **个体约束**:每个 subject × gesture × orientation 只出现一次 - **测试集变化**:约 50% 序列仅有 IMU 数据 ### 前 3 名详细对比 #### 1st Place - Devin | Ogurtsov | zyz (Andrey Ogurtsov, Devin, zyz) **核心架构:** 多成员协作 + 多模型集成 ``` Devin's part: TOF 处理: 2×2 正方形 9 个区域平均 TOF-only 模型也加入集成 Ogurtsov's part: 数据清理: 删除 gesture 不存在的序列 特征工程: 从 acc(去除重力后)提取 35 个特征 模型: LSTM, Attention, CNN 组合 增强: timeshift, timistretch 集成: 每 Fold 选择 3 run 中最佳结果 推理: 序列延伸降低模型相关性 zyz part: RNN + CNN1D 组合 ``` **关键技术:** - **TOF 图像化**:2×2 正方形 9 个区域平均降维 - **TOF-only 集成**:单独使用 TOF 数据的模型也加入集成 - **数据清理**:删除无效序列(如 SUBJ_019262, SUBJ_045235) - **特征工程**:35 个特征从 acc(去除重力后)提取 - **多模型集成**:LSTM + Attention + CNN 组合 - **推理优化**:序列延伸降低模型相关性,提升集成效果 #### 2nd Place - cucutzik **核心架构:** 4 模型系统 + 阶段感知 Attention ``` 4 个独立模型: IMU rotation 缺失/存在 × THM/TOF 缺失/存在 = 4 组合 核心创新: 四元数 6D 表现 (避免不连续性) Residual SE-CNN Block + Attention 关键技巧: 阶段感知 Attention: 预测 3 类阶段概率 (移动中/目标位置/手势执行中) 每个阶段独立 Attention,概率加权 相位 Mixup: 按阶段分割序列 同阶段内进行 Mixup "moves to target" 阶段对齐结束点 Pseudo Label: 测试数据生成 pseudo-label 小 LR (5e-5) 1 step fine-tune 后处理: 匈牙利算法全局最优标签分配 约束: subject × gesture × orientation 唯一性 ``` **关键技术:** - **四元数 6D 表现**:避免四元数不连续性问题 - **阶段感知 Attention**:分阶段独立建模和加权 - **相位 Mixup**:按阶段分割后同阶段内 Mixup - **Pseudo Label**:测试数据生成伪标签进行微调 - **匈牙利算法**:全局最优标签分配(利用个体约束) #### 3rd Place - Team RIST **核心架构:** 2D-CNN + 图像化时序 ``` 数据预处理: 四元数平滑处理 符号反转扩展 Block 扩展 模型: MaxViT, ConvNeXt-V2, EfficientNetB5 等 2D-CNN 输入: 适当尺寸的图像 增强: 世界坐标系 Z 轴旋转 (-60° 到 60°) 本地坐标系 Y 轴旋转 (-7° 到 7°) 后处理: 匈牙利算法全局最优标签分配 ``` **关键技术:** - **时序图像化**:时序数据转换为图像,使用 2D-CNN - **四元数处理**:平滑、符号反转、Block 扩展 - **双重旋转增强**:世界坐标 + 本地坐标旋转 - **多 2D-CNN 集成**:MaxViT + ConvNeXt + EfficientNetB5 ### 共性技术("银弹" - 高分者共同使用) | 技术 | 使用排名 | 说明 | |------|---------|------| | **个体约束利用** | 1st, 2nd, 3rd, 4th | subject × gesture × orientation 唯一性 | | **数据增强** | 1st, 2nd, 3rd, 4th, 6th... | mixup, cutmix, timeshift, rotation | | **异常数据处理** | 几乎所有 | SUBJ_019262, SUBJ_045235 删除或转换 | | **左手系 → 右手系对齐** | 大部分 | 将左手系传感器数据转换为右手系 | | **多模型集成** | 1st, 2nd, 3rd | 至少 3+ 模型 | | **阶段感知建模** | 2nd, 3rd, 6th | 利用 Transition/Pause/Gesture 结构 | | **BatchNorm(无归一化)** | 9th | 不使用 scaler,用 BatchNorm | ### 差异创新(各排名者的独特贡献) | 排名 | 独特创新 | 影响 | |------|---------|------| | **1st** | TOF 图像化(2×2 区域平均) | 简化 TOF 处理 | | **1st** | TOF-only 模型集成 | 单独 TOF 也有价值 | | **1st** | 序列延伸推理 | 降低模型相关性 | | **2nd** | 四元数 6D 表现 | 避免不连续性 | | **2nd** | 阶段感知 Attention | 分阶段独立建模 | | **2nd** | 相位 Mixup | 同阶段内 Mixup,对齐结束点 | | **2nd** | Pseudo Label fine-tune | 测试数据微调 | | **3rd** | 时序转图像 | 使用 2D-CNN 处理 | | **3rd** | 双重旋转增强 | 世界坐标 + 本地坐标 | | **6th** | gesture segment U-Net | 估计手势时间段 | | **9th** | 正向 + 反向模型 | 同时训练标准分类和反向分类 | | **13th** | 双向 Mamba | 长期时序依赖建模 | | **13th** | Hard Margin Loss | 针对困难样本的损失 | | **13th** | Hard Mining | 困难样本采样率提升 | ## Child Mind Institute - 数据洞察与分析 ### 数据特征理解 #### 极度稀疏的标签 **发现:** 17280 步(24小时)中仅有 2 步有标签 - **标签密度**:0.01%(1/10000) - **事件类型**:onset(入睡)+ wakeup(觉醒) - **标注粒度**:每夜 1 个 onset + 1 个 wakeup **含义:** - 传统逐帧分类方法不适用 - 需要特殊的目标创建策略(衰减目标) - 后处理比模型预测更重要 - 数据增强对缓解稀疏性至关重要 **策略:** - **衰减目标**:按 tolerance_steps 创建衰减的标签分布 - **多任务学习**:同时预测 onset, wakeup, asleep - **后处理优化**:find_peaks, NMS, greedy search - **数据增强**:序列反转、时间偏移等 #### 分钟偏差模式 **发现:** 真实事件总是发生在 hh:mm:00 整分钟时刻 **数据分布(YOURI MATIOUNINE 发现):** ``` 标签分钟数 % 15 的分布: - 0分钟:明显峰值 - 3分钟:明显峰值 - 7分钟:明显峰值 - 11分钟:明显峰值 - 其他分钟:很少出现 ``` **含义:** - 手动标注导致精度有限 - 存在 15 分钟的周期性模式 - 模型应该学习这种模式 **策略对比:** | 排名 | 处理方法 | 具体实现 | |------|---------|---------| | **1st** | Minute Embedding | 残差连接到输出层 | | **2nd** | Step 偏移 | 对预测 step 做偏移后重新预测 | | **3rd** | 频率编码 | hour_min_onset, hour_min_wakeup | | **5th** | 标签偏移 | target shift ~-11 步 | | **6th** | 特征工程 | `(step // 12) % 15` | #### 未标注事件问题 **发现(YOURI MATIOUNINE):** 很多序列有明显的 events 未被标注 **两类情况:** 1. **日周期性重复**:缺失 events 的夜晚跟前 24 小时数据完全一样 - 推测:组织方用历史正常数据填补了缺失数据 2. **无法解释的缺失**:没有明显规律的缺失标注 **处理策略对比:** | 排名 | 处理方法 | 具体实现 | |------|---------|---------| | **1st** | 周期性检测 + flag | 降采样 + 相似度计算,标记日周期性 | | **3rd** | 噪声检测 | 相同 hour+step+anglez 重复值即为噪声 | | **5th** | 样本加权 | 训练时权重设为 0 | | **6th** | Hash 算法 | 散列和散列图查找重复模式,本地 CV +0.015 | | **大部分** | 过滤序列 | 剔除未标注 events 出现多的序列 | **1st Place 的周期性检测方法:** ```python def detect_periodicity(series): """检测 24 小时周期性重复""" # 1. 降采样 downsampled = series[::12] # 5秒 → 1分钟 # 2. 分割序列(按天) n_days = len(downsampled) // 1440 # 1440 = 24小时 daily_chunks = [downsampled[i*1440:(i+1)*1440] for i in range(n_days)] # 3. 计算相邻天的相似度 for i in range(n_days - 1): # 方法1: 元素级比较 similarity = np.mean(daily_chunks[i] == daily_chunks[i+1]) # 方法2: 余弦相似度 cos_sim = np.dot(daily_chunks[i], daily_chunks[i+1]) / ( np.linalg.norm(daily_chunks[i]) * np.linalg.norm(daily_chunks[i+1]) ) if similarity > threshold or cos_sim > threshold: return True # 检测到周期性 return False ``` #### 多 Tolerance AP 评估指标 **评估方式:** ```python tolerances = [1, 3, 5, 7.5, 10, 12.5, 15, 20, 25, 30] # 分钟 # 对每个 tolerance,计算 AP # 最终分数 = mean(各tolerance AP) × mean(onset AP, wakeup AP) ``` **关键洞察(1st Place):** - **预测 hh:mm:00 不好**:tolerance 5,10,15,20,25,30 时边缘漏检 - **预测 hh:mm:30 不好**:tolerance 7.5, 12.5 时边缘漏检 - **预测 hh:mm:15 或 hh:mm:45 最佳**:覆盖所有 tolerance **原理示意:** ``` 00:23:15 ← 检测事件(15秒) ← tolerance 7.5 分 → 00:23:00 ← 真实事件(0秒) ← tolerance 7.5 分 → 00:22:45 如果检测事件在 00:23:00,则 tolerance 7.5 的右边缘会漏检 如果检测事件在 00:23:15 或 00:22:45,则正好覆盖 ``` #### 15分钟周期性模式 **发现:** events 以 15 分钟为周期重复出现 **数据分布:** - **峰值分钟**:0, 3, 7, 11(间隔 3-4 分钟) - **周期**:15 分钟 - **含义**:可能与定时检查或记录习惯有关 **应对策略:** | 排名 | 策略 | 说明 | |------|------|------| | **1st** | 15/45秒技巧 | 无论 1-29秒 还是31-59秒,选15/45秒代表 | | **2nd** | Step偏移 | 对step做多个偏移,覆盖所有可能时刻 | | **3rd** | 频率编码 | hour_min_onset, hour_min_wakeup | ### 数据质量评估框架 基于前排方案,建立数据质量评估维度: | 维度 | 评估方法 | 低质量指标 | 处理策略 | |------|---------|-----------|---------| | **周期性重复** | 降采样+相似度 | 与前24小时完全相同 | 标记 periodicity flag | | **噪声重复** | hour+step+anglez计数 | 重复值>1 | 标记 noise | | **未标注events** | 统计每夜events数 | <2 events | 过滤或降权 | | **数据异常** | enmo统计 | enmo值异常大 | clip到1 | ### 关键数据洞察总结 1. **极度稀疏标签**:需要衰减目标和后处理优化 2. **分钟偏差是关键**:所有前排方案都处理了这个问题 3. **未标注events普遍存在**:周期性检测可识别 4. **多tolerance AP需要特殊优化**:15/45秒技巧是制胜关键 5. **评估指标与数据分布不匹配**:需要针对tolerance优化 6. **Daily Normalization有效**:利用每天只有2次活动的先验 7. **15分钟周期性模式**:step偏移或频率编码可利用 ### 事件检测任务的最佳实践 与分类任务不同,事件检测任务的特殊考虑: | 方面 | 分类任务 | 事件检测任务 | |------|---------|-------------| | **目标创建** | 单标签 | 衰减目标(按tolerance加权) | | **评估指标** | Accuracy/F1 | 多tolerance AP | | **后处理** | Threshold | find_peaks, NMS, Greedy | | **模型集成** | 概率平均 | 两阶段建模 | | **验证策略** | K-Fold | Group K-Fold + 全fold训练 | --- ## CMI - Detect Behavior 数据洞察与分析 ### 数据特征理解 #### 多模态传感器数据 **三种传感器类型:** | 传感器 | 数据维度 | 特征 | 缺失率 | |-------|---------|------|--------| | **IMU** | 加速度计(x,y,z) + 陀螺仪(x,y,z) | 运动和旋转 | 无缺失 | | **THM** | 5个温度传感器 | 温度分布 | ~3-4% | | **TOF** | 5个8×8传感器阵列 | 距离映射 | ~60% | **IMU (Inertial Measurement Unit):** - 6 列:`X_accel`, `Y_accel`, `Z_accel`, `X_gyro`, `Y_gyro`, `Z_gyro` - **重力分量**:加速度计包含重力,需去除 - **四元数**:`orientation_X`, `orientation_Y`, `orientation_Z`, `orientation_W` - 表示设备旋转姿态 - **不连续性问题**:四元数在表示相同旋转时有多个值(q和-q表示相同旋转) - **解决方案**:使用旋转矩阵前两列(6D连续表示) **THM (Thermopile):** - 5 列:`thermopile_0` ~ `thermopile_4` - 温度传感器,用于检测物体接近 - **缺失标记**:-1 表示缺失 - **缺失率较低**:约3-4% **TOF (Time-of-Flight):** - 320 列:`tof_0` ~ `tof_319`(5个8×8阵列) - 距离传感器,检测物体到设备距离 - **缺失标记**:-1 表示缺失 - **缺失严重**:约60%的数据为-1 - **图像化处理**:将8×8阵列降采样为2×2特征图(1st Place创新) #### 严重数据缺失问题 **缺失分布:** ``` TOF: ~60% 缺失 (-1 标记) THM: ~3-4% 缺失 (-1 标记) IMU: 无缺失 ``` **前排处理策略:** | 排名 | TOF 处理 | THM 处理 | |------|---------|---------| | **1st** | 2×2 pooling后标记缺失mask | 简单插值或mask | | **2nd** | 特征工程提取有效点统计量 | 类似TOF处理 | | **3rd** | 转图像,缺失填0 | 不使用或简单处理 | | **其他** | 丢弃或mask | 丢弃或mask | **1st Place 的 TOF 处理创新:** ```python def tof_2x2_pooling_with_mask(tof_data): """ TOF 数据 2×2 pooling + 缺失 mask """ # 每个 8×8 传感器 for sensor_idx in range(5): sensor = tof_data[:, sensor_idx*64:(sensor_idx+1)*64] sensor = sensor.reshape(-1, 8, 8) # 2×2 pooling pooled = sensor.reshape(-1, 4, 2, 2).mean(axis=(2, 3)) # 缺失 mask mask = (sensor == -1).reshape(-1, 4, 2, 2).any(axis=(2, 3)) # 组合:特征 + mask features[:, sensor_idx*4:(sensor_idx+1)*4] = pooled features[:, 20+sensor_idx*4:20+(sensor_idx+1)*4] = mask return features ``` #### 个体约束利用 **关键约束:** 每个 subject × gesture × orientation 组合只出现一次 **含义:** - 训练集中没有重复的 subject × gesture × orientation - 验证时可以确保预测结果也满足这个约束 - 可以用匈牙利算法做全局最优标签分配 **前排利用策略:** | 排名 | 利用方法 | 说明 | |------|---------|------| | **1st** | 匈牙利算法 | 全局最优分配,提升 LB 0.01 | | **2nd** | 阶段感知建模 | 利用三阶段结构 | | **其他** | 个体特征 embedding | 添加 subject embedding | **匈牙利算法实现(1st Place):** ```python from scipy.optimize import linear_sum_assignment def hungarian_post_process(predictions, subject_ids, sequence_ids): """ 利用 subject × gesture × orientation 唯一约束 """ # 对于每个 subject for subject in unique(subject_ids): # 获取该 subject 的所有预测 mask = subject_ids == subject preds = predictions[mask] seqs = sequence_ids[mask] # 构建代价矩阵:-log(概率) cost_matrix = -np.log(preds + 1e-10) # 匈牙利算法:找到最优分配 row_ind, col_ind = linear_sum_assignment(cost_matrix) # 更新预测结果 for i, j in zip(row_ind, col_ind): predictions[mask][i] = np.zeros(n_classes) predictions[mask][i][j] = 1.0 return predictions ``` #### 三阶段结构 **发现:** 行为序列有明显的三阶段结构 ``` Transition → Pause → Gesture ``` **阶段特征:** | 阶段 | 持续时间 | 特征 | 识别要点 | |------|---------|------|---------| | **Transition** | 变化 | 从上一个状态移动到手势位置 | 运动幅度大 | | **Pause** | 短暂 | 手势开始前的准备 | 运动幅度小 | | **Gesture** | 重复 | 核心行为模式(如咬指甲) | 周期性模式 | **前排利用策略:** | 排名 | 利用方法 | 说明 | |------|---------|------| | **2nd** | 阶段感知 Attention | 每个阶段独立的 attention 权重 | | **6th** | U-Net分割 | 将手势阶段作为分割任务 | | **其他** | 特征工程 | 添加阶段分类特征 | **2nd Place 阶段感知 Attention:** ```python class PhaseAwareAttention(nn.Module): """ 阶段感知 Attention - 每个阶段独立建模 """ def __init__(self, d_model, n_heads=8): super().__init__() # 3个阶段 embedding self.phase_emb = nn.Embedding(3, d_model) # 每个阶段独立的 attention self.transition_attn = nn.MultiheadAttention(d_model, n_heads) self.pause_attn = nn.MultiheadAttention(d_model, n_heads) self.gesture_attn = nn.MultiheadAttention(d_model, n_heads) def forward(self, x, phase_labels): # phase_labels: [batch, seq_len] ∈ {0, 1, 2} batch, seq_len, d_model = x.shape outputs = [] for t in range(seq_len): phase = phase_labels[:, t] # [batch] if phase == 0: # Transition attn_out, _ = self.transition_attn(x[:, t:t+1], x, x) elif phase == 1: # Pause attn_out, _ = self.pause_attn(x[:, t:t+1], x, x) else: # Gesture attn_out, _ = self.gesture_attn(x[:, t:t+1], x, x) outputs.append(attn_out) return torch.cat(outputs, dim=1) ``` #### BFRB vs 非BFRB 类别分布 **18个手势类别:** | 类别 | BFRB类型 | 典型行为 | |------|---------|---------| | 0-7 | BFRB | 咬指甲、拉头发、抠皮肤等 | | 8-17 | 非BFRB | 拍手、挥手、其他手势 | **分布特点:** - **训练集**:BFRB 和非BFRB 数量相近 - **个体差异**:不同 subject 的手势偏好不同 - **方向差异**:同一手势不同方向的表现不同 **处理策略:** - **Phase-aware Mixup**:仅在 Gesture 阶段进行 mixup(2nd Place) - **个体 normalization**:按 subject 做归一化 - **类别平衡**:确保每个类别有足够样本 #### 测试集变化 **关键发现:** 测试集约50%的序列仅有 IMU 数据 **含义:** - 不能过度依赖 TOF 和 THM 特征 - 模型必须能够仅用 IMU 数据做出预测 - 需要训练仅用 IMU 的模型作为集成成员 **前排应对策略:** | 排名 | 应对方法 | |------|---------| | **1st** | 训练IMU-only模型,集成时加权 | | **2nd** | 4个模型:IMU-only, IMU+TOF, IMU+THM, All | | **3rd** | TOF填0处理,但效果受限 | | **其他** | 简单丢弃缺失传感器 | **推荐策略:** ```python # 训练时模拟测试集情况 def get_model_input(data): """ 根据可用传感器选择模型输入 """ has_tof = (data['tof'] != -1).any() has_thm = (data['thm'] != -1).any() if has_tof and has_thm: return model_all(data['imu'], data['tof'], data['thm']) elif has_tof: return model_imu_tof(data['imu'], data['tof']) elif has_thm: return model_imu_thm(data['imu'], data['thm']) else: return model_imu(data['imu']) ``` #### 异常数据识别 **两个异常 subject:** | Subject | 问题 | 处理策略 | |---------|------|---------| | **SUBJ_019262** | 数据异常,预测困难 | 训练时过滤或降权 | | **SUBJ_045235** | 数据异常,预测困难 | 训练时过滤或降权 | **识别方法:** - 训练集上该 subject 的 loss 异常高 - 交叉验证该 subject 的预测准确率低 - 可视化该 subject 的传感器数据,发现异常模式 **处理代码:** ```python # 异常 subject 黑名单 ANOMALY_SUBJECTS = ['SUBJ_019262', 'SUBJ_045235'] def filter_anomaly_subjects(dataframe): """ 过滤异常 subject """ mask = ~dataframe['subject'].isin(ANOMALY_SUBJECTS) return dataframe[mask] ``` #### 左手系 vs 右手系对齐 **发现:** 测试集存在左手和右手两种设备朝向 **问题:** - 左手系和右手系的传感器读数方向相反 - 四元数表示旋转的方式不同 - 直接混合训练会引入噪声 **解决方案(前排通用):** ```python def align_right_handed_system(data): """ 左手系 → 右手系对齐 """ # 翻转陀螺仪的 x, y 轴 data['X_gyro'] = -data['X_gyro'] data['Y_gyro'] = -data['Y_gyro'] # 调整四元数(取决于具体定义) # 这里假设是绕 z 轴旋转 180 度 data['orientation_X'] = -data['orientation_X'] data['orientation_Y'] = -data['orientation_Y'] return data ``` ### 数据质量评估框架 基于前排方案,建立数据质量评估维度: | 维度 | 评估方法 | 低质量指标 | 处理策略 | |------|---------|-----------|---------| | **传感器缺失** | 统计-1值比例 | TOF>50%, THM>5% | mask处理或训练IMU-only模型 | | **异常subject** | 按subject统计loss | loss > threshold | 过滤SUBJ_019262, SUBJ_045235 | | **设备朝向** | 检测左右手系 | 四元数和陀螺仪方向 | 统一到右手系 | | **三阶段一致性** | 检测阶段标签 | 阶段跳变 | 利用三阶段结构特征 | ### 关键数据洞察总结 1. **多模态融合是关键**:IMU + THM + TOF,但测试集仅50%有完整数据 2. **TOF 缺失严重(60%)**:需要创新处理(2×2 pooling + mask) 3. **个体约束必须利用**:subject × gesture × orientation 唯一约束可用匈牙利算法 4. **三阶段结构重要**:Transition/Pause/Gesture,阶段感知建模有效 5. **四元数不连续性**:需转换为6D连续表示(旋转矩阵前两列) 6. **测试集只有IMU数据**:必须训练IMU-only模型作为集成成员 7. **异常数据需处理**:SUBJ_019262和SUBJ_045235应该过滤或降权 8. **左手系右手系对齐**:统一到右手系避免噪声 ### 多模态时间序列分类的最佳实践 与单模态分类任务不同,多模态任务的特殊考虑: | 方面 | 单模态任务 | 多模态任务 | |------|-----------|-----------| | **特征提取** | 单一特征工程 | 每个模态独立提取后融合 | | **模型架构** | 单一编码器 | 多编码器或早期融合 | | **缺失处理** | 插值或丢弃 | mask处理或模态specific模型 | | **数据增强** | 简单增强 | 模态感知增强(Phase-aware Mixup) | | **后处理** | 阈值或NMS | 利用约束(匈牙利算法) |