Skip to content

Commit 869a256

Browse files
committed
initial to_structured_array
1 parent f667736 commit 869a256

10 files changed

Lines changed: 94 additions & 17 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ src/birdnet_debug
1818
src/birdnet_v1
1919
src/birdnet_v1_tests
2020
src/birdnet_v2_old
21+
playground.*
2122

2223
# VSCode
2324
.vscode

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ norecursedirs = ["src/birdnet_v1_tests"]
180180
markers = [
181181
"load_model: tests that download all models, should be run before other tests",
182182
"litert: tests requiring ai_edge_litert backend which can not be loaded after tf is imported (raises ImportError) which happens on parallel test runs",
183-
"gpu: tests requiring a GPU to run and to be runned sequentially",
183+
"gpu: tests requiring a GPU to run and to be run sequentially",
184184
"repro: tests requiring exact package versions to reproduce results",
185185
]
186186

src/birdnet/acoustic/inference/core/consumer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from multiprocessing.synchronize import Event
55
from queue import Empty
66

7-
from birdnet.acoustic.inference.core.tensor import AcousticTensorBase
87
from birdnet.acoustic.inference.core.logs import get_logger_from_session
8+
from birdnet.acoustic.inference.core.tensor import AcousticTensorBase
99

1010

1111
class Consumer:

src/birdnet/acoustic/inference/core/encoding/encoding_result.py

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,19 @@
77
from birdnet.acoustic.inference.core.encoding.encoding_tensor import (
88
AcousticEncodingTensor,
99
)
10-
from birdnet.acoustic.inference.core.result_base import AcousticResultBase
11-
from birdnet.utils.helper import get_uint_dtype
10+
from birdnet.acoustic.inference.core.result_base import (
11+
VAR_END_TIME,
12+
VAR_INPUT,
13+
VAR_START_TIME,
14+
AcousticResultBase,
15+
)
16+
from birdnet.utils.helper import (
17+
apply_speed_to_duration,
18+
get_hop_duration_s,
19+
get_uint_dtype,
20+
)
21+
22+
VAR_EMBEDDING = "embedding"
1223

1324
NP_EMB_KEY = "embeddings"
1425
NP_EMB_MASKED_KEY = "embeddings_masked"
@@ -78,6 +89,65 @@ def emd_dim(self) -> int:
7889
def max_n_segments(self) -> int:
7990
return self._embeddings.shape[1]
8091

92+
def test() -> None:
93+
pass
94+
95+
def to_structured_array(self) -> np.ndarray:
96+
valid_mask_per_segment = ~(self._embeddings_masked).all(axis=2)
97+
valid_file_idx, valid_seg_idx = np.where(valid_mask_per_segment)
98+
n_embeddings = len(valid_file_idx)
99+
100+
embeddings_selected = self.embeddings[valid_file_idx, valid_seg_idx]
101+
102+
dtype = [
103+
(VAR_INPUT, self._input_dtype),
104+
(VAR_START_TIME, self._input_durations.dtype),
105+
(VAR_END_TIME, self._input_durations.dtype),
106+
(VAR_EMBEDDING, self._embeddings.dtype, self.emd_dim),
107+
]
108+
109+
structured_array = np.empty(n_embeddings, dtype=dtype)
110+
del dtype
111+
112+
if n_embeddings == 0:
113+
return structured_array
114+
del n_embeddings
115+
116+
sort_keys = (
117+
valid_seg_idx,
118+
valid_file_idx,
119+
)
120+
sort_indices = np.lexsort(sort_keys)
121+
del sort_keys
122+
123+
file_idx_flat = valid_file_idx[sort_indices]
124+
chunk_idx_flat = valid_seg_idx[sort_indices]
125+
emb_flat = embeddings_selected[sort_indices]
126+
del embeddings_selected
127+
del sort_indices
128+
129+
hop_duration_s = get_hop_duration_s(
130+
self._segment_duration_s[0], self._overlap_duration_s[0], self._speed[0]
131+
)
132+
start_times = chunk_idx_flat.astype(self._input_durations.dtype) * hop_duration_s
133+
del hop_duration_s
134+
del chunk_idx_flat
135+
136+
structured_array[VAR_START_TIME] = start_times
137+
structured_array[VAR_END_TIME] = np.minimum(
138+
start_times
139+
+ apply_speed_to_duration(self._segment_duration_s[0], self._speed[0]),
140+
self._input_durations[file_idx_flat],
141+
)
142+
del start_times
143+
structured_array[VAR_INPUT] = self._inputs[file_idx_flat]
144+
del file_idx_flat
145+
146+
structured_array[VAR_EMBEDDING] = emb_flat
147+
del emb_flat
148+
149+
return structured_array
150+
81151
def unprocessable_inputs(self) -> np.ndarray:
82152
return self._unprocessable_inputs
83153

src/birdnet/acoustic/inference/core/encoding/encoding_tensor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import numpy as np
66
from numpy.typing import DTypeLike
77

