From 5008e04b76a86f5bb65749decae90344ab8a5872 Mon Sep 17 00:00:00 2001 From: Sruthi Srinivasan Date: Tue, 15 Sep 2026 09:41:30 -0700 Subject: [PATCH 1/2] [RPP] normalize HOST: write 3D output for non-NHWC same-layout tensors The F32 3D path computed mean/stddev but only dispatched a normalize write for NHWC layouts (avx_axis3 / nontoggle / axis3-toggle). For a same-layout non-NHWC tensor (e.g. NCHW) none of those branches fired, so the destination was left at its 0.0 pre-fill and the op returned all zeros while reporting RPP_SUCCESS. Add a same-layout fallback that uses normalize_3D_tensor_nontoggle, which steps outer dims by the descriptor strides and the innermost contiguously and is therefore layout-agnostic for dense tensors. Fixes the F32 3D "writes zeros" cases (cms2/cms3 3D go green; cms0/cms1 3D now write real values, their residual failures belong to the separate per-sample-params and supplied-stddev issues). The 4D / generic-ND compute-path defect in the same ticket is a distinct root cause and is not addressed here. --- projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp b/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp index 22416d0b1476..bf40528ebf7e 100644 --- a/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp +++ b/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp @@ -667,6 +667,13 @@ RppStatus normalize_f32_f32_host_tensor(Rpp32f* srcPtr, RpptGenericDescPtr srcGe normalize_3D_tensor_axis3_toggle(srcPtrChannel, srcGenericDescPtr, dstPtrTemp, dstGenericDescPtr, meanTensor, stdDevTensor, shift, paramStride, length); + else if (srcGenericDescPtr->layout == dstGenericDescPtr->layout) + // Same-layout 3D that is not NHWC (e.g. NCHW): the non-toggle writer steps outer + // dims by the descriptor strides and the innermost contiguously, so it is + // layout-agnostic for dense tensors. Without this the output is left zero-filled. + normalize_3D_tensor_nontoggle(srcPtrChannel, srcGenericDescPtr, dstPtrTemp, + dstGenericDescPtr, meanTensor, stdDevTensor, shift, + paramStride, length); } else // Handle any other ND tensor is passed to kernel { // Compute length of input tensors as they differ based on axisMask and tensorDims From b78a76053dffde1e1f2280cdc9c11052145bfaa9 Mon Sep 17 00:00:00 2001 From: Sruthi Srinivasan Date: Tue, 15 Sep 2026 10:15:13 -0700 Subject: [PATCH 2/2] [RPP] normalize HOST: zero-init mean/stddev before generic-ND reduction compute_ND_mean and compute_ND_stddev accumulate into meanTensor / stdDevTensor with +=, but the generic-ND path never zeroed those buffers first. They still hold the caller-supplied mean/stddev values (the API takes one buffer that is both input and scratch), so the reductions were computed on top of that data: the variance in particular was inflated by the pre-existing stddev, e.g. 1.5 / sqrt((1.0 + sumsq)/N) instead of 1.5 / sqrt(sumsq/N). The 2D and 3D helpers already zero their accumulators (meanPtr[i] = 0 / stdDevPtr[i] = 0) and HIP hipMemsetAsync's the tensors; only the ND path was missing it. Zero meanTensor and stdDevTensor over [0, size) before each compute_ND_* call, in both the f32/f32 and generic host entry points. The contamination shrinks relative to the true sum as more axes are reduced, which is why the error was largest for single-axis masks and vanished at full reduction. Fixes the generic-ND compute cases in the normalize suite (F32 3D/4D and F16 2D/3D/4D partial-mask cms2/cms3), 25 cases in total, with no regressions and HIP unchanged. --- .../rpp/src/modules/tensor/cpu/kernel/normalize.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp b/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp index bf40528ebf7e..3bfa99fef252 100644 --- a/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp +++ b/projects/rpp/src/modules/tensor/cpu/kernel/normalize.cpp @@ -702,6 +702,10 @@ RppStatus normalize_f32_f32_host_tensor(Rpp32f* srcPtr, RpptGenericDescPtr srcGe if (computeMeanStddev & 1) // Check if mean is to be computed internally { + // compute_ND_mean accumulates with +=, so the destination must start at zero. + // Unlike the 2D/3D helpers it does not self-zero, and the buffer still holds the + // caller-supplied mean here, which would otherwise corrupt the reduction. + for (int i = 0; i < size; i++) meanTensor[i] = 0.0f; compute_ND_mean(srcPtrChannel, meanTensor, newDims, srcStride, newAxis, newTensorDims, 0, 0, size, 0, lastNormAxis); Rpp32f normFactor = 1.0 / totalElements; @@ -709,6 +713,8 @@ RppStatus normalize_f32_f32_host_tensor(Rpp32f* srcPtr, RpptGenericDescPtr srcGe } if (computeMeanStddev & 2) // Check if stddev is to be computed internally { + // compute_ND_stddev also accumulates with +=; zero it first (see mean above). + for (int i = 0; i < size; i++) stdDevTensor[i] = 0.0f; compute_ND_stddev(srcPtrChannel, meanTensor, stdDevTensor, newDims, srcStride, newAxis, newTensorDims, 0, 0, size, 0, lastNormAxis); Rpp32f normFactor = (Rpp32f)(1.0 / totalElements); @@ -801,6 +807,10 @@ RppStatus normalize_generic_host_tensor(T1* srcPtr, RpptGenericDescPtr srcGeneri if (computeMeanStddev & 1) // Check if mean is to be computed internally { + // compute_ND_mean accumulates with +=, so the destination must start at zero. Unlike + // the 2D/3D helpers it does not self-zero, and the buffer still holds the + // caller-supplied mean here, which would otherwise corrupt the reduction. + for (int i = 0; i < size; i++) meanTensor[i] = 0.0f; compute_ND_mean(srcPtrChannel, meanTensor, newDims, srcStride, newAxis, newTensorDims, 0, 0, size, 0, lastNormAxis); Rpp32f normFactor = 1.0 / totalElements; @@ -808,6 +818,8 @@ RppStatus normalize_generic_host_tensor(T1* srcPtr, RpptGenericDescPtr srcGeneri } if (computeMeanStddev & 2) // Check if stddev is to be computed internally { + // compute_ND_stddev also accumulates with +=; zero it first (see mean above). + for (int i = 0; i < size; i++) stdDevTensor[i] = 0.0f; compute_ND_stddev(srcPtrChannel, meanTensor, stdDevTensor, newDims, srcStride, newAxis, newTensorDims, 0, 0, size, 0, lastNormAxis); Rpp32f normFactor = (Rpp32f)(1.0 / totalElements);