perf(perception): phase vegetation behind safety
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-shadow-profile/v3",
|
||||
"profile_id": "lab-v1-ravnoves00-ddrnet-m49-integrated-multirate-phased-shadow/v3",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"expected_timeline_frames": 4489,
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"shared_start_barrier": true,
|
||||
"ground_truth_available": false
|
||||
},
|
||||
"stages": {
|
||||
"m49_graph_tgs": {
|
||||
"profile": "m49-tgs-integrated-graph-shadow-v1.json",
|
||||
"profile_sha256": "b61e018b2d04eec58802e2d4186ce7a3dd3a15b254db106b57b609e903eeef80",
|
||||
"candidate": "frozen-native-rf-detr-plus-cpu-tgs",
|
||||
"parameters_unchanged": true,
|
||||
"timeline_rate_hz": 12.0
|
||||
},
|
||||
"vegetation": {
|
||||
"candidate_id": "ddrnet_39-goose-fine-64",
|
||||
"candidate_key": "ddrnet",
|
||||
"checkpoint_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
|
||||
"config_sha256": "96a427a8baae387b827ec9c0bf7ca42e3fb9114b8fa9a8671bbc9d10877670b9",
|
||||
"policy_sha256": "b75c4ac841d7b4bcc57f7a9c8417ca2317d8ecfa499e72a9af8a8591a2ec0d35",
|
||||
"provider_map_sha256": "f2b69046b6a740fd9532d2d88e7fabae7c20fb662f783c9502adc9026406f352",
|
||||
"container_image": "ndc/mission-core-lab-v1-goose:sg3.2.0-cu117-v1",
|
||||
"container_image_id": "sha256:591cb382c099eeb05e7ec16e2371e0b2da54d2bb5c49ec0f4ac88dbf72b0f0cd",
|
||||
"timeline_rate_hz": 12.0,
|
||||
"inference_rate_hz": 6.0,
|
||||
"inference_stride": 2,
|
||||
"inference_phase_offset_ms": 40.0,
|
||||
"held_evidence_fail_closed": true,
|
||||
"semantic_output_persisted": false,
|
||||
"one_heavy_vegetation_candidate_at_a_time": true
|
||||
}
|
||||
},
|
||||
"acceptance": {
|
||||
"minimum_graph_world_state_fps": 11.209069,
|
||||
"minimum_vegetation_timeline_fps": 11.209069,
|
||||
"minimum_vegetation_inference_fps": 5.604534,
|
||||
"maximum_vegetation_inference_completion_p95_ms": 125.0,
|
||||
"maximum_semantic_evidence_source_age_ms": 125.0,
|
||||
"maximum_combined_output_age_p99_ms": 125.0,
|
||||
"capacity_drop_count_max": 0,
|
||||
"unaccounted_frame_count_max": 0
|
||||
},
|
||||
"telemetry": {
|
||||
"sample_interval_seconds": 1.0,
|
||||
"required_roles": [
|
||||
"graph",
|
||||
"triton",
|
||||
"tgs",
|
||||
"vegetation"
|
||||
]
|
||||
},
|
||||
"invariants": {
|
||||
"raw_fisheye_immutable": true,
|
||||
"reference_graph_parameters_unchanged": true,
|
||||
"tgs_parameters_unchanged": true,
|
||||
"ddrnet_parameters_unchanged": true,
|
||||
"safety_layers_remain_12hz": true,
|
||||
"vegetation_gpu_phase_follows_safety_detector": true,
|
||||
"held_semantic_evidence_is_advisory_only": true,
|
||||
"vegetation_source_buffer_bounded": true,
|
||||
"vegetation_full_route_rgb_prefetch_allowed": false,
|
||||
"ppliteseg_concurrent_run_allowed": false,
|
||||
"camera_semantics_can_clear_rigid_geometry": false,
|
||||
"canonical_triton_mutation_allowed": false,
|
||||
"runtime_shared_source_frame_target": true,
|
||||
"gauss_or_playcanvas_in_scope": false
|
||||
},
|
||||
"authority": {
|
||||
"visual_quality_accepted": false,
|
||||
"route_truth_available": false,
|
||||
"traversability_accepted": false,
|
||||
"physical_free_space_accepted": false,
|
||||
"commands_enabled": false,
|
||||
"actuation_allowed": false,
|
||||
"navigation_or_safety_accepted": false,
|
||||
"production_accepted": false
|
||||
}
|
||||
}
|
||||
@@ -148,12 +148,12 @@ foreach ($directory in @("bin", "control", "graph", "tgs", "vegetation")) {
|
||||
|
||||
$releaseDocument = Get-Content -LiteralPath (Join-Path $payload "release.json") -Raw | ConvertFrom-Json
|
||||
$expectedReleaseSchema = if ($VegetationLoadGate) {
|
||||
"missioncore.lab-v1-vegetation-integrated-worker-release/v2"
|
||||
"missioncore.lab-v1-vegetation-integrated-worker-release/v3"
|
||||
} else {
|
||||
"missioncore.m49-tgs-integrated-graph-worker-release/v1"
|
||||
}
|
||||
$expectedTransition = if ($VegetationLoadGate) {
|
||||
"lab-v1-vegetation-m49-integrated-multirate-shadow/v2"
|
||||
"lab-v1-vegetation-m49-integrated-multirate-phased-shadow/v3"
|
||||
} else {
|
||||
"m49-tgs-native-risk-integrated-shadow/v1"
|
||||
}
|
||||
@@ -413,6 +413,7 @@ try {
|
||||
--runtime-video-cache /tmp/vegetation-right.mp4 `
|
||||
--source-rate-hz $rate `
|
||||
--inference-stride 2 `
|
||||
--inference-phase-offset-ms 40.0 `
|
||||
--minimum-effective-timeline-fps 11.209069 `
|
||||
--minimum-effective-inference-fps 5.604534 `
|
||||
--maximum-inference-completion-p95-ms 125.0 `
|
||||
@@ -562,7 +563,7 @@ try {
|
||||
--volume ($dockerRelease + ":/release:ro") `
|
||||
--volume ($dockerRun + ":/shared:rw") `
|
||||
$ParityImageTag /release/build_vegetation_integrated_graph_evidence.py `
|
||||
--profile /release/lab-v1-vegetation-integrated-multirate-shadow-v2.json `
|
||||
--profile /release/lab-v1-vegetation-integrated-multirate-phased-shadow-v3.json `
|
||||
--m49-result /shared/m49-result.json `
|
||||
--graph-frames /shared/graph/frames.jsonl `
|
||||
--tgs-timing /shared/tgs/tgs-full-timing.tsv `
|
||||
@@ -591,7 +592,7 @@ if (-not (Test-Path -LiteralPath $resultPath -PathType Leaf)) {
|
||||
$result = Get-Content -LiteralPath $resultPath -Raw | ConvertFrom-Json
|
||||
$summary = [ordered]@{
|
||||
schema_version = if ($VegetationLoadGate) {
|
||||
"missioncore.lab-v1-vegetation-integrated-worker-summary/v2"
|
||||
"missioncore.lab-v1-vegetation-integrated-worker-summary/v3"
|
||||
} else {
|
||||
"missioncore.m49-tgs-integrated-graph-worker-summary/v1"
|
||||
}
|
||||
|
||||
+20
-3
@@ -28,7 +28,7 @@ from run_goose_vegetation_benchmark import (
|
||||
validate_contracts,
|
||||
)
|
||||
|
||||
SCHEMA = "missioncore.lab-v1-vegetation-integrated-load/v2"
|
||||
SCHEMA = "missioncore.lab-v1-vegetation-integrated-load/v3"
|
||||
FRAME_SCHEMA = "missioncore.lab-v1-vegetation-integrated-frame/v2"
|
||||
FRAME_COUNT = 4_489
|
||||
AUTHORITY = {
|
||||
@@ -58,6 +58,7 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--runtime-video-cache", type=Path, required=True)
|
||||
parser.add_argument("--source-rate-hz", type=float, required=True)
|
||||
parser.add_argument("--inference-stride", type=int, required=True)
|
||||
parser.add_argument("--inference-phase-offset-ms", type=float, required=True)
|
||||
parser.add_argument("--minimum-effective-timeline-fps", type=float, required=True)
|
||||
parser.add_argument("--minimum-effective-inference-fps", type=float, required=True)
|
||||
parser.add_argument("--maximum-inference-completion-p95-ms", type=float, required=True)
|
||||
@@ -154,6 +155,12 @@ def run() -> int:
|
||||
not math.isfinite(value) or value <= 0 for value in positive_finite_values
|
||||
):
|
||||
raise IntegratedLoadError("integrated-load thresholds must be positive and finite")
|
||||
if (
|
||||
not math.isfinite(args.inference_phase_offset_ms)
|
||||
or args.inference_phase_offset_ms < 0
|
||||
or args.inference_phase_offset_ms >= 1000.0 / args.source_rate_hz
|
||||
):
|
||||
raise IntegratedLoadError("inference phase offset must fit inside one source interval")
|
||||
validate_sha256(args.release_sha256, "release")
|
||||
validate_sha256(args.video_sha256, "video")
|
||||
if args.output.exists() or args.frame_ledger.exists():
|
||||
@@ -210,12 +217,15 @@ def run() -> int:
|
||||
with args.frame_ledger.open("x", encoding="utf-8") as ledger:
|
||||
for sequence in range(FRAME_COUNT):
|
||||
scheduled_ns = start_ns + round(sequence * interval_ns)
|
||||
remaining_ns = scheduled_ns - time.monotonic_ns()
|
||||
inference_executed = sequence % args.inference_stride == 0
|
||||
execution_target_ns = scheduled_ns
|
||||
if inference_executed:
|
||||
execution_target_ns += round(args.inference_phase_offset_ms * 1_000_000.0)
|
||||
remaining_ns = execution_target_ns - time.monotonic_ns()
|
||||
if remaining_ns > 0:
|
||||
time.sleep(remaining_ns / 1_000_000_000.0)
|
||||
admitted_ns = time.monotonic_ns()
|
||||
source = decode_source(source_capture, expected_size)
|
||||
inference_executed = sequence % args.inference_stride == 0
|
||||
inference_ms: float | None = None
|
||||
if inference_executed:
|
||||
tensor, _ = preprocess(source)
|
||||
@@ -253,6 +263,9 @@ def run() -> int:
|
||||
"completion_age_ms": round(completion_age_ms, 6),
|
||||
"stage_ms": round(stage_ms, 6),
|
||||
"inference_executed": inference_executed,
|
||||
"inference_phase_offset_ms": args.inference_phase_offset_ms
|
||||
if inference_executed
|
||||
else 0.0,
|
||||
"inference_ms": round(inference_ms, 6) if inference_ms is not None else None,
|
||||
"semantic_source_sequence": last_inference_sequence,
|
||||
"semantic_evidence_source_age_ms": round(evidence_source_age_ms, 6),
|
||||
@@ -276,6 +289,8 @@ def run() -> int:
|
||||
checks = {
|
||||
"all_frames_accounted": len(completion_ages_ms) == FRAME_COUNT,
|
||||
"exact_multirate_schedule": inference_frame_count == expected_inference_frames,
|
||||
"inference_phase_offset_preserved": args.inference_phase_offset_ms
|
||||
< 1000.0 / args.source_rate_hz,
|
||||
"minimum_effective_timeline_fps": effective_timeline_fps
|
||||
>= args.minimum_effective_timeline_fps,
|
||||
"minimum_effective_inference_fps": effective_inference_fps
|
||||
@@ -313,6 +328,7 @@ def run() -> int:
|
||||
"effective_timeline_fps": round(effective_timeline_fps, 6),
|
||||
"effective_inference_fps": round(effective_inference_fps, 6),
|
||||
"inference_stride": args.inference_stride,
|
||||
"inference_phase_offset_ms": args.inference_phase_offset_ms,
|
||||
"inference_frame_count": inference_frame_count,
|
||||
"held_evidence_frame_count": FRAME_COUNT - inference_frame_count,
|
||||
"frame_count": FRAME_COUNT,
|
||||
@@ -360,6 +376,7 @@ def run() -> int:
|
||||
"predeclared_thresholds": {
|
||||
"minimum_effective_timeline_fps": args.minimum_effective_timeline_fps,
|
||||
"minimum_effective_inference_fps": args.minimum_effective_inference_fps,
|
||||
"inference_phase_offset_ms": args.inference_phase_offset_ms,
|
||||
"maximum_inference_completion_p95_ms": (
|
||||
args.maximum_inference_completion_p95_ms
|
||||
),
|
||||
|
||||
+29
-4
@@ -15,10 +15,10 @@ from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
PROFILE_SCHEMA = "missioncore.lab-v1-vegetation-integrated-shadow-profile/v2"
|
||||
PROFILE_SCHEMA = "missioncore.lab-v1-vegetation-integrated-shadow-profile/v3"
|
||||
M49_SCHEMA = "missioncore.m49-tgs-integrated-graph-shadow-result/v1"
|
||||
VEGETATION_SCHEMA = "missioncore.lab-v1-vegetation-integrated-load/v2"
|
||||
RESULT_SCHEMA = "missioncore.lab-v1-vegetation-integrated-shadow-result/v2"
|
||||
VEGETATION_SCHEMA = "missioncore.lab-v1-vegetation-integrated-load/v3"
|
||||
RESULT_SCHEMA = "missioncore.lab-v1-vegetation-integrated-shadow-result/v3"
|
||||
FRAME_COUNT = 4_489
|
||||
|
||||
|
||||
@@ -93,7 +93,11 @@ def tgs_completion_ages(path: Path) -> list[float]:
|
||||
|
||||
|
||||
def vegetation_frame_metrics(
|
||||
path: Path, *, inference_stride: int, source_rate_hz: float
|
||||
path: Path,
|
||||
*,
|
||||
inference_stride: int,
|
||||
inference_phase_offset_ms: float,
|
||||
source_rate_hz: float,
|
||||
) -> dict[str, object]:
|
||||
completion_ages: list[float] = []
|
||||
evidence_source_ages: list[float] = []
|
||||
@@ -112,6 +116,12 @@ def vegetation_frame_metrics(
|
||||
expected_inference = expected % inference_stride == 0
|
||||
if inference_executed is not expected_inference:
|
||||
raise VegetationIntegratedError("vegetation inference schedule changed")
|
||||
expected_phase = inference_phase_offset_ms if expected_inference else 0.0
|
||||
phase = row.get("inference_phase_offset_ms")
|
||||
if not isinstance(phase, (int, float)) or float(phase) != expected_phase:
|
||||
raise VegetationIntegratedError("vegetation inference phase changed")
|
||||
if expected_inference and float(age) + 0.001 < expected_phase:
|
||||
raise VegetationIntegratedError("vegetation inference phase attribution changed")
|
||||
expected_source = expected - (expected % inference_stride)
|
||||
if row.get("semantic_source_sequence") != expected_source:
|
||||
raise VegetationIntegratedError("vegetation evidence source changed")
|
||||
@@ -231,11 +241,24 @@ def build(
|
||||
|
||||
source_rate_hz = float(profile["source"]["requested_source_rate_hz"])
|
||||
inference_stride = int(profile["stages"]["vegetation"]["inference_stride"])
|
||||
inference_phase_offset_ms = float(
|
||||
profile["stages"]["vegetation"]["inference_phase_offset_ms"]
|
||||
)
|
||||
if (
|
||||
not math.isfinite(source_rate_hz)
|
||||
or source_rate_hz <= 0
|
||||
or inference_stride <= 0
|
||||
or not math.isfinite(inference_phase_offset_ms)
|
||||
or inference_phase_offset_ms < 0
|
||||
or inference_phase_offset_ms >= 1000.0 / source_rate_hz
|
||||
):
|
||||
raise VegetationIntegratedError("vegetation multirate schedule is invalid")
|
||||
graph_ages = graph_completion_ages(graph_frames_path)
|
||||
tgs_ages = tgs_completion_ages(tgs_timing_path)
|
||||
vegetation_frames = vegetation_frame_metrics(
|
||||
vegetation_frames_path,
|
||||
inference_stride=inference_stride,
|
||||
inference_phase_offset_ms=inference_phase_offset_ms,
|
||||
source_rate_hz=source_rate_hz,
|
||||
)
|
||||
vegetation_ages = vegetation_frames["completion_ages"]
|
||||
@@ -280,6 +303,8 @@ def build(
|
||||
"vegetation_load_gate_passed": vegetation.get("integrated_load_gate_passed") is True,
|
||||
"vegetation_multirate_schedule_frozen": (
|
||||
vegetation_execution.get("inference_stride") == inference_stride
|
||||
and vegetation_execution.get("inference_phase_offset_ms")
|
||||
== inference_phase_offset_ms
|
||||
and vegetation_execution.get("inference_frame_count")
|
||||
== vegetation_frames["inference_count"]
|
||||
and vegetation_execution.get("held_evidence_frame_count")
|
||||
|
||||
@@ -46,7 +46,7 @@ SOURCES = M49_SOURCES + (
|
||||
Path("config/perception/lab-v1-goose-vegetation-benchmark-v1.json"),
|
||||
Path("config/perception/lab-v1-vegetation-mission-policy-v1.json"),
|
||||
Path("config/perception/lab-v1-vegetation-provider-label-map-v1.json"),
|
||||
Path("config/perception/lab-v1-vegetation-integrated-multirate-shadow-v2.json"),
|
||||
Path("config/perception/lab-v1-vegetation-integrated-multirate-phased-shadow-v3.json"),
|
||||
)
|
||||
|
||||
|
||||
@@ -85,9 +85,9 @@ def build_artifact(
|
||||
wheel_destination.write_bytes(wheel.read_bytes())
|
||||
copied.append(wheel_destination)
|
||||
release = {
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-worker-release/v2",
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-worker-release/v3",
|
||||
"patch_id": patch_id,
|
||||
"transition": "lab-v1-vegetation-m49-integrated-multirate-shadow/v2",
|
||||
"transition": "lab-v1-vegetation-m49-integrated-multirate-phased-shadow/v3",
|
||||
"code_revision": selected_revision,
|
||||
"worker_id": "worker-006",
|
||||
"source_pack_sha256": (
|
||||
@@ -100,6 +100,7 @@ def build_artifact(
|
||||
"requested_source_rate_hz": 12.0,
|
||||
"semantic_inference_rate_hz": 6.0,
|
||||
"semantic_inference_stride": 2,
|
||||
"semantic_inference_phase_offset_ms": 40.0,
|
||||
"native_engine_sha256": (
|
||||
"b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695"
|
||||
),
|
||||
|
||||
@@ -55,6 +55,7 @@ def test_three_layer_gate_joins_exact_frames_and_preserves_false_authority(
|
||||
"policy_sha256": "d" * 64,
|
||||
"provider_map_sha256": "e" * 64,
|
||||
"inference_stride": 2,
|
||||
"inference_phase_offset_ms": 40.0,
|
||||
},
|
||||
},
|
||||
"acceptance": {
|
||||
@@ -115,6 +116,7 @@ def test_three_layer_gate_joins_exact_frames_and_preserves_false_authority(
|
||||
"effective_timeline_fps": 11.75,
|
||||
"effective_inference_fps": 5.875,
|
||||
"inference_stride": 2,
|
||||
"inference_phase_offset_ms": 40.0,
|
||||
"inference_frame_count": 2245,
|
||||
"held_evidence_frame_count": 2244,
|
||||
"capacity_drop_count": 0,
|
||||
@@ -160,10 +162,11 @@ def test_three_layer_gate_joins_exact_frames_and_preserves_false_authority(
|
||||
{
|
||||
"schema_version": "missioncore.lab-v1-vegetation-integrated-frame/v2",
|
||||
"sequence": index,
|
||||
"completion_age_ms": 20.0,
|
||||
"completion_age_ms": 60.0 if index % 2 == 0 else 20.0,
|
||||
"inference_executed": index % 2 == 0,
|
||||
"inference_phase_offset_ms": 40.0 if index % 2 == 0 else 0.0,
|
||||
"semantic_source_sequence": index - (index % 2),
|
||||
"semantic_evidence_source_age_ms": 20.0
|
||||
"semantic_evidence_source_age_ms": 60.0
|
||||
if index % 2 == 0
|
||||
else 103.333333,
|
||||
}
|
||||
@@ -205,7 +208,7 @@ def test_three_layer_gate_joins_exact_frames_and_preserves_false_authority(
|
||||
|
||||
assert result["status"] == "passed"
|
||||
assert result["source"]["joined_frame_count"] == EVIDENCE.FRAME_COUNT
|
||||
assert result["performance"]["three_layer_output_age_ms"]["p99"] == 40.0
|
||||
assert result["performance"]["three_layer_output_age_ms"]["p99"] == 60.0
|
||||
assert result["checks"]["authority_remains_false"] is True
|
||||
assert result["production_accepted"] is False
|
||||
|
||||
@@ -242,8 +245,12 @@ def test_integrated_release_is_deterministic_and_contains_one_vegetation_candida
|
||||
release = json.loads(release_stream.read())
|
||||
assert "payload/run_vegetation_integrated_load.py" in names
|
||||
assert "payload/build_vegetation_integrated_graph_evidence.py" in names
|
||||
assert "payload/lab-v1-vegetation-integrated-multirate-shadow-v2.json" in names
|
||||
assert (
|
||||
"payload/lab-v1-vegetation-integrated-multirate-phased-shadow-v3.json"
|
||||
in names
|
||||
)
|
||||
assert release["semantic_inference_rate_hz"] == 6.0
|
||||
assert release["semantic_inference_phase_offset_ms"] == 40.0
|
||||
assert release["scope"]["heavy_vegetation_candidates"] == ["ddrnet"]
|
||||
assert all(value is False for value in release["authority"].values())
|
||||
|
||||
@@ -261,6 +268,7 @@ def test_worker_gate_reuses_shared_barrier_and_keeps_canonical_triton_unchanged(
|
||||
assert '"camera_semantics_can_clear_rigid_geometry": False' in runner
|
||||
assert "--runtime-video-cache /tmp/vegetation-right.mp4" in wrapper
|
||||
assert "--inference-stride 2" in wrapper
|
||||
assert "--inference-phase-offset-ms 40.0" in wrapper
|
||||
assert '--tmpfs "/tmp:rw,noexec,nosuid,size=2g"' in wrapper
|
||||
assert "$VegetationLoadGate" in wrapper
|
||||
assert '"vegetation"' in wrapper
|
||||
|
||||
Reference in New Issue
Block a user