Skip to content

DPointNet: integrate performance paths and safe automatic selection - #481

Merged
shixnya merged 2 commits into
AllenInstitute:developfrom
shixnya:feature/dpointnet-performance-auto
Oct 18, 2026
Merged

shixnya merged 2 commits into
AllenInstitute:developfrom
shixnya:feature/dpointnet-performance-auto

Conversation

@shixnya

@shixnya shixnya commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Consolidate the DPointNet performance improvements and shared GLIF extension contracts into one complete implementation, with native user/developer documentation and safe automatic selection rather than a manual accelerator overlay.

  • Add immutable-basis backward sharing, warp-tiled event weight gradients, cached joint recurrent/input routing and configurable forward target tiles.
  • Automatically select eligible single-replica SM86/NEST projection paths: 256-target tiles at batch 1, 2048 at batches 16/32, with native-ABI, precision, connectivity and conservative routing-memory gates. Honor explicit overrides; do not automatically opt custom/STP/distributed cells into this route.
  • Preserve live neuron-coefficient mutation/restore fallback without an immutable-coefficient promise. Prepare the control predicate once per rollout, outside differentiable carriers; keep the existing temporal/checkpoint runners.
  • Add lazily selected compiled FP32 firing-rate counts, native-dtype iterator output, CPU placement of redundant canonical connectivity metadata and compact GPU EMD indexing with bidirectional old-checkpoint compatibility.
  • Expose default-preserving current injection, actual native execution options and explicit compute-shadow creation for later adapters.

Compatibility and numerical boundaries

The separate-projection rounding repair from #480 remains intact. Joint projection deliberately sums compatible sources in FP32 before one output rounding, so it can change spikes and trajectories, including full-FP32 runs. use_combined_current_sweep=false retains separate projection; compiled_spike_counts=false retains the ordinary rate reduction.

Keep Poisson counts, causal delays, silent-source credit, canonical FP32 masters and exactly-once CSR gradient restoration. Refresh recurrent and named-input shadows after update/assignment/restore. Unsupported explicit requests raise rather than silently changing the selected method.

This is not an STP adapter, neuron-partition implementation, hybrid/distributed qualification, installation or convergence claim. Those integrations remain separate PRs.

Copilot review follow-up — 8e3ee6f

Addressed all three review comments:

  • Resolve uncapped recurrent limits (max_delay=None or nonpositive) from network delays; conservatively round fractional delay steps upward.
  • Bound every external input population's delay-expanded width independently of the recurrent cap. The reported 20,000-input / 500-ms example now falls back from tile256 to tile2048; a larger case retains separate projection when neither tile fits the 512-MiB gate.
  • Use compute-weight resource-handle device placement, including frozen/per-type Keras 3 FP32 variables. Expand live coefficient mutation/restore coverage across recurrent weight modes.

Validation of the production fixes:

  • Focused RTX3090 native suite: 207 passed, 2 skipped.
  • Complete CUDA-hidden Keras 3 suite: 1906 passed, 1224 skipped.
  • Complete actual Python 3.8 / TensorFlow 2.13 / Keras 2 suite: 1870 passed, 1260 skipped.
  • After those complete CPU runs, a test-only correction made the device assertion conditional on guarded dispatch. All six affected CPU cases passed again on both stacks, and the complete focused native rerun above passed. The initial native run's three assertion failures are retained; production code was unchanged for that recovery.
  • git diff --check passed. Unchanged native operators match the original qualification hashes; no rebuild or dependency/environment mutation.
  • Sphinx rendering was attempted but blocked by the existing environment's missing nbconvert rst template. No new successful rendered-docs claim is made for this follow-up.
  • Full native-suite and performance receipts below remain scoped to the original implementation commit, not a fresh full-native or benchmark qualification of this follow-up.

Original implementation validation — 2892f86

All production, tests and documentation in the original implementation commit are byte-identical to the immutable qualification snapshot:

  • Complete RTX3090 native DPointNet suite: 3067 passed, 37 skipped.
  • Complete CUDA-hidden Keras 3 suite: 1852 passed, 1252 skipped.
  • Complete actual Python 3.8 / TensorFlow 2.13 / Keras 2 suite: 1852 passed, 1252 skipped.
  • 53 focused native automatic-selection, coefficient mutation/restore and segmented/remainder VJP cases passed; these overlap the complete suite.
  • Both actual operators built and inspected for SM61/70/75/80/86/89/90 plus PTX90. This is compilation coverage, not execution qualification on every GPU family.
  • Clean Sphinx HTML rendering with notebook execution disabled: 12 unchanged baseline diagnostics, zero new diagnostics.
  • Python 3.8 syntax and git diff --check passed. Flake8 was unavailable in the declared environment and was not installed.

Bounded full-V1 performance qualification

RTX3090 / TF2.21, bio-trained 66,658-neuron network, 24,450,554 recurrent edges, 500 steps, exact checkpoint interval 25, counted-Poisson replay, three changing qualification updates and destructive complete restore. All 28 serial arms passed real native-path, precision, master/shadow, carry, restore and one-replay-upload gates. Each arm excludes three warmups and measures 20 synchronized updates.

The four same-static-options/default-2048 B32 control arms passed: candidate 2.384997s versus reference 2.384810s, paired ratios 1.000730/0.999428 and repeat drift below 0.21%. This is fresh admission of this integrated implementation; it does not relabel the historical failed tile controls.

The remaining 24 arms form six reference/auto/auto/reference groups:

Batch Precision Manual reference, s/update Safe auto, s/update Reference / auto TF lifetime peak, GiB
1 Mixed 0.403829 0.461182 2.778 / 2.852
1 FP32 0.449174 0.528172 2.907 / 2.935
16 Mixed 1.560786 1.518586 6.211 / 5.700
16 FP32 2.183061 2.141366 9.370 / 8.296
32 Mixed 2.449932 2.411556 10.093 / 8.931
32 FP32 3.673754 3.611491 16.519 / 14.418

Values are means of the two independent run medians/peaks. The B16/32 reference is the already-optimized pre-tile manual prototype, not unchanged upstream develop. The B1 reference uses tile256 and an externally safeguarded static coefficient promise; safe auto is 14.2%/17.6% longer because it retains live mutation safety. Auto must not silently enable that promise.

All repeat drifts are below 3%; every paired B16/32 candidate/reference ratio passes the 1.03 non-regression limit. Lifetime memory is not warm traced memory or driver reservation. Warm-memory changes are small/inconsistent, B1 lifetime peaks increase, and driver-reservation savings are not established.

These are independent-trajectory timing observations, not bitwise equivalence or convergence: the historical unchanged full-model baseline itself fails strict gradient repeatability. New GPU performance qualification is TF2.21/SM86 only; the actual TF2.13 suite is CPU-only. No universal-fastest or universal-memory-saving claim is made.

Consolidate native projection, backward sharing, compact rate reduction, input replay and metadata improvements behind validated automatic capability checks. Preserve explicit overrides, canonical gradients, live coefficient mutation/restore safety and checkpoint compatibility.

Document numerical and qualification boundaries, add shared GLIF extension contracts, and cover native execution, segmented replay, gradients, updates and restore.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Delay handling can break construction or bypass routing-memory limits, and guarded dispatch has incompatible Keras 3 device access.

3 open issues
What changed in this PR

Integrates DPointNet performance paths with bounded automatic selection, compatibility safeguards, and GLIF extension interfaces.

Changes:

  • Adds joint projection, shared basis metadata, and optimized gradients.
  • Reduces input, loss, and metadata overhead.
  • Adds regression coverage and documents numerical boundaries.
File Description
tests/​simulator/​dpointnet/​test_weight_regularization.py Tests compact indexing and checkpoint compatibility.
tests/​simulator/​dpointnet/​test_training.py Checks iterator dtype selection.
tests/​simulator/​dpointnet/​test_recurrent_accumulation.py Tests gradient queue boundaries.
tests/​simulator/​dpointnet/​test_projection_basis_sharing.py Tests basis sharing and fallback.
tests/​simulator/​dpointnet/​test_performance_auto.py Tests automatic selection and live-coefficient safeguards.
tests/​simulator/​dpointnet/​test_host_input_metadata.py Tests dtype, placement, and checkpoints.
tests/​simulator/​dpointnet/​test_graded_source_contract.py Validates graded-source values and gradients.
tests/​simulator/​dpointnet/​test_glif_extension_contracts.py Tests current injection and shadow interfaces.
tests/​simulator/​dpointnet/​test_compiled_rate_counts.py Tests compiled counts and gradients.
tests/​simulator/​dpointnet/​test_combined_sweep.py Tests joint projection and restoration.
docs/​autodocs/​source/​dpointnet_training.rst Documents compiled count configuration.
docs/​autodocs/​source/​dpointnet_performance.rst Explains selection and numerical boundaries.
docs/​autodocs/​source/​dpointnet_development.rst Documents extension and gradient contracts.
bmtk/​simulator/​dpointnet/​training.py Selects native iterator output dtype.
bmtk/​simulator/​dpointnet/​rnn_model.py Prepares admission context and host indices.
bmtk/​simulator/​dpointnet/​loss_functions/​weight_regularization.py Adds compact, checkpoint-compatible indexing.
bmtk/​simulator/​dpointnet/​loss_functions/​target_firing_rates.py Adds compiled FP32 count reduction.
bmtk/​simulator/​dpointnet/​data_iterator.py Supports output dtype conversion.
bmtk/​simulator/​dpointnet/​custom_ops/​glif_state_ops.py Hoists live coefficient guards.
bmtk/​simulator/​dpointnet/​custom_ops/​csr_spike_ops.py Adds sharing and joint-projection wrappers.
bmtk/​simulator/​dpointnet/​custom_ops/​csr_spike_ops.cu.cc Implements joint sweeps and warp-tiled gradients.
bmtk/​simulator/​dpointnet/​custom_ops/​csr_spike_ops.cc Registers the combined-sweep operator.
bmtk/​simulator/​dpointnet/​cell_models/​glif3_cell.py Integrates optimized paths and extension interfaces.
bmtk/​simulator/​dpointnet/​acceleration.py Adds bounded automatic projection selection.

Review effort: Balanced

network, inputs, *, dt, max_delay, standard_cell, single_replica,
):
"""Describe the high-level runner's static projection admission boundary."""
history = max(1, int(max_delay / dt) + 1)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8e3ee6f. Uncapped (None, zero or negative) recurrent limits now resolve from the network's actual maximum delay before computing the conservative history bound; fractional steps round upward. Added direct-cell bound checks at dt=1/0.5 and high-level RNN construction regressions with acceleration disabled. All pass on actual Keras 3 and Keras 2.

Comment on lines +26 to +28
"source_rows_upper_bound": history * (
int(network["n_nodes"]) + sum(int(item["n_inputs"]) for item in inputs.values())
),

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8e3ee6f. The routing estimate now sums recurrent history plus each external population's independently delay-expanded width, without applying recurrent max_delay to inputs. Added your 4,096-neuron / 20,000-input / 1-and-500-ms example: auto rejects tile256 and selects tile2048. A 100,000-input variant exceeds the budget even at tile2048 and retains separate projection. Existing exact 512-MiB boundary tests also pass.

)
with tf.device("/CPU:0"):
guard_device = (
self.recurrent_weight_values_compute.device

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 8e3ee6f by using recurrent_weight_values_compute.handle.device. Expanded preparation and native live-coefficient mutation/restore tests across frozen, per-type and per-edge recurrent weights, with FP32 and mixed precision coverage. The final focused RTX3090 run passes 207 tests (2 skips); CPU preparation regressions pass on both actual Keras 3 and Keras 2.

Resolve uncapped recurrent delay limits from connectivity and bound external input histories independently for the 512-MiB routing gate. Use compute-weight resource handles for guarded coefficient placement with Keras 3 frozen/per-type FP32 variables. Add delay, routing-budget, live-mutation and restore regressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@shixnya
shixnya merged commit 85d308a into AllenInstitute:develop Oct 18, 2026
7 checks passed
@shixnya
shixnya deleted the feature/dpointnet-performance-auto branch October 18, 2026 05:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants