Skip to main content

GPU-accelerated edge detection evaluation (ODS/OIS/AP/R50)

Project description

Python CUDA License

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


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

edgeval-0.1.1.tar.gz (747.9 kB view details)

Uploaded Source

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

Hashes for edgeval-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f75df4a03940f4438072051a42f0a5809f0e73cec7c918cd449a18abf1ac9fc1
MD5 6d0778a0af39db8091677fe8dc4e55f9
BLAKE2b-256 996bb275060182793b22d12284b9bf50238b3ea65aff7a69a302b1f5eb0e8bc8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page