Brute-force blueprint labeling pipeline: 3 YOLO models × 4 zoom levels × 820 tiles per sheet, with Label Studio integration for human-in-the-loop annotation correction.
Self-hosted, open-source, Docker-first.
An experiment in building a (mostly) automated data-labeling engine for object detection and classification.
HDED proposes a strategy for sorting false-positives, and finding false-negatives, with minimal HITL.
The core design thesis: brute force converts search into classification. Rather than trying to detect objects cleanly the first time, HDED over-detects everything (maximum recall) then lets human annotators (or downstream classifiers) filter false positives — because filtering is a classification problem (easy) while finding missed objects is a search problem (hard).
Pipeline:
- Rasterize PDF at 300 DPI → PNG per sheet
- Tile each sheet into a 3^L grid at L zoom levels (default 4 levels = 820 tiles)
- Run 3 YOLO models per tile (precise, medium, primitive)
- Ensemble + fuse detections with weighted box fusion
- Auto-push pre-annotated projects to Label Studio for human review
- Export corrected annotations → retrain loop
git clone <this-repo> hded
cd hded
./setup.sh # interactive .env generation (creates secrets, directories)
./start.sh # starts docker compose stack (auto-detects GPU)
./set_root_admin.sh # creates first admin user (choose option 1)Then visit http://localhost:8000 and log in with the admin credentials you just created.
Upload a PDF → pipeline runs → LS project auto-created with pre-annotations.
┌────────────────────────────────────────────────────────┐
│ HDED app (FastAPI, port 8000) │
│ ├─ routes/ Thin HTTP wrappers │
│ ├─ services/ Business logic (pipeline, LS, SageMaker)│
│ ├─ pipeline/ Detection + classifier core │
│ └─ master/ SageMaker orchestration (optional) │
└────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌────────────────┐ ┌──────────────────────┐
│ Label Studio │ │ AWS SageMaker │
│ (4 containers, │ │ (optional, GPU tiers │
│ 1 per user) │ │ for large batches) │
└────────────────┘ └──────────────────────┘
│
▼
┌────────────────┐
│ Postgres │
│ (shared, 4 DBs)│
└────────────────┘
Max scale: ~10 concurrent users on single EC2. For larger deployments see docs/LIMITS.md.
- User uploads blueprint (PDF/PNG/JPG/TIFF)
- Pipeline detects symbols → saves per-sheet LS JSON with pre-annotations
- App auto-creates LS project in user's assigned container (ports 8081-8084)
- User clicks "Open in Label Studio" → SSO redirect to pre-populated project
- User corrects boxes, adds missed symbols, removes false positives
- Export from LS as YOLO format → feeds back into
classifier_bootstrapretraining
Manual re-push: On the results page, "Push to Label Studio" button re-pushes predictions (useful for retries or pushing older jobs).
For large-batch processing, HDED supports AWS SageMaker with 3 GPU tiers:
| Tier | Fleet | Use case | Cost (full-fleet/hr) |
|---|---|---|---|
| Scrooge McDuck | 40× g4dn.xlarge (T4) | Budget, cheapest | ~$30 |
| Even Steven | 5× g5.12xl + 20× g4dn | Balanced production | ~$51 |
| IDGAF | Full multi-fleet | Rush jobs | ~$220 |
Distribution is proportional to GPU power: 5 pages → 7 instances, 20 pages → 12 instances, 400 pages → 37 instances across 4 fleets.
Setup:
./setup_aws.sh # prompts for BUCKET_PREFIX, creates S3/ECR/IAM
./deploy.sh --all # builds SageMaker image + deploys app to EC2Requires: AWS CLI configured, Docker, SageMaker service quotas for g4dn/g5 instance families.
Copy .env.example to .env and fill in. Key vars:
| Variable | Purpose |
|---|---|
HDED_HOST |
Public URL of HDED app (used for LS image serving) |
HDED_SESSION_SECRET |
Random 64-char hex for cookie signing |
HDED_LS_IMAGE_HOST |
URL LS containers use to reach HDED (e.g. host.docker.internal:8000 on Mac) |
POSTGRES_PASSWORD |
Postgres password for LS databases |
HDED_RAW_BUCKET / HDED_RESULTS_BUCKET / HDED_MODELS_BUCKET |
S3 buckets (if using SageMaker) |
HDED_ECR_IMAGE |
ECR URI of SageMaker pipeline image |
HDED_SAGEMAKER_ROLE |
IAM role ARN with S3+ECR permissions |
See .env.example for all options.
hded_classifier_2/
├── app/
│ ├── auth.py # Session cookie auth (SQLite-backed)
│ ├── main.py # FastAPI factory, route registration
│ ├── routes/ # HTTP handlers (thin)
│ ├── services/ # Business logic
│ ├── templates/ # Jinja2 HTML (vim-themed)
│ └── static/css/vim.css # Single-file theme
├── pipeline/
│ ├── config.py # Unified dataclass config from config.yaml
│ ├── hded/ # Detection pipeline (tile, detect, fuse)
│ └── classifier/ # YOLO model inference
├── master/ # SageMaker orchestration
├── admin_cli/ # TUI for user/config management
├── config.yaml # Model weights + ensemble config
├── gpu_limits.yaml # Rate limits + allowed GPU tiers
├── docker-compose.yml # App + Postgres + LS
├── docker-compose.ls.yml # 4× LS containers for multi-user
├── docker-compose.prod.yml # Caddy HTTPS overlay
├── setup.sh # Interactive .env generator
├── setup_aws.sh # S3/ECR/IAM provisioning
├── deploy.sh # Rsync to EC2 + docker compose up
└── sync_ls_users.py # Seed LS accounts from HDED users
- classifier_bootstrap — CLI tool for bootstrapping YOLO classifier training data from HDED results (closes the active-learning loop)
- Label Studio — the annotation UI this integrates with (heartex/label-studio)
MIT — see LICENSE file.
This is a small-team tool and is not designed to scale past ~10 concurrent users. PRs welcome for:
- Bug fixes
- Documentation
- Pipeline improvements
- Additional GPU/cloud backends
Not accepting PRs for: horizontal-scaling refactors (Kubernetes, multi-region), Label Studio alternatives.
Current: v2.0.0 — docker-compose + FastAPI + vim-themed UI, LS multi-container integration, optional SageMaker GPU tiers, agentic JSON API.