// Copyright © Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include TEST(TestConvolutionDgradAttributes, CreateConvolutionDgradAttributes) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; // Set tensors convAttributes.set_dy(std::make_shared()); convAttributes.set_w(std::make_shared()); convAttributes.set_dx(std::make_shared()); // Set convolution parameters convAttributes.set_pre_padding({1, 1}); convAttributes.set_post_padding({1, 1}); convAttributes.set_stride({1, 1}); convAttributes.set_dilation({1, 1}); convAttributes.set_convolution_mode(hipdnn_frontend::ConvolutionMode::CROSS_CORRELATION); // Configure dy tensor (gradient of output) auto dyTensor = convAttributes.get_dy(); dyTensor->set_uid(1) .set_name("DyTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 64, 32, 32}) // NCHW format .set_stride({65536, 1024, 32, 1}); // Configure weights tensor auto wTensor = convAttributes.get_w(); wTensor->set_uid(2) .set_name("WeightsTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({64, 3, 3, 3}) // KCHW format .set_stride({27, 9, 3, 1}); // Configure dx tensor (gradient of input) auto dxTensor = convAttributes.get_dx(); dxTensor->set_uid(3) .set_name("DxTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 3, 32, 32}) // NCHW format .set_stride({3072, 1024, 32, 1}); // Verify tensor attributes EXPECT_EQ(dyTensor->get_uid(), 1); EXPECT_EQ(dyTensor->get_name(), "DyTensor"); EXPECT_EQ(dyTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(dyTensor->get_dim(), (std::vector{1, 64, 32, 32})); EXPECT_EQ(dyTensor->get_stride(), (std::vector{65536, 1024, 32, 1})); EXPECT_EQ(wTensor->get_uid(), 2); EXPECT_EQ(wTensor->get_name(), "WeightsTensor"); EXPECT_EQ(wTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(wTensor->get_dim(), (std::vector{64, 3, 3, 3})); EXPECT_EQ(wTensor->get_stride(), (std::vector{27, 9, 3, 1})); EXPECT_EQ(dxTensor->get_uid(), 3); EXPECT_EQ(dxTensor->get_name(), "DxTensor"); EXPECT_EQ(dxTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(dxTensor->get_dim(), (std::vector{1, 3, 32, 32})); EXPECT_EQ(dxTensor->get_stride(), (std::vector{3072, 1024, 32, 1})); // Verify convolution parameters EXPECT_EQ(convAttributes.get_pre_padding(), (std::vector{1, 1})); EXPECT_EQ(convAttributes.get_post_padding(), (std::vector{1, 1})); EXPECT_EQ(convAttributes.get_stride(), (std::vector{1, 1})); EXPECT_EQ(convAttributes.get_dilation(), (std::vector{1, 1})); EXPECT_EQ(convAttributes.get_convolution_mode(), hipdnn_frontend::ConvolutionMode::CROSS_CORRELATION); } TEST(TestConvolutionDgradAttributes, DefaultValues) { const hipdnn_frontend::graph::ConvDgradAttributes convAttributes; // Check default convolution mode EXPECT_EQ(convAttributes.get_convolution_mode(), hipdnn_frontend::ConvolutionMode::CROSS_CORRELATION); // Check that parameters are empty by default EXPECT_TRUE(convAttributes.get_pre_padding().empty()); EXPECT_TRUE(convAttributes.get_post_padding().empty()); EXPECT_TRUE(convAttributes.get_stride().empty()); EXPECT_TRUE(convAttributes.get_dilation().empty()); // Check that tensors are null by default EXPECT_EQ(convAttributes.get_dy(), nullptr); EXPECT_EQ(convAttributes.get_w(), nullptr); EXPECT_EQ(convAttributes.get_dx(), nullptr); } TEST(TestConvolutionDgradAttributes, SetPrePaddingWithMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; std::vector prePaddingMove = {3, 3}; convAttributes.set_pre_padding(std::move(prePaddingMove)); EXPECT_EQ(convAttributes.get_pre_padding(), (std::vector{3, 3})); } TEST(TestConvolutionDgradAttributes, SetPostPaddingWithMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; std::vector postPaddingMove = {4, 4}; convAttributes.set_post_padding(std::move(postPaddingMove)); EXPECT_EQ(convAttributes.get_post_padding(), (std::vector{4, 4})); } TEST(TestConvolutionDgradAttributes, SetStrideWithMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; std::vector strideMove = {2, 2}; convAttributes.set_stride(std::move(strideMove)); EXPECT_EQ(convAttributes.get_stride(), (std::vector{2, 2})); } TEST(TestConvolutionDgradAttributes, SetDilationWithMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; std::vector dilationMove = {2, 2}; convAttributes.set_dilation(std::move(dilationMove)); EXPECT_EQ(convAttributes.get_dilation(), (std::vector{2, 2})); } TEST(TestConvolutionDgradAttributes, SetPaddingBothPreAndPost) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; const std::vector padding = {5, 5}; convAttributes.set_padding(padding); // set_padding should set both pre and post padding to the same value EXPECT_EQ(convAttributes.get_pre_padding(), (std::vector{5, 5})); EXPECT_EQ(convAttributes.get_post_padding(), (std::vector{5, 5})); } TEST(TestConvolutionDgradAttributes, SetDyMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; auto dyTensor = std::make_shared(); dyTensor->set_uid(10) .set_name("MovedDyTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 64, 224, 224}) .set_stride({3211264, 50176, 224, 1}); // Store the raw pointer before moving auto rawPtr = dyTensor.get(); convAttributes.set_dy(std::move(dyTensor)); // After move, dyTensor should be nullptr EXPECT_EQ(dyTensor, nullptr); // The moved tensor should be accessible through get_dy() auto retrievedTensor = convAttributes.get_dy(); EXPECT_EQ(retrievedTensor.get(), rawPtr); } TEST(TestConvolutionDgradAttributes, SetWMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; auto wTensor = std::make_shared(); wTensor->set_uid(20) .set_name("MovedWeightTensor") .set_data_type(hipdnn_frontend::DataType::HALF) .set_dim({128, 64, 5, 5}) .set_stride({1600, 25, 5, 1}); // Store the raw pointer before moving auto rawPtr = wTensor.get(); convAttributes.set_w(std::move(wTensor)); // After move, wTensor should be nullptr EXPECT_EQ(wTensor, nullptr); // The moved tensor should be accessible through get_w() auto retrievedTensor = convAttributes.get_w(); EXPECT_EQ(retrievedTensor.get(), rawPtr); } TEST(TestConvolutionDgradAttributes, SetDxWithMove) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; auto dxTensor = std::make_shared(); dxTensor->set_uid(30) .set_name("MovedDxTensor") .set_data_type(hipdnn_frontend::DataType::BFLOAT16) .set_dim({1, 128, 112, 112}) .set_stride({1605632, 12544, 112, 1}); // Store the raw pointer before moving auto rawPtr = dxTensor.get(); convAttributes.set_dx(std::move(dxTensor)); // After move, dxTensor should be nullptr EXPECT_EQ(dxTensor, nullptr); // The moved tensor should be accessible through get_dx() auto retrievedTensor = convAttributes.get_dx(); EXPECT_EQ(retrievedTensor.get(), rawPtr); } TEST(TestConvolutionDgradAttributes, SetTensorsConstRef) { hipdnn_frontend::graph::ConvDgradAttributes convAttributes; // Create tensors auto dyTensor = std::make_shared(); dyTensor->set_uid(40).set_name("DyConstRef"); auto wTensor = std::make_shared(); wTensor->set_uid(50).set_name("WeightConstRef"); auto dxTensor = std::make_shared(); dxTensor->set_uid(60).set_name("DxConstRef"); // Set using const reference (copy) convAttributes.set_dy(dyTensor); convAttributes.set_w(wTensor); convAttributes.set_dx(dxTensor); // Original tensors should still be valid EXPECT_NE(dyTensor, nullptr); EXPECT_NE(wTensor, nullptr); EXPECT_NE(dxTensor, nullptr); } TEST(TestConvolutionDgradAttributes, LogicalAndStrictEquality) { hipdnn_frontend::graph::ConvDgradAttributes attrA; hipdnn_frontend::graph::ConvDgradAttributes attrB; hipdnn_frontend::graph::ConvDgradAttributes attrC; hipdnn_frontend::graph::ConvDgradAttributes attrD; // Common structurally defined sharing tensors auto dyShared = std::make_shared(); dyShared->set_uid(10) .set_name("dy") .set_dim({1, 64, 32, 32}) .set_data_type(hipdnn_frontend::DataType::FLOAT); auto wShared = std::make_shared(); wShared->set_uid(20) .set_name("w") .set_dim({64, 3, 3, 3}) .set_data_type(hipdnn_frontend::DataType::FLOAT); auto dxShared = std::make_shared(); dxShared->set_uid(30) .set_name("dx") .set_dim({1, 3, 32, 32}) .set_data_type(hipdnn_frontend::DataType::FLOAT); // Identical Baseline Setup attrA.set_dy(dyShared) .set_w(wShared) .set_dx(dxShared) .set_padding({1, 1}) .set_stride({1, 1}) .set_dilation({1, 1}); attrB.set_dy(dyShared) .set_w(wShared) .set_dx(dxShared) .set_padding({1, 1}) .set_stride({1, 1}) .set_dilation({1, 1}); EXPECT_TRUE(attrA.logicallyEquals(attrB)); EXPECT_TRUE(attrA == attrB); // Metadata Discrepancy (Names/UID variance, identical layout shapes) auto dyMetaDiff = std::make_shared(*dyShared); dyMetaDiff->set_uid(999).set_name("altered_dy_name"); attrC.set_dy(dyMetaDiff) .set_w(wShared) .set_dx(dxShared) .set_padding({1, 1}) .set_stride({1, 1}) .set_dilation({1, 1}); EXPECT_TRUE(attrA.logicallyEquals(attrC)); EXPECT_FALSE(attrA == attrC); // Functional/Mathematical Attribute Divergence // Variant 1: Padding mismatched attrD.set_dy(dyShared) .set_w(wShared) .set_dx(dxShared) .set_padding({0, 0}) .set_stride({1, 1}) .set_dilation({1, 1}); EXPECT_FALSE(attrA.logicallyEquals(attrD)); EXPECT_FALSE(attrA == attrD); // Variant 2: Stride mismatched attrD.set_padding({1, 1}).set_stride({2, 2}); EXPECT_FALSE(attrA.logicallyEquals(attrD)); EXPECT_FALSE(attrA == attrD); // Variant 3: Dilation mismatched attrD.set_stride({1, 1}).set_dilation({2, 2}); EXPECT_FALSE(attrA.logicallyEquals(attrD)); EXPECT_FALSE(attrA == attrD); // Variant 4: Math Mode mismatched attrD.set_dilation({1, 1}).set_convolution_mode(hipdnn_frontend::ConvolutionMode::CONVOLUTION); EXPECT_FALSE(attrA.logicallyEquals(attrD)); EXPECT_FALSE(attrA == attrD); }