feat(perception): add PointPillars transfer gate

This commit is contained in:
DCCONSTRUCTIONS
2026-07-31 10:48:27 +03:00
parent 29fee5c0ac
commit a9a5ca5a26
23 changed files with 5407 additions and 0 deletions
+230
View File
@@ -0,0 +1,230 @@
from __future__ import annotations
import hashlib
import json
import zipfile
from pathlib import Path
from typing import Any
import pytest
from k1link.datasets import kitti_3d_admission as module
def _sha256(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _calibration(*, complete: bool = True) -> str:
rows = [
"P0: " + " ".join(["1"] * 12),
"P1: " + " ".join(["1"] * 12),
"P2: " + " ".join(["1"] * 12),
"P3: " + " ".join(["1"] * 12),
"R0_rect: " + " ".join(["1"] * 9),
"Tr_velo_to_cam: " + " ".join(["1"] * 12),
]
if complete:
rows.append("Tr_imu_to_velo: " + " ".join(["1"] * 12))
return "\n".join(rows) + "\n"
def _label(class_name: str, *, valid: bool = True) -> str:
dimensions = "1.5 1.6 3.8" if valid else "0 1.6 3.8"
return (
f"{class_name} 0 0 0 0 0 10 10 {dimensions} 1 1 10 0\n"
)
def _release(
root: Path,
monkeypatch: pytest.MonkeyPatch,
*,
labels: dict[str, str] | None = None,
complete_calibration: bool = True,
invalid_velodyne_frame: bool = False,
train_rows: tuple[str, ...] = ("000000",),
validation_rows: tuple[str, ...] = ("000001", "000002"),
) -> dict[str, Path]:
archive_root = root / module.KITTI_3D_RELEASE_ROOT / "archives"
split_root = root / module.KITTI_3D_RELEASE_ROOT / "splits" / (
f"openpcdet-{module.KITTI_STANDARD_SPLIT_COMMIT}"
)
archive_root.mkdir(parents=True)
split_root.mkdir(parents=True)
paths = {
module.KITTI_VELODYNE_ARCHIVE: archive_root
/ module.KITTI_VELODYNE_ARCHIVE,
module.KITTI_LABEL_ARCHIVE: archive_root / module.KITTI_LABEL_ARCHIVE,
module.KITTI_CALIB_ARCHIVE: archive_root / module.KITTI_CALIB_ARCHIVE,
"train": split_root / "train.txt",
"validation": split_root / "val.txt",
}
with zipfile.ZipFile(paths[module.KITTI_VELODYNE_ARCHIVE], "w") as archive:
for frame_id in ("000000", "000001", "000002"):
size = 15 if invalid_velodyne_frame and frame_id == "000001" else 16
archive.writestr(f"training/velodyne/{frame_id}.bin", b"\x00" * size)
for frame_id in ("000000", "000001"):
archive.writestr(f"testing/velodyne/{frame_id}.bin", b"\x00" * 16)
label_payloads = labels or {
"000000": _label("Car"),
"000001": _label("Pedestrian") + _label("Car"),
"000002": _label("Cyclist"),
}
with zipfile.ZipFile(paths[module.KITTI_LABEL_ARCHIVE], "w") as archive:
for frame_id, payload in label_payloads.items():
archive.writestr(f"training/label_2/{frame_id}.txt", payload)
with zipfile.ZipFile(paths[module.KITTI_CALIB_ARCHIVE], "w") as archive:
for split, frames in {
"training": ("000000", "000001", "000002"),
"testing": ("000000", "000001"),
}.items():
for frame_id in frames:
archive.writestr(
f"{split}/calib/{frame_id}.txt",
_calibration(complete=complete_calibration),
)
paths["train"].write_text("\n".join(train_rows) + "\n", encoding="ascii")
paths["validation"].write_text(
"\n".join(validation_rows) + "\n",
encoding="ascii",
)
monkeypatch.setattr(module, "KITTI_TRAINING_FRAMES", 3)
monkeypatch.setattr(module, "KITTI_TEST_FRAMES", 2)
monkeypatch.setattr(
module,
"KITTI_ARCHIVE_BYTES",
{
name: paths[name].stat().st_size
for name in (
module.KITTI_VELODYNE_ARCHIVE,
module.KITTI_LABEL_ARCHIVE,
module.KITTI_CALIB_ARCHIVE,
)
},
)
monkeypatch.setattr(
module,
"KITTI_SPLIT_COUNTS",
{"train": len(train_rows), "validation": len(validation_rows)},
)
monkeypatch.setattr(
module,
"KITTI_SPLIT_SHA256",
{"train": _sha256(paths["train"]), "validation": _sha256(paths["validation"])},
)
monkeypatch.setattr(module, "_is_worker_dataset_root", lambda _root: True)
return paths
def test_admits_archive_only_box_truth_with_path_free_state(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(tmp_path, monkeypatch)
manifest = module.admit_kitti_3d_object_release(tmp_path)
assert manifest["status"] == "archive-ready"
assert manifest["storage"]["source_archives_extracted"] is False
assert manifest["benchmark_contract"] == {
"independent_ground_truth": True,
"annotations": ["oriented-3d-boxes"],
"point_fields": ["x", "y", "z", "intensity"],
"eligible_split": "validation",
"target_classes": ["Car", "Pedestrian", "Cyclist"],
"official_test_submission_authorized": False,
"retuning_on_validation_allowed": False,
"k1_quality_claim_authorized": False,
}
assert manifest["alignment"]["validation_target_box_counts"] == {
"Car": 1,
"Cyclist": 1,
"Pedestrian": 1,
}
serialized = json.dumps(manifest)
assert str(tmp_path) not in serialized
assert module.read_kitti_3d_admission(tmp_path) == manifest
assert module.read_kitti_standard_splits(tmp_path) == {
"train": ("000000",),
"validation": ("000001", "000002"),
}
def test_rejects_tampered_standard_split(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
paths = _release(tmp_path, monkeypatch)
paths["validation"].write_text("000002\n000001\n", encoding="ascii")
with pytest.raises(module.Kitti3DAdmissionError, match="pinned OpenPCDet"):
module.admit_kitti_3d_object_release(tmp_path)
def test_rejects_overlapping_split(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(
tmp_path,
monkeypatch,
train_rows=("000000", "000001"),
validation_rows=("000001", "000002"),
)
with pytest.raises(module.Kitti3DAdmissionError, match="overlapping or incomplete"):
module.admit_kitti_3d_object_release(tmp_path)
def test_rejects_non_xyzi_velodyne_frame(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(tmp_path, monkeypatch, invalid_velodyne_frame=True)
with pytest.raises(module.Kitti3DAdmissionError, match="not packed XYZI"):
module.admit_kitti_3d_object_release(tmp_path)
def test_rejects_invalid_target_box(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(
tmp_path,
monkeypatch,
labels={
"000000": _label("Car"),
"000001": _label("Pedestrian", valid=False),
"000002": _label("Cyclist"),
},
)
with pytest.raises(module.Kitti3DAdmissionError, match="invalid dimensions"):
module.admit_kitti_3d_object_release(tmp_path)
def test_rejects_missing_calibration_transform(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(tmp_path, monkeypatch, complete_calibration=False)
with pytest.raises(module.Kitti3DAdmissionError, match="required transforms"):
module.admit_kitti_3d_object_release(tmp_path)
def test_read_rejects_tampered_content_identity(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
_release(tmp_path, monkeypatch)
module.admit_kitti_3d_object_release(tmp_path)
state = tmp_path / "state/kitti-3d-object-v2017.json"
payload: dict[str, Any] = json.loads(state.read_text(encoding="utf-8"))
payload["identity"]["license"]["spdx"] = "unknown"
state.write_text(json.dumps(payload), encoding="utf-8")
with pytest.raises(module.Kitti3DAdmissionError, match="identity is invalid"):
module.read_kitti_3d_admission(tmp_path)
+258
View File
@@ -0,0 +1,258 @@
from __future__ import annotations
import math
import zipfile
from pathlib import Path
import pytest
from k1link.compute.kitti_pointpillars_benchmark import (
KittiLidarTruth,
KittiPointPillarsBenchmarkError,
PointPillarsFramePrediction,
evaluate_pointpillars_predictions,
read_kitti_validation_truth,
)
from k1link.compute.pointpillars_postprocess import PointPillarsBox
def _calibration() -> str:
return "\n".join(
[
"R0_rect: 1 0 0 0 1 0 0 0 1",
"Tr_velo_to_cam: 1 0 0 0 0 1 0 0 0 0 1 0",
"",
"",
]
)
def _label(class_name: str, x_m: float) -> str:
return f"{class_name} 0 0 0 0 0 10 10 1.5 2 4 {x_m} 0 0 0\n"
def _truth(
frame_id: str,
class_name: str,
*,
x_m: float = 10.0,
) -> KittiLidarTruth:
return KittiLidarTruth(
frame_id=frame_id,
benchmark_class=class_name,
x_m=x_m,
y_m=0.0,
z_m=0.0,
length_m=4.0,
width_m=2.0,
height_m=1.5,
yaw_rad=0.0,
)
def _prediction_box(
model_class: str,
*,
x_m: float = 10.0,
score: float = 0.9,
) -> PointPillarsBox:
return PointPillarsBox(
x_m=x_m,
y_m=0.0,
z_m=0.0,
length_m=4.0,
width_m=2.0,
height_m=1.5,
yaw_rad=0.0,
class_id={"Vehicle": 0, "Pedestrian": 1, "Cyclist": 2}[model_class],
model_class=model_class,
score=score,
)
def _perfect_fixture() -> tuple[
dict[str, tuple[KittiLidarTruth, ...]],
tuple[PointPillarsFramePrediction, ...],
]:
classes = (
("000000", "Car", "Vehicle"),
("000001", "Pedestrian", "Pedestrian"),
("000002", "Cyclist", "Cyclist"),
)
truth = {
frame_id: (_truth(frame_id, benchmark_class),)
for frame_id, benchmark_class, _ in classes
}
predictions = tuple(
PointPillarsFramePrediction(
frame_id=frame_id,
boxes=(_prediction_box(model_class),),
inference_ms=50.0 + index,
)
for index, (frame_id, _, model_class) in enumerate(classes)
)
return truth, predictions
def test_reads_and_converts_kitti_camera_bottom_centers(
tmp_path: Path,
) -> None:
labels = tmp_path / "labels.zip"
calibrations = tmp_path / "calib.zip"
with zipfile.ZipFile(labels, "w") as archive:
archive.writestr(
"training/label_2/000000.txt",
_label("Car", 10.0),
)
archive.writestr(
"training/label_2/000001.txt",
_label("Pedestrian", 11.0),
)
archive.writestr(
"training/label_2/000002.txt",
_label("Cyclist", 12.0),
)
with zipfile.ZipFile(calibrations, "w") as archive:
for frame_id in ("000000", "000001", "000002"):
archive.writestr(
f"training/calib/{frame_id}.txt",
_calibration(),
)
truth = read_kitti_validation_truth(
labels_archive=labels,
calibrations_archive=calibrations,
validation_frame_ids=("000000", "000001", "000002"),
)
car = truth["000000"][0]
assert car.x_m == 10.0
assert car.z_m == pytest.approx(0.75)
assert car.yaw_rad == pytest.approx(-math.pi / 2.0)
assert car.length_m == 4.0
assert car.width_m == 2.0
def test_perfect_predictions_produce_complete_metrics() -> None:
truth, predictions = _perfect_fixture()
report = evaluate_pointpillars_predictions(
truth_by_frame=truth,
predictions=predictions,
)
assert report["aggregates"]["bev_map40"] == pytest.approx(1.0)
assert report["aggregates"]["3d_map40"] == pytest.approx(1.0)
assert report["aggregates"]["false_occupied_rate"] == 0.0
assert report["aggregates"]["center_error_m"]["mean"] == 0.0
assert report["aggregates"]["range_error_m"]["mean"] == 0.0
assert report["aggregates"]["yaw_error_rad"]["mean"] == 0.0
assert report["aggregates"]["distance_bucket_recall"]["0-20m"]["recall"] == 1.0
assert report["metric_contract"]["evaluation_kind"] == (
"public-cross-domain-transfer-probe"
)
assert report["claim_boundary"]["native_model_accuracy_evaluated"] is False
assert report["claim_boundary"]["k1_transfer_evaluated"] is False
def test_false_prediction_reduces_precision_and_counts_false_occupied() -> None:
truth, predictions = _perfect_fixture()
first = predictions[0]
predictions = (
PointPillarsFramePrediction(
frame_id=first.frame_id,
boxes=(
_prediction_box("Vehicle", x_m=40.0, score=0.95),
*first.boxes,
),
inference_ms=first.inference_ms,
),
*predictions[1:],
)
report = evaluate_pointpillars_predictions(
truth_by_frame=truth,
predictions=predictions,
)
assert report["per_class"]["Car"]["true_positives"] == 1
assert report["per_class"]["Car"]["false_positives"] == 1
assert report["per_class"]["Car"]["precision"] == pytest.approx(0.5)
assert report["aggregates"]["false_occupied_rate"] == pytest.approx(0.25)
def test_predictions_outside_shared_cross_domain_range_are_not_false_positives() -> None:
truth, predictions = _perfect_fixture()
first = predictions[0]
predictions = (
PointPillarsFramePrediction(
frame_id=first.frame_id,
boxes=(
_prediction_box("Vehicle", x_m=-10.0, score=0.95),
*first.boxes,
),
inference_ms=first.inference_ms,
),
*predictions[1:],
)
report = evaluate_pointpillars_predictions(
truth_by_frame=truth,
predictions=predictions,
)
assert report["per_class"]["Car"]["false_positives"] == 0
assert report["aggregates"]["prediction_volume"] == {
"model_output_box_count": 4,
"evaluated_box_count": 3,
"outside_shared_range_count": 1,
}
def test_frame_set_must_equal_admitted_validation_split() -> None:
truth, predictions = _perfect_fixture()
with pytest.raises(
KittiPointPillarsBenchmarkError,
match="do not equal",
):
evaluate_pointpillars_predictions(
truth_by_frame=truth,
predictions=predictions[:-1],
)
def test_unknown_model_class_is_rejected() -> None:
truth, predictions = _perfect_fixture()
first = predictions[0]
unknown = PointPillarsBox(
**{
field: getattr(first.boxes[0], field)
for field in (
"x_m",
"y_m",
"z_m",
"length_m",
"width_m",
"height_m",
"yaw_rad",
"class_id",
"score",
)
},
model_class="Unknown",
)
predictions = (
PointPillarsFramePrediction(
frame_id=first.frame_id,
boxes=(unknown,),
inference_ms=first.inference_ms,
),
*predictions[1:],
)
with pytest.raises(KittiPointPillarsBenchmarkError, match="not admitted"):
evaluate_pointpillars_predictions(
truth_by_frame=truth,
predictions=predictions,
)
+428
View File
@@ -0,0 +1,428 @@
from __future__ import annotations
import copy
import json
from pathlib import Path
from typing import Any
import pytest
from k1link.compute.l3_pointpillars_admission import (
L3PointPillarsAdmissionError,
build_l3_pointpillars_admission,
read_l3_pointpillars_admission,
)
SHA = "a" * 64
TRITON_SHA = "58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
def _profile() -> dict[str, Any]:
return {
"schema_version": "missioncore.l3-pointpillars-benchmark-profile/v1",
"profile_id": "l3-pointpillars-public-transfer-probe-v1",
"detector": {
"family": "nvidia-tao-pointpillars",
"upstream_model_id": "nvidia/tao/pointpillarnet",
"candidate_frozen": False,
"candidate_model_version": None,
"candidate_source_sha256": None,
"candidate_label_sha256": None,
"triton_model_name": "pointpillars",
"required_source_format": "onnx",
"input_representation": "native-sensor-scan",
"input_coordinate_frame": "sensor/lidar",
"input_fields": ["x", "y", "z", "intensity"],
"batch_size": 1,
"maximum_points": 204_800,
"point_cloud_range": [
-51.20000076293945,
-51.20000076293945,
-1.399999976158142,
51.20000076293945,
51.20000076293945,
4.400000095367432,
],
"training_domain": "proprietary-solid-state-lidar",
"training_ground_truth_publicly_reproducible": False,
"model_classes": ["Vehicle", "Pedestrian", "Cyclist"],
"onnx_contract_sha256": (
"2fd29cd054ab058c2cfec3dfba305c71e123ef3f04b457d0c64de0c8dac2e1be"
),
"postprocessing": {
"reference_repository": (
"https://github.com/NVIDIA-AI-IOT/tao_toolkit_recipes"
),
"reference_commit": "a540badc47812a17a94e924b537d49ad3969b5a8",
"output_row_fields": [
"x",
"y",
"z",
"length",
"width",
"height",
"yaw",
"class_id",
"score",
],
"class_agnostic_nms": True,
"nms_iou_threshold": 0.01,
"pre_nms_top_n": 4096,
"embedded_score_threshold": 0.1,
"embedded_contract_source": "onnx-node-attributes",
},
},
"runtime_policy": {
"existing_triton_only": True,
"second_serving_stack_allowed": False,
"engine_built_on_target_required": True,
"precision": "strongly-typed",
"triton_image": "nvcr.io/nvidia/tritonserver:26.06-py3",
"triton_image_digest": TRITON_SHA,
},
"public_cross_domain_probe": {
"required_split": "validation",
"required_ground_truth": "oriented-3d-boxes",
"independent_ground_truth_required": True,
"benchmark_classes": ["Car", "Pedestrian", "Cyclist"],
"model_to_benchmark_class_mapping": {
"Vehicle": "Car",
"Pedestrian": "Pedestrian",
"Cyclist": "Cyclist",
},
"metrics": [
"bev-map",
"3d-map",
"center-error-m",
"range-error-m",
"yaw-error-rad",
"distance-bucket-recall",
"false-occupied-rate",
"end-to-end-latency-ms",
],
"metric_contract": {
"official_kitti_server_metric": False,
"evaluation_kind": "public-cross-domain-transfer-probe",
"ap_interpolation": "40-point",
"difficulty_filtering": False,
"predictions_outside_shared_range_ignored": True,
"iou_thresholds": {
"Car": 0.7,
"Pedestrian": 0.5,
"Cyclist": 0.5,
},
"distance_buckets_m": [[0, 20], [20, 40], [40, 70]],
},
"native_accuracy_claim_allowed": False,
"retuning_allowed": False,
},
"k1_transfer_stability": {
"requires_completed_public_cross_domain_probe": True,
"metrics": [
"input-admission-rate",
"output-schema-valid-rate",
"deterministic-replay-rate",
"end-to-end-latency-ms",
"queue-wait-ms",
"drop-rate",
],
"accuracy_claim_allowed": False,
"retuning_allowed": False,
},
"authority": {
"shadow_only": True,
"commands_enabled": False,
"navigation_or_safety_accepted": False,
},
}
def _semantic_dataset(dataset_id: str = "goose-3d/v2025-08-22") -> dict[str, Any]:
return {
"dataset_id": dataset_id,
"installed": True,
"release_identity_sha256": SHA,
"license": "CC-BY-SA-4.0",
"point_fields": ["x", "y", "z", "intensity"],
"annotations": ["point-semantic-labels", "point-instance-labels"],
"splits": ["validation"],
"independent_ground_truth": True,
}
def _box_dataset(*, installed: bool = True) -> dict[str, Any]:
return {
"dataset_id": "kitti-3d-object-detection/v1",
"installed": installed,
"release_identity_sha256": SHA if installed else None,
"license": "CC-BY-NC-SA-3.0",
"point_fields": ["x", "y", "z", "intensity"],
"annotations": ["oriented-3d-boxes"],
"splits": ["validation"],
"independent_ground_truth": True,
}
def _worker(*, pointpillars: bool = False) -> dict[str, Any]:
models: list[dict[str, Any]] = [
{
"name": "yolox_s",
"backend": "onnxruntime",
"artifact_sha256": SHA,
}
]
if pointpillars:
models.append(
{
"name": "pointpillars",
"upstream_version": "tao-6.26.03-test",
"source_model_sha256": "c" * 64,
"source_label_sha256": "e" * 64,
"source_format": "onnx",
"backend": "tensorrt",
"precision": "strongly-typed",
"artifact_sha256": "b" * 64,
"engine_built_on_target": True,
"provenance_verified": True,
"input_fields": ["x", "y", "z", "intensity"],
"maximum_points": 204_800,
"point_cloud_range": [
-51.20000076293945,
-51.20000076293945,
-1.399999976158142,
51.20000076293945,
51.20000076293945,
4.400000095367432,
],
"model_classes": ["Vehicle", "Pedestrian", "Cyclist"],
"outputs": [
{
"name": "output_boxes",
"dtype": "FP32",
"shape": [1, 393_216, 9],
},
{"name": "num_boxes", "dtype": "INT32", "shape": [1]},
],
"representation_smoke": {
"status": "engine-executed",
"input_artifact_sha256": "d" * 64,
"input_point_count": 169_883,
"single_query_gpu_compute_ms": 55.0,
"accuracy_evaluated": False,
"navigation_or_safety_accepted": False,
},
}
)
return {
"schema_version": "missioncore.l3-worker-inventory/v1",
"host_id": "worker-006",
"observed_at_utc": "2026-07-30T20:57:38Z",
"serving_stack_count": 1,
"staged_models": [],
"triton": {
"container_name": "ndc-mission-core-triton",
"image": "nvcr.io/nvidia/tritonserver:26.06-py3",
"image_digest": TRITON_SHA,
"healthy": True,
"strict_readiness": True,
"model_control_mode": "explicit",
"model_repository_read_only": True,
"models": models,
},
"gpu": {
"name": "NVIDIA GeForce RTX 4090",
"driver_version": "610.47",
"memory_total_mib": 24_564,
},
}
def _write(path: Path, value: object) -> None:
path.write_text(json.dumps(value), encoding="utf-8")
def _build(
tmp_path: Path,
*,
profile: dict[str, Any] | None = None,
datasets: list[dict[str, Any]] | None = None,
worker: dict[str, Any] | None = None,
):
profile_path = tmp_path / "profile.json"
datasets_path = tmp_path / "datasets.json"
worker_path = tmp_path / "worker.json"
_write(profile_path, profile or _profile())
_write(
datasets_path,
{
"schema_version": "missioncore.l3-lidar-dataset-inventory/v1",
"observed_at_utc": "2026-07-30T20:57:38Z",
"datasets": datasets or [_semantic_dataset()],
},
)
_write(worker_path, worker or _worker())
return build_l3_pointpillars_admission(
profile_path=profile_path,
dataset_inventory_path=datasets_path,
worker_inventory_path=worker_path,
output_root=tmp_path / "results",
)
def test_semantic_point_truth_and_missing_model_block_public_probe(
tmp_path: Path,
) -> None:
result = _build(tmp_path)
assert result.report["status"] == "blocked-foundation-assets"
assert result.report["blocker_codes"] == [
"public-oriented-3d-box-truth-not-admitted",
"pointpillars-compatible-candidate-not-frozen",
]
assert result.report["next_gate"] == (
"admit-public-3d-box-split-and-freeze-compatible-pointpillars-candidate"
)
assert result.public_transfer_probe_authorized is False
finding = result.report["dataset_findings"][0]
assert finding["semantic_or_instance_labels_are_not_boxes"] is True
assert finding["oriented_3d_box_accuracy_eligible"] is False
assert (
result.report["decision"]["semantic_point_labels_substitute_for_3d_boxes"]
is False
)
assert result.report["decision"]["k1_transfer_stability_authorized"] is False
def test_box_truth_and_target_built_model_authorize_public_probe_only(
tmp_path: Path,
) -> None:
profile = _profile()
profile["detector"]["candidate_frozen"] = True
profile["detector"]["candidate_model_version"] = "tao-6.26.03-test"
profile["detector"]["candidate_source_sha256"] = "c" * 64
profile["detector"]["candidate_label_sha256"] = "e" * 64
result = _build(
tmp_path,
profile=profile,
datasets=[_semantic_dataset(), _box_dataset()],
worker=_worker(pointpillars=True),
)
assert result.report["status"] == "ready-for-public-cross-domain-probe"
assert result.report["blocker_codes"] == []
assert result.report["eligible_public_probe_dataset_ids"] == [
"kitti-3d-object-detection/v1"
]
assert result.public_transfer_probe_authorized is True
assert result.report["decision"] == {
"public_cross_domain_probe_authorized": True,
"native_model_accuracy_claim_authorized": False,
"k1_transfer_stability_authorized": False,
"k1_transfer_quality_claim_authorized": False,
"semantic_point_labels_substitute_for_3d_boxes": False,
"fine_tuning_allowed": False,
"second_serving_stack_allowed": False,
"lab_publication_allowed": False,
"centerpoint_comparison_allowed": False,
}
assert result.report["next_gate"] == (
"run-public-cross-domain-pointpillars-probe"
)
def test_pointpillars_without_target_engine_provenance_remains_blocked(
tmp_path: Path,
) -> None:
profile = _profile()
profile["detector"]["candidate_frozen"] = True
profile["detector"]["candidate_model_version"] = "tao-6.26.03-test"
profile["detector"]["candidate_source_sha256"] = "c" * 64
profile["detector"]["candidate_label_sha256"] = "e" * 64
worker = _worker(pointpillars=True)
worker["triton"]["models"][1]["engine_built_on_target"] = False
result = _build(
tmp_path,
profile=profile,
datasets=[_box_dataset()],
worker=worker,
)
assert result.report["blocker_codes"] == [
"pointpillars-target-engine-or-provenance-not-verified"
]
assert result.report["next_gate"] == "verify-target-engine-and-model-provenance"
def test_verified_staged_engine_is_distinct_from_live_install(tmp_path: Path) -> None:
profile = _profile()
profile["detector"]["candidate_frozen"] = True
profile["detector"]["candidate_model_version"] = "tao-6.26.03-test"
profile["detector"]["candidate_source_sha256"] = "c" * 64
profile["detector"]["candidate_label_sha256"] = "e" * 64
worker = _worker(pointpillars=True)
staged = worker["triton"]["models"].pop()
worker["staged_models"] = [staged]
result = _build(
tmp_path,
profile=profile,
datasets=[_box_dataset(installed=False)],
worker=worker,
)
assert result.report["blocker_codes"] == [
"public-oriented-3d-box-truth-not-admitted",
"pointpillars-model-not-installed-live",
]
assert result.report["detector"]["staged_target_engine_ready"] is True
assert result.report["detector"]["model_ready"] is False
assert result.report["next_gate"] == (
"admit-public-3d-box-split-then-install-staged-pointpillars-model"
)
def test_second_serving_stack_is_rejected(tmp_path: Path) -> None:
profile = _profile()
profile["detector"]["candidate_frozen"] = True
profile["detector"]["candidate_model_version"] = "tao-6.26.03-test"
profile["detector"]["candidate_source_sha256"] = "c" * 64
profile["detector"]["candidate_label_sha256"] = "e" * 64
worker = _worker(pointpillars=True)
worker["serving_stack_count"] = 2
result = _build(
tmp_path,
profile=profile,
datasets=[_box_dataset()],
worker=worker,
)
assert result.report["blocker_codes"] == [
"canonical-triton-runtime-policy-not-satisfied"
]
assert result.report["runtime_checks"]["second_serving_stack_absent"] is False
assert result.report["decision"]["second_serving_stack_allowed"] is False
def test_profile_cannot_skip_the_public_transfer_probe(tmp_path: Path) -> None:
profile = copy.deepcopy(_profile())
profile["k1_transfer_stability"][
"requires_completed_public_cross_domain_probe"
] = False
with pytest.raises(L3PointPillarsAdmissionError):
_build(tmp_path, profile=profile)
def test_result_is_content_addressed_and_detects_tampering(tmp_path: Path) -> None:
first = _build(tmp_path)
second = _build(tmp_path)
assert first.result_id == second.result_id
report_path = first.result_root / "admission-report.json"
report = json.loads(report_path.read_text(encoding="utf-8"))
report["status"] = "changed"
_write(report_path, report)
with pytest.raises(L3PointPillarsAdmissionError):
read_l3_pointpillars_admission(first.result_root)
@@ -0,0 +1,82 @@
from __future__ import annotations
import importlib.util
import json
from pathlib import Path
from types import ModuleType
import pytest
def _load_builder() -> ModuleType:
path = (
Path(__file__).resolve().parents[1]
/ "experiments/perception/prepare_l3_pointpillars_worker_package.py"
)
specification = importlib.util.spec_from_file_location(
"l3_pointpillars_worker_package_test",
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_builds_and_reopens_minimal_content_addressed_package(
tmp_path: Path,
) -> None:
builder = _load_builder()
repository = Path(__file__).resolve().parents[1]
admission = tmp_path / (
"l3-pointpillars-admission-" + ("a" * 64)
)
admission.mkdir()
(admission / "manifest.json").write_text("{}\n", encoding="utf-8")
(admission / "admission-report.json").write_text("{}\n", encoding="utf-8")
package = builder.build_l3_worker_package(
repository_root=repository,
output_root=tmp_path / "packages",
admission_result=admission,
)
reopened = builder.build_l3_worker_package(
repository_root=repository,
output_root=tmp_path / "packages",
admission_result=admission,
)
manifest = builder.validate_l3_worker_package(package)
assert reopened == package
assert manifest["package_id"] == package.name
assert manifest["identity"]["execution_policy"] == {
"sequential": True,
"parallel_workers": 1,
"existing_triton_only": True,
"container_creation_allowed": False,
"container_restart_allowed": False,
"raw_tensor_export_allowed": False,
}
assert not (package / "runtime/k1link/compute/__pycache__").exists()
assert (
package / "runtime/k1link/datasets/kitti_3d_admission.py"
).is_file()
def test_validation_rejects_modified_member(tmp_path: Path) -> None:
builder = _load_builder()
repository = Path(__file__).resolve().parents[1]
package = builder.build_l3_worker_package(
repository_root=repository,
output_root=tmp_path / "packages",
)
target = package / "input/profile.json"
profile = json.loads(target.read_text(encoding="utf-8"))
profile["profile_id"] = "changed"
target.write_text(json.dumps(profile), encoding="utf-8")
with pytest.raises(
builder.L3WorkerPackageError,
match="artifact changed",
):
builder.validate_l3_worker_package(package)
@@ -0,0 +1,90 @@
from __future__ import annotations
import importlib.util
import json
from pathlib import Path
from types import ModuleType
import numpy as np
import pytest
def _load_worker() -> ModuleType:
path = (
Path(__file__).resolve().parents[1]
/ "experiments/perception/worker/run_l3_pointpillars_public_baseline.py"
)
specification = importlib.util.spec_from_file_location(
"l3_pointpillars_worker_test",
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
class _Response:
def __init__(self, payload: bytes, header_length: int) -> None:
self._payload = payload
self.headers = {"Inference-Header-Content-Length": str(header_length)}
self.status = 200
def __enter__(self) -> _Response:
return self
def __exit__(self, *_args: object) -> None:
return None
def read(self) -> bytes:
return self._payload
def test_binary_triton_response_parses_both_outputs(
monkeypatch: pytest.MonkeyPatch,
) -> None:
worker = _load_worker()
boxes = np.zeros((1, 393_216, 9), dtype=np.float32)
boxes[0, 0] = np.asarray(
[10.0, 0.0, 0.0, 4.0, 2.0, 1.5, 0.0, 0.0, 0.9],
dtype=np.float32,
)
count = np.asarray([1], dtype=np.int32)
count_bytes = count.tobytes()
boxes_bytes = boxes.tobytes()
header = json.dumps(
{
"outputs": [
{
"name": "num_boxes",
"datatype": "INT32",
"shape": [1],
"parameters": {"binary_data_size": len(count_bytes)},
},
{
"name": "output_boxes",
"datatype": "FP32",
"shape": [1, 393_216, 9],
"parameters": {"binary_data_size": len(boxes_bytes)},
},
]
},
separators=(",", ":"),
).encode()
payload = header + count_bytes + boxes_bytes
monkeypatch.setattr(
worker.urllib.request,
"urlopen",
lambda *_args, **_kwargs: _Response(payload, len(header)),
)
output_boxes, output_count, elapsed_ms = worker._infer(
"http://127.0.0.1:8000",
np.zeros((1, 204_800, 4), dtype=np.float32),
np.asarray([1], dtype=np.int32),
)
assert output_boxes.shape == (1, 393_216, 9)
assert output_count.tolist() == [1]
assert output_boxes[0, 0, 8] == pytest.approx(0.9)
assert elapsed_ms > 0.0
+136
View File
@@ -0,0 +1,136 @@
from __future__ import annotations
import math
import numpy as np
import pytest
from k1link.compute.pointpillars_postprocess import (
PointPillarsBox,
PointPillarsPostprocessError,
decode_pointpillars_output,
oriented_3d_iou,
oriented_bev_iou,
)
def _outputs(rows: list[list[float]]) -> tuple[np.ndarray, np.ndarray]:
boxes = np.zeros((1, 393_216, 9), dtype=np.float32)
boxes[0, : len(rows)] = np.asarray(rows, dtype=np.float32)
return boxes, np.asarray([len(rows)], dtype=np.int32)
def _row(
*,
x: float,
y: float = 0.0,
length: float = 4.0,
width: float = 2.0,
yaw: float = 0.0,
class_id: int = 0,
score: float = 0.9,
) -> list[float]:
return [x, y, 0.0, length, width, 1.5, yaw, float(class_id), score]
def _box(*, yaw: float = 0.0, x: float = 0.0) -> PointPillarsBox:
return PointPillarsBox(
x_m=x,
y_m=0.0,
z_m=0.0,
length_m=4.0,
width_m=2.0,
height_m=1.5,
yaw_rad=yaw,
class_id=0,
model_class="Vehicle",
score=0.9,
)
def test_decodes_native_label_order_and_sorts_by_score() -> None:
output_boxes, num_boxes = _outputs(
[
_row(x=20.0, class_id=2, score=0.6),
_row(x=0.0, class_id=0, score=0.9),
_row(x=10.0, class_id=1, score=0.8),
]
)
decoded = decode_pointpillars_output(output_boxes, num_boxes)
assert [box.model_class for box in decoded] == [
"Vehicle",
"Pedestrian",
"Cyclist",
]
assert [box.score for box in decoded] == pytest.approx([0.9, 0.8, 0.6])
def test_nms_reproduces_nvidia_sample_class_agnostic_suppression() -> None:
output_boxes, num_boxes = _outputs(
[
_row(x=0.0, class_id=0, score=0.9),
_row(x=0.1, class_id=1, score=0.8),
_row(x=20.0, class_id=1, score=0.7),
]
)
decoded = decode_pointpillars_output(output_boxes, num_boxes)
assert [(box.x_m, box.model_class) for box in decoded] == [
(0.0, "Vehicle"),
(20.0, "Pedestrian"),
]
def test_pre_nms_cap_is_applied_after_stable_score_ordering() -> None:
output_boxes, num_boxes = _outputs(
[
_row(x=0.0, score=0.7),
_row(x=10.0, score=0.9),
_row(x=20.0, score=0.8),
]
)
decoded = decode_pointpillars_output(
output_boxes,
num_boxes,
pre_nms_top_n=2,
)
assert [box.x_m for box in decoded] == [10.0, 20.0]
def test_oriented_bev_iou_handles_rotation_and_separation() -> None:
assert oriented_bev_iou(_box(), _box()) == pytest.approx(1.0)
assert oriented_bev_iou(_box(), _box(yaw=math.pi / 2.0)) == pytest.approx(
1.0 / 3.0
)
assert oriented_bev_iou(_box(), _box(x=20.0)) == 0.0
assert oriented_3d_iou(_box(), _box()) == pytest.approx(1.0)
assert oriented_3d_iou(_box(), _box(x=20.0)) == 0.0
@pytest.mark.parametrize(
("row", "message"),
[
(_row(x=0.0, class_id=3), "class id"),
(_row(x=0.0, length=0.0), "dimensions or score"),
(_row(x=0.0, score=0.09), "dimensions or score"),
(_row(x=0.0, score=1.1), "dimensions or score"),
],
)
def test_invalid_candidate_fails_closed(row: list[float], message: str) -> None:
output_boxes, num_boxes = _outputs([row])
with pytest.raises(PointPillarsPostprocessError, match=message):
decode_pointpillars_output(output_boxes, num_boxes)
def test_output_tensor_contract_is_exact() -> None:
with pytest.raises(PointPillarsPostprocessError, match="output_boxes contract"):
decode_pointpillars_output(
np.zeros((1, 1, 9), dtype=np.float32),
np.asarray([0], dtype=np.int32),
)