8-
from birdnet.acoustic.inference.core.tensor import AcousticTensorBase
98
from birdnet.acoustic.inference.core.logs import get_logger_from_session
9+
from birdnet.acoustic.inference.core.tensor import AcousticTensorBase
1010

1111

1212
class AcousticEncodingTensor(AcousticTensorBase):

src/birdnet/acoustic/inference/core/prediction/prediction_result.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@
1111
from birdnet.acoustic.inference.core.prediction.prediction_tensor import (
1212
AcousticPredictionTensor,
1313
)
14-
from birdnet.acoustic.inference.core.result_base import AcousticResultBase
14+
from birdnet.acoustic.inference.core.result_base import (
15+
VAR_END_TIME,
16+
VAR_INPUT,
17+
VAR_START_TIME,
18+
AcousticResultBase,
19+
)
1520
from birdnet.utils.helper import (
1621
apply_speed_to_duration,
1722
get_hop_duration_s,
@@ -22,9 +27,6 @@
2227
import pandas as pd
2328
import pyarrow as pa
2429

25-
VAR_INPUT = "input"
26-
VAR_START_TIME = "start_time"
27-
VAR_END_TIME = "end_time"
2830
VAR_SPECIES_NAME = "species_name"
2931
VAR_CONFIDENCE = "confidence"
3032

@@ -145,10 +147,6 @@ def _set_extra_load_data(cls, data: dict[str, np.ndarray]) -> None:
145147
cls._species_list = data[NP_SPECIES_LIST_KEY]
146148
cls._unprocessable_inputs = data[NP_UNPROCESSABLE_INPUTS_KEY]
147149

148-
@property
149-
def _input_dtype(self) -> type:
150-
return self._inputs.dtype
151-
152150
def to_structured_array(self) -> np.ndarray:
153151
valid_mask = ~self._species_masked
154152
valid_indices = np.where(valid_mask)

src/birdnet/acoustic/inference/core/prediction/prediction_worker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import numpy as np
99
from numpy.typing import DTypeLike
1010

11+
from birdnet.acoustic.inference.core.shm import RingField
1112
from birdnet.acoustic.inference.core.worker import WorkerBase
1213
from birdnet.core.backends import BackendLoader, BatchT
13-
from birdnet.acoustic.inference.core.shm import RingField
1414
from birdnet.utils.helper import flat_sigmoid_logaddexp_fast, get_uint_dtype
1515

1616
if TYPE_CHECKING:

src/birdnet/acoustic/inference/core/result_base.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
from birdnet.core.base import ResultBase
1212
from birdnet.utils.helper import get_float_dtype, get_hash, get_uint_dtype
1313

14+
VAR_INPUT = "input"
15+
VAR_START_TIME = "start_time"
16+
VAR_END_TIME = "end_time"
17+
1418
NP_INPUTS_KEY = "inputs"
1519
NP_INPUT_DURATIONS_KEY = "input_durations"
1620
NP_SEGMENT_DURATION_S_KEY = "segment_duration_s"
@@ -62,6 +66,10 @@ def __init__(
6266
self._model_fmax = np.array([model_fmax], dtype=get_uint_dtype(model_fmax))
6367
self._model_sr = np.array([model_sr], dtype=get_uint_dtype(model_sr))
6468

69+
@property
70+
def _input_dtype(self) -> type:
71+
return self._inputs.dtype
72+
6573
@property
6674
def segment_duration_s(self) -> float:
6775
return float(self._segment_duration_s[0])
@@ -146,7 +154,7 @@ def __init__(self) -> None:
146154
def __enter__(self) -> Self: ...
147155

148156
@abstractmethod
149-
def __exit__(self, *args): ...
157+
def __exit__(self, *args) -> None: ...
150158

151159
@abstractmethod
152160
def run(self, *args, **kwargs) -> ResultBase: ...

src/birdnet/acoustic/inference/core/worker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
from numpy.typing import DTypeLike
1414

1515
import birdnet.acoustic.inference.core.logs as bn_logging
16+
from birdnet.acoustic.inference.core.shm import RingField
1617
from birdnet.core.backends import BackendLoader, BatchT, VersionedBackendProtocol
1718
from birdnet.globals import (
1819
READABLE_FLAG,
1920
READING_FLAG,
2021
WRITABLE_FLAG,
2122
WRITING_FLAG,
2223
)
23-
from birdnet.acoustic.inference.core.shm import RingField
2424

2525
if TYPE_CHECKING:
2626
pass

src/birdnet/acoustic/inference/session.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def _run(self, inputs: list[Path] | list[tuple[np.ndarray, int]]) -> ResultType:
142142
self._resources.producer_resources.unprocessed_inputs
143143
)
144144

145-
if is_file_input := any(isinstance(inp, Path) for inp in inputs):
145+
if any(isinstance(inp, Path) for inp in inputs):
146146
assert all(isinstance(inp, Path) for inp in inputs)
147147
inputs = cast(list[Path], inputs)
148148
result = self._strategy.create_files_result(

0 commit comments

Comments
 (0)