WannaBeDataScientist
commited on
Commit
•
920ac9e
1
Parent(s):
a9f0a89
Final report submission
Browse files- .gitattributes +1 -0
- Paper.pdf +3 -0
- about_data_indices.ipynb +0 -0
- chabud.py +752 -0
- distribution_mask_size.ipynb +337 -0
- main.py +36 -0
- submission.py +149 -0
.gitattributes
CHANGED
@@ -32,3 +32,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
Paper.pdf filter=lfs diff=lfs merge=lfs -text
|
Paper.pdf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6c848cf800ba48198acd2e208da5cbed9bff28442ca3c02e74682fe87946bcda
|
3 |
+
size 2988104
|
about_data_indices.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
chabud.py
ADDED
@@ -0,0 +1,752 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
##
|
2 |
+
## chabud.py - Hilfsfunktionen für die ChaBuD ECML Challenge 2023
|
3 |
+
##
|
4 |
+
## CHANGES:
|
5 |
+
## 2023-05-23: Erste Version veröffentlicht
|
6 |
+
##
|
7 |
+
## TODO:
|
8 |
+
## * Funktion um Vorhersage als CSV zu speichern für Leaderboard
|
9 |
+
## * Argument um Anzahl Trainingsepochen zu steuern (epoch, max_epoch, ... ?)
|
10 |
+
## * Finales Modell ausgeben und ggf. auch Vorhersage auf Validierungsdaten speichern
|
11 |
+
##
|
12 |
+
import logging
|
13 |
+
import os
|
14 |
+
from pathlib import Path
|
15 |
+
import pandas as pd
|
16 |
+
import albumentations as A
|
17 |
+
import albumentations.pytorch.transforms as Atorch
|
18 |
+
import h5py
|
19 |
+
import numpy as np
|
20 |
+
import pytorch_lightning as pl
|
21 |
+
import segmentation_models_pytorch as smp
|
22 |
+
import torch
|
23 |
+
import xarray as xr
|
24 |
+
|
25 |
+
from pytorch_lightning.callbacks import ModelCheckpoint
|
26 |
+
|
27 |
+
fn = Path("A:/CodingProjekte/DataMining/src/train_eval.hdf5")
|
28 |
+
|
29 |
+
#Wir wollen ein Dataframe erstellen, welches nur die Namen der Datensätze enthält, die eine größere Brandfläche als 2% haben.
|
30 |
+
#Sogesehen ist es dann eine whitelist
|
31 |
+
|
32 |
+
def basic_df():
|
33 |
+
res = []
|
34 |
+
#Anzahl aller Datensätze ("name")
|
35 |
+
count_ds = 0
|
36 |
+
|
37 |
+
with h5py.File(fn, "r") as fd:
|
38 |
+
|
39 |
+
for name, ds in fd.items():
|
40 |
+
count_burnt_pixels = 0
|
41 |
+
#Standardmäßig ist überall ein pre_fire verfügbar
|
42 |
+
pre_miss = 0
|
43 |
+
#Weil wir den Datensatz schon gecheckt haben, ist ein sicherer Zugrif auf post_fire und mask möglich (hier fehlen keine ganzen Datensätze)
|
44 |
+
post = ds["post_fire"]
|
45 |
+
mask = ds["mask"]
|
46 |
+
|
47 |
+
count_burnt_pixels = np.sum(mask)
|
48 |
+
count_pixels =512 * 512
|
49 |
+
burnt_pixel_rel = count_burnt_pixels / count_pixels
|
50 |
+
#Anders als bei mask und Post müssen wir vor Zugriff überprüfen ob "pre_fire" überhaupt existiert - Vermeidung einer Fehlermeldung
|
51 |
+
if "pre_fire" not in ds:
|
52 |
+
pre_miss = 1
|
53 |
+
res.append({"name": name, "pre_missing": pre_miss, "burnt_pixel_abs": count_burnt_pixels, "burnt_pixel_rel": burnt_pixel_rel})
|
54 |
+
|
55 |
+
return pd.DataFrame(res)
|
56 |
+
|
57 |
+
def miss_dp_df():
|
58 |
+
BANDS = ["coastal_aerosol", "blue", "green", "red",
|
59 |
+
"veg_red_1", "veg_red_2", "veg_red_3", "nir",
|
60 |
+
"veg_red_4", "water_vapour", "swir_1", "swir_2"]
|
61 |
+
|
62 |
+
res = basic_df().values
|
63 |
+
|
64 |
+
# miss_dp ist eine Liste mit "name", "pre" "post" (Werte von Pre + Postt werden mit den Bandnamen selektiert)
|
65 |
+
miss_count = 0
|
66 |
+
miss_dp = []
|
67 |
+
with h5py.File(fn, "r") as fd:
|
68 |
+
for x in res:
|
69 |
+
# skippe die Datensätze mit fehlendem Pre-Bild
|
70 |
+
# if x["pre_missing"] == 1:
|
71 |
+
# continue
|
72 |
+
pre_miss = False
|
73 |
+
|
74 |
+
# Laden der Daten aus dem Originaldatensatz
|
75 |
+
name = x["name"]
|
76 |
+
ds = to_xarray(fd[name])
|
77 |
+
pre = ds["pre"][...]
|
78 |
+
post = ds["post"][...]
|
79 |
+
mask = ds["mask"][...]
|
80 |
+
|
81 |
+
if x["pre_missing"] == 1:
|
82 |
+
# Code für den Fall, dass 'pre_missing' gleich 1 ist
|
83 |
+
post_miss = []
|
84 |
+
for band in range(pre.shape[2]):
|
85 |
+
post_miss.append((np.sum(post[band] == 0).values))
|
86 |
+
x_post_miss = xr.DataArray(post_miss, dims=["band"], coords={"band": BANDS})
|
87 |
+
miss_dp.append({"name": name, "pre": [], "post": x_post_miss.values})
|
88 |
+
else:
|
89 |
+
# Code für den Fall, dass 'pre_missing' nicht gleich 1 ist
|
90 |
+
pre_miss = []
|
91 |
+
post_miss = []
|
92 |
+
for band in range(pre.shape[2]):
|
93 |
+
pre_miss.append((np.sum(pre[band] == 0).values))
|
94 |
+
post_miss.append((np.sum(post[band] == 0).values))
|
95 |
+
x_pre_miss = xr.DataArray(pre_miss, dims=["band"], coords={"band": BANDS})
|
96 |
+
x_post_miss = xr.DataArray(post_miss, dims=["band"], coords={"band": BANDS})
|
97 |
+
miss_dp.append({"name": name, "pre": x_pre_miss.values, "post": x_post_miss.values})
|
98 |
+
|
99 |
+
return miss_dp
|
100 |
+
|
101 |
+
|
102 |
+
def wl():
|
103 |
+
whitelist = []
|
104 |
+
df = basic_df()
|
105 |
+
|
106 |
+
for index, row in df.iterrows():
|
107 |
+
if row["burnt_pixel_rel"] < 0.0025:
|
108 |
+
continue
|
109 |
+
whitelist.append(row["name"])
|
110 |
+
return whitelist
|
111 |
+
|
112 |
+
checkpoint_callback = ModelCheckpoint(
|
113 |
+
#dirpath='checkpoints/',
|
114 |
+
filename='model-{epoch:02d}-{val_iou:.2f}',
|
115 |
+
monitor='valid_iou',
|
116 |
+
mode='max',
|
117 |
+
save_top_k=3
|
118 |
+
)
|
119 |
+
|
120 |
+
|
121 |
+
__version__ = "1.0.0"
|
122 |
+
logger = logging.getLogger(__name__)
|
123 |
+
|
124 |
+
ds_path = "A:/CodingProjekte/DataMining/src/train_eval.hdf5"
|
125 |
+
|
126 |
+
|
127 |
+
def to_xarray(dataset, pretty_band_names=True):
|
128 |
+
"""Konvertiert ein HDF5-Gruppenobjekt, das Vor- und Nach-Brandbilder enthält, in xarray DataArrays.
|
129 |
+
|
130 |
+
Parameters
|
131 |
+
----------
|
132 |
+
dataset : h5py.Group
|
133 |
+
Ein HDF5-Gruppenobjekt, das die Vor- und Nach-Brandbilder, die Maske und die Metadaten enthält.
|
134 |
+
pretty_band_names : bool, optional
|
135 |
+
Wenn True (Standard), werden die "Pretty" Bandnamen verwendet, ansonsten die ursprünglichen MSI Bandnummern.
|
136 |
+
|
137 |
+
Returns
|
138 |
+
-------
|
139 |
+
dict
|
140 |
+
Ein Dictionary, das die xarray DataArrays für die Vor- und Nach-Brandbilder, die Maske und die Fold-Informationen enthält.
|
141 |
+
"""
|
142 |
+
if pretty_band_names:
|
143 |
+
BANDS = ["coastal_aerosol", "blue", "green", "red",
|
144 |
+
"veg_red_1", "veg_red_2", "veg_red_3", "nir",
|
145 |
+
"veg_red_4", "water_vapour", "swir_1", "swir_2"]
|
146 |
+
else:
|
147 |
+
BANDS = ["1", "2", "3", "4", "5", "6", "7", "8", "8a", "9", "11", "12"]
|
148 |
+
|
149 |
+
post = dataset["post_fire"][...].astype("float32") / 10000.0
|
150 |
+
|
151 |
+
try:
|
152 |
+
pre = dataset["pre_fire"][...].astype("float32") / 10000.0
|
153 |
+
except KeyError:
|
154 |
+
pre = np.zeros_like(post, dtype="float32")
|
155 |
+
|
156 |
+
mask = dataset["mask"][..., 0]
|
157 |
+
|
158 |
+
return {"pre": xr.DataArray(pre, dims=["x", "y", "band"], coords={"x": range(512), "y": range(512), "band": BANDS}),
|
159 |
+
"post": xr.DataArray(post, dims=["x", "y", "band"], coords={"x": range(512), "y": range(512), "band": BANDS}),
|
160 |
+
"mask": xr.DataArray(mask, dims=["x", "y"], coords={"x": range(512), "y": range(512)}),
|
161 |
+
"fold": dataset.attrs["fold"]}
|
162 |
+
|
163 |
+
class BandExtractor:
|
164 |
+
def __init__(self, index, name) -> None:
|
165 |
+
self.index = index
|
166 |
+
self.name = name
|
167 |
+
|
168 |
+
def __call__(self, data):
|
169 |
+
if isinstance(data, np.ndarray):
|
170 |
+
return data[..., self.index]
|
171 |
+
elif isinstance(data, xr.DataArray):
|
172 |
+
return data.sel(band=self.name).values
|
173 |
+
else:
|
174 |
+
msg = "Unknown data format."
|
175 |
+
raise Exception(msg)
|
176 |
+
|
177 |
+
def __repr__(self) -> str:
|
178 |
+
return f'BandExtractor({self.index}, "{self.name}")'
|
179 |
+
|
180 |
+
|
181 |
+
band_1 = BandExtractor(0, "coastal_aerosol")
|
182 |
+
band_2 = BandExtractor(1, "blue")
|
183 |
+
band_3 = BandExtractor(2, "green")
|
184 |
+
band_4 = BandExtractor(3, "red")
|
185 |
+
band_5 = BandExtractor(4, "veg_red_1")
|
186 |
+
band_6 = BandExtractor(5, "veg_red_2")
|
187 |
+
band_7 = BandExtractor(6, "veg_red_3")
|
188 |
+
band_8 = BandExtractor(7, "nir")
|
189 |
+
band_8a = BandExtractor(8, "veg_red_4")
|
190 |
+
band_9 = BandExtractor(9, "water_vapour")
|
191 |
+
band_11 = BandExtractor(10, "swir_1")
|
192 |
+
band_12 = BandExtractor(11, "swir_2")
|
193 |
+
|
194 |
+
|
195 |
+
def NBR(data):
|
196 |
+
"""Normalized Burn Ratio.
|
197 |
+
|
198 |
+
nbr = (nir - swir_2) / (nir + swir_2)
|
199 |
+
"""
|
200 |
+
if isinstance(data, np.ndarray):
|
201 |
+
nir = data[..., 7]
|
202 |
+
swir_2 = data[..., 11]
|
203 |
+
elif isinstance(data, xr.DataArray):
|
204 |
+
nir = data.sel(band="nir").values
|
205 |
+
swir_2 = data.sel(band="swir_2").values
|
206 |
+
else:
|
207 |
+
msg = "Unknown data format."
|
208 |
+
raise Exception(msg)
|
209 |
+
|
210 |
+
zaehler = nir - swir_2
|
211 |
+
nenner = nir + swir_2
|
212 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
213 |
+
|
214 |
+
|
215 |
+
def NDVI(data):
|
216 |
+
"""Normalized Difference Vegetation Index."""
|
217 |
+
if isinstance(data, np.ndarray):
|
218 |
+
red = data[..., 3]
|
219 |
+
nir = data[..., 7]
|
220 |
+
elif isinstance(data, xr.DataArray):
|
221 |
+
red = data.sel(band="red").values
|
222 |
+
nir = data.sel(band="nir").values
|
223 |
+
else:
|
224 |
+
msg = "Unknown data format."
|
225 |
+
raise Exception(msg)
|
226 |
+
|
227 |
+
zaehler = nir - red
|
228 |
+
nenner = nir + red
|
229 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
230 |
+
|
231 |
+
|
232 |
+
def GNDVI(data):
|
233 |
+
"""Green Normalized Difference Vegetation Index."""
|
234 |
+
if isinstance(data, np.ndarray):
|
235 |
+
green = data[..., 2]
|
236 |
+
red = data[..., 3]
|
237 |
+
nir = data[..., 7]
|
238 |
+
elif isinstance(data, xr.DataArray):
|
239 |
+
green = data.sel(band="green").values
|
240 |
+
red = data.sel(band="red").values
|
241 |
+
nir = data.sel(band="nir").values
|
242 |
+
else:
|
243 |
+
msg = "Unknown data format."
|
244 |
+
raise Exception(msg)
|
245 |
+
|
246 |
+
zaehler = nir - green
|
247 |
+
nenner = nir + red
|
248 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
249 |
+
|
250 |
+
|
251 |
+
def EVI(data):
|
252 |
+
"""Enhanced Vegetation Index."""
|
253 |
+
if isinstance(data, np.ndarray):
|
254 |
+
blue = data[..., 1]
|
255 |
+
red = data[..., 3]
|
256 |
+
nir = data[..., 7]
|
257 |
+
elif isinstance(data, xr.DataArray):
|
258 |
+
blue = data.sel(band="blue").values
|
259 |
+
red = data.sel(band="red").values
|
260 |
+
nir = data.sel(band="nir").values
|
261 |
+
else:
|
262 |
+
msg = "Unknown data format."
|
263 |
+
raise Exception(msg)
|
264 |
+
|
265 |
+
zaehler = nir - red
|
266 |
+
nenner = nir + 6 * red - 7.5 * blue + 1
|
267 |
+
|
268 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
269 |
+
|
270 |
+
|
271 |
+
def AVI(data):
|
272 |
+
"""Advanced Vegetation Index."""
|
273 |
+
if isinstance(data, np.ndarray):
|
274 |
+
red = data[..., 3]
|
275 |
+
nir = data[..., 7]
|
276 |
+
elif isinstance(data, xr.DataArray):
|
277 |
+
red = data.sel(band="red").values
|
278 |
+
nir = data.sel(band="nir").values
|
279 |
+
else:
|
280 |
+
msg = "Unknown data format."
|
281 |
+
raise Exception(msg)
|
282 |
+
|
283 |
+
base = nir * (1 - red) * (nir - red)
|
284 |
+
## FIXME: Deal with cube roots of negative values?
|
285 |
+
return np.power(base, 1./3., out=np.zeros_like(base), where=base>0)
|
286 |
+
|
287 |
+
|
288 |
+
def SAVI(data):
|
289 |
+
"""Soil Adjusted Vegetation Index."""
|
290 |
+
if isinstance(data, np.ndarray):
|
291 |
+
red = data[..., 3]
|
292 |
+
nir = data[..., 7]
|
293 |
+
elif isinstance(data, xr.DataArray):
|
294 |
+
red = data.sel(band="red").values
|
295 |
+
nir = data.sel(band="nir").values
|
296 |
+
else:
|
297 |
+
msg = "Unknown data format."
|
298 |
+
raise Exception(msg)
|
299 |
+
|
300 |
+
return (nir - red) / (nir + red + 0.428) * 1.428
|
301 |
+
|
302 |
+
|
303 |
+
def NDMI(data):
|
304 |
+
if isinstance(data, np.ndarray):
|
305 |
+
nir = data[..., 7]
|
306 |
+
swir_1 = data[..., 10]
|
307 |
+
elif isinstance(data, xr.DataArray):
|
308 |
+
nir = data.sel(band="nir").values
|
309 |
+
swir_1 = data.sel(band="swir_1").values
|
310 |
+
else:
|
311 |
+
msg = "Unknown data format."
|
312 |
+
raise Exception(msg)
|
313 |
+
|
314 |
+
zaehler = nir - swir_1
|
315 |
+
nenner = nir + swir_1
|
316 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
317 |
+
|
318 |
+
|
319 |
+
def MSI(data):
|
320 |
+
"""Moisture Stress Index.
|
321 |
+
|
322 |
+
Moisture Stress Index is used for canopy stress analysis, productivity
|
323 |
+
prediction and biophysical modeling. Interpretation of the MSI is inverted
|
324 |
+
relative to other water vegetation indices; thus, higher values of the
|
325 |
+
index indicate greater plant water stress and in inference, less soil
|
326 |
+
moisture content. The values of this index range from 0 to more than 3 with
|
327 |
+
the common range for green vegetation being 0.2 to 2.
|
328 |
+
"""
|
329 |
+
if isinstance(data, np.ndarray):
|
330 |
+
nir = data[..., 7]
|
331 |
+
swir_1 = data[..., 10]
|
332 |
+
elif isinstance(data, xr.DataArray):
|
333 |
+
nir = data.sel(band="nir").values
|
334 |
+
swir_1 = data.sel(band="swir_1").values
|
335 |
+
else:
|
336 |
+
msg = "Unknown data format."
|
337 |
+
raise Exception(msg)
|
338 |
+
|
339 |
+
return swir_1 - nir
|
340 |
+
|
341 |
+
|
342 |
+
def GCI(data):
|
343 |
+
"""Green Chlorophyll Index."""
|
344 |
+
if isinstance(data, np.ndarray):
|
345 |
+
green = data[..., 2]
|
346 |
+
water_vapour = data[..., 9]
|
347 |
+
elif isinstance(data, xr.DataArray):
|
348 |
+
green = data.sel(band="green").values
|
349 |
+
water_vapour = data.sel(band="water_vapour").values
|
350 |
+
else:
|
351 |
+
msg = "Unknown data format."
|
352 |
+
raise Exception(msg)
|
353 |
+
|
354 |
+
return water_vapour - green
|
355 |
+
|
356 |
+
|
357 |
+
def BSI(data):
|
358 |
+
"""Bare Soil Index."""
|
359 |
+
if isinstance(data, np.ndarray):
|
360 |
+
blue = data[..., 1]
|
361 |
+
red = data[..., 3]
|
362 |
+
nir = data[..., 7]
|
363 |
+
swir_1 = data[..., 10]
|
364 |
+
elif isinstance(data, xr.DataArray):
|
365 |
+
blue = data.sel(band="blue").values
|
366 |
+
red = data.sel(band="red").values
|
367 |
+
nir = data.sel(band="nir").values
|
368 |
+
swir_1 = data.sel(band="swir_1").values
|
369 |
+
else:
|
370 |
+
msg = "Unknown data format."
|
371 |
+
raise Exception(msg)
|
372 |
+
|
373 |
+
swir_red = swir_1 + red
|
374 |
+
nir_blue = nir + blue
|
375 |
+
zaehler = swir_red - nir_blue
|
376 |
+
nenner = swir_red + nir_blue
|
377 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
378 |
+
|
379 |
+
|
380 |
+
def NDWI(data):
|
381 |
+
"""Normalized Difference Water Index."""
|
382 |
+
if isinstance(data, np.ndarray):
|
383 |
+
green = data[..., 2]
|
384 |
+
nir = data[..., 7]
|
385 |
+
elif isinstance(data, xr.DataArray):
|
386 |
+
green = data.sel(band="green").values
|
387 |
+
nir = data.sel(band="nir").values
|
388 |
+
else:
|
389 |
+
msg = "Unknown data format."
|
390 |
+
raise Exception(msg)
|
391 |
+
|
392 |
+
zaehler = green - nir
|
393 |
+
nenner = green + nir
|
394 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
395 |
+
|
396 |
+
|
397 |
+
def NDSI(data):
|
398 |
+
"""Normalized Difference Snow Index."""
|
399 |
+
if isinstance(data, np.ndarray):
|
400 |
+
green = data[..., 2]
|
401 |
+
swir_1 = data[..., 10]
|
402 |
+
elif isinstance(data, xr.DataArray):
|
403 |
+
green = data.sel(band="green").values
|
404 |
+
swir_1 = data.sel(band="swir_1").values
|
405 |
+
else:
|
406 |
+
msg = "Unknown data format."
|
407 |
+
raise Exception(msg)
|
408 |
+
|
409 |
+
zaehler = green - swir_1
|
410 |
+
nenner = green + swir_1
|
411 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
412 |
+
|
413 |
+
|
414 |
+
def NDGI(data):
|
415 |
+
if isinstance(data, np.ndarray):
|
416 |
+
green = data[..., 2]
|
417 |
+
red = data[..., 3]
|
418 |
+
elif isinstance(data, xr.DataArray):
|
419 |
+
green = data.sel(band="green").values
|
420 |
+
red = data.sel(band="red").values
|
421 |
+
else:
|
422 |
+
msg = "Unknown data format."
|
423 |
+
raise Exception(msg)
|
424 |
+
|
425 |
+
zaehler = green - red
|
426 |
+
nenner = green + red
|
427 |
+
return np.divide(zaehler, nenner, out=np.zeros_like(zaehler), where=nenner != 0.0)
|
428 |
+
|
429 |
+
#Die Bänder kommen in Channels
|
430 |
+
class FiresDataset(torch.utils.data.Dataset):
|
431 |
+
def __init__(self, filename, folds=(0, 1, 2, 3, 4),
|
432 |
+
channels=[],
|
433 |
+
include_pre=False,
|
434 |
+
transform=None) -> None:
|
435 |
+
self._filename = filename
|
436 |
+
self._fd = h5py.File(filename, "r")
|
437 |
+
self._channels = channels
|
438 |
+
self._transform = transform
|
439 |
+
self._names = []
|
440 |
+
|
441 |
+
whitelist = wl()
|
442 |
+
for name in self._fd:
|
443 |
+
if self._fd[name].attrs["fold"] not in folds:
|
444 |
+
continue
|
445 |
+
if name in whitelist:
|
446 |
+
self._names.append((name, "post_fire"))
|
447 |
+
if include_pre and "pre_fire" in self._fd[name]:
|
448 |
+
pre_image = self._fd[name]["pre_fire"][...]
|
449 |
+
# Include only "real" pre_fire images
|
450 |
+
if np.mean(pre_image > 0) > 0.8:
|
451 |
+
self._names.append((name, "pre_fire"))
|
452 |
+
|
453 |
+
def number_of_channels(self):
|
454 |
+
return len(self._channels)
|
455 |
+
|
456 |
+
def __getitem__(self, idx):
|
457 |
+
name, state = self._names[idx]
|
458 |
+
data = self._fd[name][state][...].astype("float32") / 10000.0
|
459 |
+
if state == "pre_fire":
|
460 |
+
mask = np.zeros((512, 512), dtype="float32")
|
461 |
+
else:
|
462 |
+
mask = self._fd[name]["mask"][..., 0].astype("float32")
|
463 |
+
|
464 |
+
channels = []
|
465 |
+
for channel in self._channels:
|
466 |
+
channels.append(channel(data))
|
467 |
+
|
468 |
+
# Stack indices into a new image in CHW format.
|
469 |
+
image = np.stack(channels)
|
470 |
+
|
471 |
+
if self._transform:
|
472 |
+
# Transpose image so we get HWC instead of CHW format.
|
473 |
+
# Transform is responsible for transposing back as required by PyTorch.
|
474 |
+
image = image.transpose((1, 2, 0))
|
475 |
+
xfrm = self._transform(image=image, mask=mask)
|
476 |
+
image, mask = xfrm["image"], xfrm["mask"]
|
477 |
+
logger.debug("Final tensor shape: %s", image.shape)
|
478 |
+
|
479 |
+
return {"image": image, "mask": mask[None, :]}
|
480 |
+
|
481 |
+
def __len__(self) -> int:
|
482 |
+
return len(self._names)
|
483 |
+
|
484 |
+
|
485 |
+
class FireModel(pl.LightningModule):
|
486 |
+
def __init__(self,
|
487 |
+
datafile,
|
488 |
+
model,
|
489 |
+
encoder,
|
490 |
+
encoder_depth,
|
491 |
+
encoder_weights,
|
492 |
+
loss,
|
493 |
+
channels,
|
494 |
+
train_transform,
|
495 |
+
train_use_pre_fire,
|
496 |
+
n_cpus,
|
497 |
+
batch_size,
|
498 |
+
lr=0.00025,
|
499 |
+
**kwargs) -> None:
|
500 |
+
super().__init__()
|
501 |
+
self.save_hyperparameters()
|
502 |
+
self.datafile = datafile
|
503 |
+
self.lr = lr
|
504 |
+
self.channels = channels
|
505 |
+
if model == "unet":
|
506 |
+
decoder_channels = [2**(8 - d) for d in range(encoder_depth, 0, -1)]
|
507 |
+
self.model = smp.Unet(encoder_name=encoder, encoder_depth=encoder_depth, encoder_weights=encoder_weights,
|
508 |
+
decoder_channels=decoder_channels,
|
509 |
+
in_channels=len(channels), classes=1)
|
510 |
+
elif model == "unetpp":
|
511 |
+
decoder_channels = [2**(8 - d) for d in range(encoder_depth, 0, -1)]
|
512 |
+
self.model = smp.UnetPlusPlus(encoder_name=encoder, encoder_depth=encoder_depth, encoder_weights=encoder_weights,
|
513 |
+
decoder_channels=decoder_channels,
|
514 |
+
in_channels=len(channels), classes=1)
|
515 |
+
elif model == "fpn":
|
516 |
+
if encoder_depth == 3:
|
517 |
+
upsampling = 1
|
518 |
+
elif encoder_depth == 4:
|
519 |
+
upsampling = 2
|
520 |
+
elif encoder_depth == 5:
|
521 |
+
upsampling = 4
|
522 |
+
else:
|
523 |
+
raise "FPN: Unsupported encoder depth {encoder_depth}."
|
524 |
+
self.model = smp.FPN(encoder_name=encoder, encoder_weights=encoder_weights, encoder_depth=encoder_depth,
|
525 |
+
upsampling=upsampling,
|
526 |
+
in_channels=len(channels), classes=1)
|
527 |
+
elif model == "dlv3":
|
528 |
+
self.model = smp.DeepLabV3(encoder_name=encoder, encoder_weights=encoder_weights, encoder_depth=encoder_depth,
|
529 |
+
in_channels=len(channels), classes=1)
|
530 |
+
elif model == "dlv3p":
|
531 |
+
if encoder_depth != 5:
|
532 |
+
raise f"Unsupported encoder depth {encoder_depth} for DeepLabV3+ (must be 5)."
|
533 |
+
self.model = smp.DeepLabV3Plus(encoder_name=encoder, encoder_weights=encoder_weights, encoder_depth=encoder_depth,
|
534 |
+
in_channels=len(channels), classes=1)
|
535 |
+
else:
|
536 |
+
raise f"Unsupported model '{model}'."
|
537 |
+
|
538 |
+
if loss == "dice":
|
539 |
+
self.loss_fn = smp.losses.DiceLoss(smp.losses.BINARY_MODE, from_logits=True)
|
540 |
+
elif loss == "bce":
|
541 |
+
self.loss_fn = smp.losses.SoftBCEWithLogitsLoss()
|
542 |
+
else:
|
543 |
+
raise f"Unsupported loss function '{loss}'."
|
544 |
+
|
545 |
+
self.train_transform = train_transform
|
546 |
+
self.train_use_pre_fire = train_use_pre_fire
|
547 |
+
self.n_cpus = n_cpus
|
548 |
+
self.batch_size = batch_size
|
549 |
+
|
550 |
+
def forward(self, image):
|
551 |
+
mask = self.model(image)
|
552 |
+
return mask
|
553 |
+
|
554 |
+
def shared_step(self, batch, stage):
|
555 |
+
image, mask = batch["image"], batch["mask"]
|
556 |
+
|
557 |
+
logits_mask = self.forward(image)
|
558 |
+
loss = self.loss_fn(logits_mask, mask)
|
559 |
+
|
560 |
+
prob_mask = logits_mask.sigmoid()
|
561 |
+
pred_mask = (prob_mask > 0.5).long()
|
562 |
+
tp, fp, fn, tn = smp.metrics.get_stats(pred_mask, mask.long(), mode="binary")
|
563 |
+
iou = smp.metrics.iou_score(tp, fp, fn, tn, reduction="micro-imagewise")
|
564 |
+
|
565 |
+
self.log(f"{stage}_loss", loss, on_step=False, on_epoch=True, prog_bar=True, logger=True)
|
566 |
+
self.log(f"{stage}_iou", iou, on_step=False, on_epoch=True, prog_bar=True, logger=True)
|
567 |
+
return loss
|
568 |
+
|
569 |
+
def training_step(self, batch, batch_idx):
|
570 |
+
return self.shared_step(batch, "train")
|
571 |
+
|
572 |
+
def train_dataloader(self):
|
573 |
+
train_ds = FiresDataset(self.datafile, folds=[1, 2, 3, 4],
|
574 |
+
channels=self.channels,
|
575 |
+
transform=self.train_transform,
|
576 |
+
include_pre=self.train_use_pre_fire)
|
577 |
+
train_dl = torch.utils.data.DataLoader(train_ds,
|
578 |
+
batch_size=self.batch_size,
|
579 |
+
num_workers=self.n_cpus,
|
580 |
+
shuffle=True,
|
581 |
+
pin_memory=True,
|
582 |
+
drop_last=False)
|
583 |
+
return train_dl
|
584 |
+
|
585 |
+
def validation_step(self, batch, batch_idx):
|
586 |
+
return self.shared_step(batch, "valid")
|
587 |
+
|
588 |
+
def val_dataloader(self):
|
589 |
+
val_ds = FiresDataset(self.datafile, folds=[0],
|
590 |
+
channels=self.channels,
|
591 |
+
transform=None,
|
592 |
+
include_pre=False)
|
593 |
+
val_dl = torch.utils.data.DataLoader(val_ds,
|
594 |
+
batch_size=self.batch_size,
|
595 |
+
num_workers=self.n_cpus,
|
596 |
+
shuffle=False,
|
597 |
+
pin_memory=True,
|
598 |
+
drop_last=False)
|
599 |
+
return val_dl
|
600 |
+
|
601 |
+
def test_step(self, batch, batch_idx):
|
602 |
+
return self.shared_step(batch, "test")
|
603 |
+
|
604 |
+
def configure_optimizers(self):
|
605 |
+
# TODO: Can we do better? We should probably implement a learning rate schedule?
|
606 |
+
return torch.optim.Adam(self.parameters(), lr=self.lr)
|
607 |
+
|
608 |
+
|
609 |
+
def main(accelerator,
|
610 |
+
datafile,
|
611 |
+
batch_size,
|
612 |
+
channels,
|
613 |
+
n_cpus,
|
614 |
+
model,
|
615 |
+
encoder,
|
616 |
+
encoder_depth,
|
617 |
+
encoder_weights,
|
618 |
+
loss,
|
619 |
+
train_use_pre_fire,
|
620 |
+
train_use_augmentation,
|
621 |
+
learning_rate,
|
622 |
+
):
|
623 |
+
|
624 |
+
|
625 |
+
if train_use_augmentation:
|
626 |
+
train_xfrm = A.Compose([
|
627 |
+
A.VerticalFlip(p=0.5),
|
628 |
+
A.HorizontalFlip(p=0.5),
|
629 |
+
A.Transpose(p=0.5),
|
630 |
+
A.RandomRotate90(p=0.5),
|
631 |
+
Atorch.ToTensorV2(),
|
632 |
+
])
|
633 |
+
else:
|
634 |
+
train_xfrm = None
|
635 |
+
|
636 |
+
logger.info("Instantiating model.")
|
637 |
+
mdl = FireModel(datafile=datafile,
|
638 |
+
model=model,
|
639 |
+
encoder=encoder,
|
640 |
+
encoder_depth=encoder_depth,
|
641 |
+
encoder_weights=encoder_weights,
|
642 |
+
loss=loss,
|
643 |
+
channels=channels,
|
644 |
+
n_cpus=n_cpus,
|
645 |
+
train_transform=train_xfrm,
|
646 |
+
train_use_pre_fire=train_use_pre_fire,
|
647 |
+
batch_size=batch_size,
|
648 |
+
lr=learning_rate)
|
649 |
+
|
650 |
+
trainer = pl.Trainer(accelerator=accelerator, devices="auto",
|
651 |
+
log_every_n_steps=10, max_epochs=30, callbacks=[checkpoint_callback])
|
652 |
+
#callbacks=[checkpoint_callback]
|
653 |
+
logger.info("Start training.")
|
654 |
+
trainer.fit(mdl)
|
655 |
+
|
656 |
+
|
657 |
+
CHANNEL_MAP = {
|
658 |
+
"band_1": band_1,
|
659 |
+
"band_2": band_2,
|
660 |
+
"band_3": band_3,
|
661 |
+
"band_4": band_4,
|
662 |
+
"band_5": band_5,
|
663 |
+
"band_6": band_6,
|
664 |
+
"band_7": band_7,
|
665 |
+
"band_8": band_8,
|
666 |
+
"band_8a": band_8a,
|
667 |
+
"band_9": band_9,
|
668 |
+
"band_11": band_11,
|
669 |
+
"band_12": band_12,
|
670 |
+
"nbr": NBR,
|
671 |
+
"ndvi": NDVI,
|
672 |
+
"gndvi": GNDVI,
|
673 |
+
"evi": EVI,
|
674 |
+
"avi": AVI,
|
675 |
+
"savi": SAVI,
|
676 |
+
"ndmi": NDMI,
|
677 |
+
"msi": MSI,
|
678 |
+
"gci": GCI,
|
679 |
+
"bsi": BSI,
|
680 |
+
"ndwi": NDWI,
|
681 |
+
"ndsi": NDSI,
|
682 |
+
"ndgi": NDGI,
|
683 |
+
}
|
684 |
+
|
685 |
+
if __name__ == "__main__":
|
686 |
+
|
687 |
+
import argparse # Only import when needed
|
688 |
+
|
689 |
+
N_CPUS = int(os.getenv("SLURM_CPUS_PER_TASK", 1))
|
690 |
+
parser = argparse.ArgumentParser("chabud.py")
|
691 |
+
parser.add_argument("--accelerator", type=str, choices=["cpu", "gpu", "auto"], default="auto")
|
692 |
+
parser.add_argument("--datafile", type=Path, default=ds_path,
|
693 |
+
help="Location of data file used for training.")
|
694 |
+
parser.add_argument("--n-cpus", type=int, default=N_CPUS, help="Number of CPU cores to use.")
|
695 |
+
parser.add_argument("--batch-size", type=int, default=2,
|
696 |
+
help="Training and validation batch size.")
|
697 |
+
parser.add_argument("--learning-rate", type=float, default=0.00025,
|
698 |
+
help="Learning rate of optimizer.")
|
699 |
+
parser.add_argument("--model", choices=["unet", "unetpp", "fpn", "dlv3", "dlv3p"], default="unet",
|
700 |
+
help="Segmentation model")
|
701 |
+
parser.add_argument("--encoder", choices=["resnet18", "resnet34", "resnet50", "vgg13", "dpn68", "dpn92", "timm-efficientnet-b0"], default="resnet34",
|
702 |
+
help="Encoder of segmentation model")
|
703 |
+
parser.add_argument("--encoder-depth", type=int, default=5,
|
704 |
+
help="Depth of encoder stage")
|
705 |
+
parser.add_argument("--encoder-weights", choices=["random", "imagenet"], default="imagenet",
|
706 |
+
help="Weight initialization for encoder")
|
707 |
+
parser.add_argument("--loss", choices=["dice", "bce"], default="dice",
|
708 |
+
help="Loss function")
|
709 |
+
parser.add_argument("--train-use-pre_fire", action="store_true",
|
710 |
+
help="Use pre_fire data for training?")
|
711 |
+
parser.add_argument("--train-use-augmentation", action="store_true",
|
712 |
+
help="Use data augmentation in training step?")
|
713 |
+
parser.add_argument("--channels", nargs="+", choices=CHANNEL_MAP.keys(),
|
714 |
+
default=["band_1", "band_2", "band_3", "band_4", "band_5", "band_6", "band_7", "band_8", "band_8a", "band_9", "band_11", "band_12"],
|
715 |
+
help="Channels to use for prediction")
|
716 |
+
parser.add_argument("--log-level", type=str, choices=["info", "debug"], default="info")
|
717 |
+
|
718 |
+
args = parser.parse_args()
|
719 |
+
|
720 |
+
LOGGING_MAP = {"info": logging.INFO, "debug": logging.DEBUG}
|
721 |
+
logging.basicConfig(level=LOGGING_MAP[args.log_level],
|
722 |
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
723 |
+
datefmt="%d-%b-%y %H:%M:%S")
|
724 |
+
|
725 |
+
|
726 |
+
if args.encoder_weights == "random":
|
727 |
+
args.encoder_weights = None
|
728 |
+
|
729 |
+
# Translate channel names to function that calculates the channel / index.
|
730 |
+
logger.info(f"Selected channels: {args.channels}")
|
731 |
+
channels = []
|
732 |
+
for channel in args.channels:
|
733 |
+
channels.append(CHANNEL_MAP[channel])
|
734 |
+
|
735 |
+
|
736 |
+
torch.set_num_threads(args.n_cpus)
|
737 |
+
torch.set_float32_matmul_precision("medium")
|
738 |
+
|
739 |
+
main(accelerator=args.accelerator,
|
740 |
+
datafile=args.datafile,
|
741 |
+
batch_size=args.batch_size,
|
742 |
+
learning_rate=args.learning_rate,
|
743 |
+
channels=channels,
|
744 |
+
n_cpus=args.n_cpus,
|
745 |
+
model=args.model,
|
746 |
+
encoder=args.encoder,
|
747 |
+
encoder_depth=args.encoder_depth,
|
748 |
+
encoder_weights=args.encoder_weights,
|
749 |
+
loss=args.loss,
|
750 |
+
train_use_pre_fire=args.train_use_pre_fire,
|
751 |
+
train_use_augmentation=args.train_use_augmentation)
|
752 |
+
|
distribution_mask_size.ipynb
ADDED
@@ -0,0 +1,337 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 1,
|
6 |
+
"id": "8b77c765-edb9-437f-bab9-9bb1217ab8a8",
|
7 |
+
"metadata": {
|
8 |
+
"execution": {
|
9 |
+
"iopub.execute_input": "2023-07-12T19:18:23.207656Z",
|
10 |
+
"iopub.status.busy": "2023-07-12T19:18:23.207403Z",
|
11 |
+
"iopub.status.idle": "2023-07-12T19:18:25.557392Z",
|
12 |
+
"shell.execute_reply": "2023-07-12T19:18:25.556690Z",
|
13 |
+
"shell.execute_reply.started": "2023-07-12T19:18:23.207621Z"
|
14 |
+
},
|
15 |
+
"tags": []
|
16 |
+
},
|
17 |
+
"outputs": [],
|
18 |
+
"source": [
|
19 |
+
"import h5py\n",
|
20 |
+
"import numpy as np\n",
|
21 |
+
"import pandas as pd\n",
|
22 |
+
"import xarray as xr\n",
|
23 |
+
"import skimage as ski\n",
|
24 |
+
"import seaborn as sns\n",
|
25 |
+
"import matplotlib.pyplot as plt\n",
|
26 |
+
"from matplotlib.colors import ListedColormap\n",
|
27 |
+
"from tqdm.auto import tqdm\n",
|
28 |
+
"from pathlib import Path\n",
|
29 |
+
"import matplotlib.pyplot as plt\n",
|
30 |
+
"\n",
|
31 |
+
"BASEDIR = Path(\"/global/public/chabud-ecml-pkdd2023/\")\n",
|
32 |
+
"fn = BASEDIR / \"train_eval.hdf5\""
|
33 |
+
]
|
34 |
+
},
|
35 |
+
{
|
36 |
+
"cell_type": "code",
|
37 |
+
"execution_count": 2,
|
38 |
+
"id": "1fafd16b-c043-4c47-9e30-2c75b72eaccf",
|
39 |
+
"metadata": {
|
40 |
+
"execution": {
|
41 |
+
"iopub.execute_input": "2023-07-12T19:18:25.562789Z",
|
42 |
+
"iopub.status.busy": "2023-07-12T19:18:25.561013Z",
|
43 |
+
"iopub.status.idle": "2023-07-12T19:18:25.571051Z",
|
44 |
+
"shell.execute_reply": "2023-07-12T19:18:25.569973Z",
|
45 |
+
"shell.execute_reply.started": "2023-07-12T19:18:25.562762Z"
|
46 |
+
},
|
47 |
+
"tags": []
|
48 |
+
},
|
49 |
+
"outputs": [],
|
50 |
+
"source": [
|
51 |
+
"def to_xarray(dataset, pretty_band_names=True):\n",
|
52 |
+
" \"\"\"Convert a single example into an xarray for easy access\"\"\"\n",
|
53 |
+
" \n",
|
54 |
+
" if pretty_band_names:\n",
|
55 |
+
" BANDS = [\"coastal_aerosol\", \"blue\", \"green\", \"red\",\n",
|
56 |
+
" \"veg_red_1\", \"veg_red_2\", \"veg_red_3\", \"nir\", \n",
|
57 |
+
" \"veg_red_4\", \"water_vapour\", \"swir_1\", \"swir_2\"]\n",
|
58 |
+
" else:\n",
|
59 |
+
" BANDS = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"8a\", \"9\", \"11\", \"12\"]\n",
|
60 |
+
" \n",
|
61 |
+
" post = dataset[\"post_fire\"][...].astype(\"float32\") / 10000.0\n",
|
62 |
+
" \n",
|
63 |
+
" # Da `pre_fire` manchmal fehlt ersetzen wir es durch 0 Werte was\n",
|
64 |
+
" # eh der Platzhalter für einen fehlenden Messwert ist.\n",
|
65 |
+
" try:\n",
|
66 |
+
" pre = dataset[\"pre_fire\"][...].astype(\"float32\") / 10000.0\n",
|
67 |
+
" except KeyError:\n",
|
68 |
+
" pre = np.zeros_like(post, dtype=\"float32\")\n",
|
69 |
+
" \n",
|
70 |
+
" # Da die Maske nur ein \"Band\" hat können wir die dritte Dimension einfach\n",
|
71 |
+
" # weglassen. Das erreichen wir in dem wir mit `0` am Ende indizieren.\n",
|
72 |
+
" mask = dataset[\"mask\"][..., 0].astype(\"bool\")\n",
|
73 |
+
" \n",
|
74 |
+
" return {\"pre\": xr.DataArray(pre, dims=[\"x\", \"y\", \"band\"], coords={\"x\": range(512), \"y\": range(512), \"band\": BANDS}),\n",
|
75 |
+
" \"post\": xr.DataArray(post, dims=[\"x\", \"y\", \"band\"], coords={\"x\": range(512), \"y\": range(512), \"band\": BANDS}),\n",
|
76 |
+
" \"mask\": xr.DataArray(mask, dims=[\"x\", \"y\"], coords={\"x\": range(512), \"y\": range(512)}),\n",
|
77 |
+
" \"fold\": dataset.attrs[\"fold\"]}"
|
78 |
+
]
|
79 |
+
},
|
80 |
+
{
|
81 |
+
"cell_type": "markdown",
|
82 |
+
"id": "385378a8-6c11-483c-a936-825af060f0c2",
|
83 |
+
"metadata": {},
|
84 |
+
"source": [
|
85 |
+
"The following code was used and edited in order to analize the effect on the median and standart deviation if data with a too small masks are removed. This was done so that the Neuronal Network gets trained to predict larger masks."
|
86 |
+
]
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"cell_type": "code",
|
90 |
+
"execution_count": 3,
|
91 |
+
"id": "3a4eb708-4a8d-484a-a3d5-79318fa2e1ce",
|
92 |
+
"metadata": {
|
93 |
+
"execution": {
|
94 |
+
"iopub.execute_input": "2023-07-12T19:18:25.575871Z",
|
95 |
+
"iopub.status.busy": "2023-07-12T19:18:25.574255Z",
|
96 |
+
"iopub.status.idle": "2023-07-12T19:18:36.454225Z",
|
97 |
+
"shell.execute_reply": "2023-07-12T19:18:36.453237Z",
|
98 |
+
"shell.execute_reply.started": "2023-07-12T19:18:25.575846Z"
|
99 |
+
},
|
100 |
+
"tags": []
|
101 |
+
},
|
102 |
+
"outputs": [],
|
103 |
+
"source": [
|
104 |
+
"res = []\n",
|
105 |
+
"\n",
|
106 |
+
"with h5py.File(fn, \"r\") as fd:\n",
|
107 |
+
" for name in fd:\n",
|
108 |
+
" ds = to_xarray(fd[name])\n",
|
109 |
+
" mask = ds[\"mask\"].values\n",
|
110 |
+
" burned = np.sum(mask) / (512*512)\n",
|
111 |
+
" #if(burned==1):\n",
|
112 |
+
" #print(name)\n",
|
113 |
+
" if(burned<=0.02):\n",
|
114 |
+
" continue;\n",
|
115 |
+
" res.append({\"burned\": burned}) \n",
|
116 |
+
" #break;"
|
117 |
+
]
|
118 |
+
},
|
119 |
+
{
|
120 |
+
"cell_type": "code",
|
121 |
+
"execution_count": 4,
|
122 |
+
"id": "450fe581-0d56-47e0-85d6-d82d3e22afde",
|
123 |
+
"metadata": {
|
124 |
+
"execution": {
|
125 |
+
"iopub.execute_input": "2023-07-12T19:18:36.460360Z",
|
126 |
+
"iopub.status.busy": "2023-07-12T19:18:36.458625Z",
|
127 |
+
"iopub.status.idle": "2023-07-12T19:18:36.467408Z",
|
128 |
+
"shell.execute_reply": "2023-07-12T19:18:36.466800Z",
|
129 |
+
"shell.execute_reply.started": "2023-07-12T19:18:36.460317Z"
|
130 |
+
},
|
131 |
+
"tags": []
|
132 |
+
},
|
133 |
+
"outputs": [],
|
134 |
+
"source": [
|
135 |
+
"df = pd.DataFrame(res)\n",
|
136 |
+
"del res"
|
137 |
+
]
|
138 |
+
},
|
139 |
+
{
|
140 |
+
"cell_type": "code",
|
141 |
+
"execution_count": 5,
|
142 |
+
"id": "87df05e4-3401-428a-88ea-98a9510933c8",
|
143 |
+
"metadata": {
|
144 |
+
"execution": {
|
145 |
+
"iopub.execute_input": "2023-07-12T19:18:36.471822Z",
|
146 |
+
"iopub.status.busy": "2023-07-12T19:18:36.470260Z",
|
147 |
+
"iopub.status.idle": "2023-07-12T19:18:36.788703Z",
|
148 |
+
"shell.execute_reply": "2023-07-12T19:18:36.787968Z",
|
149 |
+
"shell.execute_reply.started": "2023-07-12T19:18:36.471799Z"
|
150 |
+
},
|
151 |
+
"tags": []
|
152 |
+
},
|
153 |
+
"outputs": [
|
154 |
+
{
|
155 |
+
"name": "stdout",
|
156 |
+
"output_type": "stream",
|
157 |
+
"text": [
|
158 |
+
"0.23417302673938228\n",
|
159 |
+
"0.26324914249621933\n"
|
160 |
+
]
|
161 |
+
},
|
162 |
+
{
|
163 |
+
"data": {
|
164 |
+
"text/plain": [
|
165 |
+
"<matplotlib.lines.Line2D at 0x150591a3e230>"
|
166 |
+
]
|
167 |
+
},
|
168 |
+
"execution_count": 5,
|
169 |
+
"metadata": {},
|
170 |
+
"output_type": "execute_result"
|
171 |
+
},
|
172 |
+
{
|
173 |
+
"data": {
|
174 |
+
"image/png": "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O3ZszJw5M55//vmDnv/ss8/GzJkzY+zYsfHBD34wli5dWqRJgWIazL3hxz/+cZx99tlx1FFHRV1dXTQ1NcXTTz9dxGmBYhrs7x32++UvfxmVlZXxsY99bHgHBFIx2HvD7t2747bbbouGhoYYM2ZMHHvssfHII48UaVqgWAZ7b3jsscfiox/9aNTU1MTkyZPjM5/5TGzfvr1I0wLF8Nxzz8UFF1wQU6ZMiUwmE0888cQhr5FHZidEL5Lly5fHwoUL47bbbot169bFrFmz4txzz43NmzdnPf/111+P8847L2bNmhXr1q2LL33pS7FgwYL40Y9+VOTJgeE02HvDc889F2effXasXLky1q5dG2eccUZccMEFsW7duiJPDgy3wd4f9mttbY358+fHWWedVaRJgWLK595wySWXxM9//vN4+OGH4x//8R/j8ccfjz/6oz8q4tTAcBvsveGFF16I+fPnx1VXXRWvvPJKrFixIv7+7/8+rr766iJPDgyn9vb2+OhHPxr333//gM6XR+aWSZIkSXuIcnDqqafGySefHA899FDPsenTp8fcuXNjyZIl/c6/+eab48knn4yNGzf2HGtubo5f/epXsXr16qLMDAy/wd4bsjnhhBNi3rx5cfvttw/XmEAK8r0/XHrppXHcccdFRUVFPPHEE7F+/foiTAsUy2DvDU899VRceuml8dprr8URRxxRzFGBIhrsveFrX/taPPTQQ7Fp06aeY/fdd1/cfffd8eabbxZlZqC4MplM/OQnP4m5c+fmPEcemZsmehF0dnbG2rVrY86cOb2Oz5kzJ1588cWs16xevbrf+eecc06sWbMmurq6hm1WoHjyuTf0tXfv3tixY4c/FMMok+/94dFHH41NmzbFHXfcMdwjAinI597w5JNPRmNjY9x9991xzDHHxPHHHx833XRT7Nq1qxgjA0WQz73htNNOi7feeitWrlwZSZLEb3/72/jhD38Y559/fjFGBkqUPDK3yrQHKAfbtm2L7u7umDRpUq/jkyZNii1btmS9ZsuWLVnP37NnT2zbti0mT548bPMCxZHPvaGve+65J9rb2+OSSy4ZjhGBlORzf3j11Vfjlltuieeffz4qK/0WD0ajfO4Nr732WrzwwgsxduzY+MlPfhLbtm2La6+9Nt555x170WGUyOfecNppp8Vjjz0W8+bNiz/84Q+xZ8+e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",
|
175 |
+
"text/plain": [
|
176 |
+
"<Figure size 1500x500 with 1 Axes>"
|
177 |
+
]
|
178 |
+
},
|
179 |
+
"metadata": {},
|
180 |
+
"output_type": "display_data"
|
181 |
+
}
|
182 |
+
],
|
183 |
+
"source": [
|
184 |
+
"mean = np.mean(df[\"burned\"])\n",
|
185 |
+
"std = np.std(df[\"burned\"])\n",
|
186 |
+
"print(mean)\n",
|
187 |
+
"print(std)\n",
|
188 |
+
"#print(mean-std)\n",
|
189 |
+
"fig_1 = sns.displot(df, x=\"burned\", kind =\"ecdf\", height=5, aspect=3)\n",
|
190 |
+
"fig_1.ax.axvline(mean, color = \"red\")\n",
|
191 |
+
"#fig_1.ax.axvline(mean-std, color = \"blue\")\n",
|
192 |
+
"#fig_1.ax.axvline(std+mean, color = \"blue\")\n",
|
193 |
+
"#fig_1.savefig('size_mask_no_2.eps' , format = 'eps')"
|
194 |
+
]
|
195 |
+
},
|
196 |
+
{
|
197 |
+
"cell_type": "code",
|
198 |
+
"execution_count": 6,
|
199 |
+
"id": "826fa232-df66-44ec-bbe0-6d43459512f4",
|
200 |
+
"metadata": {
|
201 |
+
"execution": {
|
202 |
+
"iopub.execute_input": "2023-07-12T19:18:36.792861Z",
|
203 |
+
"iopub.status.busy": "2023-07-12T19:18:36.791384Z",
|
204 |
+
"iopub.status.idle": "2023-07-12T19:18:36.796827Z",
|
205 |
+
"shell.execute_reply": "2023-07-12T19:18:36.795906Z",
|
206 |
+
"shell.execute_reply.started": "2023-07-12T19:18:36.792836Z"
|
207 |
+
},
|
208 |
+
"tags": []
|
209 |
+
},
|
210 |
+
"outputs": [],
|
211 |
+
"source": [
|
212 |
+
"# wir sehen, dass die meisten Masken zwiscehn 0 und 20% des Bildes abdecken"
|
213 |
+
]
|
214 |
+
},
|
215 |
+
{
|
216 |
+
"cell_type": "code",
|
217 |
+
"execution_count": 7,
|
218 |
+
"id": "1574fdb1-6442-4803-b8d0-b8355e1c2377",
|
219 |
+
"metadata": {
|
220 |
+
"execution": {
|
221 |
+
"iopub.execute_input": "2023-07-12T19:18:36.801555Z",
|
222 |
+
"iopub.status.busy": "2023-07-12T19:18:36.799900Z",
|
223 |
+
"iopub.status.idle": "2023-07-12T19:18:36.805446Z",
|
224 |
+
"shell.execute_reply": "2023-07-12T19:18:36.804561Z",
|
225 |
+
"shell.execute_reply.started": "2023-07-12T19:18:36.801531Z"
|
226 |
+
},
|
227 |
+
"tags": []
|
228 |
+
},
|
229 |
+
"outputs": [],
|
230 |
+
"source": [
|
231 |
+
"# ein treshhold von 2% für die Masken sorgt schon dafür, dass der Datensatz ausgeglichener wirkt"
|
232 |
+
]
|
233 |
+
},
|
234 |
+
{
|
235 |
+
"cell_type": "code",
|
236 |
+
"execution_count": 12,
|
237 |
+
"id": "e79099d4-e737-4909-9b18-1e900e6d73e0",
|
238 |
+
"metadata": {
|
239 |
+
"execution": {
|
240 |
+
"iopub.execute_input": "2023-07-12T19:24:35.628647Z",
|
241 |
+
"iopub.status.busy": "2023-07-12T19:24:35.628293Z",
|
242 |
+
"iopub.status.idle": "2023-07-12T19:24:35.854670Z",
|
243 |
+
"shell.execute_reply": "2023-07-12T19:24:35.853911Z",
|
244 |
+
"shell.execute_reply.started": "2023-07-12T19:24:35.628618Z"
|
245 |
+
},
|
246 |
+
"tags": []
|
247 |
+
},
|
248 |
+
"outputs": [
|
249 |
+
{
|
250 |
+
"data": {
|
251 |
+
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAApwUlEQVR4nO3dfXBU9aH/8c+akDWEZC8hZDeRNVAFrpoABbxIKs+QkAqIOIVWB4migkA0A1w0eL2mlhKgBfTKlNpeLiCiwRlEveVBgjwoptQQS3nQ4UINEGrWVAxZgukGwvn90fH8XEiADYn5JrxfM2fGPee753wP0wPvnn1yWJZlCQAAwCA3NPcEAAAALkagAAAA4xAoAADAOAQKAAAwDoECAACMQ6AAAADjECgAAMA4BAoAADBOeHNPoCEuXLigL774QtHR0XI4HM09HQAAcBUsy9KZM2eUmJioG264/D2SFhkoX3zxhbxeb3NPAwAANEBpaak6dep02TEtMlCio6Ml/fMEY2Jimnk2AADgavj9fnm9Xvvf8ctpkYHy7cs6MTExBAoAAC3M1bw9gzfJAgAA4xAoAADAOAQKAAAwDoECAACMQ6AAAADjECgAAMA4BAoAADAOgQIAAIxDoAAAAOMQKAAAwDgECgAAMA6BAgAAjEOgAAAA4xAoAADAOOHNPQETdX5mY3NPATDWsQX3NPcUAFwHuIMCAACME1KgLF++XD169FBMTIxiYmLUv39/bd682d6emZkph8MRtNx1111B+wgEAsrKylJcXJyioqI0ZswYnTx5snHOBgAAtAohBUqnTp20YMEC7d27V3v37tXQoUN177336tChQ/aYkSNHqqyszF42bdoUtI/s7Gxt2LBB+fn52r17t6qqqjRq1CjV1tY2zhkBAIAWL6T3oIwePTro8S9/+UstX75ce/bs0R133CFJcjqd8ng8dT6/srJSK1as0Jo1azR8+HBJ0muvvSav16tt27YpPT29IecAAABamQa/B6W2tlb5+fk6e/as+vfvb6/fuXOn4uPj1a1bNz322GMqLy+3txUXF+vcuXNKS0uz1yUmJio5OVmFhYX1HisQCMjv9wctAACg9Qo5UA4cOKB27drJ6XRq6tSp2rBhg26//XZJUkZGhtauXavt27dr8eLFKioq0tChQxUIBCRJPp9PERERat++fdA+3W63fD5f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",
|
252 |
+
"text/plain": [
|
253 |
+
"<Figure size 640x480 with 1 Axes>"
|
254 |
+
]
|
255 |
+
},
|
256 |
+
"metadata": {},
|
257 |
+
"output_type": "display_data"
|
258 |
+
}
|
259 |
+
],
|
260 |
+
"source": [
|
261 |
+
"res_has_pre = []\n",
|
262 |
+
"res_no_pre = []\n",
|
263 |
+
"with h5py.File(fn, \"r\") as fd:\n",
|
264 |
+
" for name, ds in fd.items():\n",
|
265 |
+
" if \"pre_fire\" in ds:\n",
|
266 |
+
" res_has_pre.append(name)\n",
|
267 |
+
" else:\n",
|
268 |
+
" res_no_pre.append(name)\n",
|
269 |
+
" \n",
|
270 |
+
"x = [\"has_pre_fire\", \"missing_pre_fire\"] # X-axis values\n",
|
271 |
+
"y = [len(res_has_pre), len(res_no_pre)] # Y-axis values\n",
|
272 |
+
"\n",
|
273 |
+
"plt.bar(x, y)\n",
|
274 |
+
"#plt.show()\n",
|
275 |
+
"\n",
|
276 |
+
"plt.savefig('missing_prefire.eps')"
|
277 |
+
]
|
278 |
+
},
|
279 |
+
{
|
280 |
+
"cell_type": "code",
|
281 |
+
"execution_count": null,
|
282 |
+
"id": "664466a8-906e-46c2-b269-336450464187",
|
283 |
+
"metadata": {
|
284 |
+
"tags": []
|
285 |
+
},
|
286 |
+
"outputs": [],
|
287 |
+
"source": []
|
288 |
+
},
|
289 |
+
{
|
290 |
+
"cell_type": "code",
|
291 |
+
"execution_count": null,
|
292 |
+
"id": "5f48ae8f-32e9-457f-bf9a-e6aeddf2e86f",
|
293 |
+
"metadata": {
|
294 |
+
"execution": {
|
295 |
+
"iopub.status.busy": "2023-07-12T19:18:37.515168Z",
|
296 |
+
"iopub.status.idle": "2023-07-12T19:18:37.516757Z",
|
297 |
+
"shell.execute_reply": "2023-07-12T19:18:37.516583Z",
|
298 |
+
"shell.execute_reply.started": "2023-07-12T19:18:37.516563Z"
|
299 |
+
},
|
300 |
+
"tags": []
|
301 |
+
},
|
302 |
+
"outputs": [],
|
303 |
+
"source": [
|
304 |
+
"df"
|
305 |
+
]
|
306 |
+
},
|
307 |
+
{
|
308 |
+
"cell_type": "code",
|
309 |
+
"execution_count": null,
|
310 |
+
"id": "5cc93207-9157-459f-aab1-c712e6714b10",
|
311 |
+
"metadata": {},
|
312 |
+
"outputs": [],
|
313 |
+
"source": []
|
314 |
+
}
|
315 |
+
],
|
316 |
+
"metadata": {
|
317 |
+
"kernelspec": {
|
318 |
+
"display_name": "Python 3.10 / DM",
|
319 |
+
"language": "python",
|
320 |
+
"name": "py310-dm"
|
321 |
+
},
|
322 |
+
"language_info": {
|
323 |
+
"codemirror_mode": {
|
324 |
+
"name": "ipython",
|
325 |
+
"version": 3
|
326 |
+
},
|
327 |
+
"file_extension": ".py",
|
328 |
+
"mimetype": "text/x-python",
|
329 |
+
"name": "python",
|
330 |
+
"nbconvert_exporter": "python",
|
331 |
+
"pygments_lexer": "ipython3",
|
332 |
+
"version": "3.10.10"
|
333 |
+
}
|
334 |
+
},
|
335 |
+
"nbformat": 4,
|
336 |
+
"nbformat_minor": 5
|
337 |
+
}
|
main.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch.cuda
|
2 |
+
|
3 |
+
import chabud as ch
|
4 |
+
|
5 |
+
ds_path = "A:/CodingProjekte/DataMining/src/train_eval.hdf5"
|
6 |
+
|
7 |
+
# Press the green button in the gutter to run the script.
|
8 |
+
if __name__ == '__main__':
|
9 |
+
print(ch.__version__)
|
10 |
+
print(torch.cuda.is_available())
|
11 |
+
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
12 |
+
channels = ["band_1", "band_2", "band_3", "band_4", "band_5", "band_6", "band_7", "band_8", "band_8a", "band_9",
|
13 |
+
"band_11", "band_12", "nbr", "ndvi", "gndvi", "evi", "avi", "savi", "ndmi", "msi", "gci", "bsi", "ndwi",
|
14 |
+
"ndgi"]
|
15 |
+
# channels = ["band_1", "band_2", "band_3", "band_4", "band_5", "band_6", "band_7", "band_8", "band_8a", "band_9",
|
16 |
+
# "band_11", "band_12", "nbr", "ndmi", "ndvi", "bsi", "ndwi"]
|
17 |
+
channels_fun = []
|
18 |
+
|
19 |
+
for channel in channels:
|
20 |
+
channels_fun.append(ch.CHANNEL_MAP[channel])
|
21 |
+
|
22 |
+
ch.main(accelerator="gpu",
|
23 |
+
datafile=ds_path,
|
24 |
+
batch_size=5,
|
25 |
+
learning_rate=0.00025,
|
26 |
+
channels=channels_fun,
|
27 |
+
n_cpus=0,
|
28 |
+
model="unet",
|
29 |
+
encoder="resnet34",
|
30 |
+
encoder_depth=5,
|
31 |
+
encoder_weights="imagenet",
|
32 |
+
loss="dice",
|
33 |
+
train_use_pre_fire=False,
|
34 |
+
train_use_augmentation=True)
|
35 |
+
|
36 |
+
|
submission.py
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import pandas as pd
|
3 |
+
import h5py
|
4 |
+
import torch
|
5 |
+
from trimesh.voxel.runlength import dense_to_brle
|
6 |
+
from pathlib import Path
|
7 |
+
from matplotlib.colors import ListedColormap
|
8 |
+
from collections import defaultdict
|
9 |
+
from scipy import ndimage as ski
|
10 |
+
from typing import Any, Union, Dict, Literal
|
11 |
+
from numpy.typing import NDArray
|
12 |
+
import matplotlib as plt
|
13 |
+
|
14 |
+
import chabud
|
15 |
+
from pathlib import Path
|
16 |
+
dataset = Path("A:/CodingProjekte/DataMining/src/train_eval.hdf5")
|
17 |
+
#Es liegen 15 vortrainierte Modelle auf dem Server im Verzeichnis
|
18 |
+
#/global/public/chabud-ecml-pkdd2023/checkpoints/.
|
19 |
+
#Sie können sich verfügbaren Checkpoints wie folgt anzeigen lassen:
|
20 |
+
ckpt = Path('A:/CodingProjekte/DataMining/src/lightning_logs/version_30/checkpoints/model-epoch=25-val_iou=0.00.ckpt')
|
21 |
+
|
22 |
+
#Sie können einen beliebigen Checkpoint wie folgt laden:
|
23 |
+
mdl = chabud.FireModel.load_from_checkpoint(ckpt, map_location="cpu")
|
24 |
+
|
25 |
+
# Vom Modell `mdl` benötigte Kanäle extrahieren
|
26 |
+
# channels = np.stack([c(bands) for c in mdl.channels])
|
27 |
+
|
28 |
+
|
29 |
+
# with torch.set_grad_enabled(False):
|
30 |
+
# # Modell auf 1xlen(channels)x512x512 großen Tensor anwenden
|
31 |
+
# # D.h. wir haben eine Batchgröße von 1 (ineffizient aber einfach).
|
32 |
+
# print(channels)
|
33 |
+
# # channels = channels.astype(float)
|
34 |
+
# pred = mdl.forward(torch.Tensor(channels[np.newaxis, ...])).sigmoid() > 0.5
|
35 |
+
# # Ersten beiden Dimensionen (batch und channel) löschen und in ein numpy Array wandeln
|
36 |
+
# pred = pred[0, 0, ...].detach().numpy()
|
37 |
+
|
38 |
+
|
39 |
+
def process_dataset(scene, bands, true):
|
40 |
+
rgb = ski.exposure.adjust_gamma(np.clip(bands[..., [3, 2, 1]], 0, 1), 0.4)
|
41 |
+
|
42 |
+
channels = np.stack([c(bands) for c in mdl.channels])
|
43 |
+
with torch.set_grad_enabled(False):
|
44 |
+
pred = mdl.forward(torch.Tensor(channels[np.newaxis, ...])).sigmoid() > 0.5
|
45 |
+
pred = pred[0, 0, ...].detach().numpy()
|
46 |
+
|
47 |
+
cmap = ListedColormap(["white", "tab:brown", "tab:orange", "tab:blue"])
|
48 |
+
mask = np.zeros_like(pred, dtype=int)
|
49 |
+
mask = np.where(true & pred, 1, mask)
|
50 |
+
mask = np.where(~true & pred, 2, mask)
|
51 |
+
mask = np.where(true & ~pred, 3, mask)
|
52 |
+
|
53 |
+
true_edge = ski.feature.canny(true.astype("float")).astype("uint8")
|
54 |
+
pred_edge = ski.feature.canny(pred.astype("float")).astype("uint8")
|
55 |
+
|
56 |
+
fig, (axm, axi) = plt.subplots(ncols=2, figsize=(20, 10))
|
57 |
+
axm.imshow(mask, cmap=cmap, interpolation="nearest")
|
58 |
+
|
59 |
+
axi.imshow(rgb, interpolation="nearest")
|
60 |
+
axi.imshow(true_edge, cmap=ListedColormap(["#00000000", "tab:blue"]), interpolation="nearest")
|
61 |
+
axi.imshow(pred_edge, cmap=ListedColormap(["#00000000", "tab:orange"]), interpolation="nearest")
|
62 |
+
|
63 |
+
for ax in [axm, axi]:
|
64 |
+
ax.axes.xaxis.set_ticklabels([])
|
65 |
+
ax.axes.yaxis.set_ticklabels([])
|
66 |
+
|
67 |
+
fig.tight_layout()
|
68 |
+
|
69 |
+
fig.savefig(f"masks/{scene}-f_{dataset.attrs['fold']}.png")
|
70 |
+
plt.close()
|
71 |
+
# class RandomModel:
|
72 |
+
# def __init__(self, shape):
|
73 |
+
# self.shape = shape
|
74 |
+
# return
|
75 |
+
|
76 |
+
# def __call__(self, input):
|
77 |
+
# # input is ignored, just generate some random predictions
|
78 |
+
# return np.random.randint(0, 2, size=self.shape, dtype=bool)
|
79 |
+
|
80 |
+
class FixedModel:
|
81 |
+
def __init__(self, shape) -> None:
|
82 |
+
self.shape = shape
|
83 |
+
return
|
84 |
+
|
85 |
+
def __call__(self, input) -> Any:
|
86 |
+
# input is ignored, just generate a mask filled with zeros, with fixed pixels set to 1
|
87 |
+
mask = np.zeros(self.shape, dtype=bool)
|
88 |
+
mask[100:250, 100:250] = True
|
89 |
+
return mask
|
90 |
+
|
91 |
+
|
92 |
+
def retrieve_validation_fold(path: Union[str, Path]) -> Dict[str, NDArray]:
|
93 |
+
result = defaultdict(dict)
|
94 |
+
with h5py.File(path, 'r') as fp:
|
95 |
+
for uuid, values in fp.items():
|
96 |
+
if values.attrs['fold'] != 0:
|
97 |
+
continue
|
98 |
+
|
99 |
+
result[uuid]['post'] = values['post_fire'][...]
|
100 |
+
# result[uuid]['pre'] = values['pre_fire'][...]
|
101 |
+
|
102 |
+
return dict(result)
|
103 |
+
|
104 |
+
|
105 |
+
def compute_submission_mask(id: str, mask: NDArray):
|
106 |
+
brle = dense_to_brle(mask.astype(bool).flatten())
|
107 |
+
return {"id": id, "rle_mask": brle, "index": np.arange(len(brle))}
|
108 |
+
|
109 |
+
|
110 |
+
#der Code aus dem letzten Workshop
|
111 |
+
class PPModel:
|
112 |
+
def __init__(self,model):
|
113 |
+
self._model = model
|
114 |
+
self._model.eval()
|
115 |
+
|
116 |
+
def __call__(self,bands) -> Any:
|
117 |
+
#preprocessing
|
118 |
+
bands = bands /10000
|
119 |
+
channels = np.stack([c(bands) for c in self._model.channels])
|
120 |
+
channels = torch.Tensor(channels[np.newaxis, ...])
|
121 |
+
#Modell auswerten
|
122 |
+
with torch.set_grad_enabled(False):
|
123 |
+
mask = self._model.forward(channels).sigmoid() > 0.5
|
124 |
+
#postprocessing
|
125 |
+
mask = mask[0,0, ...].detach().numpy()
|
126 |
+
return mask
|
127 |
+
|
128 |
+
|
129 |
+
|
130 |
+
if __name__ == '__main__':
|
131 |
+
validation_fold = retrieve_validation_fold('train_eval.hdf5')
|
132 |
+
|
133 |
+
# use a list to accumulate results
|
134 |
+
result = []
|
135 |
+
# instantiate the model
|
136 |
+
# model = FixedModel(shape=(512, 512))
|
137 |
+
model = PPModel(mdl)
|
138 |
+
for uuid in validation_fold:
|
139 |
+
input_images = validation_fold[uuid]['post']
|
140 |
+
|
141 |
+
# perform the prediction
|
142 |
+
predicted = model(input_images)
|
143 |
+
# convert the prediction in RLE format
|
144 |
+
encoded_prediction = compute_submission_mask(uuid, predicted)
|
145 |
+
result.append(pd.DataFrame(encoded_prediction))
|
146 |
+
|
147 |
+
# concatenate all dataframes
|
148 |
+
submission_df = pd.concat(result)
|
149 |
+
submission_df.to_csv('predictions.csv', index=False)
|