GPU-accelerated edge detection evaluation (ODS/OIS/AP/R50)
Project description
edgeval.cu
GPU-accelerated edge detection evaluation
20 min → 1.6 min on BSDS500 | 12.8× faster than CPU
What Problem Does This Solve?
Evaluating an edge detection model on BSDS500 means solving ~99,000 independent assignment problems — matching every predicted edge pixel to every ground truth pixel, at 99 thresholds, across 5 human annotations, for 200 images.
The standard CPU pipeline takes 20 minutes. That's fine for a final paper. It's terrible when you're training and want to check your model's progress every few epochs.
edgeval.cu brings it down to 1.6 minutes — fast enough to run every epoch without slowing down training.
How It Works
Edge matching is a minimum-cost bipartite assignment problem:
Predicted edges ──→ Match (cost = distance) ←── Ground truth edges
Or pay outlier penalty
We solve it with the Auction Algorithm (Bertsekas, 1979), perfectly suited for GPU parallelism. Each predicted pixel iteratively bids on ground truth pixels; the highest bidder wins each round. Repeat until convergence.
flowchart LR
subgraph Input["📥 Input"]
EP["Edge Map\n.png"]
GT["Ground Truth\n.mat"]
end
subgraph Pre["🎯 Preprocessing"]
THR["99 Thresholds"]
THIN["Zhang-Suen\nThinning"]
end
subgraph Graph["🔗 Graph Construction"]
EDGE["CUDA Edge Builder\nSingle Kernel Launch"]
SORT["GPU Sort + Split\nby Annotator"]
end
subgraph Solve["⚔️ Solver"]
AUCT["Auction Algorithm\nε-Scaling 8→0\n485 problems/parallel"]
end
subgraph Out["📊 Output"]
ODS["ODS · OIS"]
AP["AP · R50"]
end
EP --> THR --> THIN --> EDGE
GT -.-> EDGE
EDGE --> SORT --> AUCT --> ODS
AUCT --> AP
ε-Scaling Strategy
ε = 8 → coarse solution in ~100 rounds
ε = 4 → refine in ~200 rounds
ε = 2 → refine in ~400 rounds
ε = 1 → refine in ~500 rounds
ε = 0 → exact optimality in ~300 rounds ← tuned!
Most problems converge within 200-300 rounds at ε=0. We detect convergence by counting consecutive no-change rounds — avoiding the trap of mistaking temporary bid-stalemates for convergence.
Two Modes for Two Needs
| Simple | Extended | |
|---|---|---|
| Graph | Bipartite, real edges only | n×n, kOfN + diagonal overlay |
| Speed | 0.47s/img | ~5.7s/img |
| ΔODS vs CSA reference | +0.003 | <0.001 |
| Use case | Training monitoring | Exact CSA-compatible evaluation |
Performance
BSDS500 — 200 images, 99 thresholds, RTX 4090
| CPU CSA (MATLAB) | GPU Simple | Speedup | |
|---|---|---|---|
| Per image | ~6s | 0.47s | 12.8× |
| Full dataset | ~20 min | 1.6 min | 12.8× |
| ODS accuracy | 0 (reference) | Δ = +0.003 | Stable |
Pipeline Breakdown
GPU Thinning ████████░░░░░░░░░░░░ 0.12s (25%)
Edge Builder █░░░░░░░░░░░░░░░░░░░ 0.02s ( 4%)
GPU Sort+Split █████░░░░░░░░░░░░░░░ 0.08s (17%)
Problem Build ██░░░░░░░░░░░░░░░░░░ 0.04s ( 9%)
Auction Solve ██████████░░░░░░░░░░ 0.14s (30%)
Overhead █████░░░░░░░░░░░░░░░ 0.07s (15%)
────────────────────
TOTAL 0.47s
Detailed breakdown and configuration sweep: docs/benchmarks.md
Quick Start
pip install edgeval
Requires Python 3.8+, PyTorch, CUDA toolkit (nvcc), NumPy, SciPy, OpenCV, tqdm, click.
CUDA kernels are compiled at install time — your machine needs a GPU and nvcc. If compilation fails:
# Debian/Ubuntu
sudo apt install nvidia-cuda-toolkit build-essential
# Verify nvcc
nvcc --version
# CLI — one command
edgeval eval results/ --gpu --dataset BSDS
# Python API — one function call
from edgeval_cu.eval import gpu_edges_eval_img
info, _ = gpu_edges_eval_img(edge_map, "GT/100007.mat", thrs=99, mode='simple')
Accuracy
The +0.003 ODS bias comes from the Auction solver's atomicMax tie-breaking. It is systematic and stable across images. In practice:
- Training monitoring: GPU simple mode — ~0.003 won't affect your model ranking
- Final evaluation: CPU CSA mode — exact match to MATLAB reference
| Image | GPU ODS | CSA ODS | Δ |
|---|---|---|---|
| 100007 | 0.8601 | 0.8570 | +0.0031 |
| 100039 | 0.7358 | 0.7347 | +0.0011 |
| 100099 | 0.8091 | 0.8056 | +0.0035 |
| 10081 | 0.7655 | 0.7631 | +0.0024 |
| 101027 | 0.8749 | 0.8724 | +0.0026 |
Project Structure
edgeval.cu/
├── edgeval_cu/ # Package
│ ├── eval.py # Main pipeline — gpu_edges_eval_img(), gpu_edges_eval_dir()
│ ├── auction.py # GPU Auction solver
│ ├── metrics.py # ODS/OIS/AP/R50 computation
│ ├── csa.py # CPU CSA solver (exact reference)
│ ├── nms_thin.py # Zhang-Suen thinning LUTs
│ ├── cli.py # CLI: edgeval eval / show / nms
│ ├── _dummy.c # Triggers build_ext during pip install
│ └── cuda/ # CUDA kernels
│ ├── auction_kernel.cu # ε-Scaling Auction solver
│ ├── edge_builder.cu # Fused edge builder
│ └── Makefile
├── cxx/ # CPU CSA C++ solver
│ └── lib/solve_csa.so
├── docs/
│ ├── benchmarks.md # Detailed benchmarks & config sweep
│ └── optimization.md # 8-stage optimization journey (5.7s→0.47s)
├── setup.py # Build script with CUDA compilation
└── README.md
Optimization Journey
We went from 5.7s to 0.47s per image — a 12× within-GPU speedup — through 8 systematic optimizations:
| # | What | Speedup | Key Insight |
|---|---|---|---|
| 1 | Simple bipartite graph | 4.9× | kOfN adds edges but not accuracy |
| 2 | Fused CUDA edge builder | 1.2× | Merge cdist+mask+nonzero into 1 kernel |
| 3 | GPU batched thinning | 1.0× | 99 masks in one conv2d batch |
| 4 | Consecutive stall detection | 1.3× | Wait for real convergence, not first silence |
| 5 | GPU annotator split | 1.3× | Sort by annotator on GPU, download once |
| 6 | GPU nonzero | 1.03× | Keep masks on GPU, extract coords there |
| 7 | Tuned ITERS_EPS0 | 1.2× | 500 iterations is plenty — system sweep proves it |
| 8 | Directory restructure | — | Flat modules, clean imports |
Details: docs/optimization.md
References
- HED Evaluation (MATLAB) — Original edge detection evaluation reference
- edge-eval-python — Python CSA port
- Extended BSDS Benchmark — C++ CSA solver
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file edgeval-0.1.1.tar.gz.
File metadata
- Download URL: edgeval-0.1.1.tar.gz
- Upload date:
- Size: 747.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f75df4a03940f4438072051a42f0a5809f0e73cec7c918cd449a18abf1ac9fc1
|
|
| MD5 |
6d0778a0af39db8091677fe8dc4e55f9
|
|
| BLAKE2b-256 |
996bb275060182793b22d12284b9bf50238b3ea65aff7a69a302b1f5eb0e8bc8
|