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 docs/MODELS.md
Browse files- docs/MODELS.md +194 -0
docs/MODELS.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Models
|
| 2 |
+
|
| 3 |
+
**Status tags:** `IMPLEMENTED` · `VERIFIED` · `MEASURED` · `ATTEMPTED` · `NOT RUN` · `BLOCKED` ·
|
| 4 |
+
`DEFERRED` · `REJECTED`.
|
| 5 |
+
|
| 6 |
+
SatQuery AI trains **six** artifacts. Four are task heads, one is a router adapter, one is a LoRA
|
| 7 |
+
adapter. Every backbone is **frozen** and publicly pinned by revision in `configs/base.yaml` — the
|
| 8 |
+
project trains small modules on top of frozen encoders, not end-to-end networks.
|
| 9 |
+
|
| 10 |
+
> **This file is the human-readable companion to the machine-generated
|
| 11 |
+
> [`../models/manifest.json`](../models/manifest.json) and
|
| 12 |
+
> [`../models/checksums.sha256`](../models/checksums.sha256) (Phase 3).** Where the two disagree,
|
| 13 |
+
> the generated manifest wins — it is computed from the files, this document is written by hand.
|
| 14 |
+
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
## 1. The six trained artifacts
|
| 18 |
+
|
| 19 |
+
| # | Task | Artifact path | Bytes | Kind | Backbone (frozen) |
|
| 20 |
+
|---|---|---|---|---|---|
|
| 21 |
+
| 1 | `change` | `artifacts/change/levir_change_v001/head.pt` | 63,231,009 | trained head | STANet-style, ResNet-18 + PAM |
|
| 22 |
+
| 2 | `change_vqa` | `artifacts/change_vqa/run/head.pt` | 5,822,809 | trained head | over the change encoder's features |
|
| 23 |
+
| 3 | `optical_sar` | `artifacts/optical_sar/fusion_head_production_v001/head.pt` | 14,427,457 | trained head (production) | CROMA-base (frozen), 19-class head |
|
| 24 |
+
| 4 | `grounding` | `artifacts/grounding/remoteclip_grounding_v001/head.pt` | 12,639,041 | trained head | RemoteCLIP ViT-B/32 (frozen) |
|
| 25 |
+
| 5 | `router` | `artifacts/router/router_adapter_v001/adapter.pt` | 211,961 | trained adapter | `all-MiniLM-L6-v2` (frozen) |
|
| 26 |
+
| 6 | `vlm` | `.scratch/phase6_real_adapter/phase6_adapter/adapter_model.safetensors` | 34,798,048 | **LoRA adapter** (PEFT) | `HuggingFaceTB/SmolVLM-500M-Instruct` (frozen) |
|
| 27 |
+
|
| 28 |
+
Training checkpoints also exist (`checkpoint_last.pt`, `checkpoint-1500`, `checkpoint-2000`) and are
|
| 29 |
+
**not** the released artifacts — they are archived as provenance.
|
| 30 |
+
|
| 31 |
+
## 2. Backbones — pinned, frozen, never retrained
|
| 32 |
+
|
| 33 |
+
| Role | Repository | Revision | Notes |
|
| 34 |
+
|---|---|---|---|
|
| 35 |
+
| Router encoder | `sentence-transformers/all-MiniLM-L6-v2` | `1110a243fdf4` | 90.9 MB, 22,713,216 params, 384-dim embeddings, tokenizer ceiling 256; truncation set to 128 |
|
| 36 |
+
| VLM | `HuggingFaceTB/SmolVLM-500M-Instruct` | `a7da5b986cb5` | ~1015 MB safetensors |
|
| 37 |
+
| Grounding | `chendelong/RemoteCLIP` (`RemoteCLIP-ViT-B-32.pt`) | `bf1d8a3ccf2d` | 605.2 MB; transformer width 768, **projected** dim 512 |
|
| 38 |
+
| Optical-SAR | `antofuller/CROMA` (`CROMA_base.pt`) | `0dd28e3d633b` | 777.6 MB; `encoder_dim` 768; `image_resolution` 120 |
|
| 39 |
+
|
| 40 |
+
These are resolved from the Hugging Face Hub on first use. **No backbone weights are redistributed**
|
| 41 |
+
by this project's release — see §6.
|
| 42 |
+
|
| 43 |
+
## 3. Per-artifact detail
|
| 44 |
+
|
| 45 |
+
### 3.1 Change (`change`) — `IMPLEMENTED`, `VERIFIED`
|
| 46 |
+
|
| 47 |
+
STANet-style Siamese change detector. Encoder ResNet-18, self-attention mode **PAM**, tile size 256,
|
| 48 |
+
threshold 0.50, minimum component 32 px. Loss is BCE (0.5) + Dice (0.5). Trained on LEVIR-CD-256
|
| 49 |
+
(train 7120 / val 1024 / test 2048).
|
| 50 |
+
|
| 51 |
+
**Measured** on the LEVIR-CD-256 test split (n = 2048, threshold 0.50):
|
| 52 |
+
|
| 53 |
+
| Metric | Value |
|
| 54 |
+
|---|---|
|
| 55 |
+
| pooled IoU | **0.8122** |
|
| 56 |
+
| macro IoU | **0.8457** |
|
| 57 |
+
| pooled F1 | **0.8964** |
|
| 58 |
+
|
| 59 |
+
This is the only task whose headline number carries the `VERIFIED` tag, because it is the only one
|
| 60 |
+
measured against a single, immutable public test split with a frozen threshold.
|
| 61 |
+
|
| 62 |
+
### 3.2 Change-VQA (`change_vqa`) — `IMPLEMENTED`, `MEASURED`, ruling **OPEN**
|
| 63 |
+
|
| 64 |
+
A head that answers natural-language change questions over a temporal pair. It is the dispatch
|
| 65 |
+
target for change-style questions when only one asset is attached (see
|
| 66 |
+
[`ARCHITECTURE.md`](ARCHITECTURE.md) §4).
|
| 67 |
+
|
| 68 |
+
**Measured on two test sets — both are reported; quoting only the better one would be selective:**
|
| 69 |
+
|
| 70 |
+
| Test set | accuracy | macro F1 |
|
| 71 |
+
|---|---|---|
|
| 72 |
+
| `test` (n = 39,686) | **0.697626** | **0.378373** |
|
| 73 |
+
| `test2` | **0.651469** | **0.372309** |
|
| 74 |
+
|
| 75 |
+
The wide gap between accuracy and macro-F1 means the head is carried by common classes and performs
|
| 76 |
+
poorly on rare ones. The ruling is **OPEN** — no promotion/acceptance decision has been recorded.
|
| 77 |
+
|
| 78 |
+
### 3.3 Optical-SAR fusion (`optical_sar`) — `IMPLEMENTED`, `MEASURED`, ruling **OPEN**
|
| 79 |
+
|
| 80 |
+
Uses frozen CROMA-base to produce optical (768), SAR (768) and joint (768) embeddings, concatenates
|
| 81 |
+
them with the 12 optical and 2 SAR channel descriptors, and feeds a 19-class head:
|
| 82 |
+
|
| 83 |
+
```
|
| 84 |
+
input_dim = 3 * 768 + 12 + 2 = 2318 → hidden 512 → num_classes 19 (BigEarthNet CLC)
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
The **availability mask is consumed by the fusion head, not by CROMA** — CROMA always sees the
|
| 88 |
+
canonical channel counts (12 optical, 2 SAR).
|
| 89 |
+
|
| 90 |
+
**Measured** (production head `fusion_head_production_v001`, pre-registered 115-class protocol,
|
| 91 |
+
held-out test n = 4000):
|
| 92 |
+
|
| 93 |
+
| Metric | Value |
|
| 94 |
+
|---|---|
|
| 95 |
+
| accuracy | **0.931** |
|
| 96 |
+
| macro F1 | **0.434161** |
|
| 97 |
+
|
| 98 |
+
**Both numbers must travel together.** The high accuracy with a low macro-F1 reflects class
|
| 99 |
+
imbalance across 19 classes. The pre-registered metric JSON records `macro_f1_denominator` and
|
| 100 |
+
`classes_present`/`classes_absent` so the denominator is auditable. The ruling is **OPEN**.
|
| 101 |
+
|
| 102 |
+
**Limitation:** the live service returns a bare class index (`class_18`), not a human-readable label.
|
| 103 |
+
|
| 104 |
+
### 3.4 Grounding (`grounding`) — `IMPLEMENTED`, `MEASURED` — **two protocols**
|
| 105 |
+
|
| 106 |
+
A trainable head over the frozen RemoteCLIP ViT-B/32 encoder. Per-cell feature is
|
| 107 |
+
`concat([patch, text, patch·text, global_pool])` = `4 × 512 = 2048` (enforced at config load). Cells
|
| 108 |
+
are assigned by ground-truth box centre (`cell_relative` decode). Objectness BCE is weighted **20×**
|
| 109 |
+
because only ~1 of 49 cells is positive; unweighted, the optimum collapses to "no object".
|
| 110 |
+
|
| 111 |
+
Image resolution is frozen at **224** — 448 was evaluated and **rejected** (see §4).
|
| 112 |
+
|
| 113 |
+
**Measured on VRSBench (n = 16,159), reported under two protocols:**
|
| 114 |
+
|
| 115 |
+
| Protocol | mean best IoU | recall@0.5 |
|
| 116 |
+
|---|---|---|
|
| 117 |
+
| canonical (head threshold decode) | **0.2838** | **0.2198** |
|
| 118 |
+
| matched6 | **0.2566** | **0.1938** |
|
| 119 |
+
|
| 120 |
+
Two further decode variants exist and are reported for completeness — a reviewer must be able to see
|
| 121 |
+
the whole grid, not one cell of it:
|
| 122 |
+
|
| 123 |
+
| Variant | mean best IoU |
|
| 124 |
+
|---|---|
|
| 125 |
+
| head argmax decode (canonical) | **0.1215** |
|
| 126 |
+
| zero-shot matched (no trained head) | **0.0972** |
|
| 127 |
+
|
| 128 |
+
The trained head beats the zero-shot baseline by a wide margin, which is the point of the head; the
|
| 129 |
+
absolute IoU is low, which is an honest limitation.
|
| 130 |
+
|
| 131 |
+
### 3.5 Router (`router`) — `IMPLEMENTED`, `MEASURED`, **TEST NOT RUN**
|
| 132 |
+
|
| 133 |
+
A **50,822-parameter adapter** over the frozen MiniLM encoder. Because the encoder is frozen,
|
| 134 |
+
embeddings are cached and the adapter trains on cached vectors — no GPU required (measured: 20
|
| 135 |
+
epochs / 4,096 vectors in 0.28 s on CPU). Splits are by **group** (template / hard-negative family),
|
| 136 |
+
never by example; hard-negative families are placed in the test split so their accuracy measures
|
| 137 |
+
generalisation, not memorisation.
|
| 138 |
+
|
| 139 |
+
**Measured:** overall **ungated** task accuracy **0.965116** on the validation split, **n = 86**,
|
| 140 |
+
corpus-limited. This number is (a) validation-only, (b) ungated, and (c) small. The router **test**
|
| 141 |
+
split was **NOT RUN**. Do not read 0.965116 as a test result.
|
| 142 |
+
|
| 143 |
+
### 3.6 VLM LoRA (`vlm`) — `IMPLEMENTED`, `MEASURED`, **ACCEPTANCE-REJECTED**
|
| 144 |
+
|
| 145 |
+
A PEFT LoRA adapter on frozen SmolVLM-500M-Instruct: `peft_type=LORA`, `r=16`, `alpha=32`,
|
| 146 |
+
`dropout=0.05`, targeting `model.text_model.*.{q,k,v,o,gate,up,down}_proj`. PEFT 0.19.1.
|
| 147 |
+
|
| 148 |
+
**Measured** on a frozen 1,000-question subset: exact_match **0.963**, F1 **0.96432** (+49.5 pp over
|
| 149 |
+
the unadapted baseline).
|
| 150 |
+
|
| 151 |
+
**Yet the artifact's status is `CLOSED` with headline `ACCEPTANCE-REJECTED`.** This is not a
|
| 152 |
+
contradiction — it is the project's central truthfulness distinction:
|
| 153 |
+
|
| 154 |
+
- **`USABLE_VERIFIED`** — the adapter demonstrably works (the metrics are real and reproducible).
|
| 155 |
+
- **`ACCEPTANCE-REJECTED`** — the adapter is *not accepted* for production promotion, on grounds
|
| 156 |
+
recorded in `artifacts/vlm/phase6_closure.json` (`why_acceptance_rejected`).
|
| 157 |
+
|
| 158 |
+
The deployed caption/VQA path therefore uses the **unadapted** SmolVLM. Deployment success and model
|
| 159 |
+
acceptance are different claims, and this document keeps them apart.
|
| 160 |
+
|
| 161 |
+
## 4. Rejected and deferred model decisions
|
| 162 |
+
|
| 163 |
+
| Decision | Outcome | Evidence |
|
| 164 |
+
|---|---|---|
|
| 165 |
+
| Grounding image resolution 448 vs 224 | **224 chosen; 448 REJECTED** | 448 lost on every axis: mean best IoU −0.0147, recall@0.5 −0.0022, all recall thresholds lower, at 1.59× latency. Paired test: mean diff −0.0147, 95 % CI [−0.0160, −0.0134], t = −22.63; 448 better on 8.5 % of records, worse on 20.9 %. Pre-registered rule and the paired test **agree**. |
|
| 166 |
+
| VLM adapter promotion | **REJECTED** | metrics usable, acceptance rejected (§3.6) |
|
| 167 |
+
| Calibration | **kept but ineffective** | see §5 |
|
| 168 |
+
| optical-SAR / change-VQA rulings | **OPEN** | no decision recorded |
|
| 169 |
+
|
| 170 |
+
## 5. Calibration — `MEASURED`, **not an improvement**
|
| 171 |
+
|
| 172 |
+
Temperature scaling is enabled (`confidence.temperature_scaling: true`) with
|
| 173 |
+
`calibration_v001.json`. Fitted temperature **T = 0.9772732** on the validation split (n = 16,441).
|
| 174 |
+
|
| 175 |
+
| Metric | Before | After |
|
| 176 |
+
|---|---|---|
|
| 177 |
+
| ECE | 0.013755 | **0.014929** |
|
| 178 |
+
| NLL | 0.689741 | 0.689631 |
|
| 179 |
+
|
| 180 |
+
**ECE got worse** (`ece_improvement = −0.001174`). The scaling is retained because it is part of the
|
| 181 |
+
frozen configuration, **not** because it helped. The reliability diagram on the Benchmark page is
|
| 182 |
+
explicitly labelled **pre-scaling** so a reader cannot mistake it for the calibrated result. This is
|
| 183 |
+
recorded as a negative result, not smoothed over.
|
| 184 |
+
|
| 185 |
+
## 6. Distribution and licensing
|
| 186 |
+
|
| 187 |
+
- **Backbones are not redistributed.** They are fetched from the Hugging Face Hub at run time, pinned
|
| 188 |
+
by revision. Their licences are their own (see each model's HF page).
|
| 189 |
+
- **The six trained artifacts are published by this project** on the Hugging Face Hub under
|
| 190 |
+
`thundercode/SatQuery`, labelled by kind, each with its backbone dependency documented and each
|
| 191 |
+
accompanied by a checksum. See [`../HF_RELEASE_VERIFICATION.md`](../HF_RELEASE_VERIFICATION.md).
|
| 192 |
+
- **No licence file exists in the source repository.** This is an **OPEN** item flagged in
|
| 193 |
+
[`LIMITATIONS.md`](LIMITATIONS.md); the repository README instructs the owner to select one before
|
| 194 |
+
any public release of *code*. Model weights carry the terms of their backbone licences.
|