HaiwangYu commited on
Commit
559bed2
·
1 Parent(s): 0ac8d54

tidy up dnn-roi description; add .json for l1sp

Browse files
dnn-roi/pdhd/20260615/README.md DELETED
@@ -1,120 +0,0 @@
1
- # PDHD DNN-ROI TorchScript models
2
-
3
- TorchScript (`.ts`) models loaded by the wire-cell-toolkit DNN-ROI nodes
4
- (`DNNROIFinding` / `DNNROIFindingMultiPlane`). All are exported with
5
- `DNN_ROI_SP/scripts/to_torchscript.py` and output `sigmoid` probabilities
6
- in `[0, 1]` (no extra sigmoid needed in Wire-Cell).
7
-
8
- | file | input ch | precision | size | run with |
9
- |---|---|---|---|---|
10
- | `CP43.ts` | 3 | FP32 | 20.4 MB | `run_nf_sp_dnnroi_evt.sh -n 3` (default) |
11
- | `kd_mbv3_transformer_bnKD_6ch.ts` | 6 | FP32 | 20.4 MB | `run_nf_sp_dnnroi_evt.sh -n 6` |
12
- | `qat_mbv3_transformer_bnKD_6ch_int8.ts` | 6 | INT8 (QAT) | 10.8 MB | `run_nf_sp_dnnroi_evt.sh -n 6 -D cpu` |
13
- | `pipe_base_mbv3_6ch.ts` | 6 | FP32 | 20.4 MB | `run_nf_sp_dnnroi_evt.sh -n 6` |
14
- | `pipe_distill_transformer_6ch.ts` | 6 | FP32 | 20.4 MB | `run_nf_sp_dnnroi_evt.sh -n 6` |
15
- | `pipe_qat_transformer_6ch_int8.ts` | 6 | INT8 (QAT) | 10.8 MB | `run_nf_sp_dnnroi_evt.sh -n 6 -D cpu` |
16
-
17
- ## Provenance
18
-
19
- | field | `CP43.ts` | `kd_..._6ch.ts` | `qat_..._6ch_int8.ts` |
20
- |---|---|---|---|
21
- | Architecture | MobileNetV3-large UNet | MobileNetV3-large UNet | QuantizableMobileNetV3-UNet, INT8 |
22
- | Source repo | `DNN_ROI_SP/` | `DNN_ROI_SP/` | `DNN_ROI_SP/` |
23
- | Run-id | `bs1_20260511-210525` | `distill_mbv3_transformer_bnKD_6ch_th150_ep100_l40s_ddp2` | `qat_distill_mbv3_transformer_bnKD_6ch_th150_ep20_l40s_ddp2` |
24
- | Checkpoint | `CP43.pth` | `CP70.pth` | `qat_int8_state.pth` |
25
- | Training | 3-ch baseline | Transformer teacher + bottleneck-feature KD | QAT-KD-C, warm-started from `CP70.pth` |
26
- | TorchScript mode | trace | trace | trace |
27
- | Held-out test Dice / ROI-eff | — | 0.9118 / 0.7609 | 0.8932 / 0.7274 |
28
-
29
- `to_torchscript.py` falls back to `torch.jit.trace` because `torch.jit.script`
30
- hits the `break` in the encoder loop; the INT8 quantized graph also cannot be
31
- scripted. The traced UNets are fully convolutional and run at both the
32
- per-plane (`800`) and stacked (`1600`) channel heights.
33
-
34
- ### Pipeline-reproduced models (2026-05-16)
35
-
36
- `pipe_base_mbv3_6ch.ts`, `pipe_distill_transformer_6ch.ts`, and
37
- `pipe_qat_transformer_6ch_int8.ts` are the three models deployed by the
38
- end-to-end run documented in `DNN_ROI_SP/docs/full_pipeline.md` — a baseline,
39
- the best distillation, and its QAT INT8 model, all 6-channel and trained on the
40
- same corpus and split.
41
-
42
- | field | `pipe_base_mbv3_6ch.ts` | `pipe_distill_transformer_6ch.ts` | `pipe_qat_transformer_6ch_int8.ts` |
43
- |---|---|---|---|
44
- | Architecture | MobileNetV3-large UNet | MobileNetV3-large UNet | QuantizableMobileNetV3-UNet, INT8 |
45
- | Run-id | `pipe_base_mbv3_6ch` | `pipe_distill_transformer_6ch` | `pipe_qat_transformer_6ch` |
46
- | Training | 6-ch baseline, no KD | Transformer teacher + bottleneck-feature KD | QAT-KD, warm-started from the distillation |
47
- | Held-out test Dice / ROI-eff | 0.9120 / 0.7474 | 0.9107 / 0.7454 | 0.8900 / 0.7305 |
48
-
49
- All three pass the toolkit-vs-standalone replay validation (max abs diff
50
- < 1.4e-6; the INT8 model bit-exact) — see `full_pipeline.md` §4.3.
51
-
52
- ## Input layout
53
-
54
- C++ tensor order is `(batch=1, ntags, nchannels, nticks)`:
55
-
56
- - `nchannels` = `800` per plane in per-plane (`pp`) mode, or `1600`
57
- (U+V stacked) in stacked (`mp`) mode. The W collection plane is not consumed.
58
- - `nticks` = `1500`, from PDHD's raw `6000` after `tick_per_slice=4`
59
- downsampling inside the C++ node.
60
-
61
- **3-channel model** (`CP43.ts`) — `ntags=3`, in order:
62
-
63
- ```
64
- loose_lf{APA}, mp2_roi{APA}, mp3_roi{APA}
65
- ```
66
-
67
- **6-channel models** — `ntags=6`, in order:
68
-
69
- ```
70
- loose_lf{APA}, mp2_roi{APA}, mp3_roi{APA}, tight_lf{APA}, decon_charge{APA}, gauss{APA}
71
- ```
72
-
73
- All six tags are emitted by the standard PDHD `OmnibusSigProc` chain
74
- (debug + multi-plane-protection mode) and require no SP-config change.
75
-
76
- ## Per-channel normalization (6-ch models)
77
-
78
- The 6-ch models are trained on inputs divided by **per-channel** z-scales:
79
-
80
- ```
81
- [944.6256, 4000.0, 4000.0, 803.7348, 1927.6997, 530.75]
82
- ```
83
-
84
- Wire-Cell's `DNNROIFinding` can only apply one **scalar** `input_scale` to all
85
- channels, so the per-channel division is **baked into the `.ts` module** as a
86
- fixed normalization layer. Consequently the 6-ch models must run with
87
- `input_scale = 1.0` — the `run_nf_sp_dnnroi_evt.sh -n 6` path sets this
88
- automatically (`dnnroi_pp.jsonnet`). `CP43.ts` keeps the C++ default
89
- `input_scale = 1/4000`.
90
-
91
- ## Tick padding
92
-
93
- The C++ node rebins the time axis by `tick_per_slice=4` before inference and
94
- needs the input tick count to be a multiple of the model's stride alignment.
95
- For the PDHD MobileNetV3-large UNet (no deep stride-2 cascade in the tick
96
- axis: post-rebin width 1500 = 4·375 is not divisible by 8 or higher powers
97
- of 2), the alignment requirement is just `nticks % tick_per_slice == 0`,
98
- i.e. **`nticks` must be a multiple of 4**. PDHD's standard `nticks=6000`
99
- satisfies this with no padding.
100
-
101
- The `dnnroi_pp.jsonnet` for PDHD leaves `tick_pad_multiple` unset (defaults
102
- to `tick_per_slice=4`). The C++ node pads to the next 4-multiple before
103
- inference, then crops back to `input_ticks` — a no-op for any
104
- `nticks % 4 == 0` (including 6000, 6400, 8000).
105
-
106
- ## Consumer
107
-
108
- Loaded by the toolkit C++ node `DNNROIFinding` (per-plane sequential: U
109
- and V each run their own forward call sharing one TorchService). Wired by
110
- `cfg/pgrapher/experiment/pdhd/dnnroi_pp.jsonnet`; driven by
111
- `wcp-porting-img/pdhd/run_nf_sp_dnnroi_evt.sh` (`-n 3|6` selects the
112
- input-channel set, `-M <model>` selects the `.ts`).
113
-
114
- ## Limitations
115
-
116
- - Trained on **APA0 only**. Inference on APAs 1–3 is out-of-domain.
117
- - W plane is not processed; downstream jsonnet routes it through a
118
- `PlaneSelector` passthrough.
119
- - The INT8 QAT model runs on **CPU only** (x86/fbgemm quantized backend);
120
- it cannot be placed on a GPU device.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dnn-roi/pdhd/20260615/README.pipe_distill_transformer_6ch.md DELETED
@@ -1,65 +0,0 @@
1
- # `pipe_distill_transformer_6ch.ts` — PDHD DNN-ROI (FP32, KD-Transformer)
2
-
3
- Single-file companion to the directory-level [`README.md`](README.md), which is
4
- the authoritative source for the full PDHD DNN-ROI model set, input layout,
5
- normalization, and tick-padding rules. This note documents only this one file.
6
-
7
- | field | value |
8
- |---|---|
9
- | file | `dnnroi/pdhd/pipe_distill_transformer_6ch.ts` |
10
- | size | 21,410,681 bytes (≈20.4 MB) |
11
- | architecture | MobileNetV3-large UNet |
12
- | precision | FP32 |
13
- | input channels | 6 |
14
- | output | per-pixel `sigmoid` probability in `[0, 1]` (no extra sigmoid in Wire-Cell) |
15
- | TorchScript mode | `torch.jit.trace` |
16
- | role | pipeline-reproduced FP32 distillation model |
17
-
18
- ## What it is
19
-
20
- The FP32 knowledge-distillation **Transformer-teacher** student for PDHD — the
21
- "best distillation" leg of the end-to-end run documented in
22
- `DNN_ROI_SP/docs/full_pipeline.md`. Trained 6-channel on the same corpus and
23
- split as its sibling baseline (`pipe_base_mbv3_6ch.ts`) and its QAT INT8 model
24
- (`pipe_qat_transformer_6ch_int8.ts`).
25
-
26
- | metric (held-out test) | value |
27
- |---|---|
28
- | Dice / ROI-eff | 0.9107 / 0.7454 |
29
- | run-id | `pipe_distill_transformer_6ch` |
30
- | training | Transformer teacher + bottleneck-feature KD |
31
-
32
- Passes the toolkit-vs-standalone replay validation (max abs diff < 1.4e-6) —
33
- see `full_pipeline.md` §4.3.
34
-
35
- ## Input / output
36
-
37
- C++ tensor order `(batch=1, ntags=6, nchannels, nticks)`. `nchannels = 800`
38
- per-plane (`pp` mode) or `1600` (U+V stacked, `mp` mode); the traced UNet is
39
- fully convolutional and runs at both heights. `nticks = 1500` (PDHD raw 6000
40
- after `tick_per_slice=4`). The 6 trace tags, in order:
41
-
42
- ```
43
- loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss
44
- ```
45
-
46
- All six tags come from the standard PDHD `OmnibusSigProc` chain (debug +
47
- multi-plane-protection mode) — no SP-config change needed. Per-channel z-scale
48
- normalization is **baked into the `.ts`**; run with `input_scale = 1.0`. Tick
49
- padding for PDHD only requires `nticks % 4 == 0`. Full details in the directory
50
- [`README.md`](README.md).
51
-
52
- ## Run with
53
-
54
- ```
55
- run_nf_sp_dnnroi_evt.sh -n 6
56
- ```
57
-
58
- (then `-M dnnroi/pdhd/pipe_distill_transformer_6ch.ts` to select this `.ts`).
59
- Wired by `cfg/pgrapher/experiment/pdhd/dnnroi_pp.jsonnet`; loaded by the toolkit
60
- C++ node `DNNROIFinding`.
61
-
62
- ## Limitations
63
-
64
- Trained on **APA0 only** — inference on APAs 1–3 is out-of-domain. The W plane
65
- is not processed (routed through a `PlaneSelector` passthrough).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dnn-roi/pdhd/20260615/pipe_distill_transformer_6ch.md ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PDHD DNN-ROI — `pipe_distill_transformer_6ch.ts`
2
+
3
+ TorchScript (`.ts`) DNN-ROI model for ProtoDUNE-HD (PDHD), loaded by the
4
+ wire-cell-toolkit DNN-ROI node `DNNROIFinding`. It produces a per-pixel
5
+ region-of-interest (ROI) probability map used to gate signal-processing output.
6
+
7
+ | field | value |
8
+ |---|---|
9
+ | file | `dnnroi/pdhd/pipe_distill_transformer_6ch.ts` |
10
+ | architecture | MobileNetV3-large UNet |
11
+ | precision | FP32 |
12
+ | input channels (tags) | 6 |
13
+ | output | per-pixel `sigmoid` probability in `[0, 1]` (no extra sigmoid needed in Wire-Cell) |
14
+ | TorchScript mode | `torch.jit.trace` |
15
+ | size | ≈20.4 MB (21,410,681 bytes) |
16
+
17
+ ## 1. How the model was trained
18
+
19
+ - **Architecture:** MobileNetV3-large UNet, exported to TorchScript with
20
+ `torch.jit.trace`. (`torch.jit.script` is not used because the encoder loop
21
+ contains a `break` that the scripter cannot handle.) The traced network is
22
+ fully convolutional and runs at both the per-plane (`800`) and stacked
23
+ (`1600`) channel heights.
24
+ - **Method:** knowledge distillation from a **Transformer teacher** using
25
+ bottleneck-feature KD. This is the "best distillation" leg of a matched
26
+ three-model set (a plain 6-ch baseline, this distilled model, and a QAT INT8
27
+ version), all 6-channel and trained on the same corpus and split.
28
+ - **Training data:** PDHD signal-processing frames, **APA0 only** (see
29
+ Limitations).
30
+ - **Held-out test metrics:** Dice **0.9107** / ROI-efficiency **0.7454**.
31
+ - **Validation:** passes toolkit-vs-standalone replay validation
32
+ (max absolute difference < 1.4e-6).
33
+ - **Hyperparameters** (epochs, thresholds, optimizer, dataset size/split
34
+ details): _W.I.P._
35
+
36
+ ## 2. Input / output
37
+
38
+ ### Input tensor
39
+
40
+ C++ tensor order `(batch=1, ntags=6, nchannels, nticks)`:
41
+
42
+ - **`ntags = 6`** — the 6 input trace tags, in this exact order:
43
+
44
+ ```
45
+ loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss
46
+ ```
47
+
48
+ All six tags are emitted by the standard PDHD `OmnibusSigProc` chain
49
+ (debug + multi-plane-protection mode) and require no signal-processing
50
+ config change.
51
+
52
+ - **`nchannels`** — `800` per plane in per-plane (`pp`) mode, or `1600`
53
+ (U+V stacked) in stacked (`mp`) mode. The W (collection) plane is not
54
+ consumed.
55
+
56
+ - **`nticks`** — `1500`, obtained from PDHD's raw `6000` ticks after
57
+ `tick_per_slice = 4` downsampling inside the C++ node.
58
+
59
+ ### Normalization (baked in)
60
+
61
+ The model was trained on inputs divided by **per-channel** z-scales:
62
+
63
+ ```
64
+ [944.6256, 4000.0, 4000.0, 803.7348, 1927.6997, 530.75]
65
+ ```
66
+
67
+ Because `DNNROIFinding` can apply only a single **scalar** `input_scale` to all
68
+ channels, this per-channel division is **baked into the `.ts` module** as a
69
+ fixed normalization layer. Therefore run this model with **`input_scale = 1.0`**.
70
+
71
+ ### Tick padding
72
+
73
+ The C++ node rebins the time axis by `tick_per_slice = 4` before inference and
74
+ requires the tick count to be a multiple of the model's stride alignment. For
75
+ this network the requirement is simply **`nticks % 4 == 0`**. PDHD's standard
76
+ `nticks = 6000` satisfies this with no padding (`tick_pad_multiple` may be left
77
+ unset, defaulting to `tick_per_slice = 4`). The node pads to the next
78
+ 4-multiple, runs inference, then crops back to `input_ticks` — a no-op for any
79
+ `nticks % 4 == 0` (e.g. 6000, 6400, 8000).
80
+
81
+ ### Output tensor
82
+
83
+ Per-pixel ROI probability in `[0, 1]` (`sigmoid` already applied inside the
84
+ model). No additional sigmoid should be applied in Wire-Cell.
85
+
86
+ ## 3. How to use
87
+
88
+ The model is loaded via a `TorchService` and consumed by the `DNNROIFinding`
89
+ node. Example wiring (from
90
+ [`dunereco/.../pdhd/wcls-rawdigit-dnnsp.jsonnet`](https://github.com/DUNE/dunereco/blob/25641a94aca58900c5e87f8e592f3d3aba166e6a/dunereco/DUNEWireCell/pdhd/wcls-rawdigit-dnnsp.jsonnet#L284)):
91
+
92
+ ```jsonnet
93
+ // TorchService pointing at this model
94
+ local ts = {
95
+ type: "TorchService",
96
+ name: "dnnroi",
97
+ data: {
98
+ model: "dnnroi/pdhd/pipe_distill_transformer_6ch.ts",
99
+ device: "cpu", // or "gpu"
100
+ concurrency: 1,
101
+ },
102
+ };
103
+
104
+ // DNN-ROI node, wired per anode; input_scale=1.0 because normalization
105
+ // is baked into the .ts (see §2). The dnnroi helper is imported from
106
+ // pgrapher/experiment/pdhd/dnnroi_pp.jsonnet.
107
+ local dnnroi = import 'pgrapher/experiment/pdhd/dnnroi_pp.jsonnet';
108
+
109
+ dnnroi(tools.anodes[n], ts, output_scale=1.0,
110
+ nticks=params.daq.nticks, nchunks=1),
111
+ ```
112
+
113
+ Notes:
114
+ - Run with **`input_scale = 1.0`** (normalization is baked in — see §2).
115
+ - Loaded by the toolkit C++ node `DNNROIFinding`, which processes U and V
116
+ planes sequentially (each plane runs its own forward call, sharing one
117
+ `TorchService`).
118
+
119
+ ## 4. Limitations
120
+
121
+ - Trained on **APA0 only** — inference on APAs 1–3 is out-of-domain.
122
+ - The **W (collection) plane is not processed**; downstream jsonnet routes it
123
+ through a `PlaneSelector` passthrough.
dnn-roi/pdvd/20260615/README.md DELETED
@@ -1,214 +0,0 @@
1
- # PDVD DNN-ROI TorchScript models
2
-
3
- TorchScript (`.ts`) models loaded by the wire-cell-toolkit DNN-ROI node
4
- `DNNROIFinding` (single-plane, per-plane sequential) for ProtoDUNE Vertical
5
- Drift. All are exported with `DNN_ROI_SP/scripts/to_torchscript.py` from the
6
- full-corpus 6-channel SDCC training campaign (DAGMan 287, 2026-05-20/21) and
7
- output `sigmoid` probabilities in `[0, 1]` (no extra sigmoid needed in
8
- Wire-Cell).
9
-
10
- > **2026-05-23 retrace.** The shipped `.ts` files were originally traced at
11
- > the stacked-plane shape `(1, 6, 952, 1600)` and crashed when fed the
12
- > per-plane shape `(1, 6, 476, 1600)` that the deployed `DNNROIFinding`
13
- > chain actually produces (119-vs-120 cat mismatch in `mobilenetv3_unet`'s
14
- > decoder skip at H=476). All five `.ts` files have been re-traced from
15
- > the same canonical checkpoints at the per-plane input shape; the trace
16
- > now records the model's runtime `F.interpolate` size-fixup at the
17
- > failing decoder layer (an aligned 120→119 bilinear, identity on
18
- > matched layers). Standalone replay through the re-traced
19
- > `pipe_distill_nestedunet_6ch.ts` reproduces the toolkit output to
20
- > max-abs `~5×10⁻⁷` on all 8 anodes × 2 induction planes for run 039324
21
- > evt 0 (`DNN_ROI_SP/scripts/verify_wirecell_dnn.py`).
22
-
23
- ## Production deployables
24
-
25
- The three files actively wired by the toolkit. The current default in
26
- `simulation/toolkit/pdvd/wct-nf-sp-dnnroi.jsonnet` is the INT8 primary
27
- (`pipe_qat_nestedunet_6ch_ep0_int8.ts`); flip `dnnroi_model` to a different
28
- row to swap.
29
-
30
- | file | input ch | precision | size | role | run with |
31
- |---|---|---|---|---|---|
32
- | `pipe_base_mbv3_6ch.ts` | 6 | FP32 | 20.4 MB | FP32 baseline (no KD) | `run_nf_sp_dnnroi_evt.sh -M dnnroi/pdvd/pipe_base_mbv3_6ch.ts` |
33
- | `pipe_distill_nestedunet_6ch.ts` | 6 | FP32 | 20.4 MB | FP32 best KD | `run_nf_sp_dnnroi_evt.sh -M dnnroi/pdvd/pipe_distill_nestedunet_6ch.ts` |
34
- | `pipe_qat_nestedunet_6ch_ep0_int8.ts`| 6 | INT8 (QAT) | 10.8 MB | **INT8 primary (default)** | `run_nf_sp_dnnroi_evt.sh -D cpu -M dnnroi/pdvd/pipe_qat_nestedunet_6ch_ep0_int8.ts` |
35
-
36
- ## Staged / diagnostic
37
-
38
- Not wired by default; kept so the user can re-run the §11 / §12.4
39
- comparisons without re-exporting from checkpoints. Both originate from the
40
- Transformer-teacher chain of DAGMan 287 — kept as a reference companion to
41
- the production NestedUNet-teacher chain above.
42
-
43
- | file | input ch | precision | size | role |
44
- |---|---|---|---|---|
45
- | `pipe_distill_transformer_6ch.ts` | 6 | FP32 | 20.4 MB | FP32 KD-Tx, used in §11 as a same-architecture FP32 reference for INT8-Tx |
46
- | `pipe_qat_transformer_6ch_ep3_int8.ts` | 6 | INT8 (QAT) | 10.8 MB | Tx INT8 candidate at epoch 3; narrows the §11 top-CRP regression but did not clear the strict §12.4 ≤10 % nzpx gate (an5 12.57 %). Held back from production pending an explicit decision; not the canonical Tx INT8. |
47
-
48
- (The previous canonical Tx INT8, `pipe_qat_transformer_6ch_int8.ts`, was
49
- derived from epoch 19 — the last-epoch fakequant that the un-patched
50
- `scripts/qat_kd_finetune.py` shipped by default. Per
51
- `DNN_ROI_SP/docs/qat_deployable_diagnostic_2026-05-21.md`, that ep19 ckpt
52
- was strictly dominated by ep3 on labeled Dice (0.7550 vs 0.7772) **and** on
53
- top-CRP over-emission. The ep19 `.ts` was removed in the 2026-05-21
54
- cleanup; if the user ever wants it back for a controlled comparison,
55
- re-export from `checkpoints/pdvd_qat_transformer_6ch/qat_int8_state.pth.ep19`
56
- on wcgpu1.)
57
-
58
- ## Provenance
59
-
60
- All exports trace back to DAGMan cluster **287** on SDCC
61
- (`sgpu0004`, 2× L40S, 2026-05-20 22:12 → 2026-05-21 06:51 EDT,
62
- ~8 h 40 min wall total). The training corpus is the 6-channel PDVD
63
- mix (1 000 train + 200 val + 400 held-out test, 125/25/50 events per
64
- anode × 8 anodes, `pdvd_anode{0..7}_6ch_th150_pad3.h5`).
65
-
66
- ### Production deployables
67
-
68
- | field | `pipe_base_mbv3_6ch` | `pipe_distill_nestedunet_6ch` | `pipe_qat_nestedunet_6ch_ep0_int8` |
69
- |---|---|---|---|
70
- | Architecture | MobileNetV3-large UNet | MobileNetV3-large UNet | QuantizableMobileNetV3-UNet, INT8 |
71
- | Run-id | `pdvd_mobilenetv3_all_6ch` | `pdvd_distill_nestedunet_6ch` | `pdvd_qat_nestedunet_6ch` |
72
- | Checkpoint | `CP97.pth` (best-val ep 97) | `CP35.pth` (best-val ep 35) | `qat_int8_state.pth.ep0` (best-by-post-convert) |
73
- | Training | 6-ch baseline, no KD, 100 ep | NestedUNet teacher + feature-map KD, 100 ep | QAT-KD INT8, 20 ep, warm-started from KD-NU (`pdvd_distill_nestedunet_6ch`) |
74
- | TorchScript mode | trace | trace | trace |
75
- | Held-out test (400 ev) Dice | 0.7538 | **0.7816** | 0.7797 |
76
- | Held-out test eff_roi / pur_roi | 0.7135 / 0.8594 | 0.7520 / 0.8537 | 0.7533 / 0.8490 |
77
-
78
- The KD-NestedUNet student (`pdvd_distill_nestedunet_6ch`) is the strongest
79
- FP32 model on test (Dice 0.7816, eff_roi 0.7520 — both #1 of the 5 FP32
80
- runs). The INT8 primary (`pdvd_qat_nestedunet_6ch` epoch 0) keeps 99.7 % of
81
- that FP32 Dice (0.7797 = −0.27 % vs FP32 KD parent) and clears the toolkit
82
- §12.4 ≤10 % nzpx gate on all 8 anodes (worst case 9.34 % on anode 5). The
83
- direct-MBV3 baseline is shipped as the no-KD reference.
84
-
85
- The INT8 primary's epoch choice (ep 0) is governed by post-convert dice
86
- peaking early in QAT, not the trainer's fakequant `val_dice`. See
87
- `DNN_ROI_SP/docs/qat_deployable_diagnostic_2026-05-21.md` for the full
88
- diagnostic and `DNN_ROI_SP/scripts/qat_kd_finetune.py`'s
89
- best-by-post-convert tracking that lands canonically going forward.
90
-
91
- ### Staged / diagnostic
92
-
93
- | field | `pipe_distill_transformer_6ch` | `pipe_qat_transformer_6ch_ep3_int8` |
94
- |---|---|---|
95
- | Architecture | MobileNetV3-large UNet | QuantizableMobileNetV3-UNet, INT8 |
96
- | Run-id | `pdvd_distill_transformer_6ch` | `pdvd_qat_transformer_6ch` |
97
- | Checkpoint | `CP99.pth` (best-val ep 99) | `qat_int8_state.pth.ep3` |
98
- | Held-out test Dice | 0.7680 | 0.7772 |
99
- | Notes | Diagnostic FP32 anchor for §11 / §12.4 same-arch INT8 comparison. Not the shipped FP32 deployable. | Tx-chain INT8 candidate. +1.20 % vs FP32 KD-Tx parent on labeled test Dice. Narrows the §11 top-CRP regression (an4 11.27 %→7.60 %, an5 17.63 %→12.57 %) but an5 still exceeds the §12.4 10 % strict gate; ep19 was deleted as superseded but no Tx INT8 .ts is wired as canonical until the residual is resolved (see `DNN_ROI_SP/memory/pdvd_int8_top_crp_oversegmentation.md`). |
100
-
101
- `to_torchscript.py` falls back to `torch.jit.trace` (the encoder `break`
102
- and the INT8 graph cannot be scripted); each export is verified by an
103
- eager-vs-TorchScript `allclose` (max abs diff 0.00e+00 for all five files).
104
-
105
- ## Input layout
106
-
107
- C++ tensor order is `(batch=1, ntags, nchannels, nticks)`:
108
-
109
- - `ntags` = **6**.
110
- - `nchannels` = **476** per plane. The two induction planes U and V are
111
- processed sequentially by two `DNNROIFinding` nodes per anode (sharing a
112
- single TorchService); the W collection plane is not consumed (passed
113
- through from standard SP gauss). See
114
- `cfg/pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet`.
115
- - `nticks` = **1600**, from PDVD's raw `6400` ticks after `tick_per_slice=4`
116
- downsampling inside the C++ node.
117
-
118
- The toolkit input per call is `(1, 6, 476, 1600)`. The PDVD students were
119
- trained on **stacked U+V at (1, 6, 952, 1600)**; per-plane deployment is
120
- structurally compatible (MobileNetV3-large is fully convolutional on the
121
- channel axis), and the re-traced `.ts` files include the runtime
122
- size-fixup the U-Net needs at this shape (see top-of-file note).
123
-
124
- **6-channel input** — `ntags=6`, trace tags in order:
125
-
126
- ```
127
- loose_lf{A}, mp2_roi{A}, mp3_roi{A}, tight_lf{A}, decon_charge{A}, gauss{A}
128
- ```
129
-
130
- The two new tags relative to the previous 4-ch deployment (`tight_lf` and
131
- `decon_charge`) must be emitted by PDVD's `OmnibusSigProc` chain in debug +
132
- multi-plane-protection mode — the same way PDHD 6-ch deployment works. The
133
- order matches the PDHD 6-ch sibling exactly.
134
-
135
- ## Per-channel normalization
136
-
137
- The 6-ch models are trained on inputs divided by **per-channel** z-scales.
138
- Wire-Cell's `DNNROIFinding` applies one scalar `input_scale`, so the
139
- per-channel division is baked into each `.ts` as a fixed normalization layer;
140
- the models run with `input_scale = 1.0` (set by
141
- `protodunevd/dnnroi_pp.jsonnet`).
142
-
143
- A single set is baked into all `.ts` files — the **cross-anode mean**:
144
-
145
- ```
146
- [766.1332, 4000.0, 4000.0, 762.4834, 1679.252, 11827.907]
147
- (loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss)
148
- ```
149
-
150
- The per-anode z-scales differ — z[0] runs ~50 % higher on the top CRP
151
- (anodes 4-7) than the bottom CRP (anodes 0-3). The cross-anode mean is an
152
- approximation; the unified vs split study
153
- (`DNN_ROI_SP/docs/pdvd_unified_vs_split_study.md`) shows one mixed model
154
- matches the per-half specialists, so a single set is shipped.
155
-
156
- ## Tick padding
157
-
158
- The C++ node rebins the time axis by `tick_per_slice=4` before inference;
159
- the PDVD MobileNetV3-large UNet was trained at post-rebin width
160
- **1600** (= `6400/4`), and 1600 = 64·25 has five spare factors of 2, so
161
- the deployed `.ts` has **5 stride-2 down/up levels** in the tick axis
162
- post-rebin. To survive that cascade the post-rebin width must be
163
- divisible by 2⁵ = 32, i.e. the input `nticks` must be a multiple of
164
- `tick_per_slice · 32 = 4·32 = 128`.
165
-
166
- `cfg/pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet` sets
167
- `tick_pad_multiple=128` by default; the C++ `DNNROIFinding` node then
168
- pads the input ticks up to the next 128-multiple before inference and
169
- crops the output back to the original `input_ticks`.
170
-
171
- | input `nticks` | padded `model_ticks` | output cropped to |
172
- |---|---|---|
173
- | 6000 | 6016 (= 47·128) | 6000 |
174
- | 6400 | 6400 (already 50·128) | 6400 |
175
- | 8000 | 8064 (= 63·128) | 8000 |
176
-
177
- A mismatch surfaces as a tensor-shape error inside the model at runtime,
178
- not as a toolkit-side check, so do not lower `tick_pad_multiple` for
179
- these models.
180
-
181
- ## Consumer
182
-
183
- Loaded by the toolkit C++ node `DNNROIFinding` (per-plane sequential:
184
- U and V each run their own forward call sharing one TorchService —
185
- analogous to the PDHD pp wiring). Wired by
186
- `cfg/pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet`; driven by
187
- `toolkit/pdvd/run_nf_sp_dnnroi_evt.sh` and
188
- `wcp-porting-img/pdvd/run_nf_sp_dnnroi_evt.sh` (`-M <model>` selects the
189
- `.ts`).
190
-
191
- The C++ `DNNROIFinding` node honors `debugfile` (set via the chain's
192
- `-X <basename>` flag) and writes one `{basename}_anode{N}_{plane}_call0.pt`
193
- per call containing `(input, output, meta)` — loadable with
194
- `DNN_ROI_SP/scripts/verify_wirecell_dnn.py` for offline 1:1 replay
195
- against the same `.ts`.
196
-
197
- ## Limitations
198
-
199
- - Trained on **all 8 PDVD anodes** (bottom CRP = anodes 0-3, top CRP =
200
- anodes 4-7) — the previous 4-channel deployment's "anodes 4-7
201
- out-of-domain" caveat no longer applies. See
202
- `DNN_ROI_SP/docs/pdvd_unified_vs_split_study.md` for evidence one model
203
- handles both halves.
204
- - The W collection plane is not processed; the toolkit jsonnet routes it
205
- through a `PlaneSelector` passthrough of standard SP gauss.
206
- - INT8 QAT models run on **CPU only** (x86 quantized backend); they cannot
207
- be placed on a GPU device.
208
- - The INT8 primary (NU ep0) is the result of a deployable-selection patch
209
- (best-by-post-convert dice). For runs that pre-date the patch, the
210
- trainer's last-epoch `qat_int8_state.pth` should not be assumed to be
211
- the best post-convert deployable — see the §12.6 follow-up in
212
- `DNN_ROI_SP/docs/sdcc_full_training_campaign.md` for details.
213
- - Cross-anode-mean z-scales are an approximation — see
214
- *Per-channel normalization* above.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dnn-roi/pdvd/20260615/README.pipe_distill_transformer_6ch.md DELETED
@@ -1,58 +0,0 @@
1
- # `pipe_distill_transformer_6ch.ts` — PDVD DNN-ROI (FP32, KD-Transformer)
2
-
3
- Single-file companion to the directory-level [`README.md`](README.md), which is
4
- the authoritative source for the full PDVD DNN-ROI model set, input layout,
5
- normalization, and tick-padding rules. This note documents only this one file.
6
-
7
- | field | value |
8
- |---|---|
9
- | file | `dnnroi/pdvd/pipe_distill_transformer_6ch.ts` |
10
- | size | 21,407,103 bytes (≈20.4 MB) |
11
- | architecture | MobileNetV3-large UNet |
12
- | precision | FP32 |
13
- | input channels | 6 |
14
- | output | per-pixel `sigmoid` probability in `[0, 1]` (no extra sigmoid in Wire-Cell) |
15
- | TorchScript mode | `torch.jit.trace` (re-traced 2026-05-23 at per-plane shape) |
16
- | role | **staged / diagnostic — not wired by default** |
17
-
18
- ## What it is
19
-
20
- The FP32 knowledge-distillation **Transformer-teacher** student for PDVD,
21
- exported from DAGMan cluster 287 (SDCC, 2026-05-20/21). It is the
22
- same-architecture FP32 reference used in the §11 / §12.4 INT8-vs-FP32
23
- comparisons against the Transformer INT8 candidate
24
- (`pipe_qat_transformer_6ch_ep3_int8.ts`). It is **not** the shipped FP32
25
- deployable — that is `pipe_distill_nestedunet_6ch.ts` (NestedUNet teacher,
26
- stronger on held-out test). See the directory README's *Staged / diagnostic*
27
- and *Provenance* sections.
28
-
29
- | metric (400-event held-out test) | value |
30
- |---|---|
31
- | Dice | 0.7680 |
32
- | run-id | `pdvd_distill_transformer_6ch` |
33
- | checkpoint | `CP99.pth` (best-val ep 99) |
34
-
35
- ## Input / output
36
-
37
- C++ tensor order `(batch=1, ntags=6, nchannels=476, nticks=1600)`, processed
38
- per-plane (U then V) by `DNNROIFinding`. The 6 trace tags, in order:
39
-
40
- ```
41
- loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss
42
- ```
43
-
44
- Per-channel z-scale normalization is **baked into the `.ts`**; run with
45
- `input_scale = 1.0`. Tick padding must use a multiple of
46
- `tick_per_slice·32 = 128`. Full details (the 5-level stride-2 cascade, the
47
- cross-anode-mean z-scales, the 2026-05-23 per-plane re-trace) are in the
48
- directory [`README.md`](README.md).
49
-
50
- ## Run with
51
-
52
- ```
53
- run_nf_sp_dnnroi_evt.sh -M dnnroi/pdvd/pipe_distill_transformer_6ch.ts
54
- ```
55
-
56
- Wired (when selected) by
57
- `cfg/pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet`. Loaded by the toolkit
58
- C++ node `DNNROIFinding`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dnn-roi/pdvd/20260615/pipe_distill_transformer_6ch.md ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PDVD DNN-ROI — `pipe_distill_transformer_6ch.ts`
2
+
3
+ TorchScript (`.ts`) DNN-ROI model for ProtoDUNE Vertical Drift (PDVD), loaded
4
+ by the wire-cell-toolkit DNN-ROI node `DNNROIFinding`. It produces a per-pixel
5
+ region-of-interest (ROI) probability map used to gate signal-processing output.
6
+
7
+ | field | value |
8
+ |---|---|
9
+ | file | `dnnroi/pdvd/pipe_distill_transformer_6ch.ts` |
10
+ | architecture | MobileNetV3-large UNet |
11
+ | precision | FP32 |
12
+ | input channels (tags) | 6 |
13
+ | output | per-pixel `sigmoid` probability in `[0, 1]` (no extra sigmoid needed in Wire-Cell) |
14
+ | TorchScript mode | `torch.jit.trace` (traced at the per-plane input shape) |
15
+ | size | ≈20.4 MB (21,407,103 bytes) |
16
+ | role | **diagnostic / reference — not the default production FP32 model** |
17
+
18
+ > **Which FP32 model should I use?** For production PDVD signal processing the
19
+ > recommended FP32 model is the NestedUNet-teacher student
20
+ > (`pipe_distill_nestedunet_6ch.ts`), which scores higher on the held-out test.
21
+ > This Transformer-teacher model is kept as a same-architecture FP32 reference
22
+ > for INT8-vs-FP32 comparisons.
23
+
24
+ ## 1. How the model was trained
25
+
26
+ - **Architecture:** MobileNetV3-large UNet, exported to TorchScript with
27
+ `torch.jit.trace`. (`torch.jit.script` is not used because the encoder loop
28
+ contains a `break` that the scripter cannot handle.) MobileNetV3-large is
29
+ fully convolutional on the channel axis; the model was trained on **stacked
30
+ U+V** input `(1, 6, 952, 1600)` but is deployed **per-plane** at
31
+ `(1, 6, 476, 1600)`. The traced `.ts` records the U-Net's runtime
32
+ size-fixup (an aligned bilinear interpolate at the decoder skip that would
33
+ otherwise mismatch at H=476), so it runs correctly at the per-plane shape.
34
+ - **Method:** knowledge distillation from a **Transformer teacher**.
35
+ - **Training data:** 6-channel PDVD corpus — 1,000 train + 200 val + 400
36
+ held-out test events (125/25/50 events per anode across **all 8 anodes**),
37
+ from the SDCC full-corpus 6-channel training campaign.
38
+ - **Checkpoint:** `CP99.pth` (best-val, epoch 99); run-id
39
+ `pdvd_distill_transformer_6ch`.
40
+ - **Held-out test metric:** Dice **0.7680** (400-event test set).
41
+ - **Validation:** standalone replay reproduces the toolkit output to
42
+ max absolute difference ≈ 5×10⁻⁷ (eager-vs-TorchScript `allclose` max abs
43
+ diff 0.00 at export).
44
+ - **Hyperparameters** (optimizer, learning rate, exact epoch count/schedule):
45
+ _W.I.P._
46
+
47
+ ## 2. Input / output
48
+
49
+ ### Input tensor
50
+
51
+ C++ tensor order `(batch=1, ntags=6, nchannels=476, nticks=1600)`, processed
52
+ per-plane (U then V):
53
+
54
+ - **`ntags = 6`** — the 6 input trace tags, in this exact order:
55
+
56
+ ```
57
+ loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss
58
+ ```
59
+
60
+ All six tags are emitted by PDVD's `OmnibusSigProc` chain (debug +
61
+ multi-plane-protection mode). Relative to the older 4-channel deployment,
62
+ the two additional tags are `tight_lf` and `decon_charge`; the order matches
63
+ the PDHD 6-channel model exactly.
64
+
65
+ - **`nchannels = 476`** per plane. The two induction planes U and V are
66
+ processed sequentially by two `DNNROIFinding` nodes per anode (sharing one
67
+ `TorchService`). The W (collection) plane is not consumed.
68
+
69
+ - **`nticks = 1600`**, from PDVD's raw `6400` ticks after `tick_per_slice = 4`
70
+ downsampling inside the C++ node.
71
+
72
+ ### Normalization (baked in)
73
+
74
+ The model was trained on inputs divided by **per-channel** z-scales. Because
75
+ `DNNROIFinding` can apply only a single **scalar** `input_scale`, the
76
+ per-channel division is **baked into the `.ts` module** as a fixed
77
+ normalization layer. Therefore run this model with **`input_scale = 1.0`**.
78
+
79
+ The baked-in z-scales are the **cross-anode mean**:
80
+
81
+ ```
82
+ [766.1332, 4000.0, 4000.0, 762.4834, 1679.252, 11827.907]
83
+ (loose_lf, mp2_roi, mp3_roi, tight_lf, decon_charge, gauss)
84
+ ```
85
+
86
+ Per-anode z-scales differ (channel 0 runs ~50% higher on the top CRP,
87
+ anodes 4–7, than the bottom CRP, anodes 0–3); a single cross-anode-mean set is
88
+ shipped as an approximation validated to match per-half specialists.
89
+
90
+ ### Tick padding
91
+
92
+ The C++ node rebins the time axis by `tick_per_slice = 4` before inference.
93
+ This network has **5 stride-2 down/up levels** in the (post-rebin) tick axis,
94
+ so the post-rebin width must be divisible by 2⁵ = 32 — i.e. the input
95
+ `nticks` must be a **multiple of `tick_per_slice · 32 = 128`**. Set
96
+ `tick_pad_multiple = 128`; the node pads up to the next 128-multiple before
97
+ inference and crops the output back to the original `input_ticks`:
98
+
99
+ | input `nticks` | padded `model_ticks` | output cropped to |
100
+ |---|---|---|
101
+ | 6000 | 6016 (= 47·128) | 6000 |
102
+ | 6400 | 6400 (already 50·128) | 6400 |
103
+ | 8000 | 8064 (= 63·128) | 8000 |
104
+
105
+ Do **not** lower `tick_pad_multiple` for this model — a mismatch surfaces as a
106
+ tensor-shape error inside the model at runtime, not as a toolkit-side check.
107
+
108
+ ### Output tensor
109
+
110
+ Per-pixel ROI probability in `[0, 1]` (`sigmoid` already applied inside the
111
+ model). No additional sigmoid should be applied in Wire-Cell.
112
+
113
+ ## 3. How to use
114
+
115
+ The model is loaded via a `TorchService` and consumed by the `DNNROIFinding`
116
+ node. Example wiring (analogous to the PDHD
117
+ [`wcls-rawdigit-dnnsp.jsonnet`](https://github.com/DUNE/dunereco/blob/25641a94aca58900c5e87f8e592f3d3aba166e6a/dunereco/DUNEWireCell/pdhd/wcls-rawdigit-dnnsp.jsonnet#L284)
118
+ pattern):
119
+
120
+ ```jsonnet
121
+ // TorchService pointing at this model
122
+ local ts = {
123
+ type: "TorchService",
124
+ name: "dnnroi",
125
+ data: {
126
+ model: "dnnroi/pdvd/pipe_distill_transformer_6ch.ts",
127
+ device: "cpu", // or "gpu"
128
+ concurrency: 1,
129
+ },
130
+ };
131
+
132
+ // DNN-ROI node, wired per anode; input_scale=1.0 because normalization
133
+ // is baked into the .ts (see §2), and tick_pad_multiple=128 (see §2).
134
+ // The dnnroi helper is imported from
135
+ // pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet.
136
+ local dnnroi = import 'pgrapher/experiment/protodunevd/dnnroi_pp.jsonnet';
137
+
138
+ dnnroi(tools.anodes[n], ts, output_scale=1.0,
139
+ nticks=params.daq.nticks, nchunks=1),
140
+ ```
141
+
142
+ Notes:
143
+ - Run with **`input_scale = 1.0`** and **`tick_pad_multiple = 128`**
144
+ (both set by `protodunevd/dnnroi_pp.jsonnet`).
145
+ - Loaded by the toolkit C++ node `DNNROIFinding`, which processes the U and V
146
+ induction planes sequentially (each plane runs its own forward call, sharing
147
+ one `TorchService`). The W plane is routed through a `PlaneSelector`
148
+ passthrough of standard SP gauss.
149
+
150
+ ## 4. Limitations
151
+
152
+ - The **W (collection) plane is not processed**; downstream jsonnet routes it
153
+ through a `PlaneSelector` passthrough.
154
+ - The baked-in cross-anode-mean z-scales are an approximation (per-anode
155
+ z-scales differ, especially top vs bottom CRP — see §2).
156
+ - This is a **diagnostic / reference** model, not the recommended production
157
+ FP32 deployable (see the note at the top).
l1sp/pdhd/20260615/l1sp_dnn_pdhd_v1.meta.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "experiment_dir": "/nfs/data/1/xqian/toolkit-dev/l1sp_dl_tagger/experiments/stage_a_pu_round4",
3
+ "vae_ckpt": "/nfs/data/1/xqian/toolkit-dev/l1sp_dl_tagger/experiments/stage_b_vae/model_n16.pt",
4
+ "vae_n_lat": 16,
5
+ "git_sha": "708b942b199e2cc7395e9e3468b926b8146e171b",
6
+ "nbin": 256,
7
+ "amp_floor": 1.0,
8
+ "n_features": 30,
9
+ "feature_order": [
10
+ "nbin_fit",
11
+ "temp_sum",
12
+ "temp1_sum",
13
+ "temp2_sum",
14
+ "max_val",
15
+ "min_val",
16
+ "prev_gap",
17
+ "next_gap",
18
+ "flag",
19
+ "ratio",
20
+ "temp_sum_pos",
21
+ "temp_sum_neg",
22
+ "n_above_pos",
23
+ "n_above_neg",
24
+ "argmax_tick",
25
+ "argmin_tick",
26
+ "sig_peak",
27
+ "sig_integral",
28
+ "gmax",
29
+ "gauss_fill",
30
+ "gauss_fwhm_frac",
31
+ "roi_energy_frac",
32
+ "raw_asym_wide",
33
+ "core_lo",
34
+ "core_hi",
35
+ "core_length",
36
+ "core_fill",
37
+ "core_fwhm_frac",
38
+ "core_raw_asym_wide",
39
+ "vae_kl"
40
+ ],
41
+ "scalar_feature_order": [
42
+ "nbin_fit",
43
+ "temp_sum",
44
+ "temp1_sum",
45
+ "temp2_sum",
46
+ "max_val",
47
+ "min_val",
48
+ "prev_gap",
49
+ "next_gap",
50
+ "flag",
51
+ "ratio",
52
+ "temp_sum_pos",
53
+ "temp_sum_neg",
54
+ "n_above_pos",
55
+ "n_above_neg",
56
+ "argmax_tick",
57
+ "argmin_tick",
58
+ "sig_peak",
59
+ "sig_integral",
60
+ "gmax",
61
+ "gauss_fill",
62
+ "gauss_fwhm_frac",
63
+ "roi_energy_frac",
64
+ "raw_asym_wide",
65
+ "core_lo",
66
+ "core_hi",
67
+ "core_length",
68
+ "core_fill",
69
+ "core_fwhm_frac",
70
+ "core_raw_asym_wide"
71
+ ],
72
+ "kl_index": 29,
73
+ "default_threshold": 0.9945,
74
+ "threshold_notes": "default_threshold=0.9945 \u2014 set by --default-threshold at export time. Convention is to use the p99.9 of the data-corpus score distribution from the training run; see the experiment dir's notes.md for the value that was promoted.",
75
+ "model_io": {
76
+ "forward.inputs": [
77
+ {
78
+ "name": "waveform",
79
+ "shape": [
80
+ "B",
81
+ 1,
82
+ 2,
83
+ 256
84
+ ],
85
+ "dtype": "float32",
86
+ "notes": "channel 0 = raw/scale, channel 1 = decon/scale, where scale = max(|raw|.max, |decon|.max, 1.0); window = full ROI right-padded to 256, OR \u00b1128 ticks centered on argmax(|decon|) clamped to ROI bounds. The dim-1 axis is a dummy to satisfy WCT's Pytorch::from_itensor 4-D requirement."
87
+ },
88
+ {
89
+ "name": "scalars",
90
+ "shape": [
91
+ "B",
92
+ 1,
93
+ 1,
94
+ 29
95
+ ],
96
+ "dtype": "float32",
97
+ "notes": "29 scalars in scalar_feature_order"
98
+ }
99
+ ],
100
+ "forward.output": {
101
+ "name": "score",
102
+ "shape": [
103
+ "B",
104
+ 1,
105
+ 1,
106
+ 1
107
+ ],
108
+ "dtype": "float32",
109
+ "notes": "sigmoid in [0, 1]; cut at default_threshold"
110
+ }
111
+ }
112
+ }
l1sp/pdvd/20260615/l1sp_dnn_pdvd_v1.meta.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "experiment_dir": "/nfs/data/1/xqian/toolkit-dev/l1sp_dl_tagger/experiments/stage_a_pu_round2_pdvd",
3
+ "vae_ckpt": "/nfs/data/1/xqian/toolkit-dev/l1sp_dl_tagger/experiments/stage_b_vae/model_n16.pt",
4
+ "vae_n_lat": 16,
5
+ "git_sha": "cd038ae0da106fd215a54a061824daa835f05fc6",
6
+ "nbin": 256,
7
+ "amp_floor": 1.0,
8
+ "n_features": 30,
9
+ "feature_order": [
10
+ "nbin_fit",
11
+ "temp_sum",
12
+ "temp1_sum",
13
+ "temp2_sum",
14
+ "max_val",
15
+ "min_val",
16
+ "prev_gap",
17
+ "next_gap",
18
+ "flag",
19
+ "ratio",
20
+ "temp_sum_pos",
21
+ "temp_sum_neg",
22
+ "n_above_pos",
23
+ "n_above_neg",
24
+ "argmax_tick",
25
+ "argmin_tick",
26
+ "sig_peak",
27
+ "sig_integral",
28
+ "gmax",
29
+ "gauss_fill",
30
+ "gauss_fwhm_frac",
31
+ "roi_energy_frac",
32
+ "raw_asym_wide",
33
+ "core_lo",
34
+ "core_hi",
35
+ "core_length",
36
+ "core_fill",
37
+ "core_fwhm_frac",
38
+ "core_raw_asym_wide",
39
+ "vae_kl"
40
+ ],
41
+ "scalar_feature_order": [
42
+ "nbin_fit",
43
+ "temp_sum",
44
+ "temp1_sum",
45
+ "temp2_sum",
46
+ "max_val",
47
+ "min_val",
48
+ "prev_gap",
49
+ "next_gap",
50
+ "flag",
51
+ "ratio",
52
+ "temp_sum_pos",
53
+ "temp_sum_neg",
54
+ "n_above_pos",
55
+ "n_above_neg",
56
+ "argmax_tick",
57
+ "argmin_tick",
58
+ "sig_peak",
59
+ "sig_integral",
60
+ "gmax",
61
+ "gauss_fill",
62
+ "gauss_fwhm_frac",
63
+ "roi_energy_frac",
64
+ "raw_asym_wide",
65
+ "core_lo",
66
+ "core_hi",
67
+ "core_length",
68
+ "core_fill",
69
+ "core_fwhm_frac",
70
+ "core_raw_asym_wide"
71
+ ],
72
+ "kl_index": 29,
73
+ "default_threshold": 0.16,
74
+ "threshold_notes": "default_threshold=0.16 \u2014 set by --default-threshold at export time. Convention is to use the p99.9 of the data-corpus score distribution from the training run; see the experiment dir's notes.md for the value that was promoted.",
75
+ "model_io": {
76
+ "forward.inputs": [
77
+ {
78
+ "name": "waveform",
79
+ "shape": [
80
+ "B",
81
+ 1,
82
+ 2,
83
+ 256
84
+ ],
85
+ "dtype": "float32",
86
+ "notes": "channel 0 = raw/scale, channel 1 = decon/scale, where scale = max(|raw|.max, |decon|.max, 1.0); window = full ROI right-padded to 256, OR \u00b1128 ticks centered on argmax(|decon|) clamped to ROI bounds. The dim-1 axis is a dummy to satisfy WCT's Pytorch::from_itensor 4-D requirement."
87
+ },
88
+ {
89
+ "name": "scalars",
90
+ "shape": [
91
+ "B",
92
+ 1,
93
+ 1,
94
+ 29
95
+ ],
96
+ "dtype": "float32",
97
+ "notes": "29 scalars in scalar_feature_order"
98
+ }
99
+ ],
100
+ "forward.output": {
101
+ "name": "score",
102
+ "shape": [
103
+ "B",
104
+ 1,
105
+ 1,
106
+ 1
107
+ ],
108
+ "dtype": "float32",
109
+ "notes": "sigmoid in [0, 1]; cut at default_threshold"
110
+ }
111
+ }
112
+ }