{"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,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":433016,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":351419,"modelId":372666}],"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)\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-06-12T07:55:38.603902Z","iopub.execute_input":"2025-06-12T07:55:38.604283Z","iopub.status.idle":"2025-06-12T07:55:39.885008Z","shell.execute_reply.started":"2025-06-12T07:55:38.604248Z","shell.execute_reply":"2025-06-12T07:55:39.883772Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport joblib\nimport polars as pl\nimport numpy as np\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:39.886764Z","iopub.execute_input":"2025-06-12T07:55:39.887624Z","iopub.status.idle":"2025-06-12T07:55:46.145538Z","shell.execute_reply.started":"2025-06-12T07:55:39.887588Z","shell.execute_reply":"2025-06-12T07:55:46.144605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SEQUENCE_LENGTH=150\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.146497Z","iopub.execute_input":"2025-06-12T07:55:46.146991Z","iopub.status.idle":"2025-06-12T07:55:46.151702Z","shell.execute_reply.started":"2025-06-12T07:55:46.146959Z","shell.execute_reply":"2025-06-12T07:55:46.150722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Attention(nn.Module):\n    def __init__(self, hidden_size):\n        super().__init__()\n        self.attn = nn.Linear(hidden_size, 1)\n\n    def forward(self, lstm_out):\n        scores = self.attn(lstm_out)\n        weights = torch.softmax(scores, dim=1)\n        context = torch.sum(weights*lstm_out, dim=1)\n        return context, weights","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.153605Z","iopub.execute_input":"2025-06-12T07:55:46.153834Z","iopub.status.idle":"2025-06-12T07:55:46.170529Z","shell.execute_reply.started":"2025-06-12T07:55:46.153817Z","shell.execute_reply":"2025-06-12T07:55:46.169635Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Model_Architecture(nn.Module):\n    def __init__(self, input_dim=332, hidden_dim=128, output_dim=18, num_layers=3, sequence_len=200):\n        super(Model_Architecture, self).__init__()\n\n        self.input_size = input_dim\n        self.hidden_size = hidden_dim\n        self.output_size = output_dim\n        self.sequence_len = sequence_len\n        self.num_layers=num_layers\n\n        self.lstm = nn.LSTM(input_size=self.input_size, hidden_size=self.hidden_size, num_layers=self.num_layers, dropout=0.2, batch_first=True, device=device)\n        self.ln = nn.LayerNorm(self.hidden_size)\n        self.attention = Attention(hidden_size=self.hidden_size)\n        self.fc = nn.Linear(self.hidden_size, self.output_size)\n\n    def forward(self, x):\n        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)\n        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)\n\n        out, (hn, cn) = self.lstm(x, (h0, c0))\n        out = self.ln(out)\n        out, weights = self.attention(out)\n        out = self.fc(out)\n        #out = self.fc(out[:, -1, :])\n        return out\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.171435Z","iopub.execute_input":"2025-06-12T07:55:46.171672Z","iopub.status.idle":"2025-06-12T07:55:46.181053Z","shell.execute_reply.started":"2025-06-12T07:55:46.171652Z","shell.execute_reply":"2025-06-12T07:55:46.180264Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = Model_Architecture(input_dim=332, hidden_dim=128, output_dim=18, num_layers=3, sequence_len=SEQUENCE_LENGTH)\nmodel.load_state_dict(torch.load(\"/kaggle/input/vanilla_lstm/pytorch/default/5/model_weights.pth\", map_location=device))\nmodel.to(device)\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.182034Z","iopub.execute_input":"2025-06-12T07:55:46.182384Z","iopub.status.idle":"2025-06-12T07:55:46.302504Z","shell.execute_reply.started":"2025-06-12T07:55:46.182355Z","shell.execute_reply":"2025-06-12T07:55:46.301640Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scaler = joblib.load(\"/kaggle/input/vanilla_lstm/pytorch/default/5/scaler.pkl\")\nlabel_encoder = joblib.load(\"/kaggle/input/vanilla_lstm/pytorch/default/5/label_encoder.pkl\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.303692Z","iopub.execute_input":"2025-06-12T07:55:46.304495Z","iopub.status.idle":"2025-06-12T07:55:46.869755Z","shell.execute_reply.started":"2025-06-12T07:55:46.304471Z","shell.execute_reply":"2025-06-12T07:55:46.868687Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"feature_cols = ['acc_x',\n 'acc_y',\n 'acc_z',\n 'rot_w',\n 'rot_x',\n 'rot_y',\n 'rot_z',\n 'thm_1',\n 'thm_2',\n 'thm_3',\n 'thm_4',\n 'thm_5',\n 'tof_1_v0',\n 'tof_1_v1',\n 'tof_1_v2',\n 'tof_1_v3',\n 'tof_1_v4',\n 'tof_1_v5',\n 'tof_1_v6',\n 'tof_1_v7',\n 'tof_1_v8',\n 'tof_1_v9',\n 'tof_1_v10',\n 'tof_1_v11',\n 'tof_1_v12',\n 'tof_1_v13',\n 'tof_1_v14',\n 'tof_1_v15',\n 'tof_1_v16',\n 'tof_1_v17',\n 'tof_1_v18',\n 'tof_1_v19',\n 'tof_1_v20',\n 'tof_1_v21',\n 'tof_1_v22',\n 'tof_1_v23',\n 'tof_1_v24',\n 'tof_1_v25',\n 'tof_1_v26',\n 'tof_1_v27',\n 'tof_1_v28',\n 'tof_1_v29',\n 'tof_1_v30',\n 'tof_1_v31',\n 'tof_1_v32',\n 'tof_1_v33',\n 'tof_1_v34',\n 'tof_1_v35',\n 'tof_1_v36',\n 'tof_1_v37',\n 'tof_1_v38',\n 'tof_1_v39',\n 'tof_1_v40',\n 'tof_1_v41',\n 'tof_1_v42',\n 'tof_1_v43',\n 'tof_1_v44',\n 'tof_1_v45',\n 'tof_1_v46',\n 'tof_1_v47',\n 'tof_1_v48',\n 'tof_1_v49',\n 'tof_1_v50',\n 'tof_1_v51',\n 'tof_1_v52',\n 'tof_1_v53',\n 'tof_1_v54',\n 'tof_1_v55',\n 'tof_1_v56',\n 'tof_1_v57',\n 'tof_1_v58',\n 'tof_1_v59',\n 'tof_1_v60',\n 'tof_1_v61',\n 'tof_1_v62',\n 'tof_1_v63',\n 'tof_2_v0',\n 'tof_2_v1',\n 'tof_2_v2',\n 'tof_2_v3',\n 'tof_2_v4',\n 'tof_2_v5',\n 'tof_2_v6',\n 'tof_2_v7',\n 'tof_2_v8',\n 'tof_2_v9',\n 'tof_2_v10',\n 'tof_2_v11',\n 'tof_2_v12',\n 'tof_2_v13',\n 'tof_2_v14',\n 'tof_2_v15',\n 'tof_2_v16',\n 'tof_2_v17',\n 'tof_2_v18',\n 'tof_2_v19',\n 'tof_2_v20',\n 'tof_2_v21',\n 'tof_2_v22',\n 'tof_2_v23',\n 'tof_2_v24',\n 'tof_2_v25',\n 'tof_2_v26',\n 'tof_2_v27',\n 'tof_2_v28',\n 'tof_2_v29',\n 'tof_2_v30',\n 'tof_2_v31',\n 'tof_2_v32',\n 'tof_2_v33',\n 'tof_2_v34',\n 'tof_2_v35',\n 'tof_2_v36',\n 'tof_2_v37',\n 'tof_2_v38',\n 'tof_2_v39',\n 'tof_2_v40',\n 'tof_2_v41',\n 'tof_2_v42',\n 'tof_2_v43',\n 'tof_2_v44',\n 'tof_2_v45',\n 'tof_2_v46',\n 'tof_2_v47',\n 'tof_2_v48',\n 'tof_2_v49',\n 'tof_2_v50',\n 'tof_2_v51',\n 'tof_2_v52',\n 'tof_2_v53',\n 'tof_2_v54',\n 'tof_2_v55',\n 'tof_2_v56',\n 'tof_2_v57',\n 'tof_2_v58',\n 'tof_2_v59',\n 'tof_2_v60',\n 'tof_2_v61',\n 'tof_2_v62',\n 'tof_2_v63',\n 'tof_3_v0',\n 'tof_3_v1',\n 'tof_3_v2',\n 'tof_3_v3',\n 'tof_3_v4',\n 'tof_3_v5',\n 'tof_3_v6',\n 'tof_3_v7',\n 'tof_3_v8',\n 'tof_3_v9',\n 'tof_3_v10',\n 'tof_3_v11',\n 'tof_3_v12',\n 'tof_3_v13',\n 'tof_3_v14',\n 'tof_3_v15',\n 'tof_3_v16',\n 'tof_3_v17',\n 'tof_3_v18',\n 'tof_3_v19',\n 'tof_3_v20',\n 'tof_3_v21',\n 'tof_3_v22',\n 'tof_3_v23',\n 'tof_3_v24',\n 'tof_3_v25',\n 'tof_3_v26',\n 'tof_3_v27',\n 'tof_3_v28',\n 'tof_3_v29',\n 'tof_3_v30',\n 'tof_3_v31',\n 'tof_3_v32',\n 'tof_3_v33',\n 'tof_3_v34',\n 'tof_3_v35',\n 'tof_3_v36',\n 'tof_3_v37',\n 'tof_3_v38',\n 'tof_3_v39',\n 'tof_3_v40',\n 'tof_3_v41',\n 'tof_3_v42',\n 'tof_3_v43',\n 'tof_3_v44',\n 'tof_3_v45',\n 'tof_3_v46',\n 'tof_3_v47',\n 'tof_3_v48',\n 'tof_3_v49',\n 'tof_3_v50',\n 'tof_3_v51',\n 'tof_3_v52',\n 'tof_3_v53',\n 'tof_3_v54',\n 'tof_3_v55',\n 'tof_3_v56',\n 'tof_3_v57',\n 'tof_3_v58',\n 'tof_3_v59',\n 'tof_3_v60',\n 'tof_3_v61',\n 'tof_3_v62',\n 'tof_3_v63',\n 'tof_4_v0',\n 'tof_4_v1',\n 'tof_4_v2',\n 'tof_4_v3',\n 'tof_4_v4',\n 'tof_4_v5',\n 'tof_4_v6',\n 'tof_4_v7',\n 'tof_4_v8',\n 'tof_4_v9',\n 'tof_4_v10',\n 'tof_4_v11',\n 'tof_4_v12',\n 'tof_4_v13',\n 'tof_4_v14',\n 'tof_4_v15',\n 'tof_4_v16',\n 'tof_4_v17',\n 'tof_4_v18',\n 'tof_4_v19',\n 'tof_4_v20',\n 'tof_4_v21',\n 'tof_4_v22',\n 'tof_4_v23',\n 'tof_4_v24',\n 'tof_4_v25',\n 'tof_4_v26',\n 'tof_4_v27',\n 'tof_4_v28',\n 'tof_4_v29',\n 'tof_4_v30',\n 'tof_4_v31',\n 'tof_4_v32',\n 'tof_4_v33',\n 'tof_4_v34',\n 'tof_4_v35',\n 'tof_4_v36',\n 'tof_4_v37',\n 'tof_4_v38',\n 'tof_4_v39',\n 'tof_4_v40',\n 'tof_4_v41',\n 'tof_4_v42',\n 'tof_4_v43',\n 'tof_4_v44',\n 'tof_4_v45',\n 'tof_4_v46',\n 'tof_4_v47',\n 'tof_4_v48',\n 'tof_4_v49',\n 'tof_4_v50',\n 'tof_4_v51',\n 'tof_4_v52',\n 'tof_4_v53',\n 'tof_4_v54',\n 'tof_4_v55',\n 'tof_4_v56',\n 'tof_4_v57',\n 'tof_4_v58',\n 'tof_4_v59',\n 'tof_4_v60',\n 'tof_4_v61',\n 'tof_4_v62',\n 'tof_4_v63',\n 'tof_5_v0',\n 'tof_5_v1',\n 'tof_5_v2',\n 'tof_5_v3',\n 'tof_5_v4',\n 'tof_5_v5',\n 'tof_5_v6',\n 'tof_5_v7',\n 'tof_5_v8',\n 'tof_5_v9',\n 'tof_5_v10',\n 'tof_5_v11',\n 'tof_5_v12',\n 'tof_5_v13',\n 'tof_5_v14',\n 'tof_5_v15',\n 'tof_5_v16',\n 'tof_5_v17',\n 'tof_5_v18',\n 'tof_5_v19',\n 'tof_5_v20',\n 'tof_5_v21',\n 'tof_5_v22',\n 'tof_5_v23',\n 'tof_5_v24',\n 'tof_5_v25',\n 'tof_5_v26',\n 'tof_5_v27',\n 'tof_5_v28',\n 'tof_5_v29',\n 'tof_5_v30',\n 'tof_5_v31',\n 'tof_5_v32',\n 'tof_5_v33',\n 'tof_5_v34',\n 'tof_5_v35',\n 'tof_5_v36',\n 'tof_5_v37',\n 'tof_5_v38',\n 'tof_5_v39',\n 'tof_5_v40',\n 'tof_5_v41',\n 'tof_5_v42',\n 'tof_5_v43',\n 'tof_5_v44',\n 'tof_5_v45',\n 'tof_5_v46',\n 'tof_5_v47',\n 'tof_5_v48',\n 'tof_5_v49',\n 'tof_5_v50',\n 'tof_5_v51',\n 'tof_5_v52',\n 'tof_5_v53',\n 'tof_5_v54',\n 'tof_5_v55',\n 'tof_5_v56',\n 'tof_5_v57',\n 'tof_5_v58',\n 'tof_5_v59',\n 'tof_5_v60',\n 'tof_5_v61',\n 'tof_5_v62',\n 'tof_5_v63']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.870883Z","iopub.execute_input":"2025-06-12T07:55:46.871438Z","iopub.status.idle":"2025-06-12T07:55:46.887890Z","shell.execute_reply.started":"2025-06-12T07:55:46.871405Z","shell.execute_reply":"2025-06-12T07:55:46.886901Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    # Convert Polars to Pandas\n    df = sequence.to_pandas()\n\n    # Extract features and scale\n    X = df[feature_cols].to_numpy()\n    X = scaler.transform(X)  \n    \n    # Pad or truncate\n    padded = np.zeros((SEQUENCE_LENGTH, X.shape[1]))\n    length = min(SEQUENCE_LENGTH, len(X))\n    padded[:length] = X[:length]\n\n    # Convert to tensor\n    input_tensor = torch.tensor(padded, dtype=torch.float32).unsqueeze(0).to(device)  # shape (1, seq_len, input_dim)\n\n    # Inference\n    with torch.no_grad():\n        output = model(input_tensor)\n        pred_idx = torch.argmax(output, dim=1).item()\n\n    # Decode label\n    gesture = label_encoder.inverse_transform([pred_idx])[0]\n    return gesture\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-12T07:55:46.889401Z","iopub.execute_input":"2025-06-12T07:55:46.889769Z","iopub.status.idle":"2025-06-12T07:55:46.917505Z","shell.execute_reply.started":"2025-06-12T07:55:46.889740Z","shell.execute_reply":"2025-06-12T07:55:46.916574Z"}},"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-06-12T07:55:46.920121Z","iopub.execute_input":"2025-06-12T07:55:46.920411Z","iopub.status.idle":"2025-06-12T07:55:49.120098Z","shell.execute_reply.started":"2025-06-12T07:55:46.920390Z","shell.execute_reply":"2025-06-12T07:55:49.119142Z"}},"outputs":[],"execution_count":null}]}