{"cells": [{"cell_type": "markdown", "metadata": {}, "source": "# CMI Synthetic Models V1 - Competition Submission\n\nLLM\u751f\u6210\u5408\u6210\u30c7\u30fc\u30bf\u3067\u8a13\u7df4\u3055\u308c\u305f\u30e2\u30c7\u30eb\u306b\u3088\u308b\u63a8\u8ad6"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "import os\nimport numpy as np\nimport pandas as pd\nimport polars as pl\nimport joblib\nimport warnings\nimport kaggle_evaluation.cmi_inference_server\n\nwarnings.filterwarnings(\"ignore\")\n\n# Environment detection\nIS_KAGGLE = (\n    os.getenv('KAGGLE_IS_COMPETITION_RERUN') is not None or\n    os.getenv('KAGGLE_KERNEL_RUN_TYPE') is not None or\n    os.path.exists('/kaggle/input')\n)\n\nprint(f\"Running on Kaggle: {IS_KAGGLE}\")\n\n# Model path\nMODEL_PATH = \"/kaggle/input/cmi-synthetic-models-v1\"\nprint(\"Loading synthetic models...\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "# Load models and metadata\nlgb_model = joblib.load(f\"{MODEL_PATH}/lgb_synthetic_v1.pkl\")\nxgb_model = joblib.load(f\"{MODEL_PATH}/xgb_synthetic_v1.pkl\")\ncat_model = joblib.load(f\"{MODEL_PATH}/cat_synthetic_v1.pkl\")\n\n# Load preprocessing objects\nscaler = joblib.load(f\"{MODEL_PATH}/scaler_synthetic_v1.pkl\")\nlabel_encoder = joblib.load(f\"{MODEL_PATH}/label_encoder_synthetic_v1.pkl\")\nfeature_names = joblib.load(f\"{MODEL_PATH}/feature_names_synthetic_v1.pkl\")\n\nprint(f\"Models loaded. Expected features: {len(feature_names)}\")\nprint(f\"Label classes: {label_encoder.classes_}\")\n\n# Full gesture mapping to 18 classes\nGESTURE_NAMES = [\n    \"Wave hello\",\n    \"Text on phone\", \n    \"Raise hand\",\n    \"Put hand to mouth\",\n    \"Point\",\n    \"Clap\",\n    \"Shake head\",\n    \"Nod head\",\n    \"Check watch or wrist\",\n    \"Cross arms\",\n    \"Adjust glasses\",\n    \"Touch face\",\n    \"Scratch head\",\n    \"Brush hair\",\n    \"Stretch\",\n    \"Yawn\",\n    \"Take a photo\",\n    \"Other gesture\",\n]\n\nprint(f\"Target gesture classes: {len(GESTURE_NAMES)}\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "def extract_sequence_features(seq_df):\n    \"\"\"Extract features from a single sequence - same as training\"\"\"\n    features = {}\n    \n    # Convert Polars to Pandas if needed\n    if isinstance(seq_df, pl.DataFrame):\n        df = seq_df.to_pandas()\n    else:\n        df = seq_df.copy()\n\n    # Basic info\n    features['seq_length'] = len(df)\n    features['subject_id'] = df['subject'].iloc[0] if 'subject' in df.columns else 0\n    \n    # Sensor columns\n    sensor_cols = ['accel_x', 'accel_y', 'accel_z', 'gyro_x', 'gyro_y', 'gyro_z',\n                   'quat_w', 'quat_x', 'quat_y', 'quat_z', 'temperature'] + \\\n                  [f'tof_{i}' for i in range(8)]\n    \n    for col in sensor_cols:\n        if col in df.columns:\n            values = df[col].values\n            \n            # Basic statistics\n            features[f'{col}_mean'] = np.mean(values)\n            features[f'{col}_std'] = np.std(values)\n            features[f'{col}_max'] = np.max(values)\n            features[f'{col}_min'] = np.min(values)\n            features[f'{col}_range'] = np.max(values) - np.min(values)\n            \n            # Advanced features\n            if len(values) > 1:\n                features[f'{col}_diff_mean'] = np.mean(np.diff(values))\n                features[f'{col}_diff_std'] = np.std(np.diff(values))\n            else:\n                features[f'{col}_diff_mean'] = 0\n                features[f'{col}_diff_std'] = 0\n        else:\n            # Missing sensor columns - fill with zeros\n            for suffix in ['_mean', '_std', '_max', '_min', '_range', '_diff_mean', '_diff_std']:\n                features[f'{col}{suffix}'] = 0\n    \n    # Magnitude features\n    if all(col in df.columns for col in ['accel_x', 'accel_y', 'accel_z']):\n        acc_mag = np.sqrt(df['accel_x']**2 + df['accel_y']**2 + df['accel_z']**2)\n        features['acc_magnitude_mean'] = np.mean(acc_mag)\n        features['acc_magnitude_std'] = np.std(acc_mag)\n        features['acc_magnitude_max'] = np.max(acc_mag)\n    else:\n        features['acc_magnitude_mean'] = 0\n        features['acc_magnitude_std'] = 0\n        features['acc_magnitude_max'] = 0\n    \n    if all(col in df.columns for col in ['gyro_x', 'gyro_y', 'gyro_z']):\n        gyro_mag = np.sqrt(df['gyro_x']**2 + df['gyro_y']**2 + df['gyro_z']**2)\n        features['gyro_magnitude_mean'] = np.mean(gyro_mag)\n        features['gyro_magnitude_std'] = np.std(gyro_mag)\n        features['gyro_magnitude_max'] = np.max(gyro_mag)\n    else:\n        features['gyro_magnitude_mean'] = 0\n        features['gyro_magnitude_std'] = 0\n        features['gyro_magnitude_max'] = 0\n\n    return features\n\nprint(\"Feature extraction function defined\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n    \"\"\"Synthetic model prediction function\"\"\"\n    \n    try:\n        # Extract features\n        features = extract_sequence_features(sequence)\n        \n        # Convert to DataFrame\n        X = pd.DataFrame([features])\n        \n        # Align features with training set\n        X_aligned = pd.DataFrame(index=X.index)\n        for feature_name in feature_names:\n            if feature_name in X.columns:\n                X_aligned[feature_name] = X[feature_name]\n            else:\n                X_aligned[feature_name] = 0  # Missing features filled with zero\n        \n        # Scale features\n        X_scaled = scaler.transform(X_aligned)\n        \n        # Model predictions\n        pred_lgb = lgb_model.predict_proba(X_scaled)[0]\n        pred_xgb = xgb_model.predict_proba(X_scaled)[0] \n        pred_cat = cat_model.predict_proba(X_scaled)[0]\n        \n        # Ensemble (same weights as training)\n        ensemble_probs = 0.4 * pred_lgb + 0.3 * pred_xgb + 0.3 * pred_cat\n        \n        # Get predicted class\n        pred_class_idx = np.argmax(ensemble_probs)\n        pred_class_name = label_encoder.classes_[pred_class_idx]\n        \n        print(f\"Predicted: {pred_class_name} (confidence: {ensemble_probs[pred_class_idx]:.3f})\")\n        \n        # Map to full gesture set if needed\n        if pred_class_name in GESTURE_NAMES:\n            return pred_class_name\n        else:\n            # Fallback mapping for unseen classes\n            class_mapping = {\n                \"Wave hello\": \"Wave hello\",\n                \"Text on phone\": \"Text on phone\", \n                \"Raise hand\": \"Raise hand\"\n            }\n            return class_mapping.get(pred_class_name, \"Other gesture\")\n    \n    except Exception as e:\n        print(f\"Prediction error: {e}\")\n        return \"Wave hello\"  # Safe fallback\n\nprint(\"Prediction function defined\")"}, {"cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": "# Setup inference server\nprint(\"Setting up CMI Inference Server...\")\ninference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif IS_KAGGLE:\n    print(\"Competition environment detected - serving predictions...\")\n    inference_server.serve()\nelse:\n    print(\"Local environment - running gateway test...\")\n    # Local test\n    test_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    \n    try:\n        inference_server.run_local_gateway(data_paths=test_data_paths)\n    except Exception as e:\n        print(f\"Local test failed: {e}\")\n        print(\"This is expected in a local environment without test data.\")\n\nprint(\"Synthetic V1 inference complete!\")"}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12"}}, "nbformat": 4, "nbformat_minor": 4}