{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":12271927,"sourceType":"datasetVersion","datasetId":7733450}],"dockerImageVersionId":31041,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport polars as pl\nimport pandas as pd\nimport torch\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.utils.class_weight import compute_class_weight\n\n\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.optim as optim\nfrom torch.optim import AdamW\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts\n\nimport os\nimport joblib\nimport random\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:08.397622Z","iopub.execute_input":"2025-06-24T17:24:08.397880Z","iopub.status.idle":"2025-06-24T17:24:18.007506Z","shell.execute_reply.started":"2025-06-24T17:24:08.397856Z","shell.execute_reply":"2025-06-24T17:24:18.006944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMU_DIM = 42\nBATCH_SIZE = 64\nPAD_PERCENTILE = 97\nPAD_LEN = 151\nLR_INIT = 5e-4\nWD = 3e-3\nMIXUP_ALPHA = 0.4\nEPOCHS = 200\nPATIENCE = 40\nSEED = 3126\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.008055Z","iopub.execute_input":"2025-06-24T17:24:18.008339Z","iopub.status.idle":"2025-06-24T17:24:18.098859Z","shell.execute_reply.started":"2025-06-24T17:24:18.008323Z","shell.execute_reply":"2025-06-24T17:24:18.098035Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def seed_all(seed=3126):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\ndef worker_init_fn(worker_id):\n    np.random.seed(SEED + worker_id)\n    random.seed(SEED + worker_id)\n\nseed_all()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.100616Z","iopub.execute_input":"2025-06-24T17:24:18.100805Z","iopub.status.idle":"2025-06-24T17:24:18.137148Z","shell.execute_reply.started":"2025-06-24T17:24:18.100791Z","shell.execute_reply":"2025-06-24T17:24:18.136495Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preprocessor = joblib.load(\"/kaggle/input/imu-model-submission/preprocessor.joblib\")\nlabel_encoder = joblib.load(\"/kaggle/input/imu-model-submission/label_encoder.joblib\")\nimu_features = joblib.load(\"/kaggle/input/imu-model-submission/imu_features.joblib\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.137827Z","iopub.execute_input":"2025-06-24T17:24:18.138104Z","iopub.status.idle":"2025-06-24T17:24:18.191480Z","shell.execute_reply.started":"2025-06-24T17:24:18.138088Z","shell.execute_reply":"2025-06-24T17:24:18.190992Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ResCoordAttention(nn.Module):\n    \"\"\"\n    Residual Coordinate Attention for Sequences.\n    Input: (B, T, C)\n    Output: (B, T, C)\n    \"\"\"\n    def __init__(self, channels, reduction=8):\n        super(ResCoordAttention, self).__init__()\n        self.mid_channels = max(8, channels // reduction)\n        self.pos_embed_T = nn.Parameter(torch.randn(1, self.mid_channels, PAD_LEN))\n\n        self.compression = nn.Sequential(\n            nn.Conv1d(channels, self.mid_channels, kernel_size=1, bias=False),\n            nn.BatchNorm1d(self.mid_channels),\n            nn.SiLU(inplace=True)\n        )\n\n        # Attention branches\n        self.time_conv = nn.Conv1d(1, 1, kernel_size=3, padding=1, bias=False)  # over time dim\n        self.channel_conv = nn.Conv1d(self.mid_channels, channels, kernel_size=1, bias=False)\n        self.sigmoid = nn.Sigmoid()\n\n    def forward(self, x):\n        # x: (B, T, C)\n        x_p = x.permute(0, 2, 1)  # (B, C, T)\n        f   = self.compression(x_p)  # (B, rC, T)\n        f  += self.pos_embed_T[:, :, :f.shape[-1]]\n\n        ## Time Attention (B, 1, T)\n        f_t = f.mean(dim=1, keepdim=True)      \n        time_attn = self.sigmoid(self.time_conv(f_t))  \n\n        ## Channel Attention (B, C, 1)\n        f_c = f.mean(dim=2, keepdim=True)      \n        channel_attn = self.sigmoid(self.channel_conv(f_c))  \n\n        ## Combine attentions\n        out  = x_p * time_attn * channel_attn  \n        out += x_p  \n        return out.permute(0, 2, 1)","metadata":{"trusted":true,"_kg_hide-input":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-06-24T17:24:18.191995Z","iopub.execute_input":"2025-06-24T17:24:18.192188Z","iopub.status.idle":"2025-06-24T17:24:18.198624Z","shell.execute_reply.started":"2025-06-24T17:24:18.192174Z","shell.execute_reply":"2025-06-24T17:24:18.198065Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ResCNNBlock(nn.Module):\n    \"\"\"\n    Residual CNN Block with Attention. \n    \"\"\"\n    def __init__(self, in_channels, out_channels, kernel_size=3, pool_size=2, drop=0.2):\n        super(ResCNNBlock, self).__init__()\n        # PyTorch Conv1D expects (batch_size, channels, timesteps)\n\n        ## CNN model\n        self.cnn = nn.Sequential(\n            nn.Conv1d(in_channels, out_channels, kernel_size, padding='same', bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.Conv1d(out_channels, out_channels, kernel_size, padding='same', bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n        ## Attention module\n        self.attention = ResCoordAttention(out_channels)\n        ## Projection path for skip connection\n        self.shortcut_proj = None\n        if in_channels != out_channels:\n            self.shortcut_proj = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1, padding='same', bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        ## Final processing components\n        self.relu_final = nn.ReLU(inplace=True)\n        if pool_size is not None: \n            self.max_pool = nn.MaxPool1d(pool_size)\n        else: \n            self.max_pool = None\n        self.dropout = nn.Dropout(drop)\n\n    def forward(self, x):\n        shortcut = x                                # (B, T, C_in)\n        out = self.cnn(x.permute(0, 2, 1))          # (B, C_out, T)\n        out = self.attention(out.permute(0, 2, 1))  # (B, T, C_out)\n\n        ## Handle shortcut connection\n        if self.shortcut_proj:\n            shortcut = self.shortcut_proj(shortcut.permute(0, 2, 1)).permute(0, 2, 1)\n\n        ## Residual connection\n        out += shortcut\n        out = self.relu_final(out)\n        if self.max_pool is not None:\n            ## (B, T, C_out) -> (B, T//pool_size, C_out)\n            out = self.max_pool(out.permute(0, 2, 1)).permute(0, 2, 1) \n        out = self.dropout(out)\n        \n        return out","metadata":{"trusted":true,"_kg_hide-input":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-06-24T17:24:18.199209Z","iopub.execute_input":"2025-06-24T17:24:18.199368Z","iopub.status.idle":"2025-06-24T17:24:18.228719Z","shell.execute_reply.started":"2025-06-24T17:24:18.199355Z","shell.execute_reply":"2025-06-24T17:24:18.228234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MLPAttention(nn.Module):\n    def __init__(self, feature_dim):\n        super(MLPAttention, self).__init__()\n        self.attn = nn.Sequential(\n            nn.Linear(feature_dim, feature_dim//8),\n            nn.SiLU(inplace=True),\n            nn.Linear(feature_dim//8, 1)\n        )\n\n    def forward(self, x):\n        # inputs shape: (B, T, C)\n        weights = self.attn(x)  # (B, T, 1)\n        weights = F.softmax(weights, dim=1)  # (B, T, 1)\n        context = (x * weights).sum(dim=1)  # (B, C)\n        return context","metadata":{"trusted":true,"_kg_hide-input":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-06-24T17:24:18.229361Z","iopub.execute_input":"2025-06-24T17:24:18.229546Z","iopub.status.idle":"2025-06-24T17:24:18.253401Z","shell.execute_reply.started":"2025-06-24T17:24:18.229532Z","shell.execute_reply":"2025-06-24T17:24:18.252908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TempCNNBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size=3, dilation=1, drop=0.25):\n        super(TempCNNBlock, self).__init__()\n        ## Padding computation\n        padding = (kernel_size - 1) * dilation // 2\n        ## Temporal Convolution block\n        self.conv = nn.Sequential(\n            nn.Conv1d(in_channels, out_channels, kernel_size=kernel_size,\n                      dilation=dilation, padding=padding, bias=False),\n            nn.BatchNorm1d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n        ## Attention module\n        self.attention = ResCoordAttention(out_channels)\n        ## Dropout\n        self.dropout = nn.Dropout(drop)\n        \n        ## Shortcut for skip connection\n        self.shortcut_proj = None\n        if in_channels != out_channels:\n            self.shortcut_proj = nn.Sequential(\n                nn.Conv1d(in_channels, out_channels, kernel_size=1, padding='same', bias=False),\n                nn.BatchNorm1d(out_channels)\n            )\n        self.relu_final = nn.ReLU()\n        \n    def forward(self, x):\n        ## Processes skip connection\n        shortcut = x\n        if self.shortcut_proj:\n            shortcut = self.shortcut_proj(shortcut.permute(0, 2, 1)).permute(0, 2, 1)\n        ## Processes output\n        out = self.conv(x.permute(0,2,1)).permute(0,2,1)\n        ## Skip connection\n        out = self.relu_final(self.attention(out) + shortcut)\n        out = self.dropout(out)\n        return out","metadata":{"trusted":true,"_kg_hide-input":true,"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2025-06-24T17:24:18.254090Z","iopub.execute_input":"2025-06-24T17:24:18.254353Z","iopub.status.idle":"2025-06-24T17:24:18.280405Z","shell.execute_reply.started":"2025-06-24T17:24:18.254331Z","shell.execute_reply":"2025-06-24T17:24:18.279911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class KinematicResTCNN(nn.Module):\n    \"\"\"\n    Gesture Classifier utilizing ResNet innovations with Temporal Convolution on IMU data.\n    \"\"\"\n    def __init__(self, imu_dim):\n        super(KinematicResTCNN, self).__init__()\n        ## (B,151,42) --> (B, 151//4, 512) = (B, 37, 512)\n        self.resnet = nn.Sequential(\n            ResCNNBlock(imu_dim, 64, kernel_size=3, pool_size=2, drop=0.2),\n            ResCNNBlock(64, 128, kernel_size=3, pool_size=None, drop=0.2),\n            ResCNNBlock(128, 256, kernel_size=3, pool_size=2, drop=0.2),\n            ResCNNBlock(256, 512, kernel_size=5, pool_size=None, drop=0.2),\n        )\n        ## (B, 37, 128) \n        self.temporalCNN = nn.Sequential(\n            TempCNNBlock(512, 256, kernel_size=3, dilation=1, drop=0.2),\n            TempCNNBlock(256, 256, kernel_size=3, dilation=2, drop=0.2),\n            TempCNNBlock(256, 256, kernel_size=3, dilation=4, drop=0.2),\n            TempCNNBlock(256, 128, kernel_size=3, dilation=8, drop=0.2),\n        )\n        ## (B, 37, 128) -> (B, 18)\n        self.classifier_attention = MLPAttention(128)\n        self.classifier  = nn.Sequential(\n            nn.Linear(128, 64, bias=False),\n            nn.BatchNorm1d(64),\n            nn.Dropout(.4),\n            \n            nn.Linear(64, 32, bias=False),\n            nn.BatchNorm1d(32),\n            nn.Dropout(.3),\n\n            nn.Linear(32, 18)\n        )\n\n        ## Noise added during training for regularization\n        # self.noise_std = 0.25\n        # self.noise_activation = nn.SiLU()\n        \n    def forward(self, x):\n        # (B, T, C) -> (B, T//4, 512)\n        out = self.resnet(x)\n        # (B, T//4, 512) -> (B, T//4, 128)\n        out = self.temporalCNN(out)\n        # (B, T//4, 128) -> (B, 128)\n        out = self.classifier_attention(out)\n        # (B, 128) -> (B, 18)\n        out = self.classifier(out)\n        return out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.282278Z","iopub.execute_input":"2025-06-24T17:24:18.282464Z","iopub.status.idle":"2025-06-24T17:24:18.301300Z","shell.execute_reply.started":"2025-06-24T17:24:18.282450Z","shell.execute_reply":"2025-06-24T17:24:18.300669Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MixupDataset(Dataset):\n    def __init__(self, X: np.ndarray, y: np.ndarray, alpha: float = 0.2):\n        \"\"\"\n        Args:\n            X (np.ndarray): Features (e.g., padded time series data).\n                            Expected shape (num_samples, timesteps, features).\n            y (np.ndarray): Labels (e.g., one-hot encoded or class indices).\n                            Expected shape (num_samples, num_classes) for one-hot,\n                            or (num_samples,) for class indices.\n            alpha (float): Alpha parameter for the Beta distribution used in Mixup.\n        \"\"\"\n        # Convert X and y to PyTorch tensors once\n        self.X = torch.tensor(X, dtype=torch.float32)\n        self.y = torch.tensor(y, dtype=torch.float32 if (y.ndim>1) else (torch.long)) # Use long for class indices\n        self.alpha = alpha\n\n    def __len__(self): return len(self.X)\n\n    def __getitem__(self, idx):\n        \"\"\"\n        Generates one sample of data for Mixup.\n        \"\"\"\n        x, y = self.X[idx], self.y[idx]\n        \n        if self.alpha > 0:\n            lam = np.random.beta(self.alpha, self.alpha)\n            rand_idx = np.random.randint(0, len(self.X))\n            x_rand, y_rand = self.X[rand_idx], self.y[rand_idx]\n            \n            x = lam * x + (1 - lam) * x_rand\n            y = lam * y + (1 - lam) * y_rand\n            \n        return x, y","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.301946Z","iopub.execute_input":"2025-06-24T17:24:18.302194Z","iopub.status.idle":"2025-06-24T17:24:18.328400Z","shell.execute_reply.started":"2025-06-24T17:24:18.302175Z","shell.execute_reply":"2025-06-24T17:24:18.327879Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def label_smoothing_loss(pred, target, smoothing=0.1):\n    \"\"\"Label smoothing loss\"\"\"\n    confidence = 1.0 - smoothing\n    log_probs = F.log_softmax(pred, dim=-1)\n    nll_loss = -log_probs.gather(dim=-1, index=target.unsqueeze(1))\n    nll_loss = nll_loss.squeeze(1)\n    smooth_loss = -log_probs.mean(dim=-1)\n    loss = confidence * nll_loss + smoothing * smooth_loss\n    return loss.mean()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.328920Z","iopub.execute_input":"2025-06-24T17:24:18.329069Z","iopub.status.idle":"2025-06-24T17:24:18.357511Z","shell.execute_reply.started":"2025-06-24T17:24:18.329057Z","shell.execute_reply":"2025-06-24T17:24:18.357023Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pad_sequences(sequences, maxlen, padding='post', truncating='post', dtype=torch.float32):\n    \"\"\"\n    Pads a list of PyTorch tensors to a specified maxlen.\n    \"\"\"\n    if not sequences: return torch.empty(0, maxlen, 0, dtype=dtype) # Handle empty list of sequences\n\n    # Assume all sequences have the same feature dimension\n    feature_dim = sequences[0].shape[-1]\n    # Convert all sequences to tensor type\n    sequences = [torch.tensor(seq, dtype=dtype) if not isinstance(seq, torch.Tensor) else seq \n                 for seq in sequences]\n    \n    padded_sequences = []\n    for seq in sequences:\n        current_len = seq.shape[0]\n        \n        # Truncate if necessary\n        if current_len > maxlen:\n            if truncating == 'pre':\n                truncated_seq = seq[-maxlen:]\n            else: # 'post'\n                truncated_seq = seq[:maxlen]\n        else:\n            truncated_seq = seq\n\n        padding_needed = maxlen - truncated_seq.shape[0]\n        \n        # Pad if necessary\n        if padding_needed > 0:\n            if padding == 'pre':\n                # F.pad format: (pad_left, pad_right, pad_top, pad_bottom, ...)\n                # For (timesteps, features), we pad (0,0) for features, (padding_needed, 0) for timesteps\n                padded_seq = F.pad(truncated_seq, (0, 0, padding_needed, 0), 'constant', 0)\n            else: # 'post'\n                padded_seq = F.pad(truncated_seq, (0, 0, 0, padding_needed), 'constant', 0)\n        else:\n            padded_seq = truncated_seq\n        padded_sequences.append(padded_seq)\n            \n    return torch.stack(padded_sequences).to(dtype)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.358052Z","iopub.execute_input":"2025-06-24T17:24:18.358236Z","iopub.status.idle":"2025-06-24T17:24:18.378655Z","shell.execute_reply.started":"2025-06-24T17:24:18.358223Z","shell.execute_reply":"2025-06-24T17:24:18.378165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess_sequence(df_seq: pd.DataFrame, feature_cols: list, scaler):\n    \"\"\"Normalizes and cleans the time series sequence\"\"\"\n    mat = df_seq[feature_cols].ffill().bfill().fillna(0)\n    return scaler.transform(mat).astype('float32')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.379221Z","iopub.execute_input":"2025-06-24T17:24:18.379401Z","iopub.status.idle":"2025-06-24T17:24:18.403777Z","shell.execute_reply.started":"2025-06-24T17:24:18.379377Z","shell.execute_reply":"2025-06-24T17:24:18.403318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = KinematicResTCNN(IMU_DIM).to(DEVICE)\nmodel.load_state_dict(torch.load(\"/kaggle/input/imu-model-submission/best_model.pth\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:18.404290Z","iopub.execute_input":"2025-06-24T17:24:18.404481Z","iopub.status.idle":"2025-06-24T17:24:19.258722Z","shell.execute_reply.started":"2025-06-24T17:24:18.404466Z","shell.execute_reply":"2025-06-24T17:24:19.258157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_features(data):\n    df = data.with_columns(\n        pl.fold(\n            acc = pl.lit(0),\n            function = lambda acc,x: acc + x**2,\n            exprs = \"^acc_.*$\" \n        ).sqrt().alias(\"acc_mag\"),\n    \n        (2*np.arccos(pl.col(\"rot_w\").clip(-1, 1))).alias(\"rot_angle\")\n        \n    ).with_columns(\n        pl.col(\"acc_mag\").diff().over(\"sequence_id\").fill_null(0).alias(\"acc_mag_diff\"),\n        pl.col(\"rot_angle\").diff().over(\"sequence_id\").fill_null(0).alias(\"rot_angle_diff\"),\n        pl.col(\"rot_angle\").diff().diff().over(\"sequence_id\").fill_null(0).alias(\"rot_angle_diff2\"),\n        \n        ## Differential features for acceleration features\n        pl.col(\"acc_x\").diff().over(\"sequence_id\").fill_null(0).alias(\"acc_x_diff\"),\n        pl.col(\"acc_y\").diff().over(\"sequence_id\").fill_null(0).alias(\"acc_y_diff\"),\n        pl.col(\"acc_z\").diff().over(\"sequence_id\").fill_null(0).alias(\"acc_z_diff\"),\n        pl.col(\"acc_x\").diff().diff().over(\"sequence_id\").fill_null(0).alias(\"acc_x_diff2\"),\n        pl.col(\"acc_y\").diff().diff().over(\"sequence_id\").fill_null(0).alias(\"acc_y_diff2\"),\n        pl.col(\"acc_z\").diff().diff().over(\"sequence_id\").fill_null(0).alias(\"acc_z_diff2\"),\n    \n    ).with_columns(\n        ## Curvature features of acceleration\n        (pl.col(\"acc_x_diff2\")/(pl.col(\"acc_x_diff\").abs()+1e-5)).abs().log1p().alias(\"acc_x_logAbs_curvature\"),\n        (pl.col(\"acc_y_diff2\")/(pl.col(\"acc_y_diff\").abs()+1e-5)).abs().log1p().alias(\"acc_y_logAbs_curvature\"),\n        (pl.col(\"acc_z_diff2\")/(pl.col(\"acc_z_diff\").abs()+1e-5)).abs().log1p().alias(\"acc_z_logAbs_curvature\"),\n        (pl.col(\"acc_x_diff2\")/(pl.col(\"acc_x_diff\").abs()+1e-5)).sign().alias(\"acc_x_curvature_sgn\"),\n        (pl.col(\"acc_y_diff2\")/(pl.col(\"acc_y_diff\").abs()+1e-5)).sign().alias(\"acc_y_curvature_sgn\"),\n        (pl.col(\"acc_z_diff2\")/(pl.col(\"acc_z_diff\").abs()+1e-5)).sign().alias(\"acc_z_curvature_sgn\"),\n        ## Curvature features of rot angle\n        (pl.col(\"rot_angle_diff2\")/(pl.col(\"rot_angle_diff\").abs()+1e-5)).abs().log1p().alias(\"rot_angle_logAbs_curvature\"),\n        (pl.col(\"rot_angle_diff2\")/(pl.col(\"rot_angle_diff\").abs()+1e-5)).sign().alias(\"rot_angle_curvature_sgn\")\n        \n    ).with_columns(\n        ## Signed log curvature features of acceleration\n        (pl.col(\"acc_x_curvature_sgn\")*pl.col(\"acc_x_logAbs_curvature\")).alias(\"acc_x_log_sgn_curvature\"),\n        (pl.col(\"acc_y_curvature_sgn\")*pl.col(\"acc_y_logAbs_curvature\")).alias(\"acc_y_log_sgn_curvature\"),\n        (pl.col(\"acc_z_curvature_sgn\")*pl.col(\"acc_z_logAbs_curvature\")).alias(\"acc_z_log_sgn_curvature\"),\n    \n        ## Signed rot angle curvature feature\n        (pl.col(\"rot_angle_curvature_sgn\")*pl.col(\"rot_angle_logAbs_curvature\")).alias(\"rot_angle_log_sgn_curvature\"),\n        \n        ## Sign interaction features between acceleration components\n        (pl.col(\"acc_x\")*pl.col(\"acc_y\")).sign().alias(\"acc_xy_sgn\"),\n        (pl.col(\"acc_x\")*pl.col(\"acc_z\")).sign().alias(\"acc_xz_sgn\"),\n        (pl.col(\"acc_y\")*pl.col(\"acc_z\")).sign().alias(\"acc_yz_sgn\"),\n        (pl.col(\"acc_x\")*pl.col(\"acc_y\")*pl.col(\"acc_z\")).sign().alias(\"acc_xyz_sgn\"),\n        \n        ## Sign interaction features between rotational components\n        (pl.col(\"rot_w\")*pl.col(\"rot_x\")).sign().alias(\"rot_wx_sgn\"),\n        (pl.col(\"rot_w\")*pl.col(\"rot_y\")).sign().alias(\"rot_wy_sgn\"),\n        (pl.col(\"rot_w\")*pl.col(\"rot_z\")).sign().alias(\"rot_wz_sgn\"),\n        (pl.col(\"rot_x\")*pl.col(\"rot_y\")).sign().alias(\"rot_xy_sgn\"),\n        (pl.col(\"rot_x\")*pl.col(\"rot_z\")).sign().alias(\"rot_xz_sgn\"),\n        (pl.col(\"rot_y\")*pl.col(\"rot_z\")).sign().alias(\"rot_yz_sgn\"),\n        (pl.col(\"rot_w\")*pl.col(\"rot_x\")*pl.col(\"rot_y\")*pl.col(\"rot_z\")).sign().alias(\"rot_wxyz_sgn\"),\n        (pl.col(\"rot_x\")*pl.col(\"rot_y\")*pl.col(\"rot_z\")).sign().alias(\"rot_xyz_sgn\")\n    ).to_pandas()\n    return df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:24:19.259365Z","iopub.execute_input":"2025-06-24T17:24:19.259546Z","iopub.status.idle":"2025-06-24T17:24:19.271564Z","shell.execute_reply.started":"2025-06-24T17:24:19.259532Z","shell.execute_reply":"2025-06-24T17:24:19.270978Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    sequence_df = make_features(sequence)\n        \n    X = sequence_df[imu_features[\"full_features\"]]\n    X = X.ffill().bfill().fillna(0).astype('float32')\n    X = preprocessor.transform(X)\n    X = pad_sequences([X], maxlen=PAD_LEN, padding='post', truncating='post')\n    \n    model.eval()\n    with torch.inference_mode():\n        X = torch.FloatTensor(X).to(DEVICE)\n        logits = model(X)\n        idx = logits.argmax(dim=1).item()\n        \n    return label_encoder.inverse_transform([idx])[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:25:20.296886Z","iopub.execute_input":"2025-06-24T17:25:20.297163Z","iopub.status.idle":"2025-06-24T17:25:20.302211Z","shell.execute_reply.started":"2025-06-24T17:25:20.297109Z","shell.execute_reply":"2025-06-24T17:25:20.301510Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import kaggle_evaluation.cmi_inference_server\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-24T17:25:22.152822Z","iopub.execute_input":"2025-06-24T17:25:22.153110Z","iopub.status.idle":"2025-06-24T17:25:26.258768Z","shell.execute_reply.started":"2025-06-24T17:25:22.153089Z","shell.execute_reply":"2025-06-24T17:25:26.258177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}