feat(perception): add RF-DETR upstream parity gate

This commit is contained in:
DCCONSTRUCTIONS
2026-08-26 00:45:17 +03:00
parent be079bf18f
commit 62c8ed421a
4 changed files with 1066 additions and 0 deletions
@@ -0,0 +1,50 @@
{
"schema_version": "missioncore.m48t-upstream-parity-profile/v1",
"profile_id": "m48t-rf-detr-large-upstream-coco-parity/v1",
"model": {
"package": "rfdetr",
"package_version": "1.9.4",
"upstream_revision": "9b009fa928d6218320439803d1da01869a85c072",
"checkpoint": "rf-detr-large-2026.pth",
"checkpoint_sha256": "0f4e20e19a99c0f8a62b5685f57f6c8b5c371c59081feda6752a0561a79ccf38",
"resolution": [704, 704],
"maximum_query_class_pairs": 300
},
"dataset": {
"dataset_id": "coco-2017-val",
"image_count": 5000,
"annotations_sha256": "e8c7f7908f1d7278341fae127d0da654f102f11bd7b21d8aeefa635b8c810b6f",
"evaluation": "pycocotools.COCOeval/bbox",
"all_categories": true,
"official_crowd_ignore": true,
"custom_area_filtering": false
},
"providers": {
"pytorch": {
"preprocessing": "official-rfdetr-predict-direct-original-to-704",
"dtype": "float16",
"confidence_prefilter": 0.0
},
"tensorrt": {
"provider_id": "triton-rf-detr-large-coco-risk-fp16-shadow/v0",
"engine_sha256": "986399ce706b7380472cf5e473232249fed6e628971d8007f6609e83128d46b8",
"preprocessing": "official-rfdetr-direct-original-to-704",
"confidence_prefilter": 0.0
}
},
"published_reference": {
"coco_ap_50_95": 0.565,
"coco_ap_50": 0.751,
"maximum_absolute_reproduction_delta": 0.01
},
"parity_gates": {
"maximum_absolute_ap_50_95_delta": 0.005,
"maximum_absolute_ap_50_delta": 0.005
},
"authority": {
"candidate_accepted": false,
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false
}
}
@@ -0,0 +1,618 @@
#!/usr/bin/env python3
"""Reproduce official RF-DETR COCO quality and compare the pinned TensorRT engine."""
from __future__ import annotations
import argparse
import contextlib
import gc
import gzip
import hashlib
import importlib.metadata
import io
import json
import math
import statistics
import time
from collections.abc import Iterable, Mapping
from pathlib import Path
from typing import Any, Final
import numpy as np
from PIL import Image
from k1link.perception.rf_detr_object_detector import (
COCO_SPARSE_IDS,
TritonRfDetrHttpInferenceBackend,
)
PROFILE_SCHEMA: Final = "missioncore.m48t-upstream-parity-profile/v1"
REPORT_SCHEMA: Final = "missioncore.m48t-upstream-parity-report/v1"
PROGRESS_SCHEMA: Final = "missioncore.m48t-upstream-parity-progress/v1"
FALSE_AUTHORITY: Final = {
"candidate_accepted": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
}
COCO_METRIC_NAMES: Final = (
"ap_50_95",
"ap_50",
"ap_75",
"ap_small",
"ap_medium",
"ap_large",
"ar_1",
"ar_10",
"ar_100",
"ar_small",
"ar_medium",
"ar_large",
)
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--profile", type=Path, required=True)
parser.add_argument("--annotations", type=Path, required=True)
parser.add_argument("--images-root", type=Path, required=True)
parser.add_argument("--checkpoint", type=Path, required=True)
parser.add_argument("--triton-origin", default="http://127.0.0.1:8000")
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--pytorch-predictions", type=Path, required=True)
parser.add_argument("--tensorrt-predictions", type=Path, required=True)
parser.add_argument("--progress", type=Path, required=True)
parser.add_argument("--runtime-image", required=True)
parser.add_argument("--maximum-images", type=int, default=0)
return parser.parse_args()
def main() -> None:
arguments = parse_arguments()
profile, profile_sha256 = load_profile(arguments.profile)
if arguments.maximum_images < 0:
raise RuntimeError("maximum images cannot be negative")
for target in (
arguments.output,
arguments.pytorch_predictions,
arguments.tensorrt_predictions,
arguments.progress,
):
if target.exists():
raise RuntimeError(f"output already exists: {target}")
target.parent.mkdir(parents=True, exist_ok=True)
model_profile = _object(profile.get("model"), "model")
dataset_profile = _object(profile.get("dataset"), "dataset")
annotations_sha256 = sha256_path(arguments.annotations)
if annotations_sha256 != _string(dataset_profile, "annotations_sha256"):
raise RuntimeError("COCO annotations SHA-256 changed")
if sha256_path(arguments.checkpoint) != _string(model_profile, "checkpoint_sha256"):
raise RuntimeError("RF-DETR checkpoint SHA-256 changed")
if importlib.metadata.version("rfdetr") != _string(model_profile, "package_version"):
raise RuntimeError("RF-DETR package version changed")
coco_document = _object(json.loads(arguments.annotations.read_text("utf-8")), "COCO")
images = load_coco_images(coco_document)
expected_count = _integer(dataset_profile, "image_count")
if len(images) != expected_count:
raise RuntimeError("COCO image count changed")
if arguments.maximum_images:
images = images[: arguments.maximum_images]
if not images:
raise RuntimeError("COCO parity selection is empty")
category_ids_by_name = load_category_ids_by_name(coco_document)
image_ids = [_integer(item, "id") for item in images]
full_admission_run = len(images) == expected_count
started_at = time.time_ns()
with arguments.progress.open("x", encoding="utf-8") as progress:
pytorch_rows, pytorch_timing = run_pytorch_predictions(
images=images,
images_root=arguments.images_root,
checkpoint=arguments.checkpoint,
category_ids_by_name=category_ids_by_name,
progress=progress,
)
write_gzip_jsonl(arguments.pytorch_predictions, pytorch_rows)
pytorch_metrics, pytorch_summary = evaluate_coco(
annotations=arguments.annotations,
predictions=pytorch_rows,
image_ids=image_ids,
)
pytorch_count = len(pytorch_rows)
del pytorch_rows
gc.collect()
tensorrt_rows, tensorrt_timing = run_tensorrt_predictions(
images=images,
images_root=arguments.images_root,
triton_origin=arguments.triton_origin,
progress=progress,
)
write_gzip_jsonl(arguments.tensorrt_predictions, tensorrt_rows)
tensorrt_metrics, tensorrt_summary = evaluate_coco(
annotations=arguments.annotations,
predictions=tensorrt_rows,
image_ids=image_ids,
)
tensorrt_count = len(tensorrt_rows)
del tensorrt_rows
gc.collect()
decision = build_parity_decision(
profile=profile,
pytorch_metrics=pytorch_metrics,
tensorrt_metrics=tensorrt_metrics,
full_admission_run=full_admission_run,
)
completed_at = time.time_ns()
report: dict[str, object] = {
"schema_version": REPORT_SCHEMA,
"profile_id": _string(profile, "profile_id"),
"dataset": {
"dataset_id": _string(dataset_profile, "dataset_id"),
"image_count": len(images),
"full_admission_run": full_admission_run,
"all_categories": True,
"official_crowd_ignore": True,
"custom_area_filtering": False,
"confidence_prefilter": 0.0,
},
"providers": {
"pytorch": {
"prediction_count": pytorch_count,
"metrics": pytorch_metrics,
"coco_summary": pytorch_summary,
"timing": pytorch_timing,
},
"tensorrt": {
"prediction_count": tensorrt_count,
"metrics": tensorrt_metrics,
"coco_summary": tensorrt_summary,
"timing": tensorrt_timing,
},
},
"decision": decision,
"execution": {
"worker": "DESKTOP-OPJ8J04",
"runtime_image": arguments.runtime_image,
"started_at_unix_ns": started_at,
"completed_at_unix_ns": completed_at,
"duration_seconds": (completed_at - started_at) / 1_000_000_000,
"packages": package_versions(
("rfdetr", "torch", "torchvision", "numpy", "pycocotools", "tritonclient")
),
},
"provenance": {
"profile_sha256": profile_sha256,
"annotations_sha256": annotations_sha256,
"checkpoint_sha256": sha256_path(arguments.checkpoint),
"pytorch_predictions_sha256": sha256_path(arguments.pytorch_predictions),
"tensorrt_predictions_sha256": sha256_path(arguments.tensorrt_predictions),
},
"authority": FALSE_AUTHORITY,
}
report["report_identity_sha256"] = hashlib.sha256(canonical_json(report).encode()).hexdigest()
arguments.output.write_text(canonical_json(report) + "\n", "utf-8")
print(
canonical_json(
{
"result": str(arguments.output),
"image_count": len(images),
"pytorch_ap_50_95": pytorch_metrics["ap_50_95"],
"tensorrt_ap_50_95": tensorrt_metrics["ap_50_95"],
"diagnosis": decision["diagnosis"],
"passed": decision["passed"],
}
),
flush=True,
)
def load_profile(path: Path) -> tuple[dict[str, object], str]:
raw = path.read_bytes()
profile = _object(json.loads(raw), "profile")
if profile.get("schema_version") != PROFILE_SCHEMA:
raise RuntimeError("upstream parity profile schema changed")
if _object(profile.get("authority"), "authority") != FALSE_AUTHORITY:
raise RuntimeError("upstream parity authority changed")
return profile, hashlib.sha256(raw).hexdigest()
def load_coco_images(document: Mapping[str, object]) -> list[dict[str, object]]:
values = document.get("images")
if not isinstance(values, list):
raise RuntimeError("COCO images are invalid")
images = [_object(value, "COCO image") for value in values]
for image in images:
_integer(image, "id")
_positive_integer(image, "width")
_positive_integer(image, "height")
_string(image, "file_name")
return sorted(images, key=lambda item: _integer(item, "id"))
def load_category_ids_by_name(document: Mapping[str, object]) -> dict[str, int]:
values = document.get("categories")
if not isinstance(values, list):
raise RuntimeError("COCO categories are invalid")
result: dict[str, int] = {}
for value in values:
category = _object(value, "COCO category")
name = _string(category, "name")
category_id = _positive_integer(category, "id")
if name in result:
raise RuntimeError("COCO category names are duplicated")
result[name] = category_id
if set(result.values()) != set(COCO_SPARSE_IDS):
raise RuntimeError("COCO sparse category ids changed")
return result
def run_pytorch_predictions(
*,
images: list[dict[str, object]],
images_root: Path,
checkpoint: Path,
category_ids_by_name: Mapping[str, int],
progress: Any,
) -> tuple[list[dict[str, float | int | list[float]]], dict[str, object]]:
import torch # type: ignore[import-not-found]
from rfdetr import RFDETRLarge # type: ignore[import-not-found]
started_at = time.perf_counter_ns()
model = RFDETRLarge(pretrain_weights=str(checkpoint))
model.inference(compile=False, dtype=torch.float16, inplace=True)
rows: list[dict[str, float | int | list[float]]] = []
timings: list[float] = []
try:
for index, image in enumerate(images, start=1):
image_started = time.perf_counter_ns()
image_path = (images_root / _string(image, "file_name")).resolve(strict=True)
with Image.open(image_path) as opened:
prediction = model.predict(
opened.convert("RGB"), threshold=0.0, include_source_image=False
)
boxes = np.asarray(prediction.xyxy, dtype=np.float32)
scores = np.asarray(prediction.confidence, dtype=np.float32)
names = np.asarray(prediction.data["class_name"])
if not (len(boxes) == len(scores) == len(names)):
raise RuntimeError("official RF-DETR prediction columns disagree")
for box, score, raw_name in zip(boxes, scores, names, strict=True):
name = str(raw_name)
category_id = category_ids_by_name.get(name)
if category_id is None:
continue
row = coco_prediction_row(
image_id=_integer(image, "id"),
category_id=category_id,
score=float(score),
bbox_xyxy=tuple(float(value) for value in box),
image_width=_positive_integer(image, "width"),
image_height=_positive_integer(image, "height"),
)
if row is not None:
rows.append(row)
timings.append((time.perf_counter_ns() - image_started) / 1_000_000)
write_progress(progress, "pytorch", index, len(images), len(rows), timings[-1])
finally:
del model
gc.collect()
if torch.cuda.is_available():
torch.cuda.empty_cache()
return rows, timing_report(started_at, timings)
def run_tensorrt_predictions(
*,
images: list[dict[str, object]],
images_root: Path,
triton_origin: str,
progress: Any,
) -> tuple[list[dict[str, float | int | list[float]]], dict[str, object]]:
import torch
import torchvision.transforms.functional as vision_functional # type: ignore[import-not-found]
means = [0.485, 0.456, 0.406]
stds = [0.229, 0.224, 0.225]
backend = TritonRfDetrHttpInferenceBackend(triton_origin)
rows: list[dict[str, float | int | list[float]]] = []
timings: list[float] = []
started_at = time.perf_counter_ns()
try:
for index, image in enumerate(images, start=1):
image_started = time.perf_counter_ns()
image_path = (images_root / _string(image, "file_name")).resolve(strict=True)
with Image.open(image_path) as opened:
rgb = opened.convert("RGB")
tensor = vision_functional.to_tensor(rgb)
tensor = vision_functional.resize(tensor, [704, 704], antialias=False)
tensor = vision_functional.normalize(tensor, means, stds)
batch = np.ascontiguousarray(tensor.unsqueeze(0).numpy(), dtype=np.float32)
output = backend.infer(batch)
rows.extend(
decode_tensorrt_coco_rows(
image_id=_integer(image, "id"),
image_width=_positive_integer(image, "width"),
image_height=_positive_integer(image, "height"),
boxes=output.boxes,
logits=output.logits,
maximum_detections=300,
)
)
timings.append((time.perf_counter_ns() - image_started) / 1_000_000)
write_progress(progress, "tensorrt", index, len(images), len(rows), timings[-1])
finally:
backend.close()
gc.collect()
if torch.cuda.is_available():
torch.cuda.empty_cache()
return rows, timing_report(started_at, timings)
def decode_tensorrt_coco_rows(
*,
image_id: int,
image_width: int,
image_height: int,
boxes: np.ndarray[Any, Any],
logits: np.ndarray[Any, Any],
maximum_detections: int,
) -> list[dict[str, float | int | list[float]]]:
if boxes.shape != (1, 300, 4) or logits.shape != (1, 300, 91):
raise RuntimeError("RF-DETR TensorRT output shape changed")
probabilities = 1.0 / (1.0 + np.exp(-np.clip(logits[0].astype(np.float32), -80, 80)))
flattened = probabilities.reshape(-1)
topk = np.argsort(-flattened, kind="stable")[:maximum_detections]
valid_category_ids = set(COCO_SPARSE_IDS)
result: list[dict[str, float | int | list[float]]] = []
for flat_index in topk:
category_id = int(flat_index % logits.shape[2])
if category_id not in valid_category_ids:
continue
query_index = int(flat_index // logits.shape[2])
center_x, center_y, width, height = (
float(value) for value in boxes[0, query_index].astype(np.float32)
)
row = coco_prediction_row(
image_id=image_id,
category_id=category_id,
score=float(flattened[flat_index]),
bbox_xyxy=(
(center_x - width / 2) * image_width,
(center_y - height / 2) * image_height,
(center_x + width / 2) * image_width,
(center_y + height / 2) * image_height,
),
image_width=image_width,
image_height=image_height,
)
if row is not None:
result.append(row)
return result
def coco_prediction_row(
*,
image_id: int,
category_id: int,
score: float,
bbox_xyxy: tuple[float, ...],
image_width: int,
image_height: int,
) -> dict[str, float | int | list[float]] | None:
if len(bbox_xyxy) != 4 or not all(math.isfinite(value) for value in bbox_xyxy):
raise RuntimeError("prediction box is invalid")
if not math.isfinite(score) or not 0 <= score <= 1:
raise RuntimeError("prediction score is invalid")
x1 = min(max(bbox_xyxy[0], 0.0), float(image_width))
y1 = min(max(bbox_xyxy[1], 0.0), float(image_height))
x2 = min(max(bbox_xyxy[2], 0.0), float(image_width))
y2 = min(max(bbox_xyxy[3], 0.0), float(image_height))
width = x2 - x1
height = y2 - y1
if width <= 0 or height <= 0:
return None
return {
"image_id": image_id,
"category_id": category_id,
"bbox": [x1, y1, width, height],
"score": score,
}
def evaluate_coco(
*,
annotations: Path,
predictions: list[dict[str, float | int | list[float]]],
image_ids: list[int],
) -> tuple[dict[str, float], str]:
from pycocotools.coco import COCO # type: ignore[import-untyped]
from pycocotools.cocoeval import COCOeval # type: ignore[import-untyped]
output = io.StringIO()
with contextlib.redirect_stdout(output):
truth = COCO(str(annotations))
detections = truth.loadRes(predictions)
evaluator = COCOeval(truth, detections, "bbox")
evaluator.params.imgIds = image_ids
evaluator.evaluate()
evaluator.accumulate()
evaluator.summarize()
metrics = {
name: round(float(value), 9)
for name, value in zip(COCO_METRIC_NAMES, evaluator.stats, strict=True)
}
return metrics, output.getvalue()
def build_parity_decision(
*,
profile: Mapping[str, object],
pytorch_metrics: Mapping[str, float],
tensorrt_metrics: Mapping[str, float],
full_admission_run: bool,
) -> dict[str, object]:
reference = _object(profile.get("published_reference"), "published_reference")
gates = _object(profile.get("parity_gates"), "parity_gates")
reproduction_tolerance = _number(reference, "maximum_absolute_reproduction_delta")
pytorch_reference_deltas = {
"ap_50_95": abs(pytorch_metrics["ap_50_95"] - _number(reference, "coco_ap_50_95")),
"ap_50": abs(pytorch_metrics["ap_50"] - _number(reference, "coco_ap_50")),
}
provider_deltas = {
"ap_50_95": abs(tensorrt_metrics["ap_50_95"] - pytorch_metrics["ap_50_95"]),
"ap_50": abs(tensorrt_metrics["ap_50"] - pytorch_metrics["ap_50"]),
}
reproduction_passed = all(
value <= reproduction_tolerance for value in pytorch_reference_deltas.values()
)
provider_parity_passed = provider_deltas["ap_50_95"] <= _number(
gates, "maximum_absolute_ap_50_95_delta"
) and provider_deltas["ap_50"] <= _number(gates, "maximum_absolute_ap_50_delta")
if not full_admission_run:
diagnosis = "bounded-smoke-only"
elif not reproduction_passed:
diagnosis = "upstream-reproduction-failed"
elif not provider_parity_passed:
diagnosis = "tensorrt-deployment-parity-failed"
else:
diagnosis = "upstream-and-tensorrt-parity-passed"
passed = full_admission_run and reproduction_passed and provider_parity_passed
return {
"passed": passed,
"diagnosis": diagnosis,
"full_admission_run": full_admission_run,
"pytorch_reference_deltas": pytorch_reference_deltas,
"provider_deltas": provider_deltas,
"upstream_reproduction_passed": reproduction_passed,
"provider_parity_passed": provider_parity_passed,
"semantic_authority_changed": False,
}
def write_progress(
progress: Any,
provider: str,
completed: int,
total: int,
prediction_count: int,
last_image_ms: float,
) -> None:
if completed != 1 and completed % 100 != 0 and completed != total:
return
progress.write(
canonical_json(
{
"schema_version": PROGRESS_SCHEMA,
"provider": provider,
"completed_images": completed,
"total_images": total,
"prediction_count": prediction_count,
"last_image_ms": last_image_ms,
}
)
+ "\n"
)
progress.flush()
def timing_report(started_at: int, timings: list[float]) -> dict[str, object]:
if not timings:
raise RuntimeError("provider timing is empty")
duration_seconds = (time.perf_counter_ns() - started_at) / 1_000_000_000
ordered = sorted(timings)
return {
"duration_seconds": duration_seconds,
"effective_images_per_second": len(timings) / duration_seconds,
"image_ms": {
"mean": statistics.fmean(ordered),
"p50": percentile(ordered, 0.5),
"p95": percentile(ordered, 0.95),
"p99": percentile(ordered, 0.99),
"maximum": ordered[-1],
},
}
def percentile(values: list[float], quantile: float) -> float:
position = (len(values) - 1) * quantile
lower = math.floor(position)
upper = math.ceil(position)
if lower == upper:
return values[lower]
return values[lower] + (values[upper] - values[lower]) * (position - lower)
def write_gzip_jsonl(path: Path, rows: Iterable[Mapping[str, float | int | list[float]]]) -> None:
with (
path.open("xb") as raw_handle,
gzip.GzipFile(fileobj=raw_handle, mode="wb", compresslevel=6, mtime=0) as compressed,
io.TextIOWrapper(compressed, encoding="utf-8") as handle,
):
for row in rows:
handle.write(canonical_json(row) + "\n")
def package_versions(names: Iterable[str]) -> dict[str, str]:
result: dict[str, str] = {}
for name in names:
try:
result[name] = importlib.metadata.version(name)
except importlib.metadata.PackageNotFoundError:
result[name] = "not-installed"
return result
def sha256_path(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def canonical_json(value: object) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def _object(value: object, label: str) -> dict[str, object]:
if not isinstance(value, dict) or any(not isinstance(key, str) for key in value):
raise RuntimeError(f"{label} is not an object")
return value
def _string(value: Mapping[str, object], key: str) -> str:
result = value.get(key)
if not isinstance(result, str) or not result:
raise RuntimeError(f"{key} is not a non-empty string")
return result
def _integer(value: Mapping[str, object], key: str) -> int:
result = value.get(key)
if not isinstance(result, int) or isinstance(result, bool):
raise RuntimeError(f"{key} is not an integer")
return result
def _positive_integer(value: Mapping[str, object], key: str) -> int:
result = _integer(value, key)
if result <= 0:
raise RuntimeError(f"{key} is not positive")
return result
def _number(value: Mapping[str, object], key: str) -> float:
result = value.get(key)
if not isinstance(result, (int, float)) or isinstance(result, bool):
raise RuntimeError(f"{key} is not numeric")
converted = float(result)
if not math.isfinite(converted):
raise RuntimeError(f"{key} is not finite")
return converted
if __name__ == "__main__":
main()
@@ -0,0 +1,312 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ReleaseRoot,
[Parameter(Mandatory = $true)]
[ValidatePattern("^[a-f0-9]{64}$")]
[string]$ExpectedWheelSha256,
[Parameter(Mandatory = $true)]
[ValidatePattern("^[A-Za-z0-9._-]{1,96}$")]
[string]$RunId,
[ValidateRange(0, 5000)]
[int]$MaximumImages = 0,
[string]$DatasetRoot = "D:\NDC_MISSIONCORE\datasets\coco-2017-val",
[string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\results\m48t-upstream-parity"
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
function Assert-LastExitCode([string]$Operation) {
if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" }
}
function Get-Sha256([string]$Path) {
return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
function Resolve-DDirectory([string]$Path, [string]$Label, [bool]$Create) {
if ($Create -and -not (Test-Path -LiteralPath $Path)) {
$null = New-Item -ItemType Directory -Path $Path
}
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
if (
-not $item.PSIsContainer -or
($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
[IO.Path]::GetPathRoot($item.FullName).TrimEnd("\") -ine "D:"
) {
throw "$Label must be a real D: directory"
}
return $item.FullName
}
function Assert-RegularFile([string]$Path, [string]$Label) {
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw "$Label must be a regular file"
}
return $item.FullName
}
function Convert-ToDockerPath([string]$Path) { return $Path.Replace("\", "/") }
function Get-Container([string]$Name) {
$rows = @((& docker inspect $Name) | ConvertFrom-Json)
Assert-LastExitCode "Docker inspection for $Name"
if ($rows.Count -ne 1) { throw "Container identity for $Name is not unique" }
return $rows[0]
}
if ($env:COMPUTERNAME -cne "DESKTOP-OPJ8J04") {
throw "M48T upstream parity is pinned to DESKTOP-OPJ8J04"
}
$release = Resolve-DDirectory $ReleaseRoot "M48T parity release root" $false
$dataset = Resolve-DDirectory $DatasetRoot "M48T parity dataset root" $false
$output = Resolve-DDirectory $OutputRoot "M48T parity output root" $true
$runOutput = Join-Path $output $RunId
if (Test-Path -LiteralPath $runOutput) { throw "M48T parity output already exists" }
$null = New-Item -ItemType Directory -Path $runOutput
$runOutput = Resolve-DDirectory $runOutput "M48T parity run output" $false
$wheel = Assert-RegularFile (Join-Path $release "nodedc_mission_core-0.1.0-py3-none-any.whl") "wheel"
if ((Get-Sha256 $wheel) -cne $ExpectedWheelSha256) { throw "wheel SHA-256 changed" }
$profile = Assert-RegularFile (Join-Path $release "m48t-upstream-parity-v1.json") "profile"
$runner = Assert-RegularFile (Join-Path $release "run_m48t_upstream_parity_worker.py") "runner"
$annotations = Assert-RegularFile (Join-Path $dataset "instances_val2017.json") "COCO annotations"
$imagesRoot = Resolve-DDirectory (Join-Path $dataset "val2017") "COCO val2017 images" $false
if (@(Get-ChildItem -LiteralPath $imagesRoot -File -Filter "*.jpg").Count -ne 5000) {
throw "COCO val2017 image count changed"
}
$experimentRoot = Resolve-DDirectory (
"D:\NDC_MISSIONCORE\runtime\experiments\m48t-fixed-detector-20260825T095425Z"
) "RF-DETR experiment root" $false
$checkpoint = Assert-RegularFile (Join-Path $experimentRoot "weights\rf-detr-large-2026.pth") "checkpoint"
if ((Get-Sha256 $checkpoint) -cne "0f4e20e19a99c0f8a62b5685f57f6c8b5c371c59081feda6752a0561a79ccf38") {
throw "RF-DETR checkpoint SHA-256 changed"
}
$modelRoot = Resolve-DDirectory (Join-Path $experimentRoot "triton-models") "model root" $false
$engine = Assert-RegularFile (Join-Path $modelRoot "rf_detr_large\1\model.plan") "TensorRT engine"
if ((Get-Sha256 $engine) -cne "986399ce706b7380472cf5e473232249fed6e628971d8007f6609e83128d46b8") {
throw "RF-DETR TensorRT engine SHA-256 changed"
}
$historical = Get-Container "ndc-mission-core-triton"
if (-not $historical.State.Running -or $historical.State.Health.Status -cne "healthy") {
throw "Historical Triton must remain healthy"
}
$historicalId = [string]$historical.Id
$baseImage = "nvcr.io/nvidia/tritonserver:26.06-py3@sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
& docker image inspect $baseImage *> $null
Assert-LastExitCode "pinned base image inspection"
$baseImageId = (& docker image inspect $baseImage --format "{{.Id}}").Trim()
Assert-LastExitCode "pinned base image identity"
$runtimeVolume = "ndc-mission-core-m48t-upstream-parity-env"
if (-not (& docker volume ls --quiet --filter "name=^$runtimeVolume$")) {
& docker volume create `
--label "com.nodedc.product=mission-core" `
--label "com.nodedc.stack=ndc-mission-core-compute" `
--label "com.nodedc.role=bounded-rf-detr-upstream-parity" `
--label "com.nodedc.managed-by=codex-bounded-experiment" `
$runtimeVolume *> $null
Assert-LastExitCode "M48T upstream parity dependency volume creation"
}
$torchReady = $false
$strictErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& docker run --rm `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--tmpfs "/tmp:rw,noexec,nosuid,size=512m" `
-e "PYTHONPATH=/opt/parity" `
-v ($runtimeVolume + ":/opt/parity:ro") `
--entrypoint python3 `
$baseImage `
-c "import importlib.metadata as m; assert m.version('numpy') == '1.26.4'; assert m.version('torch') == '2.9.1+cu130'; assert m.version('torchvision') == '0.24.1+cu130'" *> $null
if ($LASTEXITCODE -eq 0) { $torchReady = $true }
$ErrorActionPreference = $strictErrorActionPreference
if (-not $torchReady) {
& docker run --rm `
--name "ndc-mission-core-m48t-upstream-parity-env-torch" `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--pids-limit 512 `
--tmpfs "/tmp:rw,noexec,nosuid,size=8g" `
-e "PIP_DISABLE_PIP_VERSION_CHECK=1" `
-v ($runtimeVolume + ":/opt/parity:rw") `
--entrypoint python3 `
$baseImage `
-m pip install --no-cache-dir --target /opt/parity `
--index-url https://download.pytorch.org/whl/cu130 `
"numpy==1.26.4" "torch==2.9.1+cu130" "torchvision==0.24.1+cu130"
Assert-LastExitCode "M48T upstream parity PyTorch environment initialization"
}
$rfdetrReady = $false
$ErrorActionPreference = "Continue"
& docker run --rm `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--tmpfs "/tmp:rw,noexec,nosuid,size=512m" `
-e "PYTHONPATH=/opt/parity" `
-v ($runtimeVolume + ":/opt/parity:ro") `
--entrypoint python3 `
$baseImage `
-c "import importlib.metadata as m; import rfdetr; assert m.version('rfdetr') == '1.9.4'; assert m.version('pycocotools') == '2.0.10'; assert m.version('tritonclient') == '2.71.0'" *> $null
if ($LASTEXITCODE -eq 0) { $rfdetrReady = $true }
$ErrorActionPreference = $strictErrorActionPreference
if (-not $rfdetrReady) {
& docker run --rm `
--name "ndc-mission-core-m48t-upstream-parity-env-dependencies" `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--pids-limit 512 `
--tmpfs "/tmp:rw,noexec,nosuid,size=8g" `
-e "PIP_DISABLE_PIP_VERSION_CHECK=1" `
-e "PYTHONPATH=/opt/parity" `
-v ($runtimeVolume + ":/opt/parity:rw") `
--entrypoint python3 `
$baseImage `
-m pip install --no-cache-dir --upgrade --target /opt/parity `
"numpy==1.26.4" "requests" "tqdm" "transformers>=5.1.0,<6.0.0" `
"pydantic>=2.0,<3.0" "supervision>=0.29.0,<1.0" "pyDeprecate>=0.9,<0.10" `
"pycocotools==2.0.10" "tritonclient[http]==2.71.0"
Assert-LastExitCode "M48T upstream parity dependency initialization"
& docker run --rm `
--name "ndc-mission-core-m48t-upstream-parity-env-rfdetr" `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--pids-limit 512 `
--tmpfs "/tmp:rw,noexec,nosuid,size=2g" `
-e "PIP_DISABLE_PIP_VERSION_CHECK=1" `
-e "PYTHONPATH=/opt/parity" `
-v ($runtimeVolume + ":/opt/parity:rw") `
--entrypoint python3 `
$baseImage `
-m pip install --no-cache-dir --no-deps --upgrade --target /opt/parity "rfdetr==1.9.4"
Assert-LastExitCode "M48T upstream parity RF-DETR package initialization"
}
& docker run --rm `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--tmpfs "/tmp:rw,noexec,nosuid,size=512m" `
-e "PYTHONPATH=/opt/parity" `
-v ($runtimeVolume + ":/opt/parity:ro") `
--entrypoint python3 `
$baseImage `
-c "import importlib.metadata as m; import rfdetr, torch, torchvision; assert m.version('numpy') == '1.26.4'; assert m.version('rfdetr') == '1.9.4'; assert m.version('torch') == '2.9.1+cu130'; assert m.version('torchvision') == '0.24.1+cu130'; assert m.version('pycocotools') == '2.0.10'; assert m.version('tritonclient') == '2.71.0'"
Assert-LastExitCode "M48T upstream parity dependency volume verification"
$runtimeIdentity = $baseImageId + "+volume:" + $runtimeVolume
$tritonName = "ndc-mission-core-m48t-upstream-parity-triton"
$runnerName = "ndc-mission-core-m48t-upstream-parity"
foreach ($name in @($tritonName, $runnerName)) {
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$name$") {
throw "M48T parity container $name already exists"
}
}
try {
& docker create `
--name $tritonName `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--pids-limit 512 `
--shm-size 1g `
--gpus all `
--tmpfs "/tmp:rw,noexec,nosuid,size=2g" `
--health-cmd "curl --fail --silent http://127.0.0.1:8000/v2/health/ready" `
--health-interval 5s `
--health-timeout 3s `
--health-start-period 20s `
--health-retries 24 `
-v ((Convert-ToDockerPath $modelRoot) + ":/models:ro") `
$baseImage `
tritonserver `
--model-repository=/models `
--model-control-mode=explicit `
--load-model=rf_detr_large `
--disable-auto-complete-config `
--strict-readiness=true `
--exit-on-error=true `
--allow-http=true `
--allow-grpc=false `
--allow-metrics=false *> $null
Assert-LastExitCode "M48T parity Triton creation"
& docker start $tritonName *> $null
Assert-LastExitCode "M48T parity Triton start"
$ready = $false
foreach ($attempt in 1..60) {
Start-Sleep -Seconds 2
$candidate = Get-Container $tritonName
if (-not $candidate.State.Running) { throw "M48T parity Triton stopped during startup" }
if ($candidate.State.Health.Status -ceq "healthy") { $ready = $true; break }
}
if (-not $ready) { throw "M48T parity Triton did not become healthy" }
$maximumArguments = @()
if ($MaximumImages -gt 0) { $maximumArguments = @("--maximum-images", ([string]$MaximumImages)) }
$arguments = @(
"run", "--name", $runnerName,
"--network", ("container:{0}" -f $tritonName),
"--read-only",
"--security-opt", "no-new-privileges:true",
"--cap-drop", "ALL",
"--pids-limit", "512",
"--gpus", "all",
"--shm-size", "2g",
"--tmpfs", "/tmp:rw,noexec,nosuid,size=8g",
"-e", "PYTHONDONTWRITEBYTECODE=1",
"-e", "PYTHONPATH=/opt/parity:/release/nodedc_mission_core-0.1.0-py3-none-any.whl",
"-v", ($runtimeVolume + ":/opt/parity:ro"),
"-v", ((Convert-ToDockerPath $release) + ":/release:ro"),
"-v", ((Convert-ToDockerPath $imagesRoot) + ":/dataset/val2017:ro"),
"-v", ((Convert-ToDockerPath $annotations) + ":/dataset/instances_val2017.json:ro"),
"-v", ((Convert-ToDockerPath $checkpoint) + ":/model/rf-detr-large-2026.pth:ro"),
"-v", ((Convert-ToDockerPath $runOutput) + ":/output:rw"),
"--entrypoint", "python3",
$baseImage,
"/release/run_m48t_upstream_parity_worker.py",
"--profile", "/release/m48t-upstream-parity-v1.json",
"--annotations", "/dataset/instances_val2017.json",
"--images-root", "/dataset/val2017",
"--checkpoint", "/model/rf-detr-large-2026.pth",
"--triton-origin", "http://127.0.0.1:8000",
"--output", "/output/result.json",
"--pytorch-predictions", "/output/pytorch-predictions.jsonl.gz",
"--tensorrt-predictions", "/output/tensorrt-predictions.jsonl.gz",
"--progress", "/output/progress.jsonl",
"--runtime-image", $runtimeIdentity
) + $maximumArguments
& docker @arguments
Assert-LastExitCode "M48T upstream parity evaluation"
if (-not (Test-Path -LiteralPath (Join-Path $runOutput "result.json") -PathType Leaf)) {
throw "M48T upstream parity result was not written"
}
} finally {
foreach ($name in @($runnerName, $tritonName)) {
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$name$") {
& docker rm -f $name *> $null
}
}
$historicalAfter = Get-Container "ndc-mission-core-triton"
if (
$historicalAfter.Id -cne $historicalId -or
-not $historicalAfter.State.Running -or
$historicalAfter.State.Health.Status -cne "healthy"
) {
throw "Historical Triton changed during M48T upstream parity"
}
}
Write-Output ("M48T_UPSTREAM_PARITY_RESULT={0}" -f (Join-Path $runOutput "result.json"))
Write-Output ("RUNTIME_IDENTITY={0}" -f $runtimeIdentity)
Write-Output "HISTORICAL_TRITON_ACTION=none"
Write-Output "SEMANTIC_AUTHORITY_CHANGED=false"
+86
View File
@@ -0,0 +1,86 @@
from __future__ import annotations
import importlib.util
import json
from pathlib import Path
from types import ModuleType
import numpy as np
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
RUNNER_PATH = REPOSITORY_ROOT / "experiments/perception/run_m48t_upstream_parity_worker.py"
PROFILE_PATH = REPOSITORY_ROOT / "config/perception/m48t-upstream-parity-v1.json"
def load_runner() -> ModuleType:
specification = importlib.util.spec_from_file_location("m48t_upstream_parity", RUNNER_PATH)
assert specification is not None and specification.loader is not None
module = importlib.util.module_from_spec(specification)
specification.loader.exec_module(module)
return module
def test_upstream_parity_profile_freezes_official_and_deployed_providers() -> None:
profile = json.loads(PROFILE_PATH.read_text("utf-8"))
assert profile["model"]["package_version"] == "1.9.4"
assert profile["model"]["resolution"] == [704, 704]
assert profile["dataset"]["image_count"] == 5000
assert profile["providers"]["pytorch"]["confidence_prefilter"] == 0.0
assert profile["providers"]["tensorrt"]["confidence_prefilter"] == 0.0
assert profile["authority"]["navigation_or_safety_accepted"] is False
def test_tensorrt_decoder_uses_sparse_coco_ids_and_original_image_geometry() -> None:
runner = load_runner()
boxes = np.zeros((1, 300, 4), dtype=np.float16)
logits = np.full((1, 300, 91), -20, dtype=np.float16)
boxes[0, 4] = np.asarray((0.5, 0.5, 0.2, 0.4), dtype=np.float16)
logits[0, 4, 1] = np.float16(4.0) # COCO sparse id 1: person
logits[0, 7, 12] = np.float16(5.0) # sparse gap: must never escape
rows = runner.decode_tensorrt_coco_rows(
image_id=42,
image_width=1000,
image_height=500,
boxes=boxes,
logits=logits,
maximum_detections=2,
)
assert len(rows) == 1
assert rows[0]["image_id"] == 42
assert rows[0]["category_id"] == 1
assert np.allclose(rows[0]["bbox"], [400.0244, 149.9756, 199.9512, 200.0488], atol=0.1)
def test_parity_decision_localizes_upstream_and_deployment_failures() -> None:
runner = load_runner()
profile = json.loads(PROFILE_PATH.read_text("utf-8"))
passed = runner.build_parity_decision(
profile=profile,
pytorch_metrics={"ap_50_95": 0.565, "ap_50": 0.751},
tensorrt_metrics={"ap_50_95": 0.563, "ap_50": 0.749},
full_admission_run=True,
)
assert passed["passed"] is True
assert passed["diagnosis"] == "upstream-and-tensorrt-parity-passed"
deployment_failure = runner.build_parity_decision(
profile=profile,
pytorch_metrics={"ap_50_95": 0.565, "ap_50": 0.751},
tensorrt_metrics={"ap_50_95": 0.54, "ap_50": 0.72},
full_admission_run=True,
)
assert deployment_failure["passed"] is False
assert deployment_failure["diagnosis"] == "tensorrt-deployment-parity-failed"
smoke = runner.build_parity_decision(
profile=profile,
pytorch_metrics={"ap_50_95": 0.565, "ap_50": 0.751},
tensorrt_metrics={"ap_50_95": 0.565, "ap_50": 0.751},
full_admission_run=False,
)
assert smoke["passed"] is False
assert smoke["diagnosis"] == "bounded-smoke-only"