Spaces:
Paused
Paused
Download export_text_embeddings.py from Deagin/RoofSegmentation2: direct link, hf CLI and curl.
- Browser
- Download file 3.67 kB
-
https://huggingface.co/spaces/Deagin/RoofSegmentation2/resolve/main/export_text_embeddings.py
- Command line
-
hf download hf://spaces/Deagin/RoofSegmentation2/export_text_embeddings.py
-
curl -L -o export_text_embeddings.py https://huggingface.co/spaces/Deagin/RoofSegmentation2/resolve/main/export_text_embeddings.py
3.67 kB
| """Offline export of the SigLIP2 text embeddings for RoofSight's fixed prompts. | |
| Run this ONCE on a machine with RAM headroom (~14 GB peak). It loads the full | |
| `siglip2-g` adaptor — which instantiates the entire google/siglip2-giant model | |
| just to keep its text tower — encodes the fixed prompt set, and writes the | |
| resulting (num_prompts, D) tensor to disk. | |
| The Space then loads with the `siglip2` adaptor factory removed from RADIO's | |
| registry, so the text tower is never built there. See radio_backbone.load_model. | |
| Also captures a reference feature map so the stripped runtime path can be | |
| verified as numerically identical: | |
| python export_text_embeddings.py # export + reference | |
| python verify_stripped_adaptor.py # compare | |
| """ | |
| import os | |
| import sys | |
| import numpy as np | |
| import torch | |
| from PIL import Image | |
| from radio_backbone import ROOF_PROMPTS, NON_ROOF_PROMPTS, PATCH_SIZE | |
| OUT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "text_embeddings.pt") | |
| REF_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "_ref_features.pt") | |
| REF_IMAGE = os.path.join( | |
| os.path.dirname(os.path.abspath(__file__)), | |
| "_run_output", "1310_susan_circle", "original.png", | |
| ) | |
| # CPU + fp32 throughout: the reference must be deterministic so the parity | |
| # check measures the adaptor swap, not autocast/GPU nondeterminism. | |
| DEVICE = "cpu" | |
| def main(): | |
| all_labels = ROOF_PROMPTS + NON_ROOF_PROMPTS | |
| print(f"Loading FULL c-radio_v4-h + siglip2-g adaptor on {DEVICE} (this is the heavy path)...") | |
| model = torch.hub.load( | |
| "NVlabs/RADIO", | |
| "radio_model", | |
| version="c-radio_v4-h", | |
| adaptor_names=["siglip2-g"], | |
| vitdet_window_size=8, | |
| progress=True, | |
| skip_validation=True, | |
| trust_repo=True, | |
| ) | |
| model.eval() | |
| model.to(DEVICE) | |
| adaptor = model.adaptors["siglip2-g"] | |
| assert hasattr(adaptor, "encode_text"), ( | |
| "adaptor has no encode_text — the siglip2 factory was not used. " | |
| "This script must run WITHOUT the registry patch." | |
| ) | |
| print(f"Encoding {len(all_labels)} prompts...") | |
| text_input = adaptor.tokenizer(all_labels) | |
| text_input = {k: v.to(DEVICE) for k, v in text_input.items()} | |
| with torch.no_grad(): | |
| embeddings = adaptor.encode_text(text_input, normalize=True).float().cpu().clone() | |
| print(f" embeddings: {tuple(embeddings.shape)} dtype={embeddings.dtype}") | |
| torch.save({"prompts": all_labels, "embeddings": embeddings}, OUT_PATH) | |
| print(f" wrote {OUT_PATH} ({os.path.getsize(OUT_PATH) / 1024:.1f} KB)") | |
| # --- Reference feature map, for the parity check --- | |
| if not os.path.exists(REF_IMAGE): | |
| print(f"\nNo reference image at {REF_IMAGE}; skipping reference capture.") | |
| return | |
| print(f"\nCapturing reference features from {REF_IMAGE}...") | |
| image = np.array(Image.open(REF_IMAGE).convert("RGB")) | |
| x = torch.from_numpy(image).permute(2, 0, 1).float().div_(255.0).unsqueeze(0) | |
| snapped = model.get_nearest_supported_resolution(*x.shape[-2:]) | |
| if snapped != x.shape[-2:]: | |
| x = torch.nn.functional.interpolate(x, snapped, mode="bilinear", align_corners=False) | |
| with torch.no_grad(): | |
| out = model(x.to(DEVICE)) | |
| _, features = out["siglip2-g"] | |
| torch.save( | |
| { | |
| "features": features.float().cpu().clone(), | |
| "snapped": tuple(snapped), | |
| "image_shape": image.shape, | |
| }, | |
| REF_PATH, | |
| ) | |
| print(f" features: {tuple(features.shape)}") | |
| print(f" wrote {REF_PATH}") | |
| print("\nDone. Now run: python verify_stripped_adaptor.py") | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |