// Copyright © Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include #include #include #include #include #include #include "../utils/Helpers.hpp" using namespace hipdnn_frontend; using namespace hipdnn_data_sdk; template bool SampleRunner::operator()(const TensorLayout& layout) { using OutputType = InputType; auto inputType = getDataTypeEnumFromType(); auto computeType = getDataTypeEnumFromType(); std::cout << "Running batch normalization inference with variance + ReLU activation graph " << inputType << " [" << layout << "]" << (config.cpuValidation ? " (with CPU validation)" : "") << "...\n"; // Input dimensions const int64_t n = config.dims.size() > 0 ? config.dims[0] : 16; // BATCH SIZE const int64_t c = config.dims.size() > 1 ? config.dims[1] : 16; // CHANNELS (FEATURES) const int64_t h = config.dims.size() > 2 ? config.dims[2] : 16; // HEIGHT (SPATIAL DIMENSION) const int64_t w = config.dims.size() > 3 ? config.dims[3] : 16; // WIDTH (SPATIAL DIMENSION) auto graph = std::make_shared(); graph->set_io_data_type(inputType) .set_intermediate_data_type(computeType) .set_compute_data_type(computeType); setPreferredEngine(graph, config); auto x = createTensor({n, c, h, w}, inputType, layout); auto scale = createTensor({1, c, 1, 1}, computeType); auto bias = createTensor({1, c, 1, 1}, computeType); auto mean = createTensor({1, c, 1, 1}, computeType); auto variance = createTensor({1, c, 1, 1}, computeType); // Epsilon is a tensor for the variance extension auto epsilon = std::make_shared(); epsilon->set_value(utilities::BATCHNORM_DEFAULT_EPSILON); // Step 1: Batchnorm Inference with Variance auto bnAttributes = graph::BatchnormInferenceAttributesVarianceExt(); bnAttributes.set_name("bn_inference_variance_ext_node"); auto y = graph->batchnorm_inference_variance_ext( x, mean, variance, scale, bias, epsilon, bnAttributes); // Step 2: Pointwise ReLU Activation auto pwAttributes = graph::PointwiseAttributes(); pwAttributes.set_name("activation_node"); pwAttributes.set_mode(PointwiseMode::RELU_FWD); auto activatedY = graph->pointwise(y, pwAttributes); activatedY->set_name("activated_y"); activatedY->set_output(true); HIPDNN_FE_CHECK_SKIPPABLE(graph->build(handle)); std::cout << "Graph build successful.\n"; // Allocate tensors utilities::Tensor xTensor(x->get_dim(), layout); utilities::Tensor scaleTensor(scale->get_dim()); utilities::Tensor biasTensor(bias->get_dim()); utilities::Tensor meanTensor(mean->get_dim()); utilities::Tensor varianceTensor(variance->get_dim()); utilities::Tensor activatedYTensor(activatedY->get_dim(), layout); // Initialize tensors xTensor.fillWithRandomValues(static_cast(0.0f), static_cast(1.0f)); scaleTensor.fillWithRandomValues(static_cast(0.0f), static_cast(1.0f)); biasTensor.fillWithRandomValues(static_cast(0.0f), static_cast(1.0f)); meanTensor.fillWithRandomValues(static_cast(0.0f), static_cast(1.0f)); varianceTensor.fillWithRandomValues(static_cast(0.1f), static_cast(1.0f)); // Build variant pack std::unordered_map variantPack; variantPack[x->get_uid()] = xTensor.memory().deviceData(); variantPack[scale->get_uid()] = scaleTensor.memory().deviceData(); variantPack[bias->get_uid()] = biasTensor.memory().deviceData(); variantPack[mean->get_uid()] = meanTensor.memory().deviceData(); variantPack[variance->get_uid()] = varianceTensor.memory().deviceData(); variantPack[activatedY->get_uid()] = activatedYTensor.memory().deviceData(); int64_t workspaceSize = 0; HIPDNN_FE_CHECK(graph->get_workspace_size(workspaceSize)); const utilities::Workspace workspace(static_cast(workspaceSize)); HIPDNN_FE_CHECK(graph->execute(handle, variantPack, workspace.get())); activatedYTensor.memory().markDeviceModified(); auto activatedYHostPtr = activatedYTensor.memory().hostData(); bool validationPassed = true; if(config.cpuValidation) { std::cout << "Running CPU reference validation using CpuReferenceGraphExecutor...\n"; // Create reference tensor utilities::Tensor activatedYRefTensor(activatedY->get_dim(), layout); // Build variant pack for CPU execution (using host pointers) const std::unordered_map cpuVariantPack{ {x->get_uid(), xTensor.memory().hostData()}, {scale->get_uid(), scaleTensor.memory().hostData()}, {bias->get_uid(), biasTensor.memory().hostData()}, {mean->get_uid(), meanTensor.memory().hostData()}, {variance->get_uid(), varianceTensor.memory().hostData()}, {activatedY->get_uid(), activatedYRefTensor.memory().hostData()}}; // Execute on CPU using graph executor auto [serializedGraph, serErr] = graph->to_binary(); if(serErr.is_bad()) { std::cerr << "Failed to serialize graph: " << serErr.get_message() << '\n'; return false; } hipdnn_test_sdk::utilities::CpuReferenceGraphExecutor cpuExecutor; cpuExecutor.execute(serializedGraph.data(), serializedGraph.size(), cpuVariantPack); auto tolerance = hipdnn_test_sdk::utilities::batchnorm::getToleranceInferenceWithVariance< OutputType>(); auto yValidator = hipdnn_test_sdk::utilities::CpuFpReferenceValidation( tolerance, tolerance); std::cout << "CPU reference validation:\n"; const bool yValid = hipdnn_test_sdk::utilities::validateAndReport(std::cout, "activated_y", yValidator, activatedYRefTensor, activatedYTensor, tolerance, tolerance); validationPassed = yValid; } std::cout << "First 10 activated_y values: "; for(int i = 0; i < 10; ++i) { std::cout << static_cast(activatedYHostPtr[i]) << " "; } std::cout << "\nBatch normalization inference with variance + activation graph execution " "complete for " << inputType << ".\n\n"; return validationPassed; } int main(int argc, char* argv[]) { try { RETURN_SUCCESS_IF_NO_DEVICE(); auto config = parseCommandLineArgs(argc, argv); auto [handle, handleError] = createHipdnnHandle(); HIPDNN_FE_CHECK(handleError); const bool allPassed = run(SampleRunner{*handle, config}); if(allPassed) { std::cout << "All batch normalization inference with variance + activation runs completed " "successfully.\n"; return 0; } std::cout << "One or more batch normalization inference with variance + activation runs " "failed validation.\n"; return 1; } catch(const std::exception& e) { std::fprintf(stderr, "Unhandled exception: %s\n", e.what()); return 1; } }