Skip to content

Conversation

@Aldrago98
Copy link
Contributor

@Aldrago98 Aldrago98 commented Jun 27, 2025

This PR adds required kernels, binding and templates to support 1D autoencoders.

Added

  • Added support for 1D Autoencoder operations, including newly implemented BatchNorm, 1D ConvTranspose, and 1D MaxPool layers.
  • Added Autoencoder1D test to the CI.

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.

@diaconuccalin diaconuccalin removed this from Deeploy Jul 1, 2025
@Xeratec Xeratec added the Feature Addition of new features label Jul 1, 2025
@Xeratec Xeratec added this to Deeploy Jul 1, 2025
@Xeratec Xeratec added this to the Release xxx milestone Jul 1, 2025
Copy link
Member

@Xeratec Xeratec left a comment

Choose a reason for hiding this comment

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

Please make sure to remove unnecessary changes from the PR.

@Xeratec Xeratec moved this to In progress in Deeploy Jul 2, 2025
@Aldrago98 Aldrago98 requested a review from lukamac as a code owner July 3, 2025 10:43
@lukamac
Copy link
Contributor

lukamac commented Jul 3, 2025

Hi, as @diaconuccalin commented already, when rebasing your work on the devel branch, make sure that your commits go after all the commits from the devel branch (first point in the "PR Merge Checklist").
This makes my reviewing process easier (the changes are clearly visible) and merging it into the devel branch is much easier.
So I ask you to do it before I start reviewing.

@diaconuccalin
Copy link
Contributor

The CI pipeline is passing and the required changes have been made. I think it's ready for a new round of review @Xeratec @lukamac

Copy link
Member

@Xeratec Xeratec left a comment

Choose a reason for hiding this comment

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

It seems like most of my comments from the previous review were not addressed. Please make sure to address them! It helps if you reply to the comment to acknowledge the change and, optionally, even link a commit with the change.

Please also remove all unnecessary new line changes unless they are strictly required for the formatting to pass.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 1, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added 1D Autoencoder support with associated kernels and mappings
    • Added batch normalization layer
    • Added transposed convolution layer
    • Added 1D max pooling with float32 support
    • Extended float32 data type support across convolution, pooling, and padding operations
  • Tests

    • Added Autoencoder1D CI integration test

Walkthrough

Adds float32 1D operator support: new parsers, type-checker, bindings, templates, layers, and mappers for BatchNormalization, ConvTranspose and MaxPool1D; implements C kernels and headers (Conv1d, ConvTranspose1d, MaxPool1d, BatchNorm); updates platform mappings and CI to include Autoencoder1D.

Changes

Cohort / File(s) Summary
Bindings & Exports
Deeploy/Targets/Generic/Bindings.py
Replaces single 1D conv binding with per-type BasicConv1DBindings; adds BasicMaxPool1DBindings, BasicPad1DBindings, BasicBatchNormBindings, BasicConvTransposeBindings; exposes new templates and checkers and renames the conv public symbol.
Parsers
Deeploy/Targets/Generic/Parsers.py
Adds MaxPool1DParser, BatchNormParser, ConvTransposeParser, ConvTranspose1DParser; enhances pad/conv parsing for 1D metadata (kernel/stride/pads/dilations) and batch offsets.
Type Checkers
Deeploy/Targets/Generic/TypeCheckers.py
Adds BatchNormChecker (sign-propagating checker that infers quantization levels and signedness for BatchNorm).
Layers
Deeploy/Targets/Generic/Layers.py
Adds BatchNormalizationLayer and ConvTransposeLayer with shape inference and op-count computation.
Templates
Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py, .../ConvTransposeTemplate.py, .../FloatConvTemplate.py, .../FloatMaxPoolTemplate.py, .../FloatPadTemplate.py
Adds BatchNorm and ConvTranspose templates; introduces 1D variants for FloatConv, FloatMaxPool, and FloatPad templates (new reference1DTemplate/referenceTemplate entries).
Platform & Mappers
Deeploy/Targets/Generic/Platform.py, Deeploy/Targets/MemPool/Platform.py
Adds MaxPool1DMapper, BatchNormalizationMapper, ConvTransposeMapper; updates Conv1DMapper to use BasicConv1DBindings; extends GenericMapping and MaxPool mapping to include 1D mapper and new layer entries.
Kernel Headers
TargetLibraries/Generic/inc/DeeployBasicMath.h, TargetLibraries/Generic/inc/kernel/BatchNorm.h, .../ConvTranspose1d_fp32.h, .../Convolution.h, .../MaxPool1d.h
Adds declarations for BatchNorm_fp32, ConvTranspose1d_fp32, Conv1d_fp32_fp32_fp32, and MaxPool1d_fp32_fp32; updates includes in DeeployBasicMath.h.
Kernel Implementations
TargetLibraries/Generic/src/BatchNorm_fp32.c, .../ConvTranspose1d_fp32.c, .../Convolution_fp32.c, .../MaxPool1D_fp32.c
Implements BatchNorm_fp32 (per-channel affine), ConvTranspose1d_fp32 (transposed 1D conv), Conv1d_fp32_fp32_fp32 (direct 1D conv), and MaxPool1d_fp32_fp32 (1D max-pool).
MemPool Platform
Deeploy/Targets/MemPool/Platform.py
Updates import/use of BasicConv1DBindings (replacing previous single-binding list) and exposes additional binding symbols.
CI
.github/workflows/ci-platform-generic.yml
Adds Autoencoder1D to the generic-models test list.
Changelog
CHANGELOG.md
Adds unreleased entry documenting 1D Autoencoder support, new kernels, float32 support, and CI test.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant ONNX as ONNX Graph
    participant Parser as NodeParser
    participant Mapper as NodeMapper
    participant Binding as NodeBinding
    participant Template as NodeTemplate
    participant Kernel as C Kernel

    note right of Parser #f0f4ff: parsers added for 1D/maxpool/conv-transpose/batchnorm
    ONNX->>Parser: parse node + attributes
    Parser->>Mapper: produce context & operatorRepresentation (1D metadata, batch offsets)
    Mapper->>Binding: select binding(s) (type-driven lists per data type)
    Binding->>Template: alignToContext / instantiate template (1D / transpose / batchnorm)
    Template->>Kernel: emit kernel call (Conv1d / ConvTranspose1d / MaxPool1d / BatchNorm)
    Kernel-->>Template: execute kernel (uses provided shape/stride/has_bias metadata)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.85% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "Support for 1D Autoencoder" directly reflects the primary objective and main change of this pull request. The changeset is entirely focused on adding kernel implementations, templates, bindings, parsers, and layers to enable 1D autoencoder support on a generic platform. The title is concise, clear, and specific enough that it accurately summarizes the core purpose of the changes without being misleading or off-topic. While the title is high-level rather than listing specific technical components, it appropriately captures the overarching intent of the entire changeset.
Description Check ✅ Passed The PR description provided by the author states that "This PR adds required kernels, binding and templates to support 1D autoencoders" and specifically mentions adding support for BatchNorm, 1D ConvTranspose, and 1D MaxPool layers, as well as adding an Autoencoder1D test to the CI pipeline. These statements directly align with the actual changeset, which includes the implementation of these kernels, their associated bindings, templates, parsers, layers, and the new CI test. The description accurately reflects the core objectives and additions of the pull request without being misleading or off-topic.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 15

♻️ Duplicate comments (3)
CHANGELOG.md (1)

31-31: PR reference placement — OK.

Entry added once under v0.2.0; prior duplication concern appears resolved.

TargetLibraries/Generic/src/BatchNorm_fp32.c (1)

8-9: OpenMP usage: keep but guard for portability.

Same concern noted earlier; guarding preserves portability while enabling speedups when available.

Apply this diff:

-#pragma omp parallel for
+#ifdef _OPENMP
+#pragma omp parallel for
+#endif
Deeploy/Targets/Generic/Bindings.py (1)

321-335: ConvTranspose: duplicate bindings likely unnecessary

You define both 3-input and 2-input float bindings. If the template accepts bias=NULL, keep only the 3-input variant for simplicity.

If both are needed for template signature matching, add a brief comment explaining why two variants are required.

🧹 Nitpick comments (21)
CHANGELOG.md (2)

98-104: Added items match PR scope — OK.

Wording nit: consider “in these kernels” instead of “in the previous kernels.”

-- Support for float32 data type in the previous kernels
+- Support for float32 data type in these kernels

238-239: Minor formatting/grammar polish in “Changed”.

-- FloatConvTemplate file
-- Platform.py file  
+- FloatConvTemplate
+- Platform.py
TargetLibraries/Generic/inc/DeeployBasicMath.h (1)

59-60: Avoid circular include via MaxPool1d.h.

Including kernel/MaxPool1d.h here while that header includes DeeployBasicMath.h creates an unnecessary include cycle. Please make MaxPool1d.h include only the minimal deps (stdint.h, project types.h) and drop DeeployBasicMath.h. I’ve proposed the change in that header’s review comment.

Also applies to: 70-70, 75-75

TargetLibraries/Generic/inc/kernel/MaxPool1d.h (1)

1-10: Trim dependencies and add C++-safe linkage to avoid include cycle.

Remove DeeployBasicMath.h include; include only what’s needed and add extern "C" guards.

 #ifndef __DEEPLOY_BASIC_MATH_MAXPOOL1D_KERNEL_HEADER_
 #define __DEEPLOY_BASIC_MATH_MAXPOOL1D_KERNEL_HEADER_
 
-#include "DeeployBasicMath.h"
+#include <stdint.h>
+#include "types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 void MaxPool1d_fp32_fp32(float32_t const *__restrict__ pSrcA, uint32_t C,
                          uint32_t W, uint32_t K, uint32_t S,
                          float32_t *__restrict__ pDstC);
 
+#ifdef __cplusplus
+}
+#endif
 #endif

Build once after this change to ensure no transitive type deps were assumed.

Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)

3-11: Confirm BN kernel signature and epsilon handling.

Template assumes BatchNorm_fp32(input, scale, bias, mean, variance, output, batch, channels, window) and no epsilon. Verify it matches kernel/BatchNorm.h and that numerical stability (epsilon) is handled in-kernel or via preprocessed variance.

I can adjust the template once you confirm the exact signature/order.

TargetLibraries/Generic/src/Convolution_fp32.c (2)

94-102: Clarify/lock the shape contract (W_out, padding).

This kernel assumes no explicit padding parameter and does boundary checks. Please confirm callers pre-pad (Pad1D) or compute W_out = floor((W_in - K)/stride) + 1 for “valid” so we never accumulate partial windows. If “same” is desired, pre-pad and keep this branch, otherwise drop the check for tighter inner loops.


103-121: Hoist invariant indexing and bias to reduce work in hot loops.

Avoid recomputing base offsets every iteration.

Apply this diff:

   for (c_out = 0; c_out < C_out; ++c_out) {
-    for (w_out = 0; w_out < W_out; ++w_out) {
+    const float32_t bias = has_bias ? pSrcBias[c_out] : 0.0f;
+    const float32_t *w_base = pSrcB + c_out * C_in * K;
+    for (w_out = 0; w_out < W_out; ++w_out) {
       float32_t sum = 0.0f;
       for (c_in = 0; c_in < C_in; ++c_in) {
-        for (k = 0; k < K; ++k) {
+        const float32_t *w_row = w_base + c_in * K;
+        for (k = 0; k < K; ++k) {
           w_in = w_out * stride + k;
           if (w_in < W_in) {
-            sum += pSrcA[c_in * W_in + w_in] *
-                   pSrcB[c_out * C_in * K + c_in * K + k];
+            sum += pSrcA[c_in * W_in + w_in] * w_row[k];
           }
         }
       }
-      if (has_bias) {
-        sum += pSrcBias[c_out];
-      }
-      pDstC[c_out * W_out + w_out] = sum;
+      pDstC[c_out * W_out + w_out] = sum + bias;
     }
   }
TargetLibraries/Generic/inc/kernel/BatchNorm.h (1)

7-10: Consider unsigned dims for consistency with other kernels.

Other kernels use uint32_t for dimensions; aligning N/C/L would avoid sign/overflow mismatches.

Option (header):

-void BatchNorm_fp32(const float32_t *input, const float32_t *gamma,
-                    const float32_t *beta, const float32_t *mean,
-                    const float32_t *var, float32_t *output, int N, int C,
-                    int L);
+void BatchNorm_fp32(const float32_t *input, const float32_t *gamma,
+                    const float32_t *beta, const float32_t *mean,
+                    const float32_t *var, float32_t *output,
+                    uint32_t N, uint32_t C, uint32_t L);

(Requires mirroring in the .c file.)

TargetLibraries/Generic/src/BatchNorm_fp32.c (1)

7-7: Minor type consistency.

Use float32_t for epsilon to match the rest.

Apply this diff:

-  const float epsilon = 1e-5f;
+  const float32_t epsilon = 1e-5f;
TargetLibraries/Generic/src/MaxPool1D_fp32.c (1)

11-19: Tighten inner loop (optional).

With the guard above, w_in is always < W; drop the branch and use fmaxf.

Apply this diff:

-      for (uint32_t k = 0; k < K; ++k) {
-        uint32_t w_in = w_out * S + k;
-        if (w_in >= W)
-          continue;
-        float32_t tmp = pSrcA[c * W + w_in];
-        if (tmp > max) {
-          max = tmp;
-        }
-      }
+      for (uint32_t k = 0; k < K; ++k) {
+        uint32_t w_in = w_out * S + k;
+        float32_t tmp = pSrcA[c * W + w_in];
+        max = fmaxf(max, tmp);
+      }
Deeploy/Targets/Generic/TypeCheckers.py (1)

624-636: Silence ARG002 warnings by prefixing unused params with underscores.

Keeps intent clear and appeases Ruff.

-    def _inferNumLevels(self, inputs: List[VariableBuffer],
-                        operatorRepresentation: OperatorRepresentation) -> List[int]:
+    def _inferNumLevels(self, _inputs: List[VariableBuffer],
+                        _operatorRepresentation: OperatorRepresentation) -> List[int]:
         return [2**(self.input_types[0].referencedType.typeWidth)]
 
-    def _inferSignedness(self, inputs: List[VariableBuffer],
-                         operatorRepresentation: OperatorRepresentation) -> List[bool]:
+    def _inferSignedness(self, _inputs: List[VariableBuffer],
+                         _operatorRepresentation: OperatorRepresentation) -> List[bool]:
         return [True]
TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (3)

2-2: Include the kernel’s own header to enforce signature consistency.

Including the header here catches prototype drift at compile time.

-#include "DeeployBasicMath.h"
+#include "kernel/ConvTranspose1d_fp32.h"

16-21: Optional: zero-init via memset for speed.

A flat memset is typically faster than nested loops.

-  // Output initialization
-  for (uint32_t c = 0; c < C_out; ++c) {
-    for (uint32_t w = 0; w < W_out; ++w) {
-      output[c * W_out + w] = 0.0f;
-    }
-  }
+  // Output initialization
+  memset(output, 0, sizeof(float32_t) * C_out * W_out);

31-33: Guard against invalid stride.

Defensive check avoids UB if stride == 0 from upstream.

-          uint32_t w_out = w_in * stride + k;
+          // assume stride >= 1
+          if (__builtin_expect(stride == 0, 0)) continue;
+          uint32_t w_out = w_in * stride + k;
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (2)

37-40: Fix weight layout comment to match implementation.

Kernel and Layers assume weight shape [C_in, C_out//group, K].

-        operatorRepresentation["dim_kernel_y"] = weight.shape[2]  # Shape: [C_out, C_in, K]
+        operatorRepresentation["dim_kernel_y"] = weight.shape[2]  # Shape: [C_in, C_out//group, K]

31-36: Align dim keys with existing 1D conventions or provide aliases.

Elsewhere 1D often uses dim_im_*_x. Consider mirroring keys to avoid downstream KeyErrors.

         operatorRepresentation["ch_im_out"] = data_out.shape[1]
         operatorRepresentation["dim_im_out_y"] = data_out.shape[2]
+        # Provide x-aliases for 1D flows expecting *_x
+        operatorRepresentation["dim_im_in_x"] = operatorRepresentation["dim_im_in_y"]
+        operatorRepresentation["dim_im_out_x"] = operatorRepresentation["dim_im_out_y"]
Deeploy/Targets/Generic/Parsers.py (4)

367-372: Narrow the exception and drop unused variable

Catching bare Exception and binding e (unused) triggers lints and may mask issues.

-            try:
-                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
-            except Exception as e:
-                self.operatorRepresentation['pads'] = node.attrs['pads']
+            try:
+                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
+            except (TypeError, ValueError):
+                self.operatorRepresentation['pads'] = node.attrs['pads']

1381-1403: Remove duplicated batchOffset assignments

batchOffsetIn/Out are computed twice.

             self.operatorRepresentation['batch'] = data_in.shape[0]
             self.operatorRepresentation['dim_im_in_x'] = 1
             self.operatorRepresentation[
                 'dim_im_out_x'] = 1  # necessary since we use the same Convlayer for all convolutions
@@
             else:
                 self.operatorRepresentation['ch_im_in'] = data_in.shape[2]
                 self.operatorRepresentation['dim_im_in_y'] = data_in.shape[1]
                 self.operatorRepresentation['ch_im_out'] = data_out.shape[2]
                 self.operatorRepresentation['dim_im_out_y'] = data_out.shape[1]
 
             self.operatorRepresentation[
                 'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
             self.operatorRepresentation['batchOffsetOut'] = self.operatorRepresentation[
                 'ch_im_out'] * self.operatorRepresentation['dim_im_out_y']
-            self.operatorRepresentation[
-                'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
-            self.operatorRepresentation['batchOffsetOut'] = self.operatorRepresentation[
-                'ch_im_out'] * self.operatorRepresentation['dim_im_out_y']

2199-2211: Unify has_bias type and avoid verbose error message

Current code mixes 1D vs 2D bias flags and raises a long IndexError.

  • Align with 2D parsers by using "true"/"false" strings (or booleans consistently across templates).
  • Shorten the error message.
-            if len(node.inputs) > 2:
+            if len(node.inputs) > 2:
                 inputs.append("bias")
-                self.operatorRepresentation["has_bias"] = 1
+                self.operatorRepresentation["has_bias"] = "true"
             else:
-                self.operatorRepresentation["has_bias"] = 0
+                self.operatorRepresentation["has_bias"] = "false"
                 self.operatorRepresentation["bias"] = "NULL"
@@
-                if idx >= len(inputs):
-                    raise IndexError(
-                        f"Index {idx} out of range for inputs of length {len(inputs)} in node {inputNode.name}")
+                if idx >= len(inputs):
+                    raise IndexError("input index out of range")

Please confirm templates consume has_bias as "true"/"false" (strings) everywhere; otherwise prefer booleans and adjust templates.


2694-2743: ConvTranspose base ctxt: minor cleanups and consistency

  • channels_first is unused; either use it or prefix with underscore.
  • kernel_shape_y is computed but unused.
  • Prefer ctxt.lookup(...).name to stay consistent with other parsers (handles mangling/hoisting).
-    def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True):
+    def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True):
@@
-        self.operatorRepresentation['data_in'] = node.inputs[0].name
-        self.operatorRepresentation['weight'] = node.inputs[1].name
-        self.operatorRepresentation['data_out'] = node.outputs[0].name
+        self.operatorRepresentation['data_in'] = ctxt.lookup(node.inputs[0].name).name
+        self.operatorRepresentation['weight'] = ctxt.lookup(node.inputs[1].name).name
+        self.operatorRepresentation['data_out'] = ctxt.lookup(node.outputs[0].name).name
@@
-            kernel_shape_y = kernel_shape[1] if len(kernel_shape) > 1 else kernel_shape_x
+            # kernel_shape_y only relevant for 2D; compute when needed
+            if len(kernel_shape) > 1:
+                _ = kernel_shape[1]

If channels_last is expected anywhere for ConvTranspose, we should branch index computation by channels_first here.

Deeploy/Targets/Generic/Bindings.py (1)

81-88: Float Conv1D binding: bias handling consistency

Binding requires 3 pointers; parser sets bias="NULL" when absent. Ensure FloatConvTemplate handles NULL bias without expecting a buffer; otherwise add a 2-input float binding similar to ConvTranspose or hoist zero-bias in parser.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f4cce77 and 6c1b70b.

📒 Files selected for processing (23)
  • .github/workflows/CI.yml (1 hunks)
  • CHANGELOG.md (3 hunks)
  • Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (1 hunks)
  • Deeploy/Targets/Generic/Bindings.py (5 hunks)
  • Deeploy/Targets/Generic/Layers.py (1 hunks)
  • Deeploy/Targets/Generic/Parsers.py (9 hunks)
  • Deeploy/Targets/Generic/Platform.py (5 hunks)
  • Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatConvTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/TypeCheckers.py (1 hunks)
  • Deeploy/Targets/MemPool/Platform.py (2 hunks)
  • TargetLibraries/Generic/inc/DeeployBasicMath.h (3 hunks)
  • TargetLibraries/Generic/inc/kernel/BatchNorm.h (1 hunks)
  • TargetLibraries/Generic/inc/kernel/ConvTranspose1d_fp32.h (1 hunks)
  • TargetLibraries/Generic/inc/kernel/Convolution.h (1 hunks)
  • TargetLibraries/Generic/inc/kernel/MaxPool1d.h (1 hunks)
  • TargetLibraries/Generic/src/BatchNorm_fp32.c (1 hunks)
  • TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (1 hunks)
  • TargetLibraries/Generic/src/Convolution_fp32.c (1 hunks)
  • TargetLibraries/Generic/src/MaxPool1D_fp32.c (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (16)
Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (105-246)
TargetLibraries/Generic/inc/kernel/Convolution.h (1)
TargetLibraries/Generic/src/Convolution_fp32.c (1)
  • Conv1d_fp32_fp32_fp32 (94-121)
Deeploy/Targets/Generic/Templates/FloatConvTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (105-246)
TargetLibraries/Generic/inc/kernel/ConvTranspose1d_fp32.h (1)
TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (1)
  • ConvTranspose1d_fp32 (4-47)
TargetLibraries/Generic/inc/kernel/MaxPool1d.h (1)
TargetLibraries/Generic/src/MaxPool1D_fp32.c (1)
  • MaxPool1d_fp32_fp32 (4-23)
TargetLibraries/Generic/inc/kernel/BatchNorm.h (1)
TargetLibraries/Generic/src/BatchNorm_fp32.c (1)
  • BatchNorm_fp32 (3-24)
Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (105-246)
Deeploy/Targets/Generic/TypeCheckers.py (3)
Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (3)
  • SignPropTypeChecker (33-74)
  • _inferNumLevels (35-37)
  • _inferSignedness (39-41)
Deeploy/AbstractDataTypes.py (2)
  • Pointer (314-395)
  • typeWidth (406-407)
Deeploy/DeeployTypes.py (2)
  • inputs (2447-2467)
  • VariableBuffer (249-397)
Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (105-246)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (2)
Deeploy/DeeployTypes.py (4)
  • NetworkContext (556-1021)
  • NodeTemplate (105-246)
  • alignToContext (136-156)
  • lookup (748-780)
Deeploy/Targets/Generic/Templates/ConvTemplate.py (1)
  • alignToContext (36-49)
Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (1)
Deeploy/DeeployTypes.py (1)
  • outputs (2469-2490)
Deeploy/Targets/Generic/Layers.py (1)
Deeploy/DeeployTypes.py (4)
  • ONNXLayer (1796-2112)
  • NodeMapper (1650-1793)
  • computeOps (1808-1813)
  • computeShapes (1817-1839)
Deeploy/Targets/Generic/Bindings.py (4)
Deeploy/Targets/Generic/TypeCheckers.py (4)
  • BatchNormChecker (624-635)
  • ConvChecker (479-497)
  • MaxPoolChecker (462-476)
  • PadChecker (94-108)
Deeploy/DeeployTypes.py (1)
  • NodeBinding (1509-1647)
Deeploy/AbstractDataTypes.py (1)
  • PointerClass (543-566)
Deeploy/CommonExtensions/DataTypes.py (2)
  • int8_t (31-34)
  • int32_t (43-46)
Deeploy/Targets/Generic/Platform.py (3)
Deeploy/Targets/Generic/Layers.py (3)
  • BatchNormalizationLayer (646-656)
  • ConvTransposeLayer (659-707)
  • TransposeLayer (464-467)
Deeploy/Targets/Generic/Parsers.py (4)
  • BatchNormParser (2629-2665)
  • ConvTranspose1DParser (2746-2792)
  • MaxPool1DParser (248-287)
  • TransposeParser (182-209)
Deeploy/DeeployTypes.py (1)
  • NodeMapper (1650-1793)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1034-1049)
  • parseNodeCtxt (1052-1077)
  • lookup (748-780)
  • inputs (2447-2467)
  • NodeParser (1024-1199)
  • outputs (2469-2490)
  • NetworkContext (556-1021)
Deeploy/Targets/MemPool/Platform.py (2)
Deeploy/DeeployTypes.py (1)
  • NodeMapper (1650-1793)
Deeploy/Targets/Generic/Parsers.py (1)
  • GenericConv1DParser (2174-2213)
🪛 LanguageTool
CHANGELOG.md

[grammar] ~238-~238: There might be a mistake here.
Context: ...L. ### Changed - FloatConvTemplate file - Platform.py file - Bump the CMake vers...

(QB_NEW_EN)


[grammar] ~239-~239: There might be a mistake here.
Context: ...loatConvTemplate file - Platform.py file - Bump the CMake version to 3.24 as requir...

(QB_NEW_EN)

🪛 Ruff (0.12.2)
Deeploy/Targets/Generic/TypeCheckers.py

629-629: Unused method argument: inputs

(ARG002)


630-630: Unused method argument: operatorRepresentation

(ARG002)


633-633: Unused method argument: inputs

(ARG002)


634-634: Unused method argument: operatorRepresentation

(ARG002)

Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py

70-70: zip() without an explicit strict= parameter

Add explicit value for parameter strict=

(B905)

Deeploy/Targets/Generic/Parsers.py

369-369: Do not catch blind exception: Exception

(BLE001)


369-369: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2208-2209: Avoid specifying long messages outside the exception class

(TRY003)


2649-2649: Unused method argument: channels_first

(ARG002)


2694-2694: Unused method argument: channels_first

(ARG002)


2727-2727: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

🔇 Additional comments (15)
TargetLibraries/Generic/inc/kernel/Convolution.h (1)

70-77: API looks good; confirm template computes W_out consistently.

New Conv1d prototype aligns with implementation. Please confirm codegen computes W_out per chosen padding/stride semantics.

Deeploy/Targets/Generic/Layers.py (1)

646-657: Ops model for BatchNorm is reasonable.

5 ops/element is a fine approximation for scheduling/estimation.

Deeploy/Targets/Generic/Parsers.py (3)

248-287: MaxPool1D parser looks good

Attribute validation and IO shape handling for 1D are correct.


450-462: Pad1D: schema checks and ctxt mapping are fine

Constraints (len=6, zeroed batch/channel pads) and channels_first/last handling look consistent; x=1 sentinel is appropriate for 1D.

Also applies to: 469-491


2773-2792: Remove Y dimension for 1D ConvTranspose to avoid double-counting
Superclass parse sets dim_im_out_x; drop the dim_im_out_y assignment and update batchOffsetOut to use dim_im_out_x:

@@ -2777,8 +2777,8 @@ def parseNodeCtxt(...):
-    self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
-    self.operatorRepresentation["batchOffsetOut"] = self.operatorRepresentation["ch_im_out"] * self.operatorRepresentation["dim_im_out_y"]
+    # dim_im_out_x already set by base; remove Y dim for 1D
+    self.operatorRepresentation["batchOffsetOut"] = self.operatorRepresentation["ch_im_out"] * self.operatorRepresentation["dim_im_out_x"]

Re-run FLOP/ops accounting for the 1D Autoencoder to confirm the corrected (lower) ops counts.

Deeploy/Targets/Generic/Platform.py (5)

33-52: Imports updated correctly for new ops

Bindings/Layers/Parsers imports align with added features.


58-61: Conv1D mapper switch to multi-binding list is OK

Moving to BasicConv1DBindings matches new float+int8 support.


77-78: MaxPool now aggregates 1D and 2D

Mapper addition looks good.


94-96: New mappers registered

BatchNorm and ConvTranspose mappers are wired as expected.

Is 2D ConvTranspose intentionally unsupported on Generic? If yes, consider naming ConvTranspose1D in mapping comment to avoid confusion.


123-141: GenericMapping entries: confirm operator precedence

Order places 1D/2D Conv and DWConv together and MaxPool with 1D first; fine if type/checkers disambiguate. New BatchNormalization and ConvTranspose entries look consistent.

Deeploy/Targets/Generic/Bindings.py (5)

38-47: Template imports are consistent

New Float/BN/ConvTranspose templates added correctly.


47-52: TypeChecker imports are consistent

BatchNormChecker inclusion matches new BN bindings.


181-184: MaxPool1D float binding LGTM

Mapped to FloatMaxPoolTemplate.reference1DTemplate with MaxPoolChecker.


203-210: Pad1D float path LGTM

Extends to FloatPadTemplate 1D; consistent with 2D path.


310-319: BatchNorm bindings LGTM

5-input float binding with BatchNormChecker to BatchNormalizationTemplate is correct.

@Xeratec
Copy link
Member

Xeratec commented Sep 14, 2025

@Aldrago98, can you rebase your PR and take a look at the unresolved conversations?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (8)
Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (1)

51-66: Fix undefined variables and enforce strict zip; remove duplicated warnings

  • obj and nLevel are referenced in the else-branch but are undefined there; this will crash when signProp is False.
  • Warnings are duplicated.
  • Guard for None/mismatched lengths and use zip(strict=True) to satisfy Ruff B905 and avoid silent truncation.

Apply:

             if nLevels is None or signedness is None:
                 return ctxt
-            for obj, nLevel, sign in zip(outputs, nLevels, signedness):
+            if len(nLevels) != len(outputs) or len(signedness) != len(outputs):
+                raise ValueError("SignPropTypeChecker: inferred lengths must match outputs.")
+            for obj, nLevel, sign in zip(outputs, nLevels, signedness, strict=True):
                 obj.nLevels = nLevel
                 obj._signed = sign
-        else:
-            if issubclass(obj._type.referencedType, IntegerImmediate) and not obj._type.fitsNumLevels(nLevel):
-                log.warning(
-                    f"{obj.name} has {nLevel} levels, but {obj._type.referencedType.typeName} only supports {obj._type.referencedType.nLevels} levels."
-                )
-
-            if issubclass(obj._type.referencedType, IntegerImmediate) and not obj._type.fitsNumLevels(nLevel):
-                log.warning(
-                    f"{obj.name} has {nLevel} levels, but {obj._type.referencedType.typeName} only supports {obj._type.referencedType.nLevels} levels."
-                )
+        else:
+            # Inputs missing sign/levels metadata; skip level checks.
+            pass
Deeploy/Targets/Generic/Layers.py (2)

668-684: Harden pixel-count logic and clean comment

Support 1D/2D robustly and avoid Italian comment.

-        kernel_shape = np.prod(opRep['kernel_shape'])  # es. [3, 3] -> 9
+        kernel_shape = np.prod(opRep['kernel_shape'])  # e.g., [3, 3] -> 9
@@
-        # ConvTranspose upscales spatial dims, quindi num pixel viene da output
-        if 'dim_im_out_y' in opRep:
-            numPx = opRep['dim_im_out_x'] * opRep['dim_im_out_y']
-        else:
-            numPx = opRep['dim_im_out_x']
+        # Use output spatial size (1D or 2D)
+        if 'dim_im_out_x' in opRep and 'dim_im_out_y' in opRep:
+            numPx = opRep['dim_im_out_x'] * opRep['dim_im_out_y']
+        elif 'dim_im_out_x' in opRep:
+            numPx = opRep['dim_im_out_x']
+        elif 'dim_im_out_y' in opRep:
+            numPx = opRep['dim_im_out_y']
+        else:
+            raise KeyError("ConvTransposeLayer: missing output spatial dims")

641-666: Fix channels_last output-channel inference for ConvTranspose

channels_last branch uses weight_shape[-2] (spatial), not C_out//group. Use weight_shape[1] for both 1D/2D and multiply by group.

             else:
-                # For 1D: weight_shape = [C_in, C_out // group, kW]
-                # For 2D: weight_shape = [C_in, C_out // group, kH, kW]
-                ch_out = weight_shape[-2] * group
+                # For 1D/2D: weight_shape = [C_in, C_out // group, ...]
+                ch_out = weight_shape[1] * group
                 newOutputShapes[0][-1] = ch_out
Deeploy/Targets/Generic/TypeCheckers.py (1)

620-627: ConvTranspose nLevels uses wrong channel dim; account for groups

ONNX ConvTranspose weight shape is (C, M/group, k...); accumulation should use input channels per group, not weight.shape[1]. Also support 'group'/'groups'.

-        weight = inputs[1]
-        return [
-            np.prod(operatorRepresentation['kernel_shape']) * weight.nLevels * weight.shape[1] *  # ch_im_in
-            2**(self.input_types[0].referencedType.typeWidth)
-        ]
+        weight = inputs[1]
+        groups = int(operatorRepresentation.get('group', operatorRepresentation.get('groups', 1)) or 1)
+        ch_in_per_group = int(weight.shape[0]) // groups
+        return [
+            int(np.prod(operatorRepresentation['kernel_shape'])) * int(weight.nLevels) * ch_in_per_group *
+            2**(self.input_types[0].referencedType.typeWidth)
+        ]
Deeploy/Targets/Generic/Parsers.py (3)

2632-2669: BatchNorm: respect channels_first, validate rank, and set nodeName/nodeOp

  • Validate input is 3D.
  • Use channels_first to extract C/W.
  • Provide template identifiers.
     def parseNodeCtxt(self, ctxt, node: gs.Node, channels_first: bool = True):
@@
-        input_shape = ctxt.lookup(node.inputs[0].name).shape
-        # Save input shape information
-        self.operatorRepresentation['batch_size'] = input_shape[0]
-        self.operatorRepresentation['channel_size'] = input_shape[1]
-        self.operatorRepresentation['window_size'] = input_shape[2]
+        input_shape = ctxt.lookup(node.inputs[0].name).shape
+        if input_shape is None or len(input_shape) != 3:
+            return ctxt, False
+        self.operatorRepresentation['batch_size'] = input_shape[0]
+        if channels_first:
+            self.operatorRepresentation['channel_size'] = input_shape[1]
+            self.operatorRepresentation['window_size'] = input_shape[2]
+        else:
+            self.operatorRepresentation['channel_size'] = input_shape[2]
+            self.operatorRepresentation['window_size'] = input_shape[1]
+        self.operatorRepresentation['nodeName'] = node.name
+        self.operatorRepresentation['nodeOp'] = node.op

2755-2774: ConvTranspose1D.parseNode: return combined status

Currently returns wellFormed, ignoring 1D constraints; return both.

-        return wellFormed
+        return wellFormed and ret

2776-2796: ConvTranspose1D.parseNodeCtxt: preserve newCtxt and validate ranks

Don’t drop updated context; assert 3D tensors.

-        newCtxt, ret = super().parseNodeCtxt(ctxt, node, channels_first)
-
-        if ret:
+        newCtxt, ret = super().parseNodeCtxt(ctxt, node, channels_first)
+        if not ret:
+            return ctxt, False
+        # Expect N,C,W (or N,W,C)
+        if len(newCtxt.lookup(node.inputs[0].name).shape) != 3 or len(newCtxt.lookup(node.outputs[0].name).shape) != 3:
+            return newCtxt, False
+        if ret:
@@
-        return ctxt, True
+        return newCtxt, True
Deeploy/Targets/Generic/Bindings.py (1)

23-27: Critical: Missing import for ConvTransposeChecker (previously flagged).

ConvTransposeChecker is referenced on lines 299 and 306 but is not imported. This causes a NameError at import time.

Apply this diff:

 from Deeploy.Targets.Generic.TypeCheckers import AddChecker, BatchNormChecker, ConcatChecker, ConvChecker, \
-    DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, GEMMChecker, \
+    ConvTransposeChecker, DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, GEMMChecker, \
     LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, ReduceMeanChecker, \
     ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, SliceChecker, \
     SoftmaxChecker, TransposeChecker
🧹 Nitpick comments (4)
Deeploy/Targets/Generic/TypeCheckers.py (1)

606-613: Silence ARG002 or use inputs in BatchNormChecker

Both methods ignore parameters; prefix with underscore or add minimal assertions to satisfy Ruff ARG002.

-    def _inferNumLevels(self, inputs: List[VariableBuffer],
-                        operatorRepresentation: OperatorRepresentation) -> List[int]:
+    def _inferNumLevels(self, _inputs: List[VariableBuffer],
+                        _operatorRepresentation: OperatorRepresentation) -> List[int]:
         return [2**(self.input_types[0].referencedType.typeWidth)]
@@
-    def _inferSignedness(self, inputs: List[VariableBuffer],
-                         operatorRepresentation: OperatorRepresentation) -> List[bool]:
+    def _inferSignedness(self, _inputs: List[VariableBuffer],
+                         _operatorRepresentation: OperatorRepresentation) -> List[bool]:
         return [True]
Deeploy/Targets/Generic/Parsers.py (3)

343-347: Narrow exception and drop unused var in PadParser

Avoid broad except and unused variable; keep pads as list when conversion fails.

-            try:
-                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
-            except Exception as e:
-                self.operatorRepresentation['pads'] = node.attrs['pads']
+            try:
+                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
+            except (ValueError, TypeError):
+                self.operatorRepresentation['pads'] = list(node.attrs['pads'])

1381-1401: Remove duplicate batchOffset computations in Conv1DParser

Same expressions are assigned twice.

             self.operatorRepresentation['batchOffsetOut'] = self.operatorRepresentation[
                 'ch_im_out'] * self.operatorRepresentation['dim_im_out_y']
-            self.operatorRepresentation[
-                'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
-            self.operatorRepresentation['batchOffsetOut'] = self.operatorRepresentation[
-                'ch_im_out'] * self.operatorRepresentation['dim_im_out_y']

2201-2212: Avoid raising in parser loop; guard length instead

IndexError here is avoidable; just check length before indexing.

-            for idx, inputNode in enumerate(node.inputs):
-                if idx >= len(inputs):
-                    raise IndexError(
-                        f"Index {idx} out of range for inputs of length {len(inputs)} in node {inputNode.name}")
-                self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name
+            if len(node.inputs) > len(inputs):
+                return newCtxt, False
+            for idx, inputNode in enumerate(node.inputs):
+                self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0761293 and a4af405.

📒 Files selected for processing (14)
  • CHANGELOG.md (3 hunks)
  • Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (1 hunks)
  • Deeploy/DeeployTypes.py (0 hunks)
  • Deeploy/Targets/Generic/Bindings.py (5 hunks)
  • Deeploy/Targets/Generic/Layers.py (1 hunks)
  • Deeploy/Targets/Generic/Parsers.py (9 hunks)
  • Deeploy/Targets/Generic/Platform.py (5 hunks)
  • Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatConvTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/TypeCheckers.py (1 hunks)
  • Deeploy/Targets/MemPool/Platform.py (2 hunks)
💤 Files with no reviewable changes (1)
  • Deeploy/DeeployTypes.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • Deeploy/Targets/Generic/Templates/FloatPadTemplate.py
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py
  • Deeploy/Targets/MemPool/Platform.py
  • Deeploy/Targets/Generic/Templates/FloatConvTemplate.py
  • Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py
  • CHANGELOG.md
🧰 Additional context used
🧬 Code graph analysis (7)
Deeploy/Targets/Generic/Bindings.py (4)
Deeploy/Targets/Generic/TypeCheckers.py (6)
  • BatchNormChecker (601-612)
  • ConvChecker (456-474)
  • MaxPoolChecker (439-453)
  • PadChecker (71-85)
  • TransposeChecker (54-68)
  • ConvTransposeChecker (615-632)
Deeploy/DeeployTypes.py (1)
  • NodeBinding (1568-1712)
Deeploy/AbstractDataTypes.py (1)
  • PointerClass (536-559)
Deeploy/CommonExtensions/DataTypes.py (2)
  • int8_t (12-15)
  • int32_t (24-27)
Deeploy/Targets/Generic/TypeCheckers.py (3)
Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (3)
  • SignPropTypeChecker (14-67)
  • _inferNumLevels (16-18)
  • _inferSignedness (20-22)
Deeploy/AbstractDataTypes.py (3)
  • Pointer (303-388)
  • typeWidth (399-400)
  • nLevels (194-195)
Deeploy/DeeployTypes.py (2)
  • inputs (2558-2575)
  • VariableBuffer (232-391)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1089-1104)
  • parseNodeCtxt (1107-1132)
  • lookup (776-808)
  • inputs (2558-2575)
  • NodeParser (1079-1254)
  • outputs (2577-2594)
  • NetworkContext (564-1076)
Deeploy/Targets/Generic/Layers.py (1)
Deeploy/DeeployTypes.py (4)
  • ONNXLayer (1874-2202)
  • NodeMapper (1715-1871)
  • computeOps (1890-1895)
  • computeShapes (1899-1921)
Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (87-229)
Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py (1)
Deeploy/AbstractDataTypes.py (4)
  • IntegerImmediate (173-224)
  • fitsNumLevels (223-224)
  • fitsNumLevels (346-347)
  • nLevels (194-195)
Deeploy/Targets/Generic/Platform.py (3)
Deeploy/Targets/Generic/Layers.py (3)
  • TransposeLayer (441-444)
  • BatchNormalizationLayer (623-633)
  • ConvTransposeLayer (636-684)
Deeploy/Targets/Generic/Parsers.py (5)
  • TransposeParser (158-185)
  • BatchNormParser (2632-2668)
  • ConvTransposeParser (2671-2746)
  • MaxPool1DParser (224-263)
  • ConvTranspose1DParser (2749-2796)
Deeploy/DeeployTypes.py (1)
  • NodeMapper (1715-1871)
🪛 Ruff (0.14.0)
Deeploy/Targets/Generic/Bindings.py

299-299: Undefined name ConvTransposeChecker

(F821)


306-306: Undefined name ConvTransposeChecker

(F821)

Deeploy/Targets/Generic/TypeCheckers.py

606-606: Unused method argument: inputs

(ARG002)


607-607: Unused method argument: operatorRepresentation

(ARG002)


610-610: Unused method argument: inputs

(ARG002)


611-611: Unused method argument: operatorRepresentation

(ARG002)


630-630: Unused method argument: operatorRepresentation

(ARG002)

Deeploy/Targets/Generic/Parsers.py

345-345: Do not catch blind exception: Exception

(BLE001)


345-345: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2210-2211: Avoid specifying long messages outside the exception class

(TRY003)


2652-2652: Unused method argument: channels_first

(ARG002)


2697-2697: Unused method argument: channels_first

(ARG002)


2730-2730: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

Deeploy/Targets/Generic/Platform.py

33-33: Undefined name BasicConv1DBindings

(F821)

🔇 Additional comments (13)
Deeploy/Targets/Generic/Parsers.py (3)

229-244: MaxPool1D: spec checks and fields look good

Shape/attr validation and operatorRepresentation fields are consistent.


245-264: MaxPool1D parseNodeCtxt: LGTM

Correct handling of channels_first and 3D rank check.


2676-2696: ConvTranspose parseNode: LGTM

Attributes are captured with sensible defaults; nodeName/nodeOp provided.

Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)

3-11: No action required—the parser already sets nodeName/nodeOp.

The verification shows the BatchNormParser sets both operatorRepresentation['nodeName'] and operatorRepresentation['nodeOp'] at lines 2693–2694. The template placeholders on line 4 will resolve without error.

Likely an incorrect or invalid review comment.

Deeploy/Targets/Generic/Platform.py (4)

33-33: LGTM once import is fixed.

The update from BasicConv1DBinding to BasicConv1DBindings correctly reflects the refactor in Bindings.py that now provides per-type bindings (float and int8) for 1D convolution. Ensure the import on line 9 is corrected as noted above.


51-51: LGTM!

The new MaxPool1DMapper follows established patterns and is correctly wired into GenericMapping at line 97 alongside the existing 2D variant.


68-69: LGTM!

The new mappers for batch normalization and transposed convolution follow established patterns and are correctly integrated into the platform mapping.


97-97: LGTM!

The GenericMapping updates correctly expose the new 1D/2D pooling variants and the new BatchNormalization and ConvTranspose operations. The structure follows existing conventions.

Also applies to: 113-114

Deeploy/Targets/Generic/Bindings.py (5)

57-64: LGTM!

The refactor from a single BasicConv1DBinding to BasicConv1DBindings list correctly enables multi-type support (float and int8) for 1D convolution, following the same pattern as the 2D variant. This aligns with the usage in Platform.py line 33.


157-160: LGTM!

The new BasicMaxPool1DBindings correctly implements 1D max pooling for floating-point types, following the established binding pattern.


179-185: LGTM!

The extension of BasicPad1DBindings to support floating-point types alongside the existing signed integer types is consistent with the 2D padding pattern and correctly uses FloatPadTemplate.reference1DTemplate.


286-295: LGTM!

The new BasicBatchNormBindings correctly implements batch normalization for floating-point types with the standard 5-input signature (data, scale, bias, mean, variance). The structure follows established patterns.


297-311: LGTM once import is fixed.

The new BasicConvTransposeBindings correctly handles both biased and unbiased transposed convolution variants for floating-point types. The structure is sound, but ensure ConvTransposeChecker is imported as noted in the comment on lines 23-27.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (6)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1)

68-77: Critical: Batch loop doesn't advance input/output pointers.

All batch iterations process the first batch slice because the pointers are never incremented. This causes incorrect results for batched inputs.

Apply this diff to fix the pointer arithmetic:

     for (uint32_t n=0; n<${batch}; ++n) {
+        ${data_in_type.typeName} * in_ptr  = ref_${data_out}_${data_in}  + n * batchOffsetIn;
+        ${data_out_type.typeName} * out_ptr = ref_${data_out}_${data_out} + n * batchOffsetOut;
         ConvTranspose1d_fp32(
-            ref_${data_out}_${data_in}, ${ch_im_in}, ${dim_im_in_y},
+            in_ptr, ${ch_im_in}, ${dim_im_in_y},
             ${weight}, ${ch_im_out}, ${dim_kernel_y},
             ${stride_y},
             ${bias}, ${has_bias},
-            ref_${data_out}_${data_out}, ${dim_im_out_y}
+            out_ptr, ${dim_im_out_y}
         );
         
     }
Deeploy/Targets/Generic/Parsers.py (4)

2632-2668: BatchNormParser: Validate rank and respect channels_first parameter.

The parser assumes input shape is always [N, C, W] and ignores the channels_first parameter. This breaks when data uses channels-last layout or has unexpected rank.

Apply this diff to add validation and handle both layouts:

     def parseNodeCtxt(self, ctxt, node: gs.Node, channels_first: bool = True):
         inputs = ['data_in', 'scale', 'bias', 'mean', 'variance']
         outputs = ['data_out']

         for idx, inputNode in enumerate(node.inputs[:5]):
             self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name

         # Output (Y)
         self.operatorRepresentation[outputs[0]] = ctxt.lookup(node.outputs[0].name).name

         input_shape = ctxt.lookup(node.inputs[0].name).shape
+        # Validate 3D input
+        if len(input_shape) != 3:
+            return ctxt, False
         # Save input shape information
         self.operatorRepresentation['batch_size'] = input_shape[0]
-        self.operatorRepresentation['channel_size'] = input_shape[1]
-        self.operatorRepresentation['window_size'] = input_shape[2]
+        if channels_first:
+            self.operatorRepresentation['channel_size'] = input_shape[1]
+            self.operatorRepresentation['window_size'] = input_shape[2]
+        else:
+            self.operatorRepresentation['channel_size'] = input_shape[2]
+            self.operatorRepresentation['window_size'] = input_shape[1]

         return ctxt, True

2697-2746: ConvTransposeParser: Honor channels_first and remove unused variables.

The parser ignores the channels_first parameter when extracting shape dimensions and declares kernel_shape_y without using it. This causes incorrect shape extraction for channels-last layouts.

The implementation needs to:

  1. Respect channels_first when extracting channels and spatial dimensions for both 1D and 2D cases
  2. Remove unused kernel_shape_y variable

Apply this diff:

     def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True):
         # Register buffer names for codegen
         self.operatorRepresentation['data_in'] = node.inputs[0].name
         self.operatorRepresentation['weight'] = node.inputs[1].name
         self.operatorRepresentation['data_out'] = node.outputs[0].name
         if len(node.inputs) == 3:
             self.operatorRepresentation['bias'] = node.inputs[2].name
             self.operatorRepresentation['has_bias'] = True
         else:
             self.operatorRepresentation['has_bias'] = False
-        # Get output shape from context
-        data_out = ctxt.lookup(node.outputs[0].name)
-        out_shape = data_out.shape
-        if len(out_shape) == 3:
-            self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
-        elif len(out_shape) == 4:
-            self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
-            self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
-
-        stride_x, stride_y = 1, 1
-        if "strides" in node.attrs:
-            stride_y = node.attrs["strides"][0]
-            stride_x = node.attrs["strides"][1] if len(node.attrs["strides"]) > 1 else stride_y
-        self.operatorRepresentation["stride_y"] = stride_y
-        self.operatorRepresentation["stride_x"] = stride_x
-
-        if "kernel_shape" in node.attrs:
-            kernel_shape = node.attrs["kernel_shape"]
-            kernel_shape_x = kernel_shape[0]
-            # For 2D, kernel_shape may have two elements
-            kernel_shape_y = kernel_shape[1] if len(kernel_shape) > 1 else kernel_shape_x
-        else:
-            kernel_shape_x = 1
-            kernel_shape_y = 1
 
         data_in = ctxt.lookup(node.inputs[0].name)
         data_out = ctxt.lookup(node.outputs[0].name)
         in_shape = data_in.shape
         out_shape = data_out.shape
 
-        self.operatorRepresentation['ch_im_in'] = in_shape[1]
-        self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
-        self.operatorRepresentation['ch_im_out'] = out_shape[1]
-        self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+        # Extract input/output dimensions respecting channels_first
+        if len(in_shape) == 3:
+            if channels_first:
+                self.operatorRepresentation['ch_im_in'] = in_shape[1]
+                self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
+            else:
+                self.operatorRepresentation['ch_im_in'] = in_shape[2]
+                self.operatorRepresentation['dim_im_in_y'] = in_shape[1]
+        
+        if len(out_shape) == 3:
+            if channels_first:
+                self.operatorRepresentation['ch_im_out'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+            else:
+                self.operatorRepresentation['ch_im_out'] = out_shape[2]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[1]
+        elif len(out_shape) == 4:
+            if channels_first:
+                self.operatorRepresentation['ch_im_out'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
+            else:
+                self.operatorRepresentation['ch_im_out'] = out_shape[3]
+                self.operatorRepresentation['dim_im_out_x'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
 
         self.operatorRepresentation[
             'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
         self.operatorRepresentation[
             'batchOffsetOut'] = self.operatorRepresentation['ch_im_out'] * self.operatorRepresentation['dim_im_out_y']
         return ctxt, True

2754-2773: Bug: parseNode returns wrong validation status.

The method computes ret for 1D-specific constraints but returns wellFormed from the superclass. This allows invalid 1D configurations to pass validation.

Apply this diff:

     def parseNode(self, node: gs.Node) -> bool:
         # 1D ConvTranspose expects 3D input/output and 3D weight
         wellFormed = super().parseNode(node)
         ret = False
         if wellFormed:
             ret = all([
                 # Make sure strides are 2D
                 len(node.attrs['strides']) == 1,
                 len(node.attrs['pads']) == 2,
                 len(node.attrs['dilations']) == 1,
             ])
         if ret:

             self.operatorRepresentation['kernel_shape'] = node.attrs['kernel_shape']
             self.operatorRepresentation['dim_kernel_y'] = int(self.operatorRepresentation['kernel_shape'][0])
             self.operatorRepresentation['dilation_y'] = int(self.operatorRepresentation['dilations'][0])
             self.operatorRepresentation['padding_y'] = int(self.operatorRepresentation['pads'][0])
             self.operatorRepresentation['stride_y'] = int(self.operatorRepresentation['strides'][0])

-        return wellFormed
+        return ret

2775-2795: Critical: parseNodeCtxt discards updated context and skips validation.

Returning (ctxt, True) discards newCtxt from the superclass and unconditionally returns success, bypassing shape validation. This can lead to runtime errors with invalid configurations.

Apply this diff:

     def parseNodeCtxt(self,
                       ctxt: NetworkContext,
                       node: gs.Node,
                       channels_first: bool = True) -> Tuple[NetworkContext, bool]:

         newCtxt, ret = super().parseNodeCtxt(ctxt, node, channels_first)

+        if not ret:
+            return ctxt, False
+        
         if ret:
             data_in = newCtxt.lookup(node.inputs[0].name)
             data_out = newCtxt.lookup(node.outputs[0].name)
             in_shape = data_in.shape
             out_shape = data_out.shape
+            
+            # Validate 3D tensors
+            if len(in_shape) != 3 or len(out_shape) != 3:
+                return ctxt, False
+            
             self.operatorRepresentation['ch_im_in'] = in_shape[1]
             self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
             self.operatorRepresentation['ch_im_out'] = out_shape[1]
             self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
             self.operatorRepresentation[
                 "batchOffsetIn"] = self.operatorRepresentation["ch_im_in"] * self.operatorRepresentation["dim_im_in_y"]
             self.operatorRepresentation["batchOffsetOut"] = self.operatorRepresentation[
                 "ch_im_out"] * self.operatorRepresentation["dim_im_out_y"]
-        return ctxt, True
+        return newCtxt, True
Deeploy/Targets/Generic/Bindings.py (1)

23-27: Critical: Missing import for ConvTransposeChecker.

Lines 299 and 306 reference ConvTransposeChecker, but it's not imported. This will cause a NameError at import time.

Apply this diff:

 from Deeploy.Targets.Generic.TypeCheckers import AddChecker, BatchNormChecker, ConcatChecker, ConvChecker, \
-    DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, \
-    GEMMChecker, LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, \
-    ReduceMeanChecker, ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, \
-    SliceChecker, SoftmaxChecker, TransposeChecker
+    ConvTransposeChecker, DebugPrintChecker, DequantChecker, DivChecker, DummyChecker, GatherChecker, GELUChecker, \
+    GEMMChecker, LayerNormChecker, MatMulChecker, MaxPoolChecker, MulChecker, PadChecker, QuantChecker, \
+    ReduceMeanChecker, ReduceSumChecker, ReluChecker, RequantShiftChecker, ReshapeChecker, RQIntegerDivChecker, \
+    SliceChecker, SoftmaxChecker, TransposeChecker
🧹 Nitpick comments (2)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1)

14-15: Remove duplicate comment.

The comment "# input/output tensors" appears twice consecutively.

Apply this diff:

     def alignToContext(self, ctxt: NetworkContext,
                        operatorRepresentation: OperatorRepresentation) -> Tuple[NetworkContext, Dict, List[str]]:

         # input/output tensors
-        # input/output tensors
         data_in = ctxt.lookup(operatorRepresentation["data_in"])
         data_out = ctxt.lookup(operatorRepresentation["data_out"])
Deeploy/Targets/Generic/Parsers.py (1)

343-347: Avoid catching blind exceptions.

The broad except Exception clause masks the actual error, and the caught exception e is never used. Consider catching specific exceptions or removing the try-except if the int conversion is expected to always succeed.

Apply this diff:

         if ret:
             self.operatorRepresentation['mode'] = node.attrs['mode']
-            try:
-                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
-            except Exception as e:
-                self.operatorRepresentation['pads'] = node.attrs['pads']
-            # self.operatorRepresentation['pads'] = node.attrs['pads']
+            # Handle both list and scalar pad values
+            pads = node.attrs['pads']
+            if isinstance(pads, (list, tuple)):
+                self.operatorRepresentation['pads'] = [int(p) for p in pads]
+            else:
+                self.operatorRepresentation['pads'] = pads
             self.operatorRepresentation['value'] = node.attrs['value']
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4af405 and 61396c6.

📒 Files selected for processing (4)
  • Deeploy/Targets/Generic/Bindings.py (5 hunks)
  • Deeploy/Targets/Generic/Parsers.py (9 hunks)
  • Deeploy/Targets/Generic/Platform.py (5 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (3)
Deeploy/DeeployTypes.py (4)
  • NetworkContext (564-1076)
  • NodeTemplate (87-229)
  • alignToContext (119-139)
  • lookup (776-808)
Deeploy/Targets/Generic/Templates/ConvTemplate.py (1)
  • alignToContext (15-28)
Deeploy/AbstractDataTypes.py (1)
  • nLevels (194-195)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1089-1104)
  • parseNodeCtxt (1107-1132)
  • lookup (776-808)
  • inputs (2558-2575)
  • NodeParser (1079-1254)
  • outputs (2577-2594)
  • NetworkContext (564-1076)
Deeploy/Targets/Generic/Bindings.py (4)
Deeploy/Targets/Generic/TypeCheckers.py (6)
  • BatchNormChecker (601-612)
  • ConvChecker (456-474)
  • ConvTransposeChecker (615-632)
  • MaxPoolChecker (439-453)
  • PadChecker (71-85)
  • TransposeChecker (54-68)
Deeploy/DeeployTypes.py (1)
  • NodeBinding (1568-1712)
Deeploy/AbstractDataTypes.py (1)
  • PointerClass (536-559)
Deeploy/CommonExtensions/DataTypes.py (2)
  • int8_t (12-15)
  • int32_t (24-27)
Deeploy/Targets/Generic/Platform.py (3)
Deeploy/Targets/Generic/Layers.py (4)
  • BatchNormalizationLayer (623-633)
  • ConvTransposeLayer (636-684)
  • MaxPoolLayer (380-391)
  • TransposeLayer (441-444)
Deeploy/Targets/Generic/Parsers.py (4)
  • BatchNormParser (2632-2668)
  • ConvTranspose1DParser (2749-2795)
  • MaxPool1DParser (224-263)
  • TransposeParser (158-185)
Deeploy/DeeployTypes.py (1)
  • NodeMapper (1715-1871)
🪛 Ruff (0.14.0)
Deeploy/Targets/Generic/Parsers.py

345-345: Do not catch blind exception: Exception

(BLE001)


345-345: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2210-2211: Avoid specifying long messages outside the exception class

(TRY003)


2652-2652: Unused method argument: channels_first

(ARG002)


2697-2697: Unused method argument: channels_first

(ARG002)


2730-2730: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

Deeploy/Targets/Generic/Platform.py

35-35: Undefined name BasicConv1DBindings

(F821)

🔇 Additional comments (9)
Deeploy/Targets/Generic/Platform.py (4)

9-16: LGTM!

The imports correctly reference the new bindings and parsers. The static analysis warning about BasicConv1DBindings on line 35 is a false positive—the symbol is properly defined in Bindings.py lines 57-64.


35-35: LGTM!

The Conv1DMapper correctly uses BasicConv1DBindings (plural), which is defined as a list in Bindings.py lines 57-64. This replaces the previous single-binding approach with multi-type bindings supporting both float and int8 types.


70-71: LGTM!

The new mappers for BatchNormalization and ConvTranspose are correctly instantiated with their corresponding parsers and bindings.


99-116: LGTM!

The mapping updates correctly:

  • MaxPool now supports both 1D and 2D variants via the mapper list
  • New BatchNormalization and ConvTranspose entries are properly wired to their respective layers
Deeploy/Targets/Generic/Bindings.py (5)

57-64: LGTM!

The refactored BasicConv1DBindings correctly provides multi-type support: FloatDataTypes use the new FloatConvTemplate, while int8_t retains the original ConvTemplate. This enables proper float32 1D convolution support.


157-160: LGTM!

The new BasicMaxPool1DBindings correctly maps FloatDataTypes to the 1D float max pooling template, enabling 1D pooling support for floating-point data.


179-185: LGTM!

The extended BasicPad1DBindings adds float type support using FloatPadTemplate while preserving existing integer bindings.


286-295: LGTM!

BasicBatchNormBindings correctly wires FloatDataTypes to BatchNormalizationTemplate with appropriate type checking for the 5 input tensors (data, scale, bias, mean, variance).


297-311: LGTM!

BasicConvTransposeBindings properly handles both 3-input (with bias) and 2-input (no bias) ConvTranspose configurations for FloatDataTypes. The bindings correctly use ConvTransposeChecker and ConvTransposeTemplate.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
TargetLibraries/Generic/inc/kernel/BatchNorm.h (1)

8-14: Include DeeployBasicMath.h to define float32_t.

float32_t is not a standard type provided by stdint.h. The implementation file includes DeeployBasicMath.h, and this header should do the same.

Apply this diff:

 #include <stdbool.h>
 #include <stdint.h>
+#include "DeeployBasicMath.h"
 
 void BatchNorm_fp32(const float32_t *input, const float32_t *gamma,
                     const float32_t *beta, const float32_t *mean,
                     const float32_t *var, float32_t *output, int N, int C,
                     int L);
TargetLibraries/Generic/inc/kernel/ConvTranspose1d_fp32.h (1)

8-14: Include DeeployBasicMath.h and add C++ linkage guards.

float32_t is not a standard type, and C++ builds require extern "C" linkage. The implementation file includes DeeployBasicMath.h, so this header should as well.

Apply this diff:

 #include <stdbool.h>
 #include <stdint.h>
+#include "DeeployBasicMath.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 void ConvTranspose1d_fp32(const float32_t *input, uint32_t C_in, uint32_t W_in,
                           const float32_t *weight, uint32_t C_out, uint32_t K,
                           uint32_t stride, const float32_t *bias, bool has_bias,
                           float32_t *output, uint32_t W_out);
 
+#ifdef __cplusplus
+}
+#endif
 #endif // CONV_TRANSPOSE1D_FP32_H
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1)

72-81: Critical: Batch loop doesn't advance input/output pointers.

The for loop iterates over batches but reuses the same input/output pointers for every iteration, causing all batches to process the first batch's data repeatedly.

Apply this diff:

     for (uint32_t n=0; n<${batch}; ++n) {
+        ${data_in_type.typeName} *in_ptr  = ref_${data_out}_${data_in}  + n * batchOffsetIn;
+        ${data_out_type.typeName} *out_ptr = ref_${data_out}_${data_out} + n * batchOffsetOut;
         ConvTranspose1d_fp32(
-            ref_${data_out}_${data_in}, ${ch_im_in}, ${dim_im_in_y},
+            in_ptr, ${ch_im_in}, ${dim_im_in_y},
             ${weight}, ${ch_im_out}, ${dim_kernel_y},
             ${stride_y},
             ${bias}, ${has_bias},
-            ref_${data_out}_${data_out}, ${dim_im_out_y}
+            out_ptr, ${dim_im_out_y}
         );
         
     }
🧹 Nitpick comments (1)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1)

18-19: Remove duplicate comment.

Line 19 repeats the comment from line 18.

Apply this diff:

 
         # input/output tensors
-        # input/output tensors
         data_in = ctxt.lookup(operatorRepresentation["data_in"])
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55cb3bf and 0e1927d.

📒 Files selected for processing (8)
  • Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
  • TargetLibraries/Generic/inc/kernel/BatchNorm.h (1 hunks)
  • TargetLibraries/Generic/inc/kernel/ConvTranspose1d_fp32.h (1 hunks)
  • TargetLibraries/Generic/inc/kernel/MaxPool1d.h (1 hunks)
  • TargetLibraries/Generic/src/BatchNorm_fp32.c (1 hunks)
  • TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (1 hunks)
  • TargetLibraries/Generic/src/MaxPool1D_fp32.c (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • TargetLibraries/Generic/inc/kernel/MaxPool1d.h
  • TargetLibraries/Generic/src/MaxPool1D_fp32.c
  • TargetLibraries/Generic/src/BatchNorm_fp32.c
🧰 Additional context used
🧬 Code graph analysis (4)
Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (87-229)
TargetLibraries/Generic/inc/kernel/ConvTranspose1d_fp32.h (1)
TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (1)
  • ConvTranspose1d_fp32 (7-50)
TargetLibraries/Generic/inc/kernel/BatchNorm.h (1)
TargetLibraries/Generic/src/BatchNorm_fp32.c (1)
  • BatchNorm_fp32 (7-28)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (3)
Deeploy/DeeployTypes.py (4)
  • NetworkContext (564-1076)
  • NodeTemplate (87-229)
  • alignToContext (119-139)
  • lookup (776-808)
Deeploy/Targets/Generic/Templates/ConvTemplate.py (1)
  • alignToContext (15-28)
Deeploy/AbstractDataTypes.py (1)
  • nLevels (194-195)
🔇 Additional comments (2)
Deeploy/Targets/Generic/Templates/BatchNormalizationTemplate.py (1)

7-15: LGTM! Template follows established patterns.

The BatchNormalization template is correctly structured and follows the same pattern as other kernel templates in the codebase. The parameter mapping to BatchNorm_fp32 is accurate.

TargetLibraries/Generic/src/ConvTranspose1d_fp32.c (1)

7-50: LGTM! Transposed convolution implementation is correct.

The implementation correctly handles:

  • Output initialization to zero
  • Proper tensor indexing for [C_in, W_in] input, [C_in, C_out, K] weights, and [C_out, W_out] output
  • Transposed convolution formula w_out = w_in * stride + k
  • Bounds checking for output width
  • Optional bias addition per output channel

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Deeploy/Targets/Generic/Parsers.py (1)

2193-2211: Inconsistent has_bias representation between 1D and 2D parsers.

The 1D parser uses integers (0/1) for has_bias while the 2D parser at lines 2282-2287 uses strings ("true"/"false"). This inconsistency may cause issues in template rendering or binding logic.

Consider standardizing to match the 2D parser:

             if len(node.inputs) > 2:
                 inputs.append("bias")
-                self.operatorRepresentation["has_bias"] = 1
+                self.operatorRepresentation["has_bias"] = "true"
             else:
-                self.operatorRepresentation["has_bias"] = 0
+                self.operatorRepresentation["has_bias"] = "false"
                 self.operatorRepresentation["bias"] = "NULL"
♻️ Duplicate comments (3)
Deeploy/Targets/Generic/Parsers.py (3)

2627-2664: Respect channels_first parameter and validate input rank.

The channels_first parameter is ignored, and the parser unconditionally assumes [N, C, W] layout. This will produce incorrect results for channels-last data and fail on non-3D inputs.

Based on learnings

Apply this diff to validate rank and respect layout:

     def parseNodeCtxt(self, ctxt, node: gs.Node, channels_first: bool = True):
         inputs = ['data_in', 'scale', 'bias', 'mean', 'variance']
         outputs = ['data_out']
 
         for idx, inputNode in enumerate(node.inputs[:5]):
             self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name
 
         # Output (Y)
         self.operatorRepresentation[outputs[0]] = ctxt.lookup(node.outputs[0].name).name
 
         input_shape = ctxt.lookup(node.inputs[0].name).shape
+        
+        # Validate rank
+        if len(input_shape) != 3:
+            return ctxt, False
+        
         # Save input shape information
         self.operatorRepresentation['batch_size'] = input_shape[0]
-        self.operatorRepresentation['channel_size'] = input_shape[1]
-        self.operatorRepresentation['window_size'] = input_shape[2]
+        if channels_first:
+            self.operatorRepresentation['channel_size'] = input_shape[1]
+            self.operatorRepresentation['window_size'] = input_shape[2]
+        else:
+            self.operatorRepresentation['channel_size'] = input_shape[2]
+            self.operatorRepresentation['window_size'] = input_shape[1]
 
         return ctxt, True

2692-2742: Respect channels_first parameter and remove unused variable.

The channels_first parameter is unused, and dimension extraction assumes channels-first layout. Additionally, kernel_shape_y is assigned but never used.

Based on learnings

Apply this diff to fix the issues:

     def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True):
         # Register buffer names for codegen
         self.operatorRepresentation['data_in'] = node.inputs[0].name
         self.operatorRepresentation['weight'] = node.inputs[1].name
         self.operatorRepresentation['data_out'] = node.outputs[0].name
         if len(node.inputs) == 3:
             self.operatorRepresentation['bias'] = node.inputs[2].name
             self.operatorRepresentation['has_bias'] = True
         else:
             self.operatorRepresentation['has_bias'] = False
-        # Get output shape from context
+        
         data_out = ctxt.lookup(node.outputs[0].name)
+        data_in = ctxt.lookup(node.inputs[0].name)
         out_shape = data_out.shape
+        in_shape = data_in.shape
+        
+        # Extract dimensions respecting channels_first
         if len(out_shape) == 3:
-            self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
+            if channels_first:
+                self.operatorRepresentation['ch_im_out'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+            else:
+                self.operatorRepresentation['ch_im_out'] = out_shape[2]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[1]
         elif len(out_shape) == 4:
-            self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
-            self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
+            if channels_first:
+                self.operatorRepresentation['ch_im_out'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
+            else:
+                self.operatorRepresentation['ch_im_out'] = out_shape[3]
+                self.operatorRepresentation['dim_im_out_x'] = out_shape[1]
+                self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
 
         stride_x, stride_y = 1, 1
         if "strides" in node.attrs:
             stride_y = node.attrs["strides"][0]
             stride_x = node.attrs["strides"][1] if len(node.attrs["strides"]) > 1 else stride_y
         self.operatorRepresentation["stride_y"] = stride_y
         self.operatorRepresentation["stride_x"] = stride_x
 
-        if "kernel_shape" in node.attrs:
-            kernel_shape = node.attrs["kernel_shape"]
-            kernel_shape_x = kernel_shape[0]
-            # For 2D, kernel_shape may have two elements
-            kernel_shape_y = kernel_shape[1] if len(kernel_shape) > 1 else kernel_shape_x
-        else:
-            kernel_shape_x = 1
-            kernel_shape_y = 1
-
-        data_in = ctxt.lookup(node.inputs[0].name)
-        data_out = ctxt.lookup(node.outputs[0].name)
-        in_shape = data_in.shape
-        out_shape = data_out.shape
-
-        self.operatorRepresentation['ch_im_in'] = in_shape[1]
-        self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
-        self.operatorRepresentation['ch_im_out'] = out_shape[1]
-        self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+        # Extract input dimensions respecting channels_first
+        if len(in_shape) == 3:
+            if channels_first:
+                self.operatorRepresentation['ch_im_in'] = in_shape[1]
+                self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
+            else:
+                self.operatorRepresentation['ch_im_in'] = in_shape[2]
+                self.operatorRepresentation['dim_im_in_y'] = in_shape[1]
+        elif len(in_shape) == 4:
+            if channels_first:
+                self.operatorRepresentation['ch_im_in'] = in_shape[1]
+            else:
+                self.operatorRepresentation['ch_im_in'] = in_shape[3]
 
         self.operatorRepresentation[
             'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
         self.operatorRepresentation[
             'batchOffsetOut'] = self.operatorRepresentation['ch_im_out'] * self.operatorRepresentation['dim_im_out_y']
         return ctxt, True

2744-2790: Critical: Fix incorrect return values in parseNode and parseNodeCtxt.

Two critical bugs will cause invalid configurations to pass and lose context updates:

  1. Line 2768: parseNode returns wellFormed instead of ret, allowing invalid 1D configurations to pass even when the 1D constraint checks fail.
  2. Line 2790: parseNodeCtxt unconditionally returns (ctxt, True), discarding the updated newCtxt and ignoring the ret flag. This loses context updates and allows invalid nodes to pass.

Based on learnings

Apply this diff to fix both bugs:

     def parseNode(self, node: gs.Node) -> bool:
         # 1D ConvTranspose expects 3D input/output and 3D weight
         wellFormed = super().parseNode(node)
         ret = False
         if wellFormed:
             ret = all([
                 # Make sure strides are 2D
                 len(node.attrs['strides']) == 1,
                 len(node.attrs['pads']) == 2,
                 len(node.attrs['dilations']) == 1,
             ])
         if ret:
 
             self.operatorRepresentation['kernel_shape'] = node.attrs['kernel_shape']
             self.operatorRepresentation['dim_kernel_y'] = int(self.operatorRepresentation['kernel_shape'][0])
             self.operatorRepresentation['dilation_y'] = int(self.operatorRepresentation['dilations'][0])
             self.operatorRepresentation['padding_y'] = int(self.operatorRepresentation['pads'][0])
             self.operatorRepresentation['stride_y'] = int(self.operatorRepresentation['strides'][0])
 
-        return wellFormed
+        return ret
 
     def parseNodeCtxt(self,
                       ctxt: NetworkContext,
                       node: gs.Node,
                       channels_first: bool = True) -> Tuple[NetworkContext, bool]:
 
         newCtxt, ret = super().parseNodeCtxt(ctxt, node, channels_first)
 
         if ret:
             data_in = newCtxt.lookup(node.inputs[0].name)
             data_out = newCtxt.lookup(node.outputs[0].name)
             in_shape = data_in.shape
             out_shape = data_out.shape
+            
+            # Validate 3D tensors
+            if len(in_shape) != 3 or len(out_shape) != 3:
+                return ctxt, False
+            
             self.operatorRepresentation['ch_im_in'] = in_shape[1]
             self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
             self.operatorRepresentation['ch_im_out'] = out_shape[1]
             self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
             self.operatorRepresentation[
                 "batchOffsetIn"] = self.operatorRepresentation["ch_im_in"] * self.operatorRepresentation["dim_im_in_y"]
             self.operatorRepresentation["batchOffsetOut"] = self.operatorRepresentation[
                 "ch_im_out"] * self.operatorRepresentation["dim_im_out_y"]
-        return ctxt, True
+            return newCtxt, True
+        return ctxt, False
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0e1927d and 3ab0478.

📒 Files selected for processing (1)
  • Deeploy/Targets/Generic/Parsers.py (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1089-1104)
  • parseNodeCtxt (1107-1132)
  • lookup (776-808)
  • inputs (2559-2576)
  • NodeParser (1079-1254)
  • outputs (2578-2595)
  • NetworkContext (564-1076)
🪛 Ruff (0.14.1)
Deeploy/Targets/Generic/Parsers.py

346-346: Do not catch blind exception: Exception

(BLE001)


346-346: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2204-2205: Avoid specifying long messages outside the exception class

(TRY003)


2647-2647: Unused method argument: channels_first

(ARG002)


2692-2692: Unused method argument: channels_first

(ARG002)


2725-2725: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

🔇 Additional comments (2)
Deeploy/Targets/Generic/Parsers.py (2)

224-264: LGTM: MaxPool1DParser correctly implements 1D pooling.

The parser properly validates 1D constraints (pads length 2, kernel/strides length 1), respects the channels_first parameter when extracting dimensions, and correctly returns the updated context.


1390-1393: LGTM: Batch offset calculations are correctly added.

The batch offset calculations for 1D convolution are properly computed as the product of channel and spatial dimensions, which is necessary for batch processing.

@Xeratec Xeratec moved this from In progress to In review in Deeploy Oct 23, 2025
Copy link
Member

@Xeratec Xeratec left a comment

Choose a reason for hiding this comment

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

Some of the CodeRabbit remarks are valid. I can implement the remaining changes and merge once the tests pass.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (5)
Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1)

56-93: 1D padding template structure looks good; zero-fill bug is already flagged.

The 1D template correctly mirrors the 2D approach with simplified single-dimension offsets and NCHW/NHWC branches. The zero-fill issue (always using 0 instead of ${value}) was already raised in prior review comments.

Deeploy/Targets/Generic/Parsers.py (3)

2627-2664: Validate input rank and respect channels_first parameter.

The parser unconditionally indexes shape[0], [1], [2] without checking the tensor rank and ignores the channels_first parameter.

Apply this diff:

 def parseNodeCtxt(self, ctxt, node: gs.Node, channels_first: bool = True):
     inputs = ['data_in', 'scale', 'bias', 'mean', 'variance']
     outputs = ['data_out']

     for idx, inputNode in enumerate(node.inputs[:5]):
         self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name

     # Output (Y)
     self.operatorRepresentation[outputs[0]] = ctxt.lookup(node.outputs[0].name).name

     input_shape = ctxt.lookup(node.inputs[0].name).shape
-    # Save input shape information
+    # Validate 3D input
+    if len(input_shape) != 3:
+        return ctxt, False
+    
+    # Extract dimensions based on layout
     self.operatorRepresentation['batch_size'] = input_shape[0]
-    self.operatorRepresentation['channel_size'] = input_shape[1]
-    self.operatorRepresentation['window_size'] = input_shape[2]
+    if channels_first:
+        self.operatorRepresentation['channel_size'] = input_shape[1]
+        self.operatorRepresentation['window_size'] = input_shape[2]
+    else:
+        self.operatorRepresentation['channel_size'] = input_shape[2]
+        self.operatorRepresentation['window_size'] = input_shape[1]

     return ctxt, True

343-347: Catch specific exceptions instead of bare Exception.

Catching Exception is too broad and can mask unexpected errors. Catch only the expected conversion errors.

Apply this diff:

     try:
         self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
-    except Exception as e:
+    except (ValueError, TypeError):
         self.operatorRepresentation['pads'] = node.attrs['pads']

2692-2741: Honor channels_first and remove unused kernel_shape_y.

The parseNodeCtxt method ignores the channels_first parameter and unconditionally assumes NCW/NCHW layout. Additionally, kernel_shape_y (line 2722) is computed but never used.

Apply this diff to respect layout:

 def parseNodeCtxt(self, ctxt: NetworkContext, node: gs.Node, channels_first: bool = True):
     # Register buffer names for codegen
     self.operatorRepresentation['data_in'] = node.inputs[0].name
     self.operatorRepresentation['weight'] = node.inputs[1].name
     self.operatorRepresentation['data_out'] = node.outputs[0].name
     if len(node.inputs) == 3:
         self.operatorRepresentation['bias'] = node.inputs[2].name
         self.operatorRepresentation['has_bias'] = True
     else:
         self.operatorRepresentation['has_bias'] = False
-    # Get output shape from context
+    
     data_out = ctxt.lookup(node.outputs[0].name)
     out_shape = data_out.shape
+    
+    # Extract output dimensions based on layout
     if len(out_shape) == 3:
-        self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
+        if channels_first:
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+        else:
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[1]
     elif len(out_shape) == 4:
-        self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
-        self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
+        if channels_first:
+            self.operatorRepresentation['dim_im_out_x'] = out_shape[2]
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[3]
+        else:
+            self.operatorRepresentation['dim_im_out_x'] = out_shape[1]
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[2]

     stride_x, stride_y = 1, 1
     if "strides" in node.attrs:
         stride_y = node.attrs["strides"][0]
         stride_x = node.attrs["strides"][1] if len(node.attrs["strides"]) > 1 else stride_y
     self.operatorRepresentation["stride_y"] = stride_y
     self.operatorRepresentation["stride_x"] = stride_x

-    if "kernel_shape" in node.attrs:
-        kernel_shape = node.attrs["kernel_shape"]
-        kernel_shape_x = kernel_shape[0]
-        # For 2D, kernel_shape may have two elements
-        kernel_shape_y = kernel_shape[1] if len(kernel_shape) > 1 else kernel_shape_x
-    else:
-        kernel_shape_x = 1
-        kernel_shape_y = 1
-
     data_in = ctxt.lookup(node.inputs[0].name)
     data_out = ctxt.lookup(node.outputs[0].name)
     in_shape = data_in.shape
     out_shape = data_out.shape

-    self.operatorRepresentation['ch_im_in'] = in_shape[1]
-    self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
-    self.operatorRepresentation['ch_im_out'] = out_shape[1]
-    self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+    # Extract input/output channels and dims based on layout
+    if len(in_shape) == 3:
+        if channels_first:
+            self.operatorRepresentation['ch_im_in'] = in_shape[1]
+            self.operatorRepresentation['dim_im_in_y'] = in_shape[2]
+        else:
+            self.operatorRepresentation['ch_im_in'] = in_shape[2]
+            self.operatorRepresentation['dim_im_in_y'] = in_shape[1]
+    elif len(in_shape) == 4:
+        if channels_first:
+            self.operatorRepresentation['ch_im_in'] = in_shape[1]
+        else:
+            self.operatorRepresentation['ch_im_in'] = in_shape[3]
+    
+    if len(out_shape) == 3:
+        if channels_first:
+            self.operatorRepresentation['ch_im_out'] = out_shape[1]
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[2]
+        else:
+            self.operatorRepresentation['ch_im_out'] = out_shape[2]
+            self.operatorRepresentation['dim_im_out_y'] = out_shape[1]
+    elif len(out_shape) == 4:
+        if channels_first:
+            self.operatorRepresentation['ch_im_out'] = out_shape[1]
+        else:
+            self.operatorRepresentation['ch_im_out'] = out_shape[3]

     self.operatorRepresentation[
         'batchOffsetIn'] = self.operatorRepresentation['ch_im_in'] * self.operatorRepresentation['dim_im_in_y']
     self.operatorRepresentation[
         'batchOffsetOut'] = self.operatorRepresentation['ch_im_out'] * self.operatorRepresentation['dim_im_out_y']
     return ctxt, True
Deeploy/Targets/Generic/Layers.py (1)

665-681: Replace Italian comments and handle missing dimension keys.

Lines 669 and 675 contain Italian comments. Also, the dimension key logic should handle cases where only one spatial dimension key is present.

Apply this diff:

     groups = opRep.get('group', 1)
-    kernel_shape = np.prod(opRep['kernel_shape'])  # es. [3, 3] -> 9
+    kernel_shape = np.prod(opRep['kernel_shape'])  # e.g., [3, 3] -> 9
     ch_in = opRep['ch_im_in']
     ch_out = opRep['ch_im_out']

     opsPerPx = int(kernel_shape * ch_in * ch_out / groups) * 2

-    # ConvTranspose upscales spatial dims, quindi num pixel viene da output
-    if 'dim_im_out_y' in opRep:
-        numPx = opRep['dim_im_out_x'] * opRep['dim_im_out_y']
-    else:
-        numPx = opRep['dim_im_out_x']
+    # ConvTranspose upscales spatial dims; use output pixel count
+    if 'dim_im_out_x' in opRep and 'dim_im_out_y' in opRep:
+        numPx = opRep['dim_im_out_x'] * opRep['dim_im_out_y']
+    elif 'dim_im_out_x' in opRep:
+        numPx = opRep['dim_im_out_x']
+    elif 'dim_im_out_y' in opRep:
+        numPx = opRep['dim_im_out_y']
+    else:
+        raise KeyError("ConvTransposeLayer.computeOps: missing 'dim_im_out_x' or 'dim_im_out_y'")

     return numPx * opsPerPx
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0753ea and 2709d18.

📒 Files selected for processing (7)
  • Deeploy/Targets/Generic/Layers.py (1 hunks)
  • Deeploy/Targets/Generic/Parsers.py (6 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatConvTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py (1 hunks)
  • Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1 hunks)
  • Deeploy/Targets/MemPool/Platform.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Deeploy/Targets/Generic/Templates/FloatConvTemplate.py
  • Deeploy/Targets/Generic/Templates/FloatMaxPoolTemplate.py
🧰 Additional context used
🧬 Code graph analysis (5)
Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (3)
Deeploy/DeeployTypes.py (4)
  • NetworkContext (564-1076)
  • NodeTemplate (87-229)
  • alignToContext (119-139)
  • lookup (776-808)
Deeploy/Targets/Generic/Templates/ConvTemplate.py (1)
  • alignToContext (15-28)
Deeploy/AbstractDataTypes.py (1)
  • nLevels (194-195)
Deeploy/Targets/Generic/Layers.py (1)
Deeploy/DeeployTypes.py (4)
  • ONNXLayer (1875-2203)
  • NodeMapper (1716-1872)
  • computeOps (1891-1896)
  • computeShapes (1900-1922)
Deeploy/Targets/Generic/Templates/FloatPadTemplate.py (1)
Deeploy/DeeployTypes.py (1)
  • NodeTemplate (87-229)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1089-1104)
  • parseNodeCtxt (1107-1132)
  • lookup (776-808)
  • inputs (2559-2576)
  • NodeParser (1079-1254)
  • outputs (2578-2595)
  • NetworkContext (564-1076)
Deeploy/Targets/MemPool/Platform.py (2)
Deeploy/DeeployTypes.py (1)
  • NodeMapper (1716-1872)
Deeploy/Targets/Generic/Parsers.py (1)
  • GenericConv1DParser (2165-2211)
🪛 Ruff (0.14.1)
Deeploy/Targets/Generic/Parsers.py

346-346: Do not catch blind exception: Exception

(BLE001)


346-346: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2204-2205: Avoid specifying long messages outside the exception class

(TRY003)


2647-2647: Unused method argument: channels_first

(ARG002)


2692-2692: Unused method argument: channels_first

(ARG002)


2725-2725: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

🔇 Additional comments (6)
Deeploy/Targets/MemPool/Platform.py (1)

40-40: LGTM: Binding passed correctly.

BasicConv1DBindings is correctly passed directly to NodeMapper without extra list wrapping, matching the pattern for 2D bindings.

Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1)

61-85: Batch loop correctly advances pointers.

The loop increments both ref_${data_out}_${data_in} and ref_${data_out}_${data_out} by their respective batch offsets (lines 81-82) after each kernel call, ensuring all batch slices are processed correctly.

Deeploy/Targets/Generic/Layers.py (1)

623-634: LGTM: BatchNormalizationLayer implementation is clear.

The 5-ops-per-element model (sub, mul, add, sqrt, div) is reasonable for batch normalization.

Deeploy/Targets/Generic/Parsers.py (3)

224-264: LGTM: MaxPool1DParser correctly validates 1D constraints.

The parser properly checks for 1D-specific attributes (single-element kernel/stride, two-element pads) and respects channels_first when extracting dimensions.


2193-2211: LGTM: Bias handling and bounds checking are correct.

The code properly detects optional bias, sets has_bias flag, and includes defensive bounds checking before indexing inputs.


2744-2791: LGTM: ConvTranspose1DParser correctly validates 1D constraints.

The parser properly combines superclass validation with 1D-specific checks (single-element strides/dilations, two-element pads) and returns the combined result.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
Deeploy/Targets/Generic/Parsers.py (3)

343-347: Catch specific exception types instead of blind Exception.

This issue was already identified in a previous review but remains unaddressed. The try-except block catches a generic Exception and assigns it to an unused variable, which can mask unexpected errors.

