From 880c2d6bb61b08db49bb5d9ac96e18fc796fbb7e Mon Sep 17 00:00:00 2001 From: Brian Harrison Date: Sat, 28 Feb 2026 00:33:32 +0000 Subject: [PATCH 1/2] [HIPDNN] Add per-operation tensor dimension ordering documentation Document the expected tensor dimension ordering for each operation type rather than a blanket "always NCHW" convention. Each operation family has its own dimension semantics: - Convolution: (N, C, H, W) / (K, C/groups, R, S) - BatchNorm: (N, C, H, W) with per-channel params (1, C, 1, 1) - LayerNorm: (N, ...) with feature-matching scale/bias - Matmul: (...batch, M, K) @ (...batch, K, N) - Pointwise: dimension-agnostic with NumPy broadcasting Adds Tensor Shapes sections to operation attribute Doxygen docs and a comprehensive per-operation reference in the Porting Guide. Co-Authored-By: Claude Opus 4.6 --- .../utilities/ShapeUtilities.hpp | 35 +++++++-- .../hipdnn_data_sdk/utilities/Tensor.hpp | 29 ++++++-- .../docs/OperationSupport-ReferenceImpl.md | 6 ++ projects/hipdnn/docs/PortingGuide.md | 73 +++++++++++++++++++ .../attributes/BatchnormAttributes.hpp | 8 +- .../attributes/ConvolutionFpropAttributes.hpp | 5 ++ .../attributes/LayernormAttributes.hpp | 6 ++ .../attributes/MatmulAttributes.hpp | 7 ++ .../attributes/PointwiseAttributes.hpp | 5 ++ .../attributes/TensorAttributes.hpp | 20 ++++- .../hipdnn_frontend/node/detail/Utilities.hpp | 2 +- 11 files changed, 180 insertions(+), 16 deletions(-) diff --git a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp index 0feb25704521..546f2444e536 100644 --- a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp +++ b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp @@ -46,9 +46,24 @@ inline bool areDimensionsBroadcastCompatible(const std::vector& inputDi return true; } -// Sets a default stride ordering based off the provided stride order. -// Ex. dim = {1,2,3,4} stride_order = {3, 0, 2, 1} for NHWC -// returns {24, 1, 8, 2} +/** + * @brief Computes strides from dimensions and a stride ordering + * + * Generates strides for a tensor based on the provided dimensions and stride order. + * The stride order specifies the memory layout priority (lower values = tighter packing). + * + * @param dim Dimension sizes. The expected ordering depends on the operation type: + * convolution/batchnorm use (N, C, H, W) or (N, C, D, H, W), + * matmul uses (...batch, M, K) or (...batch, K, N). + * @param strideOrder Priority of each dimension in memory (lower = tighter packing). + * Use TensorLayout constants for common layouts. + * @return Strides corresponding to the requested memory layout + * + * @code{.cpp} + * // Example for convolution input: {N=1, C=2, H=3, W=4} + * auto nhwcStrides = generateStrides({1,2,3,4}, {3, 0, 2, 1}); // {24, 1, 8, 2} + * @endcode + */ inline std::vector generateStrides(const std::vector& dim, const std::vector& strideOrder) { @@ -309,8 +324,18 @@ static void iterateAlongDimensions(const std::vector& dims, F&& func) } } -// Constructs a full tensor indices vector from batch, channel, and spatial components. spatialOffset allows -// skipping initial elements in the spatialIndices vector for convenience. +/** + * @brief Constructs a full tensor indices vector from batch, channel, and spatial components + * + * Builds an index vector following NCHW ordering: batch at position 0, channel at position 1, + * followed by spatial dimensions (H, W for 4D; D, H, W for 5D). + * + * @param batchIdx Batch index (position 0 in result) + * @param channelIdx Channel index (position 1 in result) + * @param spatialIndices Spatial dimension indices (positions 2+ in result) + * @param spatialOffset Number of elements to skip at the start of spatialIndices + * @return Combined index vector in NCHW/NCDHW order + */ static inline std::vector buildTensorIndices(int64_t batchIdx, int64_t channelIdx, const std::vector& spatialIndices, diff --git a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp index 286d93b37472..f06b2095ed80 100644 --- a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp +++ b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp @@ -18,15 +18,32 @@ namespace hipdnn_data_sdk::utilities { +/** + * @brief Describes a tensor memory layout via stride ordering + * + * TensorLayout encodes how tensor dimensions map to memory. The `strideOrder` vector + * specifies the priority of each dimension in memory layout (lower values = tighter + * packing in memory). + * + * @note TensorLayout is primarily used with convolution and batch normalization tensors, + * which follow (N, C, H, W) / (N, C, D, H, W) dimension ordering. Other operations + * such as matmul and pointwise have their own dimension conventions. The TensorLayout + * controls how dimensions map to contiguous memory via strides computed by + * `generateStrides()`. + * + * For example, for a convolution input with dims = {1, 64, 28, 28} (N=1, C=64, H=28, W=28): + * - TensorLayout::NCHW produces strides {50176, 784, 28, 1} (channel-first) + * - TensorLayout::NHWC produces strides {50176, 1, 1792, 64} (channel-last) + */ struct TensorLayout { - std::string name; - std::vector strideOrder; + std::string name; ///< Human-readable layout name (e.g., "NCHW", "NHWC") + std::vector strideOrder; ///< Stride priority per dimension (lower = tighter packing) - static const TensorLayout NCHW; - static const TensorLayout NHWC; - static const TensorLayout NCDHW; - static const TensorLayout NDHWC; + static const TensorLayout NCHW; ///< 4D channel-first layout + static const TensorLayout NHWC; ///< 4D channel-last layout + static const TensorLayout NCDHW; ///< 5D channel-first layout + static const TensorLayout NDHWC; ///< 5D channel-last layout }; inline const TensorLayout TensorLayout::NCHW{"NCHW", {3, 2, 1, 0}}; diff --git a/projects/hipdnn/docs/OperationSupport-ReferenceImpl.md b/projects/hipdnn/docs/OperationSupport-ReferenceImpl.md index f3f24a35ef09..cbb052693e9f 100644 --- a/projects/hipdnn/docs/OperationSupport-ReferenceImpl.md +++ b/projects/hipdnn/docs/OperationSupport-ReferenceImpl.md @@ -75,6 +75,12 @@ The following table lists all operations currently supported in the CPU Referenc - **NCDHW**: Batch, Channels, Depth, Height, Width (3D, channel-first) - **NDHWC**: Batch, Depth, Height, Width, Channels (3D, channel-last) +> **Note:** The layout names (NCHW, NHWC, etc.) describe the **memory layout** controlled by +> strides. Dimension ordering is operation-specific: convolution and batch normalization use +> `(N, C, H, W)` / `(N, C, D, H, W)` ordering, matmul uses `(...batch, M, K)` ordering, +> and pointwise operations are dimension-agnostic. See the +> [Porting Guide](./PortingGuide.md#tensor-dimensions-and-layouts) for details. + ### Implementation - **CPU Reference**: CPU-based reference implementation for validation diff --git a/projects/hipdnn/docs/PortingGuide.md b/projects/hipdnn/docs/PortingGuide.md index f55b92d92c6b..d135ecf28b4f 100644 --- a/projects/hipdnn/docs/PortingGuide.md +++ b/projects/hipdnn/docs/PortingGuide.md @@ -56,6 +56,79 @@ ninja | **Device Memory Utility** | Surface | MigratableMemory | | **Device Memory Access** | Surface::devPtr | MigratableMemory::deviceData() | +### Tensor Dimensions and Layouts + +Tensor dimension ordering in hipDNN is **operation-specific**, following the same conventions as +PyTorch and cuDNN. The **memory layout** (channel-first vs channel-last) is always controlled by +strides, not by the order of the dimension vector. Use the `TensorLayout` constants and +`generateStrides()` utility to compute strides for common layouts. + +#### Convolution + +| Tensor | Shape (4D) | Shape (5D) | Description | +|--------|-----------|------------|-------------| +| Input (x) | `(N, C, H, W)` | `(N, C, D, H, W)` | Batch, channels, spatial dims | +| Weights (w) | `(K, C/groups, R, S)` | `(K, C/groups, T, R, S)` | Output channels, input channels per group, kernel spatial dims | +| Output (y) | `(N, K, H_out, W_out)` | `(N, K, D_out, H_out, W_out)` | Batch, output channels, output spatial dims | + +```cpp +// Convolution example: dims always follow (N, C, spatial...) ordering +auto x = graph.tensor(TensorAttributes() + .set_dim({1, 64, 28, 28}) // N=1, C=64, H=28, W=28 + .set_stride(generateStrides({1, 64, 28, 28}, TensorLayout::NHWC.strideOrder))); + +auto w = graph.tensor(TensorAttributes() + .set_dim({128, 64, 3, 3}) // K=128, C=64, R=3, S=3 + .set_stride(generateStrides({128, 64, 3, 3}, TensorLayout::NHWC.strideOrder))); +``` + +#### Batch Normalization + +| Tensor | Shape | Description | +|--------|-------|-------------| +| Input (x) | `(N, C, H, W)` or `(N, C, D, H, W)` | Same ordering as convolution | +| Scale, Bias, Mean, Variance | `(1, C, 1, 1)` or `(1, C, 1, 1, 1)` | Per-channel parameters | +| Output (y) | Same as input | Shape preserved | + +Statistics are computed per-channel over the batch and spatial dimensions. + +#### Layer Normalization + +| Tensor | Shape | Description | +|--------|-------|-------------| +| Input (x) | `(N, ...)` | Batch first, then feature dims | +| Scale, Bias | `(1, C, H, W)` | Batch dim = 1, feature dims match input | +| Mean, Inv Variance | Stats dims | Batch dims from input, normalized dims = 1 | + +Normalization is performed over the feature dimensions (all dims where scale > 1). + +#### Matrix Multiplication + +| Tensor | Shape | Description | +|--------|-------|-------------| +| A | `(...batch, M, K)` | Leading batch dims, last two are matrix dims | +| B | `(...batch, K, N)` | K must match A's last dim | +| C (output) | `(...batch, M, N)` | Batch dims are broadcast | + +Batch dimensions support broadcasting (dims must be equal or divisible). + +```cpp +// Matmul example: A(batch, M, K) @ B(batch, K, N) -> C(batch, M, N) +auto a = graph.tensor(TensorAttributes() + .set_dim({4, 128, 64}) // batch=4, M=128, K=64 + .set_stride({128*64, 64, 1})); + +auto b = graph.tensor(TensorAttributes() + .set_dim({4, 64, 256}) // batch=4, K=64, N=256 + .set_stride({64*256, 256, 1})); +``` + +#### Pointwise Operations + +Pointwise operations (ReLU, Sigmoid, Add, Mul, etc.) are **dimension-agnostic** — they accept +tensors of any shape. For binary and ternary operations, inputs are broadcast using NumPy-style +broadcasting rules (dimensions compared right-to-left; compatible if equal or 1). + ## Common Pitfalls ### 1. CMAKE_POSITION_INDEPENDENT_CODE diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/BatchnormAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/BatchnormAttributes.hpp index 4e4a47609071..86e736464420 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/BatchnormAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/BatchnormAttributes.hpp @@ -30,8 +30,14 @@ namespace hipdnn_frontend::graph * This operation normalizes the input tensor across the batch dimension and * computes running statistics for inference. * + * **Tensor Shapes:** + * - **X** (input): `(N, C, H, W)` or `(N, C, D, H, W)` — batch, channels, spatial dims + * - **Scale, Bias**: `(1, C, 1, 1)` or `(1, C, 1, 1, 1)` — per-channel parameters + * - **Y** (output): Same shape as X + * - **Mean, Inv_variance**: `(1, C, 1, 1)` or `(1, C, 1, 1, 1)` — per-channel statistics + * * **Required inputs:** - * - X: Input tensor to normalize (NCHW format) + * - X: Input tensor to normalize * - Scale: Per-channel scale (gamma) tensor * - Bias: Per-channel bias (beta) tensor * diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/ConvolutionFpropAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/ConvolutionFpropAttributes.hpp index 696015999b42..3a92669e1e27 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/ConvolutionFpropAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/ConvolutionFpropAttributes.hpp @@ -30,6 +30,11 @@ namespace hipdnn_frontend::graph * operation: y = conv(x, w). The operation computes the convolution of input tensor * x with filter tensor w. * + * **Tensor Shapes:** + * - **x** (input): `(N, C, H, W)` or `(N, C, D, H, W)` — batch, channels, spatial dims + * - **w** (weights): `(K, C/groups, R, S)` or `(K, C/groups, T, R, S)` — output channels, input channels per group, kernel spatial dims + * - **y** (output): `(N, K, H_out, W_out)` or `(N, K, D_out, H_out, W_out)` — batch, output channels, output spatial dims + * * @code{.cpp} * // Create a 2D convolution with 3x3 kernel, padding=1, stride=1 * auto y = graph.conv_fprop(x, w, ConvFpropAttributes() diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/LayernormAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/LayernormAttributes.hpp index c23febb77942..5745a7079277 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/LayernormAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/LayernormAttributes.hpp @@ -29,6 +29,12 @@ namespace hipdnn_frontend::graph * Unlike batch normalization which normalizes across the batch dimension, * layer normalization normalizes across the feature dimensions. * + * **Tensor Shapes:** + * - **X** (input): `(N, ...)` — batch first, then feature dims + * - **Scale, Bias**: `(1, C, H, W)` — batch dim = 1, feature dims match input + * - **Y** (output): Same shape as X + * - **Mean, InvVariance**: Batch dims from input, normalized dims = 1 + * * **Required inputs:** * - X: Input tensor to normalize * - Scale: Per-feature scale (gamma) tensor diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/MatmulAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/MatmulAttributes.hpp index be499bfa1efb..27984d80f7df 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/MatmulAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/MatmulAttributes.hpp @@ -29,6 +29,13 @@ namespace hipdnn_frontend::graph * operation: C = A @ B. Supports batched operations when tensors have * leading batch dimensions. * + * **Tensor Shapes:** + * - **A** (left input): `(...batch, M, K)` — leading batch dims, rows, columns + * - **B** (right input): `(...batch, K, N)` — K must match A's last dim + * - **C** (output): `(...batch, M, N)` — batch dims are broadcast + * + * Batch dimensions support broadcasting (dims must be equal or divisible). + * * @code{.cpp} * // Matrix multiplication: C = A @ B * auto c = graph.matmul(a, b, MatmulAttributes()); diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/PointwiseAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/PointwiseAttributes.hpp index 93972a026644..d85d206633c4 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/PointwiseAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/PointwiseAttributes.hpp @@ -48,6 +48,11 @@ namespace hipdnn_frontend::graph * .set_mode(PointwiseMode::ADD)); * @endcode * + * **Tensor Shapes:** + * Pointwise operations are dimension-agnostic — input tensors can have any shape. + * For binary and ternary operations, inputs are broadcast using NumPy-style rules + * (dimensions compared right-to-left; compatible if equal or 1). + * * @see Graph::pointwise(), PointwiseMode */ class PointwiseAttributes : public Attributes diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp index 65e54a38e9c7..d5b6b8133288 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp @@ -43,11 +43,19 @@ using hipdnn_data_sdk::types::half; * - **Virtual tensors**: Intermediate results that don't require explicit memory allocation * - **Pass-by-value tensors**: Scalar values embedded directly in the tensor * + * @note **Dimension Ordering**: The expected dimension ordering depends on the operation. + * Convolution and batch normalization tensors use `(N, C, H, W)` or `(N, C, D, H, W)`. + * Matmul tensors use `(...batch, M, K)` for A and `(...batch, K, N)` for B. + * Pointwise operations accept any shape with broadcasting support. + * In all cases, the memory layout is controlled by strides, not by dimension order. + * Use `hipdnn_data_sdk::utilities::generateStrides()` to compute strides from a TensorLayout. + * * @code{.cpp} - * // Create a 4D tensor (NCHW format) + * // Create a 4D convolution input tensor + * // For convolution, dimensions follow (N, C, H, W) ordering * auto x = Graph::tensor(TensorAttributes() - * .set_dim({1, 64, 28, 28}) - * .set_stride({50176, 784, 28, 1}) + * .set_dim({1, 64, 28, 28}) // dims: N=1, C=64, H=28, W=28 + * .set_stride({50176, 784, 28, 1}) // NCHW layout strides * .set_data_type(DataType::HALF) * .set_uid(0) * .set_name("input_x")); @@ -272,6 +280,12 @@ class TensorAttributes * @brief Set the dimensions for this tensor * @param dim Vector of dimension sizes * @return Reference to this for method chaining + * + * @note The expected dimension ordering depends on the operation type: + * convolution and batch normalization use (N, C, H, W) / (N, C, D, H, W), + * matmul uses (...batch, M, K) / (...batch, K, N), + * and pointwise operations accept any shape. + * Memory layout is always controlled by strides, not dimension order. */ TensorAttributes& set_dim(const std::vector& dim) // NOLINT(readability-identifier-naming) diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/node/detail/Utilities.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/node/detail/Utilities.hpp index 0e8b3251c8df..64fc7c05333c 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/node/detail/Utilities.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/node/detail/Utilities.hpp @@ -129,7 +129,7 @@ inline Error validateBatchNormTrainingSpatialDimensions( // Spatial mode: normalizes over N*spatial_dims per channel // Requires N*H*W > 1 (or N*D*H*W > 1 for 3D) - // dims are always declared in NCHW & NCDHW order + // Batchnorm dims follow NCHW & NCDHW order int64_t spatialElements = dims[0]; // Start with N for(size_t i = 2; i < dims.size(); ++i) { From bd540cfd3d3d846a3e238b8f754b4ff443f4046e Mon Sep 17 00:00:00 2001 From: Brian Harrison Date: Tue, 3 Mar 2026 01:05:03 +0000 Subject: [PATCH 2/2] [HIPDNN] Address PR #4991 review feedback Apply doc/comment wording improvements from CMiservaAMD and SamuelReeder: - Add stride order values and per-dim stride labels to TensorLayout examples - Expand PortingGuide stride order explanation with NCHW/NDHWC examples - Replace graph.tensor() with direct TensorAttributes construction in examples - Generalize LayerNorm scale/bias shape description for n-dimensional inputs - Clarify "dimension order in the tensor shape vector" wording in TensorAttributes - Add NHWC example alongside existing NCHW example in TensorAttributes - Minor "4D tensors / 5D tensors" wording fix in ShapeUtilities Co-Authored-By: Claude Opus 4.6 --- .../utilities/ShapeUtilities.hpp | 2 +- .../hipdnn_data_sdk/utilities/Tensor.hpp | 4 ++-- projects/hipdnn/docs/PortingGuide.md | 20 +++++++++---------- .../attributes/TensorAttributes.hpp | 12 +++++++++-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp index 546f2444e536..93d6e7b119f9 100644 --- a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp +++ b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/ShapeUtilities.hpp @@ -328,7 +328,7 @@ static void iterateAlongDimensions(const std::vector& dims, F&& func) * @brief Constructs a full tensor indices vector from batch, channel, and spatial components * * Builds an index vector following NCHW ordering: batch at position 0, channel at position 1, - * followed by spatial dimensions (H, W for 4D; D, H, W for 5D). + * followed by spatial dimensions (H, W for 4D tensors; D, H, W for 5D tensors). * * @param batchIdx Batch index (position 0 in result) * @param channelIdx Channel index (position 1 in result) diff --git a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp index f06b2095ed80..ffc517bc9741 100644 --- a/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp +++ b/projects/hipdnn/data_sdk/include/hipdnn_data_sdk/utilities/Tensor.hpp @@ -32,8 +32,8 @@ namespace hipdnn_data_sdk::utilities * `generateStrides()`. * * For example, for a convolution input with dims = {1, 64, 28, 28} (N=1, C=64, H=28, W=28): - * - TensorLayout::NCHW produces strides {50176, 784, 28, 1} (channel-first) - * - TensorLayout::NHWC produces strides {50176, 1, 1792, 64} (channel-last) + * - TensorLayout::NCHW (stride order {3,2,1,0}) produces strides {50176, 784, 28, 1} (channel-first; N=50176, C=784, H=28, W=1) + * - TensorLayout::NHWC (stride order {3,0,2,1}) produces strides {50176, 1, 1792, 64} (channel-last; N=50176, C=1, H=1792, W=64) */ struct TensorLayout { diff --git a/projects/hipdnn/docs/PortingGuide.md b/projects/hipdnn/docs/PortingGuide.md index d135ecf28b4f..654fc3efd7ab 100644 --- a/projects/hipdnn/docs/PortingGuide.md +++ b/projects/hipdnn/docs/PortingGuide.md @@ -60,7 +60,7 @@ ninja Tensor dimension ordering in hipDNN is **operation-specific**, following the same conventions as PyTorch and cuDNN. The **memory layout** (channel-first vs channel-last) is always controlled by -strides, not by the order of the dimension vector. Use the `TensorLayout` constants and +strides and stride order, not by the order of the tensor dimension vector that always holds values as [N,C,H,W] or [N,C,D,H,W]. For example, memory arranged as NCHW corresponds to stride order {3,2,1,0} (W is the most tightly packed), and NDHWC corresponds to stride order {4,0,3,2,1} (C is the most tightly packed). Use the `TensorLayout` constants and `generateStrides()` utility to compute strides for common layouts. #### Convolution @@ -73,13 +73,13 @@ strides, not by the order of the dimension vector. Use the `TensorLayout` consta ```cpp // Convolution example: dims always follow (N, C, spatial...) ordering -auto x = graph.tensor(TensorAttributes() +auto x = TensorAttributes() .set_dim({1, 64, 28, 28}) // N=1, C=64, H=28, W=28 - .set_stride(generateStrides({1, 64, 28, 28}, TensorLayout::NHWC.strideOrder))); + .set_stride(generateStrides({1, 64, 28, 28}, TensorLayout::NHWC.strideOrder)); -auto w = graph.tensor(TensorAttributes() +auto w = TensorAttributes() .set_dim({128, 64, 3, 3}) // K=128, C=64, R=3, S=3 - .set_stride(generateStrides({128, 64, 3, 3}, TensorLayout::NHWC.strideOrder))); + .set_stride(generateStrides({128, 64, 3, 3}, TensorLayout::NHWC.strideOrder)); ``` #### Batch Normalization @@ -97,7 +97,7 @@ Statistics are computed per-channel over the batch and spatial dimensions. | Tensor | Shape | Description | |--------|-------|-------------| | Input (x) | `(N, ...)` | Batch first, then feature dims | -| Scale, Bias | `(1, C, H, W)` | Batch dim = 1, feature dims match input | +| Scale, Bias | `(1, ...)` | Batch dim = 1, remaining dims match input feature dims | | Mean, Inv Variance | Stats dims | Batch dims from input, normalized dims = 1 | Normalization is performed over the feature dimensions (all dims where scale > 1). @@ -114,13 +114,13 @@ Batch dimensions support broadcasting (dims must be equal or divisible). ```cpp // Matmul example: A(batch, M, K) @ B(batch, K, N) -> C(batch, M, N) -auto a = graph.tensor(TensorAttributes() +auto a = TensorAttributes() .set_dim({4, 128, 64}) // batch=4, M=128, K=64 - .set_stride({128*64, 64, 1})); + .set_stride({128*64, 64, 1}); -auto b = graph.tensor(TensorAttributes() +auto b = TensorAttributes() .set_dim({4, 64, 256}) // batch=4, K=64, N=256 - .set_stride({64*256, 256, 1})); + .set_stride({64*256, 256, 1}); ``` #### Pointwise Operations diff --git a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp index d5b6b8133288..27ed787e7281 100644 --- a/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp +++ b/projects/hipdnn/frontend/include/hipdnn_frontend/attributes/TensorAttributes.hpp @@ -47,7 +47,7 @@ using hipdnn_data_sdk::types::half; * Convolution and batch normalization tensors use `(N, C, H, W)` or `(N, C, D, H, W)`. * Matmul tensors use `(...batch, M, K)` for A and `(...batch, K, N)` for B. * Pointwise operations accept any shape with broadcasting support. - * In all cases, the memory layout is controlled by strides, not by dimension order. + * In all cases, the memory layout is controlled by strides, not by dimension order in the tensor shape vector. * Use `hipdnn_data_sdk::utilities::generateStrides()` to compute strides from a TensorLayout. * * @code{.cpp} @@ -60,6 +60,14 @@ using hipdnn_data_sdk::types::half; * .set_uid(0) * .set_name("input_x")); * + * // Same dimensions with NHWC (channel-last) layout + * auto x_nhwc = Graph::tensor(TensorAttributes() + * .set_dim({1, 64, 28, 28}) // dims: N=1, C=64, H=28, W=28 + * .set_stride({50176, 1, 1792, 64}) // NHWC layout strides + * .set_data_type(DataType::HALF) + * .set_uid(1) + * .set_name("input_x_nhwc")); + * * // Create a scalar tensor * TensorAttributes scalar(2.0f); // Pass-by-value float * @endcode @@ -285,7 +293,7 @@ class TensorAttributes * convolution and batch normalization use (N, C, H, W) / (N, C, D, H, W), * matmul uses (...batch, M, K) / (...batch, K, N), * and pointwise operations accept any shape. - * Memory layout is always controlled by strides, not dimension order. + * Memory layout is always controlled by strides and stride order, not by dimension order in the tensor shape vector. */ TensorAttributes& set_dim(const std::vector& dim) // NOLINT(readability-identifier-naming)