Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
name: Build & test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Oldest supported and newest Python.
python-version: ["3.9", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install torch (CPU)
# Install the CPU-only torch build first to keep CI lightweight and avoid
# pulling large CUDA wheels via transitive dependencies.
run: |
python -m pip install --upgrade pip
pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu

- name: Build sdist and wheel
run: |
pip install build
python -m build

- name: Install wheel
# Install the built wheel (not an editable install) so packaging mistakes,
# e.g. missing package data, are caught.
run: pip install "$(ls dist/*.whl)[dev,examples]"

- name: Run tests against the installed package
# Run from outside the repository so `import satclip` resolves to the
# installed wheel rather than the source tree.
run: |
cp -r tests "$RUNNER_TEMP/tests"
cd "$RUNNER_TEMP"
python -c "import satclip; print('satclip public API:', satclip.__all__)"
satclip-train --help > /dev/null
pytest -q tests
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SatCLIP files
satclip_logs/

# Python
__pycache__/
*.egg-info/
build/
dist/
.pytest_cache/
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,27 @@

SatCLIP trains location and image encoders via contrastive learning, by matching images to their corresponding locations. This is analogous to the CLIP approach, which matches images to their corresponding text. Through this process, the location encoder learns characteristics of a location, as represented by satellite imagery. For more details, check out our [paper](https://arxiv.org/abs/2311.17179).

## Installation

SatCLIP is packaged as a Python module (Python 3.9+). Install it directly from GitHub:
```bash
pip install git+https://github.com/microsoft/satclip.git
```
Or, for a local/editable install (e.g. for training or development):
```bash
git clone https://github.com/microsoft/satclip.git
cd satclip
pip install -e .
```
Once installed, `satclip` can be imported from any directory — no need to set `PYTHONPATH`.

## Overview

Usage of SatCLIP is simple:

```python
from model import *
from location_encoder import *
import torch
from satclip.model import SatCLIP

model = SatCLIP(
embed_dim=512,
Expand Down Expand Up @@ -48,11 +62,11 @@ mkdir -p images
for f in data/shard-*.tar; do tar -xf "$f" -C images; done
```

Now, to train **SatCLIP** models, set the paths correctly (point `data.data_dir` in `satclip/configs/default.yaml` to this dataset directory), adapt training configs in `satclip/configs/default.yaml` and train SatCLIP by running:
Now, to train **SatCLIP** models, run the `satclip-train` command (installed with the package), pointing it at this dataset directory:
```bash
cd satclip
python main.py
satclip-train --data.data_dir /path/to/s2-100k
```
Training uses the default config in [`satclip/configs/default.yaml`](satclip/configs/default.yaml). Any option can be overridden on the command line (see `satclip-train --help`), or you can pass your own config, e.g. a modified copy of the default: `satclip-train --config path/to/config.yaml`. Logs, checkpoints and the resolved config (`default-latest.yaml`) are written to `satclip_logs/` in the current directory. `python -m satclip.main` is equivalent.

### Use of the S2-100K dataset

Expand Down Expand Up @@ -96,7 +110,7 @@ We provide six pretrained SatCLIP models, trained with different vision encoders
Usage of pretrained models is simple. Simply specify the SatCLIP model you want to access, e.g. `satclip-vit16-l40`:
```python
from huggingface_hub import hf_hub_download
from load import get_satclip
from satclip.load import get_satclip
import torch

device = "cuda" if torch.cuda.is_available() else "cpu"
Expand Down
70 changes: 3 additions & 67 deletions notebooks/A01_Simple_SatCLIP_Usage.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"source": [
"## A01 - Simple usage of pretrained SatCLIP embeddings\n",
"\n",
"To obtained pretrained **SatCLIP** embeddings, first install the repository."
"To obtain pretrained **SatCLIP** embeddings, first install the `satclip` package (this also installs all required dependencies)."
],
"metadata": {
"id": "ngz8zz9Gvbxh"
Expand Down Expand Up @@ -51,68 +51,7 @@
}
],
"source": [
"!rm -r sample_data .config # Empty current directory\n",
"!git clone https://github.com/microsoft/satclip.git . # Clone SatCLIP repository"
]
},
{
"cell_type": "markdown",
"source": [
"Now install the required Python packages."
],
"metadata": {
"id": "hOEZnNt1v2Bl"
}
},
{
"cell_type": "code",
"source": [
"!pip install lightning --quiet\n",
"!pip install rasterio --quiet\n",
"!pip install torchgeo --quiet"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Q72Ypu0Cr3Sc",
"outputId": "d54f24b8-26b1-4f86-ffc8-23da0cc63710"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m13.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m806.1/806.1 kB\u001b[0m \u001b[31m40.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m776.9/776.9 kB\u001b[0m \u001b[31m42.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m20.6/20.6 MB\u001b[0m \u001b[31m27.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m378.5/378.5 kB\u001b[0m \u001b[31m5.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m44.6/44.6 kB\u001b[0m \u001b[31m5.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m705.7/705.7 kB\u001b[0m \u001b[31m37.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m670.7/670.7 kB\u001b[0m \u001b[31m7.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m488.6/488.6 kB\u001b[0m \u001b[31m41.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m106.7/106.7 kB\u001b[0m \u001b[31m11.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.2/2.2 MB\u001b[0m \u001b[31m66.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m154.5/154.5 kB\u001b[0m \u001b[31m15.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m137.6/137.6 kB\u001b[0m \u001b[31m13.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m92.6/92.6 MB\u001b[0m \u001b[31m7.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m189.7/189.7 kB\u001b[0m \u001b[31m14.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m79.5/79.5 kB\u001b[0m \u001b[31m8.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m101.7/101.7 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.8/58.8 kB\u001b[0m \u001b[31m5.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
" Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.2/2.2 MB\u001b[0m \u001b[31m21.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.0/117.0 kB\u001b[0m \u001b[31m9.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m594.2/594.2 kB\u001b[0m \u001b[31m44.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
"\u001b[?25h Building wheel for efficientnet-pytorch (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
" Building wheel for pretrainedmodels (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
" Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
]
}
"!pip install git+https://github.com/microsoft/satclip.git"
]
},
{
Expand Down Expand Up @@ -169,11 +108,8 @@
{
"cell_type": "code",
"source": [
"import sys\n",
"sys.path.append('./satclip')\n",
"\n",
"import torch\n",
"from load import get_satclip"
"from satclip.load import get_satclip"
],
"metadata": {
"id": "grEIwoFjoHvu"
Expand Down
Loading
Loading