Skip to content
Merged
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
14 changes: 14 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
[//]: # (this file, may be copied, modified, propagated, or distributed except according to)
[//]: # (the terms contained in the file 'LICENCE.txt'.)

## [v1.3.1] – 2026-05-11

### Fixed
- **Cutana 0.3.0 compatibility** by removing the obsolete `synchronised_loading` kwarg from `StreamingOrchestrator.init_streaming` calls
- **Pretrained weight loading** when the repository is cloned without `git-lfs`: fall back to a HuggingFace download instead of failing on LFS pointer files (#7)

### Changed
- **Security:** replaced pickle-based `torch.save` / `torch.load` checkpointing with `safetensors`, removing the pickle deserialisation risk on untrusted model files (#9)
- **PyTorch minimum** raised to `>=2.6` in the conda environments to pick up upstream CVE fixes (#11)
- **Cutana minimum** raised to `>=0.3.0` in `environment.yml`, `environment_CI.yml`, and `pyproject.toml`

### Documentation
- **Programmatic Evaluation (Headless Mode)** section added to the README, showing how to run batch predictions through `Session.load_model()` + `Session.evaluate_all_images()` without launching the UI (#10)

## [v1.3.0] – 2026-02-11

### Added
Expand Down
2 changes: 1 addition & 1 deletion anomaly_match/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .utils.print_cfg import print_cfg
from .utils.set_log_level import set_log_level

__version__ = "1.3.0"
__version__ = "1.3.1"

__all__ = [
"get_default_cfg",
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies:
- pip
- pip:
- albumentations
- cutana>=0.2.1
- cutana>=0.3.0
- fitsbolt>=0.2
- opencv-python-headless
- safetensors
Expand Down
2 changes: 1 addition & 1 deletion environment_CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ dependencies:
- safetensors
- timm
- fitsbolt>=0.2
- cutana>=0.2.1
- cutana>=0.3.0
10 changes: 6 additions & 4 deletions prediction_process_cutana.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,7 @@ def evaluate_images_from_cutana(

cutana_orchestrator = cutana.StreamingOrchestrator(cutana_config)

cutana_orchestrator.init_streaming(
batch_size=batch_size, write_to_disk=False, synchronised_loading=False
)
cutana_orchestrator.init_streaming(batch_size=batch_size, write_to_disk=False)
except Exception as e:
logger.error(f"Failed to initialize Cutana orchestrator: {e}")
raise
Expand Down Expand Up @@ -266,7 +264,11 @@ def evaluate_images_from_cutana(
# Handle empty batches (cutana returns [] if all cutouts failed)
if isinstance(batch_data, list):
if len(batch_data) == 0:
logger.warning(f"Batch {batch_idx} returned empty cutouts (list), skipping")
logger.warning(
f"Batch {batch_idx} returned empty cutouts (list), skipping. "
f"Please ensure that number of extensions in Cutana source "
f"catalogues matches those of the training set."
)
continue
# Convert list to numpy array if needed
batch_data = np.array(batch_data)
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "anomaly_match"
version = "1.3.0"
version = "1.3.1"
description = "A tool for anomaly detection in images using semi-supervised and active learning with a GUI"
readme = "README.md"
license = { file = "LICENSE.txt" }
Expand Down Expand Up @@ -32,7 +32,7 @@ classifiers = [
dependencies = [
"albumentations",
"astropy",
"cutana>=0.2.1",
"cutana>=0.3.0",
"dotmap",
"fitsbolt>=0.2",
"h5py",
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/test_normalisation_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def _run_cutana_normalised(csv_path, fitsbolt_cfg, n_output_channels=3):
config.external_fitsbolt_cfg = fitsbolt_cfg

orchestrator = cutana.StreamingOrchestrator(config)
orchestrator.init_streaming(batch_size=10, write_to_disk=False, synchronised_loading=False)
orchestrator.init_streaming(batch_size=10, write_to_disk=False)

all_cutouts = []
for _ in range(orchestrator.get_batch_count()):
Expand All @@ -112,7 +112,7 @@ def _extract_raw_cutouts(csv_path, output_dir):
config.output_dir = output_dir

orchestrator = cutana.StreamingOrchestrator(config)
orchestrator.init_streaming(batch_size=10, write_to_disk=True, synchronised_loading=False)
orchestrator.init_streaming(batch_size=10, write_to_disk=True)
for _ in range(orchestrator.get_batch_count()):
orchestrator.next_batch()
orchestrator.cleanup()
Expand Down
7 changes: 3 additions & 4 deletions tests/unit/test_checkpoint_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

"""Unit tests for checkpoint_io: safetensors-based model checkpoint serialization."""

import json

import numpy as np
import pytest
import torch
from dotmap import DotMap
from fitsbolt.normalisation.NormalisationMethod import NormalisationMethod
from safetensors import safe_open

from anomaly_match.data_io.checkpoint_io import load_checkpoint, save_checkpoint

Expand Down Expand Up @@ -228,10 +231,6 @@ def test_no_pickle_in_file(self, tmp_path):

def test_metadata_is_plain_json(self, tmp_path):
"""All metadata in the safetensors header is valid JSON strings."""
import json

from safetensors import safe_open

path = save_checkpoint(_make_full_checkpoint(), tmp_path / "model")
with safe_open(str(path), framework="pt") as f:
metadata = f.metadata()
Expand Down
Loading