// Copyright (c) Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include "ck_tile/builder/factory/helpers/conv_tensor_layout.hpp" #include "impl/conv_signature_types.hpp" namespace { namespace ckb = ::ck_tile::builder; using ::ck_tile::builder::DataType; using ::ck_tile::builder::ElementwiseOperation; using ::ck_tile::builder::TensorLayout; using ::ck_tile::builder::factory::internal::AuxiliaryTensorLayouts; using ::ck_tile::builder::factory::internal::ConvTensorLayouts; using ::ck_tile::builder::factory::internal::LayoutToCK; using namespace ::ck_tile::builder::test; using enum ::ck_tile::builder::ConvDirection; TEST(ConvTensorLayout, AssignsLayoutsFor1D_NWGC_GKXC_NWGK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 1, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NWGC}}, .weight = {.config = {.layout = TensorLayout::GKXC}}, .output = {.config = {.layout = TensorLayout::NWGK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor1D_NGCW_GKXC_NGKW) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 1, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCW}}, .weight = {.config = {.layout = TensorLayout::GKXC}}, .output = {.config = {.layout = TensorLayout::NGKW}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor1D_GNWC_GKXC_GNWK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 1, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::GNWC}}, .weight = {.config = {.layout = TensorLayout::GKXC}}, .output = {.config = {.layout = TensorLayout::GNWK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor1D_NGCW_GKCX_NGKW) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 1, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCW}}, .weight = {.config = {.layout = TensorLayout::GKCX}}, .output = {.config = {.layout = TensorLayout::NGKW}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor2D_NGCHW_GKYXC_NGKHW) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCHW}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::NGKHW}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor2D_NHWGC_GKYXC_NHWGK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NHWGC}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::NHWGK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor2D_GNHWC_GKYXC_GNHWK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::GNHWC}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::GNHWK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor2D_NGCHW_GKCYX_NGKHW) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCHW}}, .weight = {.config = {.layout = TensorLayout::GKCYX}}, .output = {.config = {.layout = TensorLayout::NGKHW}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor3D_NGCDHW_GKCZYX_NGKDHW) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 3, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCDHW}}, .weight = {.config = {.layout = TensorLayout::GKCZYX}}, .output = {.config = {.layout = TensorLayout::NGKDHW}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor3D_NDHWGC_GKZYXC_NDHWGK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 3, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NDHWGC}}, .weight = {.config = {.layout = TensorLayout::GKZYXC}}, .output = {.config = {.layout = TensorLayout::NDHWGK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(ConvTensorLayout, AssignsLayoutsFor3D_GNDHWC_GKZYXC_GNDHWK) { static constexpr auto sig = ConvSignature<>{.spatial_dim = 3, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::GNDHWC}}, .weight = {.config = {.layout = TensorLayout::GKZYXC}}, .output = {.config = {.layout = TensorLayout::GNDHWK}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v>)); } TEST(AuxiliaryTensorLayout, AssignsLayoutForG_K_strided) { using CKLayout = LayoutToCK::type; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayout, AssignsLayoutForGC) { using CKLayout = LayoutToCK::type; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayout, AssignsLayoutForG_C_strided) { using CKLayout = LayoutToCK::type; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayout, EmptyAuxiliaryTensorLayoutIsEmptyTuple) { using ::ck_tile::builder::factory::internal::EmptyAuxiliaryTensorLayout; using EmptyLayout = EmptyAuxiliaryTensorLayout::type; EXPECT_TRUE((std::is_same_v>)); } struct MockAuxiliaryTensorConfig { TensorLayout layout; }; TEST(AuxiliaryTensorLayoutIntegration, SingleBiasTensorWithG_K_Layout) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::G_K_strided}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 1); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, SingleBiasTensorWithGC_Layout) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::GC}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 1); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, SingleBiasTensorWithG_C_Layout) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::G_C_strided}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 1); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, TwoAuxiliaryTensors) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::G_K_strided}, MockAuxiliaryTensorConfig{.layout = TensorLayout::GC}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 2); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, ThreeAuxiliaryTensors) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::G_K_strided}, MockAuxiliaryTensorConfig{.layout = TensorLayout::GC}, MockAuxiliaryTensorConfig{.layout = TensorLayout::G_C_strided}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 3); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, WorksWith1DConvolution) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::G_K_strided}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 1); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(AuxiliaryTensorLayoutIntegration, WorksWith3DConvolution) { static constexpr std::array aux_configs = { MockAuxiliaryTensorConfig{.layout = TensorLayout::GC}}; using AuxLayouts = AuxiliaryTensorLayouts; EXPECT_EQ(AuxLayouts::Size, 1); using ExpectedType = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(ConvTensorLayoutsWithAuxiliary, Conv2DWithSingleBiasG_K) { using OutputOp = TensorOperation; static constexpr auto sig = ConvSignature, ConvolutionTensor<>, ConvolutionTensor>{ .spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NGCHW}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::NGKHW}, .operation = OutputOp{.elementwise_operation = ElementwiseOperation::SCALE}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); using ExpectedDsLayout = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(ConvTensorLayoutsWithAuxiliary, Conv2DWithSingleBiasGC) { using OutputOp = TensorOperation; static constexpr auto sig = ConvSignature, ConvolutionTensor<>, ConvolutionTensor>{ .spatial_dim = 2, .direction = FORWARD, .data_type = DataType::BF16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NHWGC}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::NHWGK}, .operation = OutputOp{.elementwise_operation = ElementwiseOperation::SCALE}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); using ExpectedDsLayout = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(ConvTensorLayoutsWithAuxiliary, Conv2DWithTwoAuxiliaryTensors) { using OutputOp = TensorOperation; static constexpr auto sig = ConvSignature, ConvolutionTensor<>, ConvolutionTensor>{ .spatial_dim = 2, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::GNHWC}}, .weight = {.config = {.layout = TensorLayout::GKYXC}}, .output = {.config = {.layout = TensorLayout::GNHWK}, .operation = OutputOp{.elementwise_operation = ElementwiseOperation::SCALEADD_SCALEADD_RELU}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); using ExpectedDsLayout = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(ConvTensorLayoutsWithAuxiliary, Conv1DWithBias) { using OutputOp = TensorOperation; static constexpr auto sig = ConvSignature, ConvolutionTensor<>, ConvolutionTensor>{ .spatial_dim = 1, .direction = FORWARD, .data_type = DataType::FP32, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NWGC}}, .weight = {.config = {.layout = TensorLayout::GKXC}}, .output = {.config = {.layout = TensorLayout::NWGK}, .operation = OutputOp{.elementwise_operation = ElementwiseOperation::SCALE}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); using ExpectedDsLayout = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } TEST(ConvTensorLayoutsWithAuxiliary, Conv3DWithBias) { using OutputOp = TensorOperation; static constexpr auto sig = ConvSignature, ConvolutionTensor<>, ConvolutionTensor>{ .spatial_dim = 3, .direction = FORWARD, .data_type = DataType::FP16, .accumulation_data_type = DataType::FP32, .input = {.config = {.layout = TensorLayout::NDHWGC}}, .weight = {.config = {.layout = TensorLayout::GKZYXC}}, .output = {.config = {.layout = TensorLayout::NDHWGK}, .operation = OutputOp{.elementwise_operation = ElementwiseOperation::BIAS_BNORM_CLAMP}}}; using TensorLayouts = ConvTensorLayouts; EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_v)); using ExpectedDsLayout = ck::Tuple; EXPECT_TRUE((std::is_same_v)); } } // namespace