feat(lab): seal full RAVNOVES004TREE semantic review
This commit is contained in:
@@ -187,12 +187,15 @@ Write-Output "PHASE=e4-preflight-complete"
|
||||
$runToken = [Guid]::NewGuid().ToString("N")
|
||||
$workRoot = Join-Path $tmpRoot ("{0}-e4-{1}" -f $job.job_id, $runToken)
|
||||
$framesRoot = Join-Path $workRoot "frames"
|
||||
$decodedFramesRoot = Join-Path $workRoot "decoded-by-pts"
|
||||
$streamPath = Join-Path $workRoot "camera.mp4"
|
||||
$ptsPath = Join-Path $workRoot "pts.json"
|
||||
$packetsPath = Join-Path $workRoot "packets.csv"
|
||||
$decodeRepairPath = Join-Path $workRoot "decode-repair.json"
|
||||
$timelinePath = Join-Path $workRoot "timeline.jsonl"
|
||||
$publishRoot = Join-Path $derivedRoot (".{0}-e4-{1}.publish" -f $job.job_id, $runToken)
|
||||
$stagingRoot = Join-Path $publishRoot "output"
|
||||
$null = New-Item -ItemType Directory -Path $framesRoot
|
||||
$null = New-Item -ItemType Directory -Path $decodedFramesRoot
|
||||
$null = New-Item -ItemType Directory -Path $publishRoot
|
||||
$totalWatch = [Diagnostics.Stopwatch]::StartNew()
|
||||
$completed = $false
|
||||
@@ -230,29 +233,69 @@ try {
|
||||
|
||||
$extractWatch = [Diagnostics.Stopwatch]::StartNew()
|
||||
Write-Output "PHASE=e4-frame-extraction-start"
|
||||
& ffmpeg -hide_banner -loglevel fatal -i $streamPath -map 0:v:0 -fps_mode passthrough -frames:v $activeFrameCount (Join-Path $framesRoot "frame-%06d.png")
|
||||
& ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=pts,flags -of csv=p=0 -o $packetsPath $streamPath
|
||||
Assert-LastExitCode "LAB E4 packet timestamp probe"
|
||||
$packetRows = @(Get-Content -LiteralPath $packetsPath | Select-Object -First $activeFrameCount)
|
||||
if ($packetRows.Count -ne $activeFrameCount) {
|
||||
throw "LAB E4 packet count differs from the requested camera epoch"
|
||||
}
|
||||
|
||||
& ffmpeg -hide_banner -loglevel error `
|
||||
-hwaccel cuda -hwaccel_output_format cuda -c:v h264_cuvid `
|
||||
-err_detect ignore_err -flags +output_corrupt -copyts `
|
||||
-i $streamPath -map 0:v:0 -vf "hwdownload,format=nv12" `
|
||||
-fps_mode passthrough -enc_time_base demux -frames:v $activeFrameCount `
|
||||
-frame_pts 1 (Join-Path $decodedFramesRoot "frame-%d.png")
|
||||
Assert-LastExitCode "LAB E4 camera extraction"
|
||||
& ffprobe -v error -select_streams v:0 -show_entries frame=best_effort_timestamp_time -of json $streamPath | Set-Content -LiteralPath $ptsPath -Encoding utf8
|
||||
Assert-LastExitCode "LAB E4 camera timestamp probe"
|
||||
|
||||
$decodedCount = @(Get-ChildItem -LiteralPath $decodedFramesRoot -File -Filter "frame-*.png").Count
|
||||
$repairs = @()
|
||||
$packetPts = @()
|
||||
for ($index = 0; $index -lt $activeFrameCount; $index++) {
|
||||
$columns = ([string]$packetRows[$index]).Split(",")
|
||||
if ($columns.Count -lt 2) {
|
||||
throw "LAB E4 packet timestamp row is malformed"
|
||||
}
|
||||
$pts = [int64]::Parse($columns[0].Trim(), [Globalization.CultureInfo]::InvariantCulture)
|
||||
$packetPts += $pts
|
||||
$decodedPath = Join-Path $decodedFramesRoot ("frame-{0}.png" -f $pts)
|
||||
$canonicalPath = Join-Path $framesRoot ("frame-{0:D6}.png" -f ($index + 1))
|
||||
if (Test-Path -LiteralPath $decodedPath -PathType Leaf) {
|
||||
Move-Item -LiteralPath $decodedPath -Destination $canonicalPath
|
||||
continue
|
||||
}
|
||||
if ($index -eq 0 -or $repairs.Count -ge 1) {
|
||||
throw "LAB E4 source contains more than one recoverable decoder gap"
|
||||
}
|
||||
$previousPath = Join-Path $framesRoot ("frame-{0:D6}.png" -f $index)
|
||||
Copy-Item -LiteralPath $previousPath -Destination $canonicalPath
|
||||
$repairs += [ordered]@{
|
||||
sequence = $index + 1
|
||||
packet_pts = $pts
|
||||
method = "duplicate-previous-decoded-frame"
|
||||
}
|
||||
}
|
||||
|
||||
$decodedFrames = @(Get-ChildItem -LiteralPath $framesRoot -File -Filter "frame-*.png")
|
||||
$ptsDocument = Get-Content -LiteralPath $ptsPath -Raw | ConvertFrom-Json
|
||||
$pts = @($ptsDocument.frames)
|
||||
if ($decodedFrames.Count -ne $activeFrameCount -or $pts.Count -lt $activeFrameCount) {
|
||||
if ($decodedFrames.Count -ne $activeFrameCount) {
|
||||
throw "Decoded LAB E4 frame count differs from the requested camera epoch"
|
||||
}
|
||||
$firstEpochSeconds = [double]::Parse(
|
||||
([string]$pts[0].best_effort_timestamp_time).Trim(),
|
||||
[Globalization.CultureInfo]::InvariantCulture
|
||||
)
|
||||
$decodeRepair = [ordered]@{
|
||||
schema_version = "missioncore.recorded-video-decode-repair/v1"
|
||||
decoder = "ffmpeg-h264_cuvid-output-corrupt"
|
||||
packets_requested = $activeFrameCount
|
||||
frames_decoded = $decodedCount
|
||||
repaired_frame_count = $repairs.Count
|
||||
repairs = $repairs
|
||||
}
|
||||
$decodeRepair | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $decodeRepairPath -Encoding utf8
|
||||
|
||||
$firstPacketPts = [int64]$packetPts[0]
|
||||
$previousEpochSeconds = -1.0
|
||||
$timelineWriter = [IO.StreamWriter]::new($timelinePath, $false, [Text.UTF8Encoding]::new($false))
|
||||
try {
|
||||
for ($index = 0; $index -lt $activeFrameCount; $index++) {
|
||||
$epochSeconds = [double]::Parse(
|
||||
([string]$pts[$index].best_effort_timestamp_time).Trim(),
|
||||
[Globalization.CultureInfo]::InvariantCulture
|
||||
) - $firstEpochSeconds
|
||||
$epochSeconds = ([int64]$packetPts[$index] - $firstPacketPts) / 90000.0
|
||||
if ($epochSeconds -le $previousEpochSeconds -or $epochSeconds -gt ($timelineDuration + 0.001)) {
|
||||
throw "Decoded LAB E4 timestamps are not strictly monotonic inside the camera timeline"
|
||||
}
|
||||
@@ -313,6 +356,7 @@ try {
|
||||
Write-Output ("PHASE=e4-inference-start FRAMES={0}" -f $activeFrameCount)
|
||||
& docker @runArgs
|
||||
Assert-LastExitCode "LAB E4 semantic inference"
|
||||
Copy-Item -LiteralPath $decodeRepairPath -Destination (Join-Path $stagingRoot "decode-repair.json")
|
||||
$freeBytesPostInference = Assert-FreeSpace "post-inference"
|
||||
Write-Output "PHASE=e4-inference-complete"
|
||||
|
||||
|
||||
@@ -12,7 +12,18 @@ param(
|
||||
|
||||
[string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\experiments\lab-v1-vegetation",
|
||||
|
||||
[string]$RavnovesVideo = "D:\NDC_MISSIONCORE\runtime\experiments\e46e\inputs\right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8.mp4"
|
||||
[string]$RavnovesVideo = "D:\NDC_MISSIONCORE\runtime\experiments\e46e\inputs\right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8.mp4",
|
||||
|
||||
[string]$RavnovesSourceId = "RAVNOVES00/right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
|
||||
|
||||
[string]$RavnovesSha256 = "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
|
||||
|
||||
[ValidateRange(1, 1000000)]
|
||||
[int]$RavnovesExpectedFrameCount = 4489,
|
||||
|
||||
[string]$RavnovesBaseM4ResultId = "m4-threat-replay-2a953c5f27f2a5b1dddc5c658c1de2c323d7796084a099c024987a1da03aa324",
|
||||
|
||||
[string]$RavnovesSourceProfile = ""
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -38,6 +49,31 @@ $configRoot = Join-Path $ToolRoot "config"
|
||||
$benchmarkConfig = Join-Path $configRoot "lab-v1-goose-vegetation-benchmark-v1.json"
|
||||
$policyConfig = Join-Path $configRoot "lab-v1-vegetation-mission-policy-v1.json"
|
||||
$providerMapConfig = Join-Path $configRoot "lab-v1-vegetation-provider-label-map-v1.json"
|
||||
$ravnovesProfileDocument = $null
|
||||
if (-not [string]::IsNullOrWhiteSpace($RavnovesSourceProfile)) {
|
||||
$resolvedProfile = (Resolve-Path -LiteralPath $RavnovesSourceProfile).Path
|
||||
if (-not $resolvedProfile.StartsWith($ToolRoot, [StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "RAVNOVES source profile must stay under ToolRoot"
|
||||
}
|
||||
$ravnovesProfileDocument = Get-Content -LiteralPath $resolvedProfile -Raw | ConvertFrom-Json
|
||||
$source = $ravnovesProfileDocument.source
|
||||
if (
|
||||
$ravnovesProfileDocument.schema_version -ne "missioncore.lab-v1-ravnoves-source/v1" -or
|
||||
$null -eq $source -or
|
||||
[string]::IsNullOrWhiteSpace([string]$source.source_id) -or
|
||||
[string]$source.source_sha256 -notmatch "^[a-f0-9]{64}$" -or
|
||||
[int]$source.expected_width -ne 800 -or
|
||||
[int]$source.expected_height -ne 600 -or
|
||||
[int]$source.expected_frame_count -lt 1 -or
|
||||
[string]$source.crop_contract -ne "center-600-square-to-512; outside-crop-is-undefined"
|
||||
) {
|
||||
throw "RAVNOVES source profile is incompatible"
|
||||
}
|
||||
$RavnovesSourceId = [string]$source.source_id
|
||||
$RavnovesSha256 = [string]$source.source_sha256
|
||||
$RavnovesExpectedFrameCount = [int]$source.expected_frame_count
|
||||
$RavnovesBaseM4ResultId = [string]$source.base_m4_result_id
|
||||
}
|
||||
$datasetRoot = Join-Path $AssetRoot "goose-2d\validation"
|
||||
$checkpointRelative = if ($candidateKey -eq "ddrnet") {
|
||||
"models\goose\ddrnet_class_512.pth"
|
||||
@@ -51,7 +87,6 @@ $expectedCheckpointSha256 = if ($candidateKey -eq "ddrnet") {
|
||||
"6dd412c0c99115e359896c4cab43a8e6bce9e09b843e7fa885fe597b0a6121cd"
|
||||
}
|
||||
$expectedCheckpointBytes = if ($candidateKey -eq "ddrnet") { 259419077 } else { 98208249 }
|
||||
$ravnovesSha256 = "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8"
|
||||
$frameIndices = @(0, 253, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4488)
|
||||
$dockerConfig = "D:\NDC_MISSIONCORE\datasets\state\lab-v1-vegetation\docker-config"
|
||||
|
||||
@@ -110,6 +145,18 @@ function Invoke-IsolatedRun {
|
||||
[string]$FramesRoot = ""
|
||||
)
|
||||
$containerName = "ndc-lab-v1-goose-$candidateKey-$([Guid]::NewGuid().ToString('N').Substring(0, 10))"
|
||||
$activeConfigRoot = $configRoot
|
||||
if ($RunMode -eq "ravnoves-video" -and $null -ne $ravnovesProfileDocument) {
|
||||
$activeConfigRoot = Join-Path $RunRoot "effective-config"
|
||||
New-Item -ItemType Directory -Path $activeConfigRoot | Out-Null
|
||||
Copy-Item -LiteralPath $policyConfig -Destination $activeConfigRoot
|
||||
Copy-Item -LiteralPath $providerMapConfig -Destination $activeConfigRoot
|
||||
$benchmark = Get-Content -LiteralPath $benchmarkConfig -Raw | ConvertFrom-Json
|
||||
$benchmark.ravnoves = $ravnovesProfileDocument.source
|
||||
$benchmark | ConvertTo-Json -Depth 32 | Set-Content -LiteralPath (
|
||||
Join-Path $activeConfigRoot "lab-v1-goose-vegetation-benchmark-v1.json"
|
||||
) -Encoding utf8
|
||||
}
|
||||
$visualCount = if ($RunMode -eq "ravnoves-video") { 0 } else { 12 }
|
||||
$arguments = @(
|
||||
"run", "--rm", "--name", $containerName,
|
||||
@@ -125,7 +172,7 @@ function Invoke-IsolatedRun {
|
||||
"--env", "HOME=/tmp",
|
||||
"--mount", "type=bind,src=$datasetRoot,dst=/data/goose,readonly",
|
||||
"--mount", "type=bind,src=$checkpoint,dst=/models/candidate.pth,readonly",
|
||||
"--mount", "type=bind,src=$configRoot,dst=/config,readonly",
|
||||
"--mount", "type=bind,src=$activeConfigRoot,dst=/config,readonly",
|
||||
"--mount", "type=bind,src=$RunRoot,dst=/output",
|
||||
$image,
|
||||
"--mode", $RunMode,
|
||||
@@ -147,15 +194,27 @@ function Invoke-IsolatedRun {
|
||||
$tail = @($arguments[$mountIndex..($arguments.Count - 1)])
|
||||
$arguments = $head + @("--mount", "type=bind,src=$FramesRoot,dst=/input,readonly") + $tail
|
||||
}
|
||||
& docker @arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "LAB V1 container failed with exit code $LASTEXITCODE"
|
||||
$dockerExitCode = -1
|
||||
$previousErrorActionPreference = $ErrorActionPreference
|
||||
try {
|
||||
# Windows PowerShell exposes native stderr as ErrorRecord objects. Model
|
||||
# libraries legitimately emit warnings there, so merge the stream and
|
||||
# fail only on the native process exit code.
|
||||
$ErrorActionPreference = "Continue"
|
||||
& docker @arguments 2>&1 | ForEach-Object { Write-Output $_ }
|
||||
$dockerExitCode = $LASTEXITCODE
|
||||
}
|
||||
finally {
|
||||
$ErrorActionPreference = $previousErrorActionPreference
|
||||
}
|
||||
if ($dockerExitCode -ne 0) {
|
||||
throw "LAB V1 container failed with exit code $dockerExitCode"
|
||||
}
|
||||
}
|
||||
|
||||
function Export-RavnovesFrames {
|
||||
param([string]$Destination)
|
||||
Assert-FileIdentity -Path $RavnovesVideo -ExpectedBytes (Get-Item -LiteralPath $RavnovesVideo).Length -ExpectedSha256 $ravnovesSha256
|
||||
Assert-FileIdentity -Path $RavnovesVideo -ExpectedBytes (Get-Item -LiteralPath $RavnovesVideo).Length -ExpectedSha256 $RavnovesSha256
|
||||
New-Item -ItemType Directory -Path $Destination | Out-Null
|
||||
$expression = ($frameIndices | ForEach-Object { "eq(n\,$_ )" }) -join "+"
|
||||
$temporaryPattern = Join-Path $Destination "selected-%03d.png"
|
||||
@@ -175,14 +234,68 @@ function Export-RavnovesFrames {
|
||||
|
||||
function Export-RavnovesVideoFrames {
|
||||
param([string]$Destination)
|
||||
Assert-FileIdentity -Path $RavnovesVideo -ExpectedBytes (Get-Item -LiteralPath $RavnovesVideo).Length -ExpectedSha256 $ravnovesSha256
|
||||
Assert-FileIdentity -Path $RavnovesVideo -ExpectedBytes (Get-Item -LiteralPath $RavnovesVideo).Length -ExpectedSha256 $RavnovesSha256
|
||||
New-Item -ItemType Directory -Path $Destination | Out-Null
|
||||
& ffmpeg -hide_banner -loglevel error -i $RavnovesVideo -map 0:v:0 -fps_mode passthrough (Join-Path $Destination "frame-%06d.png")
|
||||
$decodedRoot = "{0}-decoded-by-pts" -f $Destination
|
||||
$packetsPath = "{0}-packets.csv" -f $Destination
|
||||
New-Item -ItemType Directory -Path $decodedRoot | Out-Null
|
||||
& ffprobe -v error -select_streams v:0 -show_packets -show_entries packet=pts,flags -of csv=p=0 -o $packetsPath $RavnovesVideo
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "RAVNOVES full-video packet probe failed"
|
||||
}
|
||||
$packetRows = @(Get-Content -LiteralPath $packetsPath | Select-Object -First $RavnovesExpectedFrameCount)
|
||||
if ($packetRows.Count -ne $RavnovesExpectedFrameCount) {
|
||||
throw "RAVNOVES full-video packet sequence changed"
|
||||
}
|
||||
& ffmpeg -hide_banner -loglevel error `
|
||||
-hwaccel cuda -hwaccel_output_format cuda -c:v h264_cuvid `
|
||||
-err_detect ignore_err -flags +output_corrupt -copyts `
|
||||
-i $RavnovesVideo -map 0:v:0 -vf "hwdownload,format=nv12" `
|
||||
-fps_mode passthrough -enc_time_base demux -frames:v $RavnovesExpectedFrameCount `
|
||||
-frame_pts 1 (Join-Path $decodedRoot "frame-%d.png")
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "RAVNOVES full-video frame extraction failed"
|
||||
}
|
||||
$decodedCount = @(Get-ChildItem -LiteralPath $decodedRoot -File -Filter "frame-*.png").Count
|
||||
$repairs = @()
|
||||
for ($index = 0; $index -lt $RavnovesExpectedFrameCount; $index++) {
|
||||
$columns = ([string]$packetRows[$index]).Split(",")
|
||||
if ($columns.Count -lt 2) {
|
||||
throw "RAVNOVES full-video packet row is malformed"
|
||||
}
|
||||
$pts = [int64]::Parse($columns[0].Trim(), [Globalization.CultureInfo]::InvariantCulture)
|
||||
$decodedPath = Join-Path $decodedRoot ("frame-{0}.png" -f $pts)
|
||||
$canonicalPath = Join-Path $Destination ("frame-{0:D6}.png" -f ($index + 1))
|
||||
if (Test-Path -LiteralPath $decodedPath -PathType Leaf) {
|
||||
Move-Item -LiteralPath $decodedPath -Destination $canonicalPath
|
||||
continue
|
||||
}
|
||||
if ($index -eq 0 -or $repairs.Count -ge 1) {
|
||||
throw "RAVNOVES source contains more than one recoverable decoder gap"
|
||||
}
|
||||
$previousPath = Join-Path $Destination ("frame-{0:D6}.png" -f $index)
|
||||
Copy-Item -LiteralPath $previousPath -Destination $canonicalPath
|
||||
$repairs += [ordered]@{
|
||||
sequence = $index + 1
|
||||
packet_pts = $pts
|
||||
method = "duplicate-previous-decoded-frame"
|
||||
}
|
||||
}
|
||||
Remove-Item -LiteralPath $decodedRoot -Recurse -Force
|
||||
Remove-Item -LiteralPath $packetsPath -Force
|
||||
[ordered]@{
|
||||
schema_version = "missioncore.recorded-video-decode-repair/v1"
|
||||
decoder = "ffmpeg-h264_cuvid-output-corrupt"
|
||||
packets_requested = $RavnovesExpectedFrameCount
|
||||
frames_decoded = $decodedCount
|
||||
repaired_frame_count = $repairs.Count
|
||||
repairs = $repairs
|
||||
} | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (
|
||||
Join-Path (Split-Path $Destination -Parent) "decode-repair.json"
|
||||
) -Encoding utf8
|
||||
$frames = @(Get-ChildItem -LiteralPath $Destination -File -Filter "frame-*.png" | Sort-Object Name)
|
||||
if ($frames.Count -ne 4489 -or $frames[0].Name -ne "frame-000001.png" -or $frames[-1].Name -ne "frame-004489.png") {
|
||||
$lastFrameName = "frame-{0:D6}.png" -f $RavnovesExpectedFrameCount
|
||||
if ($frames.Count -ne $RavnovesExpectedFrameCount -or $frames[0].Name -ne "frame-000001.png" -or $frames[-1].Name -ne $lastFrameName) {
|
||||
throw "RAVNOVES full-video frame sequence changed"
|
||||
}
|
||||
}
|
||||
@@ -244,6 +357,9 @@ try {
|
||||
$framesRoot = Join-Path $runRoot "input-frames"
|
||||
Export-RavnovesVideoFrames -Destination $framesRoot
|
||||
Invoke-IsolatedRun -RunMode "ravnoves-video" -RunRoot $runRoot -Limit 0 -FramesRoot $framesRoot
|
||||
Copy-Item -LiteralPath (Join-Path $runRoot "decode-repair.json") -Destination (
|
||||
Join-Path $runRoot "result\decode-repair.json"
|
||||
)
|
||||
Remove-Item -LiteralPath $framesRoot -Recurse -Force
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user