birdnet-analyzer 2.0.0__py3-none-any.whl → 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- birdnet_analyzer/__init__.py +9 -8
- birdnet_analyzer/analyze/__init__.py +19 -5
- birdnet_analyzer/analyze/__main__.py +3 -4
- birdnet_analyzer/analyze/cli.py +30 -25
- birdnet_analyzer/analyze/core.py +246 -245
- birdnet_analyzer/analyze/utils.py +694 -701
- birdnet_analyzer/audio.py +368 -372
- birdnet_analyzer/cli.py +732 -707
- birdnet_analyzer/config.py +243 -242
- birdnet_analyzer/eBird_taxonomy_codes_2024E.json +13046 -0
- birdnet_analyzer/embeddings/__init__.py +3 -4
- birdnet_analyzer/embeddings/__main__.py +3 -3
- birdnet_analyzer/embeddings/cli.py +12 -13
- birdnet_analyzer/embeddings/core.py +70 -70
- birdnet_analyzer/embeddings/utils.py +220 -193
- birdnet_analyzer/evaluation/__init__.py +189 -195
- birdnet_analyzer/evaluation/__main__.py +3 -3
- birdnet_analyzer/evaluation/assessment/__init__.py +0 -0
- birdnet_analyzer/evaluation/assessment/metrics.py +388 -0
- birdnet_analyzer/evaluation/assessment/performance_assessor.py +364 -0
- birdnet_analyzer/evaluation/assessment/plotting.py +378 -0
- birdnet_analyzer/evaluation/preprocessing/__init__.py +0 -0
- birdnet_analyzer/evaluation/preprocessing/data_processor.py +631 -0
- birdnet_analyzer/evaluation/preprocessing/utils.py +98 -0
- birdnet_analyzer/gui/__init__.py +19 -23
- birdnet_analyzer/gui/__main__.py +3 -3
- birdnet_analyzer/gui/analysis.py +179 -174
- birdnet_analyzer/gui/assets/arrow_down.svg +4 -4
- birdnet_analyzer/gui/assets/arrow_left.svg +4 -4
- birdnet_analyzer/gui/assets/arrow_right.svg +4 -4
- birdnet_analyzer/gui/assets/arrow_up.svg +4 -4
- birdnet_analyzer/gui/assets/gui.css +36 -28
- birdnet_analyzer/gui/assets/gui.js +93 -93
- birdnet_analyzer/gui/embeddings.py +638 -620
- birdnet_analyzer/gui/evaluation.py +801 -813
- birdnet_analyzer/gui/localization.py +75 -68
- birdnet_analyzer/gui/multi_file.py +265 -246
- birdnet_analyzer/gui/review.py +472 -527
- birdnet_analyzer/gui/segments.py +191 -191
- birdnet_analyzer/gui/settings.py +149 -129
- birdnet_analyzer/gui/single_file.py +264 -269
- birdnet_analyzer/gui/species.py +95 -95
- birdnet_analyzer/gui/train.py +687 -698
- birdnet_analyzer/gui/utils.py +797 -808
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_af.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ar.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_bg.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ca.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_cs.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_da.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_de.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_el.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_en_uk.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_es.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fi.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fr.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_he.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hr.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hu.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_in.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_is.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_it.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ja.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ko.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_lt.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ml.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_nl.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_no.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pl.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_BR.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_PT.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ro.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ru.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sk.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sl.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sr.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sv.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_th.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_tr.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_uk.txt +6522 -6522
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_zh.txt +6522 -6522
- birdnet_analyzer/lang/de.json +341 -334
- birdnet_analyzer/lang/en.json +341 -334
- birdnet_analyzer/lang/fi.json +341 -334
- birdnet_analyzer/lang/fr.json +341 -334
- birdnet_analyzer/lang/id.json +341 -334
- birdnet_analyzer/lang/pt-br.json +341 -334
- birdnet_analyzer/lang/ru.json +341 -334
- birdnet_analyzer/lang/se.json +341 -334
- birdnet_analyzer/lang/tlh.json +341 -334
- birdnet_analyzer/lang/zh_TW.json +341 -334
- birdnet_analyzer/model.py +1212 -1243
- birdnet_analyzer/playground.py +5 -0
- birdnet_analyzer/search/__init__.py +3 -3
- birdnet_analyzer/search/__main__.py +3 -3
- birdnet_analyzer/search/cli.py +11 -12
- birdnet_analyzer/search/core.py +78 -78
- birdnet_analyzer/search/utils.py +107 -111
- birdnet_analyzer/segments/__init__.py +3 -3
- birdnet_analyzer/segments/__main__.py +3 -3
- birdnet_analyzer/segments/cli.py +13 -14
- birdnet_analyzer/segments/core.py +81 -78
- birdnet_analyzer/segments/utils.py +383 -394
- birdnet_analyzer/species/__init__.py +3 -3
- birdnet_analyzer/species/__main__.py +3 -3
- birdnet_analyzer/species/cli.py +13 -14
- birdnet_analyzer/species/core.py +35 -35
- birdnet_analyzer/species/utils.py +74 -75
- birdnet_analyzer/train/__init__.py +3 -3
- birdnet_analyzer/train/__main__.py +3 -3
- birdnet_analyzer/train/cli.py +13 -14
- birdnet_analyzer/train/core.py +113 -113
- birdnet_analyzer/train/utils.py +877 -847
- birdnet_analyzer/translate.py +133 -104
- birdnet_analyzer/utils.py +425 -419
- {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.1.0.dist-info}/METADATA +146 -129
- birdnet_analyzer-2.1.0.dist-info/RECORD +125 -0
- {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.1.0.dist-info}/WHEEL +1 -1
- {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.1.0.dist-info}/licenses/LICENSE +18 -18
- birdnet_analyzer/eBird_taxonomy_codes_2021E.json +0 -25280
- birdnet_analyzer-2.0.0.dist-info/RECORD +0 -117
- {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.1.0.dist-info}/entry_points.txt +0 -0
- {birdnet_analyzer-2.0.0.dist-info → birdnet_analyzer-2.1.0.dist-info}/top_level.txt +0 -0
birdnet_analyzer/cli.py
CHANGED
@@ -1,707 +1,732 @@
|
|
1
|
-
|
2
|
-
import
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
p.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
p.
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
def
|
84
|
-
"""
|
85
|
-
Creates an argument parser for species-
|
86
|
-
Returns:
|
87
|
-
argparse.ArgumentParser: The argument parser with the following arguments:
|
88
|
-
--lat (float): Recording location latitude. Set -1 to ignore. Default is -1.
|
89
|
-
--lon (float): Recording location longitude. Set -1 to ignore. Default is -1.
|
90
|
-
--week (int): Week of the year when the recording was made. Values in [1, 48] (4 weeks per month).
|
91
|
-
Set -1 for year-round species list. Default is -1.
|
92
|
-
--slist (str): Path to species list file or folder. If folder is provided, species list needs to be named
|
93
|
-
"species_list.txt". If lat and lon are provided, this list will be ignored.
|
94
|
-
--sf_thresh (float): Minimum species occurrence frequency threshold for location filter. Values in [0.01, 0.99].
|
95
|
-
Defaults to cfg.LOCATION_FILTER_THRESHOLD.
|
96
|
-
"""
|
97
|
-
p = argparse.ArgumentParser(add_help=False)
|
98
|
-
p.add_argument("--lat", type=float, default=-1, help="Recording location latitude. Set -1 to ignore.")
|
99
|
-
p.add_argument("--lon", type=float, default=-1, help="Recording location longitude. Set -1 to ignore.")
|
100
|
-
p.add_argument(
|
101
|
-
"--week",
|
102
|
-
type=int,
|
103
|
-
default=-1,
|
104
|
-
help="Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 for year-round species list.",
|
105
|
-
)
|
106
|
-
p.add_argument(
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
"""
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
p
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
"
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
The parser includes
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
parser.
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
"
|
356
|
-
action=
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
"
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
parser.add_argument(
|
367
|
-
"--
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
return
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
parser.add_argument(
|
500
|
-
|
501
|
-
)
|
502
|
-
parser.add_argument(
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
help="
|
507
|
-
)
|
508
|
-
|
509
|
-
parser
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
parser =
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
"
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
parser
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
)
|
620
|
-
|
621
|
-
"
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
"
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
help="
|
636
|
-
)
|
637
|
-
parser.add_argument(
|
638
|
-
|
639
|
-
|
640
|
-
type=
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
type=float,
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
parser.add_argument(
|
663
|
-
|
664
|
-
|
665
|
-
type=
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
default=cfg.
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
default=cfg.
|
684
|
-
|
685
|
-
|
686
|
-
)
|
687
|
-
parser.add_argument("--
|
688
|
-
parser.add_argument(
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
help="
|
693
|
-
)
|
694
|
-
parser.add_argument(
|
695
|
-
"--
|
696
|
-
|
697
|
-
|
698
|
-
help="
|
699
|
-
)
|
700
|
-
parser.add_argument(
|
701
|
-
"--
|
702
|
-
|
703
|
-
|
704
|
-
help="
|
705
|
-
)
|
706
|
-
|
707
|
-
|
1
|
+
# ruff: noqa: E501
|
2
|
+
import argparse
|
3
|
+
import os
|
4
|
+
|
5
|
+
import birdnet_analyzer.config as cfg
|
6
|
+
|
7
|
+
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
|
8
|
+
ASCII_LOGO = r"""
|
9
|
+
.
|
10
|
+
.-=-
|
11
|
+
.:=++++.
|
12
|
+
..-======#=:.
|
13
|
+
.-%%%#*+=-#+++:..
|
14
|
+
.-+***======++++++=..
|
15
|
+
.=====+==++++++++-.
|
16
|
+
.=+++====++++++++++=:.
|
17
|
+
.++++++++=======----===:
|
18
|
+
=+++++++====-----+++++++-.
|
19
|
+
.=++++==========-=++=====+=:.
|
20
|
+
-++======---:::::-=++++***+:.
|
21
|
+
..---::::::::::::::::-=*****+-.
|
22
|
+
..--------::::::::::::--+##-.:.
|
23
|
+
++++=::::::... ..-------------::::::-::.::.
|
24
|
+
..::-------:::.-=.:::::+-.... ....:--:..
|
25
|
+
..::-======--+::...... .:---:.
|
26
|
+
..:--==+++++==-.. .-+==-
|
27
|
+
......::----: **=--
|
28
|
+
..-=-:. *+=:=
|
29
|
+
..-==== +++ =+**
|
30
|
+
========+
|
31
|
+
**=====
|
32
|
+
***+==
|
33
|
+
****+
|
34
|
+
""" # noqa: W291
|
35
|
+
|
36
|
+
|
37
|
+
def io_args():
|
38
|
+
"""
|
39
|
+
Creates an argument parser for input and output paths.
|
40
|
+
Returns:
|
41
|
+
argparse.ArgumentParser: The argument parser with input and output path arguments.
|
42
|
+
Arguments:
|
43
|
+
input (str): Path to the input file or folder. Defaults to the value specified in cfg.INPUT_PATH.
|
44
|
+
output (str): Path to the output folder. Defaults to the input path if not specified.
|
45
|
+
"""
|
46
|
+
p = argparse.ArgumentParser(add_help=False)
|
47
|
+
p.add_argument(
|
48
|
+
"audio_input",
|
49
|
+
metavar="INPUT",
|
50
|
+
help="Path to input file or folder.",
|
51
|
+
)
|
52
|
+
p.add_argument("-o", "--output", help="Path to output folder. Defaults to the input path.")
|
53
|
+
|
54
|
+
return p
|
55
|
+
|
56
|
+
|
57
|
+
def bandpass_args():
|
58
|
+
"""
|
59
|
+
Creates an argument parser for bandpass filter frequency arguments.
|
60
|
+
This function sets up an argument parser with two arguments:
|
61
|
+
--fmin and --fmax, which define the minimum and maximum frequencies
|
62
|
+
for the bandpass filter, respectively. The values are constrained
|
63
|
+
to be within the range defined by cfg.SIG_FMIN and cfg.SIG_FMAX.
|
64
|
+
Returns:
|
65
|
+
argparse.ArgumentParser: The configured argument parser.
|
66
|
+
"""
|
67
|
+
p = argparse.ArgumentParser(add_help=False)
|
68
|
+
p.add_argument(
|
69
|
+
"--fmin",
|
70
|
+
type=lambda a: max(0, min(cfg.SIG_FMAX, int(a))),
|
71
|
+
default=cfg.SIG_FMIN,
|
72
|
+
help="Minimum frequency for bandpass filter in Hz.",
|
73
|
+
)
|
74
|
+
p.add_argument(
|
75
|
+
"--fmax",
|
76
|
+
type=lambda a: max(cfg.SIG_FMIN, min(cfg.SIG_FMAX, int(a))),
|
77
|
+
default=cfg.SIG_FMAX,
|
78
|
+
help="Maximum frequency for bandpass filter in Hz.",
|
79
|
+
)
|
80
|
+
|
81
|
+
return p
|
82
|
+
|
83
|
+
def species_list_args():
|
84
|
+
"""
|
85
|
+
Creates an argument parser for species-list arguments.
|
86
|
+
Returns:
|
87
|
+
argparse.ArgumentParser: The argument parser with the following arguments:
|
88
|
+
--lat (float): Recording location latitude. Set -1 to ignore. Default is -1.
|
89
|
+
--lon (float): Recording location longitude. Set -1 to ignore. Default is -1.
|
90
|
+
--week (int): Week of the year when the recording was made. Values in [1, 48] (4 weeks per month).
|
91
|
+
Set -1 for year-round species list. Default is -1.
|
92
|
+
--slist (str): Path to species list file or folder. If folder is provided, species list needs to be named
|
93
|
+
"species_list.txt". If lat and lon are provided, this list will be ignored.
|
94
|
+
--sf_thresh (float): Minimum species occurrence frequency threshold for location filter. Values in [0.01, 0.99].
|
95
|
+
Defaults to cfg.LOCATION_FILTER_THRESHOLD.
|
96
|
+
"""
|
97
|
+
p = argparse.ArgumentParser(add_help=False)
|
98
|
+
p.add_argument("--lat", type=float, default=-1, help="Recording location latitude. Set -1 to ignore.")
|
99
|
+
p.add_argument("--lon", type=float, default=-1, help="Recording location longitude. Set -1 to ignore.")
|
100
|
+
p.add_argument(
|
101
|
+
"--week",
|
102
|
+
type=int,
|
103
|
+
default=-1,
|
104
|
+
help="Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 for year-round species list.",
|
105
|
+
)
|
106
|
+
p.add_argument(
|
107
|
+
"--sf_thresh",
|
108
|
+
type=lambda a: max(0.0001, min(0.99, float(a))),
|
109
|
+
default=cfg.LOCATION_FILTER_THRESHOLD,
|
110
|
+
help="Minimum species occurrence frequency threshold for location filter. Values in [0.0001, 0.99].",
|
111
|
+
)
|
112
|
+
return p
|
113
|
+
|
114
|
+
def species_args():
|
115
|
+
"""
|
116
|
+
Creates an argument parser for species-related arguments including the species-list arguments.
|
117
|
+
Returns:
|
118
|
+
argparse.ArgumentParser: The argument parser with the following arguments:
|
119
|
+
--lat (float): Recording location latitude. Set -1 to ignore. Default is -1.
|
120
|
+
--lon (float): Recording location longitude. Set -1 to ignore. Default is -1.
|
121
|
+
--week (int): Week of the year when the recording was made. Values in [1, 48] (4 weeks per month).
|
122
|
+
Set -1 for year-round species list. Default is -1.
|
123
|
+
--sf_thresh (float): Minimum species occurrence frequency threshold for location filter. Values in [0.01, 0.99].
|
124
|
+
Defaults to cfg.LOCATION_FILTER_THRESHOLD.
|
125
|
+
--slist (str): Path to species list file or folder. If folder is provided, species list needs to be named
|
126
|
+
"species_list.txt". If lat and lon are provided, this list will be ignored.
|
127
|
+
"""
|
128
|
+
p = species_list_args()
|
129
|
+
p.add_argument(
|
130
|
+
"--slist",
|
131
|
+
help='Path to species list file or folder. If folder is provided, species list needs to be named "species_list.txt". If lat and lon are provided, this list will be ignored.',
|
132
|
+
)
|
133
|
+
return p
|
134
|
+
|
135
|
+
|
136
|
+
def sigmoid_args():
|
137
|
+
"""
|
138
|
+
Creates an argument parser for sigmoid sensitivity.
|
139
|
+
This function sets up an argument parser with a single argument `--sensitivity`.
|
140
|
+
The sensitivity value is constrained to be within the range [0.75, 1.25], where higher
|
141
|
+
values result in higher detection sensitivity. The default value is taken from
|
142
|
+
`cfg.SIGMOID_SENSITIVITY`.
|
143
|
+
Returns:
|
144
|
+
argparse.ArgumentParser: The argument parser with the sensitivity argument configured.
|
145
|
+
"""
|
146
|
+
p = argparse.ArgumentParser(add_help=False)
|
147
|
+
p.add_argument(
|
148
|
+
"--sensitivity",
|
149
|
+
type=lambda a: min(1.25, max(0.75, float(a))),
|
150
|
+
default=cfg.SIGMOID_SENSITIVITY,
|
151
|
+
help="Detection sensitivity; Higher values result in higher sensitivity. Values in [0.75, 1.25]. Values other than 1.0 will shift the sigmoid functionon the x-axis. Use complementary to the cut-off threshold.",
|
152
|
+
)
|
153
|
+
|
154
|
+
return p
|
155
|
+
|
156
|
+
|
157
|
+
def overlap_args(help_string="Overlap of prediction segments. Values in [0.0, 2.9]."):
|
158
|
+
"""
|
159
|
+
Creates an argument parser for the overlap of prediction segments.
|
160
|
+
Args:
|
161
|
+
help_string (str): A custom help string for the overlap argument. Defaults to a formatted string
|
162
|
+
indicating the range [0.0, 2.9] and the default value from cfg.SIG_OVERLAP.
|
163
|
+
Returns:
|
164
|
+
argparse.ArgumentParser: An argument parser with the overlap argument configured.
|
165
|
+
"""
|
166
|
+
p = argparse.ArgumentParser(add_help=False)
|
167
|
+
p.add_argument(
|
168
|
+
"--overlap",
|
169
|
+
type=lambda a: max(0.0, min(2.9, float(a))),
|
170
|
+
default=cfg.SIG_OVERLAP,
|
171
|
+
help=help_string,
|
172
|
+
)
|
173
|
+
|
174
|
+
return p
|
175
|
+
|
176
|
+
|
177
|
+
def audio_speed_args():
|
178
|
+
"""
|
179
|
+
Creates an argument parser for audio speed configuration.
|
180
|
+
This function sets up an argument parser with a single argument `--audio_speed`
|
181
|
+
which allows the user to specify a speed factor for audio playback. The speed factor
|
182
|
+
must be a float value where values less than 1.0 will slow down the audio and values
|
183
|
+
greater than 1.0 will speed it up. The minimum allowed value is 0.01. The default
|
184
|
+
value is taken from the configuration (`cfg.AUDIO_SPEED`).
|
185
|
+
Returns:
|
186
|
+
argparse.ArgumentParser: The argument parser with the `--audio_speed` argument configured.
|
187
|
+
"""
|
188
|
+
p = argparse.ArgumentParser(add_help=False)
|
189
|
+
p.add_argument(
|
190
|
+
"--audio_speed",
|
191
|
+
type=lambda a: max(0.01, float(a)),
|
192
|
+
default=cfg.AUDIO_SPEED,
|
193
|
+
help="Speed factor for audio playback. Values < 1.0 will slow down the audio, values > 1.0 will speed it up. At a 10x decrease (audio speed 0.1), a 384 kHz recording becomes a 38.4 kHz recording.",
|
194
|
+
)
|
195
|
+
|
196
|
+
return p
|
197
|
+
|
198
|
+
|
199
|
+
def threads_args():
|
200
|
+
"""
|
201
|
+
Creates an argument parser for specifying the number of CPU threads to use.
|
202
|
+
The parser adds an argument `--threads` (or `-t`) which accepts an integer value.
|
203
|
+
The value is constrained to be at least 1. If not specified, the default value is
|
204
|
+
set to half the number of available CPU cores, but not exceeding 8.
|
205
|
+
Returns:
|
206
|
+
argparse.ArgumentParser: The argument parser with the `--threads` argument.
|
207
|
+
"""
|
208
|
+
import multiprocessing
|
209
|
+
|
210
|
+
p = argparse.ArgumentParser(add_help=False)
|
211
|
+
p.add_argument(
|
212
|
+
"-t",
|
213
|
+
"--threads",
|
214
|
+
type=lambda a: max(1, int(a)),
|
215
|
+
default=min(8, max(1, multiprocessing.cpu_count() // 2)),
|
216
|
+
help="Number of CPU threads.",
|
217
|
+
)
|
218
|
+
|
219
|
+
return p
|
220
|
+
|
221
|
+
|
222
|
+
def min_conf_args():
|
223
|
+
"""
|
224
|
+
Creates an argument parser for the minimum confidence threshold.
|
225
|
+
|
226
|
+
Returns:
|
227
|
+
argparse.ArgumentParser: An argument parser with the --min_conf argument.
|
228
|
+
|
229
|
+
The --min_conf argument:
|
230
|
+
- Sets the minimum confidence threshold for predictions.
|
231
|
+
- Accepts float values in the range [0.01, 0.99].
|
232
|
+
- Defaults to the value specified in cfg.MIN_CONFIDENCE.
|
233
|
+
- Ensures that the provided value is clamped between 0.01 and 0.99.
|
234
|
+
"""
|
235
|
+
p = argparse.ArgumentParser(add_help=False)
|
236
|
+
p.add_argument(
|
237
|
+
"--min_conf",
|
238
|
+
default=cfg.MIN_CONFIDENCE,
|
239
|
+
type=lambda a: max(0.00001, min(0.99, float(a))),
|
240
|
+
help="Minimum confidence threshold. Values in [0.00001, 0.99].",
|
241
|
+
)
|
242
|
+
|
243
|
+
return p
|
244
|
+
|
245
|
+
|
246
|
+
def locale_args():
|
247
|
+
"""
|
248
|
+
Creates an argument parser for locale settings.
|
249
|
+
This function creates an argument parser with a single argument `--locale`
|
250
|
+
(or `-l`) which specifies the locale for translated species common names.
|
251
|
+
The default value is 'en' (US English). The available locale values include
|
252
|
+
'af', 'en_UK', 'de', 'it', and others.
|
253
|
+
Returns:
|
254
|
+
argparse.ArgumentParser: An argument parser with the locale argument.
|
255
|
+
"""
|
256
|
+
p = argparse.ArgumentParser(add_help=False)
|
257
|
+
p.add_argument(
|
258
|
+
"-l",
|
259
|
+
"--locale",
|
260
|
+
default="en",
|
261
|
+
help="Locale for translated species common names. Values in ['af', 'en_UK', 'de', 'it', ...].",
|
262
|
+
)
|
263
|
+
|
264
|
+
return p
|
265
|
+
|
266
|
+
|
267
|
+
def bs_args(default=cfg.BATCH_SIZE):
|
268
|
+
"""
|
269
|
+
Creates an argument parser for batch size configuration.
|
270
|
+
Returns:
|
271
|
+
argparse.ArgumentParser: An argument parser with a batch size argument.
|
272
|
+
The parser includes the following argument:
|
273
|
+
-b, --batch_size: An integer specifying the number of samples to process at the same time.
|
274
|
+
The value must be at least 1. Defaults to the value of cfg.BATCH_SIZE.
|
275
|
+
"""
|
276
|
+
p = argparse.ArgumentParser(add_help=False)
|
277
|
+
p.add_argument(
|
278
|
+
"-b",
|
279
|
+
"--batch_size",
|
280
|
+
type=lambda a: max(1, int(a)),
|
281
|
+
default=default,
|
282
|
+
help="Number of samples to process at the same time.",
|
283
|
+
)
|
284
|
+
|
285
|
+
return p
|
286
|
+
|
287
|
+
|
288
|
+
def db_args():
|
289
|
+
"""
|
290
|
+
Creates an arguments parser for the database path.
|
291
|
+
Returns:
|
292
|
+
argparse.ArgumentParser: An argument parser with a database size argument.
|
293
|
+
The parser includes the following argument:
|
294
|
+
-db, --database: Path to the database folder.
|
295
|
+
"""
|
296
|
+
p = argparse.ArgumentParser(add_help=False)
|
297
|
+
p.add_argument(
|
298
|
+
"-db",
|
299
|
+
"--database",
|
300
|
+
help="Path to the database folder.",
|
301
|
+
)
|
302
|
+
|
303
|
+
return p
|
304
|
+
|
305
|
+
|
306
|
+
def analyzer_parser():
|
307
|
+
"""
|
308
|
+
Creates and returns an argument parser for the BirdNET Analyzer CLI.
|
309
|
+
The parser includes various argument groups for different functionalities such as
|
310
|
+
I/O operations, bandpass filtering, species selection, sigmoid function parameters,
|
311
|
+
overlap settings, audio speed adjustments, threading, minimum confidence levels,
|
312
|
+
locale settings, and batch size.
|
313
|
+
If the environment variable "IS_GITHUB_RUNNER" is set to "true", a simplified parser
|
314
|
+
description is used. Otherwise, a detailed ASCII logo and usage instructions are included.
|
315
|
+
The parser also defines a custom action `UniqueSetAction` to ensure that the `--rtype`
|
316
|
+
argument values are stored as a set of unique, lowercase strings.
|
317
|
+
Arguments:
|
318
|
+
--rtype: Specifies output format. Accepts multiple values from ['table', 'audacity', 'kaleidoscope', 'csv'].
|
319
|
+
--combine_results: Outputs a combined file for all selected result types if set.
|
320
|
+
-c, --classifier: Path to a custom trained classifier. Overrides --lat, --lon, and --locale if set.
|
321
|
+
--skip_existing_results: Skips files that have already been analyzed if set.
|
322
|
+
--top_n: Saves only the top N predictions for each segment. Threshold will be ignored.
|
323
|
+
--merge_consecutive: Maximum number of consecutive detections to merge for each species.
|
324
|
+
Returns:
|
325
|
+
argparse.ArgumentParser: Configured argument parser for the BirdNET Analyzer CLI.
|
326
|
+
"""
|
327
|
+
from birdnet_analyzer.analyze import POSSIBLE_ADDITIONAL_COLUMNS_MAP
|
328
|
+
parents = [
|
329
|
+
io_args(),
|
330
|
+
bandpass_args(),
|
331
|
+
species_args(),
|
332
|
+
sigmoid_args(),
|
333
|
+
overlap_args(),
|
334
|
+
audio_speed_args(),
|
335
|
+
threads_args(),
|
336
|
+
min_conf_args(),
|
337
|
+
locale_args(),
|
338
|
+
bs_args(),
|
339
|
+
]
|
340
|
+
|
341
|
+
parser = argparse.ArgumentParser(
|
342
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
343
|
+
parents=parents,
|
344
|
+
)
|
345
|
+
|
346
|
+
class UniqueSetAction(argparse.Action):
|
347
|
+
def __call__(self, parser, args, values, option_string=None):
|
348
|
+
setattr(args, self.dest, {v.lower() for v in values})
|
349
|
+
|
350
|
+
parser.add_argument(
|
351
|
+
"--rtype",
|
352
|
+
default={"table"},
|
353
|
+
choices=["table", "audacity", "kaleidoscope", "csv"],
|
354
|
+
nargs="+",
|
355
|
+
help="Specifies output format. Values in `['table', 'audacity', 'kaleidoscope', 'csv']`.",
|
356
|
+
action=UniqueSetAction,
|
357
|
+
)
|
358
|
+
parser.add_argument(
|
359
|
+
"--additional_columns",
|
360
|
+
choices=POSSIBLE_ADDITIONAL_COLUMNS_MAP.keys(),
|
361
|
+
nargs="+",
|
362
|
+
help="Additional columns to include in the output, only applied to the csv output format. "
|
363
|
+
+ f"Values in [{','.join(POSSIBLE_ADDITIONAL_COLUMNS_MAP.keys())}].",
|
364
|
+
action=UniqueSetAction,
|
365
|
+
)
|
366
|
+
parser.add_argument(
|
367
|
+
"--combine_results",
|
368
|
+
help="Also outputs a combined file for all the selected result types. If not set combined tables will be generated.",
|
369
|
+
action="store_true",
|
370
|
+
)
|
371
|
+
|
372
|
+
parser.add_argument(
|
373
|
+
"-c",
|
374
|
+
"--classifier",
|
375
|
+
default=cfg.CUSTOM_CLASSIFIER,
|
376
|
+
help="Path to custom trained classifier. If set, --lat, --lon and --locale are ignored.",
|
377
|
+
)
|
378
|
+
|
379
|
+
parser.add_argument(
|
380
|
+
"--skip_existing_results",
|
381
|
+
action="store_true",
|
382
|
+
help="Skip files that have already been analyzed.",
|
383
|
+
)
|
384
|
+
|
385
|
+
parser.add_argument(
|
386
|
+
"--top_n",
|
387
|
+
type=lambda a: max(1, int(a)),
|
388
|
+
help="Saves only the top N predictions for each segment independent of their score. Threshold will be ignored.",
|
389
|
+
)
|
390
|
+
|
391
|
+
parser.add_argument(
|
392
|
+
"--merge_consecutive",
|
393
|
+
type=int,
|
394
|
+
default=1,
|
395
|
+
help="Maximum number of consecutive detections above MIN_CONF to merge for each detected species. This will result in fewer entires in the result file with segments longer than 3 seconds. Set to 0 or 1 to disable merging. Set to None to include all consecutive detections. We use the mean of the top 3 scores from all consecutive detections for merging.",
|
396
|
+
)
|
397
|
+
|
398
|
+
return parser
|
399
|
+
|
400
|
+
|
401
|
+
def embeddings_parser():
|
402
|
+
"""
|
403
|
+
Creates and returns an argument parser for extracting feature embeddings with BirdNET.
|
404
|
+
|
405
|
+
The parser includes arguments from the following parent parsers:
|
406
|
+
- db_args(): Handles database arguments.
|
407
|
+
- bandpass_args(): Handles bandpass filter arguments.
|
408
|
+
- audio_speed_args(): Handles audio speed arguments.
|
409
|
+
- overlap_args(): Handles overlap arguments.
|
410
|
+
- threads_args(): Handles threading arguments.
|
411
|
+
- bs_args(): Handles batch size arguments.
|
412
|
+
|
413
|
+
Returns:
|
414
|
+
argparse.ArgumentParser: Configured argument parser for extracting feature embeddings.
|
415
|
+
"""
|
416
|
+
|
417
|
+
parents = [db_args(), bandpass_args(), audio_speed_args(), overlap_args(), threads_args(), bs_args()]
|
418
|
+
|
419
|
+
parser = argparse.ArgumentParser(
|
420
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
421
|
+
parents=parents,
|
422
|
+
)
|
423
|
+
|
424
|
+
parser.add_argument(
|
425
|
+
"-i",
|
426
|
+
"--input",
|
427
|
+
dest="audio_input",
|
428
|
+
help="Path to input file or folder.",
|
429
|
+
)
|
430
|
+
|
431
|
+
parser.add_argument(
|
432
|
+
"--file_output",
|
433
|
+
)
|
434
|
+
|
435
|
+
return parser
|
436
|
+
|
437
|
+
|
438
|
+
def search_parser():
|
439
|
+
"""
|
440
|
+
Creates and returns an argument parser for searching BirdNET embeddings.
|
441
|
+
|
442
|
+
The parser includes the following arguments:
|
443
|
+
- -q, --queryfile: Path to the query file.
|
444
|
+
- -o, --output: Path to the output folder.
|
445
|
+
- --n_results: Number of results to return.
|
446
|
+
- --score_function: Scoring function to use. Choose 'cosine', 'euclidean' or 'dot'. Defaults to 'cosine'.
|
447
|
+
- --crop_mode: Crop mode for the query sample. Can be 'center', 'first' or 'segments'.
|
448
|
+
|
449
|
+
The parser also includes arguments from the following parent parsers:
|
450
|
+
- overlap_args(): Handles overlap arguments if segments is selected as crop mode.
|
451
|
+
- db_args(): Handles database arguments.
|
452
|
+
"""
|
453
|
+
|
454
|
+
parents = [overlap_args(), db_args()]
|
455
|
+
|
456
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, parents=parents)
|
457
|
+
parser.add_argument("-q", "--queryfile", help="Path to the query file.")
|
458
|
+
parser.add_argument("-o", "--output", help="Path to the output folder.")
|
459
|
+
parser.add_argument("--n_results", default=10, help="Number of results to return.")
|
460
|
+
|
461
|
+
# TODO: use choice argument.
|
462
|
+
parser.add_argument(
|
463
|
+
"--score_function",
|
464
|
+
default="cosine",
|
465
|
+
choices=["cosine", "euclidean", "dot"],
|
466
|
+
help="Scoring function to use. Choose 'cosine', 'euclidean' or 'dot'. Defaults to 'cosine'.",
|
467
|
+
)
|
468
|
+
parser.add_argument(
|
469
|
+
"--crop_mode",
|
470
|
+
default=cfg.SAMPLE_CROP_MODE,
|
471
|
+
choices=["center", "first", "segments"],
|
472
|
+
help="Crop mode for the query sample. Can be 'center', 'first' or 'segments'.",
|
473
|
+
)
|
474
|
+
|
475
|
+
return parser
|
476
|
+
|
477
|
+
|
478
|
+
def client_parser():
|
479
|
+
"""
|
480
|
+
Creates and returns an argument parser for the client that queries an analyzer API endpoint server.
|
481
|
+
The parser includes the following arguments:
|
482
|
+
- --host: Host name or IP address of the API endpoint server (default: "localhost").
|
483
|
+
- -p, --port: Port of the API endpoint server (default: 8080).
|
484
|
+
- --pmode: Score pooling mode, with possible values 'avg' or 'max' (default: "avg").
|
485
|
+
- --num_results: Number of results per request (default: 5).
|
486
|
+
- --save: Flag to define if files should be stored on the server.
|
487
|
+
The parser also includes arguments from the following parent parsers:
|
488
|
+
- io_args()
|
489
|
+
- species_args()
|
490
|
+
- sigmoid_args()
|
491
|
+
- overlap_args()
|
492
|
+
Returns:
|
493
|
+
argparse.ArgumentParser: Configured argument parser for the client.
|
494
|
+
"""
|
495
|
+
parser = argparse.ArgumentParser(
|
496
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
497
|
+
parents=[io_args(), species_args(), sigmoid_args(), overlap_args()],
|
498
|
+
)
|
499
|
+
parser.add_argument("--host", default="localhost", help="Host name or IP address of API endpoint server.")
|
500
|
+
parser.add_argument("-p", "--port", type=int, default=8080, help="Port of API endpoint server.")
|
501
|
+
parser.add_argument("--pmode", default="avg", help="Score pooling mode. Values in ['avg', 'max'].")
|
502
|
+
parser.add_argument("--num_results", type=int, default=5, help="Number of results per request.")
|
503
|
+
parser.add_argument(
|
504
|
+
"--save",
|
505
|
+
action="store_true",
|
506
|
+
help="Define if files should be stored on server.",
|
507
|
+
)
|
508
|
+
|
509
|
+
return parser
|
510
|
+
|
511
|
+
|
512
|
+
def segments_parser():
|
513
|
+
"""
|
514
|
+
Creates an argument parser for extracting segments from audio files based on BirdNET detections.
|
515
|
+
Returns:
|
516
|
+
argparse.ArgumentParser: Configured argument parser with the following arguments:
|
517
|
+
- input (str): Path to folder containing audio files.
|
518
|
+
- results (str, optional): Path to folder containing result files. Defaults to the `input` path.
|
519
|
+
- output (str, optional): Output folder path for extracted segments. Defaults to the `input` path.
|
520
|
+
- max_segments (int, optional): Number of randomly extracted segments per species. Defaults to 100.
|
521
|
+
- seg_length (float, optional): Length of extracted segments in seconds. Defaults to cfg.SIG_LENGTH.
|
522
|
+
"""
|
523
|
+
parser = argparse.ArgumentParser(
|
524
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
525
|
+
parents=[audio_speed_args(), threads_args(), min_conf_args()],
|
526
|
+
)
|
527
|
+
parser.add_argument("audio_input", metavar="INPUT", help="Path to folder containing audio files.")
|
528
|
+
parser.add_argument("-r", "--results", help="Path to folder containing result files. Defaults to the `input` path.")
|
529
|
+
parser.add_argument("-o", "--output", help="Output folder path for extracted segments. Defaults to the `input` path.")
|
530
|
+
parser.add_argument(
|
531
|
+
"--max_segments",
|
532
|
+
type=lambda a: max(1, int(a)),
|
533
|
+
default=100,
|
534
|
+
help="Number of randomly extracted segments per species.",
|
535
|
+
)
|
536
|
+
|
537
|
+
parser.add_argument(
|
538
|
+
"--seg_length",
|
539
|
+
type=lambda a: max(1.0, float(a)),
|
540
|
+
default=cfg.SIG_LENGTH,
|
541
|
+
help="Minimum length of extracted segments in seconds. If a segment is shorter than this value, it will be padded with audio from the source file.",
|
542
|
+
)
|
543
|
+
|
544
|
+
return parser
|
545
|
+
|
546
|
+
|
547
|
+
def server_parser():
|
548
|
+
"""
|
549
|
+
Creates and configures an argument parser for the API endpoint server.
|
550
|
+
The parser includes arguments for specifying the host, port, and storage path for uploaded files.
|
551
|
+
It also inherits arguments from `threads_args` and `locale_args`.
|
552
|
+
Returns:
|
553
|
+
argparse.ArgumentParser: Configured argument parser with server-specific options.
|
554
|
+
"""
|
555
|
+
parser = argparse.ArgumentParser(
|
556
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
557
|
+
parents=[threads_args(), locale_args()],
|
558
|
+
)
|
559
|
+
|
560
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host name or IP address of API endpoint server.")
|
561
|
+
parser.add_argument("-p", "--port", type=int, default=8080, help="Port of API endpoint server.")
|
562
|
+
parser.add_argument(
|
563
|
+
"--spath",
|
564
|
+
default="uploads/" if os.environ.get("IS_GITHUB_RUNNER", "false").lower() == "true" else os.path.join(SCRIPT_DIR, "uploads"),
|
565
|
+
help="Path to folder where uploaded files should be stored.",
|
566
|
+
)
|
567
|
+
|
568
|
+
return parser
|
569
|
+
|
570
|
+
|
571
|
+
def species_parser():
|
572
|
+
"""
|
573
|
+
Creates an argument parser for retrieving a list of species for a given location using BirdNET.
|
574
|
+
The parser includes the following arguments:
|
575
|
+
- output: Path to the output file or folder. If a folder is provided, the file will be named 'species_list.txt'.
|
576
|
+
- --sortby: Optional argument to sort species by occurrence frequency ('freq') or alphabetically ('alpha'). Defaults to 'freq'.
|
577
|
+
Returns:
|
578
|
+
argparse.ArgumentParser: Configured argument parser for species retrieval.
|
579
|
+
"""
|
580
|
+
parser = argparse.ArgumentParser(
|
581
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
582
|
+
parents=[species_list_args()],
|
583
|
+
)
|
584
|
+
parser.add_argument(
|
585
|
+
"output",
|
586
|
+
metavar="OUTPUT",
|
587
|
+
help="Path to output file or folder. If this is a folder, file will be named 'species_list.txt'.",
|
588
|
+
)
|
589
|
+
|
590
|
+
parser.add_argument(
|
591
|
+
"--sortby",
|
592
|
+
default="freq",
|
593
|
+
choices=["freq", "alpha"],
|
594
|
+
help="Sort species by occurrence frequency or alphabetically. Values in ['freq', 'alpha'].",
|
595
|
+
)
|
596
|
+
|
597
|
+
return parser
|
598
|
+
|
599
|
+
|
600
|
+
def train_parser():
|
601
|
+
"""
|
602
|
+
Creates an argument parser for training a custom classifier with BirdNET.
|
603
|
+
The parser includes arguments for various training parameters such as input data path, crop mode,
|
604
|
+
output path, number of epochs, batch size, validation split ratio, learning rate, hidden units,
|
605
|
+
dropout rate, mixup, upsampling ratio and mode, model format, model save mode, cache mode and file,
|
606
|
+
and hyperparameter tuning options.
|
607
|
+
Returns:
|
608
|
+
argparse.ArgumentParser: Configured argument parser for training a custom classifier.
|
609
|
+
"""
|
610
|
+
parser = argparse.ArgumentParser(
|
611
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
612
|
+
parents=[
|
613
|
+
bandpass_args(),
|
614
|
+
audio_speed_args(),
|
615
|
+
threads_args(),
|
616
|
+
bs_args(cfg.TRAIN_BATCH_SIZE),
|
617
|
+
overlap_args(help_string="Overlap of training data segments in seconds if crop_mode is 'segments'."),
|
618
|
+
],
|
619
|
+
)
|
620
|
+
c = (
|
621
|
+
"checkpoints/custom/Custom_Classifier"
|
622
|
+
if os.environ.get("IS_GITHUB_RUNNER", "false").lower() == "true"
|
623
|
+
else os.path.join(SCRIPT_DIR, "checkpoints/custom/Custom_Classifier")
|
624
|
+
)
|
625
|
+
parser.add_argument(
|
626
|
+
"audio_input",
|
627
|
+
metavar="INPUT",
|
628
|
+
help="Path to training data folder. Subfolder names are used as labels.",
|
629
|
+
)
|
630
|
+
parser.add_argument("--test_data", help="Path to test data folder. If not specified, a random validation split will be used.")
|
631
|
+
parser.add_argument(
|
632
|
+
"--crop_mode",
|
633
|
+
default=cfg.SAMPLE_CROP_MODE,
|
634
|
+
choices=["center", "first", "segments", "smart"],
|
635
|
+
help="Crop mode for training data. Can be 'center', 'first', 'segments' or 'smart'.",
|
636
|
+
)
|
637
|
+
parser.add_argument("-o", "--output", default=c, help="Path to trained classifier model output.")
|
638
|
+
parser.add_argument(
|
639
|
+
"--epochs",
|
640
|
+
type=int,
|
641
|
+
default=cfg.TRAIN_EPOCHS,
|
642
|
+
help="Number of training epochs.",
|
643
|
+
)
|
644
|
+
parser.add_argument(
|
645
|
+
"--val_split",
|
646
|
+
type=float,
|
647
|
+
default=cfg.TRAIN_VAL_SPLIT,
|
648
|
+
help="Validation split ratio. Will be ignored if test_data is set.",
|
649
|
+
)
|
650
|
+
parser.add_argument(
|
651
|
+
"--learning_rate",
|
652
|
+
type=float,
|
653
|
+
default=cfg.TRAIN_LEARNING_RATE,
|
654
|
+
help="Learning rate.",
|
655
|
+
)
|
656
|
+
parser.add_argument(
|
657
|
+
"--focal-loss",
|
658
|
+
dest="use_focal_loss",
|
659
|
+
action="store_true",
|
660
|
+
help="Use focal loss for training (helps with imbalanced classes and hard examples).",
|
661
|
+
)
|
662
|
+
parser.add_argument(
|
663
|
+
"--focal-loss-gamma",
|
664
|
+
default=cfg.FOCAL_LOSS_GAMMA,
|
665
|
+
type=float,
|
666
|
+
help="Focal loss gamma parameter (focusing parameter). Higher values give more weight to hard examples.",
|
667
|
+
)
|
668
|
+
parser.add_argument(
|
669
|
+
"--focal-loss-alpha",
|
670
|
+
default=cfg.FOCAL_LOSS_ALPHA,
|
671
|
+
type=float,
|
672
|
+
help="Focal loss alpha parameter (balancing parameter). Controls weight between positive and negative examples.",
|
673
|
+
)
|
674
|
+
parser.add_argument(
|
675
|
+
"--hidden_units",
|
676
|
+
type=int,
|
677
|
+
default=cfg.TRAIN_HIDDEN_UNITS,
|
678
|
+
help="Number of hidden units. If set to >0, a two-layer classifier is used.",
|
679
|
+
)
|
680
|
+
parser.add_argument(
|
681
|
+
"--dropout",
|
682
|
+
type=lambda a: min(max(0, float(a)), 0.9),
|
683
|
+
default=cfg.TRAIN_DROPOUT,
|
684
|
+
help="Dropout rate. Higher values result in more regularization. Values in [0.0, 0.9].",
|
685
|
+
)
|
686
|
+
parser.add_argument("--label_smoothing", action="store_true", help="Whether to use label smoothing for training.")
|
687
|
+
parser.add_argument("--mixup", action="store_true", help="Whether to use mixup for training.")
|
688
|
+
parser.add_argument(
|
689
|
+
"--upsampling_ratio",
|
690
|
+
type=lambda a: min(max(0, float(a)), 1),
|
691
|
+
default=cfg.UPSAMPLING_RATIO,
|
692
|
+
help="Balance train data and upsample minority classes. Values between 0 and 1.",
|
693
|
+
)
|
694
|
+
parser.add_argument(
|
695
|
+
"--upsampling_mode",
|
696
|
+
default=cfg.UPSAMPLING_MODE,
|
697
|
+
choices=["repeat", "linear", "mean", "smote"],
|
698
|
+
help="Upsampling mode.",
|
699
|
+
)
|
700
|
+
parser.add_argument(
|
701
|
+
"--model_format",
|
702
|
+
default=cfg.TRAINED_MODEL_OUTPUT_FORMAT,
|
703
|
+
choices=["tflite", "raven", "both"],
|
704
|
+
help="Model output format.",
|
705
|
+
)
|
706
|
+
parser.add_argument(
|
707
|
+
"--model_save_mode",
|
708
|
+
default=cfg.TRAINED_MODEL_SAVE_MODE,
|
709
|
+
choices=["replace", "append"],
|
710
|
+
help="Model save mode. 'replace' will overwrite the original classification layer and 'append' will combine the original classification layer with the new one.",
|
711
|
+
)
|
712
|
+
parser.add_argument("--cache_mode", choices=["load", "save"], help="Cache mode. Can be 'load' or 'save'.")
|
713
|
+
parser.add_argument("--cache_file", default=cfg.TRAIN_CACHE_FILE, help="Path to cache file.")
|
714
|
+
parser.add_argument(
|
715
|
+
"--autotune",
|
716
|
+
action="store_true",
|
717
|
+
help="Whether to use automatic hyperparameter tuning (this will execute multiple training runs to search for optimal hyperparameters).",
|
718
|
+
)
|
719
|
+
parser.add_argument(
|
720
|
+
"--autotune_trials",
|
721
|
+
type=int,
|
722
|
+
default=cfg.AUTOTUNE_TRIALS,
|
723
|
+
help="Number of training runs for hyperparameter tuning.",
|
724
|
+
)
|
725
|
+
parser.add_argument(
|
726
|
+
"--autotune_executions_per_trial",
|
727
|
+
type=int,
|
728
|
+
default=cfg.AUTOTUNE_EXECUTIONS_PER_TRIAL,
|
729
|
+
help="The number of times a training run with a set of hyperparameters is repeated during hyperparameter tuning (this reduces the variance).",
|
730
|
+
)
|
731
|
+
|
732
|
+
return parser
|