{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceType":"competition","sourceId":71549,"databundleVersionId":8561470},{"sourceType":"datasetVersion","sourceId":9571649,"datasetId":5799213,"databundleVersionId":9790901},{"sourceType":"datasetVersion","sourceId":9566702,"datasetId":5799089,"databundleVersionId":9785377}],"dockerImageVersionId":30775,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pandas.api.types\nimport sklearn.metrics\nfrom scipy.optimize import minimize\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-08T04:19:37.588349Z","iopub.execute_input":"2024-10-08T04:19:37.589489Z","iopub.status.idle":"2024-10-08T04:19:38.782298Z","shell.execute_reply.started":"2024-10-08T04:19:37.589404Z","shell.execute_reply":"2024-10-08T04:19:38.781099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ParticipantVisibleError(Exception):\n    pass\n\n\ndef get_condition(full_location: str) -> str:\n    # Given an input like spinal_canal_stenosis_l1_l2 extracts 'spinal'\n    for injury_condition in ['spinal', 'foraminal', 'subarticular']:\n        if injury_condition in full_location:\n            return injury_condition\n    raise ValueError(f'condition not found in {full_location}')\n\n# def get_condition_v2(full_location: str) -> str:\n#     # Given an input like spinal_canal_stenosis_l1_l2 extracts 'spinal'\n#     for injury_condition in ['spinal_canal_stenosis', 'left_neural_foraminal_narrowing', \"right_neural_foraminal_narrowing\", 'left_subarticular_stenosis', \"right_subarticular_stenosis\"]:\n#         if injury_condition in full_location:\n#             return injury_condition\n#     raise ValueError(f'condition not found in {full_location}')\n\ndef score(\n        solution: pd.DataFrame,\n        submission: pd.DataFrame,\n        row_id_column_name: str,\n        any_severe_scalar: float\n    ) -> float:\n    '''\n    Pseudocode:\n    1. Calculate the sample weighted log loss for each medical condition:\n    2. Derive a new any_severe label.\n    3. Calculate the sample weighted log loss for the new any_severe label.\n    4. Return the average of all of the label group log losses as the final score, normalized for the number of columns in each group.\n       This mitigates the impact of spinal stenosis having only half as many columns as the other two conditions.\n    '''\n\n    target_levels = ['normal_mild', 'moderate', 'severe']\n\n    # Run basic QC checks on the inputs\n    if not pandas.api.types.is_numeric_dtype(submission[target_levels].values):\n        raise ParticipantVisibleError('All submission values must be numeric')\n\n    if not np.isfinite(submission[target_levels].values).all():\n        raise ParticipantVisibleError('All submission values must be finite')\n\n    if solution[target_levels].min().min() < 0:\n        raise ParticipantVisibleError('All labels must be at least zero')\n    if submission[target_levels].min().min() < 0:\n        raise ParticipantVisibleError('All predictions must be at least zero')\n\n    solution['study_id'] = solution['row_id'].apply(lambda x: x.split('_')[0])\n    solution['location'] = solution['row_id'].apply(lambda x: '_'.join(x.split('_')[1:]))\n    solution['condition'] = solution['row_id'].apply(get_condition)\n\n    del solution[row_id_column_name]\n    del submission[row_id_column_name]\n    assert sorted(submission.columns) == sorted(target_levels)\n\n    submission['study_id'] = solution['study_id']\n    submission['location'] = solution['location']\n    submission['condition'] = solution['condition']\n\n    # condition_losses = []\n    # condition_weights = []\n    # for condition in ['spinal', 'foraminal', 'subarticular']:\n    #     condition_indices = solution.loc[solution['condition'] == condition].index.values\n    #     condition_loss = sklearn.metrics.log_loss(\n    #         y_true=solution.loc[condition_indices, target_levels].values,\n    #         y_pred=submission.loc[condition_indices, target_levels].values,\n    #         sample_weight=solution.loc[condition_indices, 'sample_weight'].values\n    #     )\n    #     condition_losses.append(condition_loss)\n    #     condition_weights.append(1)\n\n    condition_losses = {}\n    condition_weights = {}\n    for condition in ['spinal', 'foraminal', 'subarticular']:\n        condition_indices = solution.loc[solution['condition'] == condition].index.values\n        condition_loss = sklearn.metrics.log_loss(\n            y_true=solution.loc[condition_indices, target_levels].values,\n            y_pred=submission.loc[condition_indices, target_levels].values,\n            sample_weight=solution.loc[condition_indices, 'sample_weight'].values\n        )\n        condition_losses[condition] = condition_loss\n        condition_weights[condition] = 1\n\n    any_severe_spinal_labels = pd.Series(solution.loc[solution['condition'] == 'spinal'].groupby('study_id')['severe'].max())\n    any_severe_spinal_weights = pd.Series(solution.loc[solution['condition'] == 'spinal'].groupby('study_id')['sample_weight'].max())\n    any_severe_spinal_predictions = pd.Series(submission.loc[submission['condition'] == 'spinal'].groupby('study_id')['severe'].max())\n    any_severe_spinal_loss = sklearn.metrics.log_loss(\n        y_true=any_severe_spinal_labels,\n        y_pred=any_severe_spinal_predictions,\n        sample_weight=any_severe_spinal_weights\n    )\n    condition_losses[\"any\"]=any_severe_spinal_loss\n    condition_weights[\"any\"] = any_severe_scalar\n    return np.average(np.asarray(list(condition_losses.values())), weights=np.asarray(list(condition_weights.values()))), condition_losses","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:38.784830Z","iopub.execute_input":"2024-10-08T04:19:38.785554Z","iopub.status.idle":"2024-10-08T04:19:38.807345Z","shell.execute_reply.started":"2024-10-08T04:19:38.785496Z","shell.execute_reply":"2024-10-08T04:19:38.805954Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\n\ntrain_df = pd.read_csv(\n    \"../input/rsna-2024-lumbar-spine-degenerative-classification/train.csv\"\n)\ntrain_df[\"fold_id\"] = -1\nfor i, (train_index, valid_index) in enumerate(\n    GroupKFold(n_splits=5).split(\n        train_df, np.arange(len(train_df)), train_df.study_id\n    )\n):\n    train_df.loc[valid_index, \"fold_id\"] = i\n\ntrain_main = pd.read_csv(\"../input/rsna-2024-lumbar-spine-degenerative-classification/train.csv\")\nsolution = train_main.melt(id_vars=[\"study_id\"], var_name=\"full_label\", value_name=\"severity\")\nsolution[\"row_id\"] = solution.apply(lambda row: str(row.study_id) + \"_\" + row.full_label, axis=1)\nsolution.severity = solution.severity.fillna(\"Normal/Mild\")\nsolution.loc[solution.severity == \"Normal/Mild\", \"normal_mild\"] = 1\nsolution.loc[solution.severity == \"Moderate\", \"moderate\"] = 1\nsolution.loc[solution.severity == \"Severe\", \"severe\"] = 1\n\nsolution.loc[solution.severity == \"Normal/Mild\", \"sample_weight\"] = 1\nsolution.loc[solution.severity == \"Moderate\", \"sample_weight\"] = 2\nsolution.loc[solution.severity == \"Severe\", \"sample_weight\"] = 4\n\nsolution = solution[[\"study_id\", \"row_id\", \"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]]\nsolution = solution.fillna(0)\nsolution = solution.sort_values(\"row_id\", ascending=True).reset_index(drop=True).copy()\n\nsolution = solution.merge(train_df[[\"study_id\", \"fold_id\"]], on=\"study_id\")\nsolution['location'] = solution['row_id'].apply(lambda x: '_'.join(x.split('_')[-2:]))\nsolution['condition'] = solution['row_id'].apply(get_condition)\nsolution.head()","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:38.808863Z","iopub.execute_input":"2024-10-08T04:19:38.809308Z","iopub.status.idle":"2024-10-08T04:19:40.903757Z","shell.execute_reply.started":"2024-10-08T04:19:38.809258Z","shell.execute_reply":"2024-10-08T04:19:40.902559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tattaka_submissions = [\n    pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp076/eval_caformer_s18_ax5ch_mask0.1.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp076/eval_resnetrs50_ax5ch_mask0.1.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp076/eval_swinv2_tiny_ax5ch_mask0.1.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp107/eval_rdnet_tiny_ax5ch_mask0.1.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp107/eval_maxxvitv2_nano_ax5ch_mask0.1.csv\"),\n#     pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp108/eval_rdnet_tiny_ax5ch_mask0.1.csv\"),\n#     pd.read_csv(\"/kaggle/input/rsna2024-oof-tattaka/exp108/eval_maxxvitv2_nano_ax5ch_mask0.1.csv\"),\n]\n\nyu4u_submissions_st1 = [\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal1_baseline_submission.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal1_s1_swint_submission.csv\"),\n]\nyu4u_submissions_st2 = [\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_baseline_submission.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_swint_submission.csv\"),\n    # pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_v2_submission.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_axial_submission.csv\"),\n    # pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_v2swint_submission.csv\"),\n    # pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_sagittal2_v2l_128_submission.csv\"),\n#     pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_stacking_submission.csv\"),\n]\nyu4u_submissions_ax = [\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_axial_baseline_submission.csv\"),\n    pd.read_csv(\"/kaggle/input/rsna2024-yu4u-oof/yu4u_axial_swint_submission.csv\"),\n]","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:40.907087Z","iopub.execute_input":"2024-10-08T04:19:40.908108Z","iopub.status.idle":"2024-10-08T04:19:41.984215Z","shell.execute_reply.started":"2024-10-08T04:19:40.908048Z","shell.execute_reply":"2024-10-08T04:19:41.982904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tattaka_submissions[0]","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:41.985939Z","iopub.execute_input":"2024-10-08T04:19:41.986419Z","iopub.status.idle":"2024-10-08T04:19:42.002219Z","shell.execute_reply.started":"2024-10-08T04:19:41.986375Z","shell.execute_reply":"2024-10-08T04:19:42.000953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def logloss(final_preds, gt, sample_weight):\n    condition_loss = sklearn.metrics.log_loss(\n        y_true=gt,\n        y_pred=final_preds,\n        sample_weight=sample_weight,\n    )\n    return condition_loss\n\ndef loss_fn(weights):\n    final_preds = 0\n    weights = np.array(weights) / np.sum(weights)\n    for weight, pred in zip(weights, preds):\n        final_preds += weight*pred\n    final_preds /= (final_preds.sum(1, keepdims=True) + 1e-6)\n    score = logloss(final_preds, gt[:, :3], gt[:, -1])\n    return score","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:42.003914Z","iopub.execute_input":"2024-10-08T04:19:42.004409Z","iopub.status.idle":"2024-10-08T04:19:42.024878Z","shell.execute_reply.started":"2024-10-08T04:19:42.004348Z","shell.execute_reply":"2024-10-08T04:19:42.023537Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# NFN nelder-mead","metadata":{}},{"cell_type":"code","source":"gt = solution[solution.condition == \"foraminal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values\ntattaka_preds = [p[solution.condition == \"foraminal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for p in tattaka_submissions]\nyu4u_preds = [tattaka_submissions[0][solution.condition == \"foraminal\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for ys in yu4u_submissions_st1]\npreds = np.stack(tattaka_preds + yu4u_preds, 0)\nstarting_weights = [1/len(preds)] * len(preds)\n\nconstraints = ({'type': 'eq', 'fun': lambda w: 1-sum(w)})\nbounds = [(0, 1)] * (len(preds))\nres = minimize(loss_fn, starting_weights, method='Nelder-Mead', bounds=bounds, constraints=constraints)\n\nnm_weight_foraminal = res['x'] / np.sum(res['x'])\nprint(f\"foraminal score: {round(res['fun'], 5)}, weight: {nm_weight_foraminal}, weight_len: {len(nm_weight_foraminal)}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:42.026601Z","iopub.execute_input":"2024-10-08T04:19:42.027013Z","iopub.status.idle":"2024-10-08T04:19:56.740976Z","shell.execute_reply.started":"2024-10-08T04:19:42.026943Z","shell.execute_reply":"2024-10-08T04:19:56.739795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# SS nelder-mead","metadata":{}},{"cell_type":"code","source":"gt = solution[solution.condition == \"subarticular\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values\ntattaka_preds = [p[solution.condition == \"subarticular\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for p in tattaka_submissions]\nyu4u_preds = [tattaka_submissions[0][solution.condition == \"subarticular\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for ys in yu4u_submissions_ax]\npreds = np.stack(tattaka_preds + yu4u_preds, 0)\nstarting_weights = [1/len(preds)] * len(preds)\n\nconstraints = ({'type': 'eq', 'fun': lambda w: 1-sum(w)})\nbounds = [(0, 1)] * (len(preds))\nres = minimize(loss_fn, starting_weights, method='Nelder-Mead', bounds=bounds, constraints=constraints)\n\nnm_weight_subarticular = res['x'] / np.sum(res['x'])\nprint(f\"ss score: {round(res['fun'], 5)}, weight: {nm_weight_subarticular}, weight_len: {len(nm_weight_subarticular)}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:19:56.742796Z","iopub.execute_input":"2024-10-08T04:19:56.743288Z","iopub.status.idle":"2024-10-08T04:20:00.973808Z","shell.execute_reply.started":"2024-10-08T04:19:56.743232Z","shell.execute_reply":"2024-10-08T04:20:00.972662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# SCS nelder-mead","metadata":{}},{"cell_type":"code","source":"def loss_fn_scs(weights):\n    final_preds = 0\n    weights = np.array(weights) / np.sum(weights)\n    for weight, pred in zip(weights, preds):\n        final_preds += weight*pred\n    score1 = logloss(final_preds, gt[:, :3], gt[:, -1])\n    final_preds_any = final_preds.reshape(-1, 5, 3)[:, :, 2].max(1)\n    gt_any = gt.reshape(-1, 5, 4)[:, :, 2].max(1)\n    weight_any = gt[:, -1].reshape(-1, 5).max(1)\n    score2 = logloss(final_preds_any, gt_any, weight_any)\n    return score1 + score2","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:00.975231Z","iopub.execute_input":"2024-10-08T04:20:00.975640Z","iopub.status.idle":"2024-10-08T04:20:00.984568Z","shell.execute_reply.started":"2024-10-08T04:20:00.975597Z","shell.execute_reply":"2024-10-08T04:20:00.983128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gt = solution[solution.condition == \"spinal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values\ntattaka_preds = [p[solution.condition == \"spinal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for p in tattaka_submissions]\nyu4u_preds = [tattaka_submissions[0][solution.condition == \"spinal\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values for ys in yu4u_submissions_st2]\npreds = np.stack(tattaka_preds + yu4u_preds, 0)\nstarting_weights = [1/len(preds)] * len(preds)\n\nconstraints = ({'type': 'eq', 'fun': lambda w: 1-sum(w)})\nbounds = [(0, 1)] * (len(preds))\nres = minimize(loss_fn_scs, starting_weights, method='Nelder-Mead', bounds=bounds, constraints=constraints)\n\nweights = res['x'] / np.sum(res['x'])\n\nfinal_preds = 0\nnm_weight_spinal = np.array(weights) / np.sum(weights)\nfor weight, pred in zip(nm_weight_spinal, preds):\n    final_preds += weight * pred\nscore1 = logloss(final_preds, gt[:, :3], gt[:, -1])\nfinal_preds_any = final_preds.reshape(-1, 5, 3)[:, :, 2].max(1)\ngt_any = gt.reshape(-1, 5, 4)[:, :, 2].max(1)\nweight_any = gt[:, -1].reshape(-1, 5).max(1)\nscore2 = logloss(final_preds_any, gt_any, weight_any)\n\nprint(f\"scs score: {round(score1, 5)}, any score: {round(score2, 5)}, weight: {nm_weight_spinal}, weight_len: {len(nm_weight_spinal)}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:00.989476Z","iopub.execute_input":"2024-10-08T04:20:00.989924Z","iopub.status.idle":"2024-10-08T04:20:04.670359Z","shell.execute_reply.started":"2024-10-08T04:20:00.989866Z","shell.execute_reply":"2024-10-08T04:20:04.669003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Stacking","metadata":{}},{"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset\nfrom torch.optim import AdamW\nfrom sklearn.model_selection import GroupKFold\nfrom pytorch_lightning import LightningDataModule, callbacks\nfrom torch import nn\nfrom torch.nn import functional as F\nimport torch\nimport sklearn\nimport pytorch_lightning as pl\nfrom torch.nn.modules.loss import _Loss\nimport math\nfrom pytorch_lightning.utilities import rank_zero_info\nfrom transformers import get_cosine_schedule_with_warmup\nfrom glob import glob","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:04.671851Z","iopub.execute_input":"2024-10-08T04:20:04.672291Z","iopub.status.idle":"2024-10-08T04:20:12.476861Z","shell.execute_reply.started":"2024-10-08T04:20:04.672249Z","shell.execute_reply":"2024-10-08T04:20:12.475569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fold_ids = solution.groupby(\"study_id\").head(1).fold_id.values\nfold_ids","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:12.478759Z","iopub.execute_input":"2024-10-08T04:20:12.479673Z","iopub.status.idle":"2024-10-08T04:20:12.498299Z","shell.execute_reply.started":"2024-10-08T04:20:12.479604Z","shell.execute_reply":"2024-10-08T04:20:12.496783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gt_foraminal = solution[solution.condition == \"foraminal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values.reshape(-1, 10, 4)\ngt_spinal = solution[solution.condition == \"spinal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values.reshape(-1, 5, 4)\ngt_subarticular = solution[solution.condition == \"subarticular\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\", \"sample_weight\"]].values.reshape(-1, 10, 4)\ngt = np.concatenate([gt_foraminal, gt_spinal, gt_subarticular], -2)\n\ngt_foraminal.shape, gt_spinal.shape, gt_subarticular.shape, gt.shape\n# (level1 + level2, level3, level4 + level5)","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:12.500074Z","iopub.execute_input":"2024-10-08T04:20:12.500628Z","iopub.status.idle":"2024-10-08T04:20:12.561642Z","shell.execute_reply.started":"2024-10-08T04:20:12.500568Z","shell.execute_reply":"2024-10-08T04:20:12.560316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tattaka_preds_foraminal = [p[solution.condition == \"foraminal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 10, 3) for p in tattaka_submissions]\nyu4u_preds_foraminal = [tattaka_submissions[0][solution.condition == \"foraminal\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 10, 3) for ys in yu4u_submissions_st1]\npreds_foraminal = np.stack(tattaka_preds_foraminal + yu4u_preds_foraminal, 0).transpose((1, 0, 2, 3))\n\ntattaka_preds_spinal = [p[solution.condition == \"spinal\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 5, 3) for p in tattaka_submissions]\nyu4u_preds_spinal = [tattaka_submissions[0][solution.condition == \"spinal\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 5, 3) for ys in yu4u_submissions_st2]\npreds_spinal = np.stack(tattaka_preds_spinal + yu4u_preds_spinal, 0).transpose((1, 0, 2, 3))\n\ntattaka_preds_subarticular = [p[solution.condition == \"subarticular\"].loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 10, 3) for p in tattaka_submissions]\nyu4u_preds_subarticular= [tattaka_submissions[0][solution.condition == \"subarticular\"].rename(columns={\"normal_mild\": \"normal_mild_tmp\", \"moderate\": \"moderate_tmp\", \"severe\": \"severe_tmp\"}).merge(ys, on=\"row_id\", how=\"left\").drop([\"normal_mild_tmp\", \"moderate_tmp\", \"severe_tmp\"],axis='columns').fillna(0).loc[:, [\"normal_mild\", \"moderate\", \"severe\"]].values.reshape(-1, 10, 3) for ys in yu4u_submissions_ax]\npreds_subarticular = np.stack(tattaka_preds_subarticular + yu4u_preds_subarticular, 0).transpose((1, 0, 2, 3))\n\n# preds = np.concatenate([preds_foraminal, preds_spinal, preds_subarticular], -2).transpose((1, 0, 2, 3))\n\npreds_foraminal.shape, preds_spinal.shape, preds_subarticular.shape\n","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:12.563589Z","iopub.execute_input":"2024-10-08T04:20:12.564005Z","iopub.status.idle":"2024-10-08T04:20:13.028863Z","shell.execute_reply.started":"2024-10-08T04:20:12.563964Z","shell.execute_reply":"2024-10-08T04:20:13.027556Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class StackingDataset(Dataset):\n    def __init__(\n        self,\n        preds_foraminal: np.ndarray,\n        preds_spinal: np.ndarray,\n        preds_subarticular: np.ndarray,\n        gt: np.ndarray, \n    ):\n        self.preds_foraminal = preds_foraminal\n        self.preds_spinal = preds_spinal\n        self.preds_subarticular = preds_subarticular\n        self.gt = gt\n        \n    def __len__(self) -> int:\n        return len(self.preds_foraminal)\n    \n    def __getitem__(self, idx: int):\n        preds_foraminal = self.preds_foraminal[idx] # (num_models, 10, 3)\n        preds_spinal = self.preds_spinal[idx] # (num_models, 5, 3)\n        preds_subarticular = self.preds_subarticular[idx] # (num_models, 10, 3)\n        gt = self.gt[idx][..., :3] # (25, 3)\n        sample_weights = self.gt[idx][..., -1] # (25)\n        \n        return {\n            \"preds_foraminal\": torch.tensor(preds_foraminal).float(),\n            \"preds_spinal\": torch.tensor(preds_spinal).float(),\n            \"preds_subarticular\": torch.tensor(preds_subarticular).float(),\n            \"gt\": torch.tensor(gt).float(), \n            \"sample_weights\": torch.tensor(sample_weights).float()\n        }\n    \n    \nclass StackingDataModule(LightningDataModule):\n    def __init__(\n        self,\n        train_preds_foraminal: np.ndarray,\n        train_preds_spinal: np.ndarray,\n        train_preds_subarticular: np.ndarray,\n        train_gt: np.ndarray, \n        valid_preds_foraminal: np.ndarray,\n        valid_preds_spinal: np.ndarray,\n        valid_preds_subarticular: np.ndarray,\n        valid_gt: np.ndarray, \n        num_workers: int = 2,\n        batch_size: int = 64,\n    ):\n        super().__init__()\n        self.train_preds_foraminal = train_preds_foraminal\n        self.train_preds_spinal = train_preds_spinal\n        self.train_preds_subarticular = train_preds_subarticular\n        self.train_gt = train_gt\n        self.valid_preds_foraminal = valid_preds_foraminal\n        self.valid_preds_spinal = valid_preds_spinal\n        self.valid_preds_subarticular = valid_preds_subarticular\n        self.valid_gt = valid_gt\n        self.save_hyperparameters(\n            ignore=[\n                \"train_preds_foraminal\", \n                \"train_preds_spinal\", \n                \"train_preds_subarticular\", \n                \"train_gt\", \n                \"valid_preds_foraminal\", \n                \"valid_preds_spinal\", \n                \"valid_preds_subarticular\", \n                \"valid_gt\"\n            ]\n        )\n        \n    def create_dataset(self, mode: str = \"train\") -> StackingDataset:\n        if mode == \"train\":\n            return StackingDataset(\n                preds_foraminal=self.train_preds_foraminal,\n                preds_spinal=self.train_preds_spinal,\n                preds_subarticular=self.train_preds_subarticular,\n                gt=self.train_gt,\n            )\n        else:\n            return StackingDataset(\n                preds_foraminal=self.valid_preds_foraminal,\n                preds_spinal=self.valid_preds_spinal,\n                preds_subarticular=self.valid_preds_subarticular,\n                gt=self.valid_gt,\n            )\n    \n    def __dataloader(self, mode: str = \"train\") -> DataLoader:\n        \"\"\"Train/validation loaders.\"\"\"\n        dataset = self.create_dataset(mode)\n        return DataLoader(\n            dataset=dataset,\n            batch_size=self.hparams.batch_size,\n            num_workers=self.hparams.num_workers,\n            shuffle=(mode == \"train\"),\n            drop_last=(mode == \"train\"),\n            pin_memory=True,\n        )\n\n    def train_dataloader(self) -> DataLoader:\n        return self.__dataloader(mode=\"train\")\n\n    def val_dataloader(self) -> DataLoader:\n        return self.__dataloader(mode=\"valid\")\n\n    def test_dataloader(self) -> DataLoader:\n        return self.__dataloader(mode=\"test\")\n    \n        ","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:13.030886Z","iopub.execute_input":"2024-10-08T04:20:13.031315Z","iopub.status.idle":"2024-10-08T04:20:13.054888Z","shell.execute_reply.started":"2024-10-08T04:20:13.031264Z","shell.execute_reply":"2024-10-08T04:20:13.053402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Custom Loss for this competition\n\nclass SevereLoss(_Loss):\n    \"\"\"\n    For RSNA 2024\n    criterion = SevereLoss()     # you can replace nn.CrossEntropyLoss\n    loss = criterion(y_pred, y)\n    \"\"\"\n    def __init__(self, temperature=1.0):\n        \"\"\"\n        Use max if temperature = 0\n        \"\"\"\n        super().__init__()\n        self.t = temperature\n        assert self.t >= 0\n        self.ce_loss = nn.CrossEntropyLoss(\n            weight=torch.tensor([1.0, 2.0, 4.0], dtype=torch.float), reduction=\"none\"\n        )\n        self.bce_loss = nn.BCELoss(reduction=\"none\")\n    \n    def __repr__(self):\n        return 'SevereLoss(t=%.1f)' % self.t\n\n    def forward(self, y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor:\n        # y_pred: (bs, 25, 3)\n        # y: (bs, 25)\n        y_ce = y.argmax(-1).long()\n        weights = torch.ones(y.shape[1], dtype=y_pred.dtype, device=y_pred.device)[None, :].repeat(y_pred.shape[0], 1)\n        weights[:, :10] = 0.5\n        weights[:, -10:] = 0.5\n        weights = weights.reshape(-1)\n#         print(y_pred.reshape(-1, 3).shape, y.reshape(-1).shape, weights.shape)\n        loss = (self.ce_loss(y_pred.reshape(-1, 3), y_ce.reshape(-1)) * weights).sum() / weights.sum()\n        \n        w_tmp = [1.0, 2.0, 4.0]\n        any_weights = torch.tensor([w_tmp[yi] for yi in y_ce[:, 10:15].amax(1)], dtype=y.dtype, device=y.device)\n        y_pred_softmax = y_pred.softmax(-1)\n        any_loss = (self.bce_loss(y_pred_softmax[:, 10:15, -1].amax(1), y[:, 10:15, -1].amax(1).float()) * any_weights).sum() / any_weights.sum()\n        \n        loss = (loss * 3 + any_loss) / 4\n        return loss","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:13.056627Z","iopub.execute_input":"2024-10-08T04:20:13.057126Z","iopub.status.idle":"2024-10-08T04:20:13.075794Z","shell.execute_reply.started":"2024-10-08T04:20:13.057068Z","shell.execute_reply":"2024-10-08T04:20:13.074531Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MLPBlock(nn.Module):\n    def __init__(self, in_dim, mid_dim, dropout_p):\n        super().__init__()\n        self.linear1 = nn.Linear(in_dim, mid_dim)\n        self.act1 = nn.GELU()\n        self.dropout = nn.Dropout(dropout_p)\n        self.linear2 = nn.Linear(mid_dim, in_dim)\n        self.act2 = nn.GELU()\n    \n    def forward(self, x):\n        return x + self.act2(self.linear2(self.dropout(self.act1(self.linear1(x)))))\n\nclass StackingModel(nn.Module):\n    def __init__(\n        self,\n        weight_foraminal,\n        weight_spinal,\n        weight_subarticular,\n    ):\n        super().__init__()\n        weight_foraminal = torch.tensor(weight_foraminal)[None, :, None, None].repeat(1,  1, 10, 1)\n        weight_spinal = torch.tensor(weight_spinal)[None, :, None, None].repeat(1,  1, 5, 1)\n        weight_subarticular = torch.tensor(weight_subarticular)[None, :, None, None].repeat(1,  1, 10, 1)\n        self.register_buffer('nm_weight_foraminal', weight_foraminal)\n        self.register_buffer('nm_weight_spinal', weight_spinal)\n        self.register_buffer('nm_weight_subarticular', weight_subarticular)\n                \n#         in_chans_nfn = nm_weight_foraminal.shape[0] * 10 * 3\n        in_chans_nfn = nm_weight_foraminal.shape[0] * 10 * 3 + nm_weight_spinal.shape[0] * 5 * 3 + nm_weight_subarticular.shape[0] * 10 * 3\n        self.mlps_nfn = nn.Sequential(\n            MLPBlock(in_chans_nfn, 512, 0.3),\n#             MLPBlock(in_chans_nfn, 512, 0.3),\n#             MLPBlock(in_chans_nfn, 512, 0.3),\n#             MLPBlock(in_chans_nfn, 512, 0.3),\n            nn.Linear(in_chans_nfn, 10 * 3)\n        )\n\n#         in_chans_scs = nm_weight_spinal.shape[0] * 5 * 3\n#         self.mlps_scs = nn.Sequential(\n#             MLPBlock(in_chans_scs, 512, 0.3),\n#             MLPBlock(in_chans_scs, 512, 0.3),\n#             MLPBlock(in_chans_scs, 512, 0.3),\n#             MLPBlock(in_chans_scs, 512, 0.3),\n#             nn.Linear(in_chans_scs, 5 * 3)\n#         )\n        \n#         in_chans_ss = nm_weight_subarticular.shape[0] * 10 * 3\n#         self.mlps_ss = nn.Sequential(\n#             MLPBlock(in_chans_ss, 512, 0.3),\n#             MLPBlock(in_chans_ss, 512, 0.3),\n#             MLPBlock(in_chans_ss, 512, 0.3),\n#             MLPBlock(in_chans_ss, 512, 0.3),\n#             nn.Linear(in_chans_ss, 10 * 3)\n#         )\n        \n        \n    def forward(self, x_foraminal, x_spinal, x_subarticular):\n        bs = x_foraminal.shape[0]\n        nm_x_foraminal = (x_foraminal * self.nm_weight_foraminal).sum(1) # (bs, 10, 3)\n        nm_x_spinal = (x_spinal * self.nm_weight_spinal).sum(1) # (bs, 5, 3)\n        nm_x_subarticular = (x_subarticular * self.nm_weight_subarticular).sum(1) # (bs, 5, 3)\n        nm_x = torch.log(torch.cat([nm_x_foraminal, nm_x_spinal, nm_x_subarticular], 1))\n        \n#         x_foraminal = self.mlps_nfn(x_foraminal.reshape(bs, -1)).reshape((bs, 10, 3))\n        x_foraminal = self.mlps_nfn(torch.cat([x_foraminal.reshape(bs, -1), x_spinal.reshape(bs, -1), x_subarticular.reshape(bs, -1)], -1)).reshape((bs, 10, 3))\n#         x_spinal = self.mlps_scs(x_spinal.reshape(bs, -1)).reshape((bs, 5, 3))\n#         x_subarticular = self.mlps_ss(x_subarticular.reshape(bs, -1)).reshape((bs, 10, 3))\n                \n        x = nm_x.clone()\n#         x += torch.cat([x_foraminal, x_spinal, x_subarticular], 1)\n        x[:, :10] += x_foraminal\n#         x[:, 10:15] += x_spinal\n#         x[:, 15:] += x_subarticular\n        return {\"logit\": x.float(), \"logit_debug\": nm_x.float()}\n    \n\nclass StackingLightningModel(pl.LightningModule):\n    def __init__(\n        self,\n        weight_foraminal=None,\n        weight_spinal=None,\n        weight_subarticular=None,\n        lr: float = 1e-3,\n        weight_decay: float = 1e-2,\n    ) -> None:\n        super().__init__()\n        self.save_hyperparameters()\n        self.__build_model(\n        )\n        self.gt_val = []\n        self.logit_val = []\n    \n    def __build_model(\n        self,\n    ):\n        self.model = StackingModel(\n            self.hparams.weight_foraminal,\n            self.hparams.weight_spinal,\n            self.hparams.weight_subarticular,\n        )\n        self.criterion = SevereLoss()\n    \n    def calc_loss(self, outputs: torch.Tensor, labels: torch.Tensor):\n        losses = {}\n        losses[\"loss\"] = self.criterion(outputs[\"logit\"], labels[\"label\"])\n        losses[\"loss_debug\"] = self.criterion(outputs[\"logit_debug\"], labels[\"label\"])\n        return losses\n    \n    def training_step(self, batch, batch_idx):\n        step_output = {}\n        outputs = {}\n        loss_target = {}\n        (\n            preds_foraminal,\n            preds_spinal,\n            preds_subarticular,\n            label,\n        ) = (\n            batch[\"preds_foraminal\"],\n            batch[\"preds_spinal\"],\n            batch[\"preds_subarticular\"],\n            batch[\"gt\"],\n        )\n        outputs.update(self.model(preds_foraminal, preds_spinal, preds_subarticular))\n        loss_target[\"label\"] = label\n        losses = self.calc_loss(outputs, loss_target)\n        step_output.update(losses)\n        loss_dict = {}\n        for key in losses:\n            if key == \"loss\":\n                loss_dict[\"train_loss\"] = losses[key]\n            else:\n                loss_dict[f\"train_{key}_loss\"] = losses[key]\n        self.log_dict(\n            loss_dict,\n            sync_dist=True,\n        )\n        return step_output\n    \n    def validation_step(self, batch, batch_idx):\n        step_output = {}\n        outputs = {}\n        loss_target = {}\n        (\n            preds_foraminal,\n            preds_spinal,\n            preds_subarticular,\n            label,\n        ) = (\n            batch[\"preds_foraminal\"],\n            batch[\"preds_spinal\"],\n            batch[\"preds_subarticular\"],\n            batch[\"gt\"],\n        )\n        outputs.update(self.model(preds_foraminal, preds_spinal, preds_subarticular))\n        loss_target[\"label\"] = label\n        losses = self.calc_loss(outputs, loss_target)\n        logit = (\n            torch.softmax(outputs[\"logit\"], -1).detach().cpu().numpy()\n        )  # (bs, 25, 3)\n        self.logit_val.append(logit)\n        self.gt_val.append(label.detach().cpu().numpy())\n        \n        step_output.update(losses)\n\n        loss_dict = {}\n        for key in losses:\n            if key == \"loss\":\n                loss_dict[\"val_loss\"] = losses[key]\n            else:\n                loss_dict[f\"val_{key}_loss\"] = losses[key]\n        self.log_dict(\n            loss_dict,\n            sync_dist=True,\n        )\n        return step_output\n    \n    def get_optimizer_parameters(self):\n        no_decay = [\"bias\", \"gamma\", \"beta\"]\n        optimizer_parameters = [\n            {\n                \"params\": [\n                    p\n                    for n, p in list(self.model.named_parameters())\n                    if any(nd in n for nd in no_decay)\n                ],\n                \"weight_decay\": 0,\n                \"lr\": self.hparams.lr,\n            },\n            {\n                \"params\": [\n                    p\n                    for n, p in list(self.model.named_parameters())\n                    if not any(nd in n for nd in no_decay)\n                ],\n                \"weight_decay\": self.hparams.weight_decay,\n                \"lr\": self.hparams.lr,\n            },\n        ]\n        return optimizer_parameters\n    \n    def configure_optimizers(self):\n        self.warmup = True\n        eps = 1e-8 if self.trainer.precision == \"32-true\" else 1e-6\n        optimizer = AdamW(self.get_optimizer_parameters(), eps=eps)\n        max_train_steps = self.trainer.estimated_stepping_batches\n        warmup_steps = math.ceil(max_train_steps / 50) if self.warmup else 0\n        rank_zero_info(\n            f\"max_train_steps: {max_train_steps}, warmup_steps: {warmup_steps}\"\n        )\n        scheduler = get_cosine_schedule_with_warmup(\n            optimizer,\n            num_warmup_steps=warmup_steps,\n            num_training_steps=max_train_steps,\n        )\n        scheduler = {\n            \"scheduler\": scheduler,\n            \"interval\": \"step\",\n            \"frequency\": 1,\n        }\n        return [optimizer], [scheduler]\n    ","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:13.077635Z","iopub.execute_input":"2024-10-08T04:20:13.078066Z","iopub.status.idle":"2024-10-08T04:20:13.121056Z","shell.execute_reply.started":"2024-10-08T04:20:13.078023Z","shell.execute_reply":"2024-10-08T04:20:13.119814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gt.shape","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:13.122593Z","iopub.execute_input":"2024-10-08T04:20:13.122971Z","iopub.status.idle":"2024-10-08T04:20:13.139837Z","shell.execute_reply.started":"2024-10-08T04:20:13.122932Z","shell.execute_reply":"2024-10-08T04:20:13.138555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\npl.seed_everything(42, workers=True)\nfor fold in range(5):\n    train_preds_foraminal = preds_foraminal[fold_ids != fold]\n    train_preds_spinal = preds_spinal[fold_ids != fold]\n    train_preds_subarticular = preds_subarticular[fold_ids != fold]\n    valid_preds_foraminal = preds_foraminal[fold_ids == fold]\n    valid_preds_spinal = preds_spinal[fold_ids == fold]\n    valid_preds_subarticular = preds_subarticular[fold_ids == fold]\n    train_gt = gt[fold_ids != fold]\n    valid_gt = gt[fold_ids == fold]\n    datamodule = StackingDataModule(\n        train_preds_foraminal=train_preds_foraminal,\n        train_preds_spinal=train_preds_spinal,\n        train_preds_subarticular=train_preds_subarticular,\n        train_gt=train_gt,\n        valid_preds_foraminal=valid_preds_foraminal,\n        valid_preds_spinal=valid_preds_spinal,\n        valid_preds_subarticular=valid_preds_subarticular,\n        valid_gt=valid_gt,\n        num_workers=2,\n        batch_size=64,\n    )\n    model = StackingLightningModel(\n        weight_foraminal=nm_weight_foraminal,\n        weight_spinal=nm_weight_spinal,\n        weight_subarticular=nm_weight_subarticular,\n        lr=1e-4,\n        weight_decay=1e-4,\n    )\n    logdir = f\"/kaggle/working/stacing_models/fold{fold}\"\n    print(f\"logdir = {logdir}\")\n    lr_monitor = callbacks.LearningRateMonitor()\n    loss_checkpoint = callbacks.ModelCheckpoint(\n        filename=\"best_loss\",\n        monitor=\"val_loss\",\n        save_top_k=1,\n        save_last=True,\n        save_weights_only=True,\n        mode=\"min\",\n    )\n    early_stopping = callbacks.EarlyStopping(\n        monitor=\"val_loss\", patience=10, log_rank_zero_only=True\n    )\n    trainer = pl.Trainer(\n        default_root_dir=logdir,\n        sync_batchnorm=True,\n        gradient_clip_val=1.0,\n        accelerator=\"auto\",\n        max_epochs=50,\n        callbacks=[\n            loss_checkpoint,\n            lr_monitor,\n            early_stopping,\n        ],\n        fast_dev_run=False,\n        num_sanity_val_steps=0,\n    )\n    trainer.fit(model, datamodule=datamodule)\n    trainer.validate(model, datamodule=datamodule)","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:20:13.141692Z","iopub.execute_input":"2024-10-08T04:20:13.142197Z","iopub.status.idle":"2024-10-08T04:21:48.961873Z","shell.execute_reply.started":"2024-10-08T04:20:13.142150Z","shell.execute_reply":"2024-10-08T04:21:48.960573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"oof = []\noof_nelder_mead = []\nfor fold in range(5):\n    valid_preds_foraminal = preds_foraminal[fold_ids == fold]\n    valid_preds_spinal = preds_spinal[fold_ids == fold]\n    valid_preds_subarticular = preds_subarticular[fold_ids == fold]\n    valid_gt = gt[fold_ids == fold]\n    ckpt_path = glob(f\"/kaggle/working/stacing_models/fold{fold}/**/best_loss.ckpt\", recursive=True)[0]\n#     model = StackingLightningModel.load_from_checkpoint(ckpt_path)\n#     out = model.model(torch.tensor(valid_preds_foraminal).float(), torch.tensor(valid_preds_spinal).float(), torch.tensor(valid_preds_subarticular).float())[\"logit\"].detach().clone().cpu().softmax(-1).numpy()\n    model = StackingLightningModel.load_from_checkpoint(ckpt_path).model.eval()\n    out = model(torch.tensor(valid_preds_foraminal).float(), torch.tensor(valid_preds_spinal).float(), torch.tensor(valid_preds_subarticular).float())[\"logit\"].detach().clone().cpu().softmax(-1).numpy()\n    \n    out_debug = model(torch.tensor(valid_preds_foraminal).float(), torch.tensor(valid_preds_spinal).float(), torch.tensor(valid_preds_subarticular).float())[\"logit_debug\"].detach().clone().cpu().softmax(-1).numpy()    \n\n    solution_fold = solution[solution.fold_id == fold].reset_index(drop=True)   \n    \n    submission_fold = solution_fold.copy().loc[:, [\"row_id\", \"normal_mild\", \"moderate\", \"severe\"]]\n    submission_fold.loc[solution_fold.condition == \"foraminal\", [\"normal_mild\", \"moderate\", \"severe\"]] = out[:, :10].reshape(-1, 3)\n    submission_fold.loc[solution_fold.condition == \"spinal\", [\"normal_mild\", \"moderate\", \"severe\"]] = out[:, 10:15].reshape(-1, 3)\n    submission_fold.loc[solution_fold.condition == \"subarticular\", [\"normal_mild\", \"moderate\", \"severe\"]] = out[:, 15:25].reshape(-1, 3)\n    \n    submission_fold_debug = solution_fold.copy().loc[:, [\"row_id\", \"normal_mild\", \"moderate\", \"severe\"]]\n    submission_fold_debug.loc[solution_fold.condition == \"foraminal\", [\"normal_mild\", \"moderate\", \"severe\"]] = out_debug[:, :10].reshape(-1, 3)\n    submission_fold_debug.loc[solution_fold.condition == \"spinal\", [\"normal_mild\", \"moderate\", \"severe\"]] = out_debug[:, 10:15].reshape(-1, 3)\n    submission_fold_debug.loc[solution_fold.condition == \"subarticular\", [\"normal_mild\", \"moderate\", \"severe\"]] = out_debug[:, 15:25].reshape(-1, 3)\n    oof.append(submission_fold)\n    oof_nelder_mead.append(submission_fold_debug)\n    \noof = pd.concat(oof).sort_values(\"row_id\", ascending=True).reset_index(drop=True).copy()\noof_nelder_mead = pd.concat(oof_nelder_mead).sort_values(\"row_id\", ascending=True).reset_index(drop=True).copy()\noof","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:48.964272Z","iopub.execute_input":"2024-10-08T04:21:48.964700Z","iopub.status.idle":"2024-10-08T04:21:50.520714Z","shell.execute_reply.started":"2024-10-08T04:21:48.964653Z","shell.execute_reply":"2024-10-08T04:21:50.519334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"s = score(solution.copy(), oof.copy(), \"row_id\", 1)\nf\"Score {s}\"","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:50.522344Z","iopub.execute_input":"2024-10-08T04:21:50.522793Z","iopub.status.idle":"2024-10-08T04:21:50.855788Z","shell.execute_reply.started":"2024-10-08T04:21:50.522749Z","shell.execute_reply":"2024-10-08T04:21:50.854514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"s = score(solution.copy(), oof_nelder_mead.copy(), \"row_id\", 1)\nf\"Score {s}\"","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:50.857659Z","iopub.execute_input":"2024-10-08T04:21:50.858650Z","iopub.status.idle":"2024-10-08T04:21:51.171580Z","shell.execute_reply.started":"2024-10-08T04:21:50.858589Z","shell.execute_reply":"2024-10-08T04:21:51.170295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# s = score(solution_tmp.copy(), submission_tmp.copy(), \"row_id\", 1)\n# f\"Score {s}\"","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:51.173167Z","iopub.execute_input":"2024-10-08T04:21:51.173636Z","iopub.status.idle":"2024-10-08T04:21:51.178904Z","shell.execute_reply.started":"2024-10-08T04:21:51.173577Z","shell.execute_reply":"2024-10-08T04:21:51.177551Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"oof.to_csv(\"tattaka_stacking_oof.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:51.180501Z","iopub.execute_input":"2024-10-08T04:21:51.180871Z","iopub.status.idle":"2024-10-08T04:21:51.695441Z","shell.execute_reply.started":"2024-10-08T04:21:51.180832Z","shell.execute_reply":"2024-10-08T04:21:51.694169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 0.4754291570225556","metadata":{"execution":{"iopub.status.busy":"2024-10-08T04:21:51.697016Z","iopub.execute_input":"2024-10-08T04:21:51.697447Z","iopub.status.idle":"2024-10-08T04:21:51.703416Z","shell.execute_reply.started":"2024-10-08T04:21:51.697403Z","shell.execute_reply":"2024-10-08T04:21:51.702166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}