Image-to-Text
PyTorch
Safetensors
PEFT
English
remote-sensing
satellite-imagery
earth-observation
change-detection
visual-grounding
image-captioning
visual-question-answering
optical-sar-fusion
sar
multimodal
lora
Instructions to use thundercode/SatQuery with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use thundercode/SatQuery with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
release: add tools/verify_readme_metrics.py
Browse files- tools/verify_readme_metrics.py +149 -0
tools/verify_readme_metrics.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Verify every metric quoted in the release README against its source artifact.
|
| 2 |
+
|
| 3 |
+
Read-only. Each claim is compared at the precision at which the README states it.
|
| 4 |
+
Writes nothing; prints a report suitable for pasting into FINAL_RELEASE_VERIFICATION.md.
|
| 5 |
+
|
| 6 |
+
Key names were discovered by walking the artifacts, NOT assumed: several live under nested
|
| 7 |
+
paths (e.g. change metrics are `metrics.pooled.iou`, grounding is
|
| 8 |
+
`results.head_threshold.mean_best_iou`, VLM is `why_usable_verified.adapted_test.*`).
|
| 9 |
+
|
| 10 |
+
WHERE THE ARTIFACTS COME FROM
|
| 11 |
+
-----------------------------
|
| 12 |
+
This tool reads the project's `artifacts/` directory, which is NOT part of the public release
|
| 13 |
+
(the release ships the six trained weights on the Hugging Face Hub, not the full artifacts tree).
|
| 14 |
+
Point it at a checkout that has the artifacts:
|
| 15 |
+
|
| 16 |
+
SATQUERY_ARTIFACTS_ROOT=/path/to/satquery-ai python verify_readme_metrics.py
|
| 17 |
+
|
| 18 |
+
Without that variable it defaults to `../..` relative to this file, which is the layout the tool
|
| 19 |
+
was authored in.
|
| 20 |
+
"""
|
| 21 |
+
import json
|
| 22 |
+
import os
|
| 23 |
+
import sys
|
| 24 |
+
|
| 25 |
+
ROOT = os.environ.get(
|
| 26 |
+
"SATQUERY_ARTIFACTS_ROOT",
|
| 27 |
+
os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..")),
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
# (label, relative path, dotted key, value as printed in the README)
|
| 31 |
+
CLAIMS = [
|
| 32 |
+
("change pooled IoU", "artifacts/change/eval_test/eval_result.json",
|
| 33 |
+
"metrics.pooled.iou", "0.8122"),
|
| 34 |
+
("change macro IoU", "artifacts/change/eval_test/eval_result.json",
|
| 35 |
+
"metrics.macro.miou", "0.8457"),
|
| 36 |
+
("change pooled F1", "artifacts/change/eval_test/eval_result.json",
|
| 37 |
+
"metrics.pooled.f1", "0.8964"),
|
| 38 |
+
("grounding canonical head_threshold mean_best_IoU",
|
| 39 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_canonical.json",
|
| 40 |
+
"results.head_threshold.mean_best_iou", "0.2838"),
|
| 41 |
+
("grounding canonical head_threshold recall@0.5",
|
| 42 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_canonical.json",
|
| 43 |
+
"results.head_threshold.recall.0.50", "0.2198"),
|
| 44 |
+
("grounding matched6 head_threshold mean_best_IoU",
|
| 45 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_matched6.json",
|
| 46 |
+
"results.head_threshold.mean_best_iou", "0.2566"),
|
| 47 |
+
("grounding matched6 head_threshold recall@0.5",
|
| 48 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_matched6.json",
|
| 49 |
+
"results.head_threshold.recall.0.50", "0.1938"),
|
| 50 |
+
("grounding head_argmax mean_best_IoU (canonical)",
|
| 51 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_canonical.json",
|
| 52 |
+
"results.head_argmax.mean_best_iou", "0.1215"),
|
| 53 |
+
("grounding zero-shot baseline IoU (canonical)",
|
| 54 |
+
"artifacts/grounding/remoteclip_grounding_v001/eval_result_canonical.json",
|
| 55 |
+
"results.zero_shot_matched.mean_best_iou", "0.0972"),
|
| 56 |
+
("optical-SAR fusion accuracy",
|
| 57 |
+
"artifacts/optical_sar/fusion_head_production_v001/pre_registered_115_metric.json",
|
| 58 |
+
"accuracy", "0.931"),
|
| 59 |
+
("optical-SAR fusion macro_F1",
|
| 60 |
+
"artifacts/optical_sar/fusion_head_production_v001/pre_registered_115_metric.json",
|
| 61 |
+
"macro_f1", "0.434161"),
|
| 62 |
+
("change_vqa test accuracy", "artifacts/change_vqa/run/PROMOTION.json",
|
| 63 |
+
"verification.test_accuracy", "0.697626"),
|
| 64 |
+
("change_vqa test macro_F1", "artifacts/change_vqa/run/PROMOTION.json",
|
| 65 |
+
"verification.test_macro_f1", "0.378373"),
|
| 66 |
+
("change_vqa test2 accuracy", "artifacts/change_vqa/run/PROMOTION.json",
|
| 67 |
+
"verification.test2_accuracy", "0.651469"),
|
| 68 |
+
("change_vqa test2 macro_F1", "artifacts/change_vqa/run/PROMOTION.json",
|
| 69 |
+
"verification.test2_macro_f1", "0.372309"),
|
| 70 |
+
("router overall ungated accuracy", "artifacts/router/threshold_sweep_val.json",
|
| 71 |
+
"overall_ungated_accuracy", "0.965116"),
|
| 72 |
+
("calibration ECE before scaling", "artifacts/calibration_v001.json",
|
| 73 |
+
"metrics.ece_before", "0.013755"),
|
| 74 |
+
("calibration ECE after scaling", "artifacts/calibration_v001.json",
|
| 75 |
+
"metrics.ece_after", "0.014929"),
|
| 76 |
+
("VLM adapter exact_match", "artifacts/vlm/phase6_closure.json",
|
| 77 |
+
"why_usable_verified.adapted_test.exact_match", "0.963"),
|
| 78 |
+
("VLM adapter F1", "artifacts/vlm/phase6_closure.json",
|
| 79 |
+
"why_usable_verified.adapted_test.f1", "0.96432"),
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def get(obj, dotted):
|
| 84 |
+
"""Resolve a dotted path, preferring the LONGEST matching key at each step.
|
| 85 |
+
|
| 86 |
+
Needed because some artifact keys themselves contain dots (e.g. the recall
|
| 87 |
+
dict is keyed "0.10"/"0.25"/"0.50"), so a naive split(".") walk would break
|
| 88 |
+
`results.head_threshold.recall.0.50` into ...recall -> 0 -> 50 and fail.
|
| 89 |
+
"""
|
| 90 |
+
return _get(obj, dotted.split("."))
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def _get(cur, parts):
|
| 94 |
+
if not parts:
|
| 95 |
+
return cur, True
|
| 96 |
+
if isinstance(cur, dict):
|
| 97 |
+
for i in range(len(parts), 0, -1): # longest key first
|
| 98 |
+
key = ".".join(parts[:i])
|
| 99 |
+
if key in cur:
|
| 100 |
+
return _get(cur[key], parts[i:])
|
| 101 |
+
return None, False
|
| 102 |
+
if isinstance(cur, list):
|
| 103 |
+
return _get(cur[int(parts[0])], parts[1:])
|
| 104 |
+
return None, False
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def decimals(s):
|
| 108 |
+
return len(s.split(".")[1]) if "." in s else 0
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
fails = 0
|
| 112 |
+
print(f"{'STATUS':8} {'claim':48} {'artifact':>14} {'readme':>12} source")
|
| 113 |
+
print("-" * 118)
|
| 114 |
+
for label, rel, key, claimed in CLAIMS:
|
| 115 |
+
path = os.path.join(ROOT, rel)
|
| 116 |
+
if not os.path.exists(path):
|
| 117 |
+
print(f"{'NOFILE':8} {label:48} {'':>14} {claimed:>12} {rel}")
|
| 118 |
+
fails += 1
|
| 119 |
+
continue
|
| 120 |
+
data = json.load(open(path, encoding="utf-8"))
|
| 121 |
+
val, found = get(data, key)
|
| 122 |
+
if not found:
|
| 123 |
+
print(f"{'NOKEY':8} {label:48} {'':>14} {claimed:>12} {rel}#{key}")
|
| 124 |
+
fails += 1
|
| 125 |
+
continue
|
| 126 |
+
ok = round(float(val), decimals(claimed)) == float(claimed)
|
| 127 |
+
if not ok:
|
| 128 |
+
fails += 1
|
| 129 |
+
print(f"{'MATCH' if ok else 'DIFFER':8} {label:48} {val:>14} {claimed:>12} {rel}#{key}")
|
| 130 |
+
|
| 131 |
+
# --- artifact-declared statuses that the README also asserts ---
|
| 132 |
+
print()
|
| 133 |
+
print("=== status assertions ===")
|
| 134 |
+
d = json.load(open(os.path.join(ROOT, "artifacts/vlm/phase6_closure.json"), encoding="utf-8"))
|
| 135 |
+
hl = d.get("headline", "")
|
| 136 |
+
print(f" VLM headline contains ACCEPTANCE-REJECTED : {'ACCEPTANCE-REJECTED' in hl}")
|
| 137 |
+
print(f" VLM status : {d.get('status')}")
|
| 138 |
+
r = json.load(open(os.path.join(ROOT, "artifacts/router/threshold_sweep_val.json"), encoding="utf-8"))
|
| 139 |
+
print(f" router corpus_limited : {r.get('corpus_limited')}")
|
| 140 |
+
print(f" router n_val : {r.get('n_val')}")
|
| 141 |
+
c = json.load(open(os.path.join(ROOT, "artifacts/calibration_v001.json"), encoding="utf-8"))
|
| 142 |
+
print(f" calibration temperature (temperature_scaling.temperature) : "
|
| 143 |
+
f"{c.get('temperature_scaling', {}).get('temperature')}")
|
| 144 |
+
print(f" calibration ece_improvement : "
|
| 145 |
+
f"{c.get('metrics', {}).get('ece_improvement')} (negative => calibration did NOT help)")
|
| 146 |
+
|
| 147 |
+
print()
|
| 148 |
+
print(f"RESULT: {'ALL CLAIMS VERIFIED' if fails == 0 else str(fails) + ' CLAIM(S) FAILED'}")
|
| 149 |
+
sys.exit(0 if fails == 0 else 1)
|