Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -30,8 +30,8 @@ SCALER_FILE = Path("mil_scaler.joblib")
|
|
| 30 |
FEATURES_FILE = Path("mil_features.joblib")
|
| 31 |
PHENO_FILE = Path("phenologythingy.csv")
|
| 32 |
SPECIES_STATS_FILE = Path("species_stats.csv")
|
| 33 |
-
MIN_BLOOM_THRESHOLD = float(os.environ.get("MIN_BLOOM_THRESHOLD",
|
| 34 |
-
MIN_PEAK_FOR_BELL = float(os.environ.get("MIN_PEAK_FOR_BELL",
|
| 35 |
|
| 36 |
ELEV_IMAGE_ID = "USGS/SRTMGL1_003"
|
| 37 |
BUFFER_METERS = int(os.environ.get("BUFFER_METERS", 200))
|
|
@@ -119,40 +119,71 @@ def gaussian_kernel(length=12, sigma=1.2):
|
|
| 119 |
kern = kern / kern.sum()
|
| 120 |
return kern
|
| 121 |
|
| 122 |
-
def smooth_monthly_probs(raw_probs, alpha=ALPHA, sigma=SMOOTH_SIGMA):
|
| 123 |
"""
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
3. pad circularly then convolve with gaussian kernel
|
| 129 |
-
4. normalize to sum to 1 and return percentages (0-100)
|
| 130 |
"""
|
| 131 |
-
a = np.asarray(raw_probs, dtype=float) / 100.0
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
if alpha != 1.0:
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
#
|
| 142 |
-
|
|
|
|
|
|
|
| 143 |
kern_range = np.arange(-pad, pad + 1)
|
| 144 |
kern = np.exp(-0.5 * (kern_range / sigma) ** 2)
|
| 145 |
kern = kern / kern.sum()
|
| 146 |
-
smoothed = np.convolve(padded, kern, mode=
|
| 147 |
-
# extract center portion
|
| 148 |
center = smoothed[pad:pad+12]
|
| 149 |
-
# clip small negatives or tiny numbers
|
| 150 |
center = np.clip(center, 0.0, None)
|
| 151 |
-
|
|
|
|
| 152 |
center = np.ones_like(center) / len(center)
|
| 153 |
-
|
|
|
|
| 154 |
norm = center / center.sum()
|
| 155 |
-
perc = (norm * 100.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
return perc.tolist()
|
| 157 |
|
| 158 |
def is_bell_shaped(perc_list):
|
|
@@ -746,8 +777,12 @@ async def predict_bloom(req: BloomPredictionRequest):
|
|
| 746 |
for mr in monthly_results
|
| 747 |
], dtype=float)
|
| 748 |
|
|
|
|
|
|
|
|
|
|
| 749 |
# Compute smoothed curve
|
| 750 |
monthly_perc = smooth_monthly_probs(raw_probs.tolist(), alpha=ALPHA, sigma=SMOOTH_SIGMA)
|
|
|
|
| 751 |
monthly_curve = {i+1: float(monthly_perc[i]) for i in range(12)}
|
| 752 |
|
| 753 |
# Check bell shape
|
|
|
|
| 30 |
FEATURES_FILE = Path("mil_features.joblib")
|
| 31 |
PHENO_FILE = Path("phenologythingy.csv")
|
| 32 |
SPECIES_STATS_FILE = Path("species_stats.csv")
|
| 33 |
+
MIN_BLOOM_THRESHOLD = float(os.environ.get("MIN_BLOOM_THRESHOLD", 20.0)) # minimum probability to predict species
|
| 34 |
+
MIN_PEAK_FOR_BELL = float(os.environ.get("MIN_PEAK_FOR_BELL", 25.0))
|
| 35 |
|
| 36 |
ELEV_IMAGE_ID = "USGS/SRTMGL1_003"
|
| 37 |
BUFFER_METERS = int(os.environ.get("BUFFER_METERS", 200))
|
|
|
|
| 119 |
kern = kern / kern.sum()
|
| 120 |
return kern
|
| 121 |
|
| 122 |
+
def smooth_monthly_probs(raw_probs, alpha=ALPHA, sigma=SMOOTH_SIGMA, min_curve_prob=MIN_CURVE_PROB):
|
| 123 |
"""
|
| 124 |
+
Robust smoothing + contrast stretch for raw monthly ML probabilities.
|
| 125 |
+
|
| 126 |
+
raw_probs: list/array length 12, values expected in [0,100]
|
| 127 |
+
Returns: list length 12, percentages summing to ~100
|
|
|
|
|
|
|
| 128 |
"""
|
| 129 |
+
a = np.asarray(raw_probs, dtype=float) / 100.0 # scale to 0-1
|
| 130 |
+
|
| 131 |
+
# If all zeros => return uniform (but avoid strict uniform by small floor)
|
| 132 |
+
if a.sum() == 0 or np.allclose(a, 0.0):
|
| 133 |
+
base = np.ones_like(a) * (min_curve_prob / 100.0)
|
| 134 |
+
base = base / base.sum()
|
| 135 |
+
return (base * 100.0).round(3).tolist()
|
| 136 |
+
|
| 137 |
+
# contrast stretch (min-max), but avoid tiny denominator
|
| 138 |
+
amin = float(a.min())
|
| 139 |
+
amax = float(a.max())
|
| 140 |
+
rng = amax - amin
|
| 141 |
+
if rng < 1e-4:
|
| 142 |
+
# values almost identical -> amplify relative differences using sqrt of original
|
| 143 |
+
a_cs = np.sqrt(a)
|
| 144 |
+
a_cs = a_cs - a_cs.min()
|
| 145 |
+
rng2 = a_cs.max() - a_cs.min()
|
| 146 |
+
if rng2 <= 1e-8:
|
| 147 |
+
a_cs = np.ones_like(a) / len(a)
|
| 148 |
+
else:
|
| 149 |
+
a_cs = a_cs / rng2
|
| 150 |
+
else:
|
| 151 |
+
a_cs = (a - amin) / (rng + 1e-12)
|
| 152 |
+
|
| 153 |
+
# small floor to avoid zeros everywhere
|
| 154 |
+
floor = min_curve_prob / 100.0
|
| 155 |
+
a_cs = np.clip(a_cs, floor * 0.001, None)
|
| 156 |
+
|
| 157 |
+
# apply sharpening exponent
|
| 158 |
if alpha != 1.0:
|
| 159 |
+
a_sh = np.power(a_cs, alpha)
|
| 160 |
+
else:
|
| 161 |
+
a_sh = a_cs
|
| 162 |
+
|
| 163 |
+
# circular pad and gaussian smooth
|
| 164 |
+
sigma = float(max(0.6, sigma))
|
| 165 |
+
pad = max(3, int(round(3 * sigma)))
|
| 166 |
+
padded = np.concatenate([a_sh[-pad:], a_sh, a_sh[:pad]])
|
| 167 |
kern_range = np.arange(-pad, pad + 1)
|
| 168 |
kern = np.exp(-0.5 * (kern_range / sigma) ** 2)
|
| 169 |
kern = kern / kern.sum()
|
| 170 |
+
smoothed = np.convolve(padded, kern, mode="same")
|
|
|
|
| 171 |
center = smoothed[pad:pad+12]
|
|
|
|
| 172 |
center = np.clip(center, 0.0, None)
|
| 173 |
+
|
| 174 |
+
if center.sum() <= 0:
|
| 175 |
center = np.ones_like(center) / len(center)
|
| 176 |
+
|
| 177 |
+
# Normalize & to percentages
|
| 178 |
norm = center / center.sum()
|
| 179 |
+
perc = (norm * 100.0)
|
| 180 |
+
# tiny rounding
|
| 181 |
+
perc = np.round(perc, 3)
|
| 182 |
+
# final safety: ensure sum ~= 100
|
| 183 |
+
s = float(perc.sum())
|
| 184 |
+
if abs(s - 100.0) > 0.001 and s > 0:
|
| 185 |
+
perc = perc * (100.0 / s)
|
| 186 |
+
|
| 187 |
return perc.tolist()
|
| 188 |
|
| 189 |
def is_bell_shaped(perc_list):
|
|
|
|
| 777 |
for mr in monthly_results
|
| 778 |
], dtype=float)
|
| 779 |
|
| 780 |
+
print("DEBUG raw_probs (months 1..12):", raw_probs.tolist())
|
| 781 |
+
print("DEBUG raw_probs stats -> min, max, mean:", float(raw_probs.min()), float(raw_probs.max()), float(raw_probs.mean()))
|
| 782 |
+
|
| 783 |
# Compute smoothed curve
|
| 784 |
monthly_perc = smooth_monthly_probs(raw_probs.tolist(), alpha=ALPHA, sigma=SMOOTH_SIGMA)
|
| 785 |
+
print("DEBUG monthly_perc:", monthly_perc)
|
| 786 |
monthly_curve = {i+1: float(monthly_perc[i]) for i in range(12)}
|
| 787 |
|
| 788 |
# Check bell shape
|