asteria-roman 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- asteria_roman-0.1.0/.github/workflows/ci.yml +44 -0
- asteria_roman-0.1.0/.github/workflows/publish.yml +67 -0
- asteria_roman-0.1.0/.gitignore +64 -0
- asteria_roman-0.1.0/LICENSE +21 -0
- asteria_roman-0.1.0/PKG-INFO +158 -0
- asteria_roman-0.1.0/README.md +117 -0
- asteria_roman-0.1.0/docs/Makefile +13 -0
- asteria_roman-0.1.0/docs/_static/images/example_blinking.gif +0 -0
- asteria_roman-0.1.0/docs/api.rst +68 -0
- asteria_roman-0.1.0/docs/architecture.rst +97 -0
- asteria_roman-0.1.0/docs/conf.py +54 -0
- asteria_roman-0.1.0/docs/dataset.rst +68 -0
- asteria_roman-0.1.0/docs/index.rst +89 -0
- asteria_roman-0.1.0/docs/weights_history.rst +107 -0
- asteria_roman-0.1.0/notebooks/01_asteria_segmentation_and_deblending.ipynb +646 -0
- asteria_roman-0.1.0/notebooks/02_starnet3_star_removal.ipynb +681 -0
- asteria_roman-0.1.0/notebooks/03_center_offset_instance_segmentation.ipynb +470 -0
- asteria_roman-0.1.0/notebooks/demo_two_panel.png +0 -0
- asteria_roman-0.1.0/pyproject.toml +83 -0
- asteria_roman-0.1.0/src/asteria/__init__.py +193 -0
- asteria_roman-0.1.0/src/asteria/cli.py +502 -0
- asteria_roman-0.1.0/src/asteria/inference/__init__.py +32 -0
- asteria_roman-0.1.0/src/asteria/inference/center_offset.py +826 -0
- asteria_roman-0.1.0/src/asteria/inference/device.py +256 -0
- asteria_roman-0.1.0/src/asteria/inference/results.py +41 -0
- asteria_roman-0.1.0/src/asteria/inference/segmentor.py +599 -0
- asteria_roman-0.1.0/src/asteria/inference/starnet3.py +640 -0
- asteria_roman-0.1.0/src/asteria/io/__init__.py +5 -0
- asteria_roman-0.1.0/src/asteria/io/reader.py +376 -0
- asteria_roman-0.1.0/src/asteria/models/__init__.py +40 -0
- asteria_roman-0.1.0/src/asteria/models/offset_losses.py +464 -0
- asteria_roman-0.1.0/src/asteria/models/starnet3.py +864 -0
- asteria_roman-0.1.0/src/asteria/models/unetpp.py +175 -0
- asteria_roman-0.1.0/src/asteria/models/unetpp_offset.py +295 -0
- asteria_roman-0.1.0/src/asteria/py.typed +0 -0
- asteria_roman-0.1.0/src/asteria/stretch/__init__.py +23 -0
- asteria_roman-0.1.0/src/asteria/stretch/leakysb.py +583 -0
- asteria_roman-0.1.0/src/asteria/utils/__init__.py +5 -0
- asteria_roman-0.1.0/src/asteria/utils/synthetic.py +152 -0
- asteria_roman-0.1.0/src/asteria/visualization/__init__.py +27 -0
- asteria_roman-0.1.0/src/asteria/visualization/clarity.py +540 -0
- asteria_roman-0.1.0/src/asteria/visualization/plot.py +429 -0
- asteria_roman-0.1.0/src/asteria/weights/__init__.py +41 -0
- asteria_roman-0.1.0/src/asteria/weights/manager.py +169 -0
- asteria_roman-0.1.0/src/asteria/weights/registry.py +64 -0
- asteria_roman-0.1.0/src/asteria/weights/starnet3_manager.py +151 -0
- asteria_roman-0.1.0/src/asteria/weights/starnet3_registry.py +52 -0
- asteria_roman-0.1.0/tests/test_clarity.py +175 -0
- asteria_roman-0.1.0/tests/test_cli.py +115 -0
- asteria_roman-0.1.0/tests/test_device.py +27 -0
- asteria_roman-0.1.0/tests/test_inference.py +185 -0
- asteria_roman-0.1.0/tests/test_io.py +117 -0
- asteria_roman-0.1.0/tests/test_leakysb.py +81 -0
- asteria_roman-0.1.0/tests/test_models.py +52 -0
- asteria_roman-0.1.0/tests/test_weights.py +66 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (${{ matrix.os }} - Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ ubuntu-latest, macos-latest, windows-latest ]
|
|
17
|
+
python-version: [ "3.11", "3.12" ]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout Repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
cache: "pip"
|
|
28
|
+
|
|
29
|
+
- name: Install Package & Test Dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip setuptools wheel
|
|
32
|
+
python -m pip install -e ".[dev]"
|
|
33
|
+
|
|
34
|
+
- name: Run Test Suite (pytest)
|
|
35
|
+
run: |
|
|
36
|
+
pytest -v --cov=asteria --cov-report=xml
|
|
37
|
+
|
|
38
|
+
- name: Build Source Distribution & Wheel
|
|
39
|
+
run: |
|
|
40
|
+
python -m build
|
|
41
|
+
|
|
42
|
+
- name: Verify Package Metadata with Twine
|
|
43
|
+
run: |
|
|
44
|
+
twine check dist/*
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Deploy to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
id-token: write # Mandatory for PyPI Trusted Publishing (OIDC)
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Run Pre-Release Tests
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout Repository
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.11"
|
|
25
|
+
cache: "pip"
|
|
26
|
+
|
|
27
|
+
- name: Install Dependencies
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
python -m pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Run Pytest
|
|
33
|
+
run: |
|
|
34
|
+
pytest -v
|
|
35
|
+
|
|
36
|
+
build-and-publish:
|
|
37
|
+
name: Build & Publish to PyPI
|
|
38
|
+
needs: test
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
environment:
|
|
41
|
+
name: pypi
|
|
42
|
+
url: https://pypi.org/p/asteria-roman
|
|
43
|
+
steps:
|
|
44
|
+
- name: Checkout Repository
|
|
45
|
+
uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- name: Set up Python
|
|
48
|
+
uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.11"
|
|
51
|
+
|
|
52
|
+
- name: Install Build Tools
|
|
53
|
+
run: |
|
|
54
|
+
python -m pip install --upgrade pip build twine
|
|
55
|
+
|
|
56
|
+
- name: Build Distribution Packages
|
|
57
|
+
run: |
|
|
58
|
+
python -m build
|
|
59
|
+
|
|
60
|
+
- name: Validate Wheel & Sdist with Twine
|
|
61
|
+
run: |
|
|
62
|
+
twine check dist/*
|
|
63
|
+
|
|
64
|
+
- name: Publish Package to PyPI
|
|
65
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
with:
|
|
67
|
+
skip-existing: true
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Environments
|
|
13
|
+
.env
|
|
14
|
+
.venv
|
|
15
|
+
env/
|
|
16
|
+
venv/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# Testing & Coverage
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.coverage
|
|
22
|
+
htmlcov/
|
|
23
|
+
coverage.xml
|
|
24
|
+
*.xml
|
|
25
|
+
|
|
26
|
+
# Weights & Large Data (Never commit real weights or data files)
|
|
27
|
+
*.pt
|
|
28
|
+
*.pth
|
|
29
|
+
*.onnx
|
|
30
|
+
*.fits
|
|
31
|
+
*.fits.gz
|
|
32
|
+
*.asdf
|
|
33
|
+
*.tar
|
|
34
|
+
*.tar.gz
|
|
35
|
+
data/
|
|
36
|
+
/weights/
|
|
37
|
+
!src/asteria/weights/
|
|
38
|
+
.cache/
|
|
39
|
+
|
|
40
|
+
# Sphinx docs build
|
|
41
|
+
docs/_build/
|
|
42
|
+
docs/build/
|
|
43
|
+
|
|
44
|
+
# IDE & OS
|
|
45
|
+
.DS_Store
|
|
46
|
+
.idea/
|
|
47
|
+
.vscode/
|
|
48
|
+
*.swp
|
|
49
|
+
|
|
50
|
+
# Untracked developer notes & guidelines
|
|
51
|
+
guidelines.md
|
|
52
|
+
*guidelines*.md
|
|
53
|
+
|
|
54
|
+
# Agent memory & guidelines (kept locally for next sessions, excluded from git)
|
|
55
|
+
MEMORY.md
|
|
56
|
+
*memory*.md
|
|
57
|
+
AGENTS.md
|
|
58
|
+
*agent*.md
|
|
59
|
+
.agents/
|
|
60
|
+
.agent/
|
|
61
|
+
_agents/
|
|
62
|
+
_agent/
|
|
63
|
+
GEMINI.md
|
|
64
|
+
*gemini*.md
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pablo M. Sanchez-Alarcon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: asteria-roman
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight astronomical deep learning inference engine and instance deblender powered by boundary-aware UNet++
|
|
5
|
+
Project-URL: Homepage, https://github.com/PabloMSanAla/asteria
|
|
6
|
+
Project-URL: Documentation, https://asteria.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/PabloMSanAla/asteria.git
|
|
8
|
+
Project-URL: Issues, https://github.com/PabloMSanAla/asteria/issues
|
|
9
|
+
Author-email: "Pablo M. Sanchez-Alarcon" <pablo.sanchezalarcon@nasa.gov>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: asdf,astronomy,astrophysics,deblending,deep-learning,fits,roman-space-telescope,segmentation,unetplusplus
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: astropy>=5.0.0
|
|
23
|
+
Requires-Dist: matplotlib>=3.6.0
|
|
24
|
+
Requires-Dist: numpy>=1.22.0
|
|
25
|
+
Requires-Dist: pixel-clarity>=0.9.0
|
|
26
|
+
Requires-Dist: requests>=2.28.0
|
|
27
|
+
Requires-Dist: roman-datamodels>=1.0.0
|
|
28
|
+
Requires-Dist: scipy>=1.9.0
|
|
29
|
+
Requires-Dist: torch>=2.0.0
|
|
30
|
+
Requires-Dist: tqdm>=4.65.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
36
|
+
Provides-Extra: docs
|
|
37
|
+
Requires-Dist: myst-parser>=2.0.0; extra == 'docs'
|
|
38
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == 'docs'
|
|
39
|
+
Requires-Dist: sphinx>=7.0.0; extra == 'docs'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# Asteria 🌌
|
|
43
|
+
|
|
44
|
+
[](https://pypi.org/project/asteria/)
|
|
45
|
+
[](https://pypi.org/project/asteria/)
|
|
46
|
+
[](https://github.com/PabloMSanAla/asteria/actions)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
[](https://asteria.readthedocs.io/en/latest/?badge=latest)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
<p><strong>Asteria</strong> is a lightweight, high-performance deep learning inference engine and instance deblender for stars in astronomical imaging, powered by boundary-aware <strong>UNet++ (Nested U-Net)</strong>.</p>
|
|
53
|
+
|
|
54
|
+
<p>Designed for the <strong>Nancy Grace Roman Space Telescope</strong>, Asteria provides promptless, end-to-end star detection in a single neural forward pass.</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<img width="40%" src="https://raw.githubusercontent.com/PabloMSanAla/asteria/prepare-production/docs/_static/images/example_blinking.gif" alt="Asteria segmentation example">
|
|
58
|
+
<sub><br> Example of <strong>Asteria</strong> star detection on a simulated Roman WFI exposure.</sub>
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Key Features
|
|
65
|
+
|
|
66
|
+
- **Lightweight & Self-Contained**: Pure PyTorch UNet++ architecture without bulky dependencies or heavyweight vision foundation models.
|
|
67
|
+
- **Hardware Acceleration with Automatic Fallback**: Auto-detects and optimizes execution across **NVIDIA CUDA** (with TF32 and AMP), **Apple Silicon MPS** (Metal Performance Shaders on macOS), and universal **CPU**.
|
|
68
|
+
- **Physical Boundary-Aware Deblending**: Trained with 3-class supervision:
|
|
69
|
+
- `0`: Sky Background
|
|
70
|
+
- `1`: Source Interior / Core
|
|
71
|
+
- `2`: Deblending Boundary / Contact Interface
|
|
72
|
+
- **Seamless Tiled Dense Inference (`predict_dense`)**: Sliding-window 2D Hann/cosine window blending to process arbitrary image sizes (from local cutouts up to full $4088 \times 4088$ Roman WFI exposures) with bounded memory ($< 350$ MB VRAM).
|
|
73
|
+
- **Photometric LeakySB Stretch**: Non-linear surface brightness transformation that preserves stellar point-spread functions (PSFs) while lifting faint, diffuse galactic wings.
|
|
74
|
+
- **Unified Astronomical I/O**: Direct support for 2D astronomical **FITS** (`.fits`, `.fits.gz`), Roman **ASDF** (`.asdf` Level 2 calibrated exposures and Level 3 mosaics via `roman_datamodels`), and raw **NumPy** arrays. Automatically converts Level 2 exposures to surface brightness units ($\text{MJy/sr}$) using calibrated photometry and enables $\text{ZP}=20.472$.
|
|
75
|
+
- **Instant Deblending**: Marker-controlled watershed expansion turning dense neural predictions into discrete celestial catalogs with centroids, bounding boxes, and photometry.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
### From PyPI
|
|
82
|
+
```bash
|
|
83
|
+
pip install asteria-roman
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### From Source
|
|
87
|
+
```bash
|
|
88
|
+
git clone https://github.com/PabloMSanAla/asteria.git
|
|
89
|
+
cd asteria
|
|
90
|
+
pip install -e .
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Quickstart
|
|
96
|
+
|
|
97
|
+
### 1. Python API
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import asteria
|
|
101
|
+
|
|
102
|
+
# 1. Load pre-trained model (auto-downloads weights on first run, auto-selects device)
|
|
103
|
+
segmentor = asteria.load_model("latest")
|
|
104
|
+
|
|
105
|
+
# 2. Run dense 3-class segmentation inference on a FITS or ASDF exposure
|
|
106
|
+
pred_mask, probs, stretched = segmentor.predict_dense(
|
|
107
|
+
"scene_0001_F106.fits",
|
|
108
|
+
tile_size=512,
|
|
109
|
+
overlap=64,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# 3. Render publication-ready side-by-side 2-panel figure
|
|
113
|
+
fig = asteria.plot_two_panel(
|
|
114
|
+
stretched=stretched,
|
|
115
|
+
pred_mask=pred_mask,
|
|
116
|
+
save_path="prediction.png",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# 4. Extract discrete, deblended astronomical sources (marker-controlled watershed)
|
|
120
|
+
catalog = segmentor.segment("scene_0001_F106.fits")
|
|
121
|
+
print(f"Extracted {len(catalog.masks)} distinct celestial objects!")
|
|
122
|
+
for idx, (cx, cy) in enumerate(catalog.centroids[:5]):
|
|
123
|
+
print(f"Source #{idx + 1}: centroid=({cx:.1f}, {cy:.1f}), area={catalog.areas[idx]} px")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 2. Command-Line Interface (CLI)
|
|
127
|
+
|
|
128
|
+
Asteria includes the `asteria-predict` CLI command:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Basic prediction and display
|
|
132
|
+
asteria-predict scene.fits
|
|
133
|
+
|
|
134
|
+
# Full-field tiled inference with saving and FITS export
|
|
135
|
+
asteria-predict scene.fits \
|
|
136
|
+
--tile_size 512 \
|
|
137
|
+
--overlap 64 \
|
|
138
|
+
--output results.png \
|
|
139
|
+
--export_fits segmap.fits \
|
|
140
|
+
--deblend \
|
|
141
|
+
--no_display
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Model Architecture & Weights History
|
|
147
|
+
|
|
148
|
+
| Weight Version | Backbone | Resolution | Training Set | Epochs | Interior IoU | Edge IoU (tol=1px) | Macro IoU | Training cutouts | Hardware |
|
|
149
|
+
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
150
|
+
| **`v0.1.0`** (latest) | UNet++ (32-512) | $512 \times 512$ | Roman WFI Synthetic | 80 | **0.754** | **0.513** | **0.6335** | 2800 | NASA NAS GH200 |
|
|
151
|
+
|
|
152
|
+
For comprehensive architectural details and benchmark comparisons, see the [Asteria Documentation](https://asteria.readthedocs.io).
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Asteria 🌌
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/asteria/)
|
|
4
|
+
[](https://pypi.org/project/asteria/)
|
|
5
|
+
[](https://github.com/PabloMSanAla/asteria/actions)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://asteria.readthedocs.io/en/latest/?badge=latest)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
<p><strong>Asteria</strong> is a lightweight, high-performance deep learning inference engine and instance deblender for stars in astronomical imaging, powered by boundary-aware <strong>UNet++ (Nested U-Net)</strong>.</p>
|
|
12
|
+
|
|
13
|
+
<p>Designed for the <strong>Nancy Grace Roman Space Telescope</strong>, Asteria provides promptless, end-to-end star detection in a single neural forward pass.</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<img width="40%" src="https://raw.githubusercontent.com/PabloMSanAla/asteria/prepare-production/docs/_static/images/example_blinking.gif" alt="Asteria segmentation example">
|
|
17
|
+
<sub><br> Example of <strong>Asteria</strong> star detection on a simulated Roman WFI exposure.</sub>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Key Features
|
|
24
|
+
|
|
25
|
+
- **Lightweight & Self-Contained**: Pure PyTorch UNet++ architecture without bulky dependencies or heavyweight vision foundation models.
|
|
26
|
+
- **Hardware Acceleration with Automatic Fallback**: Auto-detects and optimizes execution across **NVIDIA CUDA** (with TF32 and AMP), **Apple Silicon MPS** (Metal Performance Shaders on macOS), and universal **CPU**.
|
|
27
|
+
- **Physical Boundary-Aware Deblending**: Trained with 3-class supervision:
|
|
28
|
+
- `0`: Sky Background
|
|
29
|
+
- `1`: Source Interior / Core
|
|
30
|
+
- `2`: Deblending Boundary / Contact Interface
|
|
31
|
+
- **Seamless Tiled Dense Inference (`predict_dense`)**: Sliding-window 2D Hann/cosine window blending to process arbitrary image sizes (from local cutouts up to full $4088 \times 4088$ Roman WFI exposures) with bounded memory ($< 350$ MB VRAM).
|
|
32
|
+
- **Photometric LeakySB Stretch**: Non-linear surface brightness transformation that preserves stellar point-spread functions (PSFs) while lifting faint, diffuse galactic wings.
|
|
33
|
+
- **Unified Astronomical I/O**: Direct support for 2D astronomical **FITS** (`.fits`, `.fits.gz`), Roman **ASDF** (`.asdf` Level 2 calibrated exposures and Level 3 mosaics via `roman_datamodels`), and raw **NumPy** arrays. Automatically converts Level 2 exposures to surface brightness units ($\text{MJy/sr}$) using calibrated photometry and enables $\text{ZP}=20.472$.
|
|
34
|
+
- **Instant Deblending**: Marker-controlled watershed expansion turning dense neural predictions into discrete celestial catalogs with centroids, bounding boxes, and photometry.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
### From PyPI
|
|
41
|
+
```bash
|
|
42
|
+
pip install asteria-roman
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### From Source
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/PabloMSanAla/asteria.git
|
|
48
|
+
cd asteria
|
|
49
|
+
pip install -e .
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quickstart
|
|
55
|
+
|
|
56
|
+
### 1. Python API
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asteria
|
|
60
|
+
|
|
61
|
+
# 1. Load pre-trained model (auto-downloads weights on first run, auto-selects device)
|
|
62
|
+
segmentor = asteria.load_model("latest")
|
|
63
|
+
|
|
64
|
+
# 2. Run dense 3-class segmentation inference on a FITS or ASDF exposure
|
|
65
|
+
pred_mask, probs, stretched = segmentor.predict_dense(
|
|
66
|
+
"scene_0001_F106.fits",
|
|
67
|
+
tile_size=512,
|
|
68
|
+
overlap=64,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# 3. Render publication-ready side-by-side 2-panel figure
|
|
72
|
+
fig = asteria.plot_two_panel(
|
|
73
|
+
stretched=stretched,
|
|
74
|
+
pred_mask=pred_mask,
|
|
75
|
+
save_path="prediction.png",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# 4. Extract discrete, deblended astronomical sources (marker-controlled watershed)
|
|
79
|
+
catalog = segmentor.segment("scene_0001_F106.fits")
|
|
80
|
+
print(f"Extracted {len(catalog.masks)} distinct celestial objects!")
|
|
81
|
+
for idx, (cx, cy) in enumerate(catalog.centroids[:5]):
|
|
82
|
+
print(f"Source #{idx + 1}: centroid=({cx:.1f}, {cy:.1f}), area={catalog.areas[idx]} px")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Command-Line Interface (CLI)
|
|
86
|
+
|
|
87
|
+
Asteria includes the `asteria-predict` CLI command:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Basic prediction and display
|
|
91
|
+
asteria-predict scene.fits
|
|
92
|
+
|
|
93
|
+
# Full-field tiled inference with saving and FITS export
|
|
94
|
+
asteria-predict scene.fits \
|
|
95
|
+
--tile_size 512 \
|
|
96
|
+
--overlap 64 \
|
|
97
|
+
--output results.png \
|
|
98
|
+
--export_fits segmap.fits \
|
|
99
|
+
--deblend \
|
|
100
|
+
--no_display
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Model Architecture & Weights History
|
|
106
|
+
|
|
107
|
+
| Weight Version | Backbone | Resolution | Training Set | Epochs | Interior IoU | Edge IoU (tol=1px) | Macro IoU | Training cutouts | Hardware |
|
|
108
|
+
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
109
|
+
| **`v0.1.0`** (latest) | UNet++ (32-512) | $512 \times 512$ | Roman WFI Synthetic | 80 | **0.754** | **0.513** | **0.6335** | 2800 | NASA NAS GH200 |
|
|
110
|
+
|
|
111
|
+
For comprehensive architectural details and benchmark comparisons, see the [Asteria Documentation](https://asteria.readthedocs.io).
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Minimal makefile for Sphinx documentation
|
|
2
|
+
SPHINXOPTS ?=
|
|
3
|
+
SPHINXBUILD ?= sphinx-build
|
|
4
|
+
SOURCEDIR = .
|
|
5
|
+
BUILDDIR = _build
|
|
6
|
+
|
|
7
|
+
help:
|
|
8
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
9
|
+
|
|
10
|
+
.PHONY: help Makefile
|
|
11
|
+
|
|
12
|
+
%: Makefile
|
|
13
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
.. _api:
|
|
2
|
+
|
|
3
|
+
API Reference
|
|
4
|
+
=============
|
|
5
|
+
|
|
6
|
+
This section documents the public classes, functions, and modules in Asteria.
|
|
7
|
+
|
|
8
|
+
Top-Level Functions
|
|
9
|
+
-------------------
|
|
10
|
+
|
|
11
|
+
.. autofunction:: asteria.load_model
|
|
12
|
+
|
|
13
|
+
Inference & Deblending
|
|
14
|
+
----------------------
|
|
15
|
+
|
|
16
|
+
.. autoclass:: asteria.AsteriaSegmentor
|
|
17
|
+
:members:
|
|
18
|
+
:undoc-members:
|
|
19
|
+
:show-inheritance:
|
|
20
|
+
|
|
21
|
+
.. autoclass:: asteria.SegmentationResult
|
|
22
|
+
:show-inheritance:
|
|
23
|
+
|
|
24
|
+
.. autofunction:: asteria.get_optimal_device
|
|
25
|
+
|
|
26
|
+
.. autofunction:: asteria.get_device_info
|
|
27
|
+
|
|
28
|
+
Neural Network Architecture
|
|
29
|
+
---------------------------
|
|
30
|
+
|
|
31
|
+
.. autoclass:: asteria.UNetPlusPlus
|
|
32
|
+
:members:
|
|
33
|
+
:undoc-members:
|
|
34
|
+
:show-inheritance:
|
|
35
|
+
|
|
36
|
+
Photometric Stretches
|
|
37
|
+
---------------------
|
|
38
|
+
|
|
39
|
+
.. autofunction:: asteria.leaky_surface_brightness
|
|
40
|
+
|
|
41
|
+
.. autofunction:: asteria.asinh_stretch
|
|
42
|
+
|
|
43
|
+
.. autofunction:: asteria.linear_stretch
|
|
44
|
+
|
|
45
|
+
.. autofunction:: asteria.stretch_image
|
|
46
|
+
|
|
47
|
+
Astronomical Image I/O
|
|
48
|
+
----------------------
|
|
49
|
+
|
|
50
|
+
.. autofunction:: asteria.load_image
|
|
51
|
+
|
|
52
|
+
.. autoclass:: asteria.AstroImage
|
|
53
|
+
:show-inheritance:
|
|
54
|
+
|
|
55
|
+
Visualization
|
|
56
|
+
-------------
|
|
57
|
+
|
|
58
|
+
.. autofunction:: asteria.plot_two_panel
|
|
59
|
+
|
|
60
|
+
.. autofunction:: asteria.plot_instance_overlay
|
|
61
|
+
|
|
62
|
+
Model Weights Registry
|
|
63
|
+
----------------------
|
|
64
|
+
|
|
65
|
+
.. autoclass:: asteria.weights.registry.WeightMetadata
|
|
66
|
+
:show-inheritance:
|
|
67
|
+
|
|
68
|
+
.. autofunction:: asteria.weights.registry.get_weight_metadata
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
.. _architecture:
|
|
2
|
+
|
|
3
|
+
Model Architecture
|
|
4
|
+
==================
|
|
5
|
+
|
|
6
|
+
Asteria is powered by a **Nested U-Net (UNet++)** deep convolutional neural network, engineered specifically for high-contrast astronomical imaging and crowded-field source extraction.
|
|
7
|
+
|
|
8
|
+
.. contents:: Table of Contents
|
|
9
|
+
:depth: 2
|
|
10
|
+
:local:
|
|
11
|
+
|
|
12
|
+
Why UNet++ for Astronomical Source Detection?
|
|
13
|
+
---------------------------------------------
|
|
14
|
+
|
|
15
|
+
Traditional astronomical source extraction pipelines (such as SExtractor or standard thresholding) struggle in crowded stellar regions and galaxy clusters where object halos overlap. While standard U-Nets use direct skip connections between encoder and decoder stages, they suffer from a **semantic gap**: low-level encoder features contain rich spatial coordinates but high noise, whereas high-level decoder features contain abstract semantic context at degraded spatial resolution.
|
|
16
|
+
|
|
17
|
+
UNet++ (Zhou et al., 2018; 2019) overcomes this limitation by bridging the semantic gap through **nested, dense skip pathways**.
|
|
18
|
+
|
|
19
|
+
Mathematical Formulation
|
|
20
|
+
-------------------------
|
|
21
|
+
|
|
22
|
+
Let $x^{i,j}$ denote the output of node $X^{i,j}$, where:
|
|
23
|
+
|
|
24
|
+
* $i \in \{0, 1, 2, 3, 4\}$ indexes the downsampling depth along the encoder backbone.
|
|
25
|
+
* $j \in \{0, 1, 2, 3, 4\}$ indexes the dense convolution layer along the horizontal skip pathway.
|
|
26
|
+
|
|
27
|
+
The forward accumulation at each intermediate node is computed as:
|
|
28
|
+
|
|
29
|
+
.. math::
|
|
30
|
+
|
|
31
|
+
x^{i,j} = \begin{cases}
|
|
32
|
+
\mathcal{H}_{\text{enc}}\left( \mathcal{D}(x^{i-1, 0}) \right), & j = 0 \\
|
|
33
|
+
\mathcal{H}\left( \left[ [x^{i,k}]_{k=0}^{j-1}, \mathcal{U}(x^{i+1, j-1}) \right] \right), & j > 0
|
|
34
|
+
\end{cases}
|
|
35
|
+
|
|
36
|
+
where:
|
|
37
|
+
|
|
38
|
+
* $\mathcal{H}(\cdot)$ denotes a double convolution block (Conv2D $\to$ BatchNorm $\to$ ReLU $\to$ Conv2D $\to$ BatchNorm $\to$ ReLU).
|
|
39
|
+
* $\mathcal{D}(\cdot)$ denotes $2 \times 2$ max pooling with stride 2.
|
|
40
|
+
* $\mathcal{U}(\cdot)$ denotes bilinear upsampling with scale factor 2.
|
|
41
|
+
* $[\cdot]$ denotes channel-wise feature concatenation.
|
|
42
|
+
|
|
43
|
+
Through these nested skip pathways, feature maps from earlier stages are progressively merged and refined before reaching the decoder nodes, ensuring that fine astronomical boundary structures are preserved with sub-pixel fidelity.
|
|
44
|
+
|
|
45
|
+
Three-Class Boundary-Aware Target Formulation
|
|
46
|
+
---------------------------------------------
|
|
47
|
+
|
|
48
|
+
Standard binary segmentation (source vs. background) inevitably merges touching or overlapping astronomical sources into contiguous blobs, requiring heuristic post-processing deblenders.
|
|
49
|
+
|
|
50
|
+
Asteria formulates source detection as a **3-class boundary-aware semantic segmentation** task:
|
|
51
|
+
|
|
52
|
+
* **Class 0 (Sky Background)**: Deep space sky noise and intergalactic regions.
|
|
53
|
+
* **Class 1 (Source Interior / Core)**: High surface brightness galactic cores and stellar point spread functions (PSFs).
|
|
54
|
+
* **Class 2 (Deblending Boundary / Edge)**: The outer perimeter of celestial sources and, critically, the contact interface between overlapping or touching objects.
|
|
55
|
+
|
|
56
|
+
Deblending via Marker-Controlled Watershed
|
|
57
|
+
------------------------------------------
|
|
58
|
+
|
|
59
|
+
During inference, Asteria leverages the explicit boundary prediction to split touching galaxies:
|
|
60
|
+
|
|
61
|
+
1. **Topological Seed Markers**: Identified by thresholding the interior probability map ($P_{\text{core}} \ge 0.45$). Connected components generate distinct integer markers for each galaxy core.
|
|
62
|
+
2. **Total Foreground Mask**: Computed from $P_{\text{core}} + P_{\text{edge}} \ge 0.50$ (or $P_{\text{bg}} < 0.50$).
|
|
63
|
+
3. **Watershed Expansion**: Inverted Euclidean distance transforms expand the core markers outward until they collide along the predicted Class 2 boundary line, cleanly separating touching objects into discrete instances without morphological distortion.
|
|
64
|
+
|
|
65
|
+
Loss Function & Class Weighting
|
|
66
|
+
-------------------------------
|
|
67
|
+
|
|
68
|
+
Due to the extreme class imbalance in deep astronomical exposures (where the sky background occupies $\sim 85-90\%$ of pixels, source cores $\sim 2-5\%$, and 1-pixel boundaries $\sim 5-10\%$), models trained with standard unweighted Cross-Entropy collapse toward predicting the background.
|
|
69
|
+
|
|
70
|
+
Asteria was trained using a **Combined Weighted Cross-Entropy and Multi-Class Dice Loss**:
|
|
71
|
+
|
|
72
|
+
.. math::
|
|
73
|
+
|
|
74
|
+
\mathcal{L}_{\text{total}} = \mathcal{L}_{\text{WCE}} + \lambda \mathcal{L}_{\text{Dice}}
|
|
75
|
+
|
|
76
|
+
with empirically optimized class weights:
|
|
77
|
+
|
|
78
|
+
.. math::
|
|
79
|
+
|
|
80
|
+
\mathbf{w}_{\text{CE}} = [w_{\text{bg}} = 0.5, \; w_{\text{core}} = 2.5, \; w_{\text{edge}} = 8.0]
|
|
81
|
+
|
|
82
|
+
The high penalty ($8.0$) on boundary errors forces the network to prioritize thin edge continuity, which is the decisive factor for successful instance deblending.
|
|
83
|
+
|
|
84
|
+
Tiled Dense Sliding-Window Inference (`predict_dense`)
|
|
85
|
+
------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
To process large scientific exposures (such as the $4088 \times 4088$ detector arrays of the Nancy Grace Roman Space Telescope) without GPU out-of-memory (OOM) failures or artificial boundary seams:
|
|
88
|
+
|
|
89
|
+
1. The exposure is decomposed into overlapping $512 \times 512$ tiles with a default 64-pixel margin.
|
|
90
|
+
2. Each tile is evaluated in mini-batches through the neural network.
|
|
91
|
+
3. Softmax probability maps are accumulated using a **2D separable Hann / cosine window**:
|
|
92
|
+
|
|
93
|
+
.. math::
|
|
94
|
+
|
|
95
|
+
W(x, y) = \sin\left(\frac{\pi x}{T}\right) \cdot \sin\left(\frac{\pi y}{T}\right)
|
|
96
|
+
|
|
97
|
+
4. The accumulated probability tensor is normalized by the total weight matrix, completely eliminating edge discontinuity artifacts and bounding memory consumption to $< 350$ MB VRAM.
|