// Copyright © Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include TEST(TestBatchnormAttributes, CreateBatchnormAttributes) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; batchnormAttributes.set_x(std::make_shared()); batchnormAttributes.set_y(std::make_shared()); batchnormAttributes.set_scale(std::make_shared()); batchnormAttributes.set_bias(std::make_shared()); batchnormAttributes.set_prev_running_mean( std::make_shared()); batchnormAttributes.set_prev_running_variance( std::make_shared()); batchnormAttributes.set_momentum(std::make_shared()); batchnormAttributes.set_mean(std::make_shared()); batchnormAttributes.set_inv_variance( std::make_shared()); batchnormAttributes.set_next_running_mean( std::make_shared()); batchnormAttributes.set_next_running_variance( std::make_shared()); batchnormAttributes.set_epsilon( std::make_shared()); // Set epsilon auto xTensor = batchnormAttributes.get_x(); xTensor->set_uid(1) .set_name("XTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto yTensor = batchnormAttributes.get_y(); yTensor->set_uid(2) .set_name("YTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto scaleTensor = batchnormAttributes.get_scale(); scaleTensor->set_uid(3) .set_name("ScaleTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto biasTensor = batchnormAttributes.get_bias(); biasTensor->set_uid(4) .set_name("BiasTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto prevMeanTensor = batchnormAttributes.get_prev_running_mean(); prevMeanTensor->set_uid(5) .set_name("PrevMeanTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto prevVarianceTensor = batchnormAttributes.get_prev_running_variance(); prevVarianceTensor->set_uid(6) .set_name("PrevVarianceTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto momentumTensor = batchnormAttributes.get_momentum(); momentumTensor->set_uid(7) .set_name("MomentumTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto meanTensor = batchnormAttributes.get_mean(); meanTensor->set_uid(8) .set_name("MeanTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto invVarianceTensor = batchnormAttributes.get_inv_variance(); invVarianceTensor->set_uid(9) .set_name("InvVarianceTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto nextMeanTensor = batchnormAttributes.get_next_running_mean(); nextMeanTensor->set_uid(10) .set_name("NextMeanTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto nextVarianceTensor = batchnormAttributes.get_next_running_variance(); nextVarianceTensor->set_uid(11) .set_name("NextVarianceTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto epsilonTensor = batchnormAttributes.get_epsilon(); epsilonTensor->set_uid(14) .set_name("EpsilonTensor") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1}) .set_stride({1}); auto peerStat1 = std::make_shared(); peerStat1->set_uid(12) .set_name("PeerStat1") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2}) .set_stride({3, 4}); auto peerStat2 = std::make_shared(); peerStat2->set_uid(13) .set_name("PeerStat2") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({5, 6}) .set_stride({7, 8}); batchnormAttributes.set_peer_stats({peerStat1, peerStat2}); const auto& peerStats = batchnormAttributes.get_peer_stats(); ASSERT_EQ(peerStats.size(), 2); EXPECT_EQ(peerStats[0]->get_uid(), 12); EXPECT_EQ(peerStats[0]->get_name(), "PeerStat1"); EXPECT_EQ(peerStats[0]->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(peerStats[0]->get_dim(), (std::vector{1, 2})); EXPECT_EQ(peerStats[0]->get_stride(), (std::vector{3, 4})); EXPECT_EQ(peerStats[1]->get_uid(), 13); EXPECT_EQ(peerStats[1]->get_name(), "PeerStat2"); EXPECT_EQ(peerStats[1]->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(peerStats[1]->get_dim(), (std::vector{5, 6})); EXPECT_EQ(peerStats[1]->get_stride(), (std::vector{7, 8})); EXPECT_EQ(xTensor->get_uid(), 1); EXPECT_EQ(xTensor->get_name(), "XTensor"); EXPECT_EQ(xTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(xTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(xTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(yTensor->get_uid(), 2); EXPECT_EQ(yTensor->get_name(), "YTensor"); EXPECT_EQ(yTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(yTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(yTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(scaleTensor->get_uid(), 3); EXPECT_EQ(scaleTensor->get_name(), "ScaleTensor"); EXPECT_EQ(scaleTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(scaleTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(scaleTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(biasTensor->get_uid(), 4); EXPECT_EQ(biasTensor->get_name(), "BiasTensor"); EXPECT_EQ(biasTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(biasTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(biasTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(prevMeanTensor->get_uid(), 5); EXPECT_EQ(prevMeanTensor->get_name(), "PrevMeanTensor"); EXPECT_EQ(prevMeanTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(prevMeanTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(prevMeanTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(prevVarianceTensor->get_uid(), 6); EXPECT_EQ(prevVarianceTensor->get_name(), "PrevVarianceTensor"); EXPECT_EQ(prevVarianceTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(prevVarianceTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(prevVarianceTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(momentumTensor->get_uid(), 7); EXPECT_EQ(momentumTensor->get_name(), "MomentumTensor"); EXPECT_EQ(momentumTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(momentumTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(momentumTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(meanTensor->get_uid(), 8); EXPECT_EQ(meanTensor->get_name(), "MeanTensor"); EXPECT_EQ(meanTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(meanTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(meanTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(invVarianceTensor->get_uid(), 9); EXPECT_EQ(invVarianceTensor->get_name(), "InvVarianceTensor"); EXPECT_EQ(invVarianceTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(invVarianceTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(invVarianceTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(nextMeanTensor->get_uid(), 10); EXPECT_EQ(nextMeanTensor->get_name(), "NextMeanTensor"); EXPECT_EQ(nextMeanTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(nextMeanTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(nextMeanTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(nextVarianceTensor->get_uid(), 11); EXPECT_EQ(nextVarianceTensor->get_name(), "NextVarianceTensor"); EXPECT_EQ(nextVarianceTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(nextVarianceTensor->get_dim(), (std::vector{1, 2, 3, 4})); EXPECT_EQ(nextVarianceTensor->get_stride(), (std::vector{5, 6, 7, 8})); EXPECT_EQ(epsilonTensor->get_uid(), 14); EXPECT_EQ(epsilonTensor->get_name(), "EpsilonTensor"); EXPECT_EQ(epsilonTensor->get_data_type(), hipdnn_frontend::DataType::FLOAT); EXPECT_EQ(epsilonTensor->get_dim(), (std::vector{1})); EXPECT_EQ(epsilonTensor->get_stride(), (std::vector{1})); } TEST(TestBatchnormAttributes, SetXWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto xTensor = std::make_shared(); xTensor->set_uid(1).set_name("XTensor"); auto rawPtr = xTensor.get(); batchnormAttributes.set_x(std::move(xTensor)); auto retrieved = batchnormAttributes.get_x(); EXPECT_EQ(retrieved->get_uid(), 1); EXPECT_EQ(retrieved->get_name(), "XTensor"); EXPECT_EQ(xTensor, nullptr); EXPECT_EQ(retrieved.get(), rawPtr); } TEST(TestBatchnormAttributes, SetScaleWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto scaleTensor = std::make_shared(); scaleTensor->set_uid(2).set_name("ScaleTensor"); auto rawPtr = scaleTensor.get(); batchnormAttributes.set_scale(std::move(scaleTensor)); auto retrieved = batchnormAttributes.get_scale(); EXPECT_EQ(retrieved->get_uid(), 2); EXPECT_EQ(retrieved->get_name(), "ScaleTensor"); EXPECT_EQ(scaleTensor, nullptr); EXPECT_EQ(retrieved.get(), rawPtr); } TEST(TestBatchnormAttributes, SetBiasWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto biasTensor = std::make_shared(); biasTensor->set_uid(3).set_name("BiasTensor"); auto rawPtr = biasTensor.get(); batchnormAttributes.set_bias(std::move(biasTensor)); auto retrieved = batchnormAttributes.get_bias(); EXPECT_EQ(retrieved->get_uid(), 3); EXPECT_EQ(retrieved->get_name(), "BiasTensor"); EXPECT_EQ(biasTensor, nullptr); EXPECT_EQ(retrieved.get(), rawPtr); } TEST(TestBatchnormAttributes, SetPeerStatsWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto peerStat1 = std::make_shared(); peerStat1->set_uid(10).set_name("PeerStat1"); auto peerStat2 = std::make_shared(); peerStat2->set_uid(11).set_name("PeerStat2"); auto rawPtr1 = peerStat1.get(); auto rawPtr2 = peerStat2.get(); std::vector> peerStatsMove = {peerStat1, peerStat2}; batchnormAttributes.set_peer_stats(std::move(peerStatsMove)); const auto& peerStats = batchnormAttributes.get_peer_stats(); ASSERT_EQ(peerStats.size(), 2); EXPECT_EQ(peerStats[0]->get_uid(), 10); EXPECT_EQ(peerStats[0]->get_name(), "PeerStat1"); EXPECT_EQ(peerStats[1]->get_uid(), 11); EXPECT_EQ(peerStats[1]->get_name(), "PeerStat2"); // Verify the raw pointers match (same objects were moved) EXPECT_EQ(peerStats[0].get(), rawPtr1); EXPECT_EQ(peerStats[1].get(), rawPtr2); } TEST(TestBatchnormAttributes, SetPreviousRunningStatsWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto meanTensor = std::make_shared(); meanTensor->set_uid(20).set_name("MeanTensor"); auto varianceTensor = std::make_shared(); varianceTensor->set_uid(21).set_name("VarianceTensor"); auto momentumTensor = std::make_shared(); momentumTensor->set_uid(22).set_name("MomentumTensor"); auto rawMeanPtr = meanTensor.get(); auto rawVariancePtr = varianceTensor.get(); auto rawMomentumPtr = momentumTensor.get(); batchnormAttributes.set_previous_running_stats( std::move(meanTensor), std::move(varianceTensor), std::move(momentumTensor)); auto retrievedMean = batchnormAttributes.get_prev_running_mean(); EXPECT_EQ(retrievedMean->get_uid(), 20); EXPECT_EQ(retrievedMean->get_name(), "MeanTensor"); auto retrievedVariance = batchnormAttributes.get_prev_running_variance(); EXPECT_EQ(retrievedVariance->get_uid(), 21); EXPECT_EQ(retrievedVariance->get_name(), "VarianceTensor"); auto retrievedMomentum = batchnormAttributes.get_momentum(); EXPECT_EQ(retrievedMomentum->get_uid(), 22); EXPECT_EQ(retrievedMomentum->get_name(), "MomentumTensor"); // Verify the objects were moved EXPECT_EQ(meanTensor, nullptr); EXPECT_EQ(varianceTensor, nullptr); EXPECT_EQ(momentumTensor, nullptr); // Verify the raw pointers match EXPECT_EQ(retrievedMean.get(), rawMeanPtr); EXPECT_EQ(retrievedVariance.get(), rawVariancePtr); EXPECT_EQ(retrievedMomentum.get(), rawMomentumPtr); } // Simplified move tests - testing move semantics without setting uid/name TEST(TestBatchnormAttributes, SimplifiedSetXWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto xTensor = std::make_shared(); batchnormAttributes.set_x(std::move(xTensor)); // Just verify the tensor was set EXPECT_NE(batchnormAttributes.get_x(), nullptr); } TEST(TestBatchnormAttributes, SimplifiedSetPeerStatsWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; std::vector> peerStatsMove; peerStatsMove.push_back(std::make_shared()); peerStatsMove.push_back(std::make_shared()); const size_t originalSize = peerStatsMove.size(); batchnormAttributes.set_peer_stats(std::move(peerStatsMove)); // Verify the vector was moved const auto& peerStats = batchnormAttributes.get_peer_stats(); EXPECT_EQ(peerStats.size(), originalSize); } TEST(TestBatchnormAttributes, SimplifiedSetPreviousRunningStatsWithMove) { hipdnn_frontend::graph::BatchnormAttributes batchnormAttributes; auto meanTensor = std::make_shared(); auto varianceTensor = std::make_shared(); auto momentumTensor = std::make_shared(); batchnormAttributes.set_previous_running_stats( std::move(meanTensor), std::move(varianceTensor), std::move(momentumTensor)); // Just verify the tensors were set EXPECT_NE(batchnormAttributes.get_prev_running_mean(), nullptr); EXPECT_NE(batchnormAttributes.get_prev_running_variance(), nullptr); EXPECT_NE(batchnormAttributes.get_momentum(), nullptr); } TEST(TestBatchnormAttributes, LogicalAndStrictEquality) { hipdnn_frontend::graph::BatchnormAttributes attr1; attr1.set_compute_data_type(hipdnn_frontend::DataType::FLOAT); auto x1 = std::make_shared(); x1->set_uid(1) .set_name("X") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto scale1 = std::make_shared(); scale1->set_uid(2) .set_name("Scale") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto bias1 = std::make_shared(); bias1->set_uid(3) .set_name("Bias") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); // Set initial core tensors for attr1 attr1.set_x(x1).set_scale(scale1).set_bias(bias1); hipdnn_frontend::graph::BatchnormAttributes attr2; attr2.set_compute_data_type(hipdnn_frontend::DataType::FLOAT); auto x2 = std::make_shared(); x2->set_uid(1) .set_name("X") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto scale2 = std::make_shared(); scale2->set_uid(2) .set_name("Scale") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto bias2 = std::make_shared(); bias2->set_uid(3) .set_name("Bias") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); // Set initial core tensors for attr2 attr2.set_x(x2).set_scale(scale2).set_bias(bias2); EXPECT_TRUE(attr1.logicallyEquals(attr2)); attr2.set_compute_data_type(hipdnn_frontend::DataType::HALF); EXPECT_FALSE(attr1.logicallyEquals(attr2)); attr2.set_compute_data_type(hipdnn_frontend::DataType::FLOAT); // Revert auto momentum1 = std::make_shared(); momentum1->set_uid(7) .set_name("Momentum") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); attr1.set_momentum(momentum1); // Fails because attr1 specifies an optional tensor that attr2 lacks entirely EXPECT_FALSE(attr1.logicallyEquals(attr2)); auto momentum2 = std::make_shared(); momentum2->set_uid(7) .set_name("Momentum") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); attr2.set_momentum(momentum2); EXPECT_TRUE(attr1.logicallyEquals(attr2)); // Test Custom Peer Stats Vector Matrix Structural Differences auto peerTensor1Attr1 = std::make_shared(); peerTensor1Attr1->set_uid(12) .set_name("Peer1") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto peerTensor2Attr1 = std::make_shared(); peerTensor2Attr1->set_uid(13) .set_name("Peer2") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto peerTensor1Attr2 = std::make_shared(); peerTensor1Attr2->set_uid(12) .set_name("Peer1") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); auto peerTensor2Attr2 = std::make_shared(); peerTensor2Attr2->set_uid(13) .set_name("Peer2") .set_data_type(hipdnn_frontend::DataType::FLOAT) .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); attr1.set_peer_stats({peerTensor1Attr1, peerTensor2Attr1}); attr2.set_peer_stats({peerTensor1Attr2}); // Sizing mismatch EXPECT_FALSE(attr1.logicallyEquals(attr2)); attr2.set_peer_stats({peerTensor1Attr2, peerTensor2Attr2}); EXPECT_TRUE(attr1.logicallyEquals(attr2)); EXPECT_TRUE(attr1 == attr2); EXPECT_FALSE(attr1 != attr2); auto logicalMatchX = std::make_shared(); logicalMatchX ->set_uid(9999) // Divergent Tracking ID .set_name("DIVERGENT_TRAINING_X") // Divergent Descriptor Name .set_data_type(hipdnn_frontend::DataType::FLOAT) // Layout stays identical .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); attr2.set_x(logicalMatchX); // Expecting: Strict evaluation breaks, but functional graph identity passes EXPECT_FALSE(attr1 == attr2); EXPECT_TRUE(attr1.logicallyEquals(attr2)); attr2.set_x(x2); // Revert to matching state auto logicalMatchPeer2 = std::make_shared(); logicalMatchPeer2 ->set_uid(8888) // Divergent Tracking ID .set_name("PEER2_ALT_NAME") // Divergent Descriptor Name .set_data_type(hipdnn_frontend::DataType::FLOAT) // Layout stays identical .set_dim({1, 2, 3, 4}) .set_stride({5, 6, 7, 8}); attr2.set_peer_stats({peerTensor1Attr2, logicalMatchPeer2}); // Expecting: peer_stats custom strictEqualsImpl fails, but logicallyEqualsImpl passes EXPECT_FALSE(attr1 == attr2); EXPECT_TRUE(attr1.logicallyEquals(attr2)); }