{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"},{"sourceId":12875524,"sourceType":"datasetVersion","datasetId":7680402},{"sourceId":12940407,"sourceType":"datasetVersion","datasetId":8150866}],"dockerImageVersionId":31041,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, json, joblib, numpy as np, pandas as pd\nfrom pathlib import Path\nimport warnings \nwarnings.filterwarnings(\"ignore\")\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.optim import Adam\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom sklearn.utils.class_weight import compute_class_weight\nimport polars as pl\nfrom tqdm import tqdm\nimport torchmetrics\nimport random\nfrom scipy.spatial.transform import Rotation as R\nfrom scipy.fft import fft, dct\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:46.723692Z","iopub.execute_input":"2025-09-02T15:06:46.723884Z","iopub.status.idle":"2025-09-02T15:06:59.335765Z","shell.execute_reply.started":"2025-09-02T15:06:46.723864Z","shell.execute_reply":"2025-09-02T15:06:59.335141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.optim.lr_scheduler import CosineAnnealingWarmRestarts\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom sklearn.utils.class_weight import compute_class_weight\nimport polars as pl\nfrom tqdm import tqdm\nimport torchmetrics\nimport random","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.339217Z","iopub.execute_input":"2025-09-02T15:06:59.339430Z","iopub.status.idle":"2025-09-02T15:06:59.343498Z","shell.execute_reply.started":"2025-09-02T15:06:59.339411Z","shell.execute_reply":"2025-09-02T15:06:59.342676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"▶ imports ready · pytorch {torch.__version__} · device: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.344284Z","iopub.execute_input":"2025-09-02T15:06:59.344591Z","iopub.status.idle":"2025-09-02T15:06:59.366201Z","shell.execute_reply.started":"2025-09-02T15:06:59.344565Z","shell.execute_reply":"2025-09-02T15:06:59.365665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def seed_everything(seed=1234):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    \nseed_everything(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.366842Z","iopub.execute_input":"2025-09-02T15:06:59.367034Z","iopub.status.idle":"2025-09-02T15:06:59.384575Z","shell.execute_reply.started":"2025-09-02T15:06:59.367019Z","shell.execute_reply":"2025-09-02T15:06:59.383831Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"FEATURE_NAMES = [\n    'acc_x', 'acc_y', 'acc_z',\n    'rot_w', 'rot_x', 'rot_y', 'rot_z',\n    'acc_mag', 'rot_angle', 'acc_mag_jerk', 'rot_angle_vel',\n    'linear_acc_x', 'linear_acc_y', 'linear_acc_z', 'linear_acc_mag', 'linear_acc_mag_jerk',\n    'angular_vel_x', 'angular_vel_y', 'angular_vel_z',\n    'angular_distance',\n]\nCATEGORICAL_FEATURES = []\nNUMERICAL_FEATURES = [f for f in FEATURE_NAMES if f not in CATEGORICAL_FEATURES]\ntarget_gestures = [\n    'Above ear - pull hair',\n    'Cheek - pinch skin',\n    'Eyebrow - pull hair',\n    'Eyelash - pull hair',\n    'Forehead - pull hairline',\n    'Forehead - scratch',\n    'Neck - pinch skin',\n    'Neck - scratch',\n]\nnon_target_gestures = [\n    'Write name on leg',\n    'Wave hello',\n    'Glasses on/off',\n    'Text on phone',\n    'Write name in air',\n    'Feel around in tray and pull out an object',\n    'Scratch knee/leg skin',\n    'Pull air toward your face',\n    'Drink from bottle/cup',\n    'Pinch knee/leg skin'\n]\nall_classes = target_gestures + non_target_gestures\nmaps = {}\nfor k,cl in enumerate(all_classes):\n    maps[cl] = k\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nimport joblib\nfrom scipy.spatial.transform import Rotation as R\ndef preprocess_sequence(df_seq: pd.DataFrame, feature_cols: list, scaler: StandardScaler):\n    \"\"\"Normalizes and cleans the time series sequence\"\"\"\n    mat = df_seq[feature_cols].ffill().bfill().fillna(0).values\n    return scaler.transform(mat).astype('float32')\n\ndef pad_sequences_torch(sequences, maxlen, padding='post', truncating='post', value=0.0):\n    \"\"\"PyTorch equivalent of Keras pad_sequences\"\"\"\n    result = []\n    for seq in sequences:\n        if len(seq) >= maxlen:\n            if truncating == 'post':\n                seq = seq[:maxlen]\n            else:\n                seq = seq[-maxlen:]\n        else:\n            pad_len = maxlen - len(seq)\n            if padding == 'post':\n                seq = np.concatenate([seq, np.full((pad_len, seq.shape[1]), value)])\n            else:  # 'pre'\n                seq = np.concatenate([np.full((pad_len, seq.shape[1]), value), seq])\n        result.append(seq)\n    return np.array(result, dtype=np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.385369Z","iopub.execute_input":"2025-09-02T15:06:59.385606Z","iopub.status.idle":"2025-09-02T15:06:59.393855Z","shell.execute_reply.started":"2025-09-02T15:06:59.385589Z","shell.execute_reply":"2025-09-02T15:06:59.393190Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from scipy.spatial.transform import Rotation as R\nos.environ['NO_ALBUMENTATIONS_UPDATE'] = '1'\ndef seed_everything(seed: int):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\nseed_everything(42)\ndef preprocess_sequence(df_seq: pd.DataFrame, feature_cols: list, scaler: StandardScaler):\n    \"\"\"Normalizes and cleans the time series sequence\"\"\"\n    mat = df_seq[feature_cols].ffill().bfill().fillna(0).values\n    return scaler.transform(mat).astype('float32')\n\ndef pad_sequences_torch(sequences, maxlen, padding='post', truncating='post', value=0.0):\n    \"\"\"PyTorch equivalent of Keras pad_sequences\"\"\"\n    result = []\n    for seq in sequences:\n        if len(seq) >= maxlen:\n            if truncating == 'post':\n                seq = seq[:maxlen]\n            else:\n                seq = seq[-maxlen:]\n        else:\n            pad_len = maxlen - len(seq)\n            if padding == 'post':\n                seq = np.concatenate([seq, np.full((pad_len, seq.shape[1]), value)])\n            else:  # 'pre'\n                seq = np.concatenate([np.full((pad_len, seq.shape[1]), value), seq])\n        result.append(seq)\n    return np.array(result, dtype=np.float32)\n# 从acc中移除重力\ndef remove_gravity_from_acc(acc_data, rot_data):\n    if isinstance(acc_data, pd.DataFrame):\n        acc_values = acc_data[['acc_x', 'acc_y', 'acc_z']].values\n    else:\n        acc_values = acc_data\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = acc_values.shape[0]\n    linear_accel = np.zeros_like(acc_values)\n    \n    gravity_world = np.array([0, 0, 9.81])\n\n    for i in range(num_samples):\n        if np.all(np.isnan(quat_values[i])) or np.all(np.isclose(quat_values[i], 0)):\n            linear_accel[i, :] = acc_values[i, :] \n            continue\n\n        try:\n            rotation = R.from_quat(quat_values[i])\n            gravity_sensor_frame = rotation.apply(gravity_world, inverse=True)\n            linear_accel[i, :] = acc_values[i, :] - gravity_sensor_frame\n        except ValueError:\n             linear_accel[i, :] = acc_values[i, :]\n    return linear_accel\n\n# 计算角度\ndef calculate_angular_velocity_from_quat(rot_data, time_delta=1/200): # Assuming 200Hz sampling rate\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = quat_values.shape[0]\n    angular_vel = np.zeros((num_samples, 3))\n\n    for i in range(num_samples - 1):\n        q_t = quat_values[i]\n        q_t_plus_dt = quat_values[i+1]\n\n        if np.all(np.isnan(q_t)) or np.all(np.isclose(q_t, 0)) or \\\n           np.all(np.isnan(q_t_plus_dt)) or np.all(np.isclose(q_t_plus_dt, 0)):\n            continue\n\n        try:\n            rot_t = R.from_quat(q_t)\n            rot_t_plus_dt = R.from_quat(q_t_plus_dt)\n\n            # Calculate the relative rotation\n            delta_rot = rot_t.inv() * rot_t_plus_dt\n            # Convert delta rotation to angular velocity vector\n            # The rotation vector (Euler axis * angle) scaled by 1/dt\n            # is a good approximation for small delta_rot\n            angular_vel[i, :] = delta_rot.as_rotvec() / time_delta\n        except ValueError:\n            # If quaternion is invalid, angular velocity remains zero\n            pass\n    return angular_vel\n    \n# 计算角度距离\ndef calculate_angular_distance(rot_data):\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = quat_values.shape[0]\n    angular_dist = np.zeros(num_samples)\n\n    for i in range(num_samples - 1):\n        q1 = quat_values[i]\n        q2 = quat_values[i+1]\n\n        if np.all(np.isnan(q1)) or np.all(np.isclose(q1, 0)) or \\\n           np.all(np.isnan(q2)) or np.all(np.isclose(q2, 0)):\n            angular_dist[i] = 0 # Или np.nan, в зависимости от желаемого поведения\n            continue\n        try:\n            r1 = R.from_quat(q1)\n            r2 = R.from_quat(q2)\n            relative_rotation = r1.inv() * r2\n            angle = np.linalg.norm(relative_rotation.as_rotvec())\n            angular_dist[i] = angle\n        except ValueError:\n            angular_dist[i] = 0\n            pass\n    return angular_dist\ndef feature_engineering(train_df):\n    # IMU magnitude\n    train_df['acc_mag'] = np.sqrt(train_df['acc_x']**2 + train_df['acc_y']**2 + train_df['acc_z']**2)\n    # IMU angle\n    train_df['rot_angle'] = 2 * np.arccos(train_df['rot_w'].clip(-1, 1))\n    # IMU jerk, angular velocity\n    train_df['acc_mag_jerk'] = train_df.groupby('sequence_id')['acc_mag'].diff().fillna(0)\n    train_df['rot_angle_vel'] = train_df.groupby('sequence_id')['rot_angle'].diff().fillna(0)\n    # Remove gravity\n    def get_linear_accel(df):\n        res = remove_gravity_from_acc(\n            df[['acc_x', 'acc_y', 'acc_z']],\n            df[['rot_x', 'rot_y', 'rot_z', 'rot_w']]\n        )\n        res = pd.DataFrame(res, columns=['linear_acc_x', 'linear_acc_y', 'linear_acc_z'], index=df.index)\n        return res\n    linear_accel_df = train_df.groupby('sequence_id').apply(get_linear_accel, include_groups=False)\n    linear_accel_df = linear_accel_df.droplevel('sequence_id')\n    train_df = train_df.join(linear_accel_df)\n    train_df['linear_acc_mag'] = np.sqrt(train_df['linear_acc_x']**2 + train_df['linear_acc_y']**2 + train_df['linear_acc_z']**2)\n    train_df['linear_acc_mag_jerk'] = train_df.groupby('sequence_id')['linear_acc_mag'].diff().fillna(0)\n\n    # Calc angular velocity\n    def calc_angular_velocity(df):\n        res = calculate_angular_velocity_from_quat( df[['rot_x', 'rot_y', 'rot_z', 'rot_w']] )\n        res = pd.DataFrame(res, columns=['angular_vel_x', 'angular_vel_y', 'angular_vel_z'], index=df.index)\n        return res\n    angular_velocity_df = train_df.groupby('sequence_id').apply(calc_angular_velocity, include_groups=False)\n    angular_velocity_df = angular_velocity_df.droplevel('sequence_id')\n    train_df = train_df.join(angular_velocity_df)\n\n    # Calculating angular distance\n    def calc_angular_distance(df):\n        res = calculate_angular_distance(df[['rot_x', 'rot_y', 'rot_z', 'rot_w']])\n        res = pd.DataFrame(res, columns=['angular_distance'], index=df.index)\n        return res\n    angular_distance_df = train_df.groupby('sequence_id').apply(calc_angular_distance, include_groups=False)\n    angular_distance_df = angular_distance_df.droplevel('sequence_id')\n    train_df = train_df.join(angular_distance_df)\n    train_df[FEATURE_NAMES] = train_df[FEATURE_NAMES].ffill().bfill().fillna(0).values.astype('float32')\n    return train_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.394678Z","iopub.execute_input":"2025-09-02T15:06:59.394865Z","iopub.status.idle":"2025-09-02T15:06:59.417495Z","shell.execute_reply.started":"2025-09-02T15:06:59.394850Z","shell.execute_reply":"2025-09-02T15:06:59.416905Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_fix_imu(df):\n    acc_body = df[['acc_x', 'acc_y', 'acc_z']].values\n    quats = df[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    num_points = len(acc_body)\n    gravity = np.array([0, 0, 9.81])  # 重力向量 (Z轴向上)\n    positions = np.zeros((num_points, 3))\n    for i in range(num_points):\n        if quats[i][0]==0:\n            continue\n        q = quats[i] / np.linalg.norm(quats[i])\n        rotation = R.from_quat([ q[0], q[1], q[2], q[3]])  # 注意scipy的wxyz顺序\n        # # 本体加速度转世界坐标系并去除重力\n        positions[i] = rotation.apply(acc_body[i]) - gravity\n    res = pd.DataFrame(positions, columns=['remove_g_x', 'remove_g_y', 'remove_g_z'], index=df.index)\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.418215Z","iopub.execute_input":"2025-09-02T15:06:59.418711Z","iopub.status.idle":"2025-09-02T15:06:59.433929Z","shell.execute_reply.started":"2025-09-02T15:06:59.418696Z","shell.execute_reply":"2025-09-02T15:06:59.433364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 计算角度\ndef calculate_angular_velocity_from_quat_ori(df): # Assuming 200Hz sampling rate\n    if isinstance(df, pd.DataFrame):\n        quat_values = df[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    num_samples = quat_values.shape[0]\n    angular_vel = np.zeros((num_samples, 3))\n    q_t = quat_values[0]\n    for i in range(1, num_samples):\n        q_t_plus_dt = quat_values[i]\n\n        if np.all(np.isnan(q_t)) or np.all(np.isclose(q_t, 0)) or \\\n           np.all(np.isnan(q_t_plus_dt)) or np.all(np.isclose(q_t_plus_dt, 0)):\n            continue\n\n        try:\n            rot_t = R.from_quat(q_t)\n            rot_t_plus_dt = R.from_quat(q_t_plus_dt)\n\n            # Calculate the relative rotation\n            delta_rot = rot_t.inv() * rot_t_plus_dt\n            # Convert delta rotation to angular velocity vector\n            # The rotation vector (Euler axis * angle) scaled by 1/dt\n            # is a good approximation for small delta_rot\n            angular_vel[i, :] = delta_rot.as_rotvec()\n        except ValueError:\n            # If quaternion is invalid, angular velocity remains zero\n            pass\n    res = pd.DataFrame(angular_vel, columns=['ang_ori_x', 'ang_ori_y', 'ang_ori_z'], index=df.index)\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.436277Z","iopub.execute_input":"2025-09-02T15:06:59.436477Z","iopub.status.idle":"2025-09-02T15:06:59.448713Z","shell.execute_reply.started":"2025-09-02T15:06:59.436461Z","shell.execute_reply":"2025-09-02T15:06:59.448143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# convert eular\nimport numpy as np\nfrom scipy.spatial.transform import Rotation as R\ndef calculate_euler_angles_from_quat(rot_data, euler_order='xyz'):\n    # 处理输入\n    if isinstance(rot_data, pd.DataFrame):\n        quat_values = rot_data[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    else:\n        quat_values = rot_data\n\n    num_samples = quat_values.shape[0]\n    euler_angles = np.zeros((num_samples, 3))\n\n    for i in range(num_samples):\n        q = quat_values[i]\n        # 检查四元数是否有效\n        if np.all(np.isnan(q)) or np.all(np.isclose(q, 0)):\n            continue\n        try:\n            # 将四元数转换为旋转对象\n            rot = R.from_quat(q)\n            # 转换为欧拉角（角度制）\n            euler_angles[i, :] = rot.as_euler(euler_order, degrees=True)\n        except ValueError:\n            # 如果四元数无效，保持角度为零\n            pass\n    res = pd.DataFrame(euler_angles, columns=['eular_vel_x', 'eular_vel_y', 'eular_vel_z'], index=rot_data.index)\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.449334Z","iopub.execute_input":"2025-09-02T15:06:59.449588Z","iopub.status.idle":"2025-09-02T15:06:59.464307Z","shell.execute_reply.started":"2025-09-02T15:06:59.449564Z","shell.execute_reply":"2025-09-02T15:06:59.463637Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_rot(df):\n    acc_body = df[['acc_x', 'acc_y', 'acc_z']].values\n    quats = df[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    num_points = len(acc_body)\n    gravity = np.array([0, 0, 9.81])  # 重力向量 (Z轴向上)\n    rotvecs = np.zeros((num_points, 4))\n    for i in range(num_points-1):\n        q_t = quats[i]\n        q_t_plus_dt = quats[i+1]\n\n        if np.all(np.isnan(q_t)) or np.all(np.isclose(q_t, 0)) or \\\n           np.all(np.isnan(q_t_plus_dt)) or np.all(np.isclose(q_t_plus_dt, 0)):\n            continue\n        try:\n            rot_t = R.from_quat(q_t)\n            rot_t_plus_dt = R.from_quat(q_t_plus_dt)\n            delta_rot = rot_t.inv() * rot_t_plus_dt     \n            \n            # q = quats[i] / np.linalg.norm(quats[i])\n            # rotation = R.from_quat([ q[0], q[1], q[2], q[3]])  # 注意scipy的wxyz顺序\n            \n            rotvecs[i][:3] = delta_rot.as_rotvec()\n            rotvecs[i][3] = np.linalg.norm(delta_rot.as_rotvec())\n        except ValueError:\n            # 如果四元数无效，保持角度为零\n            pass\n    res = pd.DataFrame(rotvecs, columns=['rot_new_x', 'rot_new_y', 'rot_new_z','rot_new_norm'], index=df.index)\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.465013Z","iopub.execute_input":"2025-09-02T15:06:59.465303Z","iopub.status.idle":"2025-09-02T15:06:59.481075Z","shell.execute_reply.started":"2025-09-02T15:06:59.465276Z","shell.execute_reply":"2025-09-02T15:06:59.480473Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_imu_dct(df):\n    acc_body = df[['acc_x', 'acc_y', 'acc_z']].values\n    quats = df[['rot_x', 'rot_y', 'rot_z', 'rot_w']].values\n    num_points = len(acc_body)\n    positions = np.zeros((num_points, 7))\n    for k, col in enumerate(['acc_x', 'acc_y', 'acc_z','rot_x', 'rot_y', 'rot_z', 'rot_w']):\n        dct_data = dct(df[col].values, type=2, norm='ortho')\n        positions[:,k] = dct_data\n    res = pd.DataFrame(positions, columns=['acc_x_dct', 'acc_y_dct', 'acc_z_dct','rot_x_dct', 'rot_y_dct', 'rot_z_dct', 'rot_w_dct'], index=df.index)\n    return res","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.481674Z","iopub.execute_input":"2025-09-02T15:06:59.481850Z","iopub.status.idle":"2025-09-02T15:06:59.497097Z","shell.execute_reply.started":"2025-09-02T15:06:59.481837Z","shell.execute_reply":"2025-09-02T15:06:59.496551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nsys.path.append(\"/kaggle/input/cmimodel\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.497683Z","iopub.execute_input":"2025-09-02T15:06:59.497912Z","iopub.status.idle":"2025-09-02T15:06:59.509711Z","shell.execute_reply.started":"2025-09-02T15:06:59.497889Z","shell.execute_reply":"2025-09-02T15:06:59.509021Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n# from transformers import BertConfig, BertModel\n# 一样\nfrom torch.autograd import Function\n\nclass AttentionLayer(nn.Module):\n    def __init__(self, hidden_dim):\n        super().__init__()\n        self.attention = nn.Linear(hidden_dim, 1)\n    def forward(self, x):\n        # x shape: (batch, seq_len, hidden_dim)\n        scores = torch.tanh(self.attention(x))  # (batch, seq_len, 1)\n        weights = F.softmax(scores.squeeze(-1), dim=1)  # (batch, seq_len)\n        context = torch.sum(x * weights.unsqueeze(-1), dim=1)  # (batch, hidden_dim)\n        return context","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.510488Z","iopub.execute_input":"2025-09-02T15:06:59.510738Z","iopub.status.idle":"2025-09-02T15:06:59.524142Z","shell.execute_reply.started":"2025-09-02T15:06:59.510725Z","shell.execute_reply":"2025-09-02T15:06:59.523536Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(f\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\",nrows=100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.524787Z","iopub.execute_input":"2025-09-02T15:06:59.525039Z","iopub.status.idle":"2025-09-02T15:06:59.565016Z","shell.execute_reply.started":"2025-09-02T15:06:59.525021Z","shell.execute_reply":"2025-09-02T15:06:59.564550Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = feature_engineering(train)\nlinear_accel_df = train.groupby('sequence_id').apply(get_rot, include_groups=False)\nlinear_accel_df = linear_accel_df.droplevel('sequence_id')\ntrain = train.join(linear_accel_df)\nlinear_accel_df = train.groupby('sequence_id').apply(calculate_angular_velocity_from_quat_ori, include_groups=False)\nlinear_accel_df = linear_accel_df.droplevel('sequence_id')\ntrain = train.join(linear_accel_df)\ntrain['ang_diff_x'] = train.groupby('sequence_id')['angular_vel_x'].diff().fillna(0)\ntrain['ang_diff_y'] = train.groupby('sequence_id')['angular_vel_y'].diff().fillna(0)\ntrain['ang_diff_z'] = train.groupby('sequence_id')['angular_vel_z'].diff().fillna(0)\ntrain['ang_diff_the'] = train.groupby('sequence_id')['rot_angle_vel'].diff().fillna(0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.565606Z","iopub.execute_input":"2025-09-02T15:06:59.565768Z","iopub.status.idle":"2025-09-02T15:06:59.685887Z","shell.execute_reply.started":"2025-09-02T15:06:59.565755Z","shell.execute_reply":"2025-09-02T15:06:59.685356Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_gaussian_kernel(size: int, channels: int):\n    \"\"\"Create gaussian kernel for smoothing\"\"\"\n    kernel = torch.tensor([np.exp(-(i - size//2)**2/2) for i in range(size)], dtype=torch.float32)\n    kernel = kernel / kernel.sum()\n    kernel = kernel.repeat(channels, 1, 1)  # (out_channels, in_channels/groups, kernel_size)\n    return kernel\n\nk = 15\ngrouped = train.groupby('sequence_id')\nfor fe in (['rot',\"angular_vel\"]):\n    for dir in ('x', 'y', 'z'):\n        col_name = f'{fe}_{dir}'\n        weight = create_gaussian_kernel(k, 1)  # 1 channel, cause process 1 column per iteration\n        lpf_results = []\n        for _, group in grouped:\n            # convert to tensor and add dimentions (batch, channel, length)\n            data = torch.tensor(group[col_name].values, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n            # apply convolution\n            lpf = F.conv1d(data, weight, padding=k//2)\n            lpf_results.append(lpf.squeeze().numpy())\n        \n        # concatenate results\n        lpf_series = pd.concat([pd.Series(x, index=group.index) for x, (_, group) in zip(lpf_results, grouped)])\n        train[f'{fe}_lpf_{dir}'] = lpf_series\n        train[f'{fe}_hpf_{dir}'] = train[col_name] - train[f'{fe}_lpf_{dir}']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.686521Z","iopub.execute_input":"2025-09-02T15:06:59.686734Z","iopub.status.idle":"2025-09-02T15:06:59.721689Z","shell.execute_reply.started":"2025-09-02T15:06:59.686718Z","shell.execute_reply":"2025-09-02T15:06:59.721143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"grouped = train.groupby('sequence_id')\n\nfor fe in (['acc','linear_acc']):\n    for dir in ('x', 'y', 'z', 'mag'):\n        col_name = f'{fe}_{dir}'\n        weight = create_gaussian_kernel(k, 1)  # 1 channel, cause process 1 column per iteration\n        lpf_results = []\n        for _, group in grouped:\n            # convert to tensor and add dimentions (batch, channel, length)\n            data = torch.tensor(group[col_name].values, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n            # apply convolution\n            lpf = F.conv1d(data, weight, padding=k//2)\n            lpf_results.append(lpf.squeeze().numpy())\n        \n        # concatenate results\n        lpf_series = pd.concat([pd.Series(x, index=group.index) for x, (_, group) in zip(lpf_results, grouped)])\n        train[f'{fe}_lpf_{dir}'] = lpf_series\n        train[f'{fe}_hpf_{dir}'] = train[col_name] - train[f'{fe}_lpf_{dir}']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.722297Z","iopub.execute_input":"2025-09-02T15:06:59.722532Z","iopub.status.idle":"2025-09-02T15:06:59.748559Z","shell.execute_reply.started":"2025-09-02T15:06:59.722502Z","shell.execute_reply":"2025-09-02T15:06:59.747993Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"target_gestures = [\n    'Above ear - pull hair',\n    'Cheek - pinch skin',\n    'Eyebrow - pull hair',\n    'Eyelash - pull hair',\n    'Forehead - pull hairline',\n    'Forehead - scratch',\n    'Neck - pinch skin',\n    'Neck - scratch',\n]\nnon_target_gestures = [\n    'Write name on leg',\n    'Wave hello',\n    'Glasses on/off',\n    'Text on phone',\n    'Write name in air',\n    'Feel around in tray and pull out an object',\n    'Scratch knee/leg skin',\n    'Pull air toward your face',\n    'Drink from bottle/cup',\n    'Pinch knee/leg skin'\n]\nall_classes = target_gestures + non_target_gestures","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.749238Z","iopub.execute_input":"2025-09-02T15:06:59.749477Z","iopub.status.idle":"2025-09-02T15:06:59.753154Z","shell.execute_reply.started":"2025-09-02T15:06:59.749457Z","shell.execute_reply":"2025-09-02T15:06:59.752551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"gesture_classes = {}\nfor i,k in enumerate(all_classes):\n    gesture_classes[i] = k","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.753801Z","iopub.execute_input":"2025-09-02T15:06:59.754166Z","iopub.status.idle":"2025-09-02T15:06:59.767502Z","shell.execute_reply.started":"2025-09-02T15:06:59.754138Z","shell.execute_reply":"2025-09-02T15:06:59.766804Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pad_sequences_torch(sequences, maxlen, padding='post', truncating='post',value=0.0):\n    \"\"\"PyTorch equivalent of Keras pad_sequences\"\"\"\n    result = []\n    for seq in sequences:\n        if len(seq) >= maxlen:\n            if truncating == 'post':\n                seq = seq[:maxlen]\n            else:\n                seq = seq[-maxlen:]\n        else:\n            pad_len = maxlen - len(seq)\n            if padding == 'post':\n                seq = np.concatenate([seq, np.full((pad_len, seq.shape[1]), value)])\n            else:  # 'pre'\n                seq = np.concatenate([np.full((pad_len, seq.shape[1]), value), seq])\n        result.append(seq)\n    return np.array(result, dtype=np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.768245Z","iopub.execute_input":"2025-09-02T15:06:59.768797Z","iopub.status.idle":"2025-09-02T15:06:59.781706Z","shell.execute_reply.started":"2025-09-02T15:06:59.768776Z","shell.execute_reply":"2025-09-02T15:06:59.781030Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"meta_cols = {'gesture', 'gesture_int', 'sequence_type', 'behavior', 'orientation', \"orientation_id\", \"fold\", 'row_id', 'subject', 'phase', 'sequence_id', 'sequence_counter'}\nfeature_cols = [c for c in train.columns if c not in meta_cols]\nimu_cols = [c for c in feature_cols if not (c.startswith('thm_') or c.startswith('tof_'))]\ntof_cols = [c for c in feature_cols if c.startswith('thm_') or c.startswith('tof_')]\nprint(f\"  IMU {len(imu_cols)} | TOF/THM {len(tof_cols)} | total {len(feature_cols)} features\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.782304Z","iopub.execute_input":"2025-09-02T15:06:59.782469Z","iopub.status.idle":"2025-09-02T15:06:59.799209Z","shell.execute_reply.started":"2025-09-02T15:06:59.782449Z","shell.execute_reply":"2025-09-02T15:06:59.798564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"imu_cols=['acc_x',\n 'acc_y',\n 'acc_z',\n 'rot_w',\n 'rot_x',\n 'rot_y',\n 'rot_z', # 7\n          \n'acc_mag',\n'acc_mag_jerk',\n'rot_angle',\n'rot_angle_vel',  # 4\n\n \n 'linear_acc_x',\n 'linear_acc_y',\n 'linear_acc_z',\n 'linear_acc_mag',\n 'linear_acc_mag_jerk', # 5\n \n 'angular_vel_x',\n 'angular_vel_y',\n 'angular_vel_z',\n 'angular_distance', # 4\n \n 'ang_diff_x',\n 'ang_diff_y',\n 'ang_diff_z',\n 'ang_diff_the',\n 'ang_ori_x',\n 'ang_ori_y',\n 'ang_ori_z',\n 'rot_new_x',\n 'rot_new_y',\n 'rot_new_z',\n 'rot_new_norm', # 11\n          \n 'rot_hpf_x',\n 'rot_hpf_y',\n 'rot_hpf_z',\n 'angular_vel_hpf_x',\n 'angular_vel_hpf_y',\n 'angular_vel_hpf_z',\n 'acc_hpf_x',\n 'acc_hpf_y',\n 'acc_hpf_z',\n 'acc_hpf_mag',\n 'linear_acc_hpf_x',\n 'linear_acc_hpf_y',\n 'linear_acc_hpf_z',\n 'linear_acc_hpf_mag', # 14 \n\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.799853Z","iopub.execute_input":"2025-09-02T15:06:59.800157Z","iopub.status.idle":"2025-09-02T15:06:59.813694Z","shell.execute_reply.started":"2025-09-02T15:06:59.800135Z","shell.execute_reply":"2025-09-02T15:06:59.813125Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"feature_cols = imu_cols","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.814366Z","iopub.execute_input":"2025-09-02T15:06:59.815068Z","iopub.status.idle":"2025-09-02T15:06:59.831621Z","shell.execute_reply.started":"2025-09-02T15:06:59.815044Z","shell.execute_reply":"2025-09-02T15:06:59.830943Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Make sure gesture_classes exists in both modes\ncount = 0\npad_len = 256\nn_classes = 18\nimu_dim = 20\ntof_dim = 325","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.832296Z","iopub.execute_input":"2025-09-02T15:06:59.832484Z","iopub.status.idle":"2025-09-02T15:06:59.846985Z","shell.execute_reply.started":"2025-09-02T15:06:59.832471Z","shell.execute_reply":"2025-09-02T15:06:59.846329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AttentionLayer(nn.Module):\n    def __init__(self, hidden_dim):\n        super().__init__()\n        self.attention = nn.Linear(hidden_dim, 1)\n    def forward(self, x):\n        scores = torch.tanh(self.attention(x))  # (batch, seq_len, 1)\n        weights = F.softmax(scores.squeeze(-1), dim=1)  # (batch, seq_len)\n        context = torch.sum(x * weights.unsqueeze(-1), dim=1)  # (batch, hidden_dim)\n        return context\n        \nclass SEBlock(nn.Module):\n    def __init__(self, channels, reduction=1):\n        super().__init__()\n        self.squeeze = nn.AdaptiveAvgPool1d(1)\n        self.excitation = nn.Sequential(\n            nn.Linear(channels, channels // reduction, bias=False),\n            nn.ReLU(inplace=True),\n            nn.Linear(channels // reduction, channels, bias=False),\n            nn.Sigmoid()\n        )\n        \n    def forward(self, x):\n        b, c, _ = x.size()\n        y = self.squeeze(x).view(b, c)\n        y = self.excitation(y).view(b, c, 1)\n        return x * y.expand_as(x)\n        \n# 一样 加了一个maxpool和dropout\n\nclass ResidualSECNNBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size, pool_size=2, dropout=0.3, weight_decay=1e-4):\n        super().__init__()\n        # First conv block\n        self.conv1 = nn.Conv1d(in_channels, out_channels, kernel_size, padding=kernel_size//2, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels, kernel_size, padding=kernel_size//2, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        self.se = SEBlock(out_channels)\n        \n        # Shortcut connection\n        self.shortcut = nn.Sequential()\n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, 1, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        \n        self.pool = nn.MaxPool1d(pool_size)\n        self.dropout = nn.Dropout(dropout)\n        \n    def forward(self, x):\n        shortcut = self.shortcut(x)\n        # First conv\n        out = F.relu(self.bn1(self.conv1(x)))\n        # Second conv\n        out = self.bn2(self.conv2(out))\n        # SE block\n        out = self.se(out)\n        \n        # Add shortcut\n        out += shortcut\n        out = F.relu(out)\n        # Pool and dropout\n        # out = self.pool(out)\n        out = self.dropout(out)\n        return out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.847744Z","iopub.execute_input":"2025-09-02T15:06:59.847976Z","iopub.status.idle":"2025-09-02T15:06:59.867736Z","shell.execute_reply.started":"2025-09-02T15:06:59.847955Z","shell.execute_reply":"2025-09-02T15:06:59.867126Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(self.allch, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim, 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n        \n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one], dim=-1)\n\n        clssf.append(self.finalallcls(attended_trans))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return attended_one, logits, clssf, pre\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.871476Z","iopub.execute_input":"2025-09-02T15:06:59.871692Z","iopub.status.idle":"2025-09-02T15:06:59.895423Z","shell.execute_reply.started":"2025-09-02T15:06:59.871679Z","shell.execute_reply":"2025-09-02T15:06:59.894914Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"modeldet = IMUModel([7,4,5,4,11],18).to(device)\nmodeldet.load_state_dict(torch.load(\"/kaggle/input/cmimodel/bets_phasedet.pt\"))\nmodeldet.eval();","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:06:59.896071Z","iopub.execute_input":"2025-09-02T15:06:59.896307Z","iopub.status.idle":"2025-09-02T15:07:01.024804Z","shell.execute_reply.started":"2025-09-02T15:06:59.896288Z","shell.execute_reply":"2025-09-02T15:07:01.024023Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AttentionLayer(nn.Module):\n    def __init__(self, hidden_dim):\n        super().__init__()\n        self.attention = nn.Linear(hidden_dim, 1)\n    def forward(self, x):\n        scores = torch.tanh(self.attention(x))  # (batch, seq_len, 1)\n        weights = F.softmax(scores.squeeze(-1), dim=1)  # (batch, seq_len)\n        context = torch.sum(x * weights.unsqueeze(-1), dim=1)  # (batch, hidden_dim)\n        return context\n        \nclass SEBlock(nn.Module):\n    def __init__(self, channels, reduction=1):\n        super().__init__()\n        self.squeeze = nn.AdaptiveAvgPool1d(1)\n        self.excitation = nn.Sequential(\n            nn.Linear(channels, channels // reduction, bias=False),\n            nn.ReLU(inplace=True),\n            nn.Linear(channels // reduction, channels, bias=False),\n            nn.Sigmoid()\n        )\n        \n    def forward(self, x):\n        b, c, _ = x.size()\n        y = self.squeeze(x).view(b, c)\n        y = self.excitation(y).view(b, c, 1)\n        return x * y.expand_as(x)\n        \n# 一样 加了一个maxpool和dropout\n\nclass ResidualSECNNBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size, pool_size=2, dropout=0.3, weight_decay=1e-4):\n        super().__init__()\n        # First conv block\n        self.conv1 = nn.Conv1d(in_channels, out_channels, kernel_size, padding=kernel_size//2, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels, kernel_size, padding=kernel_size//2, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        self.se = SEBlock(out_channels)\n        \n        # Shortcut connection\n        self.shortcut = nn.Sequential()\n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, 1, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        \n        self.pool = nn.MaxPool1d(pool_size)\n        self.dropout = nn.Dropout(dropout)\n        \n    def forward(self, x):\n        shortcut = self.shortcut(x)\n        # First conv\n        out = F.relu(self.bn1(self.conv1(x)))\n        # Second conv\n        out = self.bn2(self.conv2(out))\n        # SE block\n        out = self.se(out)\n        \n        # Add shortcut\n        out += shortcut\n        out = F.relu(out)\n        # Pool and dropout\n        # out = self.pool(out)\n        out = self.dropout(out)\n        return out\nclass IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return attended_one, logits, clssf, pre\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:01.025775Z","iopub.execute_input":"2025-09-02T15:07:01.026144Z","iopub.status.idle":"2025-09-02T15:07:01.251499Z","shell.execute_reply.started":"2025-09-02T15:07:01.026120Z","shell.execute_reply":"2025-09-02T15:07:01.250812Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_imus = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_837.pt\",\n    \"/kaggle/input/cmimodel/bets_1_837.pt\",\n    \"/kaggle/input/cmimodel/bets_2_837.pt\",\n    \"/kaggle/input/cmimodel/bets_3_837.pt\",\n    \"/kaggle/input/cmimodel/bets_4_837.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_imu = IMUModel([7,4,5,4,11,14],18).to(device)\n    model_imu.load_state_dict(checkpoint)\n    model_imu.eval();\n    model_imus.append(model_imu)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:01.252247Z","iopub.execute_input":"2025-09-02T15:07:01.252682Z","iopub.status.idle":"2025-09-02T15:07:13.238825Z","shell.execute_reply.started":"2025-09-02T15:07:01.252664Z","shell.execute_reply":"2025-09-02T15:07:13.238093Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return finalatten, logits, clssf, phasemask\n        return logits, clssf, phasemask\n        \nclass TwoBranchModel_IMU_THM_TOF(nn.Module):\n    def __init__(self, imu_ind, n_classes, fold=0):\n        super().__init__()\n        self.imu_dim = 31\n        self.tof_dim = 320\n        self.imu_ind = imu_ind\n        the_dim = 5\n        self.the_dim = the_dim\n        self.n_classes = n_classes\n        \n        indim = 128\n        self.num_branches = len(imu_ind)\n        \n        self.allch = np.sum(self.imu_ind)\n\n        \n        self.model_imu = IMUModel(self.imu_ind,18)\n\n        ################################TOF BLOCK#########################\n        # self.tof_block = nn.Sequential(\n        #         ResidualSECNNBlock(320 + 31 + 5, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )\n        # self.tof_block2 = nn.Sequential(\n        #         ResidualSECNNBlock(64 + self.allch, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )        \n        # self.tof_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        # self.tof_gru_dropout = nn.Dropout(0.4)\n        # self.tof_attention = AttentionLayer(indim)\n        # self.tof_cls_conv1d = nn.Sequential(\n        #         nn.Linear(indim, 256, bias=False),\n        #         nn.BatchNorm1d(256),\n        #         nn.Dropout(0.5),\n        #         nn.Linear(256, n_classes)\n        # )\n        \n        self.tof_encoder = nn.Sequential(\n            nn.Conv3d(5, 32, kernel_size=(3, 3, 3), padding=1),  # [B, 32, 256, 8, 8]\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 32, 128, 4, 4]\n\n            nn.Conv3d(32, 64, kernel_size=(3, 3, 3), padding=1),  # [B, 64, 128, 4, 4]\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 64, 64, 2, 2]\n\n            nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=1),  # [B, 128, 64, 2, 2]\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d((1, 1, 1)),  # [B, 128, 1, 1, 1]\n            nn.Flatten()\n        )\n        \n        # Thermal\n        self.the_block = nn.Sequential(\n                ResidualSECNNBlock(the_dim, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.the_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.the_gru_dropout = nn.Dropout(0.4)\n        self.the_attention = AttentionLayer(indim)\n\n        \n        self.tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.the_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        self.imuprecls = nn.Sequential(\n            nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 4*indim, bias=False),\n            nn.BatchNorm1d(4*indim),\n            nn.Dropout(0.5),\n        )\n        \n        self.imucls = nn.Sequential(\n            nn.Linear(4*indim , 2*indim, bias=False),\n            nn.BatchNorm1d(2*indim),\n            nn.Dropout(0.5),\n            nn.Linear(2*indim, n_classes)\n        )\n        \n        # Dense layers\n        self.dense1 = nn.Linear(4*indim + indim + indim , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n    def forward(self, allx, phasemask):\n        \n        B, T, D = allx.shape\n        imux = allx[:,:,:self.allch]\n        tofx = allx[:,:,self.allch:]\n        \n        # IMU=======================================================\n        finalatten, logits, clssf, phasemask = self.model_imu(imux[:,:,:self.allch], phasemask, True)\n        finalatten = self.imuprecls(finalatten)\n        \n        # THE======================================================\n        the = tofx[:,:,:5]\n        the = the.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        x3 = self.the_block(the)\n        x3 = x3.transpose(1, 2)\n        x3, _ = self.the_gru(x3)\n        x3 = self.the_gru_dropout(x3)\n        attendedthe = self.the_attention(x3)\n        clssf.append(self.the_cls(attendedthe))\n\n        # TOF=====================================================\n        tof = tofx[:,:,5:]\n        # tof1d = tofx[:,:,5:].transpose(1,2)\n        tof = tof.view(B,T, 5, 8, 8)\n        tof = tof.permute(0,2,1,3,4)\n        attendedtof = self.tof_encoder(tof)\n        clssf.append(self.tof_cls(attendedtof))\n        clssf.append(self.imucls(finalatten))\n        \n        attendedfinal = torch.cat([finalatten, attendedtof, attendedthe],dim=1)\n        # 分类\n        x = F.relu(self.bn_dense1(self.dense1(attendedfinal)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        return logits, clssf\n        # clssf.append(logits)\n        # weightclsemb = torch.cat(clssf, dim=-1)\n        # return logits, clssf, attendedfinal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:13.239761Z","iopub.execute_input":"2025-09-02T15:07:13.240091Z","iopub.status.idle":"2025-09-02T15:07:13.279861Z","shell.execute_reply.started":"2025-09-02T15:07:13.240071Z","shell.execute_reply":"2025-09-02T15:07:13.279297Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_710.pt\",\n    \"/kaggle/input/cmimodel/bets_1_710.pt\",\n    \"/kaggle/input/cmimodel/bets_2_710.pt\",\n    \"/kaggle/input/cmimodel/bets_3_710.pt\",\n    \"/kaggle/input/cmimodel/bets_4_710.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:13.280680Z","iopub.execute_input":"2025-09-02T15:07:13.280939Z","iopub.status.idle":"2025-09-02T15:07:24.842593Z","shell.execute_reply.started":"2025-09-02T15:07:13.280916Z","shell.execute_reply":"2025-09-02T15:07:24.841988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls3 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_775.pt\",\n    \"/kaggle/input/cmimodel/bets_1_775.pt\",\n    \"/kaggle/input/cmimodel/bets_2_775.pt\",\n    \"/kaggle/input/cmimodel/bets_3_775.pt\",\n    \"/kaggle/input/cmimodel/bets_4_775.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls3.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:24.843609Z","iopub.execute_input":"2025-09-02T15:07:24.843831Z","iopub.status.idle":"2025-09-02T15:07:38.303268Z","shell.execute_reply.started":"2025-09-02T15:07:24.843813Z","shell.execute_reply":"2025-09-02T15:07:38.302681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n        self.embeddingcls = nn.Sequential(\n                nn.Linear(self.allch * indim + indim + self.num_branches * indim, 2*indim, bias=False),\n                nn.BatchNorm1d(2*indim),\n                nn.Dropout(0.5),\n                )\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        attended_list = []\n\n        oneattended_list = []\n\n        pre = []\n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n\n        \n        # all_embedding = out\n        pre.append(out)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n\n        \n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n\n        all_embedding = torch.cat(pre, dim=-1) # B * T * D\n        all_embedding = self.embeddingcls(all_embedding)\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return finalatten, logits, clssf, phasemask,all_embedding\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:38.304063Z","iopub.execute_input":"2025-09-02T15:07:38.304277Z","iopub.status.idle":"2025-09-02T15:07:38.335383Z","shell.execute_reply.started":"2025-09-02T15:07:38.304261Z","shell.execute_reply":"2025-09-02T15:07:38.334737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TwoBranchModel_IMU_THM_TOF(nn.Module):\n    def __init__(self, imu_ind, n_classes, fold=0):\n        super().__init__()\n        self.imu_dim = 31\n        self.tof_dim = 320\n        self.imu_ind = imu_ind\n        the_dim = 5\n        self.the_dim = the_dim\n        self.n_classes = n_classes\n        \n        indim = 128\n        self.num_branches = len(imu_ind)\n        \n        self.allch = np.sum(self.imu_ind)\n\n        \n        self.model_imu = IMUModel(self.imu_ind,18)\n\n        ################################TOF BLOCK#########################\n        # self.tof_block = nn.Sequential(\n        #         ResidualSECNNBlock(320 + 31 + 5, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )\n        # self.tof_block2 = nn.Sequential(\n        #         ResidualSECNNBlock(64 + self.allch, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )        \n        # self.tof_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        # self.tof_gru_dropout = nn.Dropout(0.4)\n        # self.tof_attention = AttentionLayer(indim)\n        # self.tof_cls_conv1d = nn.Sequential(\n        #         nn.Linear(indim, 256, bias=False),\n        #         nn.BatchNorm1d(256),\n        #         nn.Dropout(0.5),\n        #         nn.Linear(256, n_classes)\n        # )\n        \n        self.tof_encoder = nn.Sequential(\n            nn.Conv3d(5, 32, kernel_size=(3, 3, 3), padding=1),  # [B, 32, 256, 8, 8]\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 32, 128, 4, 4]\n\n            nn.Conv3d(32, 64, kernel_size=(3, 3, 3), padding=1),  # [B, 64, 128, 4, 4]\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 64, 64, 2, 2]\n\n            nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=1),  # [B, 128, 64, 2, 2]\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d((1, 1, 1)),  # [B, 128, 1, 1, 1]\n            nn.Flatten()\n        )\n        \n        # Thermal\n        self.the_block = nn.Sequential(\n                ResidualSECNNBlock(the_dim, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.the_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.the_gru_dropout = nn.Dropout(0.4)\n        self.the_attention = AttentionLayer(indim)\n\n        \n        self.tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.the_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        self.imuprecls = nn.Sequential(\n            nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 4*indim, bias=False),\n            nn.BatchNorm1d(4*indim),\n            nn.Dropout(0.5),\n        )\n        \n        self.imucls = nn.Sequential(\n            nn.Linear(4*indim , 2*indim, bias=False),\n            nn.BatchNorm1d(2*indim),\n            nn.Dropout(0.5),\n            nn.Linear(2*indim, n_classes)\n        )\n        \n        # Dense layers\n        self.dense1 = nn.Linear(4*indim + indim + indim +indim, 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        ######\n        ## tof encoder 2d\n        self.tof_encoder_2d =  nn.Sequential(\n            nn.Conv2d(5, 32, kernel_size=(3, 3), padding=1),  # [B, 256, 32, 8, 8]\n            nn.BatchNorm2d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d((2, 2)),\n\n            nn.Conv2d(32, 64, kernel_size=(3, 3), padding=1),  # [B, 256, 32, 4, 4]\n            nn.BatchNorm2d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool2d((2, 2)),\n\n            nn.Conv2d(64, 128, kernel_size=(3, 3), padding=1),  # [B, 256, 32, 2, 2]\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool2d(1),  # [B, 256, 128, 1, 1]\n        )\n\n        \n        self.imu_tof_gru = nn.GRU(indim*(1+2), indim, bidirectional=False, batch_first=True)\n        self.imu_tof_gru_drop = nn.Dropout(0.5)\n        self.imu_tof_gru_drop_attention = AttentionLayer(indim)\n        self.imu_tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        \n    def forward(self, allx, phasemask):\n        \n        B, T, D = allx.shape\n        imux = allx[:,:,:self.allch]\n        tofx = allx[:,:,self.allch:]\n        \n        # IMU=======================================================\n        finalatten, logits, clssf, phasemask,all_embedding = self.model_imu(imux[:,:,:self.allch], phasemask, True)\n        finalatten = self.imuprecls(finalatten)\n        \n        # THE======================================================\n        the = tofx[:,:,:5]\n        the = the.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        x3 = self.the_block(the)\n        x3 = x3.transpose(1, 2)\n        x3, _ = self.the_gru(x3)\n        x3 = self.the_gru_dropout(x3)\n        attendedthe = self.the_attention(x3)\n        clssf.append(self.the_cls(attendedthe))\n\n        # TOF=====================================================\n        tof = tofx[:,:,5:]\n        tof_2d = tof.view(B,T, 5, 8, 8)\n        tof = tof_2d.permute(0,2,1,3,4)\n        attendedtof = self.tof_encoder(tof)\n        clssf.append(self.tof_cls(attendedtof))\n        clssf.append(self.imucls(finalatten))\n\n        #==================================\n        tof_2d = tof_2d.view(B*T, 5,8,8)\n        tof_2d_embedding = self.tof_encoder_2d(tof_2d) # B*256  * 128 * 1 * 1\n        tof_2d_embedding = tof_2d_embedding.view(B,T,128)\n        tof_2d_embedding = torch.cat([all_embedding, tof_2d_embedding], dim=-1) # B* T * 256\n        tof_2d_embedding = self.imu_tof_gru(tof_2d_embedding)[0]\n        tof_2d_embedding = self.imu_tof_gru_drop(tof_2d_embedding)\n        tof_2d_embedding = self.imu_tof_gru_drop_attention(tof_2d_embedding)\n        clssf.append(self.imu_tof_cls(tof_2d_embedding))\n        \n        attendedfinal = torch.cat([tof_2d_embedding, finalatten, attendedtof, attendedthe],dim=1)\n        # 分类\n        x = F.relu(self.bn_dense1(self.dense1(attendedfinal)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        return logits, clssf\n        # clssf.append(logits)\n        # weightclsemb = torch.cat(clssf, dim=-1)\n        # return logits, clssf, attendedfinal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:38.336230Z","iopub.execute_input":"2025-09-02T15:07:38.336466Z","iopub.status.idle":"2025-09-02T15:07:38.358246Z","shell.execute_reply.started":"2025-09-02T15:07:38.336451Z","shell.execute_reply":"2025-09-02T15:07:38.357645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls2 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_876.pt\",\n    \"/kaggle/input/cmimodel/bets_1_876.pt\",\n    \"/kaggle/input/cmimodel/bets_2_876.pt\",\n    \"/kaggle/input/cmimodel/bets_3_876.pt\",\n    \"/kaggle/input/cmimodel/bets_4_876.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls2.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:38.358815Z","iopub.execute_input":"2025-09-02T15:07:38.358971Z","iopub.status.idle":"2025-09-02T15:07:50.798471Z","shell.execute_reply.started":"2025-09-02T15:07:38.358959Z","shell.execute_reply":"2025-09-02T15:07:50.797691Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return finalatten, logits, clssf, phasemask\n        return logits, clssf, phasemask\n        \nclass TwoBranchModel_IMU_THM_TOF(nn.Module):\n    def __init__(self, imu_ind, n_classes, fold=0):\n        super().__init__()\n        self.imu_dim = 31\n        self.tof_dim = 320\n        self.imu_ind = imu_ind\n        the_dim = 5\n        self.the_dim = the_dim\n        self.n_classes = n_classes\n        \n        indim = 128\n        self.num_branches = len(imu_ind)\n        \n        self.allch = np.sum(self.imu_ind)\n\n        \n        self.model_imu = IMUModel(self.imu_ind,18)\n\n        ################################TOF BLOCK#########################\n        # self.tof_block = nn.Sequential(\n        #         ResidualSECNNBlock(320 + 31 + 5, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )\n        # self.tof_block2 = nn.Sequential(\n        #         ResidualSECNNBlock(64 + self.allch, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )        \n        # self.tof_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        # self.tof_gru_dropout = nn.Dropout(0.4)\n        # self.tof_attention = AttentionLayer(indim)\n        # self.tof_cls_conv1d = nn.Sequential(\n        #         nn.Linear(indim, 256, bias=False),\n        #         nn.BatchNorm1d(256),\n        #         nn.Dropout(0.5),\n        #         nn.Linear(256, n_classes)\n        # )\n        \n        self.tof_encoder = nn.Sequential(\n            nn.Conv3d(5, 32, kernel_size=(3, 3, 3), padding=1),  # [B, 32, 256, 8, 8]\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 32, 128, 4, 4]\n\n            nn.Conv3d(32, 64, kernel_size=(3, 3, 3), padding=1),  # [B, 64, 128, 4, 4]\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 64, 64, 2, 2]\n\n            nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=1),  # [B, 128, 64, 2, 2]\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d((1, 1, 1)),  # [B, 128, 1, 1, 1]\n            nn.Flatten()\n        )\n        \n        # Thermal\n        self.the_block = nn.Sequential(\n                ResidualSECNNBlock(the_dim, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.the_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.the_gru_dropout = nn.Dropout(0.4)\n        self.the_attention = AttentionLayer(indim)\n\n        \n        self.tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.the_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        self.imuprecls = nn.Sequential(\n            nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 4*indim, bias=False),\n            nn.BatchNorm1d(4*indim),\n            nn.Dropout(0.5),\n        )\n        \n        self.imucls = nn.Sequential(\n            nn.Linear(4*indim , 2*indim, bias=False),\n            nn.BatchNorm1d(2*indim),\n            nn.Dropout(0.5),\n            nn.Linear(2*indim, n_classes)\n        )\n        \n        # Dense layers\n        self.dense1 = nn.Linear(4*indim + indim + indim , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n    def forward(self, allx, phasemask):\n        \n        B, T, D = allx.shape\n        imux = allx[:,:,:self.allch]\n        tofx = allx[:,:,self.allch:]\n        \n        # IMU=======================================================\n        finalatten, logits, clssf, phasemask = self.model_imu(imux[:,:,:self.allch], phasemask, True)\n        finalatten = self.imuprecls(finalatten)\n        \n        # THE======================================================\n        the = tofx[:,:,:5]\n        the = the.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        x3 = self.the_block(the)\n        x3 = x3.transpose(1, 2)\n        x3, _ = self.the_gru(x3)\n        x3 = self.the_gru_dropout(x3)\n        attendedthe = self.the_attention(x3)\n        clssf.append(self.the_cls(attendedthe))\n\n        # TOF=====================================================\n        tof = tofx[:,:,5:]\n        # tof1d = tofx[:,:,5:].transpose(1,2)\n        tof = tof.view(B,T, 5, 8, 8)\n        tof = tof.permute(0,2,1,3,4)\n        attendedtof = self.tof_encoder(tof)\n        clssf.append(self.tof_cls(attendedtof))\n        clssf.append(self.imucls(finalatten))\n        \n        attendedfinal = torch.cat([finalatten, attendedtof, attendedthe],dim=1)\n        # 分类\n        x = F.relu(self.bn_dense1(self.dense1(attendedfinal)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        return logits, clssf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:50.799490Z","iopub.execute_input":"2025-09-02T15:07:50.799808Z","iopub.status.idle":"2025-09-02T15:07:50.838874Z","shell.execute_reply.started":"2025-09-02T15:07:50.799788Z","shell.execute_reply":"2025-09-02T15:07:50.838120Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls4 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cminew/bets_0_875_addmask.pt\",\n    \"/kaggle/input/cminew/bets_1_875_addmask.pt\",\n    \"/kaggle/input/cminew/bets_2_875_addmask.pt\",\n    \"/kaggle/input/cminew/bets_3_875_addmask.pt\",\n    \"/kaggle/input/cminew/bets_4_875_addmask.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls4.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:07:50.839642Z","iopub.execute_input":"2025-09-02T15:07:50.839921Z","iopub.status.idle":"2025-09-02T15:08:03.108922Z","shell.execute_reply.started":"2025-09-02T15:07:50.839906Z","shell.execute_reply":"2025-09-02T15:08:03.108131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return attended_one, logits, clssf, pre\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:13:11.112888Z","iopub.execute_input":"2025-09-02T15:13:11.113180Z","iopub.status.idle":"2025-09-02T15:13:11.142971Z","shell.execute_reply.started":"2025-09-02T15:13:11.113153Z","shell.execute_reply":"2025-09-02T15:13:11.141953Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_imu2 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_0.838.pt\",\n    \"/kaggle/input/cmimodel/bets_1_0.838.pt\",\n    \"/kaggle/input/cmimodel/bets_2_0.838.pt\",\n    \"/kaggle/input/cmimodel/bets_3_0.838.pt\",\n    \"/kaggle/input/cmimodel/bets_4_0.838.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = IMUModel([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_imu2.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:13:11.304779Z","iopub.execute_input":"2025-09-02T15:13:11.305370Z","iopub.status.idle":"2025-09-02T15:13:17.005116Z","shell.execute_reply.started":"2025-09-02T15:13:11.305341Z","shell.execute_reply":"2025-09-02T15:13:17.004544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_imu3 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cminew/0_842.pt\",\n    \"/kaggle/input/cminew/1_842.pt\",\n    \"/kaggle/input/cminew/2_842.pt\",\n    \"/kaggle/input/cminew/3_842.pt\",\n    \"/kaggle/input/cminew/4_842.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = IMUModel([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_imu3.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:13:17.006019Z","iopub.execute_input":"2025-09-02T15:13:17.006249Z","iopub.status.idle":"2025-09-02T15:13:29.495008Z","shell.execute_reply.started":"2025-09-02T15:13:17.006231Z","shell.execute_reply":"2025-09-02T15:13:29.494365Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 + indim, 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n        self.pre_dim = nn.Sequential(\n                nn.Linear(indim, 1, bias=False),\n                nn.BatchNorm1d(indim),\n                nn.Dropout(0.5),\n                )\n        # mid fea\n        self.mid_block = nn.Sequential(\n            ResidualSECNNBlock(indim * self.num_branches, indim*2, 3, dropout=0.3),\n            ResidualSECNNBlock(indim * 2, indim, 3, dropout=0.3),\n        )\n        self.mid_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.mid_dropouts = nn.Dropout(0.5)\n        self.mid_atten = AttentionLayer(indim)\n        self.mid_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        \n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n\n        pre = torch.stack(pre,dim=1) # B * CH * 256 * 128\n        # pre = self.pre_dim(pre)[0] # B * CH * 256\n        pre = pre.mean(dim=-1)  # (B, CH, 256)\n        \n        all_x = pre[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(pre[:, ct:ct+k, :])\n            ct = ct + k\n\n        midfe = []\n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)            # (B, T, D)\n            midfe.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        midfe = torch.stack(midfe,dim=1) # B * N * 256 * 128\n        bb,nn,tt,ff = midfe.shape\n        midfe = midfe.permute(0,1,3,2)\n        midfe = midfe.reshape(bb,nn*ff,tt) # B * D * T\n        midfe = self.mid_block(midfe)\n        midfe = midfe.transpose(1, 2)# (B, T, D)\n        midfe,_ = self.mid_gru(midfe)              # GRU\n        midfe = self.mid_dropouts(midfe)             # Dropout\n        midfe = self.mid_atten(midfe)\n        clssf.append(self.mid_cls(midfe))\n        attended_list.append(midfe)\n        \n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return attended_one, logits, clssf, pre\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:13:47.674315Z","iopub.execute_input":"2025-09-02T15:13:47.674913Z","iopub.status.idle":"2025-09-02T15:13:47.713376Z","shell.execute_reply.started":"2025-09-02T15:13:47.674884Z","shell.execute_reply":"2025-09-02T15:13:47.712732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_imu4 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cmimodel/bets_0_831_imumodelchange.pt\",\n    \"/kaggle/input/cmimodel/bets_1_831_imumodelchange.pt\",\n    \"/kaggle/input/cmimodel/bets_2_831_imumodelchange.pt\",\n    \"/kaggle/input/cmimodel/bets_3_831_imumodelchange.pt\",\n    \"/kaggle/input/cmimodel/bets_4_831_imumodelchange.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = IMUModel([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_imu4.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:13:59.129808Z","iopub.execute_input":"2025-09-02T15:13:59.130481Z","iopub.status.idle":"2025-09-02T15:14:13.006260Z","shell.execute_reply.started":"2025-09-02T15:13:59.130457Z","shell.execute_reply":"2025-09-02T15:14:13.005462Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class IMUModel(nn.Module):\n    def __init__(self, imu_ind, n_classes, weight_decay=1e-4):\n        super().__init__()\n        self.imu_ind = imu_ind\n        self.imu_dim = len(imu_ind)\n        self.tof_dim = 320\n        self.n_classes = n_classes\n        self.weight_decay = weight_decay\n        indim = 128\n\n        self.pool = nn.AdaptiveAvgPool1d(1)\n        # 修改 conv lstm conv lstm\n        self.num_branches = len(imu_ind)\n        self.imu_blocks = nn.ModuleList()\n        self.grus = nn.ModuleList()\n        self.dropouts = nn.ModuleList()\n        self.attentions = nn.ModuleList()\n        self.classf = nn.ModuleList()\n\n        self.imu_blocks2 = nn.ModuleList()\n        self.grus2 = nn.ModuleList()\n        self.dropouts2 = nn.ModuleList()\n        self.attentions2 = nn.ModuleList()\n        self.classf2 = nn.ModuleList()\n        \n\n        self.imu_blocks3 = nn.ModuleList()\n        self.grus3 = nn.ModuleList()\n        self.dropouts3 = nn.ModuleList()\n        self.attentions3 = nn.ModuleList()\n        self.classf3 = nn.ModuleList()\n\n\n        self.imu_blocks4 = nn.ModuleList()\n        self.grus4 = nn.ModuleList()\n        self.dropouts4 = nn.ModuleList()\n        self.attentions4 = nn.ModuleList()\n        self.classf4 = nn.ModuleList()\n        \n        self.allch = np.sum(self.imu_ind)\n\n        #############one channel loss############################\n        for i in range(self.allch):\n            self.imu_blocks4.append(nn.Sequential(\n                ResidualSECNNBlock(1, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus4.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts4.append(nn.Dropout(0.5))\n            self.attentions4.append(AttentionLayer(indim))\n            self.classf4.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )        \n        ############################ALL#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts.append(nn.Dropout(0.5))\n            self.attentions.append(AttentionLayer(indim))\n            self.classf.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        self.allcls =  nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n        )\n        ############################Trans#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks2.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus2.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts2.append(nn.Dropout(0.5))\n            self.attentions2.append(AttentionLayer(indim))\n            # self.exp.append(Expert(indim, indim, n_classes))\n            self.classf2.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n        ############################Gesture#########################\n        for in_channels in self.imu_ind:\n            self.imu_blocks3.append(nn.Sequential(\n                ResidualSECNNBlock(in_channels, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n            ))\n            self.grus3.append(nn.GRU(indim, indim, bidirectional=False, batch_first=True))\n            self.dropouts3.append(nn.Dropout(0.5))\n            self.attentions3.append(AttentionLayer(indim))\n            self.classf3.append(\n                nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n            )\n            \n        # all block\n        self.fn_block = nn.Sequential(\n            ResidualSECNNBlock(20, indim, 3, dropout=0.3),\n            ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.fn_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.fn_dropouts = nn.Dropout(0.5)\n        self.fn_atten = AttentionLayer(indim)\n\n        ### classification\n        self.dense1 = nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.finalallcls = nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim + indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.transcls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.gescls =  nn.Sequential(\n                nn.Linear(len(self.imu_ind) * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.onecls =  nn.Sequential(\n                nn.Linear(4 * indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n\n        self.precls = nn.Sequential(\n                nn.Linear(self.allch * indim, 4 * indim, bias=False),\n                nn.BatchNorm1d(4 * indim),\n                nn.Dropout(0.5),\n                )\n        \n        \n        self.final = nn.Conv1d(indim, 1, kernel_size=1)\n\n    def forward_mask(self, x):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        all_x = x[:,:self.allch,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        phasemask = self.final(out)  # (B, 1, 256)\n        return phasemask\n    \n    def forward(self, x, phasemask, isfe=False):\n        x = x.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        imu_splits = []\n        ct = 0\n        for k in self.imu_ind:\n            imu_splits.append(x[:, ct:ct+k, :])\n            ct = ct + k\n        clssf = []\n        pre = []\n        attended_list = []\n\n        oneattended_list = []\n        \n        ###########One Channel##################\n        for i in range(self.allch):\n            imu_i = x[:, i:i+1, :]\n            out = self.imu_blocks4[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus4[i](out)              # GRU\n            out = self.dropouts4[i](out)             # Dropout\n            attended = self.attentions4[i](out)      # Attention\n            clssf.append(self.classf4[i](attended))\n            oneattended_list.append(attended)\n\n        oneattended_list = torch.cat(oneattended_list, dim=-1)\n        oneattended_list = self.precls(oneattended_list)\n        \n        all_x = x[:,:20,:]\n        out = self.fn_block(all_x)         # CNN block\n        # 预测phasemask\n        # phasemask = self.final(out)  # (B, 1, 256)\n        out = out.transpose(1, 2)# (B, T, D)\n        out,_= self.fn_gru(out)              # GRU\n        out = self.fn_dropouts(out)             # Dropout\n        attended = self.fn_atten(out)\n        clssf.append(self.allcls(attended))\n        attended_list.append(attended)\n\n        # !!!!!!!!!!!phase   000111000\n        sigac1 = phasemask.sigmoid() # (B, 1, 256)\n        sigac2 = 1 - sigac1\n        ges = x * sigac1\n        trans =  x * sigac2   \n        \n        for i in range(self.num_branches):\n            imu_i = imu_splits[i]\n            out = self.imu_blocks[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            pre.append(out)\n            out,_= self.grus[i](out)              # GRU\n            out = self.dropouts[i](out)             # Dropout\n            attended = self.attentions[i](out)      # Attention\n            clssf.append(self.classf[i](attended))\n            attended_list.append(attended)\n\n        attended_ges = []\n        ii = 0\n        for i, k in enumerate(self.imu_ind):\n            imu_i = ges[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks2[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus2[i](out)              # GRU\n            out = self.dropouts2[i](out)             # Dropout\n            attended = self.attentions2[i](out)      # Attention\n            clssf.append(self.classf2[i](attended))\n            attended_ges.append(attended)\n\n        ii = 0\n        attended_trans = []\n        for i, k in enumerate(self.imu_ind):\n            imu_i = trans[:,ii:ii+k,:]\n            ii = ii + k\n            out = self.imu_blocks3[i](imu_i)         # CNN block\n            out = out.transpose(1, 2)# (B, T, D)\n            out,_= self.grus3[i](out)              # GRU\n            out = self.dropouts3[i](out)             # Dropout\n            attended = self.attentions3[i](out)      # Attention\n            clssf.append(self.classf3[i](attended))\n            attended_trans.append(attended)\n\n        attended_one = torch.cat(attended_list, dim=-1)\n        attended_trans = torch.cat(attended_trans, dim=-1)\n        attended_ges = torch.cat(attended_ges, dim=-1)\n        # oneattended_list = torch.cat(oneattended_list, dim=-1)\n\n        finalatten = torch.cat([attended_ges, attended_trans, attended_one, oneattended_list], dim=-1)\n\n        clssf.append(self.finalallcls(attended_one))\n        clssf.append(self.transcls(attended_trans))\n        clssf.append(self.gescls(attended_ges))\n        clssf.append(self.onecls(oneattended_list))\n        \n        x = F.relu(self.bn_dense1(self.dense1(finalatten)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        if isfe:\n            return finalatten, logits, clssf, phasemask\n        return logits, clssf, phasemask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:08:14.026150Z","iopub.execute_input":"2025-09-02T15:08:14.026398Z","iopub.status.idle":"2025-09-02T15:08:14.056968Z","shell.execute_reply.started":"2025-09-02T15:08:14.026382Z","shell.execute_reply":"2025-09-02T15:08:14.056239Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TwoBranchModel_IMU_THM_TOF(nn.Module):\n    def __init__(self, imu_ind, n_classes, fold=0):\n        super().__init__()\n        self.imu_dim = 31\n        self.tof_dim = 320\n        self.imu_ind = imu_ind\n        the_dim = 5\n        self.the_dim = the_dim\n        self.n_classes = n_classes\n        \n        indim = 128\n        self.num_branches = len(imu_ind)\n        \n        self.allch = np.sum(self.imu_ind)\n\n        \n        self.model_imu = IMUModel(self.imu_ind,18)\n\n        ################################TOF BLOCK#########################\n        # self.tof_block = nn.Sequential(\n        #         ResidualSECNNBlock(320 + 31 + 5, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )\n        # self.tof_block2 = nn.Sequential(\n        #         ResidualSECNNBlock(64 + self.allch, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )        \n        # self.tof_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        # self.tof_gru_dropout = nn.Dropout(0.4)\n        # self.tof_attention = AttentionLayer(indim)\n        # self.tof_cls_conv1d = nn.Sequential(\n        #         nn.Linear(indim, 256, bias=False),\n        #         nn.BatchNorm1d(256),\n        #         nn.Dropout(0.5),\n        #         nn.Linear(256, n_classes)\n        # )\n        \n        self.tof_encoder = nn.Sequential(\n            nn.Conv3d(5, 32, kernel_size=(3, 3, 3), padding=1),  # [B, 32, 256, 8, 8]\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 32, 128, 4, 4]\n\n            nn.Conv3d(32, 64, kernel_size=(3, 3, 3), padding=1),  # [B, 64, 128, 4, 4]\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 64, 64, 2, 2]\n\n            nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=1),  # [B, 128, 64, 2, 2]\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d((1, 1, 1)),  # [B, 128, 1, 1, 1]\n            nn.Flatten()\n        )\n        \n        # Thermal\n        self.the_block = nn.Sequential(\n                ResidualSECNNBlock(the_dim, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.the_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.the_gru_dropout = nn.Dropout(0.4)\n        self.the_attention = AttentionLayer(indim)\n\n        \n        self.tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.the_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        self.imuprecls = nn.Sequential(\n            nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 4*indim, bias=False),\n            nn.BatchNorm1d(4*indim),\n            nn.Dropout(0.5),\n        )\n        \n        self.imucls = nn.Sequential(\n            nn.Linear(4*indim , 2*indim, bias=False),\n            nn.BatchNorm1d(2*indim),\n            nn.Dropout(0.5),\n            nn.Linear(2*indim, n_classes)\n        )\n        \n        # Dense layers\n        self.dense1 = nn.Linear(4*indim + indim + indim , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n    def forward(self, allx, phasemask):\n        \n        B, T, D = allx.shape\n        imux = allx[:,:,:self.allch]\n        tofx = allx[:,:,self.allch:]\n        \n        # IMU=======================================================\n        finalatten, logits, clssf, phasemask = self.model_imu(imux[:,:,:self.allch], phasemask, True)\n        finalatten = self.imuprecls(finalatten)\n        \n        # THE======================================================\n        the = tofx[:,:,:5]\n        the = the.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        x3 = self.the_block(the)\n        x3 = x3.transpose(1, 2)\n        x3, _ = self.the_gru(x3)\n        x3 = self.the_gru_dropout(x3)\n        attendedthe = self.the_attention(x3)\n        clssf.append(self.the_cls(attendedthe))\n\n        # TOF=====================================================\n        tof = tofx[:,:,5:]\n        # tof1d = tofx[:,:,5:].transpose(1,2)\n        tof = tof.view(B,T, 5, 8, 8)\n        tof = tof.permute(0,2,1,3,4)\n        attendedtof = self.tof_encoder(tof)\n        clssf.append(self.tof_cls(attendedtof))\n        clssf.append(self.imucls(finalatten))\n        \n        attendedfinal = torch.cat([finalatten, attendedtof, attendedthe],dim=1)\n        # 分类\n        x = F.relu(self.bn_dense1(self.dense1(attendedfinal)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        return logits, clssf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:08:14.057748Z","iopub.execute_input":"2025-09-02T15:08:14.058064Z","iopub.status.idle":"2025-09-02T15:08:14.083009Z","shell.execute_reply.started":"2025-09-02T15:08:14.058048Z","shell.execute_reply":"2025-09-02T15:08:14.082309Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls5 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cminew/bets_0_794.pt\",\n    \"/kaggle/input/cminew/bets_1_794.pt\",\n    \"/kaggle/input/cminew/bets_2_794.pt\",\n    \"/kaggle/input/cminew/bets_3_794.pt\",\n    \"/kaggle/input/cminew/bets_4_794.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls5.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:08:14.083740Z","iopub.execute_input":"2025-09-02T15:08:14.083968Z","iopub.status.idle":"2025-09-02T15:08:25.836863Z","shell.execute_reply.started":"2025-09-02T15:08:14.083949Z","shell.execute_reply":"2025-09-02T15:08:25.836060Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls6 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cminew/bets_0_879.pt\",\n    \"/kaggle/input/cminew/bets_1_879.pt\",\n    \"/kaggle/input/cminew/bets_2_879.pt\",\n    \"/kaggle/input/cminew/bets_3_879.pt\",\n    \"/kaggle/input/cminew/bets_4_879.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls6.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:08:25.837709Z","iopub.execute_input":"2025-09-02T15:08:25.837965Z","iopub.status.idle":"2025-09-02T15:08:38.322908Z","shell.execute_reply.started":"2025-09-02T15:08:25.837940Z","shell.execute_reply":"2025-09-02T15:08:38.322351Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TwoBranchModel_IMU_THM_TOF(nn.Module):\n    def __init__(self, imu_ind, n_classes, fold=0):\n        super().__init__()\n        self.imu_dim = 31\n        self.tof_dim = 320\n        self.imu_ind = imu_ind\n        the_dim = 5\n        self.the_dim = the_dim\n        self.n_classes = n_classes\n        \n        indim = 128\n        self.num_branches = len(imu_ind)\n        \n        self.allch = np.sum(self.imu_ind)\n\n        \n        self.model_imu = IMUModel(self.imu_ind,18)\n\n        ################################TOF BLOCK#########################\n        # self.tof_block = nn.Sequential(\n        #         ResidualSECNNBlock(320 + 31 + 5, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )\n        # self.tof_block2 = nn.Sequential(\n        #         ResidualSECNNBlock(64 + self.allch, indim, 3, dropout=0.3),\n        #         ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        # )        \n        # self.tof_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        # self.tof_gru_dropout = nn.Dropout(0.4)\n        # self.tof_attention = AttentionLayer(indim)\n        # self.tof_cls_conv1d = nn.Sequential(\n        #         nn.Linear(indim, 256, bias=False),\n        #         nn.BatchNorm1d(256),\n        #         nn.Dropout(0.5),\n        #         nn.Linear(256, n_classes)\n        # )\n        \n        self.tof_encoder = nn.Sequential(\n            nn.Conv3d(5, 32, kernel_size=(3, 3, 3), padding=1),  # [B, 32, 256, 8, 8]\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 32, 128, 4, 4]\n\n            nn.Conv3d(32, 64, kernel_size=(3, 3, 3), padding=1),  # [B, 64, 128, 4, 4]\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d((2, 2, 2)),  # [B, 64, 64, 2, 2]\n\n            nn.Conv3d(64, 128, kernel_size=(3, 3, 3), padding=1),  # [B, 128, 64, 2, 2]\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d((1, 1, 1)),  # [B, 128, 1, 1, 1]\n            nn.Flatten()\n        )\n        \n        # Thermal\n        self.the_block = nn.Sequential(\n                ResidualSECNNBlock(the_dim, indim, 3, dropout=0.3),\n                ResidualSECNNBlock(indim, indim, 3, dropout=0.3),\n        )\n        self.the_gru = nn.GRU(indim, indim, bidirectional=False, batch_first=True)\n        self.the_gru_dropout = nn.Dropout(0.4)\n        self.the_attention = AttentionLayer(indim)\n\n        \n        self.tof_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        \n        self.the_cls = nn.Sequential(\n                nn.Linear(indim, 256, bias=False),\n                nn.BatchNorm1d(256),\n                nn.Dropout(0.5),\n                nn.Linear(256, n_classes)\n                )\n        self.imuprecls = nn.Sequential(\n            nn.Linear(len(self.imu_ind) * indim * 3  + indim + indim*4 , 4*indim, bias=False),\n            nn.BatchNorm1d(4*indim),\n            nn.Dropout(0.5),\n        )\n        \n        self.imucls = nn.Sequential(\n            nn.Linear(4*indim , 2*indim, bias=False),\n            nn.BatchNorm1d(2*indim),\n            nn.Dropout(0.5),\n            nn.Linear(2*indim, n_classes)\n        )\n        \n        # Dense layers\n        self.dense1 = nn.Linear(4*indim + indim + indim , 256, bias=False)\n        self.bn_dense1 = nn.BatchNorm1d(256)\n        self.drop1 = nn.Dropout(0.5)\n        self.dense2 = nn.Linear(256, 128, bias=False)\n        self.bn_dense2 = nn.BatchNorm1d(128)\n        self.drop2 = nn.Dropout(0.3)\n        self.classifier = nn.Linear(128, n_classes)\n\n        self.classaux = nn.Sequential(\n            nn.Linear(4*indim + indim + indim , 256, bias=False),\n            nn.BatchNorm1d(256),\n            nn.Dropout(0.5),\n            nn.Linear(256, 128, bias=False),\n            nn.BatchNorm1d(128),\n            nn.Dropout(0.3),\n            nn.Linear(128, 1)\n        )\n        \n    def forward(self, allx, phasemask):\n        \n        B, T, D = allx.shape\n        imux = allx[:,:,:self.allch]\n        tofx = allx[:,:,self.allch:]\n        \n        # IMU=======================================================\n        finalatten, logits, clssf, phasemask = self.model_imu(imux[:,:,:self.allch], phasemask, True)\n        finalatten = self.imuprecls(finalatten)\n        \n        # THE======================================================\n        the = tofx[:,:,:5]\n        the = the.transpose(1, 2)  # (batch, imu_dim, seq_len)\n        x3 = self.the_block(the)\n        x3 = x3.transpose(1, 2)\n        x3, _ = self.the_gru(x3)\n        x3 = self.the_gru_dropout(x3)\n        attendedthe = self.the_attention(x3)\n        clssf.append(self.the_cls(attendedthe))\n\n        # TOF=====================================================\n        tof = tofx[:,:,5:]\n        # tof1d = tofx[:,:,5:].transpose(1,2)\n        tof = tof.view(B,T, 5, 8, 8)\n        tof = tof.permute(0,2,1,3,4)\n        attendedtof = self.tof_encoder(tof)\n        clssf.append(self.tof_cls(attendedtof))\n        clssf.append(self.imucls(finalatten))\n        \n        attendedfinal = torch.cat([finalatten, attendedtof, attendedthe],dim=1)\n        # 分类\n        x = F.relu(self.bn_dense1(self.dense1(attendedfinal)))\n        x = self.drop1(x)\n        x = F.relu(self.bn_dense2(self.dense2(x)))\n        x = self.drop2(x)\n        logits = self.classifier(x)\n        return logits, clssf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:09:41.842769Z","iopub.execute_input":"2025-09-02T15:09:41.843093Z","iopub.status.idle":"2025-09-02T15:09:41.860815Z","shell.execute_reply.started":"2025-09-02T15:09:41.843070Z","shell.execute_reply":"2025-09-02T15:09:41.860134Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_alls7 = []\ndevice = \"cuda:0\"\nmd = [\n    \"/kaggle/input/cminew/bets_0_8809.pt\",\n    \"/kaggle/input/cminew/bets_1_8809.pt\",\n    \"/kaggle/input/cminew/bets_2_8809.pt\",\n    \"/kaggle/input/cminew/bets_3_8809.pt\",\n    \"/kaggle/input/cminew/bets_4_8809.pt\"\n]\nfor fold in range(5):\n    checkpoint = torch.load(md[fold], map_location=device)\n    model_all = TwoBranchModel_IMU_THM_TOF([7,4,5,4,11,14],18).to(device)\n    model_all.load_state_dict(checkpoint)\n    model_all.eval();\n    model_alls7.append(model_all)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:09:42.461695Z","iopub.execute_input":"2025-09-02T15:09:42.462253Z","iopub.status.idle":"2025-09-02T15:09:49.516589Z","shell.execute_reply.started":"2025-09-02T15:09:42.462230Z","shell.execute_reply":"2025-09-02T15:09:49.515926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"max_len = 256\ndef predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    \"\"\"Prediction function for Kaggle competition\"\"\"    \n    df_seq = sequence.to_pandas()\n    ratio = df_seq[\"thm_1\"].isna().sum() / len(df_seq)\n    train = df_seq\n    train = feature_engineering(train)\n    linear_accel_df = train.groupby('sequence_id').apply(get_rot, include_groups=False)\n    linear_accel_df = linear_accel_df.droplevel('sequence_id')\n    train = train.join(linear_accel_df)\n    linear_accel_df = train.groupby('sequence_id').apply(calculate_angular_velocity_from_quat_ori, include_groups=False)\n    linear_accel_df = linear_accel_df.droplevel('sequence_id')\n    train = train.join(linear_accel_df)    \n    train['ang_diff_x'] = train.groupby('sequence_id')['angular_vel_x'].diff().fillna(0)\n    train['ang_diff_y'] = train.groupby('sequence_id')['angular_vel_y'].diff().fillna(0)\n    train['ang_diff_z'] = train.groupby('sequence_id')['angular_vel_z'].diff().fillna(0)\n    train['ang_diff_the'] = train.groupby('sequence_id')['rot_angle_vel'].diff().fillna(0)\n\n    k = 15\n    grouped = train.groupby('sequence_id')\n    for fe in (['rot',\"angular_vel\"]):\n        for dir in ('x', 'y', 'z'):\n            col_name = f'{fe}_{dir}'\n            weight = create_gaussian_kernel(k, 1)  # 1 channel, cause process 1 column per iteration\n            lpf_results = []\n            for _, group in grouped:\n                # convert to tensor and add dimentions (batch, channel, length)\n                data = torch.tensor(group[col_name].values, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n                # apply convolution\n                lpf = F.conv1d(data, weight, padding=k//2)\n                lpf_results.append(lpf.squeeze().numpy())\n            \n            # concatenate results\n            lpf_series = pd.concat([pd.Series(x, index=group.index) for x, (_, group) in zip(lpf_results, grouped)])\n            train[f'{fe}_lpf_{dir}'] = lpf_series\n            train[f'{fe}_hpf_{dir}'] = train[col_name] - train[f'{fe}_lpf_{dir}']\n\n    grouped = train.groupby('sequence_id')\n    for fe in (['acc','linear_acc']):\n        for dir in ('x', 'y', 'z', 'mag'):\n            col_name = f'{fe}_{dir}'\n            weight = create_gaussian_kernel(k, 1)  # 1 channel, cause process 1 column per iteration\n            lpf_results = []\n            for _, group in grouped:\n                # convert to tensor and add dimentions (batch, channel, length)\n                data = torch.tensor(group[col_name].values, dtype=torch.float32).unsqueeze(0).unsqueeze(0)\n                # apply convolution\n                lpf = F.conv1d(data, weight, padding=k//2)\n                lpf_results.append(lpf.squeeze().numpy())\n            \n            # concatenate results\n            lpf_series = pd.concat([pd.Series(x, index=group.index) for x, (_, group) in zip(lpf_results, grouped)])\n            train[f'{fe}_lpf_{dir}'] = lpf_series\n            train[f'{fe}_hpf_{dir}'] = train[col_name] - train[f'{fe}_lpf_{dir}']\n            \n    train[tof_cols] = train[tof_cols].ffill().bfill().fillna(0).values\n    feature_cols = imu_cols+tof_cols\n    with torch.no_grad():\n        mat = train[imu_cols].values\n        pad = pad_sequences_torch([mat], maxlen=pad_len, padding='post', truncating='post')\n        x = torch.FloatTensor(pad).to(device)\n        phasemask = modeldet.forward_mask(x)\n\n        fnpred = []\n        fnlog = []\n        if ratio>0.5:\n            for fold in range(3,5):\n                model = model_imus[fold]\n                logits, cls, _ = model(x, phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n            for fold in range(3,5):\n                model = model_imu2[fold]\n                logits, cls, _ = model(x, phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n            for fold in range(3,5):\n                model = model_imu3[fold]\n                logits, cls, _ = model(x, phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n            for fold in range(3,5):\n                model = model_imu4[fold]\n                logits, cls, _ = model(x, phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n        else:\n            mat = train[feature_cols].values\n            pad = pad_sequences_torch([mat], maxlen=pad_len, padding='post', truncating='post')\n            x = torch.FloatTensor(pad).to(device)\n            for fold in range(3,5):\n                model_all = model_alls[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls2[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls3[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls4[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls5[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls6[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n            for fold in range(3,5):\n                model_all = model_alls7[fold]\n                logits, cls = model_all(x,phasemask)\n                fnlog.append(logits.softmax(dim=1))\n                fnpred.append(logits.argmax(dim=1))\n\n        fnlog = torch.stack(fnlog, dim=0)   # [5, B, C]\n        preds = torch.stack(fnpred, dim=0)   # [5, B]\n\n        # B, C = fnlog.size(1), fnlog.size(2)\n        # final_preds = []\n        # for i in range(B):  # 遍历 batch\n        #     votes = torch.bincount(preds[:, i], minlength=C)  # [C] 各类别票数\n        #     max_vote = votes.max()\n        #     print(votes)\n        #     candidates = (votes == max_vote).nonzero(as_tuple=True)[0]  # 平票类别\n        #     if len(candidates) == 1:\n        #         # ✅ 有唯一最高票，直接选\n        #         final_preds.append(candidates.item())\n        #     else:\n        #         # 🤝 平票，使用平均 softmax 概率来打破平局\n        #         avg_prob = fnlog[:, i, :].mean(dim=0)  # [C]\n        #         chosen = avg_prob[candidates].argmax().item()\n        #         final_preds.append(candidates[chosen].item())\n        \n        # final_preds = torch.tensor(final_preds)  # [B]\n        fnlog = fnlog.mean(dim=0)\n        print(fnlog)\n        idx = int(fnlog[0].argmax().cpu().numpy())\n        # idx = int(final_preds.cpu().numpy()[0])\n    print(str(gesture_classes[idx]))\n    return str(gesture_classes[idx])\n# Kaggle competition interface\nimport kaggle_evaluation.cmi_inference_server\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:21:35.634466Z","iopub.execute_input":"2025-09-02T15:21:35.634786Z","iopub.status.idle":"2025-09-02T15:21:38.615787Z","shell.execute_reply.started":"2025-09-02T15:21:35.634765Z","shell.execute_reply":"2025-09-02T15:21:38.615173Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}