Handoff — Perspective render across all of Abschnitt 1/2/3

2026-07-09 · continuation agent · AI3D-226

Summary

Goal: render perspective camera views (step s3c) for every segment of Abschnitt 1, 2 and 3, using the real Step-7 run7b road-axis XML and two-segment appending — the same config already validated on Abschnitt 1 segments 0–5. Then answer how long the full run takes on Azure.

The pipeline, component, environment (s3c_render_perspective:4, rasterizer 0.3.3 with chunked/bounded memory) and the Abschnitt-1 helper pipeline all exist and work. What is left is mechanical: find each Abschnitt's Step-3 step3_output source, upload its axis XML, clone the helper pipeline for A2/A3, remove the segment 0–5 cap, raise node count, submit, monitor.

Short answer on timing (grounded in a measured 12-task run, must be refined — see Time estimate): the work is embarrassingly parallel at ~1–1.5 min compute per two-segment task. At the tested 4-node width each Abschnitt is roughly 1–2 h; raising to 16–32 nodes (if quota allows) drops each to ~15–30 min. The exact number hinges on two figures the agent must confirm first: total segment count for A2/A3, and the cluster's max node count / quota.

Time estimate — method & measured inputs

Measured per-task time (real, from the validated run)

From run lanefinder_abschnitt_1_render_perspective_20260708072345 (child d05ac804-710f-4872-9a12-b448b85ee612), the full production config (run7b axis + append-next-segment + chunked v0.3.3), 12 two-segment tasks on 4 nodes. Per-task elapsed seconds:

branch_000 seg 0..5 : 22.9  34.1  47.5  58.4  58.0  58.9
branch_001 seg 0..5 : 20.9  40.1  61.7  81.5  90.3  98.3
mean ~56 s · min 21 s · max 98 s (grows with segment size)

These are segments 0–5, which are on the smaller side. The per-segment NPZ blob-size audit showed interior segments reach ~0.9–1.2 GB each (a paired task ≈ up to ~2.3 GB ≈ 190M points). Large pairs will run longer than 98 s — use a blended planning mean of ~90 s/task for a full Abschnitt, and refine after the first ~30 real tasks complete.

Formula

wall_clock ≈ ceil(N_tasks / P_nodes) × t_task  +  overhead
  N_tasks   = total segments in the Abschnitt (append adds NO tasks)
  P_nodes   = s3c_instance_count (parallel workers, 1 proc/node)
  t_task    ≈ 90 s  (blended; measured 21–98 s on small segments)
  overhead  ≈ 5–10 min: node cold-spinup + prepare_data step
              (env IMAGE ALREADY BUILT for v4 → no rebuild wait)

Segment counts (the N you must confirm)

AbschnittSegments (render tasks)Source
1142 (branch_000 + branch_001)measured — grep of step3 blob list
2confirm unknowncount from A2 step3_output (agent task 1)
3confirm unknowncount from A3 step3_output (agent task 1)

Segments are 100 m (s3_segment_length_m: 100.0). A2/A3 are highway sections of similar order to A1; a working guess is ~120–250 each, but count them exactly — it is the dominant term. Grand total is plausibly ~400–550 tasks.

Scenario table (per Abschnitt, refine N and P)

Nodes PN=142 (A1)N≈180 (A2/A3 guess)Notes
4 (as tested)~53 min + oh ≈ ~1 h~68 min + oh ≈ ~1.2 hcurrent pipeline default
8~27 min + oh ≈ ~35 min~34 min + oh ≈ ~42 min
16~13 min + oh ≈ ~22 min~17 min + oh ≈ ~25 minif quota allows
32~7 min + oh ≈ ~15 min~9 min + oh ≈ ~17 minlarge-pair tail dominates

All-three total: the three Abschnitte are independent pipelines. Run sequentially → sum the rows (~3–4 h at 4 nodes; ~1–1.3 h at 16 nodes). Run concurrently → roughly the single-Abschnitt time, but you need 3 × P nodes free at once and enough F4s_v2 quota. The cluster CPU-Compute-4x is Standard_F4s_v2 (8 GB); confirm its scale_settings.max_instances and the subscription core quota before promising a node count (the earlier az ml compute show did not return a max — verify).

First two numbers to nail down (they determine the answer)

# 1) exact segment counts A2, A3 — from each Abschnitt's step3_output blob list
#    (see "How to run" for locating the step3 child), then:
grep -oE 'branch_[0-9]+/lane_points/segment_[0-9]+' <bloblist> | sort -u | wc -l
# 2) cluster ceiling
az ml compute show --name CPU-Compute-4x -g AI3D-rg -w ai3d-lf-mlw-pc-01 \
  --query "{size:size,min:scale_settings.min_instances,max:scale_settings.max_instances}" -o json
az vm list-usage --location polandcentral --query "[?contains(name.value,'FSv2')]" -o table

Current state A1 done end-to-end

Render config already dialed in (keep these)

