{"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":"none","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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)\nimport polars as pl\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\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelEncoder\nfrom xgboost import XGBClassifier\n\nimport kaggle_evaluation.cmi_inference_server","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:43:04.805730Z","iopub.execute_input":"2025-07-05T12:43:04.806029Z","iopub.status.idle":"2025-07-05T12:43:09.766214Z","shell.execute_reply.started":"2025-07-05T12:43:04.806001Z","shell.execute_reply":"2025-07-05T12:43:09.765300Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_train_data = pl.read_csv('/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv')#[:30057]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:43:09.832400Z","iopub.execute_input":"2025-07-05T12:43:09.832714Z","iopub.status.idle":"2025-07-05T12:43:20.333341Z","shell.execute_reply.started":"2025-07-05T12:43:09.832689Z","shell.execute_reply":"2025-07-05T12:43:20.332597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_train_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:43:23.983138Z","iopub.execute_input":"2025-07-05T12:43:23.983451Z","iopub.status.idle":"2025-07-05T12:43:24.018159Z","shell.execute_reply.started":"2025-07-05T12:43:23.983426Z","shell.execute_reply":"2025-07-05T12:43:24.017301Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tof_columns = []\nfor column in full_train_data.columns:\n    if 'tof' in column:\n        tof_columns.append(column)\n        \ntof_columns[0:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:43:31.706534Z","iopub.execute_input":"2025-07-05T12:43:31.707209Z","iopub.status.idle":"2025-07-05T12:43:31.713157Z","shell.execute_reply.started":"2025-07-05T12:43:31.707181Z","shell.execute_reply":"2025-07-05T12:43:31.712211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"last_sequence_id = full_train_data['sequence_id'][0]\ncount = 0\nX = []\ny = [full_train_data['gesture'][0]]\none_X = []\nfor i in range(full_train_data.shape[0]):\n    sequence_id = full_train_data['sequence_id'][i]\n    if sequence_id == last_sequence_id:\n        count += 1\n        if count > 29:\n            continue\n    else:\n        last_sequence_id = sequence_id\n        X.append(one_X)\n        y.append(full_train_data['gesture'][i])\n        one_X = []\n        count = 1\n\n    one_X.append(np.array(full_train_data[tof_columns][1]).reshape(5, 8, 8))\nX.append(one_X)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:43:35.266543Z","iopub.execute_input":"2025-07-05T12:43:35.267227Z","iopub.status.idle":"2025-07-05T12:45:48.973192Z","shell.execute_reply.started":"2025-07-05T12:43:35.267200Z","shell.execute_reply":"2025-07-05T12:45:48.972451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = np.array(X).transpose(0,2,1,3,4).astype(np.float32)\ny = np.array(y)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:34:58.003012Z","iopub.execute_input":"2025-07-05T12:34:58.003412Z","iopub.status.idle":"2025-07-05T12:34:58.085127Z","shell.execute_reply.started":"2025-07-05T12:34:58.003384Z","shell.execute_reply":"2025-07-05T12:34:58.083978Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# X = full_train_data.drop(['row_id', 'sequence_type', 'sequence_id', 'sequence_counter',\n#                          'subject','orientation', 'behavior', 'phase', 'gesture',\n#                          'acc_x', 'acc_y', 'acc_z', 'rot_w', 'rot_x', 'rot_y', 'rot_z', 'thm_1', 'thm_2', 'thm_3', 'thm_4', 'thm_5'])\n# y = full_train_data['gesture']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:00.358889Z","iopub.execute_input":"2025-07-05T12:35:00.359307Z","iopub.status.idle":"2025-07-05T12:35:00.365115Z","shell.execute_reply.started":"2025-07-05T12:35:00.359277Z","shell.execute_reply":"2025-07-05T12:35:00.363882Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_X, val_X, train_y, val_y = train_test_split(X, y, test_size=0.2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:00.500326Z","iopub.execute_input":"2025-07-05T12:35:00.500796Z","iopub.status.idle":"2025-07-05T12:35:00.513056Z","shell.execute_reply.started":"2025-07-05T12:35:00.500763Z","shell.execute_reply":"2025-07-05T12:35:00.511525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_encoder = LabelEncoder()\ntrain_y = label_encoder.fit_transform(train_y)\nval_y = label_encoder.transform(val_y)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:00.617426Z","iopub.execute_input":"2025-07-05T12:35:00.617835Z","iopub.status.idle":"2025-07-05T12:35:00.626068Z","shell.execute_reply.started":"2025-07-05T12:35:00.617809Z","shell.execute_reply":"2025-07-05T12:35:00.624158Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import DataLoader, TensorDataset, random_split\n\ntrain_set = TensorDataset(torch.from_numpy(train_X), torch.from_numpy(train_y))\nval_set = TensorDataset(torch.from_numpy(val_X), torch.from_numpy(val_y))\n\ntrain_loader = DataLoader(train_set, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_set, batch_size=32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:01.920229Z","iopub.execute_input":"2025-07-05T12:35:01.920669Z","iopub.status.idle":"2025-07-05T12:35:09.095957Z","shell.execute_reply.started":"2025-07-05T12:35:01.920627Z","shell.execute_reply":"2025-07-05T12:35:09.094232Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass Conv3DClassifier(nn.Module):\n    def __init__(self, num_classes=18):\n        super(Conv3DClassifier, self).__init__()\n\n        self.conv_block = nn.Sequential(\n            nn.Conv3d(in_channels=5, out_channels=16, kernel_size=3, padding=1),  # (B, 16, 30, 8, 8)\n            nn.BatchNorm3d(16),\n            nn.ReLU(),\n            nn.MaxPool3d(kernel_size=(2, 2, 2)),  # (B, 16, 15, 4, 4)\n\n            nn.Conv3d(16, 32, kernel_size=3, padding=1),  # (B, 32, 15, 4, 4)\n            nn.BatchNorm3d(32),\n            nn.ReLU(),\n            nn.MaxPool3d(kernel_size=(3, 2, 2)),  # (B, 32, 5, 2, 2)\n\n            nn.Conv3d(32, 64, kernel_size=3, padding=1),  # (B, 64, 5, 2, 2)\n            nn.BatchNorm3d(64),\n            nn.ReLU(),\n            nn.AdaptiveAvgPool3d((1, 1, 1))  # (B, 64, 1, 1, 1)\n        )\n\n        self.classifier = nn.Linear(64, num_classes)\n\n    def forward(self, x):\n        x = self.conv_block(x)\n        x = x.view(x.size(0), -1)  # Flatten to (B, 64)\n        x = self.classifier(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:09.097937Z","iopub.execute_input":"2025-07-05T12:35:09.098546Z","iopub.status.idle":"2025-07-05T12:35:09.108931Z","shell.execute_reply.started":"2025-07-05T12:35:09.098516Z","shell.execute_reply":"2025-07-05T12:35:09.107498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = Conv3DClassifier().to(device)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:12.274076Z","iopub.execute_input":"2025-07-05T12:35:12.274566Z","iopub.status.idle":"2025-07-05T12:35:16.912403Z","shell.execute_reply.started":"2025-07-05T12:35:12.274536Z","shell.execute_reply":"2025-07-05T12:35:16.911226Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train(model, dataloader, optimizer, criterion, device):\n    model.train()\n    total_loss = 0.0\n    total_correct = 0\n\n    for inputs, labels in dataloader:\n        inputs = inputs.to(device)  # shape: (B, 5, 30, 8, 8)\n        labels = labels.to(device)  # shape: (B,)\n\n        optimizer.zero_grad()\n        outputs = model(inputs)  # shape: (B, 18)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item() * inputs.size(0)\n        preds = outputs.argmax(dim=1)\n        total_correct += (preds == labels).sum().item()\n\n    avg_loss = total_loss / len(dataloader.dataset)\n    accuracy = total_correct / len(dataloader.dataset)\n    return avg_loss, accuracy","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:16.914496Z","iopub.execute_input":"2025-07-05T12:35:16.915505Z","iopub.status.idle":"2025-07-05T12:35:16.925404Z","shell.execute_reply.started":"2025-07-05T12:35:16.915449Z","shell.execute_reply":"2025-07-05T12:35:16.923965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"@torch.no_grad()\ndef evaluate(model, dataloader, criterion, device):\n    model.eval()\n    total_loss = 0.0\n    total_correct = 0\n\n    for inputs, labels in dataloader:\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n\n        total_loss += loss.item() * inputs.size(0)\n        preds = outputs.argmax(dim=1)\n        total_correct += (preds == labels).sum().item()\n\n    avg_loss = total_loss / len(dataloader.dataset)\n    accuracy = total_correct / len(dataloader.dataset)\n    return avg_loss, accuracy\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:16.926659Z","iopub.execute_input":"2025-07-05T12:35:16.927129Z","iopub.status.idle":"2025-07-05T12:35:16.968164Z","shell.execute_reply.started":"2025-07-05T12:35:16.927087Z","shell.execute_reply":"2025-07-05T12:35:16.966604Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_epochs = 100\n\nfor epoch in range(num_epochs):\n    train_loss, train_acc = train(model, train_loader, optimizer, criterion, device)\n    val_loss, val_acc = evaluate(model, val_loader, criterion, device)\n\n    print(f\"Epoch {epoch+1}/{num_epochs}\")\n    print(f\"  Train Loss: {train_loss:.4f}  Acc: {train_acc:.4f}\")\n    print(f\"  Val   Loss: {val_loss:.4f}  Acc: {val_acc:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:20.362785Z","iopub.execute_input":"2025-07-05T12:35:20.363133Z","iopub.status.idle":"2025-07-05T12:35:33.288786Z","shell.execute_reply.started":"2025-07-05T12:35:20.363109Z","shell.execute_reply":"2025-07-05T12:35:33.287566Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save(model.state_dict(), \"conv3d_classifier.pth\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_test_data = pl.read_csv('/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:37.484551Z","iopub.execute_input":"2025-07-05T12:35:37.485724Z","iopub.status.idle":"2025-07-05T12:35:37.523744Z","shell.execute_reply.started":"2025-07-05T12:35:37.485694Z","shell.execute_reply":"2025-07-05T12:35:37.522110Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"count = 0\nX = []\none_X = []\nfor i in range(full_test_data.shape[0]):\n    count += 1\n    if count > 30:\n        break\n    one_X.append(np.array(full_test_data[tof_columns][1]).reshape(5, 8, 8))\nX.append(one_X)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:35:40.831161Z","iopub.execute_input":"2025-07-05T12:35:40.831597Z","iopub.status.idle":"2025-07-05T12:35:40.862485Z","shell.execute_reply.started":"2025-07-05T12:35:40.831571Z","shell.execute_reply":"2025-07-05T12:35:40.861255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    count = 0\n    test_X = []\n    one_X = []\n    for i in range(sequence.shape[0]):\n        count += 1\n        if count > 30:\n            break\n        one_X.append(np.array(sequence[tof_columns][1]).reshape(5, 8, 8))\n    test_X.append(one_X)\n    test_X = np.array(test_X).transpose(0,2,1,3,4).astype(np.float32)\n    \n    re = label_encoder.inverse_transform((model(torch.from_numpy(test_X)).detach().numpy().argmax(),))[0]\n    return str(re)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-05T12:36:18.868065Z","iopub.execute_input":"2025-07-05T12:36:18.868973Z","iopub.status.idle":"2025-07-05T12:36:18.877110Z","shell.execute_reply.started":"2025-07-05T12:36:18.868940Z","shell.execute_reply":"2025-07-05T12:36:18.875903Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"inference_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-07-05T12:36:20.453003Z","iopub.execute_input":"2025-07-05T12:36:20.453343Z","iopub.status.idle":"2025-07-05T12:36:21.848575Z","shell.execute_reply.started":"2025-07-05T12:36:20.453321Z","shell.execute_reply":"2025-07-05T12:36:21.847317Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}