Skip to content

Add MobileNet ONNX species classification and modernize BatBot - #44

Open
bluemellophone wants to merge 9 commits into
mainfrom
jrp/ml-model
Open

Add MobileNet ONNX species classification and modernize BatBot#44
bluemellophone wants to merge 9 commits into
mainfrom
jrp/ml-model

Conversation

@bluemellophone

@bluemellophone bluemellophone commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR prepares BatBot 0.2.0 by adding end-to-end bat-species classification with a bundled 35-label MobileNet ONNX model. Users can classify existing spectrograms, generate and classify spectrograms from WAV recordings, or process directory trees with fault-tolerant summaries and ordered multi-worker inference.

The PR also restructures the package so importing batbot is lightweight, consolidates project configuration in pyproject.toml, raises the minimum Python version to 3.11, modernizes testing and publishing workflows, and expands branch coverage to 82.7%.

High-level changes

Area Change User impact
Classification Added a Scoutbot-inspired pre / predict / post ONNX inference pipeline and reusable Classifier Spectrograms can be classified directly into species codes and confidence scores
Model delivery Bundled the MobileNet model with SHA-256 verification and a pooch download mirror Installed packages work offline when the bundled model is present and can recover from the mirror
WAV and bulk processing Added WAV-to-spectrogram classification, recursive discovery, weighted aggregation, partial-failure handling, and summary statistics Large labeled or unlabeled datasets can be processed in one command
Concurrency Added bounded multi-worker ONNX inference sharing one validated session Users can increase throughput with --num-workers without loading one model per worker
CLI Added classify, classify-wav, and classify-bulk; completed fetch and the legacy batch path Classification is available without writing Python
Evaluation Added a performance plotting example for labeled WAV/JPG/JPEG datasets Users can generate confusion matrices, top-k metrics, MCC, and NOISE diagnostics
Package structure Moved high-level functions into batbot.api and added lazy submodule loading import batbot no longer initializes scientific/ONNX stacks or creates a log file
Packaging Consolidated metadata, dependencies, extras, and tool settings in pyproject.toml One authoritative configuration replaces duplicated setup and requirements files
CI/CD Updated the Python matrix, distribution validation, wheel smoke tests, and PyPI OIDC publishing Releases are tested from built artifacts and no longer require a long-lived PyPI token
Quality Added classifier, API, CLI, utility, cache, concurrency, and performance-example tests 79 tests pass, with one xdoctest skipped and 82.7% branch coverage

Model and inference behavior

  • The package includes batbot.mobilenet.9dc57ea3.onnx through Git LFS and package data.
  • The bundled model and mirrored download are checked against the expected SHA-256 hash.
  • Model downloads use a BatBot-versioned pooch cache.
  • Image preprocessing retains the model's training-time BGR layout and produces overlapping 224 × 224 × 3 windows.
  • Scores from multiple windows and multiple WAV spectrograms are aggregated using window counts as weights.
  • num_workers > 1 runs per-spectrogram ONNX calls concurrently, preserves input order, bounds in-flight work, and reuses one session.
  • Generated WAV spectrograms are temporary by default and can be retained with spectrogram_output or --spectrogram-dir.
  • Bulk processing records failures per input instead of discarding successful results.

CLI changes

Command Purpose Important options
batbot fetch Resolve the verified model path --pull, --config
batbot classify Classify one or more spectrogram images --batch-size, --num-workers, --top-k, --output
batbot classify-wav Generate spectrograms and classify WAV recordings --spectrogram-dir, --batch-size, --num-workers, --top-k, --output
batbot classify-bulk Recursively classify WAVs, spectrograms, or both --input-type, --recursive/--no-recursive, --spectrogram-dir, --num-workers
batbot batch Legacy WAV-classification alias --config, --num-workers, --output

Classification commands emit JSON containing individual results and a summary. The summary includes total, classified and failed counts, label counts, species counts excluding NOISE, the noise count, and mean confidence.

Performance plotting

examples/plot_classifier_performance.py now accepts a folder hierarchy containing WAV, JPG, or JPEG inputs, including mixed datasets. The immediate parent directory remains the ground-truth label:

validation/
├── EPFU/
│   ├── recording-01.wav
│   └── call-02.jpg
├── MYLU/
│   └── call-03.jpeg
└── NOISE/
    └── background-01.wav

The example supports reusable prediction caches and multi-worker inference. It produces count, true-normalized, and prediction-normalized confusion matrices; top-1/2/3/5 accuracy; Matthews correlation; and NOISE precision-recall, ROC, and operating-point diagnostics when applicable. Species are reordered by genus before plotting so the shaded error regions remain contiguous.

API changes

New classifier API

API Description
batbot.classifier.Classifier(...) Reusable classifier owning a lazily created, validated ONNX session
classifier.classify(inputs, ...) One-shot classification for spectrogram paths
classifier.classify_wav(filepath, ...) Spectrogram generation plus recording-level classification
classifier.classify_bulk(inputs, ...) Recursive, fault-tolerant WAV/spectrogram classification and summaries
classifier.fetch(pull=False, config=...) Return a verified bundled or cached model path
classifier.discover_inputs(...) Resolve files and directories with deterministic ordering and type filtering
classifier.summarize(results) Produce label/species counts, failures, noise count, and mean confidence
classifier.pre, predict, post Low-level Scoutbot-style preprocessing, ONNX inference, and label association

batch_size limits the number of image windows sent in one ONNX call. num_workers controls the number of concurrent per-spectrogram inference jobs and defaults to 1 to avoid unexpected CPU oversubscription.

Result contracts

Field Meaning
path Original spectrogram or WAV path
label Highest-scoring model label
confidence Score associated with label
window_count Number of model windows included in the result
top Ranked top-k label/confidence pairs
scores Score for every configured class
spectrogram_paths Retained generated spectrograms, when applicable

Bulk failures use { "path": ..., "error": ... } and remain in input order alongside successful results.

Existing top-level API

  • batbot.fetch() is now implemented and returns the resolved model path.
  • batbot.batch() is now implemented, reuses a classifier session, and returns classification results. Its clean argument remains accepted for compatibility; generated temporary spectrograms are always cleaned.
  • batbot.pipeline(), pipeline_multi_wrapper(), parallel_pipeline(), and example() moved to batbot.api and remain re-exported from batbot.
  • pipeline_multi_wrapper() and parallel_pipeline() now raise ValueError for invalid lengths or worker counts instead of relying on assertions.
  • VERSION, version, and __version__ remain available, with _version.py as the package metadata source.
  • classifier and spectrogram are exposed lazily through batbot.__getattr__.

Compatibility notes

Change Migration
Minimum Python is now 3.11 Upgrade Python before installing BatBot 0.2.0
Dependencies moved from requirements/*.txt Install batbot, batbot[test], batbot[docs], or batbot[performance] as appropriate
Logging is no longer configured at import time Configure the batbot logger in the application or call batbot.utils.init_logging()
Legacy VERBOSE, CLASSIFIER_CONFIG, and CLASSIFIER_BATCH_SIZE remain supported Prefer the BATBOT_...-prefixed environment variables
Legacy batch output is now real classifier output Consume the same result objects and summary format used by the new classification commands

Changelog

Added

  • MobileNet ONNX classifier package with 35 labels, including NOISE.
  • Verified bundled model and Kitware Data mirror retrieval through pooch.
  • Versioned model cache and forced mirror refresh through pull=True / --pull.
  • Spectrogram dataloader, resizing, padding, and overlapping window generation.
  • Low-level pre / predict / post inference functions.
  • Reusable Classifier with ONNX session reuse and optional provider selection.
  • Bounded, ordered multi-worker ONNX inference.
  • WAV classification, recursive bulk classification, fault isolation, weighted aggregation, and summary statistics.
  • classify, classify-wav, and classify-bulk CLI commands.
  • Typed classifier configuration and JSON result contracts plus the py.typed marker.
  • Performance plotting for labeled WAV/JPG/JPEG or mixed datasets, with genus-aware visualization ordering.
  • Classifier/API/CLI/cache/concurrency/utility/performance tests and real-model smoke coverage.
  • PyPI trusted-publishing documentation and GitHub OIDC release workflow.
  • Wheel installation and bundled-model inference smoke test in CI.
  • Python 3.11–3.14 CI matrix and Codecov upload from Python 3.11.

Removed

  • setup.py, setup.cfg, .flake8, and the three duplicated requirements/*.txt files.
  • Packaging support for Python versions older than 3.11.
  • Import-time Rich/file logging configuration and its batbot.log side effect.
  • Long-lived BATBOT_PYPI_TOKEN usage in the publishing workflow.
  • Redundant platform-specific wheel builds for this pure-Python distribution.
  • The scheduled daily distribution build.

Updated

  • Version metadata to 0.2.0 through batbot/_version.py.
  • Package metadata, Apache-2.0 license declaration, dependencies, extras, entry points, package data, and tool settings in pyproject.toml.
  • batbot.__init__ to a small public facade with lazy computational submodules.
  • High-level processing functions to live in batbot.api with explicit signatures and validation.
  • The legacy fetch and batch APIs from placeholders to functional classifier entry points.
  • CLI validation and JSON output behavior.
  • Spectrogram logging to use the side-effect-free package logger.
  • Docker installation to consume project metadata directly.
  • Read the Docs to use Ubuntu 24.04, Python 3.11, and the docs extra.
  • Pre-commit hooks and Python 3.11 formatting targets while retaining Black, isort, and Flake8.
  • Pytest to 8.4.2, branch coverage configuration, random ordering, and focused classifier tests.
  • README and Sphinx documentation for classification, environments, development, and trusted publishing.

Validation

Check Result
Full random-order pytest suite 79 passed, 1 xdoctest skipped
Branch coverage 82.7% overall
Classifier inference coverage 100%
Classifier bulk coverage 100%
Real bundled ONNX model Single-worker and two-worker inference validated
Formatting and linting pyupgrade, isort, Black, Flake8, and repository hygiene hooks pass
Distribution workflow Builds wheel and sdist, runs twine check, installs the wheel outside the checkout, and performs model inference

Reviewer notes

  • The ONNX model is tracked through Git LFS; reviewers and CI need LFS content available for the real-model tests and distribution build.
  • PyPI must have a trusted publisher matching owner Kitware, repository batbot, workflow python-publish.yaml, and environment pypi before the first tagged release.
  • The default inference worker count remains 1; concurrency is opt-in through num_workers or --num-workers.

@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.02597% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.2%. Comparing base (6820cc8) to head (356d76c).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
batbot/classifier/dataloader.py 95.4% 1 Missing and 2 partials ⚠️
batbot/api.py 97.5% 1 Missing and 1 partial ⚠️
batbot/batbot_cli.py 98.5% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##            main     #44      +/-   ##
========================================
+ Coverage   59.2%   80.2%   +20.9%     
========================================
  Files          7      14       +7     
  Lines       1383    1874     +491     
  Branches       0     251     +251     
========================================
+ Hits         820    1504     +684     
+ Misses       563     300     -263     
- Partials       0      70      +70     
Files with missing lines Coverage Δ
batbot/__init__.py 100.0% <100.0%> (+57.5%) ⬆️
batbot/_config.py 100.0% <100.0%> (ø)
batbot/_version.py 100.0% <100.0%> (ø)
batbot/classifier/__init__.py 100.0% <100.0%> (ø)
batbot/classifier/bulk.py 100.0% <100.0%> (ø)
batbot/classifier/config.py 100.0% <100.0%> (ø)
batbot/classifier/inference.py 100.0% <100.0%> (ø)
batbot/classifier/model.py 100.0% <100.0%> (ø)
batbot/classifier/types.py 100.0% <100.0%> (ø)
batbot/spectrogram/__init__.py 66.6% <100.0%> (-3.8%) ⬇️
... and 4 more

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a3cdeeb...356d76c. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bluemellophone bluemellophone changed the title Adding new ML model inference Add MobileNet ONNX species classification and modernize BatBot Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant