{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":112509,"databundleVersionId":14254895},{"sourceType":"modelInstanceVersion","sourceId":2652,"databundleVersionId":4910549,"modelInstanceId":1918,"modelId":257},{"sourceType":"modelInstanceVersion","sourceId":6123,"databundleVersionId":7429407,"modelInstanceId":4606,"modelId":2797}],"dockerImageVersionId":31329,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport joblib\nimport pandas as pd\nimport numpy as np\nfrom tqdm import tqdm\nimport albumentations as A\nimport cv2\n\nfrom sklearn.linear_model import Ridge\nfrom sklearn.model_selection import KFold\nfrom sklearn.preprocessing import StandardScaler\n\nimport tensorflow as tf\nimport tensorflow_hub as hub\n\n# ===============================\n# PATHS\n# ===============================\n\nBASE_PATH      = \"/kaggle/input/competitions/csiro-biomass\"\nTRAIN_CSV_PATH = os.path.join(BASE_PATH, 'train.csv')\nTEST_CSV_PATH  = os.path.join(BASE_PATH, 'test.csv')\n\nEFFICIENTNET_PATH = \"/kaggle/input/models/tensorflow/efficientnet/tensorflow2/b3-feature-vector/1\"\n\nIMG_SIZE    = 300\nRANDOM_SEED = 999\n\nN_FOLDS         = 5\nN_AUGMENTS      = 10\nN_TEST_AUGMENTS = 5\n\n# ===============================\n# LOAD DATA\n# ===============================\n\ntrain_df = pd.read_csv(TRAIN_CSV_PATH)\ntest_df  = pd.read_csv(TEST_CSV_PATH)\n\ntrain_wide_df = train_df.pivot(\n    index='image_path',\n    columns='target_name',\n    values='target'\n).reset_index()\n\nTARGET_COLS = [c for c in train_wide_df.columns if c != 'image_path']\nprint(\"Targets:\", TARGET_COLS)\nprint(f\"Imágenes de train: {len(train_wide_df)}\")\nprint(f\"Imágenes de test:  {len(test_df['image_path'].unique())}\")\n\n\n# ===============================\n# AUGMENTATION\n# ===============================\n\ndef get_train_transforms():\n    return A.Compose([\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.RandomRotate90(p=0.5),\n        A.GaussNoise(p=0.3),\n        A.RandomBrightnessContrast(\n            brightness_limit=0.2,\n            contrast_limit=0.2,\n            p=0.75\n        ),\n        A.HueSaturationValue(\n            hue_shift_limit=10,\n            sat_shift_limit=20,\n            val_shift_limit=20,\n            p=0.5\n        ),\n        A.CLAHE(clip_limit=2.0, tile_grid_size=(8, 8), p=0.3),\n        A.ColorJitter(\n            brightness=0.2,\n            contrast=0.2,\n            saturation=0.2,\n            hue=0.1,\n            p=0.75\n        ),\n        A.Resize(IMG_SIZE, IMG_SIZE),\n    ], seed=RANDOM_SEED)\n\n\ndef get_test_transforms():\n    return A.Compose([\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.RandomRotate90(p=0.5),\n        A.RandomBrightnessContrast(\n            brightness_limit=0.1,\n            contrast_limit=0.1,\n            p=0.5\n        ),\n        A.HueSaturationValue(\n            hue_shift_limit=5,\n            sat_shift_limit=10,\n            val_shift_limit=10,\n            p=0.3\n        ),\n        A.Resize(IMG_SIZE, IMG_SIZE),\n    ], seed=RANDOM_SEED)\n\ntrain_augment = get_train_transforms()\ntest_augment  = get_test_transforms()\n\n\n# ===============================\n# LOAD EfficientNetB3 FROM LOCAL PATH\n# ===============================\n\nprint(f\"Cargando EfficientNetB3 desde: {EFFICIENTNET_PATH}\")\n\nhub_layer = hub.load(EFFICIENTNET_PATH)\nprint(\"EfficientNetB3 cargado.\")\n\n\ndef load_image_as_array(img_path):\n    img = cv2.imread(img_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    return img\n\n\ndef extract_features(img_array):\n    x = img_array.astype(np.float32) / 255.0\n    x = np.expand_dims(x, axis=0)          # (1, 300, 300, 3)\n    x = tf.constant(x)\n    features = hub_layer(x, training=False) # call directly, no KerasTensor\n    return features.numpy().flatten()\n\n\n# ===============================\n# EXTRACT TRAIN FEATURES\n# ===============================\n\nprint(f\"Extrayendo features de TRAIN con augmentación (×{N_AUGMENTS + 1})...\")\ntrain_features, train_labels = [], []\n\nfor _, row in tqdm(train_wide_df.iterrows(), total=len(train_wide_df)):\n    full_path = os.path.join(BASE_PATH, row['image_path'])\n    img_array = load_image_as_array(full_path)\n    label     = row[TARGET_COLS].values.astype(np.float32)\n\n    # Imagen original\n    train_features.append(extract_features(img_array))\n    train_labels.append(label)\n\n    # Versiones aumentadas\n    for _ in range(N_AUGMENTS):\n        aug_img = train_augment(image=img_array)['image']\n        train_features.append(extract_features(aug_img))\n        train_labels.append(label)\n\ntrain_features = np.array(train_features)\ntrain_labels   = np.array(train_labels)\n\nprint(f\"→ {len(train_wide_df)} imágenes × {N_AUGMENTS + 1} = {train_features.shape[0]} ejemplos totales\")\n\n\n# ===============================\n# NORMALIZAR\n# ===============================\n\nscaler = StandardScaler()\nX_train = scaler.fit_transform(train_features)\ny_train = train_labels\n\n\n# ===============================\n# EXTRACT TEST FEATURES (TTA)\n# ===============================\n\nunique_paths = test_df['image_path'].unique()\nprint(f\"\\nImágenes únicas en test: {len(unique_paths)}\")\nprint(f\"Extrayendo features de TEST con TTA (×{N_TEST_AUGMENTS + 1})...\")\n\ntest_features_list = []\n\nfor img_path in tqdm(unique_paths):\n    full_path = os.path.join(BASE_PATH, img_path)\n    img_array = load_image_as_array(full_path)\n\n    preds_tta = [extract_features(img_array)]\n    for _ in range(N_TEST_AUGMENTS):\n        aug = test_augment(image=img_array)['image']\n        preds_tta.append(extract_features(aug))\n\n    test_features_list.append(np.mean(preds_tta, axis=0))\n\ntest_features = np.array(test_features_list)\nX_test = scaler.transform(test_features)\n\n\n# ===============================\n# MODELO: Solo Ridge\n# ===============================\n\nALPHA_OPTIONS = [0.1, 1.0, 10.0, 100.0]\n\nkf         = KFold(n_splits=N_FOLDS, shuffle=True, random_state=RANDOM_SEED)\noof_preds  = np.zeros_like(y_train)\ntest_preds = np.zeros((X_test.shape[0], len(TARGET_COLS)))\n\nall_models = {}\n\nprint(f\"\\nEntrenando Ridge con {N_FOLDS}-Fold CV...\")\nprint(f\"Probando alphas: {ALPHA_OPTIONS}\\n\")\n\nfor t_idx, target in enumerate(TARGET_COLS):\n    y_t = y_train[:, t_idx]\n    fold_test_preds = np.zeros((N_FOLDS, X_test.shape[0]))\n    target_models   = []\n\n    for fold, (train_idx, val_idx) in enumerate(kf.split(X_train)):\n        X_tr, X_val = X_train[train_idx], X_train[val_idx]\n        y_tr, y_val = y_t[train_idx],     y_t[val_idx]\n\n        best_alpha = ALPHA_OPTIONS[0]\n        best_rmse  = float('inf')\n\n        for alpha in ALPHA_OPTIONS:\n            mdl_tmp = Ridge(alpha=alpha)\n            mdl_tmp.fit(X_tr, y_tr)\n            val_pred = mdl_tmp.predict(X_val)\n            rmse_tmp = np.sqrt(np.mean((val_pred - y_val) ** 2))\n            if rmse_tmp < best_rmse:\n                best_rmse  = rmse_tmp\n                best_alpha = alpha\n\n        best_model = Ridge(alpha=best_alpha)\n        best_model.fit(X_tr, y_tr)\n\n        fold_preds_val  = best_model.predict(X_val)\n        fold_preds_test = best_model.predict(X_test)\n\n        oof_preds[val_idx, t_idx] = fold_preds_val\n        fold_test_preds[fold]     = fold_preds_test\n        target_models.append(best_model)\n\n        rmse = np.sqrt(np.mean((fold_preds_val - y_val) ** 2))\n        print(f\"  {target} | fold {fold+1}/{N_FOLDS} | alpha={best_alpha} | RMSE = {rmse:.4f}\")\n\n    test_preds[:, t_idx] = fold_test_preds.mean(axis=0)\n    all_models[target]   = target_models\n\n\n# ===============================\n# RMSE OOF REPORT\n# ===============================\n\nprint(\"\\n--- RMSE OOF por target ---\")\nfor t_idx, target in enumerate(TARGET_COLS):\n    rmse = np.sqrt(np.mean((oof_preds[:, t_idx] - y_train[:, t_idx]) ** 2))\n    print(f\"  {target}: {rmse:.4f}\")\n\noverall_rmse = np.sqrt(np.mean((oof_preds - y_train) ** 2))\nprint(f\"\\n  RMSE global OOF: {overall_rmse:.4f}\")\n\n\n# ===============================\n# SUBMISSION\n# ===============================\n\ntest_preds = np.clip(test_preds, 0, None)\n\n# Build a DataFrame with predictions per image_path\npredictions_df = pd.DataFrame(test_preds, columns=TARGET_COLS)\npredictions_df['image_path'] = unique_paths\n\n# Melt from wide to long format\npredictions_long_df = predictions_df.melt(\n    id_vars=['image_path'],\n    value_vars=TARGET_COLS,\n    var_name='target_name',\n    value_name='target'\n)\n\n# Merge with test_df to get the correct sample_id\nsubmission_df = pd.merge(\n    test_df[['sample_id', 'image_path', 'target_name']],\n    predictions_long_df,\n    on=['image_path', 'target_name']\n)[['sample_id', 'target']]\n\nsubmission_df.to_csv('submission.csv', index=False)\nprint(\"\\nSubmission creado: submission.csv\")\nprint(submission_df)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-03-21T19:07:29.318770Z","iopub.execute_input":"2026-03-21T19:07:29.319120Z","iopub.status.idle":"2026-03-21T19:09:26.563127Z","shell.execute_reply.started":"2026-03-21T19:07:29.319073Z","shell.execute_reply":"2026-03-21T19:09:26.562496Z"}},"outputs":[],"execution_count":null}]}