Spaces:
Paused
Paused
Download backend/adaptation/download_subset.py from Sahil-nith/SatQuery-api: direct link, hf CLI and curl.
- Browser
- Download file 5.66 kB
-
https://huggingface.co/spaces/Sahil-nith/SatQuery-api/resolve/main/backend/adaptation/download_subset.py
- Command line
-
hf download hf://spaces/Sahil-nith/SatQuery-api/backend/adaptation/download_subset.py
-
curl -L -o download_subset.py https://huggingface.co/spaces/Sahil-nith/SatQuery-api/resolve/main/backend/adaptation/download_subset.py
5.66 kB
| """ | |
| Pull a SMALL subset of GFM-Bench/BigEarthNet via Hugging Face streaming | |
| (no 59GB/119GB bulk download) and write it out as: | |
| data/bigearthnet_subset/images/patch_00000.png ... | |
| data/bigearthnet_subset/manifest.csv (image_path,labels) | |
| ...ready to feed straight into prepare_bigearthnet.py. | |
| Run this from backend/adaptation/ (see chat — paths assume that). | |
| Confirmed schema (from the HF dataset card): | |
| optical -> Sentinel-2 image, 12 bands, 120x120 | |
| radar -> Sentinel-1 image (not used here — VQA path is optical-only for now) | |
| label -> multi-label classification target over the 19 CLASS_LABELS below | |
| We build a true-color-ish preview PNG from bands B04/B03/B02 (Red/Green/Blue) | |
| so BLIP-VQA (a natural-image model) gets something visually sensible instead | |
| of a raw 12-band array it can't consume. | |
| """ | |
| from __future__ import annotations | |
| import csv | |
| import os | |
| import numpy as np | |
| OUT_DIR = "data/bigearthnet_subset" | |
| IMG_DIR = f"{OUT_DIR}/images" | |
| LIMIT = 500 # plenty for a LoRA demo fine-tune; raise later if you have time/VRAM to spare | |
| # Order matches the dataset card's "Class Labels" list exactly — required to | |
| # turn the numeric `label` feature back into readable text. | |
| CLASS_LABELS = [ | |
| "Urban fabric", "Industrial or commercial units", "Arable land", | |
| "Permanent crops", "Pastures", "Complex cultivation patterns", | |
| "Land principally occupied by agriculture, with significant areas of natural vegetation", | |
| "Agro-forestry areas", "Broad-leaved forest", "Coniferous forest", "Mixed forest", | |
| "Natural grassland and sparsely vegetated areas", | |
| "Moors, heathland and sclerophyllous vegetation", "Transitional woodland, shrub", | |
| "Beaches, dunes, sands", "Inland wetlands", "Coastal wetlands", | |
| "Inland waters", "Marine waters", | |
| ] | |
| # Sentinel-2 band order in this dataset's `optical_channel_wv` metadata is | |
| # B01,B02,B03,B04,B05,B06,B07,B08,B8A,B09,B11,B12 (12 bands) — so | |
| # Red=B04=index 3, Green=B03=index 2, Blue=B02=index 1. | |
| _R, _G, _B = 3, 2, 1 | |
| def _percentile_stretch(band: np.ndarray) -> np.ndarray: | |
| band = band.astype("float32") | |
| lo, hi = np.percentile(band, [2, 98]) | |
| if hi <= lo: | |
| lo, hi = float(band.min()), float(band.max() or 1.0) | |
| return np.clip((band - lo) / max(hi - lo, 1e-6), 0, 1) | |
| def _optical_to_rgb_png(optical_array: np.ndarray): | |
| """optical_array expected shape: (bands, H, W) or (H, W, bands). Returns a PIL Image.""" | |
| from PIL import Image | |
| arr = np.array(optical_array) | |
| if arr.ndim != 3: | |
| raise ValueError(f"Unexpected optical array shape {arr.shape} — inspect the raw feature and adjust this function.") | |
| # Normalize to (bands, H, W) | |
| if arr.shape[0] <= 13: # bands first | |
| bands = arr | |
| elif arr.shape[-1] <= 13: # bands last | |
| bands = np.moveaxis(arr, -1, 0) | |
| else: | |
| raise ValueError(f"Can't tell which axis is bands for shape {arr.shape} — print(arr.shape) and fix _R/_G/_B indices.") | |
| r = _percentile_stretch(bands[_R]) | |
| g = _percentile_stretch(bands[_G]) | |
| b = _percentile_stretch(bands[_B]) | |
| rgb = (np.dstack([r, g, b]) * 255).astype("uint8") | |
| return Image.fromarray(rgb, mode="RGB") | |
| def _labels_to_text(label_field) -> list[str]: | |
| """Handles either a multi-hot vector (length 19, 0/1) or a list of class indices.""" | |
| arr = np.array(label_field) | |
| if arr.ndim == 1 and arr.size == len(CLASS_LABELS) and set(np.unique(arr)).issubset({0, 1}): | |
| idxs = np.nonzero(arr)[0] | |
| else: | |
| idxs = arr.astype(int).flatten() | |
| return [CLASS_LABELS[i] for i in idxs if 0 <= i < len(CLASS_LABELS)] | |
| def main() -> None: | |
| from datasets import load_dataset | |
| os.makedirs(IMG_DIR, exist_ok=True) | |
| print("Opening GFM-Bench/BigEarthNet in streaming mode (no bulk download)...") | |
| ds = load_dataset( | |
| "GFM-Bench/BigEarthNet", split="train", streaming=True, | |
| trust_remote_code=True, # this dataset uses an old-style loading script — | |
| # only works on datasets==2.21.0, see chat/README | |
| ) | |
| rows = [] | |
| for i, example in enumerate(ds): | |
| if i >= LIMIT: | |
| break | |
| if i == 0: | |
| print("First example keys:", list(example.keys())) | |
| print("optical type/shape:", type(example["optical"]), np.array(example["optical"]).shape) | |
| print("label raw value:", example["label"]) | |
| try: | |
| img = _optical_to_rgb_png(example["optical"]) | |
| except Exception as exc: # noqa: BLE001 | |
| print(f"Skipping row {i}: could not build RGB preview ({exc})") | |
| continue | |
| labels = _labels_to_text(example["label"]) | |
| if not labels: | |
| continue | |
| fname = f"patch_{i:05d}.png" | |
| img.save(f"{IMG_DIR}/{fname}") | |
| rows.append({"image_path": fname, "labels": ";".join(labels)}) | |
| if (i + 1) % 50 == 0: | |
| print(f"...{i + 1} patches processed") | |
| if not rows: | |
| raise SystemExit("No usable rows produced — check the printed shape/keys above and fix _optical_to_rgb_png / _labels_to_text.") | |
| manifest_path = f"{OUT_DIR}/manifest.csv" | |
| with open(manifest_path, "w", newline="") as f: | |
| writer = csv.DictWriter(f, fieldnames=["image_path", "labels"]) | |
| writer.writeheader() | |
| writer.writerows(rows) | |
| print(f"\nDone. Saved {len(rows)} patches to {IMG_DIR}") | |
| print(f"Manifest written to {manifest_path}") | |
| print( | |
| "\nNext:\n" | |
| f" python prepare_bigearthnet.py --manifest {manifest_path} " | |
| f"--image-root {IMG_DIR} --out data/bigearthnet_vqa_train.jsonl" | |
| ) | |
| if __name__ == "__main__": | |
| main() | |