Upload 14 files
Browse files- ensemble/ft_g_1dpwdeeplabv3.json +5 -3
- ensemble/ft_g_1dpwdeeplabv3.pt2 +1 -1
- ensemble/ft_g_1dpwseg.json +5 -3
- ensemble/ft_g_1dpwseg.pt2 +1 -1
- ensemble/ft_g_1dpwunet.json +5 -3
- ensemble/ft_g_1dpwunet.pt2 +1 -1
- ensemble/ft_g_1dpwunetpp.json +5 -3
- ensemble/ft_g_1dpwunetpp.pt2 +1 -1
- ensemble/ft_g_deeplabv3.json +5 -3
- ensemble/ft_g_deeplabv3.pt2 +1 -1
- ensemble/ft_g_segformer.json +5 -3
- ensemble/ft_g_segformer.pt2 +1 -1
- ensemble/load.py +84 -71
ensemble/ft_g_1dpwdeeplabv3.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T09:09:20Z",
|
| 44 |
"created": "2025-10-27T09:09:20Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "DeepLabV3 + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWDEEPLABV3 Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwdeeplabv3_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T09:09:20Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T09:09:20Z",
|
| 44 |
"created": "2025-10-27T09:09:20Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:25.792758Z",
|
| 46 |
"description": "DeepLabV3 + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWDEEPLABV3 Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwdeeplabv3_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:25.792758Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T09:09:20Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_1dpwdeeplabv3.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 55868251
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:eb1a97144e6404ac8b197c5dc3bfaf91b00abe53a80563986a69f6cb39f8361a
|
| 3 |
size 55868251
|
ensemble/ft_g_1dpwseg.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:10:41Z",
|
| 44 |
"created": "2025-10-27T10:10:41Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "SegFormer + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWSEG Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwseg_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T10:10:41Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:10:41Z",
|
| 44 |
"created": "2025-10-27T10:10:41Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:30.990281Z",
|
| 46 |
"description": "SegFormer + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWSEG Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwseg_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:30.990281Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T10:10:41Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_1dpwseg.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 16934922
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5fd1141ad3f77704948e9adf7ebe5edfdd2e1e1aad483fe42aa8616b7c0416da
|
| 3 |
size 16934922
|
ensemble/ft_g_1dpwunet.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:31:37Z",
|
| 44 |
"created": "2025-10-27T10:31:37Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "UNet + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWUNET Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwunet_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T10:31:37Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:31:37Z",
|
| 44 |
"created": "2025-10-27T10:31:37Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:14.166827Z",
|
| 46 |
"description": "UNet + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWUNET Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwunet_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:14.166827Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T10:31:37Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_1dpwunet.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 31813924
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b7fcaee1a0722d51acd9eb7f01d465fa32860865825f33e1531c835f216e71a9
|
| 3 |
size 31813924
|
ensemble/ft_g_1dpwunetpp.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T09:45:39Z",
|
| 44 |
"created": "2025-10-27T09:45:39Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "UNet++ + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWUNETPP Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwunetpp_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T09:45:39Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T09:45:39Z",
|
| 44 |
"created": "2025-10-27T09:45:39Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:07.449926Z",
|
| 46 |
"description": "UNet++ + PixelWise MLP architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "1DPWUNETPP Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "1dpwunetpp_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:07.449926Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T09:45:39Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_1dpwunetpp.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 32840445
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c6bf4096004d9af6e2a954295e970d6a713ed0ba582cb0511752fe1855ac32a0
|
| 3 |
size 32840445
|
ensemble/ft_g_deeplabv3.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T11:37:50Z",
|
| 44 |
"created": "2025-10-27T11:37:50Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "DeepLabV3 architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "DEEPLABV3 Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "deeplabv3_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T11:37:50Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T11:37:50Z",
|
| 44 |
"created": "2025-10-27T11:37:50Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:45.623530Z",
|
| 46 |
"description": "DeepLabV3 architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "DEEPLABV3 Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "deeplabv3_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:45.623530Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T11:37:50Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_deeplabv3.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 55758820
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d20aea4a3537a852de8b32ca2fa1fcec6d79578e6dc0b981f28a6061d6532fe6
|
| 3 |
size 55758820
|
ensemble/ft_g_segformer.json
CHANGED
|
@@ -42,7 +42,7 @@
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:55:12Z",
|
| 44 |
"created": "2025-10-27T10:55:12Z",
|
| 45 |
-
"updated": "2025-11-
|
| 46 |
"description": "SegFormer architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "SEGFORMER Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "segformer_fdr4vgt_cloudmask_ft",
|
|
@@ -131,7 +131,9 @@
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
-
"post_processing_function": "Apply threshold
|
|
|
|
|
|
|
| 135 |
"value_range": [
|
| 136 |
0.0,
|
| 137 |
1.0
|
|
@@ -163,7 +165,7 @@
|
|
| 163 |
"custom:export_format": "torch.export.pt2",
|
| 164 |
"custom:has_sigmoid": true,
|
| 165 |
"custom:sigmoid_location": "built-in wrapper",
|
| 166 |
-
"custom:export_datetime": "2025-11-
|
| 167 |
"custom:training_datetime": "2025-10-27T10:55:12Z",
|
| 168 |
"custom:training_stage": "fine-tuning",
|
| 169 |
"custom:base_model_source": "global_cloudmask",
|
|
|
|
| 42 |
"properties": {
|
| 43 |
"datetime": "2025-10-27T10:55:12Z",
|
| 44 |
"created": "2025-10-27T10:55:12Z",
|
| 45 |
+
"updated": "2025-11-09T18:20:20.306738Z",
|
| 46 |
"description": "SegFormer architecture fine-tuned for cloud detection in VGT-1, VGT-2, and PROBA-V satellite imagery from the FDR4VGT harmonized dataset.",
|
| 47 |
"title": "SEGFORMER Cloud Detection Model - VGT1/VGT2/Proba-V (Fine-tuned)",
|
| 48 |
"mlm:name": "segformer_fdr4vgt_cloudmask_ft",
|
|
|
|
| 131 |
"color_hint": "FFFF00"
|
| 132 |
}
|
| 133 |
],
|
| 134 |
+
"post_processing_function": "Apply threshold to get binary mask. Standard threshold: 0.5. Recommended (balanced) threshold: 0.4.",
|
| 135 |
+
"standard_threshold": 0.5,
|
| 136 |
+
"recommended_threshold": 0.4,
|
| 137 |
"value_range": [
|
| 138 |
0.0,
|
| 139 |
1.0
|
|
|
|
| 165 |
"custom:export_format": "torch.export.pt2",
|
| 166 |
"custom:has_sigmoid": true,
|
| 167 |
"custom:sigmoid_location": "built-in wrapper",
|
| 168 |
+
"custom:export_datetime": "2025-11-09T18:20:20.306738Z",
|
| 169 |
"custom:training_datetime": "2025-10-27T10:55:12Z",
|
| 170 |
"custom:training_stage": "fine-tuning",
|
| 171 |
"custom:base_model_source": "global_cloudmask",
|
ensemble/ft_g_segformer.pt2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 16825964
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:792337973bec27a2a4cd84ccaae35cccd4dee272055b74fef08cdf8882a6c824
|
| 3 |
size 16825964
|
ensemble/load.py
CHANGED
|
@@ -2,17 +2,12 @@ import torch
|
|
| 2 |
import torch.nn
|
| 3 |
import pathlib
|
| 4 |
import pystac
|
| 5 |
-
import math
|
| 6 |
from typing import Literal
|
| 7 |
-
|
| 8 |
-
# --- Imports necesarios para la inferencia ---
|
| 9 |
import numpy as np
|
| 10 |
import itertools
|
| 11 |
from tqdm import tqdm
|
| 12 |
|
| 13 |
-
#
|
| 14 |
-
# Esta versión es flexible y compatible con tu 'predict_large_v3'
|
| 15 |
-
# (Solo devuelve probabilidades, no incertidumbre)
|
| 16 |
class EnsembleModel(torch.nn.Module):
|
| 17 |
def __init__(self, *models, mode="max"):
|
| 18 |
super(EnsembleModel, self).__init__()
|
|
@@ -31,32 +26,20 @@ class EnsembleModel(torch.nn.Module):
|
|
| 31 |
return None
|
| 32 |
|
| 33 |
concatenated_outputs = torch.cat(outputs, dim=1)
|
| 34 |
-
|
| 35 |
-
# ¡IMPORTANTE! Tu predict_large_v3 espera UNA salida (probabilidades).
|
| 36 |
-
# Esta lógica ha sido adaptada de tu 'EnsembleModel' original.
|
| 37 |
if self.mode == "max":
|
| 38 |
-
#
|
| 39 |
output_probs = torch.max(concatenated_outputs, dim=1, keepdim=True)[0]
|
| 40 |
elif self.mode == "mean":
|
| 41 |
output_probs = torch.mean(concatenated_outputs, dim=1, keepdim=True)
|
| 42 |
elif self.mode == "min":
|
| 43 |
output_probs = torch.min(concatenated_outputs, dim=1, keepdim=True)[0]
|
| 44 |
elif self.mode == "none":
|
| 45 |
-
return concatenated_outputs #
|
| 46 |
else:
|
| 47 |
raise ValueError("Mode must be 'min', 'mean', or 'max'.")
|
| 48 |
|
| 49 |
-
return output_probs #
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
# --- 2. API DE MLSTAC (FUNCIONES REQUERIDAS) ---
|
| 53 |
-
|
| 54 |
-
def trainable_model(path: pathlib.Path, stac_item: pystac.Item, *args, **kwargs):
|
| 55 |
-
"""
|
| 56 |
-
Este modelo de ensemble no soporta re-entrenamiento.
|
| 57 |
-
"""
|
| 58 |
-
print("El modelo de ensemble no está disponible en modo de entrenamiento.")
|
| 59 |
-
return None
|
| 60 |
|
| 61 |
def compiled_model(
|
| 62 |
path: pathlib.Path,
|
|
@@ -65,37 +48,35 @@ def compiled_model(
|
|
| 65 |
*args, **kwargs
|
| 66 |
) -> EnsembleModel:
|
| 67 |
"""
|
| 68 |
-
|
| 69 |
-
|
| 70 |
"""
|
| 71 |
-
print("
|
| 72 |
|
| 73 |
model_paths = []
|
| 74 |
|
| 75 |
for asset_key, asset in stac_item.assets.items():
|
| 76 |
if asset.href.endswith(".pt2"):
|
| 77 |
-
print(f" >
|
| 78 |
model_paths.append(asset.href)
|
| 79 |
|
| 80 |
if not model_paths:
|
| 81 |
-
raise ValueError("No
|
| 82 |
|
| 83 |
-
print(f"
|
| 84 |
|
| 85 |
model_paths.sort()
|
| 86 |
models = [torch.export.load(p).module() for p in model_paths]
|
| 87 |
|
| 88 |
cloud_model = EnsembleModel(*models, mode=mode)
|
| 89 |
|
| 90 |
-
print("Ensemble
|
| 91 |
return cloud_model
|
| 92 |
|
| 93 |
|
| 94 |
-
# --- 3. FUNCIONES DE INFERENCIA (HERRAMIENTAS) ---
|
| 95 |
-
|
| 96 |
def define_iteration(dimension: tuple, chunk_size: int, overlap: int = 0):
|
| 97 |
"""
|
| 98 |
-
|
| 99 |
"""
|
| 100 |
dimy, dimx = dimension
|
| 101 |
if chunk_size > max(dimx, dimy):
|
|
@@ -111,7 +92,7 @@ def define_iteration(dimension: tuple, chunk_size: int, overlap: int = 0):
|
|
| 111 |
|
| 112 |
def fix_lastchunk(iterchunks, s2dim, chunk_size):
|
| 113 |
"""
|
| 114 |
-
|
| 115 |
"""
|
| 116 |
itercontainer = []
|
| 117 |
for index_i, index_j in iterchunks:
|
|
@@ -120,37 +101,39 @@ def fix_lastchunk(iterchunks, s2dim, chunk_size):
|
|
| 120 |
if index_j + chunk_size > s2dim[1]:
|
| 121 |
index_j = max(s2dim[1] - chunk_size, 0)
|
| 122 |
itercontainer.append((index_i, index_j))
|
| 123 |
-
return list(set(itercontainer)) #
|
| 124 |
|
| 125 |
|
| 126 |
-
def
|
| 127 |
-
|
| 128 |
-
|
| 129 |
chunk_size: int = 512,
|
| 130 |
-
overlap: int =
|
| 131 |
-
device: str = "cpu"
|
|
|
|
| 132 |
) -> np.ndarray:
|
| 133 |
"""
|
| 134 |
-
|
| 135 |
|
| 136 |
-
|
| 137 |
-
1.
|
| 138 |
-
2.
|
|
|
|
| 139 |
|
| 140 |
-
Compatible
|
| 141 |
-
-
|
| 142 |
-
-
|
| 143 |
"""
|
| 144 |
|
| 145 |
-
# 1)
|
| 146 |
-
if
|
| 147 |
-
raise ValueError(f"Input array
|
| 148 |
|
| 149 |
-
bands, height, width =
|
| 150 |
-
print(f"
|
| 151 |
|
| 152 |
-
# 2)
|
| 153 |
-
output_array = np.
|
| 154 |
|
| 155 |
# 3) Get the list of tile offsets
|
| 156 |
coords = define_iteration(
|
|
@@ -159,36 +142,59 @@ def predict_large_array(
|
|
| 159 |
overlap=overlap
|
| 160 |
)
|
| 161 |
|
| 162 |
-
# 4)
|
| 163 |
try:
|
| 164 |
-
|
| 165 |
-
for p in
|
| 166 |
p.requires_grad = False
|
| 167 |
-
|
| 168 |
except (NotImplementedError, AttributeError):
|
| 169 |
-
#
|
| 170 |
-
|
| 171 |
|
| 172 |
-
# 5)
|
| 173 |
for idx, (row_off, col_off) in enumerate(tqdm(coords, desc="Inference")):
|
| 174 |
|
| 175 |
-
# (a)
|
| 176 |
-
patch =
|
| 177 |
:,
|
| 178 |
row_off : row_off + chunk_size,
|
| 179 |
col_off : col_off + chunk_size
|
| 180 |
]
|
| 181 |
|
| 182 |
-
# (b)
|
| 183 |
patch_tensor = torch.from_numpy(patch).float().unsqueeze(0).to(device)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
with torch.no_grad():
|
| 185 |
-
#
|
| 186 |
-
probs =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
| 188 |
-
#
|
| 189 |
-
result = probs.
|
| 190 |
|
| 191 |
-
# (c-f)
|
| 192 |
if col_off == 0:
|
| 193 |
offset_x = 0
|
| 194 |
else:
|
|
@@ -213,19 +219,26 @@ def predict_large_array(
|
|
| 213 |
length_y = chunk_size - (overlap // 2)
|
| 214 |
sub_y_start = overlap // 2 if row_off != 0 else 0
|
| 215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
to_write = result[
|
| 217 |
:,
|
| 218 |
sub_y_start : sub_y_start + length_y,
|
| 219 |
sub_x_start : sub_x_start + length_x
|
| 220 |
]
|
| 221 |
|
| 222 |
-
#
|
| 223 |
output_array[
|
| 224 |
:,
|
| 225 |
offset_y : offset_y + length_y,
|
| 226 |
offset_x : offset_x + length_x
|
| 227 |
] = to_write
|
| 228 |
|
| 229 |
-
print("
|
| 230 |
-
#
|
| 231 |
return output_array
|
|
|
|
| 2 |
import torch.nn
|
| 3 |
import pathlib
|
| 4 |
import pystac
|
|
|
|
| 5 |
from typing import Literal
|
|
|
|
|
|
|
| 6 |
import numpy as np
|
| 7 |
import itertools
|
| 8 |
from tqdm import tqdm
|
| 9 |
|
| 10 |
+
# Ensemble model for combining multiple models' outputs
|
|
|
|
|
|
|
| 11 |
class EnsembleModel(torch.nn.Module):
|
| 12 |
def __init__(self, *models, mode="max"):
|
| 13 |
super(EnsembleModel, self).__init__()
|
|
|
|
| 26 |
return None
|
| 27 |
|
| 28 |
concatenated_outputs = torch.cat(outputs, dim=1)
|
| 29 |
+
|
|
|
|
|
|
|
| 30 |
if self.mode == "max":
|
| 31 |
+
# Use keepdim=True to maintain (B, 1, H, W) and be safe
|
| 32 |
output_probs = torch.max(concatenated_outputs, dim=1, keepdim=True)[0]
|
| 33 |
elif self.mode == "mean":
|
| 34 |
output_probs = torch.mean(concatenated_outputs, dim=1, keepdim=True)
|
| 35 |
elif self.mode == "min":
|
| 36 |
output_probs = torch.min(concatenated_outputs, dim=1, keepdim=True)[0]
|
| 37 |
elif self.mode == "none":
|
| 38 |
+
return concatenated_outputs # Returns (B, N, H, W)
|
| 39 |
else:
|
| 40 |
raise ValueError("Mode must be 'min', 'mean', or 'max'.")
|
| 41 |
|
| 42 |
+
return output_probs # Returns (B, 1, H, W)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
def compiled_model(
|
| 45 |
path: pathlib.Path,
|
|
|
|
| 48 |
*args, **kwargs
|
| 49 |
) -> EnsembleModel:
|
| 50 |
"""
|
| 51 |
+
Loads the ensemble dynamically using the 'stac_item' (the ensemble.json)
|
| 52 |
+
as the ONLY source of truth.
|
| 53 |
"""
|
| 54 |
+
print("Loading ensemble dynamically from 'stac_item'...")
|
| 55 |
|
| 56 |
model_paths = []
|
| 57 |
|
| 58 |
for asset_key, asset in stac_item.assets.items():
|
| 59 |
if asset.href.endswith(".pt2"):
|
| 60 |
+
print(f" > Found model asset: {pathlib.Path(asset.href).name}")
|
| 61 |
model_paths.append(asset.href)
|
| 62 |
|
| 63 |
if not model_paths:
|
| 64 |
+
raise ValueError("No .pt2 files found in STAC item assets.")
|
| 65 |
|
| 66 |
+
print(f"Loading {len(model_paths)} .pt2 models (on CPU)...")
|
| 67 |
|
| 68 |
model_paths.sort()
|
| 69 |
models = [torch.export.load(p).module() for p in model_paths]
|
| 70 |
|
| 71 |
cloud_model = EnsembleModel(*models, mode=mode)
|
| 72 |
|
| 73 |
+
print("Ensemble loaded successfully on CPU.")
|
| 74 |
return cloud_model
|
| 75 |
|
| 76 |
|
|
|
|
|
|
|
| 77 |
def define_iteration(dimension: tuple, chunk_size: int, overlap: int = 0):
|
| 78 |
"""
|
| 79 |
+
Defines iteration strategy to traverse the image with overlap.
|
| 80 |
"""
|
| 81 |
dimy, dimx = dimension
|
| 82 |
if chunk_size > max(dimx, dimy):
|
|
|
|
| 92 |
|
| 93 |
def fix_lastchunk(iterchunks, s2dim, chunk_size):
|
| 94 |
"""
|
| 95 |
+
Adjusts last chunks to prevent them from exceeding boundaries.
|
| 96 |
"""
|
| 97 |
itercontainer = []
|
| 98 |
for index_i, index_j in iterchunks:
|
|
|
|
| 101 |
if index_j + chunk_size > s2dim[1]:
|
| 102 |
index_j = max(s2dim[1] - chunk_size, 0)
|
| 103 |
itercontainer.append((index_i, index_j))
|
| 104 |
+
return list(set(itercontainer)) # Returns unique values just in case
|
| 105 |
|
| 106 |
|
| 107 |
+
def predict_large(
|
| 108 |
+
image: np.ndarray,
|
| 109 |
+
model: torch.nn.Module,
|
| 110 |
chunk_size: int = 512,
|
| 111 |
+
overlap: int = 64,
|
| 112 |
+
device: str = "cpu",
|
| 113 |
+
nodata: float = 0.0
|
| 114 |
) -> np.ndarray:
|
| 115 |
"""
|
| 116 |
+
Predict a full 'image' (C, H, W) using overlapping patches.
|
| 117 |
|
| 118 |
+
This is a modified version of 'predict_large_v3' that:
|
| 119 |
+
1. Accepts an np.ndarray instead of file paths.
|
| 120 |
+
2. Returns an np.ndarray (probability mask) instead of saving to disk.
|
| 121 |
+
3. Handles tiles smaller than chunk_size via padding.
|
| 122 |
|
| 123 |
+
Compatible with:
|
| 124 |
+
- Normal models (with .eval())
|
| 125 |
+
- Exported models (.pt2) and Ensembles (without .eval())
|
| 126 |
"""
|
| 127 |
|
| 128 |
+
# 1) Validate input array dimensions
|
| 129 |
+
if image.ndim != 3:
|
| 130 |
+
raise ValueError(f"Input array must be (C, H, W). Received {image.shape}")
|
| 131 |
|
| 132 |
+
bands, height, width = image.shape
|
| 133 |
+
print(f"Starting prediction on array with shape: {(bands, height, width)}")
|
| 134 |
|
| 135 |
+
# 2) Initialize output array (1-band float) with nodata values
|
| 136 |
+
output_array = np.full((1, height, width), nodata, dtype=np.float32)
|
| 137 |
|
| 138 |
# 3) Get the list of tile offsets
|
| 139 |
coords = define_iteration(
|
|
|
|
| 142 |
overlap=overlap
|
| 143 |
)
|
| 144 |
|
| 145 |
+
# 4) Prepare model (compatibility logic for .pt2 models)
|
| 146 |
try:
|
| 147 |
+
model.eval()
|
| 148 |
+
for p in model.parameters():
|
| 149 |
p.requires_grad = False
|
| 150 |
+
model = model.to(device)
|
| 151 |
except (NotImplementedError, AttributeError):
|
| 152 |
+
# Exported model (.pt2) or EnsembleModel
|
| 153 |
+
model = model.to(device)
|
| 154 |
|
| 155 |
+
# 5) Iterate over tiles (using numpy only)
|
| 156 |
for idx, (row_off, col_off) in enumerate(tqdm(coords, desc="Inference")):
|
| 157 |
|
| 158 |
+
# (a) Read chunk (numpy slicing)
|
| 159 |
+
patch = image[
|
| 160 |
:,
|
| 161 |
row_off : row_off + chunk_size,
|
| 162 |
col_off : col_off + chunk_size
|
| 163 |
]
|
| 164 |
|
| 165 |
+
# (b) Convert to tensor and handle padding if tile is smaller than chunk_size
|
| 166 |
patch_tensor = torch.from_numpy(patch).float().unsqueeze(0).to(device)
|
| 167 |
+
_, _, h_tile, w_tile = patch_tensor.shape
|
| 168 |
+
|
| 169 |
+
# Calculate padding needed
|
| 170 |
+
pad_h = chunk_size - h_tile
|
| 171 |
+
pad_w = chunk_size - w_tile
|
| 172 |
+
|
| 173 |
+
# Apply padding if necessary
|
| 174 |
+
if pad_h > 0 or pad_w > 0:
|
| 175 |
+
patch_tensor = torch.nn.functional.pad(
|
| 176 |
+
patch_tensor, (0, pad_w, 0, pad_h), "constant", nodata
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
# Create mask for nodata areas (all bands are nodata)
|
| 180 |
+
mask_all = (patch_tensor == nodata).all(dim=1, keepdim=True)
|
| 181 |
+
|
| 182 |
+
# Forward pass
|
| 183 |
with torch.no_grad():
|
| 184 |
+
# Assume the model (or ensemble) returns probabilities (B, 1, H, W)
|
| 185 |
+
probs = model(patch_tensor)
|
| 186 |
+
|
| 187 |
+
# Apply nodata mask to output
|
| 188 |
+
probs = probs.masked_fill(mask_all, nodata)
|
| 189 |
+
|
| 190 |
+
# Remove batch dimension and ensure (1, H, W)
|
| 191 |
+
if probs.ndim == 4:
|
| 192 |
+
probs = probs.squeeze(0) # (1, H, W)
|
| 193 |
|
| 194 |
+
# Convert to numpy
|
| 195 |
+
result = probs.cpu().numpy() # (1, H, W)
|
| 196 |
|
| 197 |
+
# (c-f) Logic for partial writing
|
| 198 |
if col_off == 0:
|
| 199 |
offset_x = 0
|
| 200 |
else:
|
|
|
|
| 219 |
length_y = chunk_size - (overlap // 2)
|
| 220 |
sub_y_start = overlap // 2 if row_off != 0 else 0
|
| 221 |
|
| 222 |
+
# Ensure we don't exceed array bounds
|
| 223 |
+
if offset_y + length_y > height:
|
| 224 |
+
length_y = height - offset_y
|
| 225 |
+
if offset_x + length_x > width:
|
| 226 |
+
length_x = width - offset_x
|
| 227 |
+
|
| 228 |
+
# Extract the valid region from the result
|
| 229 |
to_write = result[
|
| 230 |
:,
|
| 231 |
sub_y_start : sub_y_start + length_y,
|
| 232 |
sub_x_start : sub_x_start + length_x
|
| 233 |
]
|
| 234 |
|
| 235 |
+
# Write to the output numpy array
|
| 236 |
output_array[
|
| 237 |
:,
|
| 238 |
offset_y : offset_y + length_y,
|
| 239 |
offset_x : offset_x + length_x
|
| 240 |
] = to_write
|
| 241 |
|
| 242 |
+
print("Prediction completed.")
|
| 243 |
+
# Return the array of shape (1, H, W)
|
| 244 |
return output_array
|