From 95fac940eec185a36b7de5b7514b59ac1f8cfc95 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 13:13:58 +0200 Subject: [PATCH 1/8] New datasplits --- data/s2bms/splits/explanations.txt | 6 + ..._val_test.pth => s2bms_union_val_test.pth} | Bin .../s2bms_unlabelled_union_val_test.pth | Bin 0 -> 294269 bytes ...8-14-1459_union_aef_tsr_val_test_train.pth | Bin 68355 -> 0 bytes ...9-GT-aef-tessera-datasplit-filtering.ipynb | 59002 +++++++++++++++- 5 files changed, 58940 insertions(+), 68 deletions(-) create mode 100644 data/s2bms/splits/explanations.txt rename data/s2bms/splits/{split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test.pth => s2bms_union_val_test.pth} (100%) create mode 100644 data/s2bms/splits/s2bms_unlabelled_union_val_test.pth delete mode 100644 data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test_train.pth diff --git a/data/s2bms/splits/explanations.txt b/data/s2bms/splits/explanations.txt new file mode 100644 index 0000000..56c5134 --- /dev/null +++ b/data/s2bms/splits/explanations.txt @@ -0,0 +1,6 @@ +split_indices_s2bms-unlabelled-20260529_2026-05-29-1433.pth: all train/val/test unlabelled indices (not used, source data) +split_indices_s2bms+s2bms-unlabelled-20260529_2026-05-29-1438.pth: original S2BMS split and all train/val/test unlabelled indices (not used, source data) +split_indices_s2bms_2024-08-14-1459.pth: original S2BMS split (not used, source data) + +s2bms_union_val_test: S2BMS labelled subset for this study. All val and test split datapoints are available for modalities of: coords, alphaearth and tessera. +s2bms_unlabelled_union_val_test: s2bms_union_val_test + all train samples from the unlabelled dataset \ No newline at end of file diff --git a/data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test.pth b/data/s2bms/splits/s2bms_union_val_test.pth similarity index 100% rename from data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test.pth rename to data/s2bms/splits/s2bms_union_val_test.pth diff --git a/data/s2bms/splits/s2bms_unlabelled_union_val_test.pth b/data/s2bms/splits/s2bms_unlabelled_union_val_test.pth new file mode 100644 index 0000000000000000000000000000000000000000..fa57dc03ebabba4c2833fe9edb1aa6c1cc1c8ce1 GIT binary patch literal 294269 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 diff --git a/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb b/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb index 6391757..f677a4e 100644 --- a/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb +++ b/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb @@ -2,10 +2,13 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "id": "0", - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:06.806623Z", + "start_time": "2026-06-16T11:11:05.730170Z" + } + }, "source": [ "import glob\n", "import os\n", @@ -15,23 +18,37 @@ "\n", "os.chdir(\"..\")\n", "os.getcwd()" - ] + ], + "outputs": [ + { + "data": { + "text/plain": [ + "'/Users/gabriele/PycharmProjects/aether'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 1 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:06.853660Z", + "start_time": "2026-06-16T11:11:06.847649Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "1", - "metadata": {}, - "outputs": [], "source": [ "# Check how do aef and tessera files overlap\n", "\n", - "paths = glob.glob(\"data/s2bms/eo/aef/*.tif\")\n", + "paths = glob.glob(\"data/s2bms/eo/aef/*.npy\")\n", "aef = []\n", "for p in paths:\n", " aef.append(os.path.basename(p).split(\".\")[0].split(\"-\")[-1])\n", "\n", - "\n", "paths = glob.glob(\"data/s2bms/eo/tessera/*.npy\")\n", "tsr = []\n", "for p in paths:\n", @@ -42,28 +59,51 @@ "tsr_left = list(set(tsr) - set(common)) # None\n", "aef_left = list(set(aef) - set(common)) # 12\n", "\n", + "# Filter out unlabelled data\n", + "aef_left = {i for i in tsr_left if 'sample' not in i}\n", + "aef_left = {i for i in aef_left if 'sample' not in i}\n", + "\n", "print(\"Tessera:\", tsr_left)\n", "print(\"AlphaEarth:\", aef_left)" - ] + ], + "id": "b5f98a415ee02572", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tessera: []\n", + "AlphaEarth: set()\n" + ] + } + ], + "execution_count": 2 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:06.888073Z", + "start_time": "2026-06-16T11:11:06.879905Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "2", - "metadata": {}, - "outputs": [], "source": [ "# Load in original datasplit file\n", "pth = \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459.pth\"\n", "split_indices = torch.load(pth, weights_only=False)" - ] + ], + "id": "fb7b579cda7d2828", + "outputs": [], + "execution_count": 3 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:06.903096Z", + "start_time": "2026-06-16T11:11:06.900162Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "3", - "metadata": {}, - "outputs": [], "source": [ "# Print data split sizes\n", "s = 0\n", @@ -72,14 +112,30 @@ " if not k == \"clusters\":\n", " print(k, len(v))\n", " s += len(v)" - ] + ], + "id": "ec919346408bcb68", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Before cleaning:\n", + "train_indices 947\n", + "val_indices 196\n", + "test_indices 186\n" + ] + } + ], + "execution_count": 4 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:24.064002Z", + "start_time": "2026-06-16T11:11:24.058463Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "4", - "metadata": {}, - "outputs": [], "source": [ "# Filter out remaining aef but missing tessera tiles form val and test splits\n", "\n", @@ -99,76 +155,8321 @@ " s += len(v)\n", "\n", "if os.path.exists(\n", - " \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test.pth\"\n", + " \"data/s2bms/splits/s2bms_union_val_test.pth\"\n", "):\n", " print(\"Already saved\")\n", "else:\n", " torch.save(\n", " split_indices,\n", - " \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test.pth\",\n", + " \"data/s2bms/splits/s2bms_union_val_test.pth\",\n", " )" - ] + ], + "id": "294ab8c478839c17", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "After test/val cleaning:\n", + "train_indices 947\n", + "val_indices 196\n", + "test_indices 186\n" + ] + } + ], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:26.476555Z", + "start_time": "2026-06-16T11:11:26.445660Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "5", - "metadata": {}, + "source": [ + "# Visualise data split\n", + "df = pd.read_csv(\"data/s2bms/model_ready_s2bms.csv\")\n", + "\n", + "train_idx = split_indices[\"train_indices\"]\n", + "train_df = df[df[\"name_loc\"].isin(map(str, train_idx))]\n", + "\n", + "val_idx = split_indices[\"val_indices\"]\n", + "val_df = df[df[\"name_loc\"].isin(map(str, val_idx))]\n", + "\n", + "test_idx = split_indices[\"test_indices\"]\n", + "test_df = df[df[\"name_loc\"].isin(map(str, test_idx))]" + ], + "id": "106e42d7cc81a1bb", "outputs": [], + "execution_count": 7 + }, + { + "cell_type": "code", + "id": "7", + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:38.967116Z", + "start_time": "2026-06-16T11:11:38.673570Z" + } + }, "source": [ - "# Filter out remaining aef but missing tessera tiles form train splits\n", + "import folium\n", "\n", - "split_indices[\"train_indices\"] = split_indices[\"train_indices\"][\n", - " ~split_indices[\"train_indices\"].isin(aef_left_str)\n", - "]\n", + "m = folium.Map(location=[df.lat.mean(), df.lon.mean()], zoom_start=3)\n", + "\n", + "# Train = blue\n", + "for _, row in train_df.iterrows():\n", + " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"blue\", fill=True).add_to(m)\n", + "\n", + "# Val = orange\n", + "for _, row in val_df.iterrows():\n", + " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"orange\", fill=True).add_to(m)\n", "\n", - "print(\"After test/val/train cleaning:\")\n", + "# Test = red\n", + "for _, row in test_df.iterrows():\n", + " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"red\", fill=True).add_to(m)\n", + "\n", + "m" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "

Make this Notebook Trusted to load map: File -> Trust Notebook
" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 8 + }, + { + "cell_type": "markdown", + "id": "8", + "metadata": {}, + "source": [ + "# Re-do Unlabelled split" + ] + }, + { + "cell_type": "code", + "id": "9", + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:41.392381Z", + "start_time": "2026-06-16T11:11:41.328992Z" + } + }, + "source": [ + "df_unlabelled = pd.read_csv(\"data/s2bms/model_ready_s2bms-unlabelled-20260529.csv\")\n", + "df_unlabelled = df_unlabelled[df_unlabelled.split == \"train\"]\n", + "\n", + "train_unlabelled = list(df_unlabelled.name_loc)" + ], + "outputs": [], + "execution_count": 9 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:41.705568Z", + "start_time": "2026-06-16T11:11:41.698475Z" + } + }, + "cell_type": "code", + "source": [ + "pth = \"data/s2bms/splits/split_indices_s2bms+s2bms-unlabelled-20260529_2026-05-29-1438.pth\"\n", + "split_indices = torch.load(pth, weights_only=False)\n", + "\n", + "print(\"Before test/val/train:\")\n", + "s = 0\n", "for k, v in split_indices.items():\n", " if not k == \"clusters\":\n", " print(k, len(v))\n", - " s += len(v)\n", - "\n", - "if os.path.exists(\n", - " \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test_train.pth\"\n", - "):\n", - " print(\"Already saved\")\n", - "else:\n", + " s += len(v)" + ], + "id": "c9ac107b0dff1b5c", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Before test/val/train:\n", + "train_indices 8034\n", + "val_indices 1561\n", + "test_indices 1653\n" + ] + } + ], + "execution_count": 10 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:47.993281Z", + "start_time": "2026-06-16T11:11:47.867296Z" + } + }, + "cell_type": "code", + "source": [ + "split_indices[\"train_indices\"] = pd.Series(\n", + " [i for i in list(split_indices[\"train_indices\"]) if i in train_unlabelled or \"UKBMS\" in i]\n", + ")" + ], + "id": "c5b2759dd5c31efb", + "outputs": [], + "execution_count": 12 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:49.269959Z", + "start_time": "2026-06-16T11:11:49.266108Z" + } + }, + "cell_type": "code", + "source": [ + "val_test_indices = torch.load(\n", + " \"data/s2bms/splits/s2bms_union_val_test.pth\",\n", + " weights_only=False,\n", + ")" + ], + "id": "4ac6f42dcb55ea9", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:49.713027Z", + "start_time": "2026-06-16T11:11:49.710015Z" + } + }, + "cell_type": "code", + "source": [ + "split_indices[\"val_indices\"] = pd.Series(\n", + " [i for i in list(val_test_indices[\"val_indices\"]) if \"UKBMS\" in i]\n", + ")\n", + "split_indices[\"test_indices\"] = pd.Series(\n", + " [i for i in list(val_test_indices[\"test_indices\"]) if \"UKBMS\" in i]\n", + ")" + ], + "id": "58b158e667b55e41", + "outputs": [], + "execution_count": 14 + }, + { + "cell_type": "code", + "id": "14", + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:50.114264Z", + "start_time": "2026-06-16T11:11:50.111509Z" + } + }, + "source": [ + "print(\"After test/val/train:\")\n", + "s = 0\n", + "for k, v in split_indices.items():\n", + " if not k == \"clusters\":\n", + " print(k, len(v))\n", + " s += len(v)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "After test/val/train:\n", + "train_indices 8034\n", + "val_indices 196\n", + "test_indices 186\n" + ] + } + ], + "execution_count": 15 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:50.582329Z", + "start_time": "2026-06-16T11:11:50.577952Z" + } + }, + "cell_type": "code", + "source": [ + "if not os.path.exists(\"data/s2bms/splits/s2bms_unlabelled_union_val_test.pth\"):\n", " torch.save(\n", " split_indices,\n", - " \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459_union_aef_tsr_val_test_train.pth\",\n", - " )" - ] + " \"data/s2bms/splits/s2bms_unlabelled_union_val_test.pth\",\n", + " )\n", + "else:\n", + " print('Already saved')" + ], + "id": "534e58743f3f008e", + "outputs": [], + "execution_count": 16 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:51.124201Z", + "start_time": "2026-06-16T11:11:51.082784Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "6", - "metadata": {}, - "outputs": [], "source": [ "# Visualise data split\n", - "df = pd.read_csv(\"data/s2bms/model_ready_s2bms.csv\")\n", + "df_merged = pd.concat([df, df_unlabelled])\n", "\n", "train_idx = split_indices[\"train_indices\"]\n", - "train_df = df[df[\"name_loc\"].isin(map(str, train_idx))]\n", - "\n", + "train_df = df_merged[df_merged[\"name_loc\"].isin(map(str, train_idx))]\n", "\n", "val_idx = split_indices[\"val_indices\"]\n", - "val_df = df[df[\"name_loc\"].isin(map(str, val_idx))]\n", + "val_df = df_merged[df_merged[\"name_loc\"].isin(map(str, val_idx))]\n", "\n", "test_idx = split_indices[\"test_indices\"]\n", - "test_df = df[df[\"name_loc\"].isin(map(str, test_idx))]" - ] + "test_df = df_merged[df_merged[\"name_loc\"].isin(map(str, test_idx))]" + ], + "id": "a95a5b47298f9a91", + "outputs": [], + "execution_count": 17 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2026-06-16T11:11:53.076996Z", + "start_time": "2026-06-16T11:11:51.844005Z" + } + }, "cell_type": "code", - "execution_count": null, - "id": "7", - "metadata": {}, - "outputs": [], "source": [ - "import folium\n", - "\n", "m = folium.Map(location=[df.lat.mean(), df.lon.mean()], zoom_start=3)\n", "\n", "# Train = blue\n", @@ -184,18 +8485,50583 @@ " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"red\", fill=True).add_to(m)\n", "\n", "m" - ] + ], + "id": "756409a00a278f3b", + "outputs": [ + { + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "
Make this Notebook Trusted to load map: File -> Trust Notebook
" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 18 }, { - "cell_type": "code", - "execution_count": null, - "id": "8", "metadata": {}, + "cell_type": "code", "outputs": [], - "source": [] + "execution_count": null, + "source": "", + "id": "e355ce76b6bd18e4" } ], - "metadata": {}, + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + } + }, "nbformat": 4, "nbformat_minor": 5 } From bc66de588cc8319f2180bf0e8956001379306871 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 14:17:19 +0200 Subject: [PATCH 2/8] fix wrong variable name --- ...9-GT-aef-tessera-datasplit-filtering.ipynb | 58913 +--------------- 1 file changed, 88 insertions(+), 58825 deletions(-) diff --git a/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb b/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb index f677a4e..020dcf6 100644 --- a/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb +++ b/notebooks/09-GT-aef-tessera-datasplit-filtering.ipynb @@ -2,13 +2,10 @@ "cells": [ { "cell_type": "code", + "execution_count": null, "id": "0", - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:06.806623Z", - "start_time": "2026-06-16T11:11:05.730170Z" - } - }, + "metadata": {}, + "outputs": [], "source": [ "import glob\n", "import os\n", @@ -18,32 +15,16 @@ "\n", "os.chdir(\"..\")\n", "os.getcwd()" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "'/Users/gabriele/PycharmProjects/aether'" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 1 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:06.853660Z", - "start_time": "2026-06-16T11:11:06.847649Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "1", + "metadata": {}, + "outputs": [], "source": [ "# Check how do aef and tessera files overlap\n", - "\n", "paths = glob.glob(\"data/s2bms/eo/aef/*.npy\")\n", "aef = []\n", "for p in paths:\n", @@ -60,50 +41,31 @@ "aef_left = list(set(aef) - set(common)) # 12\n", "\n", "# Filter out unlabelled data\n", - "aef_left = {i for i in tsr_left if 'sample' not in i}\n", - "aef_left = {i for i in aef_left if 'sample' not in i}\n", + "tsr_left = {i for i in tsr_left if \"sample\" not in i}\n", + "aef_left = {i for i in aef_left if \"sample\" not in i}\n", "\n", "print(\"Tessera:\", tsr_left)\n", "print(\"AlphaEarth:\", aef_left)" - ], - "id": "b5f98a415ee02572", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tessera: []\n", - "AlphaEarth: set()\n" - ] - } - ], - "execution_count": 2 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:06.888073Z", - "start_time": "2026-06-16T11:11:06.879905Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], "source": [ "# Load in original datasplit file\n", "pth = \"data/s2bms/splits/split_indices_s2bms_2024-08-14-1459.pth\"\n", "split_indices = torch.load(pth, weights_only=False)" - ], - "id": "fb7b579cda7d2828", - "outputs": [], - "execution_count": 3 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:06.903096Z", - "start_time": "2026-06-16T11:11:06.900162Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "3", + "metadata": {}, + "outputs": [], "source": [ "# Print data split sizes\n", "s = 0\n", @@ -112,30 +74,14 @@ " if not k == \"clusters\":\n", " print(k, len(v))\n", " s += len(v)" - ], - "id": "ec919346408bcb68", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before cleaning:\n", - "train_indices 947\n", - "val_indices 196\n", - "test_indices 186\n" - ] - } - ], - "execution_count": 4 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:24.064002Z", - "start_time": "2026-06-16T11:11:24.058463Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], "source": [ "# Filter out remaining aef but missing tessera tiles form val and test splits\n", "\n", @@ -154,39 +100,21 @@ " print(k, len(v))\n", " s += len(v)\n", "\n", - "if os.path.exists(\n", - " \"data/s2bms/splits/s2bms_union_val_test.pth\"\n", - "):\n", + "if os.path.exists(\"data/s2bms/splits/s2bms_union_val_test.pth\"):\n", " print(\"Already saved\")\n", "else:\n", " torch.save(\n", " split_indices,\n", " \"data/s2bms/splits/s2bms_union_val_test.pth\",\n", " )" - ], - "id": "294ab8c478839c17", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After test/val cleaning:\n", - "train_indices 947\n", - "val_indices 196\n", - "test_indices 186\n" - ] - } - ], - "execution_count": 6 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:26.476555Z", - "start_time": "2026-06-16T11:11:26.445660Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "5", + "metadata": {}, + "outputs": [], "source": [ "# Visualise data split\n", "df = pd.read_csv(\"data/s2bms/model_ready_s2bms.csv\")\n", @@ -199,20 +127,14 @@ "\n", "test_idx = split_indices[\"test_indices\"]\n", "test_df = df[df[\"name_loc\"].isin(map(str, test_idx))]" - ], - "id": "106e42d7cc81a1bb", - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "code", - "id": "7", - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:38.967116Z", - "start_time": "2026-06-16T11:11:38.673570Z" - } - }, + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], "source": [ "import folium\n", "\n", @@ -231,8047 +153,11 @@ " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"red\", fill=True).add_to(m)\n", "\n", "m" - ], - "outputs": [ - { - "data": { - "text/plain": [ - "" - ], - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 8 + ] }, { "cell_type": "markdown", - "id": "8", + "id": "7", "metadata": {}, "source": [ "# Re-do Unlabelled split" @@ -8279,30 +165,23 @@ }, { "cell_type": "code", - "id": "9", - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:41.392381Z", - "start_time": "2026-06-16T11:11:41.328992Z" - } - }, + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], "source": [ "df_unlabelled = pd.read_csv(\"data/s2bms/model_ready_s2bms-unlabelled-20260529.csv\")\n", "df_unlabelled = df_unlabelled[df_unlabelled.split == \"train\"]\n", "\n", "train_unlabelled = list(df_unlabelled.name_loc)" - ], - "outputs": [], - "execution_count": 9 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:41.705568Z", - "start_time": "2026-06-16T11:11:41.698475Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "9", + "metadata": {}, + "outputs": [], "source": [ "pth = \"data/s2bms/splits/split_indices_s2bms+s2bms-unlabelled-20260529_2026-05-29-1438.pth\"\n", "split_indices = torch.load(pth, weights_only=False)\n", @@ -8313,65 +192,39 @@ " if not k == \"clusters\":\n", " print(k, len(v))\n", " s += len(v)" - ], - "id": "c9ac107b0dff1b5c", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Before test/val/train:\n", - "train_indices 8034\n", - "val_indices 1561\n", - "test_indices 1653\n" - ] - } - ], - "execution_count": 10 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:47.993281Z", - "start_time": "2026-06-16T11:11:47.867296Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], "source": [ "split_indices[\"train_indices\"] = pd.Series(\n", " [i for i in list(split_indices[\"train_indices\"]) if i in train_unlabelled or \"UKBMS\" in i]\n", ")" - ], - "id": "c5b2759dd5c31efb", - "outputs": [], - "execution_count": 12 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:49.269959Z", - "start_time": "2026-06-16T11:11:49.266108Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "11", + "metadata": {}, + "outputs": [], "source": [ "val_test_indices = torch.load(\n", " \"data/s2bms/splits/s2bms_union_val_test.pth\",\n", " weights_only=False,\n", ")" - ], - "id": "4ac6f42dcb55ea9", - "outputs": [], - "execution_count": 13 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:49.713027Z", - "start_time": "2026-06-16T11:11:49.710015Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], "source": [ "split_indices[\"val_indices\"] = pd.Series(\n", " [i for i in list(val_test_indices[\"val_indices\"]) if \"UKBMS\" in i]\n", @@ -8379,20 +232,14 @@ "split_indices[\"test_indices\"] = pd.Series(\n", " [i for i in list(val_test_indices[\"test_indices\"]) if \"UKBMS\" in i]\n", ")" - ], - "id": "58b158e667b55e41", - "outputs": [], - "execution_count": 14 + ] }, { "cell_type": "code", - "id": "14", - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:50.114264Z", - "start_time": "2026-06-16T11:11:50.111509Z" - } - }, + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], "source": [ "print(\"After test/val/train:\")\n", "s = 0\n", @@ -8400,29 +247,14 @@ " if not k == \"clusters\":\n", " print(k, len(v))\n", " s += len(v)" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "After test/val/train:\n", - "train_indices 8034\n", - "val_indices 196\n", - "test_indices 186\n" - ] - } - ], - "execution_count": 15 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:50.582329Z", - "start_time": "2026-06-16T11:11:50.577952Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], "source": [ "if not os.path.exists(\"data/s2bms/splits/s2bms_unlabelled_union_val_test.pth\"):\n", " torch.save(\n", @@ -8430,20 +262,15 @@ " \"data/s2bms/splits/s2bms_unlabelled_union_val_test.pth\",\n", " )\n", "else:\n", - " print('Already saved')" - ], - "id": "534e58743f3f008e", - "outputs": [], - "execution_count": 16 + " print(\"Already saved\")" + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:51.124201Z", - "start_time": "2026-06-16T11:11:51.082784Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], "source": [ "# Visualise data split\n", "df_merged = pd.concat([df, df_unlabelled])\n", @@ -8456,19 +283,14 @@ "\n", "test_idx = split_indices[\"test_indices\"]\n", "test_df = df_merged[df_merged[\"name_loc\"].isin(map(str, test_idx))]" - ], - "id": "a95a5b47298f9a91", - "outputs": [], - "execution_count": 17 + ] }, { - "metadata": { - "ExecuteTime": { - "end_time": "2026-06-16T11:11:53.076996Z", - "start_time": "2026-06-16T11:11:51.844005Z" - } - }, "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], "source": [ "m = folium.Map(location=[df.lat.mean(), df.lon.mean()], zoom_start=3)\n", "\n", @@ -8485,50574 +307,15 @@ " folium.CircleMarker(location=[row.lat, row.lon], radius=2, color=\"red\", fill=True).add_to(m)\n", "\n", "m" - ], - "id": "756409a00a278f3b", - "outputs": [ - { - "data": { - "text/plain": [ - "" - ], - "text/html": [ - "
Make this Notebook Trusted to load map: File -> Trust Notebook
" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 18 + ] }, { - "metadata": {}, "cell_type": "code", - "outputs": [], "execution_count": null, - "source": "", - "id": "e355ce76b6bd18e4" + "id": "17", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { From fbe59ae1566cb67a6da20d61cfdd1f140f1377fa Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 14:18:04 +0200 Subject: [PATCH 3/8] Split after getting missing data, in the setup() call --- src/data/base_datamodule.py | 23 ++++++++++++++--------- src/data/base_dataset.py | 33 ++++++++++++++++++--------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/data/base_datamodule.py b/src/data/base_datamodule.py index 1793d26..7f969cf 100644 --- a/src/data/base_datamodule.py +++ b/src/data/base_datamodule.py @@ -2,7 +2,7 @@ import os import time from functools import partial -from typing import Any, Dict, List, Tuple +from typing import Any, Tuple import numpy as np import pandas as pd @@ -67,8 +67,6 @@ def __init__( self.caption_builder.sync_with_dataset(self.dataset) self.concept_configs = caption_builder.concepts - self.split_data() - @property def tabular_dim(self): return self.dataset.tabular_dim @@ -86,6 +84,7 @@ def setup(self, stage: str = "fit") -> None: # Set up the dataset (download requested modalities) self.dataset.setup() + self.split_data() @property def batch_size_per_device(self) -> None: @@ -251,10 +250,19 @@ def split_data(self) -> None: if test_indices is not None and not isinstance(test_indices, pd.Series): raise NotImplementedError("Expected a pd series of name_locs for data splits.") - train_indices = np.where(self.dataset.df["name_loc"].isin(train_indices))[0] - val_indices = np.where(self.dataset.df["name_loc"].isin(val_indices))[0] + ds_records_names = [i["name_loc"] for i in self.dataset.records] + records_name_to_idx = {name: idx for idx, name in enumerate(ds_records_names)} + + train_indices = np.array( + [records_name_to_idx[n] for n in train_indices if n in records_name_to_idx] + ) + val_indices = np.array( + [records_name_to_idx[n] for n in val_indices if n in records_name_to_idx] + ) if test_indices is not None: - test_indices = np.where(self.dataset.df["name_loc"].isin(test_indices))[0] + test_indices = np.array( + [records_name_to_idx[n] for n in test_indices if n in records_name_to_idx] + ) print(f"Dataset was split using indices from file: {self.saved_split_file_path}") else: @@ -264,13 +272,10 @@ def split_data(self) -> None: if split_data_from_inds: self.data_train = torch.utils.data.Subset(self.dataset, train_indices) - self.data_train.dataset.mode = "train" self.data_val = torch.utils.data.Subset(self.dataset, val_indices) - self.data_val.dataset.mode = "val" if test_indices is not None: self.data_test = torch.utils.data.Subset(self.dataset, test_indices) - self.data_test.dataset.mode = "test" else: self.data_test = None diff --git a/src/data/base_dataset.py b/src/data/base_dataset.py index d39e66a..e6f0dc8 100644 --- a/src/data/base_dataset.py +++ b/src/data/base_dataset.py @@ -10,7 +10,6 @@ from torch.utils.data import Dataset from src.utils.data_utils import center_crop_npy -from src.utils.errors import MissingDataError TORCH_DTYPES = { "float32": torch.float32, @@ -262,19 +261,22 @@ def setup_tessera(self) -> None: # If data does not exist or is empty → full download if not os.path.exists(dst_dir) or len(os.listdir(dst_dir)) == 0: - os.makedirs(dst_dir, exist_ok=True) - - tessera_from_df( - self.df, - data_dir=dst_dir, - year=year, - tile_size=size, - cache_dir=self.cache_dir, - ) + if download_missing_tiles: + os.makedirs(dst_dir, exist_ok=True) + + tessera_from_df( + self.df, + data_dir=dst_dir, + year=year, + tile_size=size, + cache_dir=self.cache_dir, + ) - # TODO: if we compile the dataset and use zenodo (or sth else) then change to pooch downloading/loading - # TODO: in case of zenodo use may need to be moved to UC dataset subclasses - # or self.setup_tessera_from_pooch() <- per children class implementation + # TODO: if we compile the dataset and use zenodo (or sth else) then change to pooch downloading/loading + # TODO: in case of zenodo use may need to be moved to UC dataset subclasses + # or self.setup_tessera_from_pooch() <- per children class implementation + else: + print("Please download the missing Tessera tiles...") # Download missing rows (if any) else: @@ -306,8 +308,9 @@ def setup_tessera(self) -> None: continue except Exception as e: print(f"Tile for {fname} could not be retrieved. Error: {e}") - self.records.pop(i) - print(f"No tile found for {fname} thus it will not be used.") + else: + self.records.pop(i) + print(f"No tile found for {fname} thus it will not be used.") @final def setup_aef(self) -> None: From 929ec5012299e87ad051d88afb62ac01a881ae93 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 14:21:08 +0200 Subject: [PATCH 4/8] Add missing aef data filtering out --- src/data/base_dataset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/data/base_dataset.py b/src/data/base_dataset.py index e6f0dc8..64ccd7b 100644 --- a/src/data/base_dataset.py +++ b/src/data/base_dataset.py @@ -322,6 +322,12 @@ def setup_aef(self) -> None: print("\n\nSetting up AEF data...\n\n") dst_dir = os.path.join(self.data_dir, "eo/aef") + avail_files = os.listdir(dst_dir) + for i, rec in enumerate(self.records): + fname = os.path.basename(rec["aef_path"]) + if fname not in avail_files: + self.records.pop(i) + print(f"No tile found for {fname} thus it will not be used.") # TODO aef retrieval? # TODO: in case of zenodo use may need to be moved to UC dataset subclasses From 82a72c7ca051c628ffd7f14c0d296d43be5a54b7 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 14:27:50 +0200 Subject: [PATCH 5/8] Include setup method in the tests --- tests/test_datasets_and_datamodules.py | 3 ++- tests/test_geo_encoders.py | 6 +----- tests/test_pred_heads.py | 7 +------ tests/test_yield_africa.py | 2 ++ 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/test_datasets_and_datamodules.py b/tests/test_datasets_and_datamodules.py index 20c94be..acdae4a 100644 --- a/tests/test_datasets_and_datamodules.py +++ b/tests/test_datasets_and_datamodules.py @@ -1,4 +1,3 @@ -from src.data.base_dataset import BaseDataset from src.data.butterfly_dataset import ButterflyDataset from src.data.heat_guatemala_dataset import HeatGuatemalaDataset from src.data.satbird_dataset import SatBirdDataset @@ -64,6 +63,7 @@ def test_datasets_generic_properties(request, tmp_path, sample_csv): def test_datamodule_random_split_and_loaders(create_butterfly_dataset): dataset, dm = create_butterfly_dataset + dm.setup() assert len(dm.data_train) == 4 assert len(dm.data_val) == 1 @@ -77,6 +77,7 @@ def test_datamodule_random_split_and_loaders(create_butterfly_dataset): def test_random_split_is_deterministic(create_butterfly_dataset): dataset1, dm1 = create_butterfly_dataset dataset2, dm2 = create_butterfly_dataset + dm1.setup(), dm2.setup() assert dm1.data_train.indices == dm2.data_train.indices assert dm1.data_val.indices == dm2.data_val.indices diff --git a/tests/test_geo_encoders.py b/tests/test_geo_encoders.py index 57ff921..4f062fb 100644 --- a/tests/test_geo_encoders.py +++ b/tests/test_geo_encoders.py @@ -1,8 +1,3 @@ -import json -import os - -import pandas as pd -import pytest import torch from src.models.components.geo_encoders.average_encoder import AverageEncoder @@ -23,6 +18,7 @@ def test_geo_encoder_generic_properties(create_butterfly_dataset): "mlp_projector": MLPProjector, } ds, dm = create_butterfly_dataset + dm.setup() batch = next(iter(dm.train_dataloader())) for geo_encoder_name, geo_encoder_class in dict_geo_encoders.items(): diff --git a/tests/test_pred_heads.py b/tests/test_pred_heads.py index 6f617c2..36149e0 100644 --- a/tests/test_pred_heads.py +++ b/tests/test_pred_heads.py @@ -1,12 +1,6 @@ -import json -import os - -import pandas as pd -import pytest import torch from src.models.components.geo_encoders.geoclip import GeoClipCoordinateEncoder -from src.models.components.pred_heads.base_pred_head import BasePredictionHead from src.models.components.pred_heads.linear_pred_head import LinearPredictionHead from src.models.components.pred_heads.mlp_pred_head import MLPPredictionHead from src.models.components.pred_heads.mlp_regression_head import ( @@ -18,6 +12,7 @@ def test_pred_head_generic_properties(create_butterfly_dataset): """Test required properties of the prediction head class.""" ds, dm = create_butterfly_dataset + dm.setup() batch = next(iter(dm.train_dataloader())) eo_encoder = GeoClipCoordinateEncoder() eo_encoder.setup() diff --git a/tests/test_yield_africa.py b/tests/test_yield_africa.py index 69cc138..d311c7d 100644 --- a/tests/test_yield_africa.py +++ b/tests/test_yield_africa.py @@ -282,6 +282,7 @@ def test_yield_africa_dataset_aux_shape(yield_africa_dataset_with_aux): def test_yield_africa_datamodule_split_sizes(yield_africa_datamodule): dm = yield_africa_datamodule + dm.setup() assert len(dm.data_train) == 7 assert len(dm.data_val) == 2 assert len(dm.data_test) == 1 @@ -323,6 +324,7 @@ def make_dm(): ) dm1, dm2 = make_dm(), make_dm() + dm1.setup(), dm2.setup() assert dm1.data_train.indices == dm2.data_train.indices assert dm1.data_val.indices == dm2.data_val.indices From f0719c16a45ef2629e3090025097572d504c6d83 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 14:31:07 +0200 Subject: [PATCH 6/8] Include setup method in the tests --- tests/test_captions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_captions.py b/tests/test_captions.py index 85951dd..454f533 100644 --- a/tests/test_captions.py +++ b/tests/test_captions.py @@ -49,6 +49,7 @@ def test_datamodule_uses_collate_when_aux_data(request, sample_csv, tmp_path): num_workers=0, pin_memory=False, ) + dm.setup() batch = next(iter(dm.train_dataloader())) assert "text" in batch From 57039502437708c2bc893c2c852474dcb0baac19 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 15:03:49 +0200 Subject: [PATCH 7/8] More test (local) fixes --- configs/experiment/prediction.yaml | 42 ++++++++++++++++++++++++++++++ tests/test_text_encoders.py | 6 +---- tests/test_train.py | 2 ++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 configs/experiment/prediction.yaml diff --git a/configs/experiment/prediction.yaml b/configs/experiment/prediction.yaml new file mode 100644 index 0000000..a4f85bf --- /dev/null +++ b/configs/experiment/prediction.yaml @@ -0,0 +1,42 @@ +# @package _global_ + +# to execute this experiment run: +# python train.py experiment=example + +defaults: + - override /model: s2bms_prediction + - override /data: s2bms_prediction + - override /metrics: s2bms_predictive + +# all parameters below will be merged with parameters from default configurations set above +# this allows you to overwrite only specified parameters + +model: + geo_encoder: + _target_: src.models.components.geo_encoders.geoclip.GeoClipCoordinateEncoder + geo_data_name: coords + trainable_modules: [prediction_head] + prediction_head: + _target_: src.models.components.pred_heads.linear_pred_head.LinearPredictionHead + +data: + dataset: + modalities: + coords: + use_target_data: true + use_aux_data: false + caption_builder: + pin_memory: false + batch_size: 8 + persistent_workers: false + saved_split_file_name: "s2bms_union_val_test.pth" + +tags: ["prediction", "geoclip_coords"] + +seed: 12345 + +trainer: + min_epochs: 1 + max_epochs: 100 + +logger: none diff --git a/tests/test_text_encoders.py b/tests/test_text_encoders.py index 0d09714..6ec31fa 100644 --- a/tests/test_text_encoders.py +++ b/tests/test_text_encoders.py @@ -1,11 +1,6 @@ -import json -import os - -import pandas as pd import pytest import torch -from src.models.components.text_encoders.base_text_encoder import BaseTextEncoder from src.models.components.text_encoders.clip_text_encoder import ClipTextEncoder from src.models.components.text_encoders.llm2clip_text_encoder import ( LLM2CLIPTextEncoder, @@ -18,6 +13,7 @@ def test_text_encoder_generic_properties(create_butterfly_dataset): """This test checks that all text encoders implement the basic properties and methods.""" list_text_encoders = [ClipTextEncoder, LLM2CLIPTextEncoder] ds, dm = create_butterfly_dataset + dm.setup() batch = next(iter(dm.train_dataloader())) text_input = batch.get("text") assert text_input is not None, f"text input is None in the batch from datamodule. {batch}" diff --git a/tests/test_train.py b/tests/test_train.py index a60a1e6..52b5eca 100644 --- a/tests/test_train.py +++ b/tests/test_train.py @@ -88,6 +88,8 @@ def test_train_resume(tmp_path: Path, cfg_train: DictConfig) -> None: """ with open_dict(cfg_train): cfg_train.trainer.max_epochs = 1 + cfg_train.callbacks.model_checkpoint.save_last = True + cfg_train.callbacks.model_checkpoint.dirpath = cfg_train.paths.output_dir + "/checkpoints" HydraConfig().set_config(cfg_train) metric_dict_1, _ = train(cfg_train) From 8be8922f0f31425da479b81124c62ee9898f31a4 Mon Sep 17 00:00:00 2001 From: GabrieleTi Date: Tue, 16 Jun 2026 15:08:06 +0200 Subject: [PATCH 8/8] More test (local) fixes --- configs/experiment/prediction.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configs/experiment/prediction.yaml b/configs/experiment/prediction.yaml index a4f85bf..738b1c0 100644 --- a/configs/experiment/prediction.yaml +++ b/configs/experiment/prediction.yaml @@ -39,4 +39,9 @@ trainer: min_epochs: 1 max_epochs: 100 -logger: none +logger: + wandb: + tags: ${tags} + group: "predictive" + aim: + experiment: "predictive"