camera_spacing 10 m · camera_height 10 m · pitch_down 25° · fov 70°
image 1600×900 · color rgb · save_depth true · append_next_segment true
axis: Step-7 HighwayData XML "Central Axis" polyline (geoshift-relative,
      == run3 geoshift; projects each segment's plane points onto the axis)
aggregation topmost (nearest-wins) · outputs: RGB + 16-bit-cm depth PNG + per-seg JSON

How to run all three — step by step

The Abschnitt-1 helper pipeline is the template: /home/miro/dev/3dai.iolabs.orchestrator/pipelines/helpers/abschnitt_1_render_perspective.yaml. It binds an existing step3_output (mounted, datastore form) + an axis_root, runs prepare_data_for_step_3b (which honours min/max_segment_index) then s3c_render_perspective.

  1. Confirm env is current: the pushed component references azureml:s3c_render_perspective:4; env v4 is registered. No rebuild needed unless you bump the rasterizer again.
  2. Locate each Abschnitt's Step-3 step3_output. A1 uses child 77f7ac77-a89a-446c-911c-37182f8caf4d (from full run lanefinder_abschnitt_1_pipeline_20260702070612). For A2/A3, the recent *_from_step3_* runs bind an existing step3 rather than producing one, so read their YAML/inputs to get the real path, or find the s3_segment_mapping child of the last full pipeline for each. Recent completed candidates: lanefinder_abschnitt_2_from_step3_20260702165047, lanefinder_abschnitt_3_from_step3_20260702203744 (inspect az ml job show --query inputs). Grab the datastore-form path azureml://datastores/workspaceblobstore/paths/azureml/<child>/step3_output/.
  3. Count segments for A2/A3 from those step3 blob lists (command in the estimate section) → fills the N in the time estimate.
  4. Upload A2/A3 axis XML to blob (A1 pattern), one XML per branch dir:
    for A in 2 3; do for b in branch_000 branch_001; do
      F=$(ls /home/miro/dev/3dai.lanefinder/data/00_external/260703_Abschnitt_$A/run7b_axis/$b/run7_lanes_*.xml)
      az storage blob upload --account-name ai3dlfmlwpc011354919387 \
        --container-name azureml-blobstore-919dd9b5-5c3a-4888-80a3-6b3f79f2fc48 \
        --name "lanefinder/aux/abschnitt_${A}_run7b_axis/$b/$(basename $F)" \
        --file "$F" --auth-mode key --overwrite; done; done
    # NB: confirm each Abschnitt's branch count — A2/A3 may not both have exactly 2 branches.
  5. Clone the helper pipeline to abschnitt_2_render_perspective.yaml / abschnitt_3_render_perspective.yaml. Change: experiment_name, existing_step3_output.path, existing_axis_root.path (to the A2/A3 aux path), set s3c_min_segment_index: -1 and s3c_max_segment_index: -1 (= ALL segments), and raise s3c_instance_count to your chosen P.
  6. Validate then submit:
    cd /home/miro/dev/3dai.iolabs.orchestrator
    az ml job validate --file pipelines/helpers/abschnitt_2_render_perspective.yaml -o json
    RUN="lanefinder_abschnitt_2_render_perspective_$(date -u +%Y%m%d%H%M%S)"
    az ml job create --file pipelines/helpers/abschnitt_2_render_perspective.yaml --set name="$RUN" -o json
  7. Monitor (background poll, matched to cache windows — do NOT sleep 300s). On failure, pull child logs and check sys/job_report/processed_mini-batches.csv for per-task status; a silent worker death + fast fail + clean stderr = OOM (unlikely now with chunking, but a single >60M-pt NPZ could still stress 8 GB).
  8. Collect to D drive with az storage blob download-batch (destination dir must pre-exist; use --overwrite true; flatten the deep azureml/<child>/step3c_output/branches/*/lane_points/perspective_views/ path into per-branch folders — see prior runs under D:\ai3d-aml\).

Auth note: uploading env/conda embeds the Nexus index credential; Miro has approved that upload. Pushing to master / default branch needs Miro's OK (auto-mode blocks it). Nexus publish uses UV_INDEX_NEXUS_USERNAME/PASSWORD env vars via UV_PUBLISH_USERNAME/PASSWORD.

Key artifacts & handles

WhatHandle
Wrapper script3dai.iolabs.orchestrator/scripts/render_perspective/render_perspective.py
Componentcomponents/s3c_render_perspective.yml (env :4)
Pipeline templatepipelines/helpers/abschnitt_1_render_perspective.yaml
Rasterizer API3dai.iolabs.imageanalyzer.rasterizerrasterization/{perspective.py,topdown_rasterizer.py} (process_perspective, cameras_from_road_axis, CameraPose)
Axis XML (local)…/00_external/260703_Abschnitt_{1,2,3}/run7b_axis/branch_XXX/run7_lanes_*.xml
Axis XML (blob, A1 only so far)lanefinder/aux/abschnitt_1_run7b_axis/branch_XXX/
A1 step3 sourcechild 77f7ac77-a89a-446c-911c-37182f8caf4d
Last good render childd05ac804-710f-4872-9a12-b448b85ee612 (A1 axis+append, 290 imgs)
Storageacct ai3dlfmlwpc011354919387, container azureml-blobstore-919dd9b5-5c3a-4888-80a3-6b3f79f2fc48, key auth
Workspacesub ba81b555-ffe9-4625-b90a-d0011d0b57c9, rg AI3D-rg, ws ai3d-lf-mlw-pc-01
Jira tagAI3D-226

Project memory (already written): ~/.claude/projects/-home-miro-dev-3dai-iolabs-imageanalyzer-rasterizer/memory/perspective-deployment-state.md and perspective-camera-spec.md — read them for the full frame contract and the OOM-triage note.

Risks & open questions

Suggested skills

azure-cli (AI3D Azure ML ops — has the constants, child-job and blob recipes), and this repo's wrap-up if the rasterizer needs another Nexus release.