{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":12893197,"sourceType":"datasetVersion","datasetId":8157485},{"sourceId":12893248,"sourceType":"datasetVersion","datasetId":8157524},{"sourceId":12893289,"sourceType":"datasetVersion","datasetId":8157547},{"sourceId":12893329,"sourceType":"datasetVersion","datasetId":8157577},{"sourceId":12901807,"sourceType":"datasetVersion","datasetId":8163223},{"sourceId":12901820,"sourceType":"datasetVersion","datasetId":8163233},{"sourceId":12901831,"sourceType":"datasetVersion","datasetId":8163239},{"sourceId":12901849,"sourceType":"datasetVersion","datasetId":8163254},{"sourceId":12932760,"sourceType":"datasetVersion","datasetId":8183823},{"sourceId":12933146,"sourceType":"datasetVersion","datasetId":8184096},{"sourceId":12933415,"sourceType":"datasetVersion","datasetId":8184271},{"sourceId":12936704,"sourceType":"datasetVersion","datasetId":8186267},{"sourceId":12936714,"sourceType":"datasetVersion","datasetId":8186274},{"sourceId":12936739,"sourceType":"datasetVersion","datasetId":8186294},{"sourceId":12936753,"sourceType":"datasetVersion","datasetId":8186302},{"sourceId":12936765,"sourceType":"datasetVersion","datasetId":8186312},{"sourceId":12941953,"sourceType":"datasetVersion","datasetId":8189968},{"sourceId":12941968,"sourceType":"datasetVersion","datasetId":8189977},{"sourceId":12943518,"sourceType":"datasetVersion","datasetId":8191029},{"sourceId":12943610,"sourceType":"datasetVersion","datasetId":8191094},{"sourceId":240649816,"sourceType":"kernelVersion"}],"dockerImageVersionId":31090,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:47:15.200358Z","iopub.execute_input":"2025-09-02T15:47:15.200623Z","iopub.status.idle":"2025-09-02T15:47:15.632272Z","shell.execute_reply.started":"2025-09-02T15:47:15.200600Z","shell.execute_reply":"2025-09-02T15:47:15.631647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport kagglehub\nfrom pathlib import Path\nimport numpy as np\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom scipy.spatial.transform import Rotation as R\nfrom collections import defaultdict\nfrom torch.utils.data import Dataset, DataLoader, Subset\nfrom tqdm.notebook import tqdm\nfrom torch.amp import autocast\nimport pandas as pd\nimport polars as pl\nfrom sklearn.model_selection import StratifiedKFold, StratifiedGroupKFold\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom numpy.fft import fft\nfrom transformers import DebertaV2Model, DebertaV2Config\nfrom transformers import BertConfig, BertModel\nfrom transformers import DebertaV2Model, DebertaV2Config, get_linear_schedule_with_warmup\nfrom transformers import RobertaModel, RobertaConfig\nimport joblib\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T17:31:49.749594Z","iopub.execute_input":"2025-09-02T17:31:49.750329Z","iopub.status.idle":"2025-09-02T17:31:49.758646Z","shell.execute_reply.started":"2025-09-02T17:31:49.750294Z","shell.execute_reply":"2025-09-02T17:31:49.757739Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def 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    num_samples = acc_values.shape[0]\n    linear_accel = np.zeros_like(acc_values)\n    gravity_world = np.array([0, 0, 9.81])\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        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\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    num_samples = quat_values.shape[0]\n    angular_vel = np.zeros((num_samples, 3))\n    for i in range(num_samples - 1):\n        q_t = quat_values[i]\n        q_t_plus_dt = quat_values[i+1]\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            angular_vel[i, :] = delta_rot.as_rotvec() / time_delta\n        except ValueError:\n            pass\n    return angular_vel\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    num_samples = quat_values.shape[0]\n    angular_dist = np.zeros(num_samples)\n    for i in range(num_samples - 1):\n        q1 = quat_values[i]\n        q2 = quat_values[i+1]\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\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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:47:37.542268Z","iopub.execute_input":"2025-09-02T15:47:37.542694Z","iopub.status.idle":"2025-09-02T15:47:37.554309Z","shell.execute_reply.started":"2025-09-02T15:47:37.542677Z","shell.execute_reply":"2025-09-02T15:47:37.553680Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CMIFeDataset(Dataset):\n    def __init__(self, data_path, config):\n        self.config = config\n        self.init_feature_names(data_path)\n        df = self.generate_features(pd.read_csv(data_path, usecols=set(self.use_cols) & set(self.raw_columns)))\n        self.generate_dataset(df)\n\n    def init_feature_names(self, data_path):\n        self.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        ]\n        self.non_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        ]\n\n        self.acc_features = ['acc_mag', 'acc_mag_jerk', 'linear_acc_mag', 'linear_acc_mag_jerk']\n        self.rot_features = ['rot_angle', 'rot_angle_vel', 'angular_vel_x', 'angular_vel_y', 'angular_vel_z', 'angular_distance']\n        self.old_imu_features = [\n            'acc_mag', 'rot_angle','acc_mag_jerk', 'rot_angle_vel',\n            'linear_acc_mag', 'linear_acc_mag_jerk',\n            'angular_vel_x', 'angular_vel_y', 'angular_vel_z', 'angular_distance'\n        ]\n\n        self.acc_features = ['acc_mag', 'acc_mag_jerk', 'linear_acc_mag', 'linear_acc_mag_jerk']\n        self.rot_features = ['rot_angle', 'rot_angle_vel', 'angular_vel_x', 'angular_vel_y', 'angular_vel_z',\n                             'angular_distance']\n        self.old_imu_features = [\n            'acc_mag', 'rot_angle', 'acc_mag_jerk', 'rot_angle_vel',\n            'linear_acc_mag', 'linear_acc_mag_jerk',\n            'angular_vel_x', 'angular_vel_y', 'angular_vel_z', 'angular_distance'\n        ]\n        # \"acc_xy_magnitude\",\"acc_xz_magnitude\",\"acc_yz_magnitude\",'acc_xy_sum'\n        self.sum_imu_features = ['acc_yz_sum','acc_xy_sum','acc_xz_sum']\n        # 'acc_xz_sum','acc_xy_diff','acc_yz_diff','acc_xz_diff','acc_xy_z_net','acc_yz_x_net',   'acc_xz_y_net'\n        # rot_xy_z_net  rot_xw_y_net_md rot_xw_z_net_md rot_yw_x_net_md rot_xy_z_net_md rot_yz_x_net_md rot_zw_y_net_md rot_xz_over_yw rot_xw_over_yz\n        self.ms_rot_features = [\"rot_yz_x_net\",\"rot_xz_y_net\",\"rot_xw_z_net\"]\n        # \"rot_yw_x_net\",\"rot_xw_y_net\",'rot_xw_z_net_ms',\"rot_yw_x_net_ms\",\"rot_xw_y_net_ms\",\"rot_xy_z_net_ms\",\"rot_yz_x_net_ms\",\"rot_zw_y_net_ms\"\n        self.md_rot_features = [\"rot_xy_plus_zw\",\"rot_xz_plus_yw\",\"rot_xw_plus_yz\"]\n\n        self.jerk = [\"angular_jerk_x\",\n                    \"angular_jerk_y\",\n                    \"angular_jerk_z\"]\n\n        self.rot_magnitude = [\n\t\t\t\t\"rot_xyz_magnitude\",\n\t\t\t\t\"rot_xyw_magnitude\",\n\t\t\t\t\"rot_xzw_magnitude\",\n\t\t\t\t\"rot_yzw_magnitude\",\n\t\t\t\t\"rot_full_magnitude\"\n\t\t\t\t]\n\n        self.rolling_mean = [\n\t\t\t\t\"acc_mag_smooth_mean\",\n\t\t\t\t\"linear_acc_mean\",\n\t\t\t\t\"rot_full_magnitude_mean\"]\n\n        self.rot_jerk = [\n                        \"rot_w_vel\",\n                        \"rot_x_vel\",\n                        \"rot_y_vel\",\n                        \"rot_z_vel\"\n                            ]\n        self.rot_xyz = [\"rot_xy_over_zw\",\"rot_xz_over_yw\",\"rot_xw_over_yz\"]        \n\n        self.extra_imu_features = self.config.get(\"imu_feats\", [])\n        self.imu_features = self.extra_imu_features.copy()\n        if self.config.get(\"add_imu_feat_default\", True):\n            if self.config.get(\"old_imu_feat\", True):\n                self.imu_features.extend(self.old_imu_features)\n            else:\n                self.imu_features.extend(self.acc_features)\n                self.imu_features.extend(self.rot_features)\n        self.er1_fearues = [\"er_x\", \"er_y\", \"er_z\"]\n        self.er2_fearues = ['er_r_xy', 'er_r_xz', 'er_r_yz', 'er_c_xy', 'er_c_xz', 'er_c_yz']\n        self.er_fearues = self.er1_fearues + self.er2_fearues\n        self.tof_mode = self.config.get(\"tof_mode\", \"stats\")\n        self.tof_region_stats = ['mean', 'std', 'min', 'max']\n        self.tof_cols = self.generate_tof_feature_names()\n\n        self.raw_columns = pd.read_csv(data_path, nrows=0).columns.tolist()\n        self.imu_acc_cols_base = ['acc_x', 'acc_y', 'acc_z', 'linear_acc_x', 'linear_acc_y', 'linear_acc_z'] if self.config.get(\"add_raw_acc\", False) else ['linear_acc_x', 'linear_acc_y', 'linear_acc_z']\n        self.imu_rot_cols_base = ['rot_w', 'rot_x', 'rot_y', 'rot_z']\n        self.imu_cols_base = self.imu_acc_cols_base + self.imu_rot_cols_base + self.sum_imu_features +\\\n                                self.ms_rot_features + self.md_rot_features + self.jerk + self.rot_magnitude +\\\n                                self.rolling_mean + self.rot_jerk + self.rot_xyz\n        self.imu_cols = list()\n        self.imu_channel_keys = defaultdict(list)\n        if self.config.get(\"add_imu_base\", True): \n            self.imu_cols.extend(self.imu_cols_base)\n            self.imu_channel_keys[\"acc\"] = self.imu_acc_cols_base\n            self.imu_channel_keys[\"rot\"] = self.imu_rot_cols_base\n            self.imu_channel_keys[\"sum\"] = self.sum_imu_features\n            self.imu_channel_keys[\"ms\"] = self.ms_rot_features\n            self.imu_channel_keys[\"md\"] = self.md_rot_features\n            self.imu_channel_keys[\"jerk\"] = self.jerk\n            self.imu_channel_keys[\"rot_magnitude\"] = self.rot_magnitude\n            self.imu_channel_keys[\"roll_mean\"] = self.rolling_mean\n            self.imu_channel_keys[\"angular_jerk\"] = self.rot_jerk\n            self.imu_channel_keys[\"rot_xyz\"] = self.rot_xyz\n        if self.config.get(\"add_imu_feats\", True): \n            self.imu_cols.extend(self.imu_features)\n            if self.config.get(\"split_imu_feat\", False):\n                if self.config.get(\"old_imu_feat\", True):\n                    assert False, \"split_imu_feat=True and old_imu_feat=True not supported\"\n                self.imu_channel_keys[\"acc_feat\"] = self.acc_features\n                self.imu_channel_keys[\"rot_feat\"] = self.rot_features\n            else:\n                if self.config.get(\"old_imu_feat\", True):\n                    self.imu_channel_keys[\"other\"].extend(self.old_imu_features)\n                else:\n                    self.imu_channel_keys[\"other\"].extend(self.acc_features)\n                    self.imu_channel_keys[\"other\"].extend(self.rot_features)\n        if self.config.get(\"add_imu_er_feats\", False): \n            self.imu_cols.extend(self.er_fearues)\n            if self.config.get(\"split_imu_feat\", False):\n                self.imu_channel_keys[\"er1_feat\"] = self.er1_fearues\n                self.imu_channel_keys[\"er2_feat\"] = self.er2_fearues\n            else:\n                self.imu_channel_keys[\"other\"].extend(self.er1_fearues)\n                self.imu_channel_keys[\"other\"].extend(self.er2_fearues)\n        self.flip_imu_cols = [f\"{col}_flip\" for col in self.imu_cols]\n        self.imu_channel_keys = {k: sorted(v) for k, v in self.imu_channel_keys.items()}\n        self.thm_cols = [c for c in self.raw_columns if c.startswith('thm_')] + ['thm_right_chain','thm_left_chain','thm_center_chain','thm_height_chain','thm_weight_chain']\n        self.thm_cols1 = [c for c in self.raw_columns if c.startswith('thm_')] #+ ['thm_right_chain','thm_left_chain','thm_center_chain','thm_height_chain','thm_weight_chain']\n        self.thm_cols2 = ['thm_right_chain','thm_left_chain','thm_center_chain','thm_height_chain','thm_weight_chain']\n        self.thm_channel_keys = {k+1: [a,b] for k,(a,b) in enumerate(zip(self.thm_cols1,self.thm_cols2))}  #{k: [f\"thm_{k}\"] for k in range(1, 6)}\n        self.feature_cols = self.imu_cols + self.thm_cols + self.tof_cols\n        self.imu_dim = len(self.imu_cols)\n        self.thm_dim = len(self.thm_cols)\n        self.tof_dim = len(self.tof_cols)\n        self.base_cols = ['acc_x', 'acc_y', 'acc_z',\n                          'rot_x', 'rot_y', 'rot_z', 'rot_w',\n                          'sequence_id', 'subject', \n                          'sequence_type', 'gesture', 'orientation'] + [c for c in self.raw_columns if c.startswith('thm_')] + [f\"tof_{i}_v{p}\" for i in range(1, 6) for p in range(64)]\n        self.use_cols = self.base_cols + self.feature_cols\n        if self.config.get(\"return_flip_imu\", False):\n            self.use_cols.extend(self.flip_imu_cols)\n        self.fold_cols = ['subject', 'sequence_type', 'gesture', 'orientation', 'sequence_id']\n        if self.config.get(\"use_dg\", False):\n            self.dg_cols = ['adult_child', 'age', 'sex', 'handedness', 'shoulder_to_wrist_height', 'elbow_to_wrist_height']\n        self.global_imu_indices = {k: sorted([self.imu_cols.index(feat) for feat in feats]) for k, feats in self.imu_channel_keys.items()}\n        self.global_thm_indices = {k: sorted([self.thm_cols.index(key) for key in self.thm_channel_keys[k]]) for k in range(1, 6)}\n        self.global_tof_indices = {k: sorted([self.tof_cols.index(key) for key in self.tof_channel_keys[k]]) for k in range(1, 6)}\n            \n    def generate_tof_feature_names(self):\n        features = list()\n        self.tof_channel_keys = defaultdict(list)\n        if self.config.get(\"tof_raw\", False):\n            for i in range(1, 6):\n                features.extend([f\"tof_{i}_v{p}\" for p in range(64)])\n                self.tof_channel_keys[i].extend([f\"tof_{i}_v{p}\" for p in range(64)])\n        for i in range(1, 6):\n            if self.tof_mode != 0:\n                for stat in self.tof_region_stats:\n                    features.append(f'tof_{i}_{stat}')\n                    self.tof_channel_keys[i].append(f'tof_{i}_{stat}')\n                if self.tof_mode > 1:\n                    for r in range(self.tof_mode):\n                        for stat in self.tof_region_stats:\n                            features.append(f'tof{self.tof_mode}_{i}_region_{r}_{stat}')\n                            self.tof_channel_keys[i].append(f'tof{self.tof_mode}_{i}_region_{r}_{stat}')\n                if self.tof_mode == -1:\n                    for mode in [2, 4, 8, 16, 32]:\n                        for r in range(mode):\n                            for stat in self.tof_region_stats:\n                                features.append(f'tof{mode}_{i}_region_{r}_{stat}')\n                                self.tof_channel_keys[i].append(f'tof{mode}_{i}_region_{r}_{stat}')\n        return features\n\n    def compute_cross_axis_energy(self, df):\n        axes=['x', 'y', 'z']\n        features = {}\n        for axis in axes:\n            fft_result = fft(df[f'acc_{axis}'].values)\n            energy = np.sum(np.abs(fft_result)**2)\n            features[f\"er_{axis}\"] = energy\n        for i, axis1 in enumerate(axes):\n            for axis2 in axes[i+1:]:\n                features[f'er_r_{axis1}{axis2}'] = features[f'er_{axis1}'] / (features[f'er_{axis2}'] + 1e-6)\n        for i, axis1 in enumerate(axes):\n            for axis2 in axes[i+1:]:\n                features[f'er_c_{axis1}{axis2}'] = np.corrcoef(np.abs(fft(df[f'acc_{axis1}'].values)), np.abs(fft(df[f'acc_{axis2}'].values)))[0, 1]\n        return {k: v for k, v in features.items() if k in self.er_fearues}\n\n    def compute_imu_features(self, df):\n        if self.config.get(\"rot_fillna\", False):\n            df['rot_w'] = df['rot_w'].fillna(1)\n            df[['rot_x', 'rot_y', 'rot_z']] = df[['rot_x', 'rot_y', 'rot_z']].fillna(0)\n        df['acc_mag'] = np.sqrt(df['acc_x']**2 + df['acc_y']**2 + df['acc_z']**2)\n        df['rot_angle'] = 2 * np.arccos(df['rot_w'].clip(-1, 1))\n        df['acc_mag_jerk'] = df.groupby('sequence_id')['acc_mag'].diff().fillna(0)\n        df['rot_angle_vel'] = df.groupby('sequence_id')['rot_angle'].diff().fillna(0)\n            \n        linear_accel_list = []\n        for _, group in df.groupby('sequence_id'):\n            acc_data_group = group[['acc_x', 'acc_y', 'acc_z']]\n            rot_data_group = group[['rot_x', 'rot_y', 'rot_z', 'rot_w']]\n            linear_accel_group = remove_gravity_from_acc(acc_data_group, rot_data_group)\n            linear_accel_list.append(pd.DataFrame(linear_accel_group, columns=['linear_acc_x', 'linear_acc_y', 'linear_acc_z'], index=group.index))\n        df_linear_accel = pd.concat(linear_accel_list)\n        df = pd.concat([df, df_linear_accel], axis=1)\n        df['linear_acc_mag'] = np.sqrt(df['linear_acc_x']**2 + df['linear_acc_y']**2 + df['linear_acc_z']**2)\n        df['linear_acc_mag_jerk'] = df.groupby('sequence_id')['linear_acc_mag'].diff().fillna(0)\n    \n        angular_vel_list = []\n        for _, group in df.groupby('sequence_id'):\n            rot_data_group = group[['rot_x', 'rot_y', 'rot_z', 'rot_w']]\n            angular_vel_group = calculate_angular_velocity_from_quat(rot_data_group)\n            angular_vel_list.append(pd.DataFrame(angular_vel_group, columns=['angular_vel_x', 'angular_vel_y', 'angular_vel_z'], index=group.index))\n        df_angular_vel = pd.concat(angular_vel_list)\n        df = pd.concat([df, df_angular_vel], axis=1)\n    \n        angular_distance_list = []\n        for _, group in df.groupby('sequence_id'):\n            rot_data_group = group[['rot_x', 'rot_y', 'rot_z', 'rot_w']]\n            angular_dist_group = calculate_angular_distance(rot_data_group)\n            angular_distance_list.append(pd.DataFrame(angular_dist_group, columns=['angular_distance'], index=group.index))\n        df_angular_distance = pd.concat(angular_distance_list)\n        df = pd.concat([df, df_angular_distance], axis=1)\n\n        # linear_acc_x linear_acc_y linear_acc_z\n        ##################################modified features#####################################################\n        df[\"acc_xy_magnitude\"] = np.sqrt(df[\"linear_acc_x\"] ** 2 + df[\"linear_acc_y\"] ** 2)\n        df[\"acc_xz_magnitude\"] = np.sqrt(df[\"linear_acc_x\"] ** 2 + df[\"linear_acc_y\"] ** 2)\n        df[\"acc_yz_magnitude\"] = np.sqrt(df[\"linear_acc_y\"] ** 2 + df[\"linear_acc_z\"] ** 2)\n\n        # Additive combinations\n        df[\"acc_xy_sum\"] = df[\"linear_acc_x\"] + df[\"linear_acc_y\"]\n        df[\"acc_yz_sum\"] = df[\"linear_acc_y\"] + df[\"linear_acc_z\"]\n        df[\"acc_xz_sum\"] = df[\"linear_acc_x\"] + df[\"linear_acc_z\"]\n\n        # Subtractive combinations\n        df[\"acc_xy_diff\"] = df[\"linear_acc_x\"] - df[\"linear_acc_y\"]\n        df[\"acc_yz_diff\"] = df[\"linear_acc_y\"] - df[\"linear_acc_z\"]\n        df[\"acc_xz_diff\"] = df[\"linear_acc_x\"] - df[\"linear_acc_z\"]\n\n        # Triple-axis interactions\n        df[\"acc_xy_z_net\"] = df[\"linear_acc_x\"] + df[\"linear_acc_y\"] - df[\"linear_acc_z\"]\n        df[\"acc_yz_x_net\"] = df[\"linear_acc_y\"] + df[\"linear_acc_z\"] - df[\"linear_acc_x\"]\n        df[\"acc_xz_y_net\"] = df[\"linear_acc_x\"] + df[\"linear_acc_z\"] - df[\"linear_acc_y\"]\n\n####################################################################################\n        # df[\"acc_xy_magnitude\"] = np.sqrt(df[\"acc_x\"] ** 2 + df[\"acc_y\"] ** 2)\n        # df[\"acc_xz_magnitude\"] = np.sqrt(df[\"acc_x\"] ** 2 + df[\"acc_z\"] ** 2)\n        # df[\"acc_yz_magnitude\"] = np.sqrt(df[\"acc_y\"] ** 2 + df[\"acc_z\"] ** 2)\n\n        # # Additive combinations\n        # df[\"acc_xy_sum\"] = df[\"acc_x\"] + df[\"acc_y\"]\n        # df[\"acc_yz_sum\"] = df[\"acc_y\"] + df[\"acc_z\"]\n        # df[\"acc_xz_sum\"] = df[\"acc_x\"] + df[\"acc_z\"]\n\n        # # Subtractive combinations\n        # df[\"acc_xy_diff\"] = df[\"acc_x\"] - df[\"acc_y\"]\n        # df[\"acc_yz_diff\"] = df[\"acc_y\"] - df[\"acc_z\"]\n        # df[\"acc_xz_diff\"] = df[\"acc_x\"] - df[\"acc_z\"]\n\n        # # Triple-axis interactions\n        # df[\"acc_xy_z_net\"] = df[\"acc_x\"] + df[\"acc_y\"] - df[\"acc_z\"]\n        # df[\"acc_yz_x_net\"] = df[\"acc_y\"] + df[\"acc_z\"] - df[\"acc_x\"]\n        # df[\"acc_xz_y_net\"] = df[\"acc_x\"] + df[\"acc_z\"] - df[\"acc_y\"]\n###############################################################################        \n\n        # Linear combinations \n        df[\"rot_xy_z_net\"] = df[\"rot_x\"] + df[\"rot_y\"] - df[\"rot_z\"] \n        df[\"rot_yz_x_net\"] = df[\"rot_y\"] + df[\"rot_z\"] - df[\"rot_x\"]\n        df[\"rot_xz_y_net\"] = df[\"rot_x\"] + df[\"rot_z\"] - df[\"rot_y\"]\n\n        df[\"rot_xw_z_net\"] = df[\"rot_x\"] + df[\"rot_w\"] - df[\"rot_z\"]\n        df[\"rot_yw_x_net\"] = df[\"rot_y\"] + df[\"rot_w\"] - df[\"rot_x\"]\n        df[\"rot_xw_y_net\"] = df[\"rot_x\"] + df[\"rot_w\"] - df[\"rot_y\"]\n\n        # Multiplicative + subtractive\n        df[\"rot_xw_z_net_ms\"] = df[\"rot_x\"] * df[\"rot_w\"] - df[\"rot_z\"]\n        df[\"rot_yw_x_net_ms\"] = df[\"rot_y\"] * df[\"rot_w\"] - df[\"rot_x\"]\n        df[\"rot_xw_y_net_ms\"] = df[\"rot_x\"] * df[\"rot_w\"] - df[\"rot_y\"]\n\n        df[\"rot_xy_z_net_ms\"] = df[\"rot_x\"] * df[\"rot_y\"] - df[\"rot_z\"]\n        df[\"rot_yz_x_net_ms\"] = df[\"rot_y\"] * df[\"rot_z\"] - df[\"rot_x\"]\n        df[\"rot_zw_y_net_ms\"] = df[\"rot_z\"] * df[\"rot_w\"] - df[\"rot_y\"]\n\n        # Division + subtractive\n        df[\"rot_xw_z_net_md\"] = df[\"rot_x\"] / df[\"rot_w\"] - df[\"rot_z\"]\n        df[\"rot_yw_x_net_md\"] = df[\"rot_y\"] / df[\"rot_w\"] - df[\"rot_x\"]\n        df[\"rot_xw_y_net_md\"] = df[\"rot_x\"] / df[\"rot_w\"] - df[\"rot_y\"]\n\n        df[\"rot_xy_z_net_md\"] = df[\"rot_x\"] / df[\"rot_y\"] - df[\"rot_z\"]\n        df[\"rot_yz_x_net_md\"] = df[\"rot_y\"] / df[\"rot_z\"] - df[\"rot_x\"]\n        df[\"rot_zw_y_net_md\"] = df[\"rot_z\"] / df[\"rot_w\"] - df[\"rot_y\"]\n\n        # Pairwise interactions\n        df[\"rot_xy_plus_zw\"] = df[\"rot_x\"] * df[\"rot_y\"] + df[\"rot_z\"] * df[\"rot_w\"]\n        df[\"rot_xz_plus_yw\"] = df[\"rot_x\"] * df[\"rot_z\"] + df[\"rot_y\"] * df[\"rot_w\"]\n        df[\"rot_xw_plus_yz\"] = df[\"rot_x\"] * df[\"rot_w\"] + df[\"rot_y\"] * df[\"rot_z\"]\n\n        # Ratios with numerical stability\n        df[\"rot_xy_over_zw\"] = (df[\"rot_x\"] + df[\"rot_y\"]) / (df[\"rot_z\"] + df[\"rot_w\"] + 1e-6)\n        df[\"rot_xz_over_yw\"] = (df[\"rot_x\"] + df[\"rot_z\"]) / (df[\"rot_y\"] + df[\"rot_w\"] + 1e-6)\n        df[\"rot_xw_over_yz\"] = (df[\"rot_x\"] + df[\"rot_w\"]) / (df[\"rot_y\"] + df[\"rot_z\"] + 1e-6)\n\n        # Angular jerk (difference over sequence_id)\n        df[\"angular_jerk_x\"] = df.groupby(\"sequence_id\")[\"angular_vel_x\"].diff()\n        df[\"angular_jerk_y\"] = df.groupby(\"sequence_id\")[\"angular_vel_y\"].diff()\n        df[\"angular_jerk_z\"] = df.groupby(\"sequence_id\")[\"angular_vel_z\"].diff()\n        \n        # Rotation magnitudes\n        df[\"rot_xyz_magnitude\"] = np.sqrt(df[\"rot_x\"]**2 + df[\"rot_y\"]**2 + df[\"rot_z\"]**2)\n        df[\"rot_xyw_magnitude\"] = np.sqrt(df[\"rot_x\"]**2 + df[\"rot_y\"]**2 + df[\"rot_w\"]**2)\n        df[\"rot_xzw_magnitude\"] = np.sqrt(df[\"rot_x\"]**2 + df[\"rot_z\"]**2 + df[\"rot_w\"]**2)\n        df[\"rot_yzw_magnitude\"] = np.sqrt(df[\"rot_y\"]**2 + df[\"rot_z\"]**2 + df[\"rot_w\"]**2)\n        df[\"rot_full_magnitude\"] = np.sqrt(df[\"rot_x\"]**2 + df[\"rot_y\"]**2 + df[\"rot_z\"]**2 + df[\"rot_w\"]**2)\n        \n        # Rolling means over sequence_id\n        df[\"acc_mag_smooth_mean\"] = df.groupby(\"sequence_id\")[\"acc_mag\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean())\n        df[\"linear_acc_mean\"] = df.groupby(\"sequence_id\")[\"linear_acc_mag\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean())\n        df[\"rot_full_magnitude_mean\"] = df.groupby(\"sequence_id\")[\"rot_full_magnitude\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean()) \n\n        # df[\"angular_jerk_x\"] = df.groupby(\"sequence_id\")[\"angular_vel_x\"].diff()\n        # df[\"angular_jerk_y\"] = df.groupby(\"sequence_id\")[\"angular_vel_y\"].diff()\n        # df[\"angular_jerk_z\"] = df.groupby(\"sequence_id\")[\"angular_vel_z\"].diff()\n\n        df[\"rot_xy_over_zw\"] = ((df[\"rot_x\"] + df[\"rot_y\"]) / (df[\"rot_z\"] + df[\"rot_w\"]+ 1e-6)).clip(-47.0799630, 48.1292149256)\n        \n        # rot_xz_over_yw\n        df[\"rot_xz_over_yw\"] = ((df[\"rot_x\"] + df[\"rot_z\"]) / (df[\"rot_y\"] + df[\"rot_w\"]+ 1e-6)).clip(-47.0799630, 48.1292149256)\n        \n        # rot_xw_over_yz\n        df[\"rot_xw_over_yz\"] = ((df[\"rot_x\"] + df[\"rot_w\"]) / (df[\"rot_y\"] + df[\"rot_z\"]+ 1e-6)).clip(-47.0799630, 48.1292149256) \n\n        df[\"rot_w_vel\"] = df.groupby(\"sequence_id\")[\"rot_w\"].diff()\n        df[\"rot_x_vel\"] = df.groupby(\"sequence_id\")[\"rot_x\"].diff()\n        df[\"rot_y_vel\"] = df.groupby(\"sequence_id\")[\"rot_y\"].diff()\n        df[\"rot_z_vel\"] = df.groupby(\"sequence_id\")[\"rot_z\"].diff()\n\n        def mean_abs_chain(diffs):\n            return sum(d.abs() for d in diffs) / len(diffs)\n        \n        df['thm_right_chain'] = mean_abs_chain([\n            df['thm_3'] - df['thm_2'],\n            df['thm_3'] - df['thm_1'],\n            df['thm_3'] - df['thm_4'],\n        ])\n        \n        df['thm_left_chain'] = mean_abs_chain([\n            df['thm_5'] - df['thm_2'],\n            df['thm_5'] - df['thm_1'],\n            df['thm_5'] - df['thm_4'],\n        ])\n        \n        df['thm_center_chain'] = mean_abs_chain([\n            df['thm_1'] - df['thm_2'],\n            df['thm_1'] - df['thm_3'],\n            df['thm_1'] - df['thm_4'],\n            df['thm_1'] - df['thm_5'],\n        ])\n        \n        df['thm_height_chain'] = mean_abs_chain([\n            df['thm_2'] - df['thm_1'],\n            df['thm_1'] - df['thm_4'],\n        ])\n        \n        df['thm_weight_chain'] = mean_abs_chain([\n            df['thm_4'] - df['thm_1'],\n            df['thm_3'] - df['thm_2'],\n        ])\n        \n        return df\n\n    def compute_flip_features(self, df):\n        flip_df = df[['sequence_id', 'acc_x', 'acc_y', 'acc_z', 'rot_x', 'rot_y', 'rot_z', 'rot_w']].copy()\n        flip_df[['acc_x', 'acc_y', 'rot_x', 'rot_y']] *= -1\n        flip_df = self.compute_imu_features(flip_df)\n        for col in flip_df.columns:\n            if col != 'sequence_id':\n                df[f\"{col}_flip\"] = flip_df[col]\n        return df\n\n    def compute_features(self, df):\n        df = self.compute_imu_features(df)\n        if self.tof_mode != 0:\n            new_columns = {}\n            for i in range(1, 6):\n                pixel_cols = [f\"tof_{i}_v{p}\" for p in range(64)]\n                tof_data = df[pixel_cols].replace(-1, np.nan)\n                new_columns.update({\n                    f'tof_{i}_mean': tof_data.mean(axis=1),\n                    f'tof_{i}_std': tof_data.std(axis=1),\n                    f'tof_{i}_min': tof_data.min(axis=1),\n                    f'tof_{i}_max': tof_data.max(axis=1)\n                })\n                if self.tof_mode > 1:\n                    region_size = 64 // self.tof_mode\n                    for r in range(self.tof_mode):\n                        region_data = tof_data.iloc[:, r*region_size : (r+1)*region_size]\n                        new_columns.update({\n                            f'tof{self.tof_mode}_{i}_region_{r}_mean': region_data.mean(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_std': region_data.std(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_min': region_data.min(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_max': region_data.max(axis=1)\n                        })\n                if self.tof_mode == -1:\n                    for mode in [2, 4, 8, 16, 32]:\n                        region_size = 64 // mode\n                        for r in range(mode):\n                            region_data = tof_data.iloc[:, r*region_size : (r+1)*region_size]\n                            new_columns.update({\n                                f'tof{mode}_{i}_region_{r}_mean': region_data.mean(axis=1),\n                                f'tof{mode}_{i}_region_{r}_std': region_data.std(axis=1),\n                                f'tof{mode}_{i}_region_{r}_min': region_data.min(axis=1),\n                                f'tof{mode}_{i}_region_{r}_max': region_data.max(axis=1)\n                            })\n            df = pd.concat([df, pd.DataFrame(new_columns)], axis=1)\n            \n        def _calc_features(group):\n            return pd.DataFrame(self.compute_cross_axis_energy(group), index=[group.index[0]])\n        features_df = df.groupby('sequence_id', group_keys=False).apply(_calc_features)\n        df = df.join(features_df, how='left')\n        df[features_df.columns] = df.groupby('sequence_id')[features_df.columns].ffill()\n        \n        return df\n        \n    def generate_features(self, df):\n        self.le = LabelEncoder()\n        if self.config.get(\"one_neg\", False):\n            neg_other = \"Write name on leg\"\n            df['gesture'] = df['gesture'].apply(lambda x: x if x in self.target_gestures else neg_other)\n        df['gesture_int'] = self.le.fit_transform(df['gesture'])\n        self.class_num = len(self.le.classes_)\n        self.target_ints = np.array([self.le.classes_.tolist().index(name) for name in self.target_gestures])\n        self.non_target_ints = np.array([self.le.classes_.tolist().index(name) for name in self.non_target_gestures])\n        \n        if all(c in df.columns for c in self.feature_cols):\n            print(\"Features have precomputed, skip compute.\")\n        else:\n            print(\"Features not precomputed, do compute.\")\n            df = self.compute_features(df)\n\n        if self.config.get(\"return_flip_imu\", False):\n            if all(c in df.columns for c in self.flip_imu_cols):\n                print(\"Flip have precomputed, skip compute.\")\n            else:\n                print(\"Flip not precomputed, do compute.\")\n                df = self.compute_flip_features(df)\n\n        if self.config.get(\"use_dg\", False):\n            dg_df = pd.read_csv(self.config[\"dg_path\"])\n            df = pd.merge(df, dg_df, how='left', on='subject')\n            df['age'] /= 100\n            df['shoulder_to_wrist_height'] = df['shoulder_to_wrist_cm'] / df['height_cm']\n            df['elbow_to_wrist_height'] = df['elbow_to_wrist_cm'] / df['height_cm']\n        \n        if self.config.get(\"save_precompute\", False):\n            df.to_csv(self.config.get(\"save_filename\", \"train.csv\"))\n        return df\n\n    def scale(self, data_unscaled):\n        scaler_function = self.config.get(\"scaler_function\", StandardScaler())\n        scaler = scaler_function.fit(np.concatenate(data_unscaled, axis=0))\n        return [scaler.transform(x) for x in data_unscaled], scaler\n\n    def pad(self, data_scaled, cols):\n        pad_data = np.zeros((len(data_scaled), self.pad_len, len(cols)), dtype='float32')\n        for i, seq in enumerate(data_scaled):\n            seq_len = min(len(seq), self.pad_len)\n            pad_data[i, :seq_len] = seq[:seq_len]\n        return pad_data\n\n    def get_nan_value(self, data, ratio):\n        max_value = data.max().max()\n        nan_value = -max_value * ratio\n        print(f\"Max: {max_value}, set nan to {nan_value}\")\n        return nan_value\n\n    def generate_dataset(self, df):\n        seq_gp = df.groupby('sequence_id') \n        imu_unscaled, thm_unscaled, tof_unscaled = list(), list(), list()\n        if self.config.get(\"return_flip_imu\", False): flip_imu_unscaled = list()\n        classes, lens = list(), list()\n        self.imu_nan_value = self.get_nan_value(df[self.imu_cols], self.config[\"nan_ratio\"][\"imu\"])\n        self.thm_nan_value = self.get_nan_value(df[self.thm_cols], self.config[\"nan_ratio\"][\"thm\"])\n        self.tof_nan_value = self.get_nan_value(df[self.tof_cols], self.config[\"nan_ratio\"][\"tof\"])\n        if self.config.get(\"use_dg\", False):\n            self.dg = list()\n\n        self.fold_feats = defaultdict(list)\n        for seq_id, seq_df in seq_gp:\n            imu_data = seq_df[self.imu_cols]\n            if self.config[\"fbfill\"][\"imu\"]:\n                imu_data = imu_data.ffill().bfill()\n            imu_unscaled.append(imu_data.fillna(self.imu_nan_value).values.astype('float32'))\n\n            if self.config.get(\"return_flip_imu\", False):\n                flip_imu_data = seq_df[self.flip_imu_cols]\n                if self.config[\"fbfill\"][\"imu\"]:\n                    flip_imu_data = flip_imu_data.ffill().bfill()\n                flip_imu_unscaled.append(flip_imu_data.fillna(self.imu_nan_value).values.astype('float32'))\n\n            thm_data = seq_df[self.thm_cols]\n            if self.config[\"fbfill\"][\"thm\"]:\n                thm_data = thm_data.ffill().bfill()\n            thm_unscaled.append(thm_data.fillna(self.thm_nan_value).values.astype('float32'))\n\n            tof_data = seq_df[self.tof_cols]\n            if self.config[\"fbfill\"][\"tof\"]:\n                tof_data = tof_data.ffill().bfill()\n            tof_unscaled.append(tof_data.fillna(self.tof_nan_value).values.astype('float32'))\n            \n            classes.append(seq_df['gesture_int'].iloc[0])\n            lens.append(len(imu_data))\n\n            for col in self.fold_cols:\n                self.fold_feats[col].append(seq_df[col].iloc[0])\n\n            if self.config.get(\"use_dg\", False):\n                self.dg.append(seq_df[self.dg_cols].iloc[0].values.astype('float32'))\n            \n        self.dataset_indices = classes\n        self.pad_len = int(np.percentile(lens, self.config.get(\"percent\", 95)))\n        if self.config.get(\"one_scale\", True):\n            x_unscaled = [np.concatenate([imu, thm, tof], axis=1) for imu, thm, tof in zip(imu_unscaled, thm_unscaled, tof_unscaled)]\n            x_scaled, self.x_scaler = self.scale(x_unscaled)\n            x = self.pad(x_scaled, self.imu_cols+self.thm_cols+self.tof_cols)\n            self.imu = x[..., :self.imu_dim]\n            self.thm = x[..., self.imu_dim:self.imu_dim+self.thm_dim]\n            self.tof = x[..., self.imu_dim+self.thm_dim:self.imu_dim+self.thm_dim+self.tof_dim]\n\n            if self.config.get(\"return_flip_imu\", False):\n                flip_x_unscaled = [np.concatenate([flip_imu, thm, tof], axis=1) for flip_imu, thm, tof in zip(flip_imu_unscaled, thm_unscaled, tof_unscaled)]\n                flip_x_scaled = [self.x_scaler.transform(x) for x in flip_x_unscaled]\n                flip_x = self.pad(flip_x_scaled, self.imu_cols+self.thm_cols+self.tof_cols)\n                self.flip_imu = flip_x[..., :self.imu_dim]\n        else:\n            imu_scaled, self.imu_scaler = self.scale(imu_unscaled)\n            thm_scaled, self.thm_scaler = self.scale(thm_unscaled)\n            tof_scaled, self.tof_scaler = self.scale(tof_unscaled)\n            self.imu = self.pad(imu_scaled, self.imu_cols)\n            self.thm = self.pad(thm_scaled, self.thm_cols)\n            self.tof = self.pad(tof_scaled, self.tof_cols)\n\n            if self.config.get(\"return_flip_imu\", False):\n                flip_imu_scaled = [self.imu_scaler.transform(x) for x in flip_imu_unscaled]\n                self.flip_imu = self.pad(flip_imu_scaled, self.imu_cols)\n        self.precompute_scaled_nan_values()\n        self.class_ = F.one_hot(torch.from_numpy(np.array(classes)).long(), num_classes=len(self.le.classes_)).float().numpy()\n        self.binary_class_ = np.isin(np.array(classes), self.target_ints).astype(np.float32)\n        self.class_weight = torch.FloatTensor(compute_class_weight('balanced', classes=np.arange(len(self.le.classes_)), y=classes))\n\n    def precompute_scaled_nan_values(self):\n        dummy_df = pd.DataFrame(\n            np.array([[self.imu_nan_value]*len(self.imu_cols) + \n                     [self.thm_nan_value]*len(self.thm_cols) +\n                     [self.tof_nan_value]*len(self.tof_cols)]),\n            columns=self.imu_cols + self.thm_cols + self.tof_cols\n        )\n        \n        if self.config.get(\"one_scale\", True):\n            scaled = self.x_scaler.transform(dummy_df)\n            self.imu_scaled_nan = scaled[0, :self.imu_dim].mean()\n            self.thm_scaled_nan = scaled[0, self.imu_dim:self.imu_dim+self.thm_dim].mean()\n            self.tof_scaled_nan = scaled[0, self.imu_dim+self.thm_dim:self.imu_dim+self.thm_dim+self.tof_dim].mean()\n        else:\n            self.imu_scaled_nan = self.imu_scaler.transform(dummy_df[self.imu_cols])[0].mean()\n            self.thm_scaled_nan = self.thm_scaler.transform(dummy_df[self.thm_cols])[0].mean()\n            self.tof_scaled_nan = self.tof_scaler.transform(dummy_df[self.tof_cols])[0].mean()\n\n    def get_scaled_nan_tensors(self, imu, thm, tof):\n        return torch.full(imu.shape, self.imu_scaled_nan, device=imu.device), \\\n            torch.full(thm.shape, self.thm_scaled_nan, device=thm.device), \\\n            torch.full(tof.shape, self.tof_scaled_nan, device=tof.device)\n\n    def inference_process(self, sequence, demographics=None, reverse=False):\n        if self.config.get(\"use_dg\", False):\n            assert demographics is not None, \"Demographics needed\"\n            df_dg = demographics.to_pandas().copy()\n            df_dg['age'] /= 100\n            df_dg['shoulder_to_wrist_height'] = df_dg['shoulder_to_wrist_cm'] / df_dg['height_cm']\n            df_dg['elbow_to_wrist_height'] = df_dg['elbow_to_wrist_cm'] / df_dg['height_cm']\n        df_seq = sequence.to_pandas().copy()\n        if reverse:\n            df_seq[['acc_x', 'acc_y', 'rot_x', 'rot_y']] *= -1\n        if self.config.get(\"rot_fillna\", False):\n            df_seq['rot_w'] = df_seq['rot_w'].fillna(1)\n            df_seq[['rot_x', 'rot_y', 'rot_z']] = df_seq[['rot_x', 'rot_y', 'rot_z']].fillna(0)\n        if not all(c in df_seq.columns for c in self.imu_features):\n            df_seq['acc_mag'] = np.sqrt(df_seq['acc_x']**2 + df_seq['acc_y']**2 + df_seq['acc_z']**2)\n            df_seq['rot_angle'] = 2 * np.arccos(df_seq['rot_w'].clip(-1, 1))\n            df_seq['acc_mag_jerk'] = df_seq['acc_mag'].diff().fillna(0)\n            df_seq['rot_angle_vel'] = df_seq['rot_angle'].diff().fillna(0)\n            if all(col in df_seq.columns for col in ['acc_x', 'acc_y', 'acc_z', 'rot_x', 'rot_y', 'rot_z', 'rot_w']):\n                linear_accel = remove_gravity_from_acc(\n                    df_seq[['acc_x', 'acc_y', 'acc_z']], \n                    df_seq[['rot_x', 'rot_y', 'rot_z', 'rot_w']]\n                )\n                df_seq[['linear_acc_x', 'linear_acc_y', 'linear_acc_z']] = linear_accel\n            else:\n                df_seq['linear_acc_x'] = df_seq.get('acc_x', 0)\n                df_seq['linear_acc_y'] = df_seq.get('acc_y', 0)\n                df_seq['linear_acc_z'] = df_seq.get('acc_z', 0)\n            df_seq['linear_acc_mag'] = np.sqrt(df_seq['linear_acc_x']**2 + df_seq['linear_acc_y']**2 + df_seq['linear_acc_z']**2)\n            df_seq['linear_acc_mag_jerk'] = df_seq['linear_acc_mag'].diff().fillna(0)\n            if all(col in df_seq.columns for col in ['rot_x', 'rot_y', 'rot_z', 'rot_w']):\n                angular_vel = calculate_angular_velocity_from_quat(df_seq[['rot_x', 'rot_y', 'rot_z', 'rot_w']])\n                df_seq[['angular_vel_x', 'angular_vel_y', 'angular_vel_z']] = angular_vel\n            else:\n                df_seq[['angular_vel_x', 'angular_vel_y', 'angular_vel_z']] = 0\n            if all(col in df_seq.columns for col in ['rot_x', 'rot_y', 'rot_z', 'rot_w']):\n                df_seq['angular_distance'] = calculate_angular_distance(df_seq[['rot_x', 'rot_y', 'rot_z', 'rot_w']])\n            else:\n                df_seq['angular_distance'] = 0\n\n                 # linear_acc_x linear_acc_y linear_acc_z\n        ##################################modified features#####################################################\n        df_seq[\"acc_xy_magnitude\"] = np.sqrt(df_seq[\"linear_acc_x\"] ** 2 + df_seq[\"linear_acc_y\"] ** 2)\n        df_seq[\"acc_xz_magnitude\"] = np.sqrt(df_seq[\"linear_acc_x\"] ** 2 + df_seq[\"linear_acc_y\"] ** 2)\n        df_seq[\"acc_yz_magnitude\"] = np.sqrt(df_seq[\"linear_acc_y\"] ** 2 + df_seq[\"linear_acc_z\"] ** 2)\n\n        # Additive combinations\n        df_seq[\"acc_xy_sum\"] = df_seq[\"linear_acc_x\"] + df_seq[\"linear_acc_y\"]\n        df_seq[\"acc_yz_sum\"] = df_seq[\"linear_acc_y\"] + df_seq[\"linear_acc_z\"]\n        df_seq[\"acc_xz_sum\"] = df_seq[\"linear_acc_x\"] + df_seq[\"linear_acc_z\"]\n\n        # Subtractive combinations\n        df_seq[\"acc_xy_diff\"] = df_seq[\"linear_acc_x\"] - df_seq[\"linear_acc_y\"]\n        df_seq[\"acc_yz_diff\"] = df_seq[\"linear_acc_y\"] - df_seq[\"linear_acc_z\"]\n        df_seq[\"acc_xz_diff\"] = df_seq[\"linear_acc_x\"] - df_seq[\"linear_acc_z\"]\n\n        # Triple-axis interactions\n        df_seq[\"acc_xy_z_net\"] = df_seq[\"linear_acc_x\"] + df_seq[\"linear_acc_y\"] - df_seq[\"linear_acc_z\"]\n        df_seq[\"acc_yz_x_net\"] = df_seq[\"linear_acc_y\"] + df_seq[\"linear_acc_z\"] - df_seq[\"linear_acc_x\"]\n        df_seq[\"acc_xz_y_net\"] = df_seq[\"linear_acc_x\"] + df_seq[\"linear_acc_z\"] - df_seq[\"linear_acc_y\"]\n\n####################################################################################\n        # df_seq[\"acc_xy_magnitude\"] = np.sqrt(df_seq[\"acc_x\"] ** 2 + df_seq[\"acc_y\"] ** 2)\n        # df_seq[\"acc_xz_magnitude\"] = np.sqrt(df_seq[\"acc_x\"] ** 2 + df_seq[\"acc_z\"] ** 2)\n        # df_seq[\"acc_yz_magnitude\"] = np.sqrt(df_seq[\"acc_y\"] ** 2 + df_seq[\"acc_z\"] ** 2)\n\n        # # Additive combinations\n        # df_seq[\"acc_xy_sum\"] = df_seq[\"acc_x\"] + df_seq[\"acc_y\"]\n        # df_seq[\"acc_yz_sum\"] = df_seq[\"acc_y\"] + df_seq[\"acc_z\"]\n        # df_seq[\"acc_xz_sum\"] = df_seq[\"acc_x\"] + df_seq[\"acc_z\"]\n\n        # # Subtractive combinations\n        # df_seq[\"acc_xy_diff\"] = df_seq[\"acc_x\"] - df_seq[\"acc_y\"]\n        # df_seq[\"acc_yz_diff\"] = df_seq[\"acc_y\"] - df_seq[\"acc_z\"]\n        # df_seq[\"acc_xz_diff\"] = df_seq[\"acc_x\"] - df_seq[\"acc_z\"]\n\n        # # Triple-axis interactions\n        # df_seq[\"acc_xy_z_net\"] = df_seq[\"acc_x\"] + df_seq[\"acc_y\"] - df_seq[\"acc_z\"]\n        # df_seq[\"acc_yz_x_net\"] = df_seq[\"acc_y\"] + df_seq[\"acc_z\"] - df_seq[\"acc_x\"]\n        # df_seq[\"acc_xz_y_net\"] = df_seq[\"acc_x\"] + df_seq[\"acc_z\"] - df_seq[\"acc_y\"]\n###############################################################################        \n\n        # Linear combinations \n        df_seq[\"rot_xy_z_net\"] = df_seq[\"rot_x\"] + df_seq[\"rot_y\"] - df_seq[\"rot_z\"] \n        df_seq[\"rot_yz_x_net\"] = df_seq[\"rot_y\"] + df_seq[\"rot_z\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_xz_y_net\"] = df_seq[\"rot_x\"] + df_seq[\"rot_z\"] - df_seq[\"rot_y\"]\n\n        df_seq[\"rot_xw_z_net\"] = df_seq[\"rot_x\"] + df_seq[\"rot_w\"] - df_seq[\"rot_z\"]\n        df_seq[\"rot_yw_x_net\"] = df_seq[\"rot_y\"] + df_seq[\"rot_w\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_xw_y_net\"] = df_seq[\"rot_x\"] + df_seq[\"rot_w\"] - df_seq[\"rot_y\"]\n\n        # Multiplicative + subtractive\n        df_seq[\"rot_xw_z_net_ms\"] = df_seq[\"rot_x\"] * df_seq[\"rot_w\"] - df_seq[\"rot_z\"]\n        df_seq[\"rot_yw_x_net_ms\"] = df_seq[\"rot_y\"] * df_seq[\"rot_w\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_xw_y_net_ms\"] = df_seq[\"rot_x\"] * df_seq[\"rot_w\"] - df_seq[\"rot_y\"]\n\n        df_seq[\"rot_xy_z_net_ms\"] = df_seq[\"rot_x\"] * df_seq[\"rot_y\"] - df_seq[\"rot_z\"]\n        df_seq[\"rot_yz_x_net_ms\"] = df_seq[\"rot_y\"] * df_seq[\"rot_z\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_zw_y_net_ms\"] = df_seq[\"rot_z\"] * df_seq[\"rot_w\"] - df_seq[\"rot_y\"]\n\n        # Division + subtractive\n        df_seq[\"rot_xw_z_net_md\"] = df_seq[\"rot_x\"] / df_seq[\"rot_w\"] - df_seq[\"rot_z\"]\n        df_seq[\"rot_yw_x_net_md\"] = df_seq[\"rot_y\"] / df_seq[\"rot_w\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_xw_y_net_md\"] = df_seq[\"rot_x\"] / df_seq[\"rot_w\"] - df_seq[\"rot_y\"]\n\n        df_seq[\"rot_xy_z_net_md\"] = df_seq[\"rot_x\"] / df_seq[\"rot_y\"] - df_seq[\"rot_z\"]\n        df_seq[\"rot_yz_x_net_md\"] = df_seq[\"rot_y\"] / df_seq[\"rot_z\"] - df_seq[\"rot_x\"]\n        df_seq[\"rot_zw_y_net_md\"] = df_seq[\"rot_z\"] / df_seq[\"rot_w\"] - df_seq[\"rot_y\"]\n\n        # Pairwise interactions\n        df_seq[\"rot_xy_plus_zw\"] = df_seq[\"rot_x\"] * df_seq[\"rot_y\"] + df_seq[\"rot_z\"] * df_seq[\"rot_w\"]\n        df_seq[\"rot_xz_plus_yw\"] = df_seq[\"rot_x\"] * df_seq[\"rot_z\"] + df_seq[\"rot_y\"] * df_seq[\"rot_w\"]\n        df_seq[\"rot_xw_plus_yz\"] = df_seq[\"rot_x\"] * df_seq[\"rot_w\"] + df_seq[\"rot_y\"] * df_seq[\"rot_z\"]\n\n        # Ratios with numerical stability\n        df_seq[\"rot_xy_over_zw\"] = (df_seq[\"rot_x\"] + df_seq[\"rot_y\"]) / (df_seq[\"rot_z\"] + df_seq[\"rot_w\"] + 1e-6)\n        df_seq[\"rot_xz_over_yw\"] = (df_seq[\"rot_x\"] + df_seq[\"rot_z\"]) / (df_seq[\"rot_y\"] + df_seq[\"rot_w\"] + 1e-6)\n        df_seq[\"rot_xw_over_yz\"] = (df_seq[\"rot_x\"] + df_seq[\"rot_w\"]) / (df_seq[\"rot_y\"] + df_seq[\"rot_z\"] + 1e-6)\n\n        # Angular jerk (difference over sequence_id)\n        df_seq[\"angular_jerk_x\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_x\"].diff()\n        df_seq[\"angular_jerk_y\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_y\"].diff()\n        df_seq[\"angular_jerk_z\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_z\"].diff()\n        \n        # Rotation magnitudes\n        df_seq[\"rot_xyz_magnitude\"] = np.sqrt(df_seq[\"rot_x\"]**2 + df_seq[\"rot_y\"]**2 + df_seq[\"rot_z\"]**2)\n        df_seq[\"rot_xyw_magnitude\"] = np.sqrt(df_seq[\"rot_x\"]**2 + df_seq[\"rot_y\"]**2 + df_seq[\"rot_w\"]**2)\n        df_seq[\"rot_xzw_magnitude\"] = np.sqrt(df_seq[\"rot_x\"]**2 + df_seq[\"rot_z\"]**2 + df_seq[\"rot_w\"]**2)\n        df_seq[\"rot_yzw_magnitude\"] = np.sqrt(df_seq[\"rot_y\"]**2 + df_seq[\"rot_z\"]**2 + df_seq[\"rot_w\"]**2)\n        df_seq[\"rot_full_magnitude\"] = np.sqrt(df_seq[\"rot_x\"]**2 + df_seq[\"rot_y\"]**2 + df_seq[\"rot_z\"]**2 + df_seq[\"rot_w\"]**2)\n        \n        # Rolling means over sequence_id\n        df_seq[\"acc_mag_smooth_mean\"] = df_seq.groupby(\"sequence_id\")[\"acc_mag\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean())\n        df_seq[\"linear_acc_mean\"] = df_seq.groupby(\"sequence_id\")[\"linear_acc_mag\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean())\n        df_seq[\"rot_full_magnitude_mean\"] = df_seq.groupby(\"sequence_id\")[\"rot_full_magnitude\"].transform(lambda x: x.rolling(window=5, min_periods=1).mean()) \n\n        # df_seq[\"angular_jerk_x\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_x\"].diff()\n        # df_seq[\"angular_jerk_y\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_y\"].diff()\n        # df_seq[\"angular_jerk_z\"] = df_seq.groupby(\"sequence_id\")[\"angular_vel_z\"].diff()\n\n        df_seq[\"rot_xy_over_zw\"] = ((df_seq[\"rot_x\"] + df_seq[\"rot_y\"]) / (df_seq[\"rot_z\"] + df_seq[\"rot_w\"]+ 1e-6)).clip(-47.0799630, 48.1292149256)\n        \n        # rot_xz_over_yw\n        df_seq[\"rot_xz_over_yw\"] = ((df_seq[\"rot_x\"] + df_seq[\"rot_z\"]) / (df_seq[\"rot_y\"] + df_seq[\"rot_w\"]+ 1e-6)).clip(-47.0799630, 48.1292149256)\n        \n        # rot_xw_over_yz\n        df_seq[\"rot_xw_over_yz\"] = ((df_seq[\"rot_x\"] + df_seq[\"rot_w\"]) / (df_seq[\"rot_y\"] + df_seq[\"rot_z\"]+ 1e-6)).clip(-47.0799630, 48.1292149256) \n\n        df_seq[\"rot_w_vel\"] = df_seq.groupby(\"sequence_id\")[\"rot_w\"].diff()\n        df_seq[\"rot_x_vel\"] = df_seq.groupby(\"sequence_id\")[\"rot_x\"].diff()\n        df_seq[\"rot_y_vel\"] = df_seq.groupby(\"sequence_id\")[\"rot_y\"].diff()\n        df_seq[\"rot_z_vel\"] = df_seq.groupby(\"sequence_id\")[\"rot_z\"].diff()\n\n        def mean_abs_chain(diffs):\n            return sum(d.abs() for d in diffs) / len(diffs)\n        \n        df_seq['thm_right_chain'] = mean_abs_chain([\n            df_seq['thm_3'] - df_seq['thm_2'],\n            df_seq['thm_3'] - df_seq['thm_1'],\n            df_seq['thm_3'] - df_seq['thm_4'],\n        ])\n        \n        df_seq['thm_left_chain'] = mean_abs_chain([\n            df_seq['thm_5'] - df_seq['thm_2'],\n            df_seq['thm_5'] - df_seq['thm_1'],\n            df_seq['thm_5'] - df_seq['thm_4'],\n        ])\n        \n        df_seq['thm_center_chain'] = mean_abs_chain([\n            df_seq['thm_1'] - df_seq['thm_2'],\n            df_seq['thm_1'] - df_seq['thm_3'],\n            df_seq['thm_1'] - df_seq['thm_4'],\n            df_seq['thm_1'] - df_seq['thm_5'],\n        ])\n        \n        df_seq['thm_height_chain'] = mean_abs_chain([\n            df_seq['thm_2'] - df_seq['thm_1'],\n            df_seq['thm_1'] - df_seq['thm_4'],\n        ])\n        \n        df_seq['thm_weight_chain'] = mean_abs_chain([\n            df_seq['thm_4'] - df_seq['thm_1'],\n            df_seq['thm_3'] - df_seq['thm_2'],\n        ])\n\n        if self.tof_mode != 0:\n            new_columns = {} \n            for i in range(1, 6):\n                pixel_cols = [f\"tof_{i}_v{p}\" for p in range(64)]\n                tof_data = df_seq[pixel_cols].replace(-1, np.nan)\n                new_columns.update({\n                    f'tof_{i}_mean': tof_data.mean(axis=1),\n                    f'tof_{i}_std': tof_data.std(axis=1),\n                    f'tof_{i}_min': tof_data.min(axis=1),\n                    f'tof_{i}_max': tof_data.max(axis=1)\n                })\n                if self.tof_mode > 1:\n                    region_size = 64 // self.tof_mode\n                    for r in range(self.tof_mode):\n                        region_data = tof_data.iloc[:, r*region_size : (r+1)*region_size]\n                        new_columns.update({\n                            f'tof{self.tof_mode}_{i}_region_{r}_mean': region_data.mean(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_std': region_data.std(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_min': region_data.min(axis=1),\n                            f'tof{self.tof_mode}_{i}_region_{r}_max': region_data.max(axis=1)\n                        })\n                if self.tof_mode == -1:\n                    for mode in [2, 4, 8, 16, 32]:\n                        region_size = 64 // mode\n                        for r in range(mode):\n                            region_data = tof_data.iloc[:, r*region_size : (r+1)*region_size]\n                            new_columns.update({\n                                f'tof{mode}_{i}_region_{r}_mean': region_data.mean(axis=1),\n                                f'tof{mode}_{i}_region_{r}_std': region_data.std(axis=1),\n                                f'tof{mode}_{i}_region_{r}_min': region_data.min(axis=1),\n                                f'tof{mode}_{i}_region_{r}_max': region_data.max(axis=1)\n                            })\n            df_seq = pd.concat([df_seq, pd.DataFrame(new_columns)], axis=1)\n        \n        imu_unscaled = df_seq[self.imu_cols]\n        if self.config[\"fbfill\"][\"imu\"]:\n            imu_unscaled = imu_unscaled.ffill().bfill()\n        imu_unscaled = imu_unscaled.fillna(self.imu_nan_value).values.astype('float32')\n\n        thm_unscaled = df_seq[self.thm_cols]\n        if self.config[\"fbfill\"][\"thm\"]:\n            thm_unscaled = thm_unscaled.ffill().bfill()\n        thm_unscaled = thm_unscaled.fillna(self.thm_nan_value).values.astype('float32')\n\n        tof_unscaled = df_seq[self.tof_cols]\n        if self.config[\"fbfill\"][\"tof\"]:\n            tof_unscaled = tof_unscaled.ffill().bfill()\n        tof_unscaled = tof_unscaled.fillna(self.tof_nan_value).values.astype('float32')\n        \n        if self.config.get(\"one_scale\", True):\n            x_unscaled = np.concatenate([imu_unscaled, thm_unscaled, tof_unscaled], axis=1)\n            x_scaled = self.x_scaler.transform(x_unscaled)\n            imu_scaled = x_scaled[..., :self.imu_dim]\n            thm_scaled = x_scaled[..., self.imu_dim:self.imu_dim+self.thm_dim]\n            tof_scaled = x_scaled[..., self.imu_dim+self.thm_dim:self.imu_dim+self.thm_dim+self.tof_dim]\n        else:\n            imu_scaled = self.imu_scaler.transform(imu_unscaled)\n            thm_scaled = self.thm_scaler.transform(thm_unscaled)\n            tof_scaled = self.tof_scaler.transform(tof_unscaled)\n\n        combined = np.concatenate([imu_scaled, thm_scaled, tof_scaled], axis=1)\n        padded = np.zeros((self.pad_len, combined.shape[1]), dtype='float32')\n        seq_len = min(combined.shape[0], self.pad_len)\n        padded[:seq_len] = combined[:seq_len]\n        imu = padded[..., :self.imu_dim]\n        thm = padded[..., self.imu_dim:self.imu_dim+self.thm_dim]\n        tof = padded[..., self.imu_dim+self.thm_dim:self.imu_dim+self.thm_dim+self.tof_dim]\n\n        ret = [torch.from_numpy(imu).float().unsqueeze(0), torch.from_numpy(thm).float().unsqueeze(0), torch.from_numpy(tof).float().unsqueeze(0)]\n        if self.config.get(\"use_dg\", False):\n            dg = df_dg[self.dg_cols].values.astype('float32')\n            ret.append(torch.from_numpy(dg).float())\n        return ret\n\n    def split5(self, imu, thm, tof):\n        imus = [imu[:, self.global_imu_indices[k]] for k in self.global_imu_indices]\n        thms = [thm[:, self.global_thm_indices[k]] for k in range(1, 6)]\n        tofs = [tof[:, self.global_tof_indices[k]] for k in range(1, 6)]\n        return imus, thms, tofs\n\n    def slide(self, imu, thm, tof, ratio=1.0):\n        def slide_tensor(tensor, nan_value, ratio):\n            b, l, d = tensor.shape\n            length = int(l * ratio)\n            if length > l:\n                pad = torch.full((b, length-l, d), nan_value, device=tensor.device)\n                tensor = torch.cat([tensor, pad], dim=1)\n            elif length < l:\n                tensor = tensor[:, :length, :] \n            return tensor\n        return slide_tensor(imu, self.imu_scaled_nan, ratio), slide_tensor(thm, self.thm_scaled_nan, ratio), slide_tensor(tof, self.tof_scaled_nan, ratio)\n\n    def __getitem__(self, idx):\n        imus, thms, tofs = self.split5(self.imu[idx], self.thm[idx], self.tof[idx])\n        ret = [imus, thms, tofs, self.class_[idx], self.binary_class_[idx]]\n        if self.config.get(\"return_extra\", False):\n            fold_feat_info = [self.fold_feats[col][idx] for col in self.fold_cols]\n            ret.append((idx, fold_feat_info))\n        if self.config.get(\"use_dg\", False):\n            ret.append(self.dg[idx])\n        if self.config.get(\"return_flip_imu\", False):\n            ret.append(self.flip_imu[idx])\n        return ret\n\n    def __len__(self):\n        return len(self.class_)\n\nclass CMIFoldDataset:\n    def __init__(self, data_path, config, full_dataset_function, n_folds=5, random_seed=0):\n        self.full_dataset = full_dataset_function(data_path=data_path, config=config)\n        self.imu_dim = self.full_dataset.imu_dim\n        self.thm_dim = self.full_dataset.thm_dim\n        self.tof_dim = self.full_dataset.tof_dim\n        self.le = self.full_dataset.le\n        self.class_names = self.full_dataset.le.classes_\n        self.class_weight = self.full_dataset.class_weight\n        self.n_folds = n_folds\n        self.sgkf = StratifiedGroupKFold(n_splits=n_folds, shuffle=True, random_state=random_seed)\n        self.fold_y = np.array(self.full_dataset.fold_feats[config.get(\"fold_y\", \"sequence_type\")])\n        self.fold_groups = np.array(self.full_dataset.fold_feats[config.get(\"fold_groups\", \"subject\")])\n        self.folds = list(self.sgkf.split(X=np.arange(len(self.full_dataset)), y=self.fold_y, groups=self.fold_groups))\n        self.exclude_subjects = set(config.get(\"exclude_subjects\", []))\n    \n    def get_fold_datasets(self, fold_idx):\n        if self.folds is None or fold_idx >= self.n_folds: return None, None\n        fold_train_idx, fold_valid_idx = self.folds[fold_idx]\n        subjects = np.array(self.full_dataset.fold_feats[\"subject\"])\n        train_subjects, valid_subjects = subjects[fold_train_idx], subjects[fold_valid_idx]\n        train_mask, valid_mask = ~np.isin(train_subjects, list(self.exclude_subjects)), ~np.isin(valid_subjects, list(self.exclude_subjects))\n        return Subset(self.full_dataset, np.array(fold_train_idx)[train_mask].tolist()), Subset(self.full_dataset, np.array(fold_valid_idx)[valid_mask].tolist())\n\n    def print_fold_stats(self):\n        def get_label_counts(subset):\n            counts = {name: 0 for name in self.class_names}\n            if subset is None: return counts\n            for idx in subset.indices:\n                label_idx = self.full_dataset.dataset_indices[idx]\n                counts[self.class_names[label_idx]] += 1\n            return counts\n        \n        print(\"\\n交叉验证折叠统计:\")\n        for fold_idx in range(self.n_folds):\n            train_fold, valid_fold = self.get_fold_datasets(fold_idx)\n            train_counts = get_label_counts(train_fold)\n            valid_counts = get_label_counts(valid_fold)\n            print(f\"\\nFold {fold_idx + 1}:\")\n            print(f\"{'类别':<50} {'训练集':<10} {'验证集':<10}\")\n            for name in self.class_names:\n                print(f\"{name:<50} {train_counts[name]:<10} {valid_counts[name]:<10}\")\n\n        for fold_idx, (train_idx, val_idx) in enumerate(self.folds):\n            train_subjects = set(self.fold_groups[train_idx])\n            val_subjects = set(self.fold_groups[val_idx])\n            print(f\"\\nFold {fold_idx + 1}:\")\n            print(\"训练集受试者:\", train_subjects)\n            print(\"验证集受试者:\", val_subjects)\n\n        self.print_filtered_stats()\n\n    def print_filtered_stats(self):\n        original_counts = defaultdict(int)\n        filtered_counts = defaultdict(int)\n        \n        for fold_idx in range(self.n_folds):\n            train_idx, val_idx = self.folds[fold_idx]\n            for idx in train_idx:\n                original_counts['train'] += 1\n            for idx in val_idx:\n                original_counts['valid'] += 1\n            train_set, val_set = self.get_fold_datasets(fold_idx)\n            filtered_counts['train'] += len(train_set)\n            filtered_counts['valid'] += len(val_set)\n        \n        print(f\"\\n排除subject {self.exclude_subjects} 后的数据量变化:\")\n        print(f\"原始训练集样本: {original_counts['train']}\")\n        print(f\"过滤后训练集样本: {filtered_counts['train']}\")\n        print(f\"原始验证集样本: {original_counts['valid']}\") \n        print(f\"过滤后验证集样本: {filtered_counts['valid']}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:47:37.555384Z","iopub.execute_input":"2025-09-02T15:47:37.555598Z","iopub.status.idle":"2025-09-02T15:47:37.670354Z","shell.execute_reply.started":"2025-09-02T15:47:37.555580Z","shell.execute_reply":"2025-09-02T15:47:37.669746Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CUDA0 = \"cuda\"\nseed = 0\nbatch_size = 64\nnum_workers = 4\nn_folds = 5\n\nroot_dir = Path(\"/kaggle/input/cmi-detect-behavior-with-sensor-data\")\nuniverse_csv_path = Path(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\n\nimu_only = False\n\ndeterministic = kagglehub.package_import('wasupandceacar/deterministic').deterministic\ndeterministic.init_all(seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:47:37.671960Z","iopub.execute_input":"2025-09-02T15:47:37.672185Z","iopub.status.idle":"2025-09-02T15:47:38.026348Z","shell.execute_reply.started":"2025-09-02T15:47:37.672168Z","shell.execute_reply":"2025-09-02T15:47:38.025838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def init_dataset():\n    dataset_config = {\n        \"percent\": 99,\n        \"scaler_config\": StandardScaler(),\n        \"nan_ratio\": {\n            \"imu\": 0,\n            \"thm\": 0,\n            \"tof\": 0,\n        },\n        \"fbfill\": {\n            \"imu\": True,\n            \"thm\": True,\n            \"tof\": True,\n        },\n        \"one_scale\": False,\n        \"tof_raw\": True,\n        \"tof_mode\": 16,\n        \"save_precompute\": False,\n        \"fold_y\": \"gesture\",\n        \"fold_groups\": \"subject\",\n    }\n\n    dataset = CMIFoldDataset(universe_csv_path, dataset_config, full_dataset_function=CMIFeDataset, n_folds=n_folds, random_seed=seed)\n    dataset.print_fold_stats()\n    return dataset\n\ndef get_fold_dataset(dataset, fold):\n    _, valid_dataset = dataset.get_fold_datasets(fold)\n    valid_loader = DataLoader(valid_dataset, batch_size=batch_size, num_workers=num_workers, shuffle=False)\n    return valid_loader\n\ndataset = init_dataset()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:47:38.027041Z","iopub.execute_input":"2025-09-02T15:47:38.027301Z","iopub.status.idle":"2025-09-02T15:52:39.543329Z","shell.execute_reply.started":"2025-09-02T15:47:38.027278Z","shell.execute_reply":"2025-09-02T15:52:39.542465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        out = out + identity\n        return self.relu(out)\n\nconfig = DebertaV2Config(\n    hidden_size=256,\n    num_hidden_layers=4,\n    num_attention_heads=8,\n    intermediate_size=1024,\n    max_position_embeddings=512,\n    relative_attention=True,\n    position_biased_input=False,\n    position_buckets=256,\n    norm_rel_ebd=\"layer_norm\",\n    share_att_key=True,\n    pos_att_type=\"p2c|c2p\",\n    layer_norm_eps=1e-7,\n)\n\n     \nclass CMIModel_deberta_dp_aux(nn.Module): \n    def __init__(self,**kwargs):\n        super().__init__()\n        self.imu_branch_linear = nn.Sequential(\n            self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n    \n        self.thm_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"thm_dim\"], kwargs[\"thm1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"thm1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"thm1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm2_dropout\"])\n        )\n        \n        self.tof_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"tof_dim\"], kwargs[\"tof1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"tof1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"tof1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof2_dropout\"])\n        )\n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))\n        # self.bert = BertModel(BertConfig(\n        #     hidden_size=kwargs[\"feat_dim\"],\n        #     num_hidden_layers=kwargs[\"bert_layers\"],\n        #     num_attention_heads=kwargs[\"bert_heads\"],\n        #     intermediate_size=kwargs[\"feat_dim\"]*4\n        # ))\n\n        # self.deberta = DebertaV2Model(DebertaV2Config(\n        #             hidden_size=model_args[\"feat_dim\"],\n        #             num_hidden_layers=model_args[\"bert_layers\"],\n        #             num_attention_heads=model_args[\"bert_heads\"],\n        #             intermediate_size=model_args[\"feat_dim\"]*4,\n        #             max_position_embeddings=512\n        #         ))\n\n        # self.roberta = RobertaModel(RobertaConfig(\n        #                 hidden_size=kwargs[\"feat_dim\"],                 # e.g., 768 or 1024\n        #                 num_hidden_layers=kwargs[\"bert_layers\"],        # e.g., 12 (base) or 24 (large)\n        #                 num_attention_heads=kwargs[\"bert_heads\"],       # e.g., 12 (base) or 16 (large)\n        #                 intermediate_size=kwargs[\"feat_dim\"] * 4,       # feed-forward dimension\n        #                 max_position_embeddings=514,                        # default for RoBERTa\n        #                 vocab_size=50265,                                   # RoBERTa tokenizer vocab size\n        #                 type_vocab_size=1,                                  # RoBERTa doesn’t use token_type_ids\n        #                 pad_token_id=1,                                     # RoBERTa’s padding ID\n        #                 layer_norm_eps=1e-5,\n        #                 hidden_dropout_prob=0.1,\n        #                 attention_probs_dropout_prob=0.1\n        #             ))\n\n        # self.bert = DebertaV2Model.from_pretrained(\n        #     \"microsoft/deberta-v3-large\"\n        # )     \n\n        self.deberta = DebertaV2Model(config)\n\n        self.aux_classifier = nn.Linear(kwargs[\"feat_dim\"], 1)\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n        \n    \n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=wd),\n            nn.MaxPool1d(pool_size),\n            nn.Dropout(drop)\n        )\n    \n    def forward(self, imu, thm, tof):\n        # imu = torch.cat(imu, dim=-1)\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n        thm = torch.cat(thm, dim=-1)\n        tof = torch.cat((tof), dim=-1)\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n        # print(\"imu_feat, thm_feat, tof_feat.shape 111\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=1).shape)\n        # print(\"imu_feat.shape\",imu_feat1.shape)\n        thm_feat = self.thm_branch(thm.permute(0, 2, 1))\n        tof_feat = self.tof_branch(tof.permute(0, 2, 1))\n        # print(imu_feat.shape,thm_feat.shape,thm_feat.shape)\n        # print(\"imu_feat, thm_feat, tof_feat.shape\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).shape)\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).permute(0, 2, 1)\n        # print('bert_input -->',bert_input.shape)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        # print(\"cls_token\",cls_token.shape)\n        # print(\"cls_token concat\",torch.cat([cls_token, bert_input], dim=1).shape)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.deberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        pred_cls = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        return self.classifier(pred_cls),self.aux_classifier(cls_token).squeeze(-1)\n\n# model_args = {\"feat_dim\": 256,\n#               \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n#               \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n#               \"imu1_layers\": 0, \"imu2_layers\": 0,\n#               \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n#               \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n#               \"bert_layers\": 4, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n#               \"cls1_channels\": 937, \"cls2_channels\": 303, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n#                  \"imu_dim\": dataset.full_dataset.imu_dim, \n#                 \"thm_dim\": dataset.full_dataset.thm_dim,\n#                 \"tof_dim\": dataset.full_dataset.tof_dim,\n#                 \"n_classes\": dataset.full_dataset.class_num}        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.544400Z","iopub.execute_input":"2025-09-02T15:52:39.544695Z","iopub.status.idle":"2025-09-02T15:52:39.566260Z","shell.execute_reply.started":"2025-09-02T15:52:39.544666Z","shell.execute_reply":"2025-09-02T15:52:39.565473Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CMIModel_deberta_dp_aux CMIModel_roberta_dp_aux","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.567088Z","iopub.execute_input":"2025-09-02T15:52:39.567362Z","iopub.status.idle":"2025-09-02T15:52:39.583708Z","shell.execute_reply.started":"2025-09-02T15:52:39.567336Z","shell.execute_reply":"2025-09-02T15:52:39.583026Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        out = out + identity\n        return self.relu(out)\n\nconfig = DebertaV2Config(\n    hidden_size=256,\n    num_hidden_layers=4,\n    num_attention_heads=8,\n    intermediate_size=1024,\n    max_position_embeddings=512,\n    relative_attention=True,\n    position_biased_input=False,\n    position_buckets=256,\n    norm_rel_ebd=\"layer_norm\",\n    share_att_key=True,\n    pos_att_type=\"p2c|c2p\",\n    layer_norm_eps=1e-7,\n)\n\n     \n\nclass CMIModel_roberta_dp_aux(nn.Module):\n    def __init__(self,**kwargs):\n        super().__init__()\n        self.imu_branch_linear = nn.Sequential(\n            self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n    \n        self.thm_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"thm_dim\"], kwargs[\"thm1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"thm1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"thm1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm2_dropout\"])\n        )\n        \n        self.tof_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"tof_dim\"], kwargs[\"tof1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"tof1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"tof1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof2_dropout\"])\n        )\n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))\n        # self.bert = BertModel(BertConfig(\n        #     hidden_size=kwargs[\"feat_dim\"],\n        #     num_hidden_layers=kwargs[\"bert_layers\"],\n        #     num_attention_heads=kwargs[\"bert_heads\"],\n        #     intermediate_size=kwargs[\"feat_dim\"]*4\n        # ))\n\n        # self.deberta = DebertaV2Model(DebertaV2Config(\n        #             hidden_size=model_args[\"feat_dim\"],\n        #             num_hidden_layers=model_args[\"bert_layers\"],\n        #             num_attention_heads=model_args[\"bert_heads\"],\n        #             intermediate_size=model_args[\"feat_dim\"]*4,\n        #             max_position_embeddings=512\n        #         ))\n\n        self.roberta = RobertaModel(RobertaConfig(\n                        hidden_size=kwargs[\"feat_dim\"],                 # e.g., 768 or 1024\n                        num_hidden_layers=kwargs[\"bert_layers\"],        # e.g., 12 (base) or 24 (large)\n                        num_attention_heads=kwargs[\"bert_heads\"],       # e.g., 12 (base) or 16 (large)\n                        intermediate_size=kwargs[\"feat_dim\"] * 4,       # feed-forward dimension\n                        max_position_embeddings=514,                        # default for RoBERTa\n                        vocab_size=50265,                                   # RoBERTa tokenizer vocab size\n                        type_vocab_size=1,                                  # RoBERTa doesn’t use token_type_ids\n                        pad_token_id=1,                                     # RoBERTa’s padding ID\n                        layer_norm_eps=1e-5,\n                        hidden_dropout_prob=0.1,\n                        attention_probs_dropout_prob=0.1\n                    ))\n\n        # self.bert = DebertaV2Model.from_pretrained(\n        #     \"microsoft/deberta-v3-large\"\n        # )     \n\n        # self.deberta = DebertaV2Model(config)\n\n        self.aux_classifier = nn.Linear(kwargs[\"feat_dim\"], 1)\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n        \n    \n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=wd),\n            nn.MaxPool1d(pool_size),\n            nn.Dropout(drop)\n        )\n    \n    def forward(self, imu, thm, tof):\n        # imu = torch.cat(imu, dim=-1)\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n        thm = torch.cat(thm, dim=-1)\n        tof = torch.cat((tof), dim=-1)\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n        # print(\"imu_feat, thm_feat, tof_feat.shape 111\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=1).shape)\n        # print(\"imu_feat.shape\",imu_feat1.shape)\n        thm_feat = self.thm_branch(thm.permute(0, 2, 1))\n        tof_feat = self.tof_branch(tof.permute(0, 2, 1))\n        # print(imu_feat.shape,thm_feat.shape,thm_feat.shape)\n        # print(\"imu_feat, thm_feat, tof_feat.shape\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).shape)\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).permute(0, 2, 1)\n        # print('bert_input -->',bert_input.shape)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        # print(\"cls_token\",cls_token.shape)\n        # print(\"cls_token concat\",torch.cat([cls_token, bert_input], dim=1).shape)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.roberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        pred_cls = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        return self.classifier(pred_cls),self.aux_classifier(cls_token).squeeze(-1)\n\nmodel_args = {\"feat_dim\": 256,\n              \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n              \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n              \"imu1_layers\": 0, \"imu2_layers\": 0,\n              \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n              \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n              \"bert_layers\": 4, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n              \"cls1_channels\": 937, \"cls2_channels\": 303, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                 \"imu_dim\": dataset.full_dataset.imu_dim, \n                \"thm_dim\": dataset.full_dataset.thm_dim,\n                \"tof_dim\": dataset.full_dataset.tof_dim,\n                \"n_classes\": dataset.full_dataset.class_num}        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.584433Z","iopub.execute_input":"2025-09-02T15:52:39.584628Z","iopub.status.idle":"2025-09-02T15:52:39.608215Z","shell.execute_reply.started":"2025-09-02T15:52:39.584604Z","shell.execute_reply":"2025-09-02T15:52:39.607622Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        #out = out + identity\n        #return self.relu(out)\n        out = out + identity\n        out = self.relu(out)\n        out = F.layer_norm(out, out.shape[1:])\n        return out\n\nclass AttentionLayer(nn.Module):\n    def __init__(self, feature_dim):\n        super().__init__()\n        self.score_fn = nn.Linear(feature_dim, 1, bias=True)\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, x):\n        # x: (B, L, F)\n        score = torch.tanh(self.score_fn(x))     # (B, L, 1)\n        weights = self.softmax(score.squeeze(-1))# (B, L)\n        weights = weights.unsqueeze(-1)          # (B, L, 1)\n        context = x * weights                    # (B, L, F)\n        return context.sum(dim=1)                # (B, F)\n\nclass GaussianNoise(nn.Module):\n    \"\"\"Add Gaussian noise to input tensor\"\"\"\n    def __init__(self, stddev):\n        super().__init__()\n        self.stddev = stddev\n    \n    def forward(self, x):\n        if self.training:\n            noise = torch.randn_like(x) * self.stddev\n            return x + noise\n        return x\n\n\nclass CMIBackbone(nn.Module):\n    def __init__(self, **kwargs):\n        super().__init__()\n        self.imu_acc_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_rot_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_sum_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_ms_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_md_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )      \n        self.imu_other_branch = nn.Sequential(\n            self.residual_feature_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_jerk_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rotmag_branch = nn.Sequential(\n            self.residual_feature_block(5, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rollmean_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )            \n        self.imu_rotkerk_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n        self.imu_rotxyz_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n        # kwargs[\"thm_dim\"]  kwargs[\"tof_dim\"]\n        self.thm_branch1, self.tof_branch1 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch2, self.tof_branch2 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch3, self.tof_branch3 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch4, self.tof_branch4 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch5, self.tof_branch5 = self.init_thm_tof_branch(**kwargs)\n\n        self.imu_proj1 = ResNetSEBlock(in_channels=3*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.imu_proj2 = ResNetSEBlock(in_channels=4*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.thm_proj = ResNetSEBlock(in_channels=5*kwargs[\"thm2_channels\"], out_channels=kwargs[\"thm2_channels\"])\n        self.tof_proj = ResNetSEBlock(in_channels=5*kwargs[\"tof2_channels\"], out_channels=kwargs[\"tof2_channels\"])\n\n        self.lstm = nn.LSTM(\n            input_size=2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'],\n            hidden_size=kwargs['lstm_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        self.gru = nn.GRU(\n            input_size=2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'],\n            hidden_size=kwargs['gru_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        \n        self.noise = GaussianNoise(kwargs['gaussian_noise_rate'])\n        self.dense = nn.Sequential(\n            nn.Linear(2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'], kwargs['dense_channels']),\n            nn.ELU()\n        )\n        \n        self.attn = AttentionLayer(feature_dim=(kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'])  # lstm + gru + dense\n\n    def feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def residual_feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=1e-4),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def init_thm_tof_branch(self, **kwargs):\n        thm_branch = nn.Sequential(\n            self.feature_block(kwargs[\"thm_dim\"]//5, kwargs[\"thm1_channels\"], kwargs[\"thm1_layers\"], drop=kwargs[\"thm1_dropout\"]),\n            self.feature_block(kwargs[\"thm1_channels\"], kwargs[\"thm2_channels\"], kwargs[\"thm2_layers\"], drop=kwargs[\"thm2_dropout\"]),\n        )\n        tof_branch = nn.Sequential(\n            self.feature_block(kwargs[\"tof_dim\"]//5, kwargs[\"tof1_channels\"], kwargs[\"tof1_layers\"], drop=kwargs[\"tof1_dropout\"]),\n            self.feature_block(kwargs[\"tof1_channels\"], kwargs[\"tof2_channels\"], kwargs[\"tof2_layers\"], drop=kwargs[\"tof2_dropout\"]),\n        )\n        return thm_branch, tof_branch\n    \n    def forward(self, imus, thms, tofs):\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imus\n        imu_acc_feat = self.imu_acc_branch(imu_acc.permute(0, 2, 1))\n        imu_rot_feat = self.imu_rot_branch(imu_rot.permute(0, 2, 1))\n        imu_sum_feat = self.imu_sum_branch(imu_sum.permute(0, 2, 1))\n        imu_ms_feat = self.imu_ms_branch(imu_ms.permute(0, 2, 1))\n        imu_md_feat = self.imu_md_branch(imu_md.permute(0, 2, 1))\n        imu_others_feat = self.imu_other_branch(imu_others.permute(0, 2, 1))\n        imu_jerk_feat = self.imu_jerk_branch(imu_jerk.permute(0, 2, 1))\n        imu_rotmag_feat = self.imu_rotmag_branch(imu_rot_mag.permute(0, 2, 1))\n        imu_rollmean_feat = self.imu_rollmean_branch(imu_roll_mean.permute(0, 2, 1))\n\n        imu_rotkerk_feat = self.imu_rotkerk_branch(imu_rot_jerk.permute(0, 2, 1))\n        imu_rotxyz_feat = self.imu_rotxyz_branch(imu_rot_xyz.permute(0, 2, 1))\n\n        imu_feat1 = self.imu_proj1(torch.cat([imu_acc_feat, imu_rot_feat, imu_others_feat], dim=1)) #\n        imu_feat2 = self.imu_proj2(torch.cat([imu_md_feat, imu_jerk_feat,imu_ms_feat,imu_sum_feat], dim=1)) # imu_rotmag_feat\n\n        thm1, thm2, thm3, thm4, thm5 = thms\n        tof1, tof2, tof3, tof4, tof5 = tofs\n        \n        thm1_feat = self.thm_branch1(thm1.permute(0, 2, 1))\n        thm2_feat = self.thm_branch2(thm2.permute(0, 2, 1))\n        thm3_feat = self.thm_branch3(thm3.permute(0, 2, 1))\n        thm4_feat = self.thm_branch4(thm4.permute(0, 2, 1))\n        thm5_feat = self.thm_branch5(thm5.permute(0, 2, 1))\n        thm_feat = self.thm_proj(torch.cat([thm1_feat, thm2_feat, thm3_feat, thm4_feat, thm5_feat], dim=1))\n        \n        tof1_feat = self.tof_branch1(tof1.permute(0, 2, 1))\n        tof2_feat = self.tof_branch2(tof2.permute(0, 2, 1))\n        tof3_feat = self.tof_branch3(tof3.permute(0, 2, 1))\n        tof4_feat = self.tof_branch4(tof4.permute(0, 2, 1))\n        tof5_feat = self.tof_branch5(tof5.permute(0, 2, 1))\n        tof_feat = self.tof_proj(torch.cat([tof1_feat, tof2_feat, tof3_feat, tof4_feat, tof5_feat], dim=1))\n        \n        feat = torch.cat([imu_feat1,imu_feat2, thm_feat, tof_feat], dim=1).permute(0, 2, 1)\n        lstm_out, _ = self.lstm(feat)\n        gru_out, _ = self.gru(feat)\n        dense_out = self.dense(self.noise(feat))\n        \n        return self.attn(torch.cat([lstm_out, gru_out, dense_out], dim=-1))\n\nclass CMIModel_combined_model(nn.Module):\n    def __init__(self, target_classes_num, non_target_classes_num, **kwargs):\n        super().__init__()\n        self.backbone = CMIBackbone(**kwargs)\n        # self.target_classifier = nn.Sequential(\n        #     nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls_channels1\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout1\"]),\n        #     nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout2\"]),\n        #     nn.Linear(kwargs[\"cls_channels2\"], target_classes_num)\n        # )\n        # self.non_target_classifier = nn.Sequential(\n        #     nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls_channels1\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout1\"]),\n        #     nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout2\"]),\n        #     nn.Linear(kwargs[\"cls_channels2\"], non_target_classes_num)\n        # )\n\n        # self.aux_classifier = nn.Sequential(\n        #     nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls_channels1\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout1\"]),\n        #     nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n        #     nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n        #     nn.ReLU(),\n        #     nn.Dropout(kwargs[\"cls_dropout2\"]),\n        #     nn.Linear(kwargs[\"cls_channels2\"], 1)\n        # )\n\n        ######################################################################################################\n\n        \n        self.imu_branch_linear = nn.Sequential(\n        self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                   drop=kwargs[\"imu1_dropout\"]),\n        self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n    \n        self.thm_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"thm_dim\"], kwargs[\"thm1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"thm1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"thm1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"thm2_dropout\"])\n        )\n        \n        self.tof_branch = nn.Sequential(\n            nn.Conv1d(kwargs[\"tof_dim\"], kwargs[\"tof1_channels\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"tof1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof1_dropout\"]),\n            \n            nn.Conv1d(kwargs[\"tof1_channels\"], kwargs[\"feat_dim\"], kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(kwargs[\"feat_dim\"]),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(2, ceil_mode=True),\n            nn.Dropout(kwargs[\"tof2_dropout\"])\n        )\n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))\n\n        self.roberta = RobertaModel(RobertaConfig(\n                        hidden_size=kwargs[\"feat_dim\"],                 # e.g., 768 or 1024\n                        num_hidden_layers=kwargs[\"bert_layers\"],        # e.g., 12 (base) or 24 (large)\n                        num_attention_heads=kwargs[\"bert_heads\"],       # e.g., 12 (base) or 16 (large)\n                        intermediate_size=kwargs[\"feat_dim\"] * 4,       # feed-forward dimension\n                        max_position_embeddings=514,                        # default for RoBERTa\n                        vocab_size=50265,                                   # RoBERTa tokenizer vocab size\n                        type_vocab_size=1,                                  # RoBERTa doesn’t use token_type_ids\n                        pad_token_id=1,                                     # RoBERTa’s padding ID\n                        layer_norm_eps=1e-5,\n                        hidden_dropout_prob=0.1,\n                        attention_probs_dropout_prob=0.1\n                    ))\n\n        # self.aux_classifier = nn.Linear(kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, 1)\n\n        self.aux_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], 1)\n        )        \n   \n        self.classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n        *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n        ResNetSEBlock(in_channels, out_channels, wd=wd),\n        nn.MaxPool1d(pool_size),\n        nn.Dropout(drop))        \n\n\n\n    def forward(self, imu, thm, tof):\n        feat1 = self.backbone(imu, thm, tof)\n        # targets_y = self.target_classifier(feat)\n        # non_targets_y = self.non_target_classifier(feat)\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n        thm = torch.cat(thm, dim=-1)\n        tof = torch.cat((tof), dim=-1)\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n        # print(\"imu_feat, thm_feat, tof_feat.shape 111\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=1).shape)\n        # print(\"imu_feat.shape\",imu_feat1.shape)\n        thm_feat = self.thm_branch(thm.permute(0, 2, 1))\n        tof_feat = self.tof_branch(tof.permute(0, 2, 1))\n        # print(imu_feat.shape,thm_feat.shape,thm_feat.shape)\n        # print(\"imu_feat, thm_feat, tof_feat.shape\",torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).shape)\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3, thm_feat, tof_feat], dim=-1).permute(0, 2, 1)\n        # print('bert_input -->',bert_input.shape)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        # print(\"cls_token\",cls_token.shape)\n        # print(\"cls_token concat\",torch.cat([cls_token, bert_input], dim=1).shape)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.roberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        feat2 = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        # aux = self.aux_classifier(feat).squeeze(-1)\n        # targets_y = self.target_classifier(feat)\n        # non_targets_y = self.non_target_classifier(feat)\n        combined = torch.cat([feat1, feat2], dim=-1)\n        aux = self.aux_classifier(combined).squeeze(-1)\n        targets = self.classifier(combined)\n        # targets_y = self.target_classifier(combined)\n        # non_targets_y = self.non_target_classifier(combined)\n        return targets,aux","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.608953Z","iopub.execute_input":"2025-09-02T15:52:39.609118Z","iopub.status.idle":"2025-09-02T15:52:39.654829Z","shell.execute_reply.started":"2025-09-02T15:52:39.609104Z","shell.execute_reply":"2025-09-02T15:52:39.654114Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        #out = out + identity\n        #return self.relu(out)\n        out = out + identity\n        out = self.relu(out)\n        out = F.layer_norm(out, out.shape[1:])\n        return out\n\nclass AttentionLayer(nn.Module):\n    def __init__(self, feature_dim):\n        super().__init__()\n        self.score_fn = nn.Linear(feature_dim, 1, bias=True)\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, x):\n        # x: (B, L, F)\n        score = torch.tanh(self.score_fn(x))     # (B, L, 1)\n        weights = self.softmax(score.squeeze(-1))# (B, L)\n        weights = weights.unsqueeze(-1)          # (B, L, 1)\n        context = x * weights                    # (B, L, F)\n        return context.sum(dim=1)                # (B, F)\n\nclass GaussianNoise(nn.Module):\n    \"\"\"Add Gaussian noise to input tensor\"\"\"\n    def __init__(self, stddev):\n        super().__init__()\n        self.stddev = stddev\n    \n    def forward(self, x):\n        if self.training:\n            noise = torch.randn_like(x) * self.stddev\n            return x + noise\n        return x\n\n\nclass CMIBackbone(nn.Module):\n    def __init__(self, **kwargs):\n        super().__init__()\n        self.imu_acc_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_rot_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_sum_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_ms_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_md_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )      \n        self.imu_other_branch = nn.Sequential(\n            self.residual_feature_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_jerk_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rotmag_branch = nn.Sequential(\n            self.residual_feature_block(5, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rollmean_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )            \n        self.imu_rotkerk_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n        self.imu_rotxyz_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n\n        self.thm_branch1, self.tof_branch1 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch2, self.tof_branch2 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch3, self.tof_branch3 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch4, self.tof_branch4 = self.init_thm_tof_branch(**kwargs)\n        self.thm_branch5, self.tof_branch5 = self.init_thm_tof_branch(**kwargs)\n\n        self.imu_proj1 = ResNetSEBlock(in_channels=3*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.imu_proj2 = ResNetSEBlock(in_channels=4*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.thm_proj = ResNetSEBlock(in_channels=5*kwargs[\"thm2_channels\"], out_channels=kwargs[\"thm2_channels\"])\n        self.tof_proj = ResNetSEBlock(in_channels=5*kwargs[\"tof2_channels\"], out_channels=kwargs[\"tof2_channels\"])\n\n        self.lstm = nn.LSTM(\n            input_size=2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'],\n            hidden_size=kwargs['lstm_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        self.gru = nn.GRU(\n            input_size=2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'],\n            hidden_size=kwargs['gru_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        \n        self.noise = GaussianNoise(kwargs['gaussian_noise_rate'])\n        self.dense = nn.Sequential(\n            nn.Linear(2*kwargs['imu2_channels']+kwargs['thm2_channels']+kwargs['tof2_channels'], kwargs['dense_channels']),\n            nn.ELU()\n        )\n        \n        self.attn = AttentionLayer(feature_dim=(kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'])  # lstm + gru + dense\n\n    def feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def residual_feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=1e-4),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def init_thm_tof_branch(self,**kwargs):\n        thm_branch = nn.Sequential(\n            self.feature_block(kwargs[\"thm_dim\"]//5, kwargs[\"thm1_channels\"], kwargs[\"thm1_layers\"], drop=kwargs[\"thm1_dropout\"]),\n            self.feature_block(kwargs[\"thm1_channels\"], kwargs[\"thm2_channels\"], kwargs[\"thm2_layers\"], drop=kwargs[\"thm2_dropout\"]),\n        )\n        tof_branch = nn.Sequential(\n            self.feature_block(kwargs[\"tof_dim\"]//5, kwargs[\"tof1_channels\"], kwargs[\"tof1_layers\"], drop=kwargs[\"tof1_dropout\"]),\n            self.feature_block(kwargs[\"tof1_channels\"], kwargs[\"tof2_channels\"], kwargs[\"tof2_layers\"], drop=kwargs[\"tof2_dropout\"]),\n        )\n        return thm_branch, tof_branch\n    \n    def forward(self, imus, thms, tofs):\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imus\n        imu_acc_feat = self.imu_acc_branch(imu_acc.permute(0, 2, 1))\n        imu_rot_feat = self.imu_rot_branch(imu_rot.permute(0, 2, 1))\n        imu_sum_feat = self.imu_sum_branch(imu_sum.permute(0, 2, 1))\n        imu_ms_feat = self.imu_ms_branch(imu_ms.permute(0, 2, 1))\n        imu_md_feat = self.imu_md_branch(imu_md.permute(0, 2, 1))\n        imu_others_feat = self.imu_other_branch(imu_others.permute(0, 2, 1))\n        imu_jerk_feat = self.imu_jerk_branch(imu_jerk.permute(0, 2, 1))\n        imu_rotmag_feat = self.imu_rotmag_branch(imu_rot_mag.permute(0, 2, 1))\n        imu_rollmean_feat = self.imu_rollmean_branch(imu_roll_mean.permute(0, 2, 1))\n\n        imu_rotkerk_feat = self.imu_rotkerk_branch(imu_rot_jerk.permute(0, 2, 1))\n        imu_rotxyz_feat = self.imu_rotxyz_branch(imu_rot_xyz.permute(0, 2, 1))\n\n        imu_feat1 = self.imu_proj1(torch.cat([imu_acc_feat, imu_rot_feat, imu_others_feat], dim=1)) #\n        imu_feat2 = self.imu_proj2(torch.cat([imu_md_feat, imu_jerk_feat,imu_ms_feat,imu_sum_feat], dim=1)) # imu_rotmag_feat\n\n        thm1, thm2, thm3, thm4, thm5 = thms\n        tof1, tof2, tof3, tof4, tof5 = tofs\n        \n        thm1_feat = self.thm_branch1(thm1.permute(0, 2, 1))\n        thm2_feat = self.thm_branch2(thm2.permute(0, 2, 1))\n        thm3_feat = self.thm_branch3(thm3.permute(0, 2, 1))\n        thm4_feat = self.thm_branch4(thm4.permute(0, 2, 1))\n        thm5_feat = self.thm_branch5(thm5.permute(0, 2, 1))\n        thm_feat = self.thm_proj(torch.cat([thm1_feat, thm2_feat, thm3_feat, thm4_feat, thm5_feat], dim=1))\n        \n        tof1_feat = self.tof_branch1(tof1.permute(0, 2, 1))\n        tof2_feat = self.tof_branch2(tof2.permute(0, 2, 1))\n        tof3_feat = self.tof_branch3(tof3.permute(0, 2, 1))\n        tof4_feat = self.tof_branch4(tof4.permute(0, 2, 1))\n        tof5_feat = self.tof_branch5(tof5.permute(0, 2, 1))\n        tof_feat = self.tof_proj(torch.cat([tof1_feat, tof2_feat, tof3_feat, tof4_feat, tof5_feat], dim=1))\n        \n        feat = torch.cat([imu_feat1,imu_feat2, thm_feat, tof_feat], dim=1).permute(0, 2, 1)\n        lstm_out, _ = self.lstm(feat)\n        gru_out, _ = self.gru(feat)\n        dense_out = self.dense(self.noise(feat))\n        \n        return self.attn(torch.cat([lstm_out, gru_out, dense_out], dim=-1))\n\nclass CMIModel_cnn_model_normal(nn.Module):\n    def __init__(self, target_classes_num, non_target_classes_num, **kwargs):\n        super().__init__()\n        self.backbone = CMIBackbone(**kwargs)\n        self.target_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], target_classes_num)\n        )\n        self.non_target_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], non_target_classes_num)\n        )\n\n        self.aux_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], 1)\n        )\n    def forward(self, imu, thm, tof):\n        feat = self.backbone(imu, thm, tof)\n        targets_y = self.target_classifier(feat)\n        non_targets_y = self.non_target_classifier(feat)\n        aux = self.aux_classifier(feat).squeeze(-1)\n        return torch.cat([targets_y, non_targets_y], dim=1),aux\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.655922Z","iopub.execute_input":"2025-09-02T15:52:39.656167Z","iopub.status.idle":"2025-09-02T15:52:39.690930Z","shell.execute_reply.started":"2025-09-02T15:52:39.656141Z","shell.execute_reply":"2025-09-02T15:52:39.690247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"infer = True\ntraining = False\n\nimport copy\nimport math\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader\nfrom sklearn.metrics import f1_score\nfrom tqdm import tqdm\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import accuracy_score\n\nclass WarmupCosineScheduler(torch.optim.lr_scheduler._LRScheduler):\n    def __init__(self, optimizer, warmup_epochs, total_epochs, base_lr, final_lr=2e-5, last_epoch=-1):\n        self.warmup_epochs = warmup_epochs\n        self.total_epochs = total_epochs\n        self.base_lr = base_lr\n        self.final_lr = final_lr\n        super(WarmupCosineScheduler, self).__init__(optimizer, last_epoch)\n\n    def get_lr(self):\n        if self.last_epoch < self.warmup_epochs:\n            return [self.base_lr * (self.last_epoch + 1) / self.warmup_epochs for _ in self.optimizer.param_groups]\n        else:\n            decay_epoch = self.last_epoch - self.warmup_epochs\n            decay_total = self.total_epochs - self.warmup_epochs\n            cosine_decay = 0.5 * (1 + math.cos(math.pi * decay_epoch / decay_total))\n            return [self.final_lr + (self.base_lr - self.final_lr) * cosine_decay for _ in self.optimizer.param_groups]\n\n# === Metric ===\nclass CompetitionMetric:\n    def __init__(self):\n        self.target_gestures = [\n            'Above ear - pull hair', 'Cheek - pinch skin', 'Eyebrow - pull hair',\n            'Eyelash - pull hair', 'Forehead - pull hairline', 'Forehead - scratch',\n            'Neck - pinch skin', 'Neck - scratch'\n        ]\n        self.non_target_gestures = [\n            'Write name on leg', 'Wave hello', 'Glasses on/off', 'Text on phone',\n            'Write name in air', 'Feel around in tray and pull out an object',\n            'Scratch knee/leg skin', 'Pull air toward your face',\n            'Drink from bottle/cup', 'Pinch knee/leg skin'\n        ]\n\n    def calculate_hierarchical_f1(self, sol: pd.DataFrame, sub: pd.DataFrame) -> float:\n        y_true_bin = sol['gesture'].isin(self.target_gestures).values\n        y_pred_bin = sub['gesture'].isin(self.target_gestures).values\n        f1_binary = f1_score(y_true_bin, y_pred_bin, pos_label=True, zero_division=0, average='binary')\n        y_true_mc = sol['gesture'].apply(lambda x: x if x in self.target_gestures else 'non_target')\n        y_pred_mc = sub['gesture'].apply(lambda x: x if x in self.target_gestures else 'non_target')\n        f1_macro = f1_score(y_true_mc, y_pred_mc, average='macro', zero_division=0)\n        return 0.5 * f1_binary + 0.5 * f1_macro\n\ndef plot_lr_schedule(optimizer, scheduler, total_epochs):\n    lrs = []\n    for epoch in range(total_epochs):\n        scheduler.step()\n        lrs.append(optimizer.param_groups[0]['lr'])\n    plt.plot(range(total_epochs), lrs)\n    plt.xlabel(\"Epoch\")\n    plt.ylabel(\"Learning Rate\")\n    plt.title(\"Learning Rate Schedule with Warmup and Cosine Decay\")\n    plt.grid(True)\n    plt.show()\n\ndef check_tensor(tensor, name=\"tensor\"):\n    if torch.isnan(tensor).any():\n        print(f\"⚠️ NaN detected in {name}\")\n    if torch.isinf(tensor).any():\n        print(f\"⚠️ Inf detected in {name}\")\n\nclass ModelEMA:\n    def __init__(self, model, decay=0.9999):\n        self.ema_model = copy.deepcopy(model).eval()\n        self.decay = decay\n        self.ema_model.requires_grad_(False)\n\n    def update(self, model):\n        with torch.no_grad():\n            msd = model.state_dict()\n            for k, ema_v in self.ema_model.state_dict().items():\n                model_v = msd[k].detach()\n                if model_v.dtype.is_floating_point:\n                    ema_v.copy_(ema_v * self.decay + (1. - self.decay) * model_v)\n                else:\n                    ema_v.copy_(model_v)\n\n# === Training ===\ndef train_model(config, dataset, fold_idx, num_epochs):\n    patience = 40\n    model_lr = 5e-4\n    model_weight_decay = 3e-3\n    model_warmup_steps = 30\n    min_lr = 2e-5\n    min_lr_mode = False\n    bad_epochs = 0\n\n    train_set, val_set = dataset.get_fold_datasets(fold_idx)\n\n    train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers)\n    val_loader = DataLoader(val_set, batch_size=batch_size, shuffle=False, num_workers=num_workers)\n\n    model = CMIModel(\n        **config\n    ).to(CUDA0)\n    ema = ModelEMA(model, decay=0.999)\n\n    optimizer = optim.Adam(model.parameters(), lr=model_lr)\n    scheduler_dummy = WarmupCosineScheduler(optimizer, warmup_epochs=model_warmup_steps, total_epochs=240, base_lr=model_lr)\n    criterion = nn.CrossEntropyLoss()\n    metric = CompetitionMetric()\n\n    plot_lr_schedule(optimizer, scheduler_dummy, total_epochs=num_epochs)\n    scheduler = WarmupCosineScheduler(optimizer, warmup_epochs=model_warmup_steps, total_epochs=240, base_lr=model_lr)\n\n    #print(\"H-F1 values from here out are actually ACC!\")\n    ACC_NOT_F1 = False\n    best_hf1 = 0\n    for epoch in range(num_epochs):\n        for m in model.modules():\n            if isinstance(m, (nn.LSTM, nn.GRU)):\n                m.flatten_parameters()\n        for m in ema.ema_model.modules():\n            if isinstance(m, (nn.LSTM, nn.GRU)):\n                m.flatten_parameters()\n                \n        model.train()\n        train_loss = 0\n        train_preds, train_targets = [], []\n\n        for imus, thms, tofs, labels, _ in train_loader:\n            for idx, imu in enumerate(imus):\n                imus[idx] = imu.to(CUDA0)\n            for idx, thm in enumerate(thms):\n                thms[idx] = thm.to(CUDA0)\n            for idx, tof in enumerate(tofs):\n                tofs[idx] = tof.to(CUDA0)\n            labels = labels.to(CUDA0)\n            imus, thms, tofs = imu_only_augment(imus, thms, tofs, p=0.3)\n            imus, thms, tofs, labels = mixup_augment(imus, thms, tofs, labels)\n            \n            #check_tensor(imu, \"imu\")\n            #check_tensor(thm, \"thm\")\n            #check_tensor(tof, \"tof\")\n            #check_tensor(labels, \"labels\")\n        \n            labels_cls = labels.argmax(dim=1)\n\n            optimizer.zero_grad()\n            outputs = model(imus, thms, tofs)\n            loss = criterion(outputs, labels_cls)\n            loss.backward()\n            check_tensor(loss, \"loss\")\n            check_tensor(outputs, \"outputs\")\n\n            torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)\n            if torch.isnan(loss):\n                print(f\"⚠️ NaN detected in loss at epoch {epoch+1}\")\n                break  # Stop training if NaN is detected\n\n            optimizer.step()\n            ema.update(model)\n\n            train_loss += loss.item()\n            train_preds.extend(outputs.argmax(1).cpu().numpy())\n            train_targets.extend(labels_cls.cpu().numpy())\n\n        train_df = pd.DataFrame({'gesture': [dataset.class_names[p] for p in train_preds]})\n        train_target_df = pd.DataFrame({'gesture': [dataset.class_names[t] for t in train_targets]})\n        train_hf1 = metric.calculate_hierarchical_f1(train_target_df, train_df)\n        #train_hf1 = accuracy_score(train_targets, train_preds)\n\n        #model.eval()\n        ema.ema_model.eval()\n        val_preds, val_targets = [], []\n        with torch.no_grad():\n            for imus, thms, tofs, labels, _ in val_loader:\n                for idx, imu in enumerate(imus):\n                    imus[idx] = imu.to(CUDA0)\n                for idx, thm in enumerate(thms):\n                    thms[idx] = thm.to(CUDA0)\n                for idx, tof in enumerate(tofs):\n                    tofs[idx] = tof.to(CUDA0)\n                labels = labels.to(CUDA0)\n                labels_cls = labels.argmax(dim=1)\n\n                #outputs = model(imus, thms, tofs)\n                outputs = ema.ema_model(imus, thms, tofs)\n                val_preds.extend(outputs.argmax(1).cpu().numpy())\n                val_targets.extend(labels_cls.cpu().numpy())\n\n        val_df = pd.DataFrame({'gesture': [dataset.class_names[p] for p in val_preds]})\n        val_target_df = pd.DataFrame({'gesture': [dataset.class_names[t] for t in val_targets]})\n        val_hf1_full = metric.calculate_hierarchical_f1(val_target_df, val_df)\n\n        val_preds, val_targets = [], []\n        with torch.no_grad():\n            for imus, thms, tofs, labels, _ in val_loader:\n                for idx, imu in enumerate(imus):\n                    imus[idx] = imu.to(CUDA0)\n                for idx, thm in enumerate(thms):\n                    thms[idx] = thm.to(CUDA0)\n                for idx, tof in enumerate(tofs):\n                    tofs[idx] = tof.to(CUDA0)\n                imus, thms, tofs = imu_only_augment(imus, thms, tofs, p=1)\n                labels = labels.to(CUDA0)\n                labels_cls = labels.argmax(dim=1)\n\n                #outputs = model(imus, thms, tofs)\n                outputs = ema.ema_model(imus, thms, tofs)\n                val_preds.extend(outputs.argmax(1).cpu().numpy())\n                val_targets.extend(labels_cls.cpu().numpy())\n\n        val_df = pd.DataFrame({'gesture': [dataset.class_names[p] for p in val_preds]})\n        val_target_df = pd.DataFrame({'gesture': [dataset.class_names[t] for t in val_targets]})\n        val_hf1_imu = metric.calculate_hierarchical_f1(val_target_df, val_df)\n        val_hf1 = (val_hf1_full + val_hf1_imu) / 2\n\n        current_lr = optimizer.param_groups[0]['lr']\n        print(f\"Epoch {epoch+1}: Train H-F1: {train_hf1:.4f}, Val H-F1 full: {val_hf1_full:.4f}, Val H-F1 imu: {val_hf1_imu:.4f}, Val H-F1: {val_hf1:.4f}, LR: {current_lr:.8f}\")\n\n        if val_hf1 > best_hf1:\n            best_hf1 = val_hf1\n            bad_epochs = 0\n            #torch.save(model.state_dict(), f\"best_model_fold{fold_idx}.pt\")\n            torch.save(ema.ema_model.state_dict(), f\"best_model_fold{fold_idx}.pt\")\n        else:\n            bad_epochs += 1\n            #if bad_epochs >= patience:\n            #    print(f\"Early stopping triggered after {epoch+1} epochs.\")\n            #    break\n        '''\n        model_ = CMIModel(\n            **config\n        ).to(CUDA0)\n        model_.load_state_dict(torch.load(f\"best_model_fold{fold_idx}.pt\"))\n        model_.eval()\n        val_preds, val_targets = [], []\n        with torch.no_grad():\n            for imus, thms, tofs, labels, _ in val_loader:\n                for idx, imu in enumerate(imus):\n                    imus[idx] = imu.to(CUDA0)\n                for idx, thm in enumerate(thms):\n                    thms[idx] = thm.to(CUDA0)\n                for idx, tof in enumerate(tofs):\n                    tofs[idx] = tof.to(CUDA0)\n                labels = labels.to(CUDA0)\n                labels_cls = labels.argmax(dim=1)\n\n                #outputs = model(imus, thms, tofs)\n                outputs = model_(imus, thms, tofs)\n                val_preds.extend(outputs.argmax(1).cpu().numpy())\n                val_targets.extend(labels_cls.cpu().numpy())\n\n        val_df = pd.DataFrame({'gesture': [dataset.class_names[p] for p in val_preds]})\n        val_target_df = pd.DataFrame({'gesture': [dataset.class_names[t] for t in val_targets]})\n        val_hf1 = metric.calculate_hierarchical_f1(val_target_df, val_df)\n        print(val_hf1)\n        '''\n        '''\n        if ACC_NOT_F1:\n            if val_hf1 <= 0.05:\n                print(f\"Training collapse detected at epoch {epoch+1} with Val H-F1: {val_hf1:.4f}. Stopping training.\")\n                break\n        if not ACC_NOT_F1:\n            if val_hf1 <= 0.10:\n                print(f\"Training collapse detected at epoch {epoch+1} with Val H-F1: {val_hf1:.4f}. Stopping training.\")\n                break\n        '''\n\n        scheduler.step()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.691611Z","iopub.execute_input":"2025-09-02T15:52:39.691830Z","iopub.status.idle":"2025-09-02T15:52:39.719952Z","shell.execute_reply.started":"2025-09-02T15:52:39.691814Z","shell.execute_reply":"2025-09-02T15:52:39.719319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        out = out + identity\n        return self.relu(out)\n\n\n\n     \nclass CMIModel_deberta_dp_imu(nn.Module): \n    def __init__(self,**kwargs):\n        super().__init__()\n        self.imu_branch_linear = nn.Sequential(\n            self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))  \n        config = DebertaV2Config(\n                hidden_size=kwargs[\"feat_dim\"],\n                num_hidden_layers=kwargs[\"bert_layers\"],\n                num_attention_heads=kwargs[\"bert_heads\"],\n                intermediate_size=kwargs[\"feat_dim\"] * 4,\n                max_position_embeddings=512,\n                relative_attention=True,\n                position_biased_input=False,\n                position_buckets=256,\n                norm_rel_ebd=\"layer_norm\",\n                share_att_key=True,\n                pos_att_type=\"p2c|c2p\",\n                layer_norm_eps=1e-7,\n            )\n\n        self.deberta = DebertaV2Model(config)\n\n        self.aux_classifier = nn.Linear(kwargs[\"feat_dim\"], 1)\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n        \n    \n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=wd),\n            nn.MaxPool1d(pool_size),\n            nn.Dropout(drop)\n        )\n    \n    def forward(self, imu):\n        # imu = torch.cat(imu, dim=-1)\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3], dim=-1).permute(0, 2, 1)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.deberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        pred_cls = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        return self.classifier(pred_cls),self.aux_classifier(cls_token).squeeze(-1)  ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.720750Z","iopub.execute_input":"2025-09-02T15:52:39.720998Z","iopub.status.idle":"2025-09-02T15:52:39.740880Z","shell.execute_reply.started":"2025-09-02T15:52:39.720974Z","shell.execute_reply":"2025-09-02T15:52:39.740204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        out = out + identity\n        return self.relu(out)\n     \n\nclass CMIModel_roberta_dp_imu(nn.Module):\n    def __init__(self,**kwargs):\n        super().__init__()\n        self.imu_branch_linear = nn.Sequential(\n            self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))\n\n        self.roberta = RobertaModel(RobertaConfig(\n                        hidden_size=kwargs[\"feat_dim\"],                 # e.g., 768 or 1024\n                        num_hidden_layers=kwargs[\"bert_layers\"],        # e.g., 12 (base) or 24 (large)\n                        num_attention_heads=kwargs[\"bert_heads\"],       # e.g., 12 (base) or 16 (large)\n                        intermediate_size=kwargs[\"feat_dim\"] * 4,       # feed-forward dimension\n                        max_position_embeddings=514,                        # default for RoBERTa\n                        vocab_size=50265,                                   # RoBERTa tokenizer vocab size\n                        type_vocab_size=1,                                  # RoBERTa doesn’t use token_type_ids\n                        pad_token_id=1,                                     # RoBERTa’s padding ID\n                        layer_norm_eps=1e-5,\n                        hidden_dropout_prob=0.1,\n                        attention_probs_dropout_prob=0.1\n                    ))\n\n        self.aux_classifier = nn.Linear(kwargs[\"feat_dim\"], 1)\n        \n        self.classifier = nn.Sequential(\n            nn.Linear(kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n        \n    \n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=wd),\n            nn.MaxPool1d(pool_size),\n            nn.Dropout(drop)\n        )\n    \n    def forward(self, imu):\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n\n\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3], dim=-1).permute(0, 2, 1)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.roberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        pred_cls = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        return self.classifier(pred_cls),self.aux_classifier(cls_token).squeeze(-1)  ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.743005Z","iopub.execute_input":"2025-09-02T15:52:39.743205Z","iopub.status.idle":"2025-09-02T15:52:39.762027Z","shell.execute_reply.started":"2025-09-02T15:52:39.743190Z","shell.execute_reply":"2025-09-02T15:52:39.761318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        #out = out + identity\n        #return self.relu(out)\n        out = out + identity\n        out = self.relu(out)\n        out = F.layer_norm(out, out.shape[1:])\n        return out\n\nclass AttentionLayer(nn.Module):\n    def __init__(self, feature_dim):\n        super().__init__()\n        self.score_fn = nn.Linear(feature_dim, 1, bias=True)\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, x):\n        # x: (B, L, F)\n        score = torch.tanh(self.score_fn(x))     # (B, L, 1)\n        weights = self.softmax(score.squeeze(-1))# (B, L)\n        weights = weights.unsqueeze(-1)          # (B, L, 1)\n        context = x * weights                    # (B, L, F)\n        return context.sum(dim=1)                # (B, F)\n\nclass GaussianNoise(nn.Module):\n    \"\"\"Add Gaussian noise to input tensor\"\"\"\n    def __init__(self, stddev):\n        super().__init__()\n        self.stddev = stddev\n    \n    def forward(self, x):\n        if self.training:\n            noise = torch.randn_like(x) * self.stddev\n            return x + noise\n        return x\n\n\nclass CMIBackbone_imu(nn.Module):\n    def __init__(self, **kwargs):\n        super().__init__()\n        self.imu_acc_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_rot_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_sum_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_ms_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_md_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )      \n        self.imu_other_branch = nn.Sequential(\n            self.residual_feature_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_jerk_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rotmag_branch = nn.Sequential(\n            self.residual_feature_block(5, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rollmean_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )            \n        self.imu_rotkerk_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n        self.imu_rotxyz_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n\n        self.imu_proj1 = ResNetSEBlock(in_channels=3*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.imu_proj2 = ResNetSEBlock(in_channels=4*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n\n\n        self.lstm = nn.LSTM(\n            input_size=2*kwargs['imu2_channels'],\n            hidden_size=kwargs['lstm_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        self.gru = nn.GRU(\n            input_size=2*kwargs['imu2_channels'],\n            hidden_size=kwargs['gru_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        \n        self.noise = GaussianNoise(kwargs['gaussian_noise_rate'])\n        self.dense = nn.Sequential(\n            nn.Linear(2*kwargs['imu2_channels'], kwargs['dense_channels']),\n            nn.ELU()\n        )\n        \n        self.attn = AttentionLayer(feature_dim=(kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'])  # lstm + gru + dense\n\n    def feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def residual_feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=1e-4),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    \n    def forward(self, imus):\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imus\n        imu_acc_feat = self.imu_acc_branch(imu_acc.permute(0, 2, 1))\n        imu_rot_feat = self.imu_rot_branch(imu_rot.permute(0, 2, 1))\n        imu_sum_feat = self.imu_sum_branch(imu_sum.permute(0, 2, 1))\n        imu_ms_feat = self.imu_ms_branch(imu_ms.permute(0, 2, 1))\n        imu_md_feat = self.imu_md_branch(imu_md.permute(0, 2, 1))\n        imu_others_feat = self.imu_other_branch(imu_others.permute(0, 2, 1))\n        imu_jerk_feat = self.imu_jerk_branch(imu_jerk.permute(0, 2, 1))\n        imu_rotmag_feat = self.imu_rotmag_branch(imu_rot_mag.permute(0, 2, 1))\n        imu_rollmean_feat = self.imu_rollmean_branch(imu_roll_mean.permute(0, 2, 1))\n\n        imu_rotkerk_feat = self.imu_rotkerk_branch(imu_rot_jerk.permute(0, 2, 1))\n        imu_rotxyz_feat = self.imu_rotxyz_branch(imu_rot_xyz.permute(0, 2, 1))\n\n        imu_feat1 = self.imu_proj1(torch.cat([imu_acc_feat, imu_rot_feat, imu_others_feat], dim=1)) #\n        imu_feat2 = self.imu_proj2(torch.cat([imu_md_feat, imu_jerk_feat,imu_ms_feat,imu_sum_feat], dim=1)) # imu_rotmag_feat\n        \n        feat = torch.cat([imu_feat1,imu_feat2], dim=1).permute(0, 2, 1)\n        lstm_out, _ = self.lstm(feat)\n        gru_out, _ = self.gru(feat)\n        dense_out = self.dense(self.noise(feat))\n        \n        return self.attn(torch.cat([lstm_out, gru_out, dense_out], dim=-1))\n\nclass CMIModel_combined_model_imu(nn.Module):\n    def __init__(self, target_classes_num, non_target_classes_num, **kwargs):\n        super().__init__()\n        self.backbone = CMIBackbone_imu(**kwargs)\n        \n        self.imu_branch_linear = nn.Sequential(\n        self.residual_se_cnn_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                   drop=kwargs[\"imu1_dropout\"]),\n        self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_rot = nn.Sequential(\n            self.residual_se_cnn_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )\n\n        self.imu_branch_other = nn.Sequential(\n            self.residual_se_cnn_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"],\n                                       drop=kwargs[\"imu1_dropout\"]),\n            self.residual_se_cnn_block(kwargs[\"imu1_channels\"], kwargs[\"feat_dim\"], kwargs[\"imu2_layers\"],\n                                       drop=kwargs[\"imu2_dropout\"])\n        )        \n    \n\n        self.cls_token = nn.Parameter(torch.zeros(1, 1, kwargs[\"feat_dim\"]))\n\n        self.roberta = RobertaModel(RobertaConfig(\n                        hidden_size=kwargs[\"feat_dim\"],                 # e.g., 768 or 1024\n                        num_hidden_layers=kwargs[\"bert_layers\"],        # e.g., 12 (base) or 24 (large)\n                        num_attention_heads=kwargs[\"bert_heads\"],       # e.g., 12 (base) or 16 (large)\n                        intermediate_size=kwargs[\"feat_dim\"] * 4,       # feed-forward dimension\n                        max_position_embeddings=514,                        # default for RoBERTa\n                        vocab_size=50265,                                   # RoBERTa tokenizer vocab size\n                        type_vocab_size=1,                                  # RoBERTa doesn’t use token_type_ids\n                        pad_token_id=1,                                     # RoBERTa’s padding ID\n                        layer_norm_eps=1e-5,\n                        hidden_dropout_prob=0.1,\n                        attention_probs_dropout_prob=0.1\n                    ))\n\n        self.aux_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], 1)\n        )        \n   \n        self.classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels']+kwargs[\"feat_dim\"]*2, kwargs[\"cls1_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls1_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls1_dropout\"]),\n            nn.Linear(kwargs[\"cls1_channels\"], kwargs[\"cls2_channels\"], bias=False),\n            nn.BatchNorm1d(kwargs[\"cls2_channels\"]),\n            nn.ReLU(inplace=True),\n            nn.Dropout(kwargs[\"cls2_dropout\"]),\n            nn.Linear(kwargs[\"cls2_channels\"], kwargs[\"n_classes\"])\n        )\n\n    def residual_se_cnn_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3, wd=1e-4):\n        return nn.Sequential(\n        *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n        ResNetSEBlock(in_channels, out_channels, wd=wd),\n        nn.MaxPool1d(pool_size),\n        nn.Dropout(drop))        \n\n\n\n    def forward(self, imu):\n        feat1 = self.backbone(imu)\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imu\n\n        imu_feat1 = self.imu_branch_linear(imu_acc.permute(0, 2, 1))\n        imu_feat2 = self.imu_branch_rot(imu_rot.permute(0, 2, 1))\n        imu_feat3 = self.imu_branch_other(imu_others.permute(0, 2, 1))\n\n        bert_input = torch.cat([imu_feat1,imu_feat2,imu_feat3], dim=-1).permute(0, 2, 1)\n        cls_token = self.cls_token.expand(bert_input.size(0), -1, -1)  # (B,1,H)\n        bert_input = torch.cat([cls_token, bert_input], dim=1)  # (B,T+1,H)\n        outputs = self.roberta(inputs_embeds=bert_input)\n        last_hidden = outputs.last_hidden_state\n        cls_token = last_hidden[:, 0, :]\n        mean_pool = last_hidden.mean(dim=1)\n        feat2 = torch.cat([cls_token, mean_pool], dim=-1)  # (B, 2H)\n        combined = torch.cat([feat1, feat2], dim=-1)\n        aux = self.aux_classifier(combined).squeeze(-1)\n        targets = self.classifier(combined)\n        return targets,aux","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.762944Z","iopub.execute_input":"2025-09-02T15:52:39.763189Z","iopub.status.idle":"2025-09-02T15:52:39.798528Z","shell.execute_reply.started":"2025-09-02T15:52:39.763166Z","shell.execute_reply":"2025-09-02T15:52:39.797815Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEBlock(nn.Module):\n    def __init__(self, channels, reduction = 8):\n        super().__init__()\n        self.fc1 = nn.Linear(channels, channels // reduction, bias=True)\n        self.fc2 = nn.Linear(channels // reduction, channels, bias=True)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, C, L)\n        se = F.adaptive_avg_pool1d(x, 1).squeeze(-1)      # -> (B, C)\n        se = F.relu(self.fc1(se), inplace=True)          # -> (B, C//r)\n        se = self.sigmoid(self.fc2(se)).unsqueeze(-1)    # -> (B, C, 1)\n        return x * se                \n\nclass ResNetSEBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, wd = 1e-4):\n        super().__init__()\n        self.conv1 = nn.Conv1d(in_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn1 = nn.BatchNorm1d(out_channels)\n        self.conv2 = nn.Conv1d(out_channels, out_channels,\n                               kernel_size=3, padding=1, bias=False)\n        self.bn2 = nn.BatchNorm1d(out_channels)\n        # SE\n        self.se = SEBlock(out_channels)\n        \n        if in_channels != out_channels:\n            self.shortcut = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1,\n                          padding=0, bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        else:\n            self.shortcut = nn.Identity()\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x) :\n        identity = self.shortcut(x)              # (B, out, L)\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.bn2(self.conv2(out))\n        out = self.se(out)                       # (B, out, L)\n        #out = out + identity\n        #return self.relu(out)\n        out = out + identity\n        out = self.relu(out)\n        out = F.layer_norm(out, out.shape[1:])\n        return out\n\nclass AttentionLayer(nn.Module):\n    def __init__(self, feature_dim):\n        super().__init__()\n        self.score_fn = nn.Linear(feature_dim, 1, bias=True)\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, x):\n        # x: (B, L, F)\n        score = torch.tanh(self.score_fn(x))     # (B, L, 1)\n        weights = self.softmax(score.squeeze(-1))# (B, L)\n        weights = weights.unsqueeze(-1)          # (B, L, 1)\n        context = x * weights                    # (B, L, F)\n        return context.sum(dim=1)                # (B, F)\n\nclass GaussianNoise(nn.Module):\n    \"\"\"Add Gaussian noise to input tensor\"\"\"\n    def __init__(self, stddev):\n        super().__init__()\n        self.stddev = stddev\n    \n    def forward(self, x):\n        if self.training:\n            noise = torch.randn_like(x) * self.stddev\n            return x + noise\n        return x\n\n\nclass CMIBackbone_cnn_imu(nn.Module):\n    def __init__(self, **kwargs):\n        super().__init__()\n        self.imu_acc_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_rot_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_sum_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_ms_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )\n        self.imu_md_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )      \n        self.imu_other_branch = nn.Sequential(\n            self.residual_feature_block(10, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_jerk_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rotmag_branch = nn.Sequential(\n            self.residual_feature_block(5, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )    \n\n        self.imu_rollmean_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )            \n        self.imu_rotkerk_branch = nn.Sequential(\n            self.residual_feature_block(4, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n        self.imu_rotxyz_branch = nn.Sequential(\n            self.residual_feature_block(3, kwargs[\"imu1_channels\"], kwargs[\"imu1_layers\"], drop=kwargs[\"imu1_dropout\"]),\n            self.residual_feature_block(kwargs[\"imu1_channels\"], kwargs[\"imu2_channels\"], kwargs[\"imu2_layers\"], drop=kwargs[\"imu2_dropout\"])\n        )   \n\n        self.imu_proj1 = ResNetSEBlock(in_channels=3*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n        self.imu_proj2 = ResNetSEBlock(in_channels=4*kwargs[\"imu2_channels\"], out_channels=kwargs[\"imu2_channels\"])\n\n\n        self.lstm = nn.LSTM(\n            input_size=2*kwargs['imu2_channels'],\n            hidden_size=kwargs['lstm_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        self.gru = nn.GRU(\n            input_size=2*kwargs['imu2_channels'],\n            hidden_size=kwargs['gru_hidden_size'],\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        \n        self.noise = GaussianNoise(kwargs['gaussian_noise_rate'])\n        self.dense = nn.Sequential(\n            nn.Linear(2*kwargs['imu2_channels'], kwargs['dense_channels']),\n            nn.ELU()\n        )\n        \n        self.attn = AttentionLayer(feature_dim=(kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'])  # lstm + gru + dense\n\n    def feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            nn.Conv1d(in_channels, out_channels, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    def residual_feature_block(self, in_channels, out_channels, num_layers, pool_size=2, drop=0.3):\n        return nn.Sequential(\n            *[ResNetSEBlock(in_channels=in_channels, out_channels=in_channels) for i in range(num_layers)],\n            ResNetSEBlock(in_channels, out_channels, wd=1e-4),\n            nn.MaxPool1d(pool_size, ceil_mode=True),\n            nn.Dropout(drop)\n        )\n\n    \n    def forward(self, imus):\n        imu_acc, imu_rot, imu_sum, imu_ms, imu_md, imu_jerk, imu_rot_mag, imu_roll_mean,imu_rot_jerk,imu_rot_xyz, imu_others = imus\n        imu_acc_feat = self.imu_acc_branch(imu_acc.permute(0, 2, 1))\n        imu_rot_feat = self.imu_rot_branch(imu_rot.permute(0, 2, 1))\n        imu_sum_feat = self.imu_sum_branch(imu_sum.permute(0, 2, 1))\n        imu_ms_feat = self.imu_ms_branch(imu_ms.permute(0, 2, 1))\n        imu_md_feat = self.imu_md_branch(imu_md.permute(0, 2, 1))\n        imu_others_feat = self.imu_other_branch(imu_others.permute(0, 2, 1))\n        imu_jerk_feat = self.imu_jerk_branch(imu_jerk.permute(0, 2, 1))\n        imu_rotmag_feat = self.imu_rotmag_branch(imu_rot_mag.permute(0, 2, 1))\n        imu_rollmean_feat = self.imu_rollmean_branch(imu_roll_mean.permute(0, 2, 1))\n\n        imu_rotkerk_feat = self.imu_rotkerk_branch(imu_rot_jerk.permute(0, 2, 1))\n        imu_rotxyz_feat = self.imu_rotxyz_branch(imu_rot_xyz.permute(0, 2, 1))\n\n        imu_feat1 = self.imu_proj1(torch.cat([imu_acc_feat, imu_rot_feat, imu_others_feat], dim=1)) #\n        imu_feat2 = self.imu_proj2(torch.cat([imu_md_feat, imu_jerk_feat,imu_ms_feat,imu_sum_feat], dim=1)) # imu_rotmag_feat\n\n        \n        feat = torch.cat([imu_feat1,imu_feat2], dim=1).permute(0, 2, 1)\n        lstm_out, _ = self.lstm(feat)\n        gru_out, _ = self.gru(feat)\n        dense_out = self.dense(self.noise(feat))\n        \n        return self.attn(torch.cat([lstm_out, gru_out, dense_out], dim=-1))\n\nclass CMIModel_cnn_model_normal_imu(nn.Module):\n    def __init__(self, target_classes_num, non_target_classes_num, **kwargs):\n        super().__init__()\n        self.backbone = CMIBackbone_cnn_imu(**kwargs)\n        self.target_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], target_classes_num)\n        )\n        self.non_target_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], non_target_classes_num)\n        )\n\n        self.aux_classifier = nn.Sequential(\n            nn.Linear((kwargs['lstm_hidden_size']+kwargs['gru_hidden_size'])*2+kwargs['dense_channels'], kwargs[\"cls_channels1\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels1\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout1\"]),\n            nn.Linear(kwargs[\"cls_channels1\"], kwargs[\"cls_channels2\"]),\n            nn.BatchNorm1d(kwargs[\"cls_channels2\"]),\n            nn.ReLU(),\n            nn.Dropout(kwargs[\"cls_dropout2\"]),\n            nn.Linear(kwargs[\"cls_channels2\"], 1)\n        )\n    def forward(self, imu):\n        feat = self.backbone(imu)\n        targets_y = self.target_classifier(feat)\n        non_targets_y = self.non_target_classifier(feat)\n        aux = self.aux_classifier(feat).squeeze(-1)\n        return torch.cat([targets_y, non_targets_y], dim=1),aux","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.799282Z","iopub.execute_input":"2025-09-02T15:52:39.799507Z","iopub.status.idle":"2025-09-02T15:52:39.829730Z","shell.execute_reply.started":"2025-09-02T15:52:39.799483Z","shell.execute_reply":"2025-09-02T15:52:39.829115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if infer:\n    model_args_dbv2 = {\"feat_dim\": 256,\n                  \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n                  \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0,\n                  \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n                  \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n                  \"bert_layers\": 4, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n                  \"cls1_channels\": 937, \"cls2_channels\": 303, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                  \"imu_dim\": 44, \n                  \"thm_dim\": 10,\n                  \"tof_dim\": 660,\n                  \"n_classes\": 18,\n                 \"imu1_channels\": 128, \"imu2_channels\": 256, \"imu1_dropout\": 0.3, \"imu2_dropout\": 0.25,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0, \n                  \"thm1_channels\": 32, \"thm2_channels\": 64, \"thm1_dropout\": 0.25, \"thm2_dropout\": 0.2,\n                  \"thm1_layers\": 0, \"thm2_layers\": 0, \n                  \"tof1_channels\": 256, \"tof2_channels\": 512, \"tof1_dropout\": 0.4, \"tof2_dropout\": 0.3,\n                  \"tof1_layers\": 0, \"tof2_layers\": 0, \n                  \"lstm_hidden_size\": 128, \"gru_hidden_size\": 128, \"gaussian_noise_rate\": 0.1, \"dense_channels\": 32,\n                  \"cls_channels1\": 256, \"cls_dropout1\": 0.2, \"cls_channels2\": 128, \"cls_dropout2\": 0.2,\n                  \"target_classes_num\": 8, \"non_target_classes_num\": 10}   \n    model_args_roberta_deberta = {\"feat_dim\": 256,\n              \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n              \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n              \"imu1_layers\": 0, \"imu2_layers\": 0,\n              \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n              \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n              \"bert_layers\": 4, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n              \"cls1_channels\": 937, \"cls2_channels\": 303, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                 \"imu_dim\": dataset.full_dataset.imu_dim, \n                \"thm_dim\": dataset.full_dataset.thm_dim,\n                \"tof_dim\": dataset.full_dataset.tof_dim,\n                \"n_classes\": dataset.full_dataset.class_num}   \n\n    model_args_dbv2_imu = {\"feat_dim\": 128,\n                  \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n                  \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0,\n                  \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n                  \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n                  \"bert_layers\": 2, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n                  \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                  \"imu_dim\": 44, \n                  \"thm_dim\": 10,\n                  \"tof_dim\": 660,\n                  \"n_classes\": 18,\n                 \"imu1_channels\": 128, \"imu2_channels\": 256, \"imu1_dropout\": 0.3, \"imu2_dropout\": 0.25,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0, \n                  \"thm1_channels\": 32, \"thm2_channels\": 64, \"thm1_dropout\": 0.25, \"thm2_dropout\": 0.2,\n                  \"thm1_layers\": 0, \"thm2_layers\": 0, \n                  \"tof1_channels\": 256, \"tof2_channels\": 512, \"tof1_dropout\": 0.4, \"tof2_dropout\": 0.3,\n                  \"tof1_layers\": 0, \"tof2_layers\": 0, \n                  \"lstm_hidden_size\": 128, \"gru_hidden_size\": 128, \"gaussian_noise_rate\": 0.1, \"dense_channels\": 32,\n                  \"cls_channels1\": 256, \"cls_dropout1\": 0.2, \"cls_channels2\": 128, \"cls_dropout2\": 0.2,\n                  \"target_classes_num\": 8, \"non_target_classes_num\": 10}   \n    model_args_roberta_deberta_imu = {\"feat_dim\": 256,\n              \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n              \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n              \"imu1_layers\": 0, \"imu2_layers\": 0,\n              \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n              \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n              \"bert_layers\": 2, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n              \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                 \"imu_dim\": dataset.full_dataset.imu_dim, \n                \"thm_dim\": dataset.full_dataset.thm_dim,\n                \"tof_dim\": dataset.full_dataset.tof_dim,\n                \"n_classes\": dataset.full_dataset.class_num} \n\n    model_args_dbv2_imu1 = {\"feat_dim\": 128,\n                  \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n                  \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0,\n                  \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n                  \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n                  \"bert_layers\": 2, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n                  \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                  \"imu_dim\": 44, \n                  \"thm_dim\": 10,\n                  \"tof_dim\": 660,\n                  \"n_classes\": 18,\n                 \"imu1_channels\": 128, \"imu2_channels\": 256, \"imu1_dropout\": 0.3, \"imu2_dropout\": 0.25,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0, \n                  \"thm1_channels\": 32, \"thm2_channels\": 64, \"thm1_dropout\": 0.25, \"thm2_dropout\": 0.2,\n                  \"thm1_layers\": 0, \"thm2_layers\": 0, \n                  \"tof1_channels\": 256, \"tof2_channels\": 512, \"tof1_dropout\": 0.4, \"tof2_dropout\": 0.3,\n                  \"tof1_layers\": 0, \"tof2_layers\": 0, \n                  \"lstm_hidden_size\": 128, \"gru_hidden_size\": 128, \"gaussian_noise_rate\": 0.1, \"dense_channels\": 32,\n                  \"cls_channels1\": 256, \"cls_dropout1\": 0.2, \"cls_channels2\": 128, \"cls_dropout2\": 0.2,\n                  \"target_classes_num\": 8, \"non_target_classes_num\": 10}   \n    model_args_roberta_deberta_imu1 = {\"feat_dim\": 256,\n              \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n              \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n              \"imu1_layers\": 0, \"imu2_layers\": 0,\n              \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n              \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n              \"bert_layers\": 2, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n              \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                 \"imu_dim\": dataset.full_dataset.imu_dim, \n                \"thm_dim\": dataset.full_dataset.thm_dim,\n                \"tof_dim\": dataset.full_dataset.tof_dim,\n                \"n_classes\": dataset.full_dataset.class_num}    \n\n    model_args_dbv2_imu2 = {\"feat_dim\": 128,\n                  \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n                  \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0,\n                  \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n                  \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n                  \"bert_layers\": 2, \"bert_heads\": 8,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n                  \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                  \"imu_dim\": 44, \n                  \"thm_dim\": 10,\n                  \"tof_dim\": 660,\n                  \"n_classes\": 18,\n                 \"imu1_channels\": 128, \"imu2_channels\": 256, \"imu1_dropout\": 0.3, \"imu2_dropout\": 0.25,\n                  \"imu1_layers\": 0, \"imu2_layers\": 0, \n                  \"thm1_channels\": 32, \"thm2_channels\": 64, \"thm1_dropout\": 0.25, \"thm2_dropout\": 0.2,\n                  \"thm1_layers\": 0, \"thm2_layers\": 0, \n                  \"tof1_channels\": 256, \"tof2_channels\": 512, \"tof1_dropout\": 0.4, \"tof2_dropout\": 0.3,\n                  \"tof1_layers\": 0, \"tof2_layers\": 0, \n                  \"lstm_hidden_size\": 128, \"gru_hidden_size\": 128, \"gaussian_noise_rate\": 0.1, \"dense_channels\": 32,\n                  \"cls_channels1\": 256, \"cls_dropout1\": 0.2, \"cls_channels2\": 128, \"cls_dropout2\": 0.2,\n                  \"target_classes_num\": 8, \"non_target_classes_num\": 10}   \n    model_args_roberta_deberta_imu2 = {\"feat_dim\": 256,\n              \"imu1_channels\": 219, \"imu1_dropout\": 0.2946731587132302, \"imu2_dropout\": 0.2697745571929592,\n              \"imu1_weight_decay\": 0.0014824054650601245, \"imu2_weight_decay\": 0.002742543773142381,\n              \"imu1_layers\": 0, \"imu2_layers\": 0,\n              \"thm1_channels\": 82, \"thm1_dropout\": 0.2641274454844602, \"thm2_dropout\": 0.302896343020985, \n              \"tof1_channels\": 82, \"tof1_dropout\": 0.2641274454844602, \"tof2_dropout\": 0.3028963430209852, \n              \"bert_layers\": 2, \"bert_heads\": 4,\"target_classes_num\": 8, \"non_target_classes_num\": 10,\n              \"cls1_channels\": 256, \"cls2_channels\": 128, \"cls1_dropout\": 0.2281834512100508, \"cls2_dropout\": 0.22502521933558461,\n                 \"imu_dim\": dataset.full_dataset.imu_dim, \n                \"thm_dim\": dataset.full_dataset.thm_dim,\n                \"tof_dim\": dataset.full_dataset.tof_dim,\n                \"n_classes\": dataset.full_dataset.class_num} \n\n    \n    model_dicts_roberta = [\n        {\n            \"model_path\": f\"/kaggle/input/roberta-dp-aux/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_roberta = list()\n    folds_roberta  = list()\n    for model_dict in model_dicts_roberta:\n        model_path = model_dict['model_path']\n        model = CMIModel_roberta_dp_aux(**model_args_roberta_deberta).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_roberta.append(model)\n        folds_roberta.append(model_dict['fold'])\n\n    \n\n    model_dicts_deberta = [\n        {\n            \"model_path\": f\"/kaggle/input/deberta-dp-aux/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_deberta = list()\n    folds_deberta = list()\n    for model_dict in model_dicts_deberta:\n        model_path = model_dict['model_path']\n        model = CMIModel_deberta_dp_aux(**model_args_roberta_deberta).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_deberta.append(model)\n        folds_deberta.append(model_dict['fold'])\n\n\n    model_dicts_combined_model = [\n        {\n            \"model_path\": f\"/kaggle/input/combined-model/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_combined_model = list()\n    folds_combined_model = list()\n    for model_dict in model_dicts_combined_model:\n        model_path = model_dict['model_path']\n        model = CMIModel_combined_model(**model_args_dbv2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_combined_model.append(model)\n        folds_combined_model.append(model_dict['fold'])\n\n\n    model_dicts_cnn_model_normal = [\n        {\n            \"model_path\": f\"/kaggle/input/cnn-model-normal/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_cnn_model = list()\n    folds_cnn_model = list()\n    for model_dict in model_dicts_cnn_model_normal:\n        model_path = model_dict['model_path']\n        model = CMIModel_cnn_model_normal(**model_args_dbv2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_cnn_model.append(model)\n        folds_cnn_model.append(model_dict['fold'])\n\n\n###############################################################################################################################################################\n        model_dicts_roberta1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-roberta-dp-aux/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_roberta1 = list()\n    folds_roberta1  = list()\n    for model_dict in model_dicts_roberta1:\n        model_path = model_dict['model_path']\n        model = CMIModel_roberta_dp_aux(**model_args_roberta_deberta).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_roberta1.append(model)\n        folds_roberta1.append(model_dict['fold'])\n\n    \n\n    model_dicts_deberta1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-deberta-dp-aux/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_deberta1 = list()\n    folds_deberta1 = list()\n    for model_dict in model_dicts_deberta1:\n        model_path = model_dict['model_path']\n        model = CMIModel_deberta_dp_aux(**model_args_roberta_deberta).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_deberta1.append(model)\n        folds_deberta1.append(model_dict['fold'])\n\n\n    model_dicts_combined_model1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-combined-model/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_combined_model1 = list()\n    folds_combined_model1 = list()\n    for model_dict in model_dicts_combined_model1:\n        model_path = model_dict['model_path']\n        model = CMIModel_combined_model(**model_args_dbv2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_combined_model1.append(model)\n        folds_combined_model1.append(model_dict['fold'])\n\n\n    model_dicts_cnn_model_normal1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-cnn-model-normal/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_cnn_model1 = list()\n    folds_cnn_model1 = list()\n    for model_dict in model_dicts_cnn_model_normal1:\n        model_path = model_dict['model_path']\n        model = CMIModel_cnn_model_normal(**model_args_dbv2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_cnn_model1.append(model)\n        folds_cnn_model1.append(model_dict['fold'])\n######################################################################################################################################################################\n\n    model_dicts_deberta_imu = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-deberta-dp-imu/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_deberta_model = list()\n    folds_deberta_model = list()\n    for model_dict in model_dicts_deberta_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_deberta_dp_imu(**model_args_roberta_deberta_imu).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_deberta_model.append(model)\n        folds_deberta_model.append(model_dict['fold'])\n\n    model_dicts_roberta_imu = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-roberta-dp-imu-org/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_roberta_model = list()\n    folds_roberta_model = list()\n    for model_dict in model_dicts_roberta_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_roberta_dp_imu(**model_args_roberta_deberta_imu).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_roberta_model.append(model)\n        folds_roberta_model.append(model_dict['fold'])\n\n\n    model_dicts_combined_model_imu = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-combined-model-imu/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_combined_model_imu = list()\n    folds_combined_model_imu = list()\n    for model_dict in model_dicts_combined_model_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_combined_model_imu(**model_args_dbv2_imu).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_combined_model_imu.append(model)\n        folds_combined_model_imu.append(model_dict['fold'])\n\n\n    model_dicts_cnn_model_normal_imu = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-cnn-model-normal-imu/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_cnn_model_imu = list()\n    folds_cnn_model_imu = list()\n    for model_dict in model_dicts_cnn_model_normal_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_cnn_model_normal_imu(**model_args_dbv2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_cnn_model_imu.append(model)\n        folds_cnn_model_imu.append(model_dict['fold'])\n\n\n###########################################################################################################################\n    model_dicts_deberta_imu1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-deberta-dp-imu1/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_deberta_model1 = list()\n    folds_deberta_model1 = list()\n    for model_dict in model_dicts_deberta_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_deberta_dp_imu(**model_args_roberta_deberta_imu1).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_deberta_model1.append(model)\n        folds_deberta_model1.append(model_dict['fold'])\n\n    model_dicts_roberta_imu1 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-roberta-dp-imu1-copy/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_roberta_model1 = list()\n    folds_roberta_model1 = list()\n    for model_dict in model_dicts_roberta_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_roberta_dp_imu(**model_args_roberta_deberta_imu1).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_roberta_model1.append(model)\n        folds_roberta_model1.append(model_dict['fold'])\n\n\n    model_dicts_combined_model_imu1 = [\n        {\n            \"model_path\": f\"/kaggle/input//kaggle/input/cmimodel-combined-model-imu1/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_combined_model_imu1 = list()\n    folds_combined_model_imu1 = list()\n    for model_dict in model_dicts_combined_model_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_combined_model_imu(**model_args_dbv2_imu1).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_combined_model_imu1.append(model)\n        folds_combined_model_imu1.append(model_dict['fold'])\n\n\n    model_dicts_cnn_model_normal_imu1 = [\n        {\n            \"model_path\": f\"/kaggle/input//kaggle/input/cmimodel-cnn-model-normal-imu1/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_cnn_model_imu1 = list()\n    folds_cnn_model_imu1 = list()\n    for model_dict in model_dicts_cnn_model_normal_imu:\n        model_path = model_dict['model_path']\n        model = CMIModel_cnn_model_normal_imu(**model_args_dbv2_imu1).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_cnn_model_imu1.append(model)\n        folds_cnn_model_imu1.append(model_dict['fold'])\n\n\n###############################################################################################################################################################################    \n\n\n    model_dicts_combined_model_imu2 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-combined-model-imu2/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_combined_model_imu2 = list()\n    folds_combined_model_imu2 = list()\n    for model_dict in model_dicts_combined_model_imu2:\n        model_path = model_dict['model_path']\n        model = CMIModel_combined_model_imu(**model_args_dbv2_imu2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_combined_model_imu2.append(model)\n        folds_combined_model_imu2.append(model_dict['fold'])\n\n\n    model_dicts_cnn_model_normal_imu2 = [\n        {\n            \"model_path\": f\"/kaggle/input/cmimodel-cnn-model-normal-imu2/best_model_fold{fold}.pt\",\n            \"fold\": fold,\n        } for fold in range(5)\n    ]\n    \n    models_cnn_model_imu2 = list()\n    folds_cnn_model_imu2 = list()\n    for model_dict in model_dicts_cnn_model_normal_imu2:\n        model_path = model_dict['model_path']\n        model = CMIModel_cnn_model_normal_imu(**model_args_dbv2_imu2).to(CUDA0)\n        model.load_state_dict(torch.load(model_path))\n        models_cnn_model_imu2.append(model)\n        folds_cnn_model_imu2.append(model_dict['fold'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T15:52:39.830459Z","iopub.execute_input":"2025-09-02T15:52:39.830712Z","iopub.status.idle":"2025-09-02T15:54:08.649877Z","shell.execute_reply.started":"2025-09-02T15:52:39.830687Z","shell.execute_reply":"2025-09-02T15:54:08.649065Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_lgb1 = joblib.load(f'/kaggle/input/stacklgb/lgb_fold_1.pkl')\nmodel_lgb2= joblib.load(f'/kaggle/input/stacklgb/lgb_fold_2.pkl')\nmodel_lgb3 = joblib.load(f'/kaggle/input/stacklgb/lgb_fold_3.pkl')\nmodel_lgb4 = joblib.load(f'/kaggle/input/stacklgb/lgb_fold_4.pkl')\nmodel_lgb5 = joblib.load(f'/kaggle/input/stacklgb/lgb_fold_5.pkl')\nle = joblib.load(f'/kaggle/input/lgblabelencoder/catboost_label_encoder.pkl')\ndef model_lgb(params):\n    predictions1 = 0\n    predictions2 = 0\n    predictions3 = 0\n    predictions4 = 0\n    predictions5 = 0\n\n    predictions1 += model_lgb1.predict_proba(\n            params\n        )\n    predictions2 += model_lgb2.predict_proba(\n        params\n    )\n    predictions3 += model_lgb3.predict_proba(\n        params\n    )\n    predictions4 += model_lgb4.predict_proba(\n        params\n    )\n    predictions5 += model_lgb5.predict_proba(\n        params\n    )  \n\n    predictions =(predictions1 + predictions2 + predictions3+ predictions4+predictions5)/5\n    return predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T17:56:47.590030Z","iopub.execute_input":"2025-09-02T17:56:47.590323Z","iopub.status.idle":"2025-09-02T17:56:47.688823Z","shell.execute_reply.started":"2025-09-02T17:56:47.590303Z","shell.execute_reply":"2025-09-02T17:56:47.688105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def avg_predict(models, imus, thms, tofs):\n    outputs = []\n    with autocast(device_type='cuda', dtype=torch.bfloat16):\n        for model in models:\n            model.eval()\n            with torch.no_grad():\n                pred_y,_ = model(imus, thms, tofs)\n            outputs.append(pred_y)\n    return torch.mean(torch.stack(outputs), dim=0)\n\ndef avg_predict_imu(models, imus):\n    outputs = []\n    with autocast(device_type='cuda', dtype=torch.bfloat16):\n        for model in models:\n            model.eval()\n            with torch.no_grad():\n                pred_y,_ = model(imus)\n            outputs.append(pred_y)\n    return torch.mean(torch.stack(outputs), dim=0)\n\ndef split5(dataset, imu, thm, tof):\n    imus = [imu[:, :, dataset.global_imu_indices[k]] for k in dataset.global_imu_indices]\n    thms = [thm[:, :, dataset.global_thm_indices[k]] for k in range(1, 6)]\n    tofs = [tof[:, :, dataset.global_tof_indices[k]] for k in range(1, 6)]\n    return imus, thms, tofs\n\ndef predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    imu, thm, tof = dataset.full_dataset.inference_process(sequence)\n    imus, thms, tofs = split5(dataset.full_dataset, imu, thm, tof)\n    with torch.no_grad():\n        for idx, imu in enumerate(imus):\n            imus[idx] = imu.to(CUDA0)\n        for idx, thm in enumerate(thms):\n            thms[idx] = thm.to(CUDA0)\n        for idx, tof in enumerate(tofs):\n            tofs[idx] = tof.to(CUDA0)\n        tof_cols = [c for c in sequence.columns if c.startswith(\"tof_\")]\n        is_imu_only = (\n            sequence.select(pl.all_horizontal([pl.col(c).is_null() for c in tof_cols]))\n            .select(pl.col(\"*\").all())\n            .item()\n        )\n        if not is_imu_only:\n            # print(f\"inside full data {sequence['sequence_id'][0]}\")\n            # pred_y_roberta = avg_predict(models_roberta, imus, thms, tofs)\n            # pred_y_deberta = avg_predict(models_deberta, imus, thms, tofs)\n            # pred_y_combined = avg_predict(models_combined_model, imus, thms, tofs)\n            # pred_y_cnn = avg_predict(models_cnn_model, imus, thms, tofs)\n\n            # pred_y_roberta1 = avg_predict(models_roberta, imus, thms, tofs)\n            # pred_y_deberta1 = avg_predict(models_deberta, imus, thms, tofs)\n            # pred_y_combined1 = avg_predict(models_combined_model, imus, thms, tofs)\n            # pred_y_cnn1 = avg_predict(models_cnn_model, imus, thms, tofs)\n            # pred_y = 0.05913396*pred_y_deberta+0.07754561*pred_y_roberta+ 0.20615861*pred_y_combined+ 0.17179234*pred_y_cnn + 0.06252562*pred_y_deberta1+0.12136593*pred_y_roberta1+ 0.14496756*pred_y_combined1+ 0.15651036*pred_y_cnn1\n            # print(f'full {dataset.le.classes_[pred_y.argmax(dim=1).cpu()]}')\n            # return dataset.le.classes_[pred_y.argmax(dim=1).cpu()]\n            pred_y_roberta = avg_predict_imu(models_roberta_model, imus)\n            pred_y_deberta = avg_predict_imu(models_deberta_model, imus)\n            pred_y_combined = avg_predict_imu(models_combined_model_imu, imus)\n            pred_y_cnn = avg_predict_imu(models_cnn_model_imu, imus)\n\n            pred_y_roberta1 = avg_predict_imu(models_roberta_model1, imus)\n            pred_y_deberta1 = avg_predict_imu(models_deberta_model1, imus)\n            pred_y_combined1 = avg_predict_imu(models_combined_model_imu1, imus)\n            pred_y_cnn1 = avg_predict_imu(models_cnn_model_imu1, imus)    \n\n            pred_y_combined2 = avg_predict_imu(models_combined_model_imu2, imus)\n            pred_y_cnn2 = avg_predict_imu(models_cnn_model_imu2, imus)              \n\n            \n            pred_y = 0.10138931*pred_y_deberta+0.10672078*pred_y_roberta+0.10058728*pred_y_combined+0.09702458*pred_y_cnn + 0.09771485*pred_y_deberta1+0.10032133*pred_y_roberta1+ \\\n                     0.10271614*pred_y_combined1+0.09454371*pred_y_cnn1+0.09688748*pred_y_combined2+0.10209453*pred_y_cnn2\n\n            return dataset.le.classes_[pred_y.argmax(dim=1).cpu()]\n        else:\n            # # print(f\"imu data {sequence['sequence_id'][0]}\")\n            pred_y_roberta = avg_predict_imu(models_roberta_model, imus)\n            pred_y_deberta = avg_predict_imu(models_deberta_model, imus)\n            pred_y_combined = avg_predict_imu(models_combined_model_imu, imus)\n            pred_y_cnn = avg_predict_imu(models_cnn_model_imu, imus)\n\n            pred_y_roberta1 = avg_predict_imu(models_roberta_model1, imus)\n            pred_y_deberta1 = avg_predict_imu(models_deberta_model1, imus)\n            pred_y_combined1 = avg_predict_imu(models_combined_model_imu1, imus)\n            pred_y_cnn1 = avg_predict_imu(models_cnn_model_imu1, imus)    \n\n            pred_y_combined2 = avg_predict_imu(models_combined_model_imu2, imus)\n            pred_y_cnn2 = avg_predict_imu(models_cnn_model_imu2, imus)              \n\n            \n            # pred_y = 0.10138931*pred_y_deberta+0.10672078*pred_y_roberta+0.10058728*pred_y_combined+0.09702458*pred_y_cnn + 0.09771485*pred_y_deberta1+0.10032133*pred_y_roberta1+ \\\n            #          0.10271614*pred_y_combined1+0.09454371*pred_y_cnn1+0.09688748*pred_y_combined2+0.10209453*pred_y_cnn2\n\n        # pred_y = 0.17009305*pred_y_deberta+0.02304243*pred_y_roberta+0.18289433*pred_y_deberta+0.12792821*pred_y_roberta+ 0.22931832*pred_y_combined+ 0.26672366*pred_y_cnn\n        # print(dataset.le.classes_[pred_y.argmax(dim=1).cpu()])\n            stacking_output = np.hstack([pred_y_combined.cpu().float().numpy(),pred_y_roberta.cpu().float().numpy(),pred_y_deberta.cpu().float().numpy(),pred_y_cnn.cpu().float().numpy(),\\\n                           pred_y_combined1.cpu().float().numpy(),pred_y_roberta1.cpu().float().numpy(),pred_y_deberta1.cpu().float().numpy(),pred_y_cnn1.cpu().float().numpy(),\\\n                           pred_y_combined2.cpu().float().numpy(),pred_y_cnn2.cpu().float().numpy()]).reshape(1, -1)\n            pred_y = model_lgb(stacking_output)\n            # print(f'imu {dataset.le.classes_[np.argmax(pred_y,axis=1)][0]}')\n            return dataset.le.classes_[np.argmax(pred_y,axis=1)][0]    \n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-02T18:00:02.075072Z","iopub.execute_input":"2025-09-02T18:00:02.075343Z","iopub.status.idle":"2025-09-02T18:00:02.089827Z","shell.execute_reply.started":"2025-09-02T18:00:02.075322Z","shell.execute_reply":"2025-09-02T18:00:02.089229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import kaggle_evaluation.cmi_inference_server\n\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-02T18:00:02.330951Z","iopub.execute_input":"2025-09-02T18:00:02.331500Z","iopub.status.idle":"2025-09-02T18:00:07.524436Z","shell.execute_reply.started":"2025-09-02T18:00:02.331475Z","shell.execute_reply":"2025-09-02T18:00:07.523661Z"}},"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}]}