# A06_9 — DETR-Style Sparse 3D Transformer CSI Path Predictor (New Branch) ## Goal Description Build, in the sibling directory `A06_9_detr_style_voxel_sparse_3d_transformer_net/`, a CSI-only network that predicts, for each `(scene, TX, RX)` triple, a variable number of propagation paths (each path = existence, delay in ns, peak attenuation in dB) using a DETR-style set-prediction head over a sparse 3D voxel backbone. The architecture borrows TRELLIS-2's sparse transformer blocks, sparse 3D downsampling, and AdaLN-zero modulation, and abandons the A06_7 rigid ordered-slot CSI head whose power-undershoot failure mode is considered unfixable. This branch is explicitly CSI-only. The A06_7 radiomap head is out of scope here and will be re-attached as a frozen-backbone adapter in a later branch. > **Plan Version 12 (2026-04-19) — user-directed scope change.** The user has instructed the team to **drop the cross-model A06_7 throughput baseline comparison** ("跳过对比算法 base line a06-7") and **focus on the DETR branch's own convergence on single-scene and tiny10 at 200 epochs**. Concretely: > > 1. AC-5's "≥ 0.67 × A06_7 baseline" clause is removed; AC-5 is now a self-contained caching + throughput contract (see the AC-5 plan-note). > 2. Two new acceptance criteria land: **AC-11** (training-speed optimization — BF16 default, larger batch, efficient DataLoader, GPU utilization ≥ 70%) and **AC-12** (200-epoch convergence sweep on single-scene + tiny10 with per-epoch loss CSV + every-10-epoch full metric JSON + analysis recommending a default training-epoch budget). > 3. Two new milestones: **M6** (training-speed optimization) and **M7** (200-epoch sweep). **M8** absorbs the optional 30/50/100-scene scale-up and is explicitly conditional on M7's convergence analysis. > 4. task16–task19 are narrowed to the bring-up path (short single-scene + short tiny10 smoke); the real convergence and AC-8 check live in task22 (200-epoch single-scene) and task23 (200-epoch tiny10 + `convergence_analysis.md`). > 5. task20 (profile), task21 (speed optimization implementation), task22 (200-epoch single-scene), task23 (200-epoch tiny10 + analysis) are added. ## Acceptance Criteria Following TDD philosophy, each criterion includes positive and negative tests for deterministic verification. - AC-1: Repository scaffold exists, isolated from A06_7, with reproducible `reference/` clones of the external borrowed codebases. - Positive Tests (expected to PASS): - `A06_9_detr_style_voxel_sparse_3d_transformer_net/code_snapshot/` contains a fresh package (e.g. `radiomapvggt_v20_voxel_cir_detr/`) whose `__init__.py`, `config.py`, `models/`, `data/`, `engine/`, `utils/` directories are importable without reaching into `../A06_7_*/`. - `reference/` subdirectory contains read-only clones of `roboflow/rf-detr`, `happinesslz/SEED`, `JIA-Lab-research/VoxelNeXt`, each pinned to a specific commit hash recorded in `reference/MANIFEST.md`. - `pytest code_snapshot/tests/test_import_smoke.py` imports the model, dataset, and trainer classes with zero `ImportError` from the new package. - Negative Tests (expected to FAIL): - Any `import` path in the new package resolves to a file inside `../A06_7_*/` (the branch must be self-contained; a grep for `A06_7` in `code_snapshot/` returns zero hits outside comments). - Running training with `radiomap_*` weights or radiomap manifests loaded raises a configured guard error rather than silently training a radiomap head. - AC-2: Target contract is frozen and shared by data, loss, and metrics. - Positive Tests: - A single module (e.g. `data/csi_path_targets.py`) defines one function that converts a raw Sionna CIR into the set of supervised paths. Whether that set is "raw physical paths" or "merged unique delay-bin paths" is decided in DEC-1; the code matches exactly one option. - The loss module imports the target spec from that module without redefining "what counts as a path". - The metric module (PDP cosine, peak dB MAE, delay MAE, count accuracy, false-positive rate on zero-path samples) imports the same spec. - Negative Tests: - Two of {data, loss, metric} disagree on whether two co-bin paths are one path or two (the cross-module contract would be broken). - A sample with zero paths is dropped silently by the collate function (zero-path samples MUST survive to validation). - AC-3: A DETR-style set-prediction CSI head is implemented with Hungarian matching between K learnable path queries and the ground-truth path set, emitting `(exists_logit, delay_pred, peak_db_pred)` per query, under the frozen batch tensor contract defined below. **Batch Tensor Contract (frozen; referenced by AC-3, AC-5, AC-6, AC-7, AC-9, task5, task10, task11, task12).** After collation, a batch holds `Q` triples, where `Q` is the number of `(scene_id, tx_id, rx_id)` triples in that batch. The dataset/collator emits: - `scene_idx [Q]` — integer index into the batch's unique scene list; `U = number of unique scene_ids in batch`. - `tx_scene_idx [Q]` — integer index into the batch's unique `(scene_id, tx_id)` pair list; `P = number of unique (scene, TX) pairs in batch`. - `rx_xyz_norm [Q, 3]`, `tx_xyz_norm [Q, 3]`, `scene_extent [Q, ...]`, plus the voxel structures indexed by scene. - Ground-truth paths per triple: `gt_num_paths [Q]`, `gt_delay_ns [Q, M_max]`, `gt_peak_db [Q, M_max]`, `gt_path_mask [Q, M_max]`, where `M_max = max GT paths in the batch`. The head's forward returns exactly: `csi_exists_logits [Q, K]`, `csi_delay_ns [Q, K]`, `csi_peak_db [Q, K]`, with `K = configured query budget` (default `K = 8`, subject to DEC-5). - Positive Tests: - Given a synthetic `Q`-triple batch with known GT paths, the Hungarian-matching unit test recovers the correct 1:1 assignment when predictions are close and the correct "no-object" assignment when they are far. - The head's forward returns exactly the three keys above with the exact shapes above; extra keys or missing keys both fail the test. - Finite-output assert: for random input, all three outputs are finite; `csi_peak_db` is inside `[db_low − ε, db_high + ε]` under the configured bounded parameterization. - Negative Tests: - The head mixes Hungarian matching with an ordered-slot loss applied to unmatched queries (e.g. also penalizing delay_rank of a query marked no-object). This is the exact failure mode Codex flagged and is disallowed. - The head predicts `peak_db` via any `floor_db + softplus(raw)` parameterization (with any value of `floor_db`). Power MUST be produced by a saturating map to `[db_low, db_high]` configured from dataset statistics (e.g., `db_low + (db_high − db_low) · σ(raw)`), so a randomly-initialized head cannot output a value outside the configured dB range. - AC-4: Backbone uses TRELLIS-2-style sparse 3D transformer blocks with at least one sparse 3D downsample stage, and TX is injected as AdaLN-zero global modulation rather than as a separate token. - Positive Tests: - The backbone class imports `SparseTransformerBlock` (and/or `ModulatedSparseTransformerBlock`) plus `SparseDownsample` from whichever TRELLIS-2 source DEC-8 resolves to (vendored pinned subset under `code_snapshot/vendor/trellis2_sparse/` by default, or live dependency on a pinned commit of `/data/conda_envs/trellis2` if the user overrides DEC-8), and a forward pass runs on a tiny voxel batch without CUDA OOM on a single 80 GB GPU. - A config switch toggles the number of downsample stages `S ∈ {1, 2, 3}`; all three configurations pass a shape-and-finite smoke test on synthetic voxels. - TX injection is implemented via modulation; a unit test confirms that passing two distinct TXs through the backbone yields modulated scene features that differ in at least one AdaLN `scale/shift` vector, and that the underlying SparseTensor **coordinates** stay the same (only features/modulation differ). - Negative Tests: - The model prepends TX and RX as two extra sparse voxel tokens (the exact pattern the draft rules out). - RX is injected into the backbone before the final downsample stage (RX-conditioned backbone features cannot be reused; late injection is the architectural requirement — see DEC-3). - AC-5: Per-`(scene, TX, RX)` inference reuses backbone work across all RXs sharing a `(scene, TX)` within the batch; throughput is measured in normalized work units so the metric remains comparable as batch shape changes. (Plan Version 12 / 2026-04-19: the cross-model A06_7 throughput ratio is REMOVED per user directive "跳过对比算法 base line a06-7". The A06_7 baseline reruns referenced in prior Round 0–11 summaries are retained on disk for future lookup but are no longer a gate. AC-5 is now a self-contained caching + throughput contract.) - Positive Tests: - The trainer logs, per gradient step, (a) the voxel-encoder forward-call count `C_enc` and (b) the TX-modulation forward-call count `C_txmod`. With `U` = unique `scene_id`s in the batch and `P` = unique `(scene_id, tx_id)` pairs in the batch (as defined in AC-3's tensor contract), every logged step satisfies `C_enc ≤ U` and `C_txmod ≤ P`. A unit test injects a batch with known `U, P, Q` and asserts these counters. - A benchmark script reports throughput in **triples per second** on a fixed tiny10 `(scene, TX, RX)` manifest (manifest path pinned in `benchmarks/tiny10_triples_manifest.json`), recorded as median over ≥ 100 warmed-up gradient steps on a single 80 GB GPU. The benchmark also reports **peak CUDA memory** per step. - The benchmark script reports `mean_triples_per_step` alongside triples/sec so any future shape adapter cannot silently over-count throughput. - Negative Tests: - `C_enc` scales with `Q` (the encoder runs once per triple), indicating scene-token caching is absent. - `C_txmod` scales with `Q` rather than `P`, indicating `(scene, TX)` memory caching is absent and DEC-4 has been silently violated. - Wall-clock per triple grows with `R` (RXs per `(scene, TX)`) instead of staying flat, proving the decoder is wasting work on reusable backbone state. - Throughput is reported as raw steps/sec or samples/sec without the triples-per-step normalization. - AC-6: Loss is unambiguously defined over the matched set only (plus no-object BCE on unmatched queries), in dB space for power and ns-space for delay, operating on the `[Q, K]` outputs from AC-3's tensor contract. - Positive Tests: - For every training step, a logged `loss_dict` lists these four keys always present: `loss_match_exists`, `loss_match_delay_ns`, `loss_match_peak_db`, `loss_no_object_exists`. Two optional auxiliary keys `loss_pair_gap_delay` and `loss_pair_gap_db` are computed ONLY over matched pairs sorted by predicted delay, and default to OFF (`enable_pair_gap_losses = False`) for the first end-to-end run; enabling them requires an explicit config override. - Unit test: a triple with zero GT paths (`gt_num_paths[q] == 0`) contributes only `loss_no_object_exists`; all other per-triple loss components are exactly zero for that triple. - Unit test: the delay loss numerically equals Huber or L1 in nanoseconds applied to `csi_delay_ns` selected by the Hungarian matching indices; the dB loss numerically equals Huber or L1 in dB applied to `csi_peak_db` at those same indices. - Negative Tests: - The loss linearizes power (converts dB to mW) before the regression term — this is forbidden per the draft's explicit dB-domain requirement. - An ordered-slot delay-rank loss is applied to unmatched queries (Codex flagged this as the predecessor's failure trap). - Pair-gap losses are silently enabled by default, or are computed over unmatched queries. - AC-7: Checkpoint selection uses a composite CSI criterion that jointly guards against power collapse, false positives on zero-path samples, count-prediction failure, delay-regression failure, and single-metric local optima. - Positive Tests: - The validation loop reports at least: `pdp_cosine_nonzero`, `peak_db_mae_matched`, `peak_db_bias_matched`, `delay_mae_matched_ns`, `count_acc`, `zero_path_fpr`, and `gt_paths_truncated_rate` (fraction of val samples where `gt_num_paths > K`). - The checkpoint selector is a deterministic function of the validation metric table implementing this composite rule (all thresholds configured in `config.py`, default values shown in brackets): 1. **Feasibility guards (hard gates):** an epoch is a candidate only if `peak_db_bias_matched ∈ [−3, +3] dB` **AND** `zero_path_fpr ≤ 10%` **AND** `count_acc ≥ 0.5` **AND** `delay_mae_matched_ns ≤ 1.0`. 2. **Primary objective over feasible candidates:** maximize `pdp_cosine_nonzero`. 3. **Lexicographic tie-break within 0.001 of the primary optimum:** minimize `peak_db_mae_matched`; then minimize `delay_mae_matched_ns`; then maximize `count_acc`. 4. **Fallback:** if no epoch is feasible, the selector refuses to pick one, emits a loud warning, and returns `None` so the run fails loudly rather than silently saving a pathological checkpoint. - Unit test on a synthetic epoch table: exactly one canonical "best" row is returned, matches the rule above row-by-row, and the pathological row (high cosine but `peak_db_bias_matched = −150 dB`) is rejected. - Negative Tests: - The selector picks `argmax(pdp_cosine_nonzero)` even when any hard gate fails. - `peak_db_bias_matched`, `count_acc`, `delay_mae_matched_ns`, or `zero_path_fpr` is missing from the validation log. - The selector uses only two guards (bias + FPR) without count / delay gates, reproducing the Codex-flagged under-specified variant. - AC-8: One-scene success gate is enforced before multi-scene sweeps. - Positive Tests: - A dedicated single-scene manifest exists (e.g. `manifests/task_a069_single_scene.json`) selecting exactly one scene from the tiny10 set. - A "scale-up gate" check in the training orchestrator refuses to launch the 10/30/50/100-scene runs unless the single-scene run's final checkpoint satisfies a configurable success rule (default: `count_acc ≥ 0.9`, `delay_mae_matched_ns ≤ 0.3 ns`, `peak_db_bias_matched ∈ [-3 dB, +3 dB]` — all tunable in `config.py`). - Negative Tests: - The 100-scene run launches even though the single-scene model has not met the gate (the orchestrator MUST block). - The gate uses only a single metric (e.g. cosine alone), reproducing the predecessor's selection pathology. - AC-9: Zero-path samples are first-class citizens in data, loss, and metrics. - Positive Tests: - The dataset reports the zero-path sample rate per manifest; validation metrics include `zero_path_fpr`, `nonzero_path_count_mae`, and `match_rate_over_all_samples` (matched paths divided by GT paths across the full val set including zero-path samples). - A direct unit test with a zero-path batch asserts that `loss_no_object_exists` is the only non-zero training loss term and that gradients do not contain NaNs/Infs. - Negative Tests: - `zero_path_fpr` is missing from the validation log. - Zero-path samples are discarded in the collate step. - AC-10: DETR-style query budget `K` is justified by dataset statistics, supervised truncation is measured at runtime, and truncation never happens silently. - Positive Tests: - A small utility script emits the histogram of GT path counts per sample over the tiny10 training set and writes it to `reports/path_count_histogram.md`, with per-bucket counts and the cumulative percentile at every integer `num_paths` value. - The config default for `K` is chosen such that at least 99% of tiny10 samples have `num_paths ≤ K`, or a documented `DEC-5` user override exists. - `gt_paths_truncated_rate` (fraction of val samples where GT path count exceeded `K` and was truncated to the top-`K` earliest paths) is computed in every validation epoch and included in the AC-7 metric bundle; a run with `gt_paths_truncated_rate > 0.01` for the chosen manifest emits a loud warning at val end. - Negative Tests: - `K = 8` is committed to config with zero evidence that the tiny10 distribution truncation rate is acceptable. - Samples with more than `K` GT paths are truncated without being counted; `gt_paths_truncated_rate` is missing from the metric dict. - AC-11: Training-speed optimization lands before the 200-epoch sweeps so wall-clock is not the bottleneck. (Plan Version 12 / 2026-04-19: user directive — "我们训练轮数这么高,所以说在进行这个200轮训练之前,一定要优化一下我们的数据集读写以及我们的模型训练速度".) - Positive Tests: - The trainer uses bf16 autocast on CUDA for trellis2 backbone forward + head (already in place; AC-11 requires it to be the DEFAULT enabled path, not an opt-in flag). - A benchmark-optimization report `reports/training_speed_optimization.md` documents the before/after numbers for: (a) **median triples/sec** on the pinned tiny10 manifest at batch_triples=8, (b) **peak CUDA memory MB**, (c) **GPU utilization %** (via `nvidia-smi dmon -s u -c 30`), (d) **DataLoader time / total step time ratio**. The file must show a post-optimization GPU utilization ≥ 70% for at least 80% of sampled `dmon` rows, and data-loader time fraction ≤ 15% of median step time. - `DataLoader(num_workers≥4, pin_memory=True, persistent_workers=True, prefetch_factor=4)` (or the equivalent optimization) is enabled by default when a manifest is provided to `scripts/train_and_eval.py`; a test or a runtime assertion verifies these flags are on. - The batch size `--batch-triples` can be raised at least to the largest power-of-two value that fits in 80 GB without triggering OOM during the 200-epoch sweeps (AC-12); the optimization report records the chosen max value and the observed peak memory at that value. - Negative Tests: - Training runs in fp32 when CUDA + trellis2 is available (should be bf16 autocast). - DataLoader runs `num_workers=0` by default, forcing synchronous data materialization. - The training launcher refuses to print GPU utilization in the report. - Raising batch size causes silent truncation, dropping samples from an epoch. - AC-12: Empirical convergence sweep answers "how many epochs does DETR need to fit". (Plan Version 12 / 2026-04-19: user directive — "200 轮收敛验证,单场景 + tiny10,每 epoch 记 loss,每 10 epoch 详细指标,挑出最优训练轮数".) - Positive Tests: - Two training runs land in `reports/`: (a) `reports/single_scene_200ep.{md,csv,json}` on `manifests/task_a069_single_scene.json`, and (b) `reports/tiny10_200ep.{md,csv,json}` on `benchmarks/tiny10_triples_manifest.json`. Both runs are 200 epochs, backbone=`trellis2`, AC-11 optimized config. The CSV logs one row per epoch with columns: `epoch, lr, train_loss_total, loss_match_exists, loss_match_delay_ns, loss_match_peak_db, loss_no_object_exists, grad_norm`. The JSON logs, every 10 epochs AND at the final epoch, the full AC-7 metric bundle (`pdp_cosine_nonzero, count_acc, delay_mae_matched_ns, peak_db_mae_matched, peak_db_bias_matched, zero_path_fpr, nonzero_path_count_mae, match_rate_over_all_samples, gt_paths_truncated_rate`). - Learning-rate schedule: initial `lr=1e-4`, with at least one documented decay (e.g. cosine to `1e-6`, or step-decay ×0.1 at `{100, 150}`). The exact schedule is picked during task20 and recorded in the config section of each report. - An analysis report `reports/convergence_analysis.md` compares the two 200-epoch logs, plots loss trajectories and per-metric trajectories, identifies the **earliest epoch** at which the AC-7 feasibility gates are satisfied, and the **peak-metric epoch** on the primary objective `pdp_cosine_nonzero`. Based on that evidence the report **recommends a default training epoch budget** for future runs. - AC-8 single-scene gate (`count_acc ≥ 0.9`, `delay_mae_matched_ns ≤ 0.3`, `peak_db_bias_matched ∈ [−3, +3]`) is either PASSED at some epoch in the 200-epoch window (and that epoch is reported), OR explicitly RECORDED AS NOT YET REACHED with the best-epoch numbers. The plan does not require AC-8 to pass at 200 epochs for AC-12 to be met; AC-12 is satisfied by the honest empirical answer. - Negative Tests: - The 200-epoch run exits early without emitting the per-epoch CSV row for each completed epoch. - The every-10-epoch metric JSON is written only at the final epoch (loss-only logging is not enough). - `convergence_analysis.md` recommends an epoch budget without citing the CSV + JSON evidence it is derived from. ## Path Boundaries Path boundaries define the acceptable range of implementation quality and choices. ### Upper Bound (Maximum Acceptable Scope) The A06_9 branch delivers: - A standalone `code_snapshot/radiomapvggt_v20_voxel_cir_detr/` package with its own `config.py`, dataset, model, trainer, losses, and metrics; no imports from `A06_7_*`. - A sparse 3D backbone built from TRELLIS-2's `SparseTransformerBlock`, `ModulatedSparseTransformerBlock`, and `SparseDownsample`, with 2–3 downsample stages kept sparse throughout (no forced dense grid). - A DETR-style head with `K` learnable path queries (default `K = 8`), Hungarian set matching, bounded-dB power regression, optional AdaLN modulation by TX embedding at the backbone stage and cross-attention to TX/RX features at the decoder stage. - A scene-token cache and a `(scene, TX)` memory cache so that per-RX compute is decoder-only in a batch. - A composite-rule checkpoint selector, a single-scene success gate, a scale-up manifest sweep (1 → 10 → 30 → 50 → 100 scenes), and a benchmark script reproducing tiny10 throughput. - Unit tests for the head's Hungarian matching, power bound, zero-path handling, and TX-injection invariance; a smoke import test; one end-to-end 10-step training test on a synthetic batch. - `reference/` with pinned clones of rf-detr, SEED, VoxelNeXt, each with a short `NOTES.md` listing which subsystem informed which design decision. ### Lower Bound (Minimum Acceptable Scope) A06_9 passes AC-1 through AC-10 with: - One backbone variant (one downsample stage is acceptable if justified by throughput). - Hungarian matching WITHOUT auxiliary pair-gap losses. - TX injection via AdaLN-zero modulation; RX strictly via learnable query + cross-attention only. - AC-5 caching invariants (`C_enc ≤ U` and `C_txmod ≤ P`) are mandatory; the minimum permitted implementation may satisfy `C_txmod ≤ P` via an in-step bucketized `(scene, TX)` grouping (no persistent cross-step cache object required), but per-step TX-modulation reruns per triple are NOT acceptable. - Single-scene gate + tiny10 run; the 30/50/100-scene runs are not a hard requirement for lower-bound acceptance. - `reference/` cloning is mandatory (AC-1); design notes per reference may be terse. ### Allowed Choices - Can use: TRELLIS-2 sparse ops (AdaLN-zero modulated blocks, SparseDownsample, SparseUpsample), FlexGEMM / torchsparse / spconv backends as configured upstream, FlashAttention for dense attention paths, scipy's `linear_sum_assignment` for Hungarian matching on CPU per-sample (standard DETR pattern), Huber or L1 for delay / dB regression, BCE or focal for existence. - Can use: bounded-range power parameterization (`db_low + (db_high − db_low) · σ(raw)`), additive dB offsets, learnable per-slot dB biases. - Cannot use: TX or RX as extra sparse voxel tokens prepended into the backbone; RX conditioning placed before the final downsample stage; ANY `floor_db + softplus(raw)` power parameterization regardless of `floor_db` value (this is a hard ban — the A06_9 head must use a bounded saturating map such as `db_low + (db_high − db_low) · σ(raw)` for every path-power output); rigid delay-ordered slot supervision anywhere in the live training loss (permitted only inside an explicitly labeled offline ablation script, not in `config.py` defaults); a single-metric checkpoint selector; silent truncation of zero-path samples; silent truncation of `num_paths > K` samples without metric recording; linearization of power before the regression loss. - Cannot use: the existing A06_7 `CSIPathSetHead`, `_collapse_paths_by_delay_slot`, or A06_7 trainer modules as live dependencies. They may be referenced as read-only for migration, but not imported. > **Note on Deterministic Designs**: The draft fixes several semantic choices (dB domain, query-based set prediction, TX/RX-as-modulation rather than tokens, 8-slot query budget as a starting guess, CSI-only scope, new branch path). The path boundaries above reflect these constraints. Items still under genuine choice (matching policy, target merging rule, RX injection placement, compute caching strategy, query budget `K`) are surfaced as `DEC-*` entries in `## Pending User Decisions`. ## Feasibility Hints and Suggestions > **Note**: This section is for reference and understanding only. These are conceptual suggestions, not prescriptive requirements. ### Conceptual Approach Pipeline for one forward step on a batch of `P` (scene, TX) pairs with `R_p` RXs each: 1. **Scene encoding (once per unique scene in the batch):** - Build sparse voxel input from scene occupancy (reuse A06_7 voxel cache format if still valid, else rebuild). - Run `S` stages of `ModulatedSparseTransformerBlock`, interleaved with `SparseDownsample` (e.g. 40 cm → 80 cm → 1.6 m base voxel size, capped at ~16³ effective resolution for the deepest stage; remains sparse throughout). Each block is modulated by a zero vector (no condition) or, optionally, a static scene-level embedding. Output: `scene_tokens_cache[scene_id]`. 2. **TX conditioning (once per unique `(scene, TX)` in the batch):** - Encode TX coordinate with a continuous Fourier embedding + small MLP → `tx_emb [D]`. - Run a shallow `ModulatedSparseTransformerBlock` stack over `scene_tokens_cache[scene_id]`, modulated by `tx_emb`. This is the TX-conditioned scene memory. Output: `tx_mem_cache[(scene_id, tx_id)]`. 3. **Query decoding (once per `(scene, TX, RX)` triple):** - Encode RX with a continuous Fourier embedding + small MLP → `rx_emb [D]`. - Instantiate `K` learnable path queries; add `rx_emb` as a modulation or as an added positional bias on the queries (RX goes LATE, never into the backbone). - Run `L` decoder layers of self-attention over queries + cross-attention to `tx_mem_cache[(scene_id, tx_id)]`. - Project to `(exists_logit, delay_pred_ns, peak_db_pred)` per query. Power is bounded via `db_low + (db_high − db_low) · σ(raw_peak)` with `db_low, db_high` set from dataset statistics (e.g., `-120 dB, -10 dB`). 4. **Matching and loss:** - For each `(scene, TX, RX)` sample in the batch, compute the DETR cost matrix between `K` predictions and `M` GT paths (cost = `α · |Δdelay_ns| + β · |Δpeak_db| + γ · BCE(exists)`). - Hungarian match via `scipy.optimize.linear_sum_assignment` on the CPU per sample (standard DETR pattern); matched pairs contribute delay / dB / exists losses, unmatched queries contribute no-object exists loss only. - Optional auxiliary: sort matched pairs by predicted delay, compute pair-gap losses over adjacent matched pairs only. ### Relevant References - `/data/conda_envs/trellis2/trellis2/modules/sparse/transformer/blocks.py` — `SparseTransformerBlock` class and signature. - `/data/conda_envs/trellis2/trellis2/modules/sparse/transformer/modulated.py` — `ModulatedSparseTransformerBlock` (AdaLN-zero), `ModulatedSparseTransformerCrossBlock` (self + cross + modulation). - `/data/conda_envs/trellis2/trellis2/modules/sparse/spatial/basic.py` — `SparseDownsample`, `SparseUpsample` (stride-2 sparse pool/gather). - `/data/jing_code/wl/radiomapvggt/v20_voxel_radiomap_cir/ablationstudy/A06_7_merged_tap_set_prediction/code_snapshot/radiomapvggt_v20_voxel_cir/models/csi_path_head.py` — legacy ordered-slot head; read-only reference for migration, not importable. - `/data/jing_code/wl/radiomapvggt/v20_voxel_radiomap_cir/ablationstudy/A06_7_merged_tap_set_prediction/reports/T08_A06_7_LASTPT_POWER_UNDERSHOOT_ANALYSIS_CN.md` — the documented failure mode this branch must avoid reproducing. - `/data/jing_code/wl/radiomapvggt/v20_voxel_radiomap_cir/ablationstudy/A06_7_merged_tap_set_prediction/code_snapshot/radiomapvggt_v20_voxel_cir/utils/metrics.py` — PDP cosine, peak dB MAE, tap match-rate utilities (pattern to match, not import). - `reference/rf-detr/` — DETR decoder, Hungarian matcher, no-object class handling. - `reference/SEED/` — DETR-style sparse 3D detection (closest analogue to the voxel-based set head). - `reference/VoxelNeXt/` — sparse voxel backbone with 3D downsampling. ## Dependencies and Sequence ### Milestones 1. **Milestone M1 — Repo scaffold and target contract (AC-1, AC-2, AC-10).** - Phase M1.A: Create the `code_snapshot/` tree, `reference/` with pinned clones, manifest for tiny10 single-scene, smoke import test. - Phase M1.B: Define the target contract (raw vs. merged, per DEC-1) in `data/csi_path_targets.py`. Emit the path-count histogram report used to justify `K`. - Phase M1.C: Verify zero-path samples survive collate. 2. **Milestone M2 — Backbone and caching (AC-4, AC-5).** - Phase M2.A: Port / vendor the minimum TRELLIS-2 sparse blocks required; confirm CUDA extensions build in the project's existing environment. - Phase M2.B: Implement the sparse 3D backbone with configurable downsample count; TX injection via AdaLN-zero. - Phase M2.C: Implement `scene_tokens_cache` and `(scene, TX)` memory cache in the trainer's batch loop; verify forward-call invariants from AC-5 via logged counters. 3. **Milestone M3 — DETR head, loss, matching (AC-3, AC-6, AC-9).** - Phase M3.A: Implement the head with `K` learnable queries, bounded-dB output, unit tests for shape/bound/finite. - Phase M3.B: Implement Hungarian matcher using `scipy.optimize.linear_sum_assignment`; unit test on synthetic batches. - Phase M3.C: Implement loss module strictly over matched-plus-no-object; unit test zero-path and all-matched cases. 4. **Milestone M4 — Metrics, checkpoint selection, gate (AC-7, AC-8, AC-9, AC-10).** - Phase M4.A: Implement the full validation metric bundle required by AC-7, AC-9, and AC-10: `pdp_cosine_nonzero`, `peak_db_mae_matched`, `peak_db_bias_matched`, `delay_mae_matched_ns`, `count_acc`, `nonzero_path_count_mae`, `zero_path_fpr`, `match_rate_over_all_samples`, and `gt_paths_truncated_rate`. - Phase M4.B: Implement composite checkpoint selector with the AC-7 guard rules (four hard feasibility guards + cosine primary + lexicographic tie-break + loud-fail `None` fallback). - Phase M4.C: Implement the single-scene → multi-scene gate; make scale-up a manifest sweep rather than a monolithic run. 5. **Milestone M5 — Single-scene and tiny10 validation runs (bring-up).** - Phase M5.A: Single-scene overfit bring-up (short run) — smoke test the pipeline. - Phase M5.B: Tiny10 bring-up on the pinned `benchmarks/tiny10_triples_manifest.json`; verify AC-5 caching invariants + triples/sec envelope and peak CUDA memory; verify AC-7 composite checkpoint selection *infrastructure* on short-run data. - Phase M5.C: Scale-up decision is DEFERRED to M7; M5 stops at bring-up. 6. **Milestone M6 — Training-speed optimization (AC-11).** Prerequisite for M7. - Phase M6.A: Profile the current tiny10 forward; classify time spent between (DataLoader, scene encode, TX modulation, decoder, head, backward). - Phase M6.B: Raise `--batch-triples` to the largest power-of-two that fits in 80 GB without OOM. Enable `DataLoader(num_workers≥4, pin_memory=True, persistent_workers=True, prefetch_factor=4)` as the training default. Confirm bf16 autocast on CUDA is the default for trellis2 forward. Report `reports/training_speed_optimization.md` with before/after numbers and `nvidia-smi dmon` GPU utilization. - Phase M6.C: Produce the optimized-config snapshot (batch, num_workers, autocast, lr baseline) that M7 consumes. No AC-8 attempt in M6. 7. **Milestone M7 — 200-epoch convergence sweep (AC-12).** Prerequisite: M6 landed. - Phase M7.A: Single-scene 200-epoch run under M6 config; write per-epoch CSV + every-10-epoch JSON metric bundle. Log `reports/single_scene_200ep.{md,csv,json}`. - Phase M7.B: Tiny10 200-epoch run under M6 config (same schedule); write `reports/tiny10_200ep.{md,csv,json}`. - Phase M7.C: Analyze both 200-epoch logs; `reports/convergence_analysis.md` recommends a default training-epoch budget and reports the best-metric epoch + earliest-feasibility-gate epoch per run. Records honestly whether AC-8 was reached in the 200-epoch window. 8. **Milestone M8 — Optional scale-up (conditional).** Conditional on M7's convergence-analysis verdict being favourable. - Phase M8.A: 30-scene run under the M7-recommended epoch budget. - Phase M8.B: 50-scene run. - Phase M8.C: 100-scene run. M8 as a whole is optional and does not block plan completion. Dependencies: M1 must complete before any model code is written. M2 blocks M3's end-to-end integration test. M3 blocks M4. M4 blocks M5. M5 blocks M6 (the speed optimization needs a working bring-up to profile against). M6 blocks M7. M7 blocks M8. Within M3, M3.A / M3.B / M3.C can be written in parallel but all three must pass unit tests before an end-to-end forward on real data is attempted. ## Task Breakdown Each task must include exactly one routing tag: - `coding`: implemented by Claude - `analyze`: executed via Codex (`/humanize:ask-codex`) | Task ID | Description | Target AC | Tag (`coding`/`analyze`) | Depends On | |---------|-------------|-----------|----------------------------|------------| | task1 | Build the empty `code_snapshot/` package skeleton, `reference/` clones with pinned commits, smoke-import test. | AC-1 | coding | - | | task2 | Analyze A06_7's Sionna CIR → supervised-path pipeline end-to-end and recommend a frozen target contract (raw vs merged, same-bin multipath behavior, truncation rule). | AC-2, DEC-1 | analyze | task1 | | task3 | Implement `data/csi_path_targets.py` under the chosen contract; add the path-count histogram utility; verify zero-path samples survive collate. | AC-2, AC-9, AC-10 | coding | task2 | | task4 | Analyze whether current A06_7 voxel caches and manifests are reusable for `(scene, TX, RX)` sampling or need a new collator. | AC-5 | analyze | task1 | | task5 | Implement the new collator and dataset for `(scene, TX, RX)` triples, reusing A06_7 voxel caches where valid. The collator MUST emit the frozen AC-3 batch tensor contract: `scene_idx [Q]`, `tx_scene_idx [Q]`, `rx_xyz_norm [Q, 3]`, `tx_xyz_norm [Q, 3]`, and the GT set tensors `gt_num_paths [Q]`, `gt_delay_ns [Q, M_max]`, `gt_peak_db [Q, M_max]`, `gt_path_mask [Q, M_max]`. | AC-5, AC-9 | coding | task4 | | task6 | Vendor the minimal TRELLIS-2 sparse module set needed (blocks, modulated blocks, sparse downsample, sparse backend adapter). Confirm the CUDA extensions build in the project environment. | AC-4 | coding | task1 | | task7 | Implement the sparse 3D backbone with configurable downsample count and AdaLN-zero TX modulation. | AC-4 | coding | task6 | | task8 | Implement the `scene_tokens_cache` and `(scene, TX)` memory cache in the trainer's batch iterator; add unit tests that assert BOTH `C_enc ≤ U` and `C_txmod ≤ P` on an injected batch with known `U`, `P`, `Q`. | AC-5 | coding | task7 | | task9 | Analyze and recommend bounded-dB power parameterization constants (`db_low`, `db_high`) from A06_7 tiny10 statistics. | AC-3, AC-6 | analyze | task3 | | task10 | Implement the DETR-style head: `K` queries, bounded-dB output, Hungarian matcher, unit tests. | AC-3 | coding | task9 | | task11 | Implement the loss module (matched-set regression + no-object BCE + optional matched-pair gap losses). | AC-6 | coding | task10 | | task12 | Implement the full validation metric bundle: `pdp_cosine_nonzero`, `peak_db_mae_matched`, `peak_db_bias_matched`, `delay_mae_matched_ns`, `count_acc`, `nonzero_path_count_mae`, `zero_path_fpr`, `match_rate_over_all_samples`, `gt_paths_truncated_rate`. | AC-7, AC-9, AC-10 | coding | task11 | | task13 | Implement the composite checkpoint selector with guard rules and regression tests. | AC-7 | coding | task12 | | task14 | Implement the single-scene success gate and the scale-up manifest orchestrator. | AC-8 | coding | task13 | | task15 | Implement the self-contained throughput benchmark script and verify the AC-5 caching invariants + triples/sec envelope on tiny10. (Plan Version 12: cross-model A06_7 comparison removed.) | AC-5 | coding | task8, task10 | | task16 | Run the single-scene bring-up experiment to smoke-test the pipeline; record honest gate status. AC-8 is NOT expected to pass at bring-up; the real AC-8 check happens inside task22's 200-epoch run. | AC-8 | coding | task14 | | task17 | Run the tiny10 bring-up experiment on `benchmarks/tiny10_triples_manifest.json`, collect the full AC-7/AC-9/AC-10 metric bundle on a short run, confirm AC-5 triples/sec envelope and peak memory, confirm composite checkpoint selection *infrastructure*. | AC-5, AC-7 | coding | task15, task16 | | task18 | Analyze the tiny10 bring-up report; recommend whether the pipeline is ready for 200-epoch sweeps. No cross-model A06_7 comparison required. | - | analyze | task17 | | task19 | Conditional: placeholder for any 30 / 50 / 100-scene manifest sweep. Now gated by task23, not task18. | - | coding | task23 | | task20 | Profile current tiny10 forward+backward at bring-up config; classify time spent between DataLoader, scene encode, TX modulation, decoder, head, backward. Report baseline GPU utilization via `nvidia-smi dmon -s u -c 30`. | AC-11 | analyze | task17 | | task21 | Implement training-speed optimization: raise `--batch-triples` to the largest OOM-safe power-of-two; enable `DataLoader(num_workers≥4, pin_memory=True, persistent_workers=True, prefetch_factor=4)` as default; confirm bf16 autocast on CUDA for trellis2 is the default. Produce `reports/training_speed_optimization.md` with before/after triples/sec, peak memory, GPU utilization, and data-loader time fraction. | AC-11 | coding | task20 | | task22 | Run the **single-scene 200-epoch sweep** with AC-12's schedule (lr=1e-4, at least one documented decay). Per-epoch CSV logging of loss + optimizer state; every-10-epoch JSON dump of the full AC-7 metric bundle. Write `reports/single_scene_200ep.{md,csv,json}`. Honestly record whether AC-8 gate is reached and at which epoch. | AC-12, AC-8 | coding | task21 | | task23 | Run the **tiny10 200-epoch sweep** with the same schedule as task22. Write `reports/tiny10_200ep.{md,csv,json}`. Then produce `reports/convergence_analysis.md` comparing the two 200-epoch logs: earliest-feasibility-gate epoch, peak-metric epoch, and a recommended default training-epoch budget for future runs. | AC-12, AC-7 | coding | task22 | ## Claude-Codex Deliberation ### Agreements - A06_7's CSI head is structurally trapped by `floor_db + softplus(raw)` power parameterization plus rigid ordered-slot supervision; a new branch is the correct response. - Power regression MUST stay in the dB domain and MUST be bounded to a realistic dB range; the predecessor's extreme `floor_db` is disallowed. - Zero-path samples, `zero_path_fpr`, and `peak_db_bias_matched` MUST be first-class citizens in data, loss, and validation. - Checkpoint selection via a single metric (`pdp_cosine_nonzero`) is pathological and MUST be replaced by a composite guarded rule. - The sample unit changes to `(scene, TX, RX)`; without scene-token caching, this inflates backbone compute per batch rather than reducing it. - TX modulation via AdaLN-zero over sparse transformer blocks (TRELLIS-2 pattern) is a sound replacement for treating TX as a token. - TRELLIS-2's `ModulatedSparseTransformerBlock`, `ModulatedSparseTransformerCrossBlock`, and `SparseDownsample` are the correct primitives to borrow; the sparse path does NOT need to be densified to a `16³` dense grid. - `K = 8` query budget is a draft starting value and MUST be validated against the tiny10 path-count histogram. - The single-scene success gate must precede multi-scene scale-up; CSI-only isolation from radiomap is a hard constraint for this branch. ### Resolved Disagreements - **Mixing Hungarian matching with rigid delay-ordered slot supervision.** Claude's v1 position: keep both as co-equal losses. Codex position: doing so reproduces the predecessor's failure trap because rigid ordering conflicts with set-prediction gradients. Resolution: Hungarian matching is the primary supervision; rigid ordered loss is forbidden in the primary loss and is moved entirely out of acceptance criteria into an optional offline ablation script. This is codified in AC-3, AC-6, the "Ablation and experiment notes" section, and the allowed-choice list. - **Dense `16³` latent compression.** Draft hint: "compress to 16×16×16 grid, TRELLIS-2-style 3D VAE." Codex position: forced dense compression likely destroys fine-scale cues critical for weak reflection paths. Resolution: keep sparse throughout; the deepest stage may operate at a coarse voxel size (e.g. 1.6 m base with reduced active voxels), but no forced dense grid. - **TX and RX injected symmetrically.** Draft position: both TX and RX as modulation into the backbone. Codex position: RX-conditioned backbone features cannot be reused across the RXs in a batch, killing throughput. Resolution: TX as AdaLN-zero modulation in the backbone (shared across all RXs for a given `(scene, TX)`); RX only in the decoder (late cross-attention or query-level bias). Codified in AC-4 / AC-5; surfaced as DEC-3 in ratify-or-reopen form. - **AC-5 throughput contract ambiguity (Round 1).** R1 Codex position: `steps/sec at matched batch size` is not stable when the sample unit changes. Resolution: AC-5 is rewritten to use normalized triples/sec on a pinned tiny10 triples manifest, plus `C_enc ≤ U` and `C_txmod ≤ P` invariants, plus peak CUDA memory accounting. - **Ambiguous batch tensor shape `[B, N, K]` (Round 1).** R1 Codex position: after the sample unit change, `B` and `N` are under-defined. Resolution: AC-3 introduces a single frozen batch tensor contract based on `Q` = number of `(scene, TX, RX)` triples, `U` = unique scenes, `P` = unique `(scene, TX)` pairs. All downstream sections (AC-5, AC-6, AC-7, AC-9, AC-10, hard invariants) reference this contract. - **Power parameterization loophole (Round 1).** R1 Codex position: AC-3 mandates bounded dB output but "Allowed Choices" leaves a `floor_db + softplus(raw)` loophole with moderate floor values. Resolution: `floor_db + softplus(raw)` is now banned regardless of floor; the only permitted parameterization is a bounded saturating map to `[db_low, db_high]`. - **Checkpoint selector under-specification (Round 1).** R1 Codex position: guards on bias + FPR alone still allow single-metric local optima on count / delay. Resolution: AC-7 now requires four hard feasibility guards (bias, zero-path FPR, count accuracy, delay MAE), a primary objective (cosine), a lexicographic tie-break, and a "no feasible epoch → return None" fallback. - **DEC-2 / DEC-3 / DEC-4 framing (Round 1).** R1 Codex position: these were marked pending but the plan text already hard-committed one side. Resolution: reframe each as "ratify-or-reopen" with explicit disclosure of the plan's currently-encoded default, so the user can either ratify the default (zero-cost) or request a rewrite (non-trivial replan). - **Ordered-slot ablation as acceptance criterion (Round 1).** R1 Codex position: useful but not a convergence gate. Resolution: moved from AC-3 positive test into "Ablation and experiment notes". - **Query-budget truncation measurement (Round 1).** R1 Codex position: histogram-and-documentation alone is not enough. Resolution: AC-10 now requires `gt_paths_truncated_rate` computed every validation epoch and surfaced in the AC-7 metric bundle. - **Pair-gap losses defaulting on (Round 1).** R1 Codex position: default them off for the first end-to-end run. Resolution: AC-6 now specifies `enable_pair_gap_losses = False` as the default; enabling requires an explicit config override. - **TRELLIS-2 dependency ambiguity (Round 1).** R1 Codex position: plan allows both vendored and live-env, weakening reproducibility. Resolution: new DEC-8 forces an explicit choice; vendored pinned subset is the recommended default. - **Lower-Bound contradiction (Round 2).** R2 Codex position: Lower Bound said "scene-token caching ONLY" while AC-5 and DEC-4 encoded both caches as mandatory, and it skipped AC-10. Resolution: Lower Bound now requires AC-1 through AC-10, explicitly restates that `C_enc ≤ U` AND `C_txmod ≤ P` are mandatory at minimum scope, and clarifies that a persistent cross-step cache object is optional so long as the per-step invariants hold. - **Stale metric-count wording (Round 2).** R2 Codex position: M4.A and task12 still said "six validation metrics" while the full bundle had grown. Resolution: M4.A and task12 now enumerate the complete nine-metric bundle (`pdp_cosine_nonzero`, `peak_db_mae_matched`, `peak_db_bias_matched`, `delay_mae_matched_ns`, `count_acc`, `nonzero_path_count_mae`, `zero_path_fpr`, `match_rate_over_all_samples`, `gt_paths_truncated_rate`), and task12 now targets AC-7, AC-9, and AC-10. - **task8 invariant coverage (Round 2).** R2 Codex position: task8 only mentioned encoder-call counts, leaving `C_txmod ≤ P` uncovered. Resolution: task8 now explicitly requires unit tests for BOTH `C_enc ≤ U` and `C_txmod ≤ P`. - **Secondary wording alignment (Round 2, optional).** R2 Codex noted M5.B / task17 / DEC-6 still used weaker "matched batch size" / "≤ 1.5× wall-clock" language. Resolution: all three now reference the pinned `benchmarks/tiny10_triples_manifest.json` and the `triples/sec ≥ 0.67 × A06_7 baseline` rule; AC-4 now ties its TRELLIS-2 source reference to DEC-8; task5 now explicitly emits the frozen AC-3 batch tensor contract. ### Convergence Status - Final Status: `converged` — all Round 1, Round 2, and Round 3 Codex items are incorporated in plan v3, and all eight user decisions (DEC-1 through DEC-8) are `RESOLVED` by user choice (recorded in each DEC entry above). No PENDING items remain. The plan is ready for `/humanize:start-rlcr-loop` execution. ## Pending User Decisions - DEC-1: **Target contract — raw physical paths or merged unique delay-bin paths?** - Claude Position: Merged unique delay-bin paths, to retain metric comparability with A06_7 and to avoid same-bin multipath ambiguity during Hungarian matching. Document the merge rule (e.g., two paths within < 0.1 ns collapse to one, power summed in dB via `10 · log10(10^(p1/10) + 10^(p2/10))`). - Codex Position: N/A — open question (Codex flagged this as under-specified; either choice is defensible if fixed once). - Tradeoff Summary: Raw paths preserve physical fidelity and are closer to Sionna's native output but make Hungarian matching ambiguous when two GT paths share a delay bin. Merged paths are easier to match and keep parity with A06_7's label pipeline but lose information about multipath that happens to be co-bin. - Decision Status: `RESOLVED — Merged delay-bin paths`. `data/csi_path_targets.py` implements the merge rule (co-bin dB-sum via `10·log10(Σ 10^(p_i/10))`); task3 is now unambiguous. - DEC-2: **Matching policy — ratify pure Hungarian (currently encoded) or reopen for staged coarse-to-fine?** - Plan's Currently-Encoded Default: Pure Hungarian matching. AC-3, AC-6, M3, and task10 are written under this assumption and enforce it. - Claude Position: Ratify pure Hungarian. Pair-gap auxiliary losses default OFF per AC-6. Staging deferred unless tiny10 fails. - Codex Position: Pure Hungarian is defensible once named and locked; acceptable as the plan default. Coarse-to-fine would require reopening AC-3 / AC-6 / task10. - Tradeoff Summary: Pure Hungarian is simpler, standard DETR, fewer moving parts. Staged coarse-to-fine (predict delay-bin occupancy first, regress top-k paths second) reduces search space but adds a second head and staging complexity. - Decision Status: `RESOLVED — Ratified pure Hungarian`. No rewrite of AC-3 / AC-6 / M3 / task10 required; pair-gap auxiliaries remain OFF by default. - DEC-3: **RX conditioning placement — ratify late-only (currently encoded) or reopen for full backbone modulation?** - Plan's Currently-Encoded Default: Late-only RX injection. AC-4 negative tests forbid RX into the backbone; AC-5 caching invariants assume scene/`(scene,TX)` features are RX-independent; lower-bound scope also assumes late-only. - Claude Position: Ratify late-only. This enables the AC-5 caching invariants; full backbone RX modulation would re-multiply backbone compute by the RX count per `(scene,TX)`. - Codex Position: Late-only is strongly preferred; full modulation forfeits cache reuse at the most expensive stage. - Tradeoff Summary: Late-only is a throughput multiplier; full modulation is more expressive but costs per-RX backbone reruns. Draft text implies symmetric TX/RX modulation. - Decision Status: `RESOLVED — Ratified late-only RX`. RX stays at the decoder; AC-4 / AC-5 stand as written. - DEC-4: **Compute caching scope — ratify "both caches mandatory" (currently encoded) or relax to scene-token-only?** - Plan's Currently-Encoded Default: Both caches mandatory for convergence. AC-5 positive tests require `C_txmod ≤ P`, which presumes `(scene, TX)` memory caching; task8 builds both caches; upper-bound scope requires both. - Claude Position: Ratify "both mandatory." Both caches easily fit in host/device memory for tiny10-scale runs. - Codex Position: Both caches are recommended; scene-only is acceptable as a relaxed minimum if memory pressure is real. - Tradeoff Summary: Both caches = less redundant compute, more memory pressure. Scene-only relaxes memory at the cost of a per-`(scene,TX)` TX-modulation rerun; this would weaken the AC-5 invariant `C_txmod ≤ P` to `C_txmod ≤ total (scene,TX) pair occurrences in batch`. - Decision Status: `RESOLVED — Ratified both caches mandatory`. AC-5's invariant `C_txmod ≤ P` stays mandatory; task8 implements both caches. - DEC-5: **Query budget `K` — fixed 8 or dataset-driven?** - Claude Position: Start at `K = 8` per draft, but only after confirming via the path-count histogram that tiny10 samples with more than 8 GT paths are ≤ 1%; otherwise raise `K` to cover ≥ 99% of samples. - Codex Position: Evidence-driven only. `K = 8` without histogram evidence is a silent truncation risk. - Tradeoff Summary: Larger `K` = more no-object queries and slightly more compute, but no truncation risk. Smaller `K` saves compute but may silently drop multipath-rich samples. The dataset statistic settles it. - Decision Status: `RESOLVED — Dataset-driven after histogram`. task3 emits the histogram first; `K` is then set so ≥ 99% of tiny10 samples satisfy `num_paths ≤ K`. Start from `K = 8` only if the evidence supports it. - DEC-6: **First hard success gate — single-scene overfit, tiny10 win over A06_7, or throughput gate?** - Claude Position: Single-scene overfit first (AC-8), then tiny10 triples/sec on the pinned manifest at ≥ 0.67 × A06_7 baseline on the same manifest (AC-5), then scale-up. - Codex Position: Option D (all three in sequence) is safest. - Tradeoff Summary: Single-scene gate first is fastest to fail-fast on fundamental architecture bugs. Tiny10 direct is more ambitious and exposes scaling / regularization issues earlier. Throughput gate first avoids spending GPU-hours on an inefficient forward pass. - Decision Status: `RESOLVED — Single-scene → tiny10 triples/sec → scale-up`. M5.A is the first mandatory gate; M5.B is the second; M5.C (30/50/100-scene sweep) is gated by M5.B success. - DEC-7: **Metric continuity with A06_7 — strict backward-comparable or CSI-only new metrics?** - Claude Position: Dual report — keep A06_7 metrics that are semantically valid under the new target contract (PDP cosine, count accuracy, peak dB MAE computed over matched pairs) AND add new set-prediction metrics (`zero_path_fpr`, `peak_db_bias_matched`, `match_rate_over_all_samples`, `gt_paths_truncated_rate`). - Codex Position: Dual report is the safer path during the branch's first validation; strict backward-compat may be impossible if DEC-1 chooses "raw paths." - Tradeoff Summary: Dual reporting slightly increases validation cost but makes cross-branch comparison with A06_7 reports feasible. Pure new metrics are cleaner but sever that comparability. - Decision Status: `RESOLVED — Dual report`. The AC-7 metric bundle includes both A06_7-comparable and new set-prediction metrics; M4.A and task12 remain as enumerated. - DEC-8: **TRELLIS-2 dependency handling — vendored pinned subset in-branch or live dependency on `/data/conda_envs/trellis2`?** - Claude Position: Vendored pinned subset. Copy only the minimal set of TRELLIS-2 sparse modules (blocks, modulated blocks, sparse down/upsample, sparse backend adapter, their CUDA extensions' build scripts) into `code_snapshot/vendor/trellis2_sparse/` with a pinned commit hash recorded. This makes the branch self-contained and reproducible. - Codex Position: Exactly one of vendored-pinned or live-env MUST be chosen. Allowing both (as v1 implied) weakens reproducibility and branch isolation. - Tradeoff Summary: Vendored = reproducible, robust to upstream TRELLIS-2 changes, heavier in-branch footprint, rebuild of CUDA extensions required once. Live dependency = lighter footprint, simpler initial bringup, BUT fragile: any upstream change silently alters A06_9 behavior, and the branch is not truly self-contained per AC-1's intent. - Decision Status: `RESOLVED — Vendored pinned subset in-branch`. task6 vendors the minimal TRELLIS-2 sparse module set into `code_snapshot/vendor/trellis2_sparse/` with a pinned commit hash recorded in `reference/MANIFEST.md`. AC-1 branch isolation stands; AC-4's import path resolves to the vendored subset. ## Implementation Notes ### Code Style Requirements - Implementation code and comments must NOT contain plan-specific terminology such as "AC-", "Milestone", "Step", "Phase", or similar workflow markers - These terms are for plan documentation only, not for the resulting codebase - Use descriptive, domain-appropriate naming in code instead ### Hard engineering invariants (derived from AC-3, AC-4, AC-5, AC-6, AC-7) - Sparse voxel encoder forward must be called at most `U` times per gradient step, where `U` = unique `scene_id`s in the batch (AC-5 invariant logged via a counter). - TX-modulation block forward must be called at most `P` times per gradient step, where `P` = unique `(scene_id, tx_id)` pairs in the batch (AC-5 invariant logged via a counter). - Power head output range must be clamped to `[db_low − ε, db_high + ε]` via a bounded parameterization; a runtime assert guards against drift. `floor_db + softplus(raw)` is banned regardless of floor value. - Loss modules must be pure functions of `(predictions, gt, matching)`; matching is computed once and passed through, never silently recomputed. - Pair-gap auxiliary losses default OFF; enabling them requires an explicit config flag; even when on, they compute only over matched pairs sorted by predicted delay. - Checkpoint selector must be implemented as a deterministic function of the validation metric table; unit tests cover both the canonical "best feasible" case and the "all epochs fail the guard → return None" regression case. - The batch tensor contract in AC-3 is the single source of truth for tensor shapes; any module that reshapes to ambiguous `[B, N, K]` notation must first normalize into the `[Q, K]` contract. ### Ablation and experiment notes (non-blocking) - An optional offline ablation script may swap Hungarian matching for rigid delay-ordered assignment to reproduce A06_7-like behavior for diagnostic comparison. This ablation is explicitly NOT a convergence gate and lives under `scripts/ablations/` rather than in the main training loop. - Memory accounting: the benchmark report from AC-5 includes peak CUDA memory alongside triples/sec so cache-strategy tradeoffs (DEC-4) remain visible. ### Device and environment assumptions - CUDA-only training; single-GPU tiny10 and single-scene runs; multi-GPU is optional for 30/50/100-scene runs. - TRELLIS-2 dependency handling is governed by DEC-8. Under the default (vendored pinned subset), the branch env rebuilds the CUDA extensions locally; under the live-env override, `/data/conda_envs/trellis2` is pinned to a specific commit and the branch is no longer fully self-contained. - Dataset artifacts (voxel caches, manifests, Sionna CIR labels) reuse the A06_7 paths; no new dataset generation is in scope. ## Output File Convention This template is used to produce the main output file (e.g., `plan.md`). ### Translated Language Variant When `alternative_plan_language` resolves to a supported language name through merged config loading, a translated variant of the output file is also written after the main file. Humanize loads config from merged layers in this order: default config, optional user config, then optional project config; `alternative_plan_language` may be set at any of those layers. The variant filename is constructed by inserting `_` (the ISO 639-1 code from the built-in mapping table) immediately before the file extension: - `plan.md` becomes `plan_.md` (e.g. `plan_zh.md` for Chinese, `plan_ko.md` for Korean) - `docs/my-plan.md` becomes `docs/my-plan_.md` - `output` (no extension) becomes `output_` The translated variant file contains a full translation of the main plan file's current content in the configured language. All identifiers (`AC-*`, task IDs, file paths, API names, command flags) remain unchanged, as they are language-neutral. When `alternative_plan_language` is empty, absent, set to `"English"`, or set to an unsupported language, no translated variant is written. Humanize does not auto-create `.humanize/config.json` when no project config file is present. --- Original Design Draft Start --- 我们这里设计一个DETR风格的3D的稀疏Transformer+3D下采样,融合的一个预测CSI的网络 就是说我们把每一个给定的场景下的一个TX和一个RX pair它的路径数。把它看成不定的,对吧,它本身就是不定,然后它每个路径数就是通过这样的query方式把它猜出来,这不就是一种DTR的风格嘛,只不过,我们这里要用到我们的场景是提速输入,然后我们TX和RX是坐标,我觉得它可以作为一种调制方式,作为输入进去,然后我们来学习和编码。至于其他的部分,可能你们自行参考和修改,选择一个合适的方式。大概至于这个数据的范围呀,约束呀,还有一些激活呀,这些小细节,我可能就需要你们自己来,嗯,还有网络结构啊,都要都都你们自己来决定 原先的这个版本,它就是说我觉得它其实还是有一些问题的,而且它已经积重难返了,那就开一个新的分支对吧 /data/jing_code/wl/radiomapvggt/v20_voxel_radiomap_cir/ablationstudy/A06_7_merged_tap_set_prediction 新分支我们放在这里 /data/jing_code/wl/radiomapvggt/v20_voxel_radiomap_cir/ablationstudy/A06_9_detr_style_voxel_sparse_3d_transformer_net 这里要设计指标 比如预测给定了一个TX,一个RX,还有它的场景,他们之间可能没有路径,也可能有3~4条不同路径四条不同的路径,它有它的时间的延时和它的一个信号的一个衰减,相当于是一个CIR 但是这些不同路径之间,他们的信号衰减可能是按DB来算的,可能iOS的路径它是-20多DB,那一次反射路径可能就直接降到了-50 DB. 所以说我们预测还有做这个处理,还是做损失,还是做一些其他的计算,最好都是在DB领域来做。因为如果你进行转换成线性领域的话,他可能就直接学习不了任何东西了 设计三个指标,首先对于每一条路径,我们看看预测的准不准,依次匹配。它的定义,比如一次性,我们最多预测8条路径,就相当于有8个slot,根据D,e, TR的风格,对吧?然后我们暂时规定:从第一个slot到第8个slot,它的延时上就是第一个slot预测延时到达最到达最快的那个,相当于我们按延时分布。第二个lo就是第二条到达路径。第三个就是第3条到达路径路径 然后我们计算这个是这个预测上的时间延时的损失,它就是一个时间延时的一个散度对吧, 我们还要预测每一个到达路径,它有一个线代表这条路径的信道衰减,预测的损失代表直接按DB来算,相当于代表了一个散度。我们这里自己定义一个可能物理意义上没那么好的散度。比如第一条路径真实值是-25 DB,预测是-20 DB,相当于有5 DB的差距。第二条路径是-50 DB,预测是-55 DB,相当于又是一个5 DB的差距,然后我们要算它的这样的一个,每次损失的它的一个均值和一个方差,相当于作为我们一个评判的指标 我现在是这么想的,我们这个CSI header它可能扩展成一个新的架构吧,就可能就是说,我们直接重新设计整个网络的结构。我现在是这么想的 嗯,主线任务1就是说我们的backbone部分,就是说我们是voxel的输入对吧 人的网络结构,还有它使用的一些基于稀疏的提速的处理,都来源于这个模型的借鉴,对吧 /data/TRELLIS.2 嗯,原始的A06-7,它还是前期的一些操作是可以保留下来的,就比如说他会对输入voxel做多层attention相互关注。 然后我们可以新增两个部分 第一个部分就是3D下采样,你可能有多种设计方案,你可以挑一个比较好的设计方案给我,然后参数量也不要太小,否则的话,他可能学不了什么东西 但是这里后面的话,我们可以,嗯,把它进行压缩,我觉得就是说我们把它进行3D的当sample,然后然后再做稀疏的3D的attention,然后再当sample,把它压缩成类似于16×16×16这样的一个grid,这里的借鉴就是借鉴于TRELLIS.2一种3D的Vae思想,对吧,然后 然后第二个部分 嗯,这里我只有一个大概的思路,所以我具体设计还要你们来搞里的话,可能它的block和层数可能不能太少,太少的话,可能他也学不到什么东西 就是多层的attention网络,加上我们的TX和RX的注入,所以我们把TX和RX token看成是一种条件的信息,是一种约束的条件信息,它是注入进来的。而我们的query token就是说我们预测给定的TX和RX token的它八条路径,这就是我们的query token 这里相当于说,OK, 我暂时没想好怎么注入比较好,但是我觉得它不应该是作为单独的token输入进来。我觉得它是可以作为注入的手段,让他理解OK,我们的TX是这样,RX这样注入到我们这样的一个attention网络里,就像那些,DiffuSiOn model或者是flow matching model, 他们是把这些条件信息注入进去的 TX token和RX token, 它可能会作为一种调制手段注入到我们的这些体素里,这里的话可以参考一下我们的这个TRELLIS.2 然后后面一个部分就是query,就是说我们固定好8个路径,最多8个路径来做query Query, 如何和我们最后的得到的attention再做融合?这个网络可能还要再设计一下,确保它的GPU利用率、显存占用率都得到合理的使用 可能也要用多层的attention m LP, 还有一些其他的东西. 嗯,主线任务2就是说我们要基于DETR的思想设计一个更好的输出头部分 这个首先它的输出头部分是DETR的思想,但我目前想法很朴素,可能后面你需要自己把它变得更加的完善和具体。相当于我们可能就是说我们固定了18个预测路径的slot,然后它相当于有8个query在这里,每个query它要输出它自己的一个它存不存在,然后它的时间延时和它预测的这样的路径的一个信号衰减。这是一个大概的思路,具体设计可能还要再参考很多别的设计和思路,最后最后让它的使用率和显存使用率能够有效的提高 主线主线任务3就是我们的损失函数,还有我们的这样的一个优化器,还有我们的学习力。这些东西可能还要重新设计一下,他们可能需要有效的能够训练他们: 然后每一个预测好的路径,他们之间也可以做处理。就比如说,我们预测了总共就3个路径,然后每个路径我们还要之间,就比如说,比如说它有三个路径,那第一条和第二条路径之间的延时和它们之间的功率项差距,也是可以拿来做损失和训练的。 第二条和第三条路径之间的延时,和他们的损失差距也是可以拿来做训练的。 然后,我们的网络可以先在一个场景上看看能不能学会,然后在10个场景看看看能不能学会。然后30个场景、50个场景、100个场景分别试一试,他的训练轮数可能要高一点,嗯,主要是第一TR他可能训练起来没那么容易,我觉得所以说。然后它的一个sample 可能已经变成了给定一个TX,给定一个RX,给定一个场景这样的一个sample了 这个sample相较于我们原先的sample,是一个TX加上一个Z轴平面的RX,相当于是一个TX和1296个RX,其实已经缩短了非常多了。所以说,我们可以把batch size之类东西开的高一点,嗯,可能还要优化一下,这样的话,保证我们的训练速度不要太慢 当然也许有其他的方法可以优化一下他的学习速度,或者是优化一下他的这样的一个批量输入和批量输出的速度和效率率,可以使它的GPU利用率高一点 一些可以借鉴的算法,你可以下载下来放到我们这个文件夹里,放到这个reference的文件夹,我们可能有多个不同的代码,可以作为借鉴和参考注意,我们主任务用的代码其实是基于 trellis 2 他的仓库和文件继续开发的 /data/conda_envs/trellis2 https://github.com/roboflow/rf-detr https://github.com/happinesslz/SEED https://github.com/JIA-Lab-research/VoxelNeXt 对于那个radio map header, 它的输出头,它的输入要一个TS和一个Z轴平面来实现。我觉得这个可以暂时先切割开来,暂时不不把它加入我们这里了。毕竟我们radioma它的预测已经效果已经很好了,它相当于那他的那一套处理方法已经感觉可以定型,不用管了,哪怕后面我们写论文的时候,也就相当于把它看成两条分支,完全单独处理也是可以的 甚至我觉得他们后续我们就把,如果我们的CSI这条重新设计的整个网络结构比较好的话,我们再把radio、map他们那些东西给重新加进来,就是作为额外分支加到我们已经训练好的这个网络里,再重新训练就行了。所以说就是先别管他们,总而言之就是先别管radiomap了,就先看看我们这样的一个新的模型架构能不能用 数据集就参考以前的数据集,就是我们基于之前的那个分支接着用就行 --- Original Design Draft End ---