Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
* text=auto

*.py text eol=lf
*.js text eol=lf
*.css text eol=lf
*.html text eol=lf
*.md text eol=lf
*.json text eol=lf
*.toml text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.txt text eol=lf
*.webmanifest text eol=lf
*.svg text eol=lf

*.onnx binary
40 changes: 40 additions & 0 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Deploy Fieldmark to GitHub Pages

on:
push:
branches:
- main
- agent/github-pages-browser-inference
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: true

jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Configure GitHub Pages
uses: actions/configure-pages@v5

- name: Upload static site
uses: actions/upload-pages-artifact@v3
with:
path: web

- name: Deploy GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.ruff_cache/
.venv/
venv/
node_modules/
.env
.DS_Store

# Editor and agent-local state
.claude/

# NABirds may exist in either supported local location. Never publish it.
nabirds/
data/raw/*
!data/raw/.gitkeep
data/external/my_photos/*
!data/external/my_photos/.gitkeep
data/processed/*
!data/processed/.gitkeep

# Large/generated Python model artifacts stay local.
models/*
!models/.gitkeep
reports/*
!reports/.gitkeep
!reports/figures/
reports/figures/*
!reports/figures/.gitkeep

# The optimized browser artifact is intentionally versioned under web/model.
20 changes: 20 additions & 0 deletions .streamlit/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[theme]
base = "dark"
primaryColor = "#67C592"
backgroundColor = "#0F1513"
secondaryBackgroundColor = "#17201B"
textColor = "#EAF0E9"
linkColor = "#8CD6AB"
borderColor = "#3B4A40"
showWidgetBorder = true
baseRadius = "0.8rem"
buttonRadius = "full"
font = "sans-serif"
headingFont = "serif"
codeFont = "monospace"

[browser]
gatherUsageStats = false

[server]
maxUploadSize = 20
144 changes: 144 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Fieldmark Bird Detector

[![Deploy Fieldmark to GitHub Pages](https://github.com/du000362/Bird-Detector/actions/workflows/pages.yml/badge.svg)](https://github.com/du000362/Bird-Detector/actions/workflows/pages.yml)

Fieldmark is a complete fine-grained bird-recognition project built with PyTorch, EfficientNet-B0, NABirds, and an interactive privacy-first website.

**Live website:** [du000362.github.io/Bird-Detector](https://du000362.github.io/Bird-Detector/)

The GitHub Pages version runs the trained ONNX model directly in the visitor's browser. A selected photograph is decoded and classified on-device; it is not uploaded to GitHub or an inference API.

## Model results

Evaluation used the untouched official NABirds test split: 24,633 images across 555 fine-grained classes.

| Metric | Result | Meaning |
|---|---:|---|
| Top-1 accuracy | 52.02% | The first guess was the exact class |
| Top-3 accuracy | 71.05% | The exact class appeared among three guesses |
| Top-5 accuracy | 78.03% | The exact class appeared among five guesses |
| Macro-F1 | 49.27% | Every class received equal weight |
| Calibration error | 1.67% | Confidence closely tracked observed accuracy |

Top-5 accuracy is not a 78% guarantee for a particular photo. It is the share of the full test set where the correct class appeared somewhere in the five-name shortlist.

## Run it

### Interactive GitHub Pages site

Open the [live website](https://du000362.github.io/Bird-Detector/), select **Identify**, wait for the 18 MB browser model to become ready, then drop in a JPEG, PNG, or WebP image.

### Local Fieldmark website

From PowerShell:

```powershell
Set-Location "F:\Python Code\Bird Detector"
.\.venv\Scripts\Activate.ps1
python webapp.py
```

Open the address printed by the command. The local Starlette interface uses the PyTorch checkpoint and can use CUDA.

### Streamlit interface

```powershell
Set-Location "F:\Python Code\Bird Detector"
.\.venv\Scripts\Activate.ps1
streamlit run app.py
```

### Command-line prediction

```powershell
python -m src.predict --image "F:\path\to\bird.jpg"
```

## Fresh setup

Python 3.11 or newer is recommended.

```powershell
Set-Location "F:\Python Code\Bird Detector"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
```

The large training dataset and PyTorch checkpoints are intentionally ignored by Git. The optimized 18 MB browser model is versioned at `web/model/fieldmark.onnx` so the public site can make real predictions.

## Project layout

```text
Bird Detector/
├── app.py Streamlit interface
├── webapp.py Local Starlette interface and prediction API
├── config/config.yaml Paths and training configuration
├── src/ Dataset, model, training, evaluation, inference
├── scripts/export_browser_model.py PyTorch-to-ONNX export and parity validation
├── web/ Static GitHub Pages application
│ ├── model/ ONNX model and class metadata
│ └── static/ CSS, JavaScript, and icon assets
└── .github/workflows/pages.yml GitHub Pages deployment
```

## Browser inference architecture

1. GitHub Pages serves static HTML, CSS, JavaScript, model metadata, and `fieldmark.onnx`.
2. ONNX Runtime Web loads the model once into browser memory.
3. Canvas applies the same resize, center-crop, RGB conversion, and ImageNet normalization used during Python evaluation.
4. EfficientNet-B0 generates logits for all 555 classes.
5. Temperature scaling calibrates the probabilities.
6. Fieldmark returns the ranked alternatives, entropy, top-two margin, and uncertainty verdict.

No backend is required for the Pages site. The original local Python interfaces remain available for CUDA inference, training, and evaluation.

## Re-export the browser model

Install the export dependencies, then run the reproducible exporter:

```powershell
python -m pip install -r requirements-export.txt
python scripts/export_browser_model.py
```

The exporter checks the ONNX graph and compares deterministic ONNX Runtime logits against the PyTorch checkpoint before writing metadata.

## Train and continue training

Start training:

```powershell
python -m src.train --config config\config.yaml
```

Continue from a checkpoint:

```powershell
python -m src.train --config config\config.yaml --resume models\checkpoints\last.pt
```

Evaluate the best model:

```powershell
python -m src.evaluate --config config\config.yaml
```

## Validate before publishing

```powershell
python scripts\check_static_site.py
python scripts\check_theme_contrast.py
node --check web\static\js\browser-inference.js
node --check web\static\js\app.js
pytest -q
```

Pushes to `main` deploy `web/` through the GitHub Pages workflow.

## Dataset and responsible use

NABirds is a fine-grained North American bird image dataset assembled with the Cornell Lab of Ornithology and collaborators. Download it from the [official NABirds page](https://dl.allaboutbirds.org/nabirds), review the [NABirds / Merlin terms](https://dl.allaboutbirds.org/merlin-computer-vision-terms-of-use), and preserve the supplied attribution and citation materials.

This repository does not redistribute NABirds photographs or metadata. The classifier is closed-set: it can only name classes it learned. Low confidence can mean an unsupported class, poor lighting, an unusual pose, background shift, or an ordinary model error; it is not a scientifically validated unknown-species detector.
Loading
Loading