teacher
birdnet_stm32.data.teacher
¶
Per-window soft targets from a cached teacher model.
A teacher (a larger audio classifier) is run once, offline, over every training recording on a fixed window grid, and its scores are stored on disk. Training then looks up the teacher window that best matches each chunk and blends its scores into the chunk's label. The teacher never runs during training, so this costs nothing per step.
Why: training labels are weak. A recording carries one species label, so every chunk drawn from it trains as that species alone, whether the chunk holds the call, silence, or a different bird calling over it. A per-window teacher score says which of those it is.
Kept free of TensorFlow: the loader's worker processes import it.
Cache format (a directory):
meta.json:classes(must match the training class order),teacher_mask(one bool per class;Falsewhere the teacher has no corresponding output, and such classes keep their hard label), andteacher_window_s(teacher window length in seconds).mapped.npy: float16[n_windows, n_classes]teacher probabilities.starts.npy: float32[n_windows]window start, in seconds from the start of the recording.index.npz:sample_id(recording file stem),row_offsetandn_windows, locating each recording's rows.emb.npy(optional): float16[n_windows, emb_dim]teacher embeddings, row-aligned withmapped.npy. Needed only for embedding distillation.
The large arrays are memory-mapped, so every worker shares one copy through the page cache.
TeacherTargets
¶
Look up cached teacher scores for a chunk of a training recording.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache_dir
|
str | Path
|
Directory in the format described in the module docstring. |
required |
classes
|
list[str]
|
The training class order. Must equal the cache's, so a cache built for another schema cannot silently mislabel classes. |
required |
embeddings
|
bool
|
Also memory-map |
False
|
Source code in birdnet_stm32/data/teacher.py
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | |
embedding_dim
property
¶
Width of the teacher embedding (0 when embeddings are not loaded).
lookup(sample_id, chunk_start_s, chunk_duration_s)
¶
Teacher scores for the window whose centre is nearest the chunk's.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sample_id
|
str
|
Recording identifier (the file stem). |
required |
chunk_start_s
|
float
|
Where the chunk starts in the recording, in seconds. |
required |
chunk_duration_s
|
float
|
Chunk length in seconds. |
required |
Returns:
| Type | Description |
|---|---|
ndarray | None
|
float32 |
ndarray | None
|
recording is not in the cache, no teacher window lies within one |
ndarray | None
|
window length of the chunk, or the teacher's scores for that window |
ndarray | None
|
are not finite. Callers fall back to the hard label. |
A non-finite row means the teacher's output was undefined, not that it heard nothing: BirdNET+ V3.0 returns NaN on digital silence (the muted stretches of edited recordings), where its input normalization divides by zero. Reading that as "no species present" would be wrong, and a single NaN target is enough to turn every weight non-finite.
Source code in birdnet_stm32/data/teacher.py
embedding(sample_id, chunk_start_s, chunk_duration_s)
¶
Teacher embedding for the window nearest the chunk, as :meth:lookup.
Returns:
| Type | Description |
|---|---|
ndarray | None
|
float32 |
ndarray | None
|
meth: |
ndarray | None
|
the chunk out of the embedding loss. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the cache was opened without |
Source code in birdnet_stm32/data/teacher.py
blend_targets(hard, teacher, mask, weight, background=False)
¶
Mix a hard label with teacher scores on the classes the teacher covers.
(1 - weight) * hard + weight * teacher where mask is set, and the
hard label unchanged elsewhere. A non-finite teacher entry also keeps the
hard label (np.clip passes NaN through, so clipping alone would not
catch it). Every entry stays in [0, 1], so the result is a valid soft
target for binary cross-entropy.
With weight 0.5, a labelled class the teacher also hears stays near 1,
a labelled class on a chunk where the teacher hears nothing drops to 0.5,
and an unlabelled species the teacher hears clearly rises toward 0.5.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hard
|
ndarray
|
float32 |
required |
teacher
|
ndarray
|
float32 |
required |
mask
|
ndarray
|
bool |
required |
weight
|
float
|
Teacher share in |
required |
background
|
bool
|
Where the hard label is 0 (a species the file does not
name), use the teacher's score itself from |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
float32 |