mirror of
https://github.com/macaodha/batdetect2.git
synced 2026-04-04 15:20:19 +02:00
Better cli docs
This commit is contained in:
parent
7277151f33
commit
e4bbde9995
@ -41,6 +41,8 @@ html_theme = "sphinx_book_theme"
|
|||||||
html_static_path = ["_static"]
|
html_static_path = ["_static"]
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
"home_page_in_toc": True,
|
"home_page_in_toc": True,
|
||||||
|
"show_navbar_depth": 2,
|
||||||
|
"show_toc_level": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
intersphinx_mapping = {
|
intersphinx_mapping = {
|
||||||
@ -58,7 +60,7 @@ intersphinx_mapping = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# -- Options for autodoc ------------------------------------------------------
|
# -- Options for autodoc ------------------------------------------------------
|
||||||
autosummary_generate = True
|
autosummary_generate = False
|
||||||
autosummary_imported_members = True
|
autosummary_imported_members = True
|
||||||
|
|
||||||
autodoc_default_options = {
|
autodoc_default_options = {
|
||||||
@ -70,3 +72,7 @@ autodoc_default_options = {
|
|||||||
"show-inheritance": True,
|
"show-inheritance": True,
|
||||||
"module-first": True,
|
"module-first": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numpydoc_show_class_members = False
|
||||||
|
numpydoc_show_inherited_class_members = False
|
||||||
|
numpydoc_class_members_toctree = False
|
||||||
|
|||||||
@ -80,4 +80,4 @@ pip install batdetect2
|
|||||||
- Run your first detection workflow:
|
- Run your first detection workflow:
|
||||||
{doc}`tutorials/run-inference-on-folder`
|
{doc}`tutorials/run-inference-on-folder`
|
||||||
- For practical task recipes, go to {doc}`how_to/index`
|
- For practical task recipes, go to {doc}`how_to/index`
|
||||||
- For command and option details, go to {doc}`reference/cli`
|
- For command and option details, go to {doc}`reference/cli/index`
|
||||||
|
|||||||
@ -27,4 +27,4 @@ batdetect2 predict file_list \
|
|||||||
- `--workers` to set data-loading parallelism.
|
- `--workers` to set data-loading parallelism.
|
||||||
- `--format` to select output format.
|
- `--format` to select output format.
|
||||||
|
|
||||||
For complete option details, see {doc}`../reference/cli`.
|
For complete option details, see {doc}`../reference/cli/index`.
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
CLI reference
|
|
||||||
=============
|
|
||||||
|
|
||||||
.. click:: batdetect2.cli:cli
|
|
||||||
:prog: batdetect2
|
|
||||||
:nested: full
|
|
||||||
|
|
||||||
8
docs/source/reference/cli/base.rst
Normal file
8
docs/source/reference/cli/base.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Base command
|
||||||
|
============
|
||||||
|
|
||||||
|
The options on this page apply to all subcommands.
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli:cli
|
||||||
|
:prog: batdetect2
|
||||||
|
:nested: none
|
||||||
8
docs/source/reference/cli/data.rst
Normal file
8
docs/source/reference/cli/data.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Data command
|
||||||
|
============
|
||||||
|
|
||||||
|
Inspect and convert dataset config files.
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli.data:data
|
||||||
|
:prog: batdetect2 data
|
||||||
|
:nested: full
|
||||||
17
docs/source/reference/cli/detect_legacy.rst
Normal file
17
docs/source/reference/cli/detect_legacy.rst
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Legacy detect command
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
``batdetect2 detect`` is a legacy compatibility command.
|
||||||
|
Prefer ``batdetect2 predict directory`` for new workflows.
|
||||||
|
|
||||||
|
Migration at a glance
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
- Legacy: ``batdetect2 detect AUDIO_DIR ANN_DIR DETECTION_THRESHOLD``
|
||||||
|
- Current: ``batdetect2 predict directory MODEL_PATH AUDIO_DIR OUTPUT_PATH``
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli.compat:detect
|
||||||
|
:prog: batdetect2 detect
|
||||||
|
:nested: none
|
||||||
8
docs/source/reference/cli/evaluate.rst
Normal file
8
docs/source/reference/cli/evaluate.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Evaluate command
|
||||||
|
================
|
||||||
|
|
||||||
|
Evaluate a checkpoint against a configured test dataset.
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli.evaluate:evaluate_command
|
||||||
|
:prog: batdetect2 evaluate
|
||||||
|
:nested: none
|
||||||
18
docs/source/reference/cli/index.md
Normal file
18
docs/source/reference/cli/index.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# CLI reference
|
||||||
|
|
||||||
|
Use this section like this:
|
||||||
|
|
||||||
|
1. Check `base` for global options shared by all commands.
|
||||||
|
2. Pick the command page you need (`predict`, `data`, `train`, or `evaluate`).
|
||||||
|
3. Use `detect_legacy` only if you are maintaining old workflows.
|
||||||
|
|
||||||
|
```{toctree}
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
base
|
||||||
|
predict
|
||||||
|
data
|
||||||
|
train
|
||||||
|
evaluate
|
||||||
|
detect_legacy
|
||||||
|
```
|
||||||
8
docs/source/reference/cli/predict.rst
Normal file
8
docs/source/reference/cli/predict.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Predict command
|
||||||
|
===============
|
||||||
|
|
||||||
|
Run model inference from a directory, a file list, or a dataset.
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli.inference:predict
|
||||||
|
:prog: batdetect2 predict
|
||||||
|
:nested: full
|
||||||
8
docs/source/reference/cli/train.rst
Normal file
8
docs/source/reference/cli/train.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Train command
|
||||||
|
=============
|
||||||
|
|
||||||
|
Train a model from dataset configs or fine-tune from a checkpoint.
|
||||||
|
|
||||||
|
.. click:: batdetect2.cli.train:train_command
|
||||||
|
:prog: batdetect2 train
|
||||||
|
:nested: none
|
||||||
@ -1,7 +0,0 @@
|
|||||||
# Config Reference
|
|
||||||
|
|
||||||
```{eval-rst}
|
|
||||||
.. automodule:: batdetect2.config
|
|
||||||
:members:
|
|
||||||
:inherited-members: pydantic.BaseModel
|
|
||||||
```
|
|
||||||
5
docs/source/reference/configs.rst
Normal file
5
docs/source/reference/configs.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Config reference
|
||||||
|
================
|
||||||
|
|
||||||
|
.. automodule:: batdetect2.config
|
||||||
|
:members:
|
||||||
@ -6,7 +6,7 @@ configuration, and data structures.
|
|||||||
```{toctree}
|
```{toctree}
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
cli
|
cli/index
|
||||||
configs
|
configs
|
||||||
targets
|
targets
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
# Targets Reference
|
|
||||||
|
|
||||||
```{eval-rst}
|
|
||||||
.. automodule:: batdetect2.targets
|
|
||||||
:members:
|
|
||||||
```
|
|
||||||
5
docs/source/reference/targets.rst
Normal file
5
docs/source/reference/targets.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Targets reference
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. automodule:: batdetect2.targets
|
||||||
|
:members:
|
||||||
@ -1,6 +1,6 @@
|
|||||||
## Defining Target Geometry: Mapping Sound Event Regions
|
# Defining Target Geometry: Mapping Sound Event Regions
|
||||||
|
|
||||||
### Introduction
|
## Introduction
|
||||||
|
|
||||||
In the previous steps of defining targets, we focused on determining _which_ sound events are relevant (`filtering`), _what_ descriptive tags they should have (`transform`), and _which category_ they belong to (`classes`).
|
In the previous steps of defining targets, we focused on determining _which_ sound events are relevant (`filtering`), _what_ descriptive tags they should have (`transform`), and _which category_ they belong to (`classes`).
|
||||||
However, for the model to learn effectively, it also needs to know **where** in the spectrogram each sound event is located and approximately **how large** it is.
|
However, for the model to learn effectively, it also needs to know **where** in the spectrogram each sound event is located and approximately **how large** it is.
|
||||||
@ -10,7 +10,7 @@ This ROI contains detailed spatial information (start/end time, low/high frequen
|
|||||||
|
|
||||||
This section explains how BatDetect2 converts the geometric ROI from your annotations into the specific positional and size information used as targets during model training.
|
This section explains how BatDetect2 converts the geometric ROI from your annotations into the specific positional and size information used as targets during model training.
|
||||||
|
|
||||||
### From ROI to Model Targets: Position & Size
|
## From ROI to Model Targets: Position & Size
|
||||||
|
|
||||||
BatDetect2 does not directly predict a full bounding box.
|
BatDetect2 does not directly predict a full bounding box.
|
||||||
Instead, it is trained to predict:
|
Instead, it is trained to predict:
|
||||||
@ -21,7 +21,7 @@ Instead, it is trained to predict:
|
|||||||
This step defines _how_ BatDetect2 calculates this specific reference point and these numerical size values from the original annotation's bounding box.
|
This step defines _how_ BatDetect2 calculates this specific reference point and these numerical size values from the original annotation's bounding box.
|
||||||
It also handles the reverse process – converting predicted positions and sizes back into bounding boxes for visualization or analysis.
|
It also handles the reverse process – converting predicted positions and sizes back into bounding boxes for visualization or analysis.
|
||||||
|
|
||||||
### Configuring the ROI Mapping
|
## Configuring the ROI Mapping
|
||||||
|
|
||||||
You can control how this conversion happens through settings in your configuration file (e.g., your main `.yaml` file).
|
You can control how this conversion happens through settings in your configuration file (e.g., your main `.yaml` file).
|
||||||
These settings are usually placed within the main `targets:` configuration block, under a specific `roi:` key.
|
These settings are usually placed within the main `targets:` configuration block, under a specific `roi:` key.
|
||||||
@ -74,12 +74,12 @@ targets: # Top-level key for target definition
|
|||||||
frequency_scale: 0.00116 # e.g., Model predicts height relative to ~860Hz (or other model-specific scaling)
|
frequency_scale: 0.00116 # e.g., Model predicts height relative to ~860Hz (or other model-specific scaling)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Decoding Size Predictions
|
## Decoding Size Predictions
|
||||||
|
|
||||||
These scaling factors (`time_scale`, `frequency_scale`) are also essential for interpreting the model's output correctly.
|
These scaling factors (`time_scale`, `frequency_scale`) are also essential for interpreting the model's output correctly.
|
||||||
When the model predicts numerical values for width and height, BatDetect2 uses these same scales (in reverse) to convert those numbers back into physically meaningful durations (seconds) and bandwidths (Hz/kHz) when reconstructing bounding boxes from predictions.
|
When the model predicts numerical values for width and height, BatDetect2 uses these same scales (in reverse) to convert those numbers back into physically meaningful durations (seconds) and bandwidths (Hz/kHz) when reconstructing bounding boxes from predictions.
|
||||||
|
|
||||||
### Outcome
|
## Outcome
|
||||||
|
|
||||||
By configuring the `roi` settings, you ensure that BatDetect2 consistently translates the geometric information from your annotations into the specific reference points and scaled size values required for training the model.
|
By configuring the `roi` settings, you ensure that BatDetect2 consistently translates the geometric information from your annotations into the specific reference points and scaled size values required for training the model.
|
||||||
Using consistent scales that are appropriate for your data and potentially beneficial for training stability allows the model to effectively learn not just _what_ sound is present, but also _where_ it is located and _how large_ it is, and enables meaningful interpretation of the model's spatial and size predictions.
|
Using consistent scales that are appropriate for your data and potentially beneficial for training stability allows the model to effectively learn not just _what_ sound is present, but also _where_ it is located and _how large_ it is, and enables meaningful interpretation of the model's spatial and size predictions.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
## Bringing It All Together: The `Targets` Object
|
# Bringing It All Together: The `Targets` Object
|
||||||
|
|
||||||
### Recap: Defining Your Target Strategy
|
## Recap: Defining Your Target Strategy
|
||||||
|
|
||||||
In the previous sections, we covered the sequential steps to precisely define what your BatDetect2 model should learn, specified within your configuration file:
|
In the previous sections, we covered the sequential steps to precisely define what your BatDetect2 model should learn, specified within your configuration file:
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ In the previous sections, we covered the sequential steps to precisely define wh
|
|||||||
|
|
||||||
You define all these aspects within your configuration file (e.g., YAML), which holds the complete specification for your target definition strategy, typically under a main `targets:` key.
|
You define all these aspects within your configuration file (e.g., YAML), which holds the complete specification for your target definition strategy, typically under a main `targets:` key.
|
||||||
|
|
||||||
### What is the `Targets` Object?
|
## What is the `Targets` Object?
|
||||||
|
|
||||||
While the configuration file specifies _what_ you want to happen, BatDetect2 needs an active component to actually _perform_ these steps.
|
While the configuration file specifies _what_ you want to happen, BatDetect2 needs an active component to actually _perform_ these steps.
|
||||||
This is the role of the `Targets` object.
|
This is the role of the `Targets` object.
|
||||||
@ -21,7 +21,7 @@ The `Targets` is an organized container that holds all the specific functions an
|
|||||||
It's created directly from your configuration and provides methods to apply the **filtering**, **transformation**, **ROI mapping** (geometry to position/size and back), **class encoding**, and **class decoding** steps you defined.
|
It's created directly from your configuration and provides methods to apply the **filtering**, **transformation**, **ROI mapping** (geometry to position/size and back), **class encoding**, and **class decoding** steps you defined.
|
||||||
It effectively bundles together all the target definition logic determined by your settings into a single, usable object.
|
It effectively bundles together all the target definition logic determined by your settings into a single, usable object.
|
||||||
|
|
||||||
### How is it Created and Used?
|
## How is it Created and Used?
|
||||||
|
|
||||||
For most standard training workflows, you typically won't need to create or interact with the `Targets` object directly in Python code.
|
For most standard training workflows, you typically won't need to create or interact with the `Targets` object directly in Python code.
|
||||||
BatDetect2 usually handles its creation automatically when you provide your main configuration file during training setup.
|
BatDetect2 usually handles its creation automatically when you provide your main configuration file during training setup.
|
||||||
@ -50,7 +50,7 @@ targets_processor: TargetProtocol = load_targets(target_config_file)
|
|||||||
# to be used internally by the training pipeline or for prediction processing.
|
# to be used internally by the training pipeline or for prediction processing.
|
||||||
```
|
```
|
||||||
|
|
||||||
### What Does the `Targets` Object Do? (Its Role)
|
## What Does the `Targets` Object Do? (Its Role)
|
||||||
|
|
||||||
Once created, the `targets_processor` object plays several vital roles within the BatDetect2 system:
|
Once created, the `targets_processor` object plays several vital roles within the BatDetect2 system:
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ Once created, the `targets_processor` object plays several vital roles within th
|
|||||||
- `targets_processor.generic_class_tags`: The tags representing the generic class.
|
- `targets_processor.generic_class_tags`: The tags representing the generic class.
|
||||||
- `targets_processor.dimension_names`: The names used for the size dimensions (e.g., `['width', 'height']`).
|
- `targets_processor.dimension_names`: The names used for the size dimensions (e.g., `['width', 'height']`).
|
||||||
|
|
||||||
### Why is Understanding This Important?
|
## Why is Understanding This Important?
|
||||||
|
|
||||||
As a researcher using BatDetect2, your primary interaction is typically through the **configuration file**.
|
As a researcher using BatDetect2, your primary interaction is typically through the **configuration file**.
|
||||||
The `Targets` object is the component that materializes your configurations.
|
The `Targets` object is the component that materializes your configurations.
|
||||||
@ -84,7 +84,7 @@ Understanding its role can be important:
|
|||||||
While standard training runs handle this object internally, the underlying functions for filtering, transforming, encoding, decoding, and ROI mapping are accessible or can be built individually.
|
While standard training runs handle this object internally, the underlying functions for filtering, transforming, encoding, decoding, and ROI mapping are accessible or can be built individually.
|
||||||
This modular design provides the **flexibility to use or customize specific parts of the target definition workflow programmatically** for advanced analyses, integration tasks, or specialized data processing pipelines, should you need to go beyond the standard configuration-driven approach.
|
This modular design provides the **flexibility to use or customize specific parts of the target definition workflow programmatically** for advanced analyses, integration tasks, or specialized data processing pipelines, should you need to go beyond the standard configuration-driven approach.
|
||||||
|
|
||||||
### Summary
|
## Summary
|
||||||
|
|
||||||
The `Targets` object encapsulates the entire configured target definition logic specified in your `TargetConfig` file.
|
The `Targets` object encapsulates the entire configured target definition logic specified in your `TargetConfig` file.
|
||||||
It acts as the central component within BatDetect2 for applying filtering, tag transformation, ROI mapping (geometry to/from position/size), class encoding (for training preparation), and class/ROI decoding (for interpreting predictions).
|
It acts as the central component within BatDetect2 for applying filtering, tag transformation, ROI mapping (geometry to/from position/size), class encoding (for training preparation), and class/ROI decoding (for interpreting predictions).
|
||||||
|
|||||||
@ -25,7 +25,7 @@ batdetect2 predict directory \
|
|||||||
## What to do next
|
## What to do next
|
||||||
|
|
||||||
- Use {doc}`../how_to/tune-detection-threshold` to tune sensitivity.
|
- Use {doc}`../how_to/tune-detection-threshold` to tune sensitivity.
|
||||||
- Use {doc}`../reference/cli` for full command options.
|
- Use {doc}`../reference/cli/index` for full command options.
|
||||||
|
|
||||||
Note: this is the initial Phase 1 scaffold and will be expanded with a full,
|
Note: this is the initial Phase 1 scaffold and will be expanded with a full,
|
||||||
validated end-to-end walkthrough.
|
validated end-to-end walkthrough.
|
||||||
|
|||||||
@ -27,7 +27,11 @@ BatDetect2 - Detection and Classification
|
|||||||
help="Increase verbosity. -v for INFO, -vv for DEBUG.",
|
help="Increase verbosity. -v for INFO, -vv for DEBUG.",
|
||||||
)
|
)
|
||||||
def cli(verbose: int = 0):
|
def cli(verbose: int = 0):
|
||||||
"""BatDetect2 - Bat Call Detection and Classification."""
|
"""Run the BatDetect2 CLI.
|
||||||
|
|
||||||
|
This command initializes logging and exposes subcommands for prediction,
|
||||||
|
training, evaluation, and dataset utilities.
|
||||||
|
"""
|
||||||
click.echo(INFO_STR)
|
click.echo(INFO_STR)
|
||||||
|
|
||||||
enable_logging(verbose)
|
enable_logging(verbose)
|
||||||
|
|||||||
@ -12,7 +12,13 @@ DEFAULT_MODEL_PATH = os.path.join(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command(
|
||||||
|
short_help="Legacy detection command.",
|
||||||
|
epilog=(
|
||||||
|
"Deprecated workflow. Prefer `batdetect2 predict directory` for "
|
||||||
|
"new analyses."
|
||||||
|
),
|
||||||
|
)
|
||||||
@click.argument(
|
@click.argument(
|
||||||
"audio_dir",
|
"audio_dir",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
@ -68,7 +74,10 @@ def detect(
|
|||||||
time_expansion_factor: int,
|
time_expansion_factor: int,
|
||||||
**args,
|
**args,
|
||||||
):
|
):
|
||||||
"""Detect bat calls in files in AUDIO_DIR and save predictions to ANN_DIR.
|
"""Legacy detection command for directory-based inference.
|
||||||
|
|
||||||
|
Detect bat calls in files in `AUDIO_DIR` and save predictions to
|
||||||
|
`ANN_DIR`.
|
||||||
|
|
||||||
DETECTION_THRESHOLD is the detection threshold. All predictions with a
|
DETECTION_THRESHOLD is the detection threshold. All predictions with a
|
||||||
score below this threshold will be discarded. Values between 0 and 1.
|
score below this threshold will be discarded. Values between 0 and 1.
|
||||||
@ -78,6 +87,11 @@ def detect(
|
|||||||
Spaces in the input paths will throw an error. Wrap in quotes.
|
Spaces in the input paths will throw an error. Wrap in quotes.
|
||||||
|
|
||||||
Input files should be short in duration e.g. < 30 seconds.
|
Input files should be short in duration e.g. < 30 seconds.
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
This command is kept for backwards compatibility. Prefer
|
||||||
|
`batdetect2 predict directory` for new workflows.
|
||||||
"""
|
"""
|
||||||
from batdetect2 import api
|
from batdetect2 import api
|
||||||
from batdetect2.utils.detector_utils import save_results_to_file
|
from batdetect2.utils.detector_utils import save_results_to_file
|
||||||
@ -132,7 +146,7 @@ def detect(
|
|||||||
|
|
||||||
|
|
||||||
def print_config(config):
|
def print_config(config):
|
||||||
"""Print the processing configuration."""
|
"""Print the processing configuration values."""
|
||||||
click.echo("\nProcessing Configuration:")
|
click.echo("\nProcessing Configuration:")
|
||||||
click.echo(f"Time Expansion Factor: {config.get('time_expansion')}")
|
click.echo(f"Time Expansion Factor: {config.get('time_expansion')}")
|
||||||
click.echo(f"Detection Threshold: {config.get('detection_threshold')}")
|
click.echo(f"Detection Threshold: {config.get('detection_threshold')}")
|
||||||
|
|||||||
@ -7,12 +7,12 @@ from batdetect2.cli.base import cli
|
|||||||
__all__ = ["data"]
|
__all__ = ["data"]
|
||||||
|
|
||||||
|
|
||||||
@cli.group()
|
@cli.group(short_help="Inspect and convert datasets.")
|
||||||
def data():
|
def data():
|
||||||
"""Inspect and convert dataset configuration files."""
|
"""Inspect and convert dataset configuration files."""
|
||||||
|
|
||||||
|
|
||||||
@data.command()
|
@data.command(short_help="Print dataset summary information.")
|
||||||
@click.argument(
|
@click.argument(
|
||||||
"dataset_config",
|
"dataset_config",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
@ -20,17 +20,27 @@ def data():
|
|||||||
@click.option(
|
@click.option(
|
||||||
"--field",
|
"--field",
|
||||||
type=str,
|
type=str,
|
||||||
help="If the dataset info is in a nested field please specify here.",
|
help=(
|
||||||
|
"Nested field name that contains dataset configuration. "
|
||||||
|
"Use this when the config is wrapped in a larger file."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--targets",
|
"--targets",
|
||||||
"targets_path",
|
"targets_path",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
|
help=(
|
||||||
|
"Path to targets config file. If provided, a per-class summary "
|
||||||
|
"table is printed."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--base-dir",
|
"--base-dir",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
help="The base directory to which all recording and annotations paths are relative to.",
|
help=(
|
||||||
|
"Base directory used to resolve relative recording and annotation "
|
||||||
|
"paths in the dataset config."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
def summary(
|
def summary(
|
||||||
dataset_config: Path,
|
dataset_config: Path,
|
||||||
@ -38,7 +48,11 @@ def summary(
|
|||||||
targets_path: Path | None = None,
|
targets_path: Path | None = None,
|
||||||
base_dir: Path | None = None,
|
base_dir: Path | None = None,
|
||||||
):
|
):
|
||||||
"""Show annotation counts and optional class summary."""
|
"""Show dataset size and optional class summary.
|
||||||
|
|
||||||
|
Prints the number of annotated clips. If `--targets` is provided, it also
|
||||||
|
prints a per-class summary table based on the configured targets.
|
||||||
|
"""
|
||||||
from batdetect2.data import compute_class_summary, load_dataset_from_config
|
from batdetect2.data import compute_class_summary, load_dataset_from_config
|
||||||
from batdetect2.targets import load_targets
|
from batdetect2.targets import load_targets
|
||||||
|
|
||||||
@ -62,7 +76,7 @@ def summary(
|
|||||||
print(summary.to_markdown())
|
print(summary.to_markdown())
|
||||||
|
|
||||||
|
|
||||||
@data.command()
|
@data.command(short_help="Convert dataset config to annotation set.")
|
||||||
@click.argument(
|
@click.argument(
|
||||||
"dataset_config",
|
"dataset_config",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
@ -70,7 +84,10 @@ def summary(
|
|||||||
@click.option(
|
@click.option(
|
||||||
"--field",
|
"--field",
|
||||||
type=str,
|
type=str,
|
||||||
help="If the dataset info is in a nested field please specify here.",
|
help=(
|
||||||
|
"Nested field name that contains dataset configuration. "
|
||||||
|
"Use this when the config is wrapped in a larger file."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--output",
|
"--output",
|
||||||
@ -80,12 +97,18 @@ def summary(
|
|||||||
@click.option(
|
@click.option(
|
||||||
"--base-dir",
|
"--base-dir",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
help="The base directory to which all recording and annotations paths are relative to.",
|
help=(
|
||||||
|
"Base directory used to resolve relative recording and annotation "
|
||||||
|
"paths in the dataset config."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--audio-dir",
|
"--audio-dir",
|
||||||
type=click.Path(exists=True),
|
type=click.Path(exists=True),
|
||||||
help="The directory containing the audio files. All paths will be relative to this directory.",
|
help=(
|
||||||
|
"Directory containing audio files. Output annotation paths are "
|
||||||
|
"made relative to this directory."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
def convert(
|
def convert(
|
||||||
dataset_config: Path,
|
dataset_config: Path,
|
||||||
@ -94,7 +117,11 @@ def convert(
|
|||||||
base_dir: Path | None = None,
|
base_dir: Path | None = None,
|
||||||
audio_dir: Path | None = None,
|
audio_dir: Path | None = None,
|
||||||
):
|
):
|
||||||
"""Convert a dataset config file to soundevent format."""
|
"""Convert a dataset config into soundevent annotation-set format.
|
||||||
|
|
||||||
|
Writes a single annotation-set file that can be used by downstream tools.
|
||||||
|
Use `--audio-dir` to control relative audio path handling in the output.
|
||||||
|
"""
|
||||||
from soundevent import data, io
|
from soundevent import data, io
|
||||||
|
|
||||||
from batdetect2.data import load_dataset, load_dataset_config
|
from batdetect2.data import load_dataset, load_dataset_config
|
||||||
|
|||||||
@ -11,20 +11,73 @@ __all__ = ["evaluate_command"]
|
|||||||
DEFAULT_OUTPUT_DIR = Path("outputs") / "evaluation"
|
DEFAULT_OUTPUT_DIR = Path("outputs") / "evaluation"
|
||||||
|
|
||||||
|
|
||||||
@cli.command(name="evaluate")
|
@cli.command(name="evaluate", short_help="Evaluate a model checkpoint.")
|
||||||
@click.argument("model_path", type=click.Path(exists=True))
|
@click.argument("model_path", type=click.Path(exists=True))
|
||||||
@click.argument("test_dataset", type=click.Path(exists=True))
|
@click.argument("test_dataset", type=click.Path(exists=True))
|
||||||
@click.option("--targets", "targets_config", type=click.Path(exists=True))
|
@click.option(
|
||||||
@click.option("--audio-config", type=click.Path(exists=True))
|
"--targets",
|
||||||
@click.option("--evaluation-config", type=click.Path(exists=True))
|
"targets_config",
|
||||||
@click.option("--inference-config", type=click.Path(exists=True))
|
type=click.Path(exists=True),
|
||||||
@click.option("--outputs-config", type=click.Path(exists=True))
|
help="Path to targets config file.",
|
||||||
@click.option("--logging-config", type=click.Path(exists=True))
|
)
|
||||||
@click.option("--base-dir", type=click.Path(), default=Path.cwd())
|
@click.option(
|
||||||
@click.option("--output-dir", type=click.Path(), default=DEFAULT_OUTPUT_DIR)
|
"--audio-config",
|
||||||
@click.option("--experiment-name", type=str)
|
type=click.Path(exists=True),
|
||||||
@click.option("--run-name", type=str)
|
help="Path to audio config file.",
|
||||||
@click.option("--workers", "num_workers", type=int)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--evaluation-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to evaluation config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--inference-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to inference config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--outputs-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to outputs config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--logging-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to logging config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--base-dir",
|
||||||
|
type=click.Path(),
|
||||||
|
default=Path.cwd(),
|
||||||
|
show_default=True,
|
||||||
|
help=(
|
||||||
|
"Base directory used to resolve relative paths in the dataset "
|
||||||
|
"configuration."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--output-dir",
|
||||||
|
type=click.Path(),
|
||||||
|
default=DEFAULT_OUTPUT_DIR,
|
||||||
|
show_default=True,
|
||||||
|
help="Directory where evaluation outputs are written.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--experiment-name",
|
||||||
|
type=str,
|
||||||
|
help="Experiment name used for logging backends.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--run-name",
|
||||||
|
type=str,
|
||||||
|
help="Run name used for logging backends.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--workers",
|
||||||
|
"num_workers",
|
||||||
|
type=int,
|
||||||
|
help="Number of worker processes for dataset loading.",
|
||||||
|
)
|
||||||
def evaluate_command(
|
def evaluate_command(
|
||||||
model_path: Path,
|
model_path: Path,
|
||||||
test_dataset: Path,
|
test_dataset: Path,
|
||||||
@ -40,7 +93,11 @@ def evaluate_command(
|
|||||||
experiment_name: str | None = None,
|
experiment_name: str | None = None,
|
||||||
run_name: str | None = None,
|
run_name: str | None = None,
|
||||||
):
|
):
|
||||||
"""Evaluate a checkpoint against a configured test dataset."""
|
"""Evaluate a checkpoint against a test dataset.
|
||||||
|
|
||||||
|
Loads model and optional override configs, runs evaluation on
|
||||||
|
`test_dataset`, and writes metrics/artifacts to `output_dir`.
|
||||||
|
"""
|
||||||
from batdetect2.api_v2 import BatDetect2API
|
from batdetect2.api_v2 import BatDetect2API
|
||||||
from batdetect2.audio import AudioConfig
|
from batdetect2.audio import AudioConfig
|
||||||
from batdetect2.data import load_dataset_from_config
|
from batdetect2.data import load_dataset_from_config
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
|
from functools import wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@ -7,12 +9,89 @@ from soundevent.audio.files import get_audio_files
|
|||||||
|
|
||||||
from batdetect2.cli.base import cli
|
from batdetect2.cli.base import cli
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from batdetect2.api_v2 import BatDetect2API
|
||||||
|
from batdetect2.audio import AudioConfig
|
||||||
|
from batdetect2.inference import InferenceConfig
|
||||||
|
from batdetect2.outputs import OutputsConfig
|
||||||
|
|
||||||
__all__ = ["predict"]
|
__all__ = ["predict"]
|
||||||
|
|
||||||
|
|
||||||
@cli.group(name="predict")
|
@cli.group(name="predict", short_help="Run prediction workflows.")
|
||||||
def predict() -> None:
|
def predict() -> None:
|
||||||
"""Run model inference on audio using API v2."""
|
"""Run model inference on audio files.
|
||||||
|
|
||||||
|
Use one of the subcommands to select inputs from a directory, a text file
|
||||||
|
list, or an annotation dataset.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def common_predict_options(func):
|
||||||
|
"""Attach options shared by all `predict` subcommands."""
|
||||||
|
|
||||||
|
@click.option(
|
||||||
|
"--audio-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help=(
|
||||||
|
"Path to an audio config file. Use this to override audio "
|
||||||
|
"loading and preprocessing-related settings."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--inference-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help=(
|
||||||
|
"Path to an inference config file. Use this to override "
|
||||||
|
"prediction-time thresholds and behavior."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--outputs-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help=(
|
||||||
|
"Path to an outputs config file. Use this to control the "
|
||||||
|
"prediction fields written to disk."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--logging-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help=(
|
||||||
|
"Path to a logging config file. Use this to customize logging "
|
||||||
|
"format and levels."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--batch-size",
|
||||||
|
type=int,
|
||||||
|
help=(
|
||||||
|
"Batch size for inference. If omitted, the value from the "
|
||||||
|
"loaded config is used."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--workers",
|
||||||
|
"num_workers",
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
show_default=True,
|
||||||
|
help="Number of worker processes for audio loading.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--format",
|
||||||
|
"format_name",
|
||||||
|
type=str,
|
||||||
|
help=(
|
||||||
|
"Output format name used by the prediction writer. If omitted, "
|
||||||
|
"the default output format is used."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@wraps(func)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
def _build_api(
|
def _build_api(
|
||||||
@ -21,7 +100,7 @@ def _build_api(
|
|||||||
inference_config: Path | None,
|
inference_config: Path | None,
|
||||||
outputs_config: Path | None,
|
outputs_config: Path | None,
|
||||||
logging_config: Path | None,
|
logging_config: Path | None,
|
||||||
):
|
) -> "tuple[BatDetect2API, AudioConfig | None, InferenceConfig | None, OutputsConfig | None]":
|
||||||
from batdetect2.api_v2 import BatDetect2API
|
from batdetect2.api_v2 import BatDetect2API
|
||||||
from batdetect2.audio import AudioConfig
|
from batdetect2.audio import AudioConfig
|
||||||
from batdetect2.inference import InferenceConfig
|
from batdetect2.inference import InferenceConfig
|
||||||
@ -103,17 +182,14 @@ def _run_prediction(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@predict.command(name="directory")
|
@predict.command(
|
||||||
|
name="directory",
|
||||||
|
short_help="Predict on audio files in a directory.",
|
||||||
|
)
|
||||||
@click.argument("model_path", type=click.Path(exists=True))
|
@click.argument("model_path", type=click.Path(exists=True))
|
||||||
@click.argument("audio_dir", type=click.Path(exists=True))
|
@click.argument("audio_dir", type=click.Path(exists=True))
|
||||||
@click.argument("output_path", type=click.Path())
|
@click.argument("output_path", type=click.Path())
|
||||||
@click.option("--audio-config", type=click.Path(exists=True))
|
@common_predict_options
|
||||||
@click.option("--inference-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--outputs-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--logging-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--batch-size", type=int)
|
|
||||||
@click.option("--workers", "num_workers", type=int, default=0)
|
|
||||||
@click.option("--format", "format_name", type=str)
|
|
||||||
def predict_directory_command(
|
def predict_directory_command(
|
||||||
model_path: Path,
|
model_path: Path,
|
||||||
audio_dir: Path,
|
audio_dir: Path,
|
||||||
@ -126,7 +202,11 @@ def predict_directory_command(
|
|||||||
num_workers: int,
|
num_workers: int,
|
||||||
format_name: str | None,
|
format_name: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Predict on all audio files in a directory."""
|
"""Predict on all audio files in a directory.
|
||||||
|
|
||||||
|
Loads a checkpoint, scans `audio_dir` for supported audio files, runs
|
||||||
|
inference, and saves predictions to `output_path`.
|
||||||
|
"""
|
||||||
audio_files = list(get_audio_files(audio_dir))
|
audio_files = list(get_audio_files(audio_dir))
|
||||||
_run_prediction(
|
_run_prediction(
|
||||||
model_path=model_path,
|
model_path=model_path,
|
||||||
@ -142,17 +222,14 @@ def predict_directory_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@predict.command(name="file_list")
|
@predict.command(
|
||||||
|
name="file_list",
|
||||||
|
short_help="Predict on paths listed in a text file.",
|
||||||
|
)
|
||||||
@click.argument("model_path", type=click.Path(exists=True))
|
@click.argument("model_path", type=click.Path(exists=True))
|
||||||
@click.argument("file_list", type=click.Path(exists=True))
|
@click.argument("file_list", type=click.Path(exists=True))
|
||||||
@click.argument("output_path", type=click.Path())
|
@click.argument("output_path", type=click.Path())
|
||||||
@click.option("--audio-config", type=click.Path(exists=True))
|
@common_predict_options
|
||||||
@click.option("--inference-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--outputs-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--logging-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--batch-size", type=int)
|
|
||||||
@click.option("--workers", "num_workers", type=int, default=0)
|
|
||||||
@click.option("--format", "format_name", type=str)
|
|
||||||
def predict_file_list_command(
|
def predict_file_list_command(
|
||||||
model_path: Path,
|
model_path: Path,
|
||||||
file_list: Path,
|
file_list: Path,
|
||||||
@ -165,7 +242,11 @@ def predict_file_list_command(
|
|||||||
num_workers: int,
|
num_workers: int,
|
||||||
format_name: str | None,
|
format_name: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Predict on audio files listed in a text file."""
|
"""Predict on audio files listed in a text file.
|
||||||
|
|
||||||
|
The list file should contain one audio path per line. Empty lines are
|
||||||
|
ignored.
|
||||||
|
"""
|
||||||
file_list = Path(file_list)
|
file_list = Path(file_list)
|
||||||
audio_files = [
|
audio_files = [
|
||||||
Path(line.strip())
|
Path(line.strip())
|
||||||
@ -187,17 +268,14 @@ def predict_file_list_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@predict.command(name="dataset")
|
@predict.command(
|
||||||
|
name="dataset",
|
||||||
|
short_help="Predict on recordings from a dataset config.",
|
||||||
|
)
|
||||||
@click.argument("model_path", type=click.Path(exists=True))
|
@click.argument("model_path", type=click.Path(exists=True))
|
||||||
@click.argument("dataset_path", type=click.Path(exists=True))
|
@click.argument("dataset_path", type=click.Path(exists=True))
|
||||||
@click.argument("output_path", type=click.Path())
|
@click.argument("output_path", type=click.Path())
|
||||||
@click.option("--audio-config", type=click.Path(exists=True))
|
@common_predict_options
|
||||||
@click.option("--inference-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--outputs-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--logging-config", type=click.Path(exists=True))
|
|
||||||
@click.option("--batch-size", type=int)
|
|
||||||
@click.option("--workers", "num_workers", type=int, default=0)
|
|
||||||
@click.option("--format", "format_name", type=str)
|
|
||||||
def predict_dataset_command(
|
def predict_dataset_command(
|
||||||
model_path: Path,
|
model_path: Path,
|
||||||
dataset_path: Path,
|
dataset_path: Path,
|
||||||
@ -210,7 +288,11 @@ def predict_dataset_command(
|
|||||||
num_workers: int,
|
num_workers: int,
|
||||||
format_name: str | None,
|
format_name: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Predict on recordings referenced in an annotation dataset."""
|
"""Predict on recordings referenced in an annotation dataset.
|
||||||
|
|
||||||
|
The dataset is read as a soundevent annotation set and unique recording
|
||||||
|
paths are extracted before inference.
|
||||||
|
"""
|
||||||
dataset_path = Path(dataset_path)
|
dataset_path = Path(dataset_path)
|
||||||
dataset = io.load(dataset_path, type="annotation_set")
|
dataset = io.load(dataset_path, type="annotation_set")
|
||||||
audio_files = sorted(
|
audio_files = sorted(
|
||||||
|
|||||||
@ -8,26 +8,103 @@ from batdetect2.cli.base import cli
|
|||||||
__all__ = ["train_command"]
|
__all__ = ["train_command"]
|
||||||
|
|
||||||
|
|
||||||
@cli.command(name="train")
|
@cli.command(name="train", short_help="Train or fine-tune a model.")
|
||||||
@click.argument("train_dataset", type=click.Path(exists=True))
|
@click.argument("train_dataset", type=click.Path(exists=True))
|
||||||
@click.option("--val-dataset", type=click.Path(exists=True))
|
@click.option(
|
||||||
@click.option("--model", "model_path", type=click.Path(exists=True))
|
"--val-dataset",
|
||||||
@click.option("--targets", "targets_config", type=click.Path(exists=True))
|
type=click.Path(exists=True),
|
||||||
@click.option("--model-config", type=click.Path(exists=True))
|
help="Path to validation dataset config file.",
|
||||||
@click.option("--training-config", type=click.Path(exists=True))
|
)
|
||||||
@click.option("--audio-config", type=click.Path(exists=True))
|
@click.option(
|
||||||
@click.option("--evaluation-config", type=click.Path(exists=True))
|
"--model",
|
||||||
@click.option("--inference-config", type=click.Path(exists=True))
|
"model_path",
|
||||||
@click.option("--outputs-config", type=click.Path(exists=True))
|
type=click.Path(exists=True),
|
||||||
@click.option("--logging-config", type=click.Path(exists=True))
|
help=(
|
||||||
@click.option("--ckpt-dir", type=click.Path(exists=True))
|
"Path to a checkpoint to continue training from. If omitted, "
|
||||||
@click.option("--log-dir", type=click.Path(exists=True))
|
"training starts from a fresh model config."
|
||||||
@click.option("--train-workers", type=int)
|
),
|
||||||
@click.option("--val-workers", type=int)
|
)
|
||||||
@click.option("--num-epochs", type=int)
|
@click.option(
|
||||||
@click.option("--experiment-name", type=str)
|
"--targets",
|
||||||
@click.option("--run-name", type=str)
|
"targets_config",
|
||||||
@click.option("--seed", type=int)
|
type=click.Path(exists=True),
|
||||||
|
help="Path to targets config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--model-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help=("Path to model config file. Cannot be used together with --model."),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--training-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to training config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--audio-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to audio config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--evaluation-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to evaluation config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--inference-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to inference config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--outputs-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to outputs config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--logging-config",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Path to logging config file.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--ckpt-dir",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Directory where checkpoints are saved.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--log-dir",
|
||||||
|
type=click.Path(exists=True),
|
||||||
|
help="Directory where logs are written.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--train-workers",
|
||||||
|
type=int,
|
||||||
|
help="Number of worker processes for training data loading.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--val-workers",
|
||||||
|
type=int,
|
||||||
|
help="Number of worker processes for validation data loading.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--num-epochs",
|
||||||
|
type=int,
|
||||||
|
help="Maximum number of training epochs.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--experiment-name",
|
||||||
|
type=str,
|
||||||
|
help="Experiment name used for logging backends.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--run-name",
|
||||||
|
type=str,
|
||||||
|
help="Run name used for logging backends.",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--seed",
|
||||||
|
type=int,
|
||||||
|
help="Random seed used for reproducibility.",
|
||||||
|
)
|
||||||
def train_command(
|
def train_command(
|
||||||
train_dataset: Path,
|
train_dataset: Path,
|
||||||
val_dataset: Path | None = None,
|
val_dataset: Path | None = None,
|
||||||
@ -49,7 +126,12 @@ def train_command(
|
|||||||
experiment_name: str | None = None,
|
experiment_name: str | None = None,
|
||||||
run_name: str | None = None,
|
run_name: str | None = None,
|
||||||
):
|
):
|
||||||
"""Train a model from dataset configs or a checkpoint."""
|
"""Train a BatDetect2 model.
|
||||||
|
|
||||||
|
Train either from a fresh config (`--model-config`) or by fine-tuning an
|
||||||
|
existing checkpoint (`--model`). Training data are loaded from
|
||||||
|
`train_dataset`, with optional validation data from `--val-dataset`.
|
||||||
|
"""
|
||||||
from batdetect2.api_v2 import BatDetect2API
|
from batdetect2.api_v2 import BatDetect2API
|
||||||
from batdetect2.audio import AudioConfig
|
from batdetect2.audio import AudioConfig
|
||||||
from batdetect2.config import BatDetect2Config
|
from batdetect2.config import BatDetect2Config
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
"""Main entry point for the BatDetect2 Postprocessing pipeline."""
|
"""Main entry point for the BatDetect2 Postprocessing pipeline."""
|
||||||
|
|
||||||
from batdetect2.postprocess.config import PostprocessConfig
|
from batdetect2.postprocess.config import (
|
||||||
|
DEFAULT_CLASSIFICATION_THRESHOLD,
|
||||||
|
DEFAULT_DETECTION_THRESHOLD,
|
||||||
|
PostprocessConfig,
|
||||||
|
)
|
||||||
from batdetect2.postprocess.nms import non_max_suppression
|
from batdetect2.postprocess.nms import non_max_suppression
|
||||||
from batdetect2.postprocess.postprocessor import (
|
from batdetect2.postprocess.postprocessor import (
|
||||||
Postprocessor,
|
Postprocessor,
|
||||||
@ -28,4 +32,6 @@ __all__ = [
|
|||||||
"PostprocessorProtocol",
|
"PostprocessorProtocol",
|
||||||
"build_postprocessor",
|
"build_postprocessor",
|
||||||
"non_max_suppression",
|
"non_max_suppression",
|
||||||
|
"DEFAULT_CLASSIFICATION_THRESHOLD",
|
||||||
|
"DEFAULT_DETECTION_THRESHOLD",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,23 +1,19 @@
|
|||||||
"""Handles mapping between geometric ROIs and target representations.
|
"""Map geometric ROIs to target representations and back.
|
||||||
|
|
||||||
This module defines a standardized interface (`ROITargetMapper`) for converting
|
This module defines a standardized interface (`ROITargetMapper`) for converting
|
||||||
a sound event's Region of Interest (ROI) into a target representation suitable
|
a sound event ROI into a target representation for model training and decoding
|
||||||
for machine learning models, and for decoding model outputs back into geometric
|
model outputs back into approximate geometries.
|
||||||
ROIs.
|
|
||||||
|
|
||||||
The core operations are:
|
Core operations:
|
||||||
1. **Encoding**: A `soundevent.data.SoundEvent` is mapped to a reference
|
|
||||||
`Position` (time, frequency) and a `Size` array. The method for
|
|
||||||
determining the position and size varies by the mapper implementation
|
|
||||||
(e.g., using a bounding box anchor or the point of peak energy).
|
|
||||||
2. **Decoding**: A `Position` and `Size` array are mapped back to an
|
|
||||||
approximate `soundevent.data.Geometry` (typically a `BoundingBox`).
|
|
||||||
|
|
||||||
This logic is encapsulated within specific mapper classes. Configuration for
|
- Encode a `soundevent.data.SoundEvent` into a reference `Position`
|
||||||
each mapper (e.g., anchor point, scaling factors) is managed by a corresponding
|
`(time, frequency)` and a `Size` array.
|
||||||
Pydantic config object. The `ROIMapperConfig` type allows for flexibly
|
- Decode a `Position` and `Size` array into an approximate
|
||||||
selecting and configuring the desired mapper. This module separates the
|
`soundevent.data.Geometry` (usually a `BoundingBox`).
|
||||||
*geometric* aspect of target definition from *semantic* classification.
|
|
||||||
|
The specific mapping depends on the selected mapper implementation. Config
|
||||||
|
objects provide mapper-specific parameters such as anchor choice and scaling.
|
||||||
|
This module focuses on the geometric part of target definition.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Annotated, Literal
|
from typing import Annotated, Literal
|
||||||
@ -131,12 +127,12 @@ class AnchorBBoxMapper(ROITargetMapper):
|
|||||||
This class implements the `ROITargetMapper` protocol for `BoundingBox`
|
This class implements the `ROITargetMapper` protocol for `BoundingBox`
|
||||||
geometries.
|
geometries.
|
||||||
|
|
||||||
**Encoding**: The `position` is a fixed anchor point on the bounding box
|
Encoding uses a fixed anchor point on the bounding box for `position`
|
||||||
(e.g., "bottom-left"). The `size` is a 2-element array containing the
|
(for example, ``bottom-left``). The `size` is a 2-element array with
|
||||||
scaled width and height of the box.
|
scaled width and height.
|
||||||
|
|
||||||
**Decoding**: Reconstructs a `BoundingBox` from an anchor point and
|
Decoding reconstructs a `BoundingBox` from anchor position and scaled
|
||||||
scaled width/height.
|
width/height.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -300,13 +296,12 @@ class PeakEnergyBBoxMapper(ROITargetMapper):
|
|||||||
|
|
||||||
This class implements the `ROITargetMapper` protocol.
|
This class implements the `ROITargetMapper` protocol.
|
||||||
|
|
||||||
**Encoding**: The `position` is the (time, frequency) coordinate of the
|
Encoding sets `position` to the (time, frequency) coordinate of peak energy
|
||||||
point with the highest energy within the sound event's bounding box. The
|
inside the sound event bounding box. The `size` is a 4-element array with
|
||||||
`size` is a 4-element array representing the scaled distances from this
|
scaled distances from the peak point to left, bottom, right, and top edges.
|
||||||
peak energy point to the left, bottom, right, and top edges of the box.
|
|
||||||
|
|
||||||
**Decoding**: Reconstructs a `BoundingBox` by adding/subtracting the
|
Decoding reconstructs a `BoundingBox` by applying the unscaled distances to
|
||||||
un-scaled distances from the peak energy point.
|
the peak-energy position.
|
||||||
|
|
||||||
Attributes
|
Attributes
|
||||||
----------
|
----------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user