feat: serve GeoCLIP visual geolocation via /v1/embeddings (geoclip + geoclip-location)
Implements the HomeHunter request (REQUEST-geoclip-embeddings.md): two model ids
on the existing embeddings endpoint, both returning 512-d L2-normalised vectors in
ONE shared space so a property photo can be scored directly against candidate GPS
coordinates.
geoclip — image encoder (CLIP ViT-L/14 + projection MLP), on GPU.
Accepts the image data URI in EITHER `input` (per the request)
or the `image` field (like dinov2).
geoclip-location — GPS encoder (equal-earth + RFF MLP), pinned to CPU: it is a
tiny MLP, so CPU is fast, frees VRAM, and is bit-exact across
batch sizes (GPU reduction order otherwise perturbs a cached
coordinate by ~1e-7). Batches an array of "lat,lon" strings to
one vector per element, in input order.
Both sides load from the SAME bundled GeoCLIP checkpoint, so the spaces coincide by
construction — the mismatched-checkpoint failure the request warns about cannot
happen. Loaded as separate _EmbeddingModel('geoclip', ...) instances so each is
independently evictable.
transformers>=5 compat: CLIPModel.get_image_features now returns a
BaseModelOutputWithPooling (768-d projected features in pooler_output) instead of a
bare tensor, which breaks GeoCLIP's internal mlp() call. The image path extracts the
768-d tensor itself (tolerant of both the old tensor and the new object) before the
projection MLP.
geoclip (+geopy, geographiclib) added to requirements.txt; its heavy deps (torch,
transformers, Pillow, pandas, numpy) are already pinned, so no ML-stack churn.
Verified end-to-end: 512-d L2-normalised both sides; batching + index order; same
request bit-exact; both ids in GET /v1/models; image·location scoring varies by image.
Co-Authored-By:
Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoSpEthysqmseCc6Geizty
Showing
| ... | @@ -34,6 +34,13 @@ torchaudio | ... | @@ -34,6 +34,13 @@ torchaudio |
| # ML dependencies | # ML dependencies | ||
| transformers>=4.35.0 | transformers>=4.35.0 | ||
| accelerate>=0.24.0 | accelerate>=0.24.0 | ||
| # GeoCLIP visual geolocation embedder (image<->GPS shared space) — served as the | |||
| # 'geoclip' / 'geoclip-location' embedding model ids. Its deps (torch, transformers, | |||
| # Pillow, pandas, numpy) are already pinned above/below; geopy+geographiclib are the | |||
| # only extras it pulls (both pure-python, no version churn on the ML stack). | |||
| geoclip>=1.2.0 | |||
| geopy>=2.4 | |||
| geographiclib>=2.0 | |||
| diffusers>=0.25.0 # For Stable Diffusion image generation | diffusers>=0.25.0 # For Stable Diffusion image generation | ||
| safetensors>=0.4.0 # Required by diffusers | safetensors>=0.4.0 # Required by diffusers | ||
| ftfy>=6.0 # Prompt text cleaning for diffusers Wan/T5 pipelines (prompt_clean) | ftfy>=6.0 # Prompt text cleaning for diffusers Wan/T5 pipelines (prompt_clean) | ||
| ... | ... |
Please
register
or
sign in
to comment