Detector-independent bounding-box and instance-mask evaluation for MoonBit
| Need | Start here |
|---|---|
| Evaluate in MoonBit code | Install and call the library (moon add python123-ops/moondeteval@0.2.0) |
| Evaluate one or two prediction sets from files | Run the source examples (moon run cli --target native -- --help) |
| Inspect an existing JSON report | Read-only browser viewer |
| Compare more than two prediction sets | Batch evaluator |
///|
let detection = @moondeteval.CocoRle::new(3, 4, [1, 2, 2, 3, 4])
///|
let truth = @moondeteval.CocoRle::new(3, 4, [0, 3, 2, 1, 6])
// detection.area() == 5; detection.iou(truth) == 0.5
// detection.crowd_iou(truth) == 0.6
///|
let compressed = @moondeteval.parse_coco_rle(
"{\"size\":[3,4],\"counts\":\"032N4\"}",
)
// compressed.to_compressed() == "032N4"; detection.iou(compressed) == 0.5///|
let masks = @moondeteval.parse_coco_mask_dataset(ground_truth_json)
///|
let predictions = @moondeteval.parse_coco_mask_detections(detections_json)
///|
let report = @moondeteval.evaluate_masks(masks, predictions)
///|
let comparison = @moondeteval.compare_mask_predictions(
masks, predictions, other_predictions,
)moon run cli --target native -- examples/mask-ground-truth.json examples/mask-baseline.json --iou-type segm --compare examples/mask-candidate.json --diagnostics --image-ranking --pr-curves --min-ap50 1moon run cli --target native -- examples/polygon-ground-truth.json examples/polygon-detections.json --iou-type segm --compare examples/mask-candidate.json --pr-curves --image-ranking --min-ap50 1///|
fn main {
let box = @moondeteval.Box::from_xywh(0.0, 0.0, 10.0, 10.0) catch {
error => abort(error.message())
}
let dataset = @moondeteval.Dataset::new(
[@moondeteval.Image::new(1, 20, 20)],
[@moondeteval.Category::new(7, "object")],
[@moondeteval.GroundTruth::new(9L, 1, 7, box, area=100.0)],
) catch {
error => abort(error.message())
}
let prediction = @moondeteval.Detection::new(0, 1, 7, box, 0.9) catch {
error => abort(error.message())
}
let report = @moondeteval.evaluate(dataset, [prediction]) catch {
error => abort(error.message())
}
println("AP50=\{report.summary().ap50()}")
}python examples/batch_eval.py --ground-truth examples/compare-ground-truth.json --model baseline examples/compare-baseline.json --model candidate examples/compare-candidate.json --baseline baseline --image-ranking --pr-curves --output-dir ../moondeteval-batch-resultspython examples/batch_eval.py --ground-truth examples/polygon-ground-truth.json --iou-type segm --model polygon examples/polygon-detections.json --model rle examples/mask-candidate.json --model miss examples/mask-baseline.json --baseline polygon --diagnostics --image-ranking --pr-curves --output-dir ../moondeteval-segm-batch-results--min-metric METRIC=VALUE
--max-metric-drop METRIC=VALUE
--min-class-metric CATEGORY:METRIC=VALUE
--max-class-drop CATEGORY:METRIC=VALUE
--undefined-gate fail|skipmoon run cli --target native -- examples/compare-ground-truth.json examples/compare-baseline.json --compare examples/compare-candidate.json --max-metric-drop ap50=0.1 --min-metric ar100=0.5 --output ../regression.report.jsonpython examples/batch_eval.py --ground-truth examples/compare-ground-truth.json --model baseline examples/compare-baseline.json --model candidate examples/compare-candidate.json --model unchanged examples/compare-baseline.json --baseline baseline --max-metric-drop ap50=0.1 --output-dir ../gated-batch{"format_version":"1","undefined_policy":"fail","rules":[{"kind":"max_drop","metric":"ap50","threshold":0.1},{"kind":"minimum","metric":"ar100","threshold":0.5}]}moon run cli --target native -- --check-gate-policy examples/regression-policy.json
moon run cli --target native -- examples/compare-ground-truth.json examples/compare-baseline.json --compare examples/compare-candidate.json --gate-policy examples/regression-policy.json
python examples/batch_eval.py --ground-truth examples/compare-ground-truth.json --model baseline examples/compare-baseline.json --model candidate examples/compare-candidate.json --model unchanged examples/compare-baseline.json --baseline baseline --gate-policy examples/regression-policy.json --output-dir ../policy-batchmoon run cli --target native -- examples/ground-truth.json examples/detections.json
moon run cli --target native -- examples/ground-truth.json examples/detections.json --diagnostics --min-ap50 0.8
moon run cli --target native -- examples/ground-truth.json examples/detections.json --output report.json
python examples/compare_demo.py
python examples/showcase_demo.py{"schema_version":"0.1.0","summary":{"ap":1,"ap50":1,"ap75":1,"ap_small":1,"ap_medium":-1,"ap_large":-1,"ar1":0,"ar10":1,"ar100":1,"ar_small":1,"ar_medium":-1,"ar_large":-1}}moon run cli --target native -- examples/compare-ground-truth.json examples/compare-baseline.json --compare examples/compare-candidate.json --diagnostics
moon run cli --target native -- examples/compare-ground-truth.json examples/compare-baseline.json --compare examples/compare-candidate.json --image-ranking
moon run cli --target native -- examples/compare-ground-truth.json examples/compare-baseline.json --compare examples/compare-candidate.json --pr-curves{
"category_ids": [42, 7],
"images": [
{"image_id": 12, "file": "labels/image-12.txt"},
{"image_id": 9, "file": "labels/image-9.txt"}
]
}moon run cli --target native -- examples/yolo/ground-truth.json examples/yolo/manifest.json --prediction-format yolo --diagnostics
moon run cli --target native -- examples/yolo/ground-truth.json examples/yolo/detections.json --compare examples/yolo/manifest.json --compare-format yolo --diagnostics
moon run cli --target native -- examples/yolo/ground-truth.json examples/yolo/manifest.json --prediction-format yolo --min-ap50 0.8 --output failed-gate.jsonmoon build cli --target native --release
# Replace the executable path with the build artifact on your platform.
_build/native/release/build/cli/cli.exe ground-truth.json predictions.json --iou-type segm --max-input-bytes 536870912 --max-total-input-bytes 1073741824 --max-records 5000000 --max-iou-cache-pairs 262144 --timings --output report.json///|
let dataset = @moondeteval.parse_coco_dataset(ground_truth_json)
///|
let predictions = @moondeteval.parse_coco_detections(detections_json)
///|
let report = @moondeteval.evaluate(dataset, predictions)
///|
let ap50 = report.summary().ap50()
///|
let config = @moondeteval.EvalConfig::new([0.5, 0.75], include_diagnostics=true)
///|
let custom = @moondeteval.evaluate_with_config(dataset, predictions, config)
///|
let comparison = @moondeteval.compare_predictions(
dataset, predictions, other_predictions,
)
///|
let ap50_change = comparison.metrics()[1].delta()
///|
let yolo_predictions = @moondeteval.parse_yolo_detections(
yolo_txt,
dataset,
9,
[42, 7],
first_detection_id=100,
)
///|
let manifest = @moondeteval.parse_yolo_manifest(manifest_json, dataset)
///|
let retained = report.counts().evaluated_detections()
///|
let warnings = report.quality_warnings()
///|
let explicit_ignore = @moondeteval.EvalConfig::new(
[0.5],
ignore_policy="respect_explicit",
)moon fmt --check
moon check --target all --deny-warn
moon test --target all --deny-warn
python -m unittest examples/scale_test.py -v
python examples/compare_demo.py
python examples/yolo_manifest_demo.py
python -m pip install numpy==1.26.4 pycocotools==2.0.7
python reference_compare.py
python examples/mask_rle_reference.py
python examples/mask_ap_reference.py
python examples/polygon_reference.pypub(all) suberror EvalError {
InvalidBox(String)
InvalidInput(String)
InvalidConfig(String)
} derive(Debug)pub struct ComparisonReport {
schema_version : String
baseline : EvaluationReport
candidate : EvaluationReport
metrics : Array[MetricChange]
classes : Array[ClassComparison]
image_changes : Array[ImageChange]
} derive(ToJson)fn ComparisonReport::check_gates(self : ComparisonReport, policy : GatePolicy) -> GateReport raise EvalErrorfn EvalConfig::new(iou_thresholds : Array[Double], include_diagnostics? : Bool, ignore_policy? : String, include_image_summaries? : Bool, include_pr_curves? : Bool) -> EvalConfig raise EvalErrorpub struct EvaluationReport {
schema_version : String
evaluator_version : String
iou_type : String
config : EvalConfig
counts : InputCounts
summary : Metrics
classes : Array[ClassMetrics]
diagnostics : Array[MatchDiagnostic]
image_summaries : Array[ImageSummary]
recall_thresholds : Array[Double]
pr_curves : Array[PrecisionRecallCurve]
quality_warnings : Array[QualityWarning]
}impl ToJson for EvaluationReportfn EvaluationReport::check_gates(self : EvaluationReport, policy : GatePolicy) -> GateReport raise EvalErrorpub struct GateCheck {
kind : String
metric : String
category_id : Int?
threshold : Double
baseline : Double?
candidate : Double?
drop : Double?
status : String
reason : String
}impl ToJson for GatePolicyfn GatePolicy::new(rules : Array[GateRule], undefined_policy? : String) -> GatePolicy raise EvalErrorpub struct GateRule {
kind : String
metric : String
threshold : Double
category_id : Int?
} derive(ToJson)fn GroundTruth::new(id : Int64, image_id : Int, category_id : Int, bbox : Box, area~ : Double, iscrowd? : Bool, ignore? : Bool) -> GroundTruth raise EvalErrorpub struct ImageChange {
image_id : Int
baseline_errors : Int
candidate_errors : Int
error_delta : Int
} derive(ToJson)pub struct ImageSummary {
image_id : Int
tp : Int
fp : Int
fn_count : Int
ignored : Int
} derive(ToJson)pub struct InputCounts {
images : Int
categories : Int
ground_truths : Int
detections : Int
evaluated_detections : Int
} derive(ToJson)fn MaskDataset::new(images : Array[Image], categories : Array[Category], truths : Array[MaskGroundTruth]) -> MaskDataset raise EvalErrorfn MaskDetection::new(id : Int, image_id : Int, category_id : Int, mask : CocoRle, score : Double) -> MaskDetection raise EvalErrorfn MaskGroundTruth::new(id : Int64, image_id : Int, category_id : Int, mask : CocoRle, area~ : Double, iscrowd? : Bool, ignore? : Bool) -> MaskGroundTruth raise EvalErrorpub struct MatchDiagnostic {
iou_threshold : Double
image_id : Int
category_id : Int
detection_id : Int?
ground_truth_id : Int64?
iou : Double
status : String
reason : String
}impl ToJson for MatchDiagnosticpub struct MetricChange {
name : String
baseline : Double?
candidate : Double?
delta : Double?
}impl ToJson for MetricChangepub struct QualityWarning {
source : String
record_id : Int64
image_id : Int
category_id : Int
kind : String
}impl ToJson for QualityWarningpub struct YoloFile {
image_id : Int
file : String
}fn compare_mask_predictions(dataset : MaskDataset, baseline : Array[MaskDetection], candidate : Array[MaskDetection]) -> ComparisonReport raise EvalErrorfn compare_mask_predictions_with_config(dataset : MaskDataset, baseline : Array[MaskDetection], candidate : Array[MaskDetection], config : EvalConfig, max_iou_cache_pairs? : Int) -> ComparisonReport raise EvalErrorfn compare_predictions_with_config(dataset : Dataset, baseline : Array[Detection], candidate : Array[Detection], config : EvalConfig) -> ComparisonReport raise EvalErrorfn evaluate_masks(dataset : MaskDataset, predictions : Array[MaskDetection]) -> EvaluationReport raise EvalErrorfn evaluate_masks_with_config(dataset : MaskDataset, predictions : Array[MaskDetection], config : EvalConfig, max_iou_cache_pairs? : Int) -> EvaluationReport raise EvalErrorfn evaluate_with_config(dataset : Dataset, predictions : Array[Detection], config : EvalConfig) -> EvaluationReport raise EvalErrorfn evaluate_with_diagnostics(dataset : Dataset, predictions : Array[Detection]) -> EvaluationReport raise EvalErrorfn parse_coco_mask_detections_with_dataset(source : String, dataset : MaskDataset) -> Array[MaskDetection] raise EvalErrorInstall
Download zipDetector-independent bounding-box and instance-mask evaluation for MoonBit