mirror of
https://github.com/macaodha/batdetect2.git
synced 2026-05-22 22:32:18 +02:00
docs: refresh api reference guidance
This commit is contained in:
parent
5cc5767eff
commit
b4efcfcf0f
165
README.md
165
README.md
@ -1,49 +1,67 @@
|
||||
# BatDetect2
|
||||
<img style="display: block-inline;" width="64" height="64" src="assets/bat_icon.png"> Code for detecting and classifying bat echolocation calls in high frequency audio recordings.
|
||||
<img style="display:
|
||||
block-inline;" width="64" height="64" src="assets/bat_icon.png">Code for
|
||||
detecting and
|
||||
classifying bat
|
||||
echolocation
|
||||
calls in high
|
||||
frequency audio
|
||||
recordings.
|
||||
|
||||
> [!WARNING]
|
||||
> BatDetect2 2.0.1 is out.
|
||||
> There are many changes and new recommended workflows.
|
||||
> We have left the previous `batdetect2.api` module intact, but if you run
|
||||
> into issues or want to upgrade, see the migration guide in the docs site.
|
||||
>
|
||||
> This update also ships with a refreshed default model.
|
||||
> It was trained in the same way and on the same data as before, but you
|
||||
> should still expect small output differences in some cases.
|
||||
|
||||
## What BatDetect2 is useful for
|
||||
|
||||
BatDetect2 can help you screen recordings for bat calls,
|
||||
find recordings that need expert review,
|
||||
and compare model outputs across sites or projects with appropriate caution.
|
||||
BatDetect2 can help you screen recordings for bat calls, find recordings that
|
||||
need expert review, and compare model outputs across sites or projects with
|
||||
appropriate caution.
|
||||
|
||||
It is best used as a tool to support ecological work,
|
||||
not as a replacement for validation or expert interpretation.
|
||||
It is best used as a tool to support ecological work, not as a replacement for
|
||||
validation or expert interpretation.
|
||||
|
||||
## Start here
|
||||
|
||||
If you want the simplest current workflow,
|
||||
use the documentation site and start with:
|
||||
If you want the simplest current workflow, use the documentation site and start
|
||||
with:
|
||||
|
||||
- getting started: `docs/source/getting_started.md`
|
||||
- first tutorial: `docs/source/tutorials/run-inference-on-folder.md`
|
||||
- getting started:
|
||||
`docs/source/getting_started.md`
|
||||
- first tutorial:
|
||||
`docs/source/tutorials/run-inference-on-folder.md`
|
||||
|
||||
The current docs default to:
|
||||
|
||||
- the current command-line workflow: `batdetect2 predict`
|
||||
- the current Python workflow: `batdetect2.api_v2.BatDetect2API`
|
||||
|
||||
If you need the previous workflow based on `batdetect2 detect` or `batdetect2.api`,
|
||||
use the legacy docs section and migration guide in the docs site.
|
||||
If you need the previous workflow based on `batdetect2 detect` or
|
||||
`batdetect2.api`, use the legacy docs section and migration guide in the docs
|
||||
site.
|
||||
|
||||
## Install BatDetect2
|
||||
|
||||
If you already use Python,
|
||||
activate the environment where you want BatDetect2 to live.
|
||||
If you already use Python, activate the environment where you want BatDetect2 to
|
||||
live.
|
||||
|
||||
If not,
|
||||
create a fresh one first so BatDetect2 stays separate from other software on your machine.
|
||||
If not, create a fresh one first so BatDetect2 stays separate from other
|
||||
software on your machine.
|
||||
|
||||
Two common options are:
|
||||
|
||||
* Install the Anaconda Python 3.10 distribution for your operating system from [here](https://www.continuum.io/downloads). Create a new environment and activate it:
|
||||
* Install the Anaconda Python 3.10 distribution for your operating system from
|
||||
[here](https://www.continuum.io/downloads).
|
||||
Create a new environment and activate it:
|
||||
|
||||
```bash
|
||||
conda create -y --name batdetect2 python==3.10
|
||||
conda activate batdetect2
|
||||
```
|
||||
|
||||
* If you already have Python installed (version >= 3.10,< 3.14), you can create a fresh environment with:
|
||||
* If you already have Python installed (version >= 3.10,< 3.14), you can create
|
||||
a fresh environment with:
|
||||
|
||||
```bash
|
||||
python -m venv .venv
|
||||
@ -57,7 +75,8 @@ You can use pip to install `batdetect2`:
|
||||
pip install batdetect2
|
||||
```
|
||||
|
||||
Alternatively, download this code from the repository (by clicking on the green button on top right) and unzip it.
|
||||
Alternatively, download this code from the repository (by clicking on the green
|
||||
button on top right) and unzip it.
|
||||
Once unzipped, run this from extracted folder.
|
||||
|
||||
```bash
|
||||
@ -68,11 +87,11 @@ Make sure you have the environment activated before installing `batdetect2`.
|
||||
|
||||
## Run BatDetect2 on a folder of recordings
|
||||
|
||||
Once installed,
|
||||
the simplest current workflow is to run BatDetect2 on a folder of `.wav` files.
|
||||
Once installed, the simplest current workflow is to run BatDetect2 on a folder
|
||||
of `.wav` files.
|
||||
|
||||
If you are working from this repository checkout,
|
||||
you can use this example checkpoint path:
|
||||
If you are working from this repository checkout, you can use this example
|
||||
checkpoint path:
|
||||
|
||||
```text
|
||||
src/batdetect2/models/checkpoints/Net2DFast_UK_same.pth.tar
|
||||
@ -87,32 +106,37 @@ batdetect2 predict directory \
|
||||
outputs
|
||||
```
|
||||
|
||||
This will scan the audio files in `example_data/audio`
|
||||
and save model outputs to `outputs`.
|
||||
This will scan the audio files in `example_data/audio` and save model outputs to
|
||||
`outputs`.
|
||||
|
||||
For the full beginner walkthrough,
|
||||
use `docs/source/tutorials/run-inference-on-folder.md`.
|
||||
For the full beginner walkthrough, use
|
||||
`docs/source/tutorials/run-inference-on-folder.md`.
|
||||
|
||||
## Legacy workflow
|
||||
|
||||
The sections below are kept only for people maintaining older BatDetect2 scripts and analysis pipelines.
|
||||
The sections below are kept only for people maintaining older BatDetect2 scripts
|
||||
and analysis pipelines.
|
||||
|
||||
If you are new to BatDetect2,
|
||||
stop here and use the current docs and command above.
|
||||
If you are new to BatDetect2, stop here and use the current docs and command
|
||||
above.
|
||||
|
||||
If you really do need the older workflow,
|
||||
the reference material is below.
|
||||
If you really do need the older workflow, the reference material is below.
|
||||
|
||||
|
||||
## Try the model
|
||||
1) You can try a demo of the model (for UK species) on [huggingface](https://huggingface.co/spaces/macaodha/batdetect2).
|
||||
1) You can try a demo of the model (for UK species) on
|
||||
[huggingface](https://huggingface.co/spaces/macaodha/batdetect2).
|
||||
|
||||
2) Alternatively, click [here](https://colab.research.google.com/github/macaodha/batdetect2/blob/master/batdetect2_notebook.ipynb) to run the model using Google Colab. You can also run this notebook locally.
|
||||
2) Alternatively, click
|
||||
[here](https://colab.research.google.com/github/macaodha/batdetect2/blob/master/batdetect2_notebook.ipynb)
|
||||
to run the model using Google Colab.
|
||||
You can also run this notebook locally.
|
||||
|
||||
|
||||
## Running the model on your own data
|
||||
|
||||
After following the above steps to install the code you can run the model on your own data.
|
||||
After following the above steps to install the code you can run the model on
|
||||
your own data.
|
||||
|
||||
The remainder of this section is legacy reference material.
|
||||
|
||||
@ -133,23 +157,35 @@ batdetect2 detect example_data/audio/ example_data/anns/ 0.3
|
||||
```
|
||||
|
||||
`AUDIO_DIR` is the path on your computer to the audio wav files of interest.
|
||||
`ANN_DIR` is the path on your computer where the model predictions will be saved. The model will output both `.csv` and `.json` results for each audio file.
|
||||
`DETECTION_THRESHOLD` is a number between 0 and 1 specifying the cut-off threshold applied to the calls. A smaller number will result in more calls detected, but with the chance of introducing more mistakes.
|
||||
`ANN_DIR` is the path on your computer where the model predictions will be
|
||||
saved.
|
||||
The model will output both `.csv` and `.json` results for each audio file.
|
||||
`DETECTION_THRESHOLD` is a number between 0 and 1 specifying the cut-off
|
||||
threshold applied to the calls.
|
||||
A smaller number will result in more calls detected, but with the chance of
|
||||
introducing more mistakes.
|
||||
|
||||
There are also optional arguments, e.g. you can request that the model outputs features (i.e. estimated call parameters) such as duration, max_frequency, etc. by setting the flag `--spec_features`. These will be saved as `*_spec_features.csv` files:
|
||||
There are also optional arguments, e.g. you can request that the model outputs
|
||||
features (i.e. estimated call parameters) such as duration, max_frequency, etc.
|
||||
by setting the flag `--spec_features`.
|
||||
These will be saved as `*_spec_features.csv` files:
|
||||
`batdetect2 detect example_data/audio/ example_data/anns/ 0.3 --spec_features`
|
||||
|
||||
You can also specify which model to use by setting the `--model_path` argument. If not specified, it will default to using a model trained on UK data e.g.
|
||||
`batdetect2 detect example_data/audio/ example_data/anns/ 0.3 --model_path models/Net2DFast_UK_same.pth.tar`
|
||||
You can also specify which model to use by setting the `--model_path` argument.
|
||||
If not specified, it will default to using a model trained on UK data e.g.
|
||||
`batdetect2 detect example_data/audio/ example_data/anns/ 0.3 --model_path
|
||||
models/Net2DFast_UK_same.pth.tar`
|
||||
|
||||
|
||||
### Using the Python API
|
||||
|
||||
The examples below describe the legacy Python API.
|
||||
|
||||
For new work, prefer `batdetect2.api_v2.BatDetect2API` and the current docs site.
|
||||
For new work, prefer `batdetect2.api_v2.BatDetect2API` and the current docs
|
||||
site.
|
||||
|
||||
If you prefer to process your data within a Python script then you can use the `batdetect2` Python API.
|
||||
If you prefer to process your data within a Python script then you can use the
|
||||
`batdetect2` Python API.
|
||||
|
||||
```python
|
||||
from batdetect2 import api
|
||||
@ -170,25 +206,32 @@ detections, features = api.process_spectrogram(spec)
|
||||
# Do something else ...
|
||||
```
|
||||
|
||||
You can integrate the detections or the extracted features to your custom analysis pipeline.
|
||||
You can integrate the detections or the extracted features to your custom
|
||||
analysis pipeline.
|
||||
|
||||
|
||||
## Training the model on your own data
|
||||
Take a look at the training tutorial in the docs site first.
|
||||
|
||||
If you are working from this repository checkout,
|
||||
start with `docs/source/tutorials/train-a-custom-model.md`.
|
||||
If you are working from this repository checkout, start with
|
||||
`docs/source/tutorials/train-a-custom-model.md`.
|
||||
|
||||
|
||||
## Data and annotations
|
||||
The raw audio data and annotations used to train the models in the paper will be added soon.
|
||||
The audio interface used to annotate audio data for training and evaluation is available [here](https://github.com/macaodha/batdetect2_GUI).
|
||||
The raw audio data and annotations used to train the models in the paper will be
|
||||
added soon.
|
||||
The audio interface used to annotate audio data for training and evaluation is
|
||||
available [here](https://github.com/macaodha/batdetect2_GUI).
|
||||
|
||||
|
||||
## Warning
|
||||
The models developed and shared as part of this repository should be used with caution.
|
||||
While they have been evaluated on held out audio data, great care should be taken when using the model outputs for any form of biodiversity assessment.
|
||||
Your data may differ, and as a result it is very strongly recommended that you validate the model first using data with known species to ensure that the outputs can be trusted.
|
||||
The models developed and shared as part of this repository should be used with
|
||||
caution.
|
||||
While they have been evaluated on held out audio data, great care should be
|
||||
taken when using the model outputs for any form of biodiversity assessment.
|
||||
Your data may differ, and as a result it is very strongly recommended that you
|
||||
validate the model first using data with known species to ensure that the
|
||||
outputs can be trusted.
|
||||
|
||||
|
||||
## FAQ
|
||||
@ -196,7 +239,9 @@ For more information please consult our [FAQ](docs/source/faq.md).
|
||||
|
||||
|
||||
## Reference
|
||||
If you find our work useful in your research please consider citing our paper which you can find [here](https://www.biorxiv.org/content/10.1101/2022.12.14.520490v1):
|
||||
If you find our work useful in your research please consider citing our paper
|
||||
which you can find
|
||||
[here](https://www.biorxiv.org/content/10.1101/2022.12.14.520490v1):
|
||||
```
|
||||
@article{batdetect2_2022,
|
||||
title = {Towards a General Approach for Bat Echolocation Detection and Classification},
|
||||
@ -207,10 +252,6 @@ If you find our work useful in your research please consider citing our paper wh
|
||||
```
|
||||
|
||||
## Acknowledgements
|
||||
Thanks to all the contributors who spent time collecting and annotating audio data.
|
||||
|
||||
|
||||
### TODOs
|
||||
- [x] Release the code and pretrained model
|
||||
- [ ] Release the datasets and annotations used the experiments in the paper
|
||||
- [ ] Add the scripts used to generate the tables and figures from the paper
|
||||
Thanks to all the contributors who spent time collecting and annotating audio
|
||||
data.
|
||||
|
||||
@ -54,7 +54,8 @@ class BatDetect2API:
|
||||
evaluate predictions, and train or fine-tune models.
|
||||
|
||||
In most cases, start with :meth:`from_checkpoint` to load a trained model.
|
||||
Use :meth:`from_config` when you want to build a new model with custom configs.
|
||||
Use :meth:`from_config` when you want to build a new model with custom
|
||||
configs.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@ -93,7 +94,7 @@ class BatDetect2API:
|
||||
):
|
||||
"""Create a fully configured API instance.
|
||||
|
||||
This initializer is mainly for internal wiring.
|
||||
This initializer is mainly for internal use.
|
||||
In most cases, users should create the API with
|
||||
:meth:`from_checkpoint` or :meth:`from_config`.
|
||||
|
||||
@ -264,7 +265,7 @@ class BatDetect2API:
|
||||
targets_config: TargetConfig,
|
||||
val_annotations: Sequence[data.ClipAnnotation] | None = None,
|
||||
trainable: Literal[
|
||||
"all", "heads", "classifier_head", "bbox_head"
|
||||
"all", "heads", "classifier_head", "size_head"
|
||||
] = "heads",
|
||||
train_workers: int = 0,
|
||||
val_workers: int = 0,
|
||||
@ -279,11 +280,11 @@ class BatDetect2API:
|
||||
logger_config: LoggerConfig | None = None,
|
||||
logging_callbacks: Sequence[LoggingCallback[TrainLoggingContext]] = (),
|
||||
) -> "BatDetect2API":
|
||||
"""Fine-tune the current model with a new target definition.
|
||||
"""Fine-tune the current model for new target sounds.
|
||||
|
||||
Use this when you want to keep the existing model weights but change
|
||||
the target sounds. You can fine-tune the whole model or just the
|
||||
classifier heads.
|
||||
heads.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -293,7 +294,7 @@ class BatDetect2API:
|
||||
Target definition to train against.
|
||||
val_annotations : Sequence[data.ClipAnnotation] | None, optional
|
||||
Validation annotations.
|
||||
trainable : {"all", "heads", "classifier_head", "bbox_head"}, optional
|
||||
trainable : {"all", "heads", "classifier_head", "size_head"}, optional
|
||||
Which model parameters remain trainable.
|
||||
train_workers : int, optional
|
||||
Number of worker processes for training data loading.
|
||||
@ -509,19 +510,63 @@ class BatDetect2API:
|
||||
return metrics
|
||||
|
||||
def load_audio(self, path: data.PathLike) -> np.ndarray:
|
||||
"""Load one audio file into a waveform array."""
|
||||
"""Load one audio file into a waveform array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
path : data.PathLike
|
||||
Path to the audio file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
np.ndarray
|
||||
Audio waveform loaded from disk.
|
||||
"""
|
||||
return self.audio_loader.load_file(path)
|
||||
|
||||
def load_recording(self, recording: data.Recording) -> np.ndarray:
|
||||
"""Load one recording object into a waveform array."""
|
||||
"""Load one recording object into a waveform array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
recording : data.Recording
|
||||
Recording object describing the audio to load.
|
||||
|
||||
Returns
|
||||
-------
|
||||
np.ndarray
|
||||
Audio waveform for the requested recording.
|
||||
"""
|
||||
return self.audio_loader.load_recording(recording)
|
||||
|
||||
def load_clip(self, clip: data.Clip) -> np.ndarray:
|
||||
"""Load one clip object into a waveform array."""
|
||||
"""Load one clip object into a waveform array.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
clip : data.Clip
|
||||
Clip object describing the section of audio to load.
|
||||
|
||||
Returns
|
||||
-------
|
||||
np.ndarray
|
||||
Audio waveform for the requested clip.
|
||||
"""
|
||||
return self.audio_loader.load_clip(clip)
|
||||
|
||||
def get_top_class_name(self, detection: Detection) -> str:
|
||||
"""Get highest-confidence class name for one detection."""
|
||||
"""Get the name of the highest-confidence class for one detection.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
detection : Detection
|
||||
Detection whose class scores will be inspected.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Class name with the highest score.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
@ -535,7 +580,22 @@ class BatDetect2API:
|
||||
include_top_class: bool = True,
|
||||
sort_descending: bool = True,
|
||||
) -> list[tuple[str, float]]:
|
||||
"""Get class score list as ``(class_name, score)`` pairs."""
|
||||
"""Get class scores as ``(class_name, score)`` pairs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
detection : Detection
|
||||
Detection whose class scores will be returned.
|
||||
include_top_class : bool, optional
|
||||
If ``False``, omit the highest-scoring class from the result.
|
||||
sort_descending : bool, optional
|
||||
If ``True``, sort scores from highest to lowest.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[tuple[str, float]]
|
||||
Class-score pairs for the detection.
|
||||
"""
|
||||
|
||||
scores = [
|
||||
(class_name, float(score))
|
||||
@ -559,17 +619,22 @@ class BatDetect2API:
|
||||
if class_name != top_class_name
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_detection_features(detection: Detection) -> np.ndarray:
|
||||
"""Get extracted feature vector for one detection."""
|
||||
|
||||
return detection.features
|
||||
|
||||
def generate_spectrogram(
|
||||
self,
|
||||
audio: np.ndarray,
|
||||
) -> torch.Tensor:
|
||||
"""Convert a waveform array into a model spectrogram."""
|
||||
"""Convert a waveform array into a spectrogram tensor.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
audio : np.ndarray
|
||||
Audio waveform.
|
||||
|
||||
Returns
|
||||
-------
|
||||
torch.Tensor
|
||||
Spectrogram tensor ready for model inference.
|
||||
"""
|
||||
import torch
|
||||
|
||||
tensor = torch.tensor(audio).unsqueeze(0)
|
||||
@ -703,7 +768,20 @@ class BatDetect2API:
|
||||
audio_dir: data.PathLike,
|
||||
detection_threshold: float | None = None,
|
||||
) -> list[ClipDetections]:
|
||||
"""Run inference on all supported audio files in a directory."""
|
||||
"""Run inference on all supported audio files in a directory.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
audio_dir : data.PathLike
|
||||
Directory containing audio files.
|
||||
detection_threshold : float | None, optional
|
||||
Detection score threshold override.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[ClipDetections]
|
||||
Predictions for all supported audio files found in the directory.
|
||||
"""
|
||||
from soundevent.audio.files import get_audio_files
|
||||
|
||||
files = list(get_audio_files(audio_dir))
|
||||
@ -904,8 +982,8 @@ class BatDetect2API:
|
||||
) -> "BatDetect2API":
|
||||
"""Build an API instance from config objects.
|
||||
|
||||
Use this when you want to create a new model stack without loading a
|
||||
saved checkpoint.
|
||||
Use this when you want to create a new model without loading a saved
|
||||
checkpoint.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -1161,7 +1239,7 @@ class BatDetect2API:
|
||||
|
||||
def _set_trainable_parameters(
|
||||
self,
|
||||
trainable: Literal["all", "heads", "classifier_head", "bbox_head"],
|
||||
trainable: Literal["all", "heads", "classifier_head", "size_head"],
|
||||
) -> None:
|
||||
detector = self.model.detector
|
||||
|
||||
@ -1177,6 +1255,6 @@ class BatDetect2API:
|
||||
for parameter in detector.classifier_head.parameters():
|
||||
parameter.requires_grad = True
|
||||
|
||||
if trainable in {"heads", "bbox_head"}:
|
||||
if trainable in {"heads", "size_head"}:
|
||||
for parameter in detector.size_head.parameters():
|
||||
parameter.requires_grad = True
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
from pathlib import Path
|
||||
from typing import Literal, cast
|
||||
from typing import Literal
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
|
||||
from batdetect2.cli.base import cli
|
||||
from batdetect2.train.checkpoints import DEFAULT_CHECKPOINT
|
||||
|
||||
__all__ = ["finetune_command"]
|
||||
|
||||
@ -20,8 +19,7 @@ __all__ = ["finetune_command"]
|
||||
type=str,
|
||||
help=(
|
||||
"Path to a checkpoint, bundled checkpoint alias, or a Hugging Face "
|
||||
"URI to fine-tune from. Defaults to "
|
||||
f"'{DEFAULT_CHECKPOINT}'."
|
||||
"URI to fine-tune from. Defaults to uk_same"
|
||||
),
|
||||
)
|
||||
@click.option(
|
||||
@ -61,7 +59,7 @@ __all__ = ["finetune_command"]
|
||||
)
|
||||
@click.option(
|
||||
"--trainable",
|
||||
type=click.Choice(["all", "heads", "classifier_head", "bbox_head"]),
|
||||
type=click.Choice(["all", "heads", "classifier_head", "size_head"]),
|
||||
default="heads",
|
||||
show_default=True,
|
||||
help="Which model parameters remain trainable during fine-tuning.",
|
||||
@ -119,7 +117,9 @@ def finetune_command(
|
||||
training_config: Path | None = None,
|
||||
audio_config: Path | None = None,
|
||||
logging_config: Path | None = None,
|
||||
trainable: str = "heads",
|
||||
trainable: Literal[
|
||||
"all", "heads", "classifier_head", "size_head"
|
||||
] = "heads",
|
||||
seed: int | None = None,
|
||||
num_epochs: int | None = None,
|
||||
train_workers: int = 0,
|
||||
@ -196,10 +196,7 @@ def finetune_command(
|
||||
train_annotations=train_annotations,
|
||||
val_annotations=val_annotations,
|
||||
targets_config=target_conf,
|
||||
trainable=cast(
|
||||
Literal["all", "heads", "classifier_head", "bbox_head"],
|
||||
trainable,
|
||||
),
|
||||
trainable=trainable,
|
||||
train_workers=train_workers,
|
||||
val_workers=val_workers,
|
||||
checkpoint_dir=ckpt_dir,
|
||||
|
||||
@ -200,13 +200,14 @@ def test_user_can_read_extracted_features_per_detection(
|
||||
) -> None:
|
||||
"""User story: inspect extracted feature vectors per detection."""
|
||||
|
||||
# Given
|
||||
prediction = api_v2.process_file(example_audio_files[0])
|
||||
|
||||
assert len(prediction.detections) > 0
|
||||
# When
|
||||
feature_vectors = [det.features for det in prediction.detections]
|
||||
|
||||
feature_vectors = [
|
||||
api_v2.get_detection_features(det) for det in prediction.detections
|
||||
]
|
||||
# Then
|
||||
assert len(prediction.detections) > 0
|
||||
assert len(feature_vectors) == len(prediction.detections)
|
||||
assert all(vec.ndim == 1 for vec in feature_vectors)
|
||||
assert all(vec.size > 0 for vec in feature_vectors)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user