Spread capped failure samples across weak contexts
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Jens
2026-07-30 00:45:04 +02:00
parent 087704e326
commit c2859e5919
3 changed files with 162 additions and 8 deletions
+50 -8
View File
@@ -39,6 +39,30 @@ def dataset_validation_source(source_yaml: Path) -> str:
raise ValueError(f"Source dataset YAML has no validation source: {source_yaml}")
def spread_repeats(paths: list[str], *, sampling_round: int, lane: str) -> list[str]:
"""Deterministically spread adjacent repeats before a regional cap."""
indexed = enumerate(paths)
return [
path
for _index, path in sorted(
indexed,
key=lambda item: hashlib.sha256(
f"{sampling_round}:{lane}:{item[0]}:{item[1]}".encode()
).digest(),
)
]
def interleave(left: list[str], right: list[str]) -> list[str]:
combined: list[str] = []
for index in range(max(len(left), len(right))):
if index < len(left):
combined.append(left[index])
if index < len(right):
combined.append(right[index])
return combined
def build_sampling(
*,
summary: dict[str, Any],
@@ -128,6 +152,7 @@ def build_sampling(
)
base_paths_by_region: dict[str, list[str]] = {}
priority_positive_paths_by_region: dict[str, list[str]] = {}
extra_paths_by_region: dict[str, list[str]] = {}
selected_samples: set[str] = set()
protected_samples: set[str] = set()
@@ -161,9 +186,14 @@ def build_sampling(
)
path = str(Path(tile["image_path"]).resolve())
base_paths_by_region.setdefault(region, []).append(path)
priority_positives = priority_positive_paths_by_region.setdefault(region, [])
extras = extra_paths_by_region.setdefault(region, [])
repeated = [path] * (repeat - 1)
if tile["label_count"] == 0 and context_key in targeted_negative_contexts:
if tile["label_count"] > 0 and context_key in weak_recall_contexts:
# Preserve diagnostic positives before precision-oriented
# negatives when the regional cap truncates repeat entries.
priority_positives.extend(repeated)
elif tile["label_count"] == 0 and context_key in targeted_negative_contexts:
# Preserve the most diagnostic hard-negative repeats when the
# regional cap has to remove lower-priority repetition.
extras[:0] = repeated
@@ -172,7 +202,11 @@ def build_sampling(
selected_samples.add(tile["sample_slug"])
pre_cap_counts = Counter({
region: len(paths) + len(extra_paths_by_region[region])
region: (
len(paths)
+ len(priority_positive_paths_by_region[region])
+ len(extra_paths_by_region[region])
)
for region, paths in base_paths_by_region.items()
})
capped_counts = Counter(pre_cap_counts)
@@ -193,12 +227,17 @@ def build_sampling(
base_paths = base_paths_by_region[region]
extra_limit = capped_counts[region] - len(base_paths)
image_paths.extend(base_paths)
extras = extra_paths_by_region[region]
if extras and extra_limit < len(extras):
# Rotate the capped repeat window between loop rounds so persistent
# failures cannot yield the exact same training list indefinitely.
offset = sampling_round % len(extras)
extras = extras[offset:] + extras[:offset]
priority_positives = spread_repeats(
priority_positive_paths_by_region[region],
sampling_round=sampling_round,
lane=f"{region}:positive",
)
corrections = spread_repeats(
extra_paths_by_region[region],
sampling_round=sampling_round,
lane=f"{region}:correction",
)
extras = interleave(priority_positives, corrections)
image_paths.extend(extras[:extra_limit])
repeat_counts = Counter({region: capped_counts[region] for region in capped_counts})
if not image_paths:
@@ -233,6 +272,9 @@ def build_sampling(
),
"sampled_train_entry_count": len(image_paths),
"sampled_entries_by_region": dict(sorted(repeat_counts.items())),
"priority_positive_repeat_count": sum(
len(paths) for paths in priority_positive_paths_by_region.values()
),
"pre_cap_entries_by_region": dict(sorted(pre_cap_counts.items())),
"dropped_region_repeat_count": sum(pre_cap_counts.values()) - len(image_paths),
"selected_train_sample_count": len(selected_samples),