{"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":12423906,"sourceType":"datasetVersion","datasetId":7836204}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport pickle\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport pytorch_lightning as pyl\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.nn as nn\nfrom tqdm.auto import tqdm\nfrom pytorch_lightning.callbacks import ModelCheckpoint, EarlyStopping, ModelSummary\n\nfrom sklearn.model_selection import StratifiedKFold\nimport polars as pl\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-09T18:33:53.516091Z","iopub.execute_input":"2025-07-09T18:33:53.516445Z","iopub.status.idle":"2025-07-09T18:33:53.522945Z","shell.execute_reply.started":"2025-07-09T18:33:53.516421Z","shell.execute_reply":"2025-07-09T18:33:53.521698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_dir = '/kaggle/input/model1/'\nwith open(model_dir+'num_to_id.pkl', 'rb') as f:\n    num_to_id = pickle.load(f)\n\nf = np.load(model_dir+'features_scale.npz')\nfeatures_names=f['features_names']\nfeatures_means=f['features_means']\nfeatures_std=f['features_std']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T18:53:09.482530Z","iopub.execute_input":"2025-07-09T18:53:09.483407Z","iopub.status.idle":"2025-07-09T18:53:09.498004Z","shell.execute_reply.started":"2025-07-09T18:53:09.483378Z","shell.execute_reply":"2025-07-09T18:53:09.496823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MAX_LEN = 128\nFEATURE_DIM = 7\nnumber_of_classes = len(num_to_id)\nprint(number_of_classes)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T18:53:12.647981Z","iopub.execute_input":"2025-07-09T18:53:12.648326Z","iopub.status.idle":"2025-07-09T18:53:12.654067Z","shell.execute_reply.started":"2025-07-09T18:53:12.648302Z","shell.execute_reply":"2025-07-09T18:53:12.652863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pad_or_truncate(seq, max_len=MAX_LEN, feature_dim=FEATURE_DIM):\n    length = len(seq)\n    if length < max_len:\n        pad = np.zeros((max_len - length, feature_dim))\n        return np.vstack((pad,seq))\n    else:\n        return seq[-max_len:]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T18:57:27.380012Z","iopub.execute_input":"2025-07-09T18:57:27.380478Z","iopub.status.idle":"2025-07-09T18:57:27.387077Z","shell.execute_reply.started":"2025-07-09T18:57:27.380440Z","shell.execute_reply":"2025-07-09T18:57:27.385945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SequenceClassifier(pyl.LightningModule):\n    def __init__(self, input_dim=8, hidden_dim=64, num_classes=10):\n        super().__init__()\n        self.lstm = nn.LSTM(input_dim, hidden_dim, batch_first=True)\n        self.classifier = nn.Linear(hidden_dim, num_classes)\n        self.loss_fn = nn.CrossEntropyLoss()\n        self.train_losses = []\n        self.val_losses = []\n\n    def forward(self, x):\n        _, (hn, _) = self.lstm(x)  # hn: (1, batch, hidden)\n        logits = self.classifier(hn.squeeze(0))\n        return logits\n\n    def training_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.loss_fn(logits, y)\n        self.log('train_loss', loss, on_step=False, on_epoch=True)\n        return loss\n\n    def on_train_epoch_end(self):\n        train_loss = self.trainer.callback_metrics.get('train_loss')\n        if train_loss is not None:\n            self.train_losses.append(train_loss.item())\n\n    def validation_step(self, batch, batch_idx):\n        x, y = batch\n        logits = self(x)\n        loss = self.loss_fn(logits, y)\n        acc = (logits.argmax(dim=1) == y).float().mean()\n        self.log('val_loss', loss, prog_bar=True, on_step=False, on_epoch=True)\n        self.log('val_acc', acc, prog_bar=True)\n        return loss\n\n    def on_validation_epoch_end(self):\n        val_loss = self.trainer.callback_metrics.get('val_loss')\n        if val_loss is not None:\n            self.val_losses.append(val_loss.item())\n\n\n    def configure_optimizers(self):\n        return torch.optim.Adam(self.parameters(), lr=1e-3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T18:34:02.597494Z","iopub.execute_input":"2025-07-09T18:34:02.597843Z","iopub.status.idle":"2025-07-09T18:34:02.607937Z","shell.execute_reply.started":"2025-07-09T18:34:02.597813Z","shell.execute_reply":"2025-07-09T18:34:02.606937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MODELS = [model_dir+f'model_{i}.ckpt' for i in range(5)]\nmodels = []\nfor path in MODELS:\n    model = SequenceClassifier.load_from_checkpoint(path)\n    model.eval()\n    models.append(model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T19:05:23.765618Z","iopub.execute_input":"2025-07-09T19:05:23.765916Z","iopub.status.idle":"2025-07-09T19:05:24.153819Z","shell.execute_reply.started":"2025-07-09T19:05:23.765897Z","shell.execute_reply":"2025-07-09T19:05:24.152908Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"The evaluation API requires that you set up a server which will respond to inference requests. We have already defined the server; you just need write the predict function. When we evaluate your submission on the hidden test set the client defined in the gateway will run in a different container with direct access to the hidden test set and hand off the one sequence at a time.\n\nYour code will always have access to the published copies of the files.","metadata":{"execution":{"iopub.status.busy":"2025-05-29T22:29:18.955791Z","iopub.execute_input":"2025-05-29T22:29:18.956193Z","iopub.status.idle":"2025-05-29T22:29:18.965179Z","shell.execute_reply.started":"2025-05-29T22:29:18.956169Z","shell.execute_reply":"2025-05-29T22:29:18.963797Z"}}},{"cell_type":"code","source":"from collections import Counter\n\ndef predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    # Replace this function with your inference code.\n    # You can return either a Pandas or Polars dataframe, though Polars is recommended.\n    # Each prediction (except the very first) must be returned within 30 minutes of the batch features being provided.\n    sequence = sequence.to_pandas()\n    mat = sequence[features_names].ffill().bfill().fillna(0).values\n    mat = (mat-features_means)/features_std\n    pad_seq = pad_or_truncate(mat)\n    \n\n    with torch.no_grad():\n        \n        predictions = []\n        for model in models:\n            device = model.device\n            x = torch.FloatTensor(pad_seq).to(device)\n            model.eval()\n            \n            logits = model(x)\n            \n            pred = torch.argmax(logits).item()\n            \n            predictions.append(pred)\n        vote_counts = Counter(predictions)\n        idx = vote_counts.most_common(1)[0][0]\n    \n\n    \n    return str(num_to_id[idx])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-09T19:09:46.040247Z","iopub.execute_input":"2025-07-09T19:09:46.040586Z","iopub.status.idle":"2025-07-09T19:09:46.048134Z","shell.execute_reply.started":"2025-07-09T19:09:46.040566Z","shell.execute_reply":"2025-07-09T19:09:46.046992Z"}},"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-09T19:09:49.196782Z","iopub.execute_input":"2025-07-09T19:09:49.197062Z","iopub.status.idle":"2025-07-09T19:09:50.255075Z","shell.execute_reply.started":"2025-07-09T19:09:49.197044Z","shell.execute_reply":"2025-07-09T19:09:50.254115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}