Commit 81698963 authored by Andrey Filippov's avatar Andrey Filippov

CLAUDE: Configurable DNN patch size (curt_dnn_patch) for larger-attention model

inferROI's receptive-field patch was hardcoded P=24. Add CuasDnnInfer.setPatch
and new param curt_dnn_patch (default 24) so a wider-attention model (patch 32)
can be deployed: CuasDetectRT sets it on the inferer. The 32-patch model widens
off-center suppression reach (off_max 9->13 px) and removes the trajectory-alias
ghosts seen in the clean synthetic grid (field ~0.16 -> ~0.003). Must match the
loaded model's training patch.
Co-Authored-By: 's avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 0bd16311
...@@ -1207,6 +1207,7 @@ public class CuasDetectRT { ...@@ -1207,6 +1207,7 @@ public class CuasDetectRT {
final int dnn_stride = Math.max(1, clt_parameters.imp.curt_dnn_stride); // 1 = every slice (testing), 4 = production 50% overlap // By Claude on 06/14/2026 final int dnn_stride = Math.max(1, clt_parameters.imp.curt_dnn_stride); // 1 = every slice (testing), 4 = production 50% overlap // By Claude on 06/14/2026
try { // By Claude on 06/13/2026 try { // By Claude on 06/13/2026
CuasDnnInfer dnn = new CuasDnnInfer(clt_parameters.imp.curt_dnn_model, 8); // 8 = fallback hint only // By Claude on 06/13/2026 CuasDnnInfer dnn = new CuasDnnInfer(clt_parameters.imp.curt_dnn_model, 8); // 8 = fallback hint only // By Claude on 06/13/2026
dnn.setPatch(clt_parameters.imp.curt_dnn_patch); // 24 or 32 (RF/training patch) - must match the loaded model // By Claude on 06/16/2026
final int N_dnn = dnn.getNFrames(); // 8 or 9, read from the loaded ONNX input shape -> 8/9 models swap at runtime // By Claude on 06/15/2026 final int N_dnn = dnn.getNFrames(); // 8 or 9, read from the loaded ONNX input shape -> 8/9 models swap at runtime // By Claude on 06/15/2026
for (int nlev = 0; nlev < pyramid_levels; nlev++) { // By Claude on 06/13/2026 for (int nlev = 0; nlev < pyramid_levels; nlev++) { // By Claude on 06/13/2026
if (!c5LevelSelected(c5_levels, nlev)) continue; // level gating (curt_c5_levels) // By Claude on 06/13/2026 if (!c5LevelSelected(c5_levels, nlev)) continue; // level gating (curt_c5_levels) // By Claude on 06/13/2026
......
...@@ -31,6 +31,7 @@ public class CuasDnnInfer implements AutoCloseable { ...@@ -31,6 +31,7 @@ public class CuasDnnInfer implements AutoCloseable {
private final OrtSession session; private final OrtSession session;
private final String inputName; private final String inputName;
private final int nframes; private final int nframes;
private int patch = 24; // receptive-field / training patch (24 or 32); set via setPatch to match the model. By Claude on 06/16/2026
public CuasDnnInfer(String modelSpec, int nframes) throws Exception { public CuasDnnInfer(String modelSpec, int nframes) throws Exception {
String local = resolveModel(modelSpec); String local = resolveModel(modelSpec);
...@@ -57,6 +58,10 @@ public class CuasDnnInfer implements AutoCloseable { ...@@ -57,6 +58,10 @@ public class CuasDnnInfer implements AutoCloseable {
/** Temporal depth the loaded model expects (N frames), read from its input shape. By Claude on 06/15/2026 */ /** Temporal depth the loaded model expects (N frames), read from its input shape. By Claude on 06/15/2026 */
public int getNFrames() { return nframes; } public int getNFrames() { return nframes; }
/** Set the receptive-field / training patch size (24 or 32) the model was trained at;
* inferROI extracts this P×P patch per ROI pixel (half=P/2 = the output-pixel index). By Claude on 06/16/2026 */
public void setPatch(int p) { if (p > 0) this.patch = p; }
/** Run one patch. frames = [N][H][W] (newest first). Returns the raw output channels /** Run one patch. frames = [N][H][W] (newest first). Returns the raw output channels
* [outCh] for the center output pixel: [0]=det logit, [1..V*V]=vel logits, last 2 = offset. */ * [outCh] for the center output pixel: [0]=det logit, [1..V*V]=vel logits, last 2 = offset. */
public float[] inferRaw(float[][][] frames) throws Exception { public float[] inferRaw(float[][][] frames) throws Exception {
...@@ -89,7 +94,7 @@ public class CuasDnnInfer implements AutoCloseable { ...@@ -89,7 +94,7 @@ public class CuasDnnInfer implements AutoCloseable {
* offset channels (op[1+nvel], op[1+nvel+1]) - the DNN's per-pixel sub-pixel position estimate. */ * offset channels (op[1+nvel], op[1+nvel+1]) - the DNN's per-pixel sub-pixel position estimate. */
public double[][][] inferROI(float[][] frames, int width, int height, Rectangle roi, int velRadius, double sThresh, double[][] offOut) throws Exception { public double[][][] inferROI(float[][] frames, int width, int height, Rectangle roi, int velRadius, double sThresh, double[][] offOut) throws Exception {
final int N = frames.length; final int N = frames.length;
final int P = 24, half = P / 2; // receptive field == training patch final int P = patch, half = P / 2; // receptive field == training patch (24 or 32, via setPatch) // By Claude on 06/16/2026
final int vdim = 2 * velRadius + 1, nvel = vdim * vdim; final int vdim = 2 * velRadius + 1, nvel = vdim * vdim;
final int rw = roi.width, rh = roi.height, npix = rw * rh; final int rw = roi.width, rh = roi.height, npix = rw * rh;
final int CHUNK = 2048; // tile the batch so ORT activations stay small (B*32*22*22) final int CHUNK = 2048; // tile the batch so ORT activations stay small (B*32*22*22)
......
...@@ -1182,6 +1182,7 @@ min_str_neib_fpn 0.35 ...@@ -1182,6 +1182,7 @@ min_str_neib_fpn 0.35
public double curt_dnn_thresh = 0.0; // DNN display threshold: zero the (Vx,Vy,s) field where detection s < this (0 - show all); cosmetic FP-suppression - real-clutter FPs need a retrain with real-bg negatives, not a threshold // By Claude on 06/13/2026 public double curt_dnn_thresh = 0.0; // DNN display threshold: zero the (Vx,Vy,s) field where detection s < this (0 - show all); cosmetic FP-suppression - real-clutter FPs need a retrain with real-bg negatives, not a threshold // By Claude on 06/13/2026
public int curt_dnn_stride = 1; // DNN temporal output stride (per pyramid-level slice): 1 = every step (testing, watch each temporal unit); 4 = production (50% overlap, matches the convolver's integer-pixel-shift cadence = curt_recur_period) // By Claude on 06/14/2026 public int curt_dnn_stride = 1; // DNN temporal output stride (per pyramid-level slice): 1 = every step (testing, watch each temporal unit); 4 = production (50% overlap, matches the convolver's integer-pixel-shift cadence = curt_recur_period) // By Claude on 06/14/2026
public double curt_dnn_vmax = 1.4; // "ghostbuster": trained DNN velocity limit (px/frame); zero velocity-grid cells beyond this radius (cell-R > vmax*vel_decimate) and discard pixels whose peak lands there (s=0) - the untrained corner cells emit spurious sidelobes that would confuse the recurrent. Set to match the loaded model's training vmax_px (PM models=1.4, base=1.0); <=0 disables // By Claude on 06/15/2026 public double curt_dnn_vmax = 1.4; // "ghostbuster": trained DNN velocity limit (px/frame); zero velocity-grid cells beyond this radius (cell-R > vmax*vel_decimate) and discard pixels whose peak lands there (s=0) - the untrained corner cells emit spurious sidelobes that would confuse the recurrent. Set to match the loaded model's training vmax_px (PM models=1.4, base=1.0); <=0 disables // By Claude on 06/15/2026
public int curt_dnn_patch = 24; // DNN receptive-field / training patch size (px): inferROI extracts this PxP patch per ROI pixel (half=P/2 = the output pixel). MUST match the loaded model (24 = base/PM models, 32 = larger-attention model) // By Claude on 06/16/2026
public boolean curt_dnn_recur_splat = false; // when feeding the DNN field to the recurrent layer: false = feed per-pixel field as-is; true = splat each pixel's velocity vector to its fractional offset (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin // By Claude on 06/14/2026 public boolean curt_dnn_recur_splat = false; // when feeding the DNN field to the recurrent layer: false = feed per-pixel field as-is; true = splat each pixel's velocity vector to its fractional offset (px+dx,py+dy) so neighbours reinforce in one sub-pixel bin // By Claude on 06/14/2026
public double curt_dnn_recur_scale = 10.0; // multiply the DNN field (softmax*s, peaks ~0.1) by this before the recurrent feed, to reach the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Alternative to lowering curt_recur_rs_min // By Claude on 06/14/2026 public double curt_dnn_recur_scale = 10.0; // multiply the DNN field (softmax*s, peaks ~0.1) by this before the recurrent feed, to reach the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Alternative to lowering curt_recur_rs_min // By Claude on 06/14/2026
public boolean curt_synth_src = true; // default set for the synthetic B-measurement experiment (set false for real-data runs); reads *-CUAS-SYNTHETIC-CUAS.tiff, output titles get -SYNTH // By Claude on 06/12/2026 public boolean curt_synth_src = true; // default set for the synthetic B-measurement experiment (set false for real-data runs); reads *-CUAS-SYNTHETIC-CUAS.tiff, output titles get -SYNTH // By Claude on 06/12/2026
...@@ -3537,6 +3538,8 @@ min_str_neib_fpn 0.35 ...@@ -3537,6 +3538,8 @@ min_str_neib_fpn 0.35
"Multiply the DNN field (peaks ~0.1) by this before the recurrent feed so it reaches the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Set 1 and instead lower curt_recur_rs_min if you prefer."); // By Claude on 06/14/2026 "Multiply the DNN field (peaks ~0.1) by this before the recurrent feed so it reaches the recurrent's tuned scale (rs_min=1.0); ~10 -> peak ~1.0. Set 1 and instead lower curt_recur_rs_min if you prefer."); // By Claude on 06/14/2026
gd.addNumericField("DNN ghostbuster vmax", this.curt_dnn_vmax, 4,8,"pix/frame", // By Claude on 06/15/2026 gd.addNumericField("DNN ghostbuster vmax", this.curt_dnn_vmax, 4,8,"pix/frame", // By Claude on 06/15/2026
"Zero DNN velocities beyond this radius (untrained corner cells) and discard pixels peaking there (s=0); match the model's training vmax_px (PM=1.4, base=1.0); <=0 disables."); "Zero DNN velocities beyond this radius (untrained corner cells) and discard pixels peaking there (s=0); match the model's training vmax_px (PM=1.4, base=1.0); <=0 disables.");
gd.addNumericField("DNN patch size (RF)", this.curt_dnn_patch, 0,3,"pix", // By Claude on 06/16/2026
"Receptive-field / training patch the model was built at (24 = base/PM, 32 = larger-attention). MUST match the loaded model.");
gd.addNumericField("DNN temporal stride", this.curt_dnn_stride, 0,3,"slices", // By Claude on 06/14/2026 gd.addNumericField("DNN temporal stride", this.curt_dnn_stride, 0,3,"slices", // By Claude on 06/14/2026
"DNN output stride along the pyramid-level time axis: 1 = a fresh inference at every slice (testing, watch each temporal step); 4 = production (50% overlap of the window, matches the convolver's integer-pixel-shift cadence)."); // By Claude on 06/14/2026 "DNN output stride along the pyramid-level time axis: 1 = a fresh inference at every slice (testing, watch each temporal step); 4 = production (50% overlap of the window, matches the convolver's integer-pixel-shift cadence)."); // By Claude on 06/14/2026
gd.addCheckbox ("Use synthetic input", this.curt_synth_src, // By Claude on 06/11/2026 gd.addCheckbox ("Use synthetic input", this.curt_synth_src, // By Claude on 06/11/2026
...@@ -5093,6 +5096,7 @@ min_str_neib_fpn 0.35 ...@@ -5093,6 +5096,7 @@ min_str_neib_fpn 0.35
this.curt_dnn_recur_splat = gd.getNextBoolean(); // By Claude on 06/14/2026 this.curt_dnn_recur_splat = gd.getNextBoolean(); // By Claude on 06/14/2026
this.curt_dnn_recur_scale = gd.getNextNumber(); // By Claude on 06/14/2026 this.curt_dnn_recur_scale = gd.getNextNumber(); // By Claude on 06/14/2026
this.curt_dnn_vmax = gd.getNextNumber(); // By Claude on 06/15/2026 this.curt_dnn_vmax = gd.getNextNumber(); // By Claude on 06/15/2026
this.curt_dnn_patch = (int) gd.getNextNumber(); // By Claude on 06/16/2026
this.curt_dnn_stride = (int) gd.getNextNumber(); // By Claude on 06/14/2026 this.curt_dnn_stride = (int) gd.getNextNumber(); // By Claude on 06/14/2026
this.curt_synth_src = gd.getNextBoolean(); // By Claude on 06/11/2026 this.curt_synth_src = gd.getNextBoolean(); // By Claude on 06/11/2026
this.curt_synth_scale = gd.getNextNumber(); // By Claude on 06/12/2026 this.curt_synth_scale = gd.getNextNumber(); // By Claude on 06/12/2026
...@@ -6467,6 +6471,7 @@ min_str_neib_fpn 0.35 ...@@ -6467,6 +6471,7 @@ min_str_neib_fpn 0.35
properties.setProperty(prefix+"curt_dnn_recur_scale", this.curt_dnn_recur_scale+""); // double // By Claude on 06/14/2026 properties.setProperty(prefix+"curt_dnn_recur_scale", this.curt_dnn_recur_scale+""); // double // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_dnn_stride", this.curt_dnn_stride+""); // int // By Claude on 06/14/2026 properties.setProperty(prefix+"curt_dnn_stride", this.curt_dnn_stride+""); // int // By Claude on 06/14/2026
properties.setProperty(prefix+"curt_dnn_vmax", this.curt_dnn_vmax+""); // double // By Claude on 06/15/2026 properties.setProperty(prefix+"curt_dnn_vmax", this.curt_dnn_vmax+""); // double // By Claude on 06/15/2026
properties.setProperty(prefix+"curt_dnn_patch", this.curt_dnn_patch+""); // int // By Claude on 06/16/2026
properties.setProperty(prefix+"curt_synth_src", this.curt_synth_src+""); // boolean // By Claude on 06/11/2026 properties.setProperty(prefix+"curt_synth_src", this.curt_synth_src+""); // boolean // By Claude on 06/11/2026
properties.setProperty(prefix+"curt_synth_scale", this.curt_synth_scale+""); // double // By Claude on 06/12/2026 properties.setProperty(prefix+"curt_synth_scale", this.curt_synth_scale+""); // double // By Claude on 06/12/2026
properties.setProperty(prefix+"curt_subtract_avg", this.curt_subtract_avg+""); // boolean // By Claude on 06/14/2026 properties.setProperty(prefix+"curt_subtract_avg", this.curt_subtract_avg+""); // boolean // By Claude on 06/14/2026
...@@ -6875,6 +6880,7 @@ min_str_neib_fpn 0.35 ...@@ -6875,6 +6880,7 @@ min_str_neib_fpn 0.35
if (properties.getProperty(prefix+"curt_dnn_recur_scale")!=null) this.curt_dnn_recur_scale=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_recur_scale")); // By Claude on 06/14/2026 if (properties.getProperty(prefix+"curt_dnn_recur_scale")!=null) this.curt_dnn_recur_scale=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_recur_scale")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_dnn_stride")!=null) this.curt_dnn_stride=Integer.parseInt(properties.getProperty(prefix+"curt_dnn_stride")); // By Claude on 06/14/2026 if (properties.getProperty(prefix+"curt_dnn_stride")!=null) this.curt_dnn_stride=Integer.parseInt(properties.getProperty(prefix+"curt_dnn_stride")); // By Claude on 06/14/2026
if (properties.getProperty(prefix+"curt_dnn_vmax")!=null) this.curt_dnn_vmax=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_vmax")); // By Claude on 06/15/2026 if (properties.getProperty(prefix+"curt_dnn_vmax")!=null) this.curt_dnn_vmax=Double.parseDouble(properties.getProperty(prefix+"curt_dnn_vmax")); // By Claude on 06/15/2026
if (properties.getProperty(prefix+"curt_dnn_patch")!=null) this.curt_dnn_patch=Integer.parseInt(properties.getProperty(prefix+"curt_dnn_patch")); // By Claude on 06/16/2026
if (properties.getProperty(prefix+"curt_synth_src")!=null) this.curt_synth_src=Boolean.parseBoolean(properties.getProperty(prefix+"curt_synth_src")); // By Claude on 06/11/2026 if (properties.getProperty(prefix+"curt_synth_src")!=null) this.curt_synth_src=Boolean.parseBoolean(properties.getProperty(prefix+"curt_synth_src")); // By Claude on 06/11/2026
if (properties.getProperty(prefix+"curt_synth_scale")!=null) this.curt_synth_scale=Double.parseDouble(properties.getProperty(prefix+"curt_synth_scale")); // By Claude on 06/12/2026 if (properties.getProperty(prefix+"curt_synth_scale")!=null) this.curt_synth_scale=Double.parseDouble(properties.getProperty(prefix+"curt_synth_scale")); // By Claude on 06/12/2026
...@@ -9165,6 +9171,7 @@ min_str_neib_fpn 0.35 ...@@ -9165,6 +9171,7 @@ min_str_neib_fpn 0.35
imp.curt_dnn_recur_scale = this.curt_dnn_recur_scale; // By Claude on 06/14/2026 imp.curt_dnn_recur_scale = this.curt_dnn_recur_scale; // By Claude on 06/14/2026
imp.curt_dnn_stride = this.curt_dnn_stride; // By Claude on 06/14/2026 imp.curt_dnn_stride = this.curt_dnn_stride; // By Claude on 06/14/2026
imp.curt_dnn_vmax = this.curt_dnn_vmax; // By Claude on 06/15/2026 imp.curt_dnn_vmax = this.curt_dnn_vmax; // By Claude on 06/15/2026
imp.curt_dnn_patch = this.curt_dnn_patch; // By Claude on 06/16/2026
imp.curt_synth_src = this.curt_synth_src; // By Claude on 06/11/2026 imp.curt_synth_src = this.curt_synth_src; // By Claude on 06/11/2026
imp.curt_synth_scale = this.curt_synth_scale; // By Claude on 06/12/2026 imp.curt_synth_scale = this.curt_synth_scale; // By Claude on 06/12/2026
imp.curt_subtract_avg = this.curt_subtract_avg; // By Claude on 06/14/2026 imp.curt_subtract_avg = this.curt_subtract_avg; // By Claude on 06/14/2026
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment