Skip to content

Fix Neureka#188

Open
marchioa wants to merge 19 commits into
pulp-platform:develfrom
FondazioneChipsIT:am/neureka
Open

Fix Neureka#188
marchioa wants to merge 19 commits into
pulp-platform:develfrom
FondazioneChipsIT:am/neureka

Conversation

@marchioa

@marchioa marchioa commented May 4, 2026

Copy link
Copy Markdown
Contributor

Current implementation of Neureka has a few bugs that need to be fixed. This PR wants to fix those bugs and provide some test to check the functionality. Most changes are related to the tiler for Dense and DW Convolutions.

Added

  • tests for Regular and DW Conv2D with 3x3 kernel (current tests are not 3x3 so it does not trigger 3x3 mode)
  • engine-aware DW lowering pass NeurekaNCHWtoNHWCDwConvPass which apply the weight layout depending on the engine.

Changed

  • Refactor the topology optimization pass NeurekaReshapePointwiseConvolutionPass
  • in _requantized_gemm_to_pw_fun, add a guard on mul and add shapes to check if they are consistent with PW output channels.

Fixed

  • Neureka's output-channels subtile size (in ConvTemplate)
  • Dense/DW/PW tile constraints
  • Fix PULPOpen's _merge_conv_rq_fun lowering pass (which merges Conv and RequantShift into RequantConv) to make the Engine color be inherited from Conv instead of RequantShift.
  • in _createIOBindings, set _live = True on network input and output buffers. They are externally allocated and effectively reserved for the whole inference (mirroring ConstantBuffer, which already hardcodes _live = True). This makes has_live_aliases() correctly see them as live, so any buffer aliasing a network I/O tensor is no longer deallocated while the I/O tensor is still in use.
  • latent bug in has_live_aliases(): visited = set(self.name) built a set of the name's characters instead of {self.name}

PR Merge Checklist

  1. The PR is rebased on the latest devel commit and pointing to devel.
  2. Your PR reviewed and approved.
  3. All checks are passing.
  4. The CHANGELOG.md file has been updated.
  5. If the docker was modified, change back its link after review.

@marchioa marchioa force-pushed the am/neureka branch 2 times, most recently from d0ed93d to 5081593 Compare June 4, 2026 07:42
marchioa added 8 commits June 30, 2026 11:12
…te conv layers

- in parser, weights are contrained to have 3 dimensions. That is correct for PW only. DW and Dense require 4 dimensions. The fix allows weights with 4 dimensions for DW and Dense.
- in tiler, again only 3-dim weights for PW is supported. Add support for 4-dim weights for DW and Dense.
- in test-runner, arguments for neureka are ignored. Add support for `enable-3x3` and `neureka-wmem` arguments.
@marchioa marchioa marked this pull request as ready for review July 9, 2026 10:52
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes the experimental enable3x3 flag, updates Neureka lowering and parsing paths for 3x3 depthwise and pointwise convolutions, tightens tile and weight-shape constraints, fixes buffer liveness and aliasing tracking, and updates test configuration and changelog entries.

Changes

Neureka 3x3 fix and depthwise lowering

Layer / File(s) Summary
Buffer liveness and aliasing fix
Deeploy/DeeployTypes.py
Fixes has_live_aliases visited-set bookkeeping and marks global IO buffers as live to prevent deallocation.
Remove enable3x3 flag and enable 3x3 by default
Deeploy/Targets/Neureka/Engine.py, Deeploy/Targets/Neureka/Deployer.py, DeeployTest/testMVP.py, DeeployTest/testUtils/deeployRunner.py
Removes the enable3x3 parameter and CLI flag, always substitutes the Neureka NCHW→NHWC pass, and adds --neureka-wmem propagation.
Neureka parser weight-shape validation
Deeploy/Targets/Neureka/Parsers.py
Adds and updates parser checks for weight dimensionality and mul/add sizing across DW, PW, RQS-PW, and Dense parsers.
Requantized GEMM/Conv validation
Deeploy/CommonExtensions/OptimizationPasses/TopologyOptimizationPasses/LoweringOptimizationPasses.py, Deeploy/Targets/PULPOpen/TopologyOptimizationPasses/Passes.py
Adds mul/add shape compatibility checks, n_levels_out fallback logic, and conditional engine attribute preservation when merging Conv/RQS attrs.
Neureka depthwise lowering and pointwise reshape rework
Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py
Removes depthwise weight transpose, replaces reshape factorization logic, and adds engine-dispatched depthwise NCHW→NHWC lowering.
Tile constraint and template updates
Deeploy/Targets/Neureka/TileConstraints/*.py, Deeploy/Targets/Neureka/Templates/ConvTemplate.py
Constrains weight non-tiled dims, rebuilds weight/input cubes with expanded dimensionality, and adjusts channel-out tiling sizes.
Test kernel configs and changelog
DeeployTest/test_siracusa_neureka_tiled_config.py, CHANGELOG.md
Adds new kernel test entries and corresponding changelog bullets.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • pulp-platform/Deeploy#122: Both touch NCHW→NHWC lowering and requantization-related constant handling in the optimization passes.

Suggested labels: Bug

Suggested reviewers: Victor-Jung, Xeratec

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is relevant but too vague to convey the main change. Use a more specific title like 'Fix Neureka tiling, lowering, and buffer liveness bugs'.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description matches the Neureka bug fixes and tests in the changeset.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py (1)

103-109: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant elif depthwise branch — collapse it.

With the depthwise transpose removed earlier in _weightEncode, the elif depthwise and else branches now return an identical expression, so the depthwise flag no longer changes the produced layout. The branch (and possibly the depthwise parameter itself, if all callers can drop it) can be simplified.

♻️ Proposed simplification
     if height == 1 and width == 1:
         # (cout, cinMajor, Weight Bandwidth Bytes)
         return weight.reshape(cout, cinMajor, weightBandwidthBytes)
-    elif depthwise:
-        return weight.reshape(cout, cinMajor, bits, weightBandwidthBytes)
-    else:
-        return weight.reshape(cout, cinMajor, bits, weightBandwidthBytes)
+    return weight.reshape(cout, cinMajor, bits, weightBandwidthBytes)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py` around lines
103 - 109, The `reshapeWeight` logic in `Passes.py` has a redundant `elif
depthwise` branch because it returns the same layout as the `else` case.
Simplify the conditional so the `depthwise` flag no longer affects the returned
`weight.reshape(...)` result, and update the surrounding
`_weightEncode`/`reshapeWeight` flow to remove `depthwise` entirely if no
callers still need it.
Deeploy/Targets/Neureka/Engine.py (1)

38-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Verify that GVSOC logging should be unconditionally enabled at init.

neureka_gvsoc_log_activate(..., NEUREKA_GVSOC_LOG_LEVEL_ALL, ...) is now emitted into the standard init code for every Neureka deployment. LOG_LEVEL_ALL is very verbose and this appears to be a debug/tracing aid; enabling it unconditionally can drown simulation logs and slow runs. Consider gating it behind a debug/profiling flag if it isn't meant to be always-on.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Deeploy/Targets/Neureka/Engine.py` around lines 38 - 42, The Neureka init
snippet in _neurekaInitCode always enables gvsoc logging with
NEUREKA_GVSOC_LOG_LEVEL_ALL, which should not be unconditionally turned on in
normal deployments. Update the init path in Engine.py so
neureka_gvsoc_log_activate is only emitted when a debug/profiling flag or
similar opt-in is enabled, while keeping neureka_nnx_init and the device setup
unchanged. Use the existing _neurekaInitCode generation point to make the
logging conditional.
Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py (1)

234-235: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

cube is unused in this loop.

Since the DW weight is loaded in full per tile, cube is no longer referenced; iterate over inputLoadSchedule directly for clarity.

♻️ Optional cleanup
-            for cube, load in zip(outputCubes, inputLoadSchedule):
-                load['weight'] = HyperRectangle((0,) * len(weightShape), tuple(weightShape))
+            for load in inputLoadSchedule:
+                load['weight'] = HyperRectangle((0,) * len(weightShape), tuple(weightShape))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py` around
lines 234 - 235, The loop in NeurekaDepthwiseConstraint is carrying an unused
`cube` variable, since the DW weight is loaded in full per tile and only
`inputLoadSchedule` is needed. Update the iteration in the relevant
weight-loading block to loop directly over `inputLoadSchedule`, keeping the
`load['weight'] = HyperRectangle(...)` assignment unchanged and removing the
unused `cube` binding for clarity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Deeploy/Targets/Neureka/Parsers.py`:
- Around line 109-119: Update the Neureka parser methods so they always return
the expected (NetworkContext, bool) tuple instead of a bare False. In
NeurekaDWConv2DParser.parseNodeCtxt, NeurekaPWConv2DParser.parseNodeCtxt, and
NeurekaDenseConv2DParser.parseNodeCtxt, make both failure paths (the
super().parseNodeCtxt call returning false and the weight-shape validation
failure) return the current context together with False, matching the
Tuple[NetworkContext, bool] contract used by the base parser and RQS parser.
Keep the successful return as (newCtxt, True) and ensure callers can safely
unpack the result.

---

Nitpick comments:
In `@Deeploy/Targets/Neureka/Engine.py`:
- Around line 38-42: The Neureka init snippet in _neurekaInitCode always enables
gvsoc logging with NEUREKA_GVSOC_LOG_LEVEL_ALL, which should not be
unconditionally turned on in normal deployments. Update the init path in
Engine.py so neureka_gvsoc_log_activate is only emitted when a debug/profiling
flag or similar opt-in is enabled, while keeping neureka_nnx_init and the device
setup unchanged. Use the existing _neurekaInitCode generation point to make the
logging conditional.

In `@Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py`:
- Around line 234-235: The loop in NeurekaDepthwiseConstraint is carrying an
unused `cube` variable, since the DW weight is loaded in full per tile and only
`inputLoadSchedule` is needed. Update the iteration in the relevant
weight-loading block to loop directly over `inputLoadSchedule`, keeping the
`load['weight'] = HyperRectangle(...)` assignment unchanged and removing the
unused `cube` binding for clarity.

In `@Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py`:
- Around line 103-109: The `reshapeWeight` logic in `Passes.py` has a redundant
`elif depthwise` branch because it returns the same layout as the `else` case.
Simplify the conditional so the `depthwise` flag no longer affects the returned
`weight.reshape(...)` result, and update the surrounding
`_weightEncode`/`reshapeWeight` flow to remove `depthwise` entirely if no
callers still need it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4e9e3fa4-4260-4a98-9c31-0218ebe4ba82

📥 Commits

Reviewing files that changed from the base of the PR and between 6818f31 and bfac59a.

📒 Files selected for processing (21)
  • CHANGELOG.md
  • Deeploy/CommonExtensions/OptimizationPasses/TopologyOptimizationPasses/LoweringOptimizationPasses.py
  • Deeploy/DeeployTypes.py
  • Deeploy/Targets/Neureka/Deployer.py
  • Deeploy/Targets/Neureka/Engine.py
  • Deeploy/Targets/Neureka/Parsers.py
  • Deeploy/Targets/Neureka/Templates/ConvTemplate.py
  • Deeploy/Targets/Neureka/TileConstraints/NeurekaDenseConstraint.py
  • Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py
  • Deeploy/Targets/Neureka/TileConstraints/NeurekaPointwiseConstraint.py
  • Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py
  • Deeploy/Targets/PULPOpen/TopologyOptimizationPasses/Passes.py
  • DeeployTest/Tests/Kernels/Integer/Conv/DW_3x3_RQ/inputs.npz
  • DeeployTest/Tests/Kernels/Integer/Conv/DW_3x3_RQ/network.onnx
  • DeeployTest/Tests/Kernels/Integer/Conv/DW_3x3_RQ/outputs.npz
  • DeeployTest/Tests/Kernels/Integer/Conv/Regular_3x3_RQ/inputs.npz
  • DeeployTest/Tests/Kernels/Integer/Conv/Regular_3x3_RQ/network.onnx
  • DeeployTest/Tests/Kernels/Integer/Conv/Regular_3x3_RQ/outputs.npz
  • DeeployTest/testMVP.py
  • DeeployTest/testUtils/deeployRunner.py
  • DeeployTest/test_siracusa_neureka_tiled_config.py
💤 Files with no reviewable changes (1)
  • DeeployTest/testMVP.py

Comment thread Deeploy/Targets/Neureka/Parsers.py

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
Deeploy/Targets/Neureka/Engine.py (1)

41-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider removing the commented-out GVSOC log line.

The commented-out neureka_gvsoc_log_activate(...) call is dead code in the generated init string. If it's kept intentionally for easy debug toggling, a brief comment explaining that would help future readers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Deeploy/Targets/Neureka/Engine.py` at line 41, Remove the commented-out
neureka_gvsoc_log_activate call from the init string, or if you want to keep it
for debug toggling, replace it with a brief explanatory comment so the intent is
clear. Update the Neureka engine initialization logic in Engine.py around the
generated init string to avoid leaving dead code in the output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Deeploy/Targets/Neureka/Engine.py`:
- Line 41: Remove the commented-out neureka_gvsoc_log_activate call from the
init string, or if you want to keep it for debug toggling, replace it with a
brief explanatory comment so the intent is clear. Update the Neureka engine
initialization logic in Engine.py around the generated init string to avoid
leaving dead code in the output.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0934c17d-b027-42c9-83a5-2d1681520b68

📥 Commits

Reviewing files that changed from the base of the PR and between bfac59a and 1aa9ac7.

📒 Files selected for processing (4)
  • Deeploy/Targets/Neureka/Engine.py
  • Deeploy/Targets/Neureka/Parsers.py
  • Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py
  • Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • Deeploy/Targets/Neureka/TileConstraints/NeurekaDepthwiseConstraint.py
  • Deeploy/Targets/Neureka/TopologyOptimizationPasses/Passes.py
  • Deeploy/Targets/Neureka/Parsers.py

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.

1 participant