Apply this diff to improve exception handling:

-            try:
-                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
-            except Exception as e:
-                self.operatorRepresentation['pads'] = node.attrs['pads']
+            try:
+                self.operatorRepresentation['pads'] = [int(p) for p in node.attrs['pads']]
+            except (ValueError, TypeError):
+                self.operatorRepresentation['pads'] = node.attrs['pads']

2627-2664: BatchNorm: respect channels_first and validate rank.

This issue was already identified in a previous review but remains unaddressed. The channels_first parameter is ignored, and shapes are assumed to be [N, C, W] without validation or layout flexibility.

Apply this diff to handle both layouts and validate rank:

 class BatchNormParser(NodeParser):
 
     def __init__(self):
         super().__init__()
 
     def parseNode(self, node: gs.Node) -> bool:
         # Verify the attributes (epsilon is mandatory, momentum and training_mode  are optional)
         if 'epsilon' not in node.attrs:
             return False
         # Common Inputs: 5 (X, scale, B, mean, var)
         if len(node.inputs) < 5:
             return False
 
         # Save the attributes, default values are provided if not present
         self.operatorRepresentation['epsilon'] = node.attrs.get('epsilon', 1e-5)
         self.operatorRepresentation['momentum'] = node.attrs.get('momentum', 0.9)
         self.operatorRepresentation['training_mode'] = node.attrs.get('training_mode', 0)
 
         return True
 
     def parseNodeCtxt(self, ctxt, node: gs.Node, channels_first: bool = True):
         inputs = ['data_in', 'scale', 'bias', 'mean', 'variance']
         outputs = ['data_out']
 
         for idx, inputNode in enumerate(node.inputs[:5]):
             self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name
 
         # Output (Y)
         self.operatorRepresentation[outputs[0]] = ctxt.lookup(node.outputs[0].name).name
 
         input_shape = ctxt.lookup(node.inputs[0].name).shape
+        # Validate 3D input
+        if len(input_shape) != 3:
+            return ctxt, False
         # Save input shape information
         self.operatorRepresentation['batch_size'] = input_shape[0]
-        self.operatorRepresentation['channel_size'] = input_shape[1]
-        self.operatorRepresentation['window_size'] = input_shape[2]
+        if channels_first:
+            self.operatorRepresentation['channel_size'] = input_shape[1]
+            self.operatorRepresentation['window_size'] = input_shape[2]
+        else:
+            self.operatorRepresentation['channel_size'] = input_shape[2]
+            self.operatorRepresentation['window_size'] = input_shape[1]
 
         return ctxt, True

Based on learnings.


2666-2742: ConvTranspose: honor channels_first and remove unused variables.

This issue was already identified in a previous review but remains unaddressed. The channels_first parameter is ignored, kernel_shape_y is computed but unused, and shape extraction assumes fixed indices without respecting layout.

Key issues to address:

  • Extract channel and spatial dimensions based on channels_first for both 1D (3D tensors) and 2D (4D tensors)
  • Remove unused kernel_shape_y computation (line 2722) or use it appropriately
  • Handle both channels_first=True (NCHW) and channels_first=False (NHWC) layouts

Based on learnings.

🧹 Nitpick comments (1)
Deeploy/Targets/Generic/Parsers.py (1)

2193-2207: Consider simplifying the error message format.

The bias handling logic is correct, but the IndexError message could be more concise by moving the detailed explanation to a separate comment.

             for idx, inputNode in enumerate(node.inputs):
                 if idx >= len(inputs):
-                    raise IndexError(
-                        f"Index {idx} out of range for inputs of length {len(inputs)} in node {inputNode.name}")
+                    raise IndexError(f"Input index {idx} exceeds expected inputs ({len(inputs)})")
 
                 self.operatorRepresentation[inputs[idx]] = ctxt.lookup(inputNode.name).name
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2709d18 and 8fc7cc6.

📒 Files selected for processing (2)
  • Deeploy/Targets/Generic/Parsers.py (6 hunks)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Deeploy/Targets/Generic/Templates/ConvTransposeTemplate.py
🧰 Additional context used
🧬 Code graph analysis (1)
Deeploy/Targets/Generic/Parsers.py (1)
Deeploy/DeeployTypes.py (7)
  • parseNode (1089-1104)
  • parseNodeCtxt (1107-1132)
  • lookup (776-808)
  • inputs (2559-2576)
  • NodeParser (1079-1254)
  • outputs (2578-2595)
  • NetworkContext (564-1076)
🪛 Ruff (0.14.1)
Deeploy/Targets/Generic/Parsers.py

346-346: Do not catch blind exception: Exception

(BLE001)


346-346: Local variable e is assigned to but never used

Remove assignment to unused variable e

(F841)


2204-2205: Avoid specifying long messages outside the exception class

(TRY003)


2647-2647: Unused method argument: channels_first

(ARG002)


2692-2692: Unused method argument: channels_first

(ARG002)


2725-2725: Local variable kernel_shape_y is assigned to but never used

Remove assignment to unused variable kernel_shape_y

(F841)

🔇 Additional comments (2)
Deeploy/Targets/Generic/Parsers.py (2)

224-264: LGTM! Well-structured 1D MaxPool parser.

The implementation correctly validates 1D-specific constraints, respects the channels_first parameter in both parseNode and parseNodeCtxt, and properly validates 3D tensor shapes.


1390-1393: LGTM! Batch offset calculations are correct.

The batch offset computations (ch_im_in * dim_im_in_y and ch_im_out * dim_im_out_y) are appropriate for 1D convolution and consistent with the pattern used elsewhere (e.g., ConvTranspose1DParser).

@Xeratec Xeratec merged commit dc111be into pulp-platform:devel Oct 24, 2025
134 checks passed
@github-project-automation github-project-automation bot moved this from In review to Done in Deeploy Oct 24, 2025
@Xeratec Xeratec mentioned this pull request Oct 24, 2025
5 tasks
This was referenced Oct 27, 2025
This was referenced Feb 5, 2026
Victor-Jung added a commit that referenced this pull request Feb 5, 2026
This release includes improvements to the tiling and DMA code
generation, new networks and operators, improved CI workflows, migration
to PyTest, and support for PyPi package releases.

Note: Since the release tag references the Docker container tagged with
the release tag (ghcr.io/pulp-platform/deeploy:v0.2.1), the CI will
initially fail. The Deeploy Docker image must be built after the release
PR is merged and the CI restarted.

### List of Pull Requests
- PyPi Package Deployment + Remove Banshee Dept
[#154](#154)
- PyTest Migration
[#144](#144)
- Update submodule `pulp-nn-mixed`
[#145](#145)
- Improve Profiling
[#138](#138)
- FP32 ReduceMean operator improvement
[#137](#137)
- Support for RMSNorm (Pow and Sqrt operators)
[#136](#136)
- Demo TinyViT compatibility with tiled Siracusa
[#124](#124)
- TinyViT on non-tiled Siracusa
[#117](#117)
- Support Fully Asynchronous DMAs
[#114](#114)
- Disallow shape inference
[#128](#128)
- Remove memory-aware node bindings
[#123](#123)
- Fix missing const's layout transformation and refactor NCHWtoNHWC
passes [#122](#122)
- Fix aliasing [#125](#125)
- Support for 1D Autoencoder
[#98](#98)
- Refactor Logging for Improved Debugging
[#115](#115)
- Add reuse-tool as an SPDX license header linter
[#113](#113)
- Bug fixes, API Cleanup and Reduce Compiler Warning on PULP
[#112](#112)
- Fix PULP GEMM `batch` serialization
[#109](#109)
- Split CI Workflows by Platform and Task, Improve Formatting and
Linting Reliability
[#108](#108)
- Refactor tiling code generation
[#105](#105)
- Change order of typeMatching entries
[#68](#68)
- Node Mangling to avoid duplication
[#93](#93)
- Prepare Post v0.2.0 Release
[#104](#104)
- Use Docker digests instead of arch-specific tags
[#106](#106)
- Fix `Unsqueeze` Op. when using ONNX opset 13 or higher (from attribute
to input) [#119](#119)
- Fix bias hoisting in generic GEMM with no bias
[#126](#126)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature Addition of new features

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants