CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
828 lines
34 KiB
C++
828 lines
34 KiB
C++
// Copyright © Advanced Micro Devices, Inc., or its affiliates.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include <hipdnn_flatbuffers_sdk/flatbuffer_utilities/FlatbufferTypeHelpers.hpp>
|
|
#include <hipdnn_plugin_sdk/PluginException.hpp>
|
|
#include <hipdnn_plugin_sdk/PluginLogging.hpp>
|
|
#include <miopen/miopen.h>
|
|
#include <string>
|
|
#include <unordered_set>
|
|
|
|
#include "MiopenBatchnormPlanBuilder.hpp"
|
|
#include "MiopenUtils.hpp"
|
|
#include "engines/plans/MiopenBatchnormApplicabilityChecks.hpp"
|
|
#include "engines/plans/MiopenBatchnormBwdPlan.hpp"
|
|
#include "engines/plans/MiopenBatchnormFwdInferencePlan.hpp"
|
|
#include "engines/plans/MiopenBatchnormFwdInferenceWithVariancePlan.hpp"
|
|
#include "engines/plans/MiopenBatchnormFwdTrainingPlan.hpp"
|
|
|
|
namespace miopen_plugin
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
std::tuple<const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes&,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes&,
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormBackwardAttributes&>
|
|
getBatchnormBackwardFusionNodeAttrs(
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph)
|
|
{
|
|
if(opGraph.nodeCount() != 3)
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm fusion requires exactly 3 nodes. Graph has "
|
|
+ std::to_string(opGraph.nodeCount()) + " nodes");
|
|
}
|
|
|
|
const auto& bnInfAttr
|
|
= opGraph.getNodeWrapper(0)
|
|
.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes>();
|
|
|
|
const auto& actAttr
|
|
= opGraph.getNodeWrapper(1)
|
|
.attributesAs<hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes>();
|
|
|
|
const auto& bnBwdAttr
|
|
= opGraph.getNodeWrapper(2)
|
|
.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormBackwardAttributes>();
|
|
|
|
return {bnInfAttr, actAttr, bnBwdAttr};
|
|
}
|
|
|
|
auto getBatchnormBackwardFusionNodeAttrsLogErrors(
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph)
|
|
-> std::optional<decltype(getBatchnormBackwardFusionNodeAttrs(opGraph))>
|
|
{
|
|
try
|
|
{
|
|
return getBatchnormBackwardFusionNodeAttrs(opGraph);
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return {};
|
|
}
|
|
}
|
|
|
|
void batchnormBwdFusionCheckTensors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormBackwardAttributes& bnBwdAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
using PM = hipdnn_flatbuffers_sdk::data_objects::PointwiseMode;
|
|
static const std::unordered_set<PM> s_supportedActivations = {PM::RELU_BWD};
|
|
|
|
if(s_supportedActivations.count(actAttr.operation()) == 0)
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm fusion currently only supports RELU_BWD activation");
|
|
}
|
|
|
|
const auto actIn1Uid = actAttr.in_1_tensor_uid();
|
|
if(!actIn1Uid.has_value())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation backward requires in_1 tensor (forward activation input)");
|
|
}
|
|
|
|
if(actIn1Uid.value() != bnInfAttr.y_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation in_1 must be the batchnorm inference output tensor (y)");
|
|
}
|
|
|
|
// Verify activation backwards output is BN backward dy input
|
|
if(actAttr.out_0_tensor_uid() != bnBwdAttr.dy_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward dy input must be the activation output tensor");
|
|
}
|
|
|
|
// Verify that different BN operations use shared inputs where applicable
|
|
if(bnBwdAttr.x_tensor_uid() != bnInfAttr.x_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward must use the same X tensor as batchnorm inference");
|
|
}
|
|
|
|
if(bnBwdAttr.mean_tensor_uid().has_value()
|
|
&& bnBwdAttr.mean_tensor_uid().value() != bnInfAttr.mean_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward must use the same mean tensor as batchnorm inference");
|
|
}
|
|
|
|
if(bnBwdAttr.inv_variance_tensor_uid().has_value()
|
|
&& bnBwdAttr.inv_variance_tensor_uid().value() != bnInfAttr.inv_variance_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward must use the same inv_variance tensor as batchnorm inference");
|
|
}
|
|
|
|
if(bnBwdAttr.scale_tensor_uid() != bnInfAttr.scale_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward must use the same scale tensor as batchnorm inference");
|
|
}
|
|
|
|
// Check for virtual tensors
|
|
const auto& bnInfTensorX
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.x_tensor_uid());
|
|
const auto& bnInfTensorMean
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.mean_tensor_uid());
|
|
const auto& bnInfTensorInvVar
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.inv_variance_tensor_uid());
|
|
const auto& bnInfTensorScale
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.scale_tensor_uid());
|
|
const auto& bnInfTensorBias
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.bias_tensor_uid());
|
|
const auto& bnInfTensorY
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.y_tensor_uid());
|
|
|
|
if(bnInfTensorX.virtual_() || bnInfTensorMean.virtual_() || bnInfTensorInvVar.virtual_()
|
|
|| bnInfTensorScale.virtual_() || bnInfTensorBias.virtual_() || !bnInfTensorY.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm inference input tensors must be non-virtual, output tensor must be virtual");
|
|
}
|
|
|
|
const auto& actTensorIn0
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.in_0_tensor_uid());
|
|
|
|
if(actTensorIn0.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM, "Activation in_0 (dy gradient) must be non-virtual");
|
|
}
|
|
|
|
const auto& actTensorIn1 = miopen_utils::findTensorAttributes(tensorMap, actIn1Uid.value());
|
|
const auto& actTensorOut
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.out_0_tensor_uid());
|
|
|
|
if(!actTensorIn1.virtual_() || !actTensorOut.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation input from batchnorm must be virtual, output must be virtual");
|
|
}
|
|
|
|
const auto& bnBwdTensorDy
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnBwdAttr.dy_tensor_uid());
|
|
const auto& bnBwdTensorDx
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnBwdAttr.dx_tensor_uid());
|
|
const auto& bnBwdTensorDscale
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnBwdAttr.dscale_tensor_uid());
|
|
const auto& bnBwdTensorDbias
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnBwdAttr.dbias_tensor_uid());
|
|
|
|
if(!bnBwdTensorDy.virtual_() || bnBwdTensorDx.virtual_() || bnBwdTensorDscale.virtual_()
|
|
|| bnBwdTensorDbias.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm backward dy input must be virtual, output tensors must be non-virtual");
|
|
}
|
|
}
|
|
|
|
void batchnormFwdFusionCheckTensors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
using PM = hipdnn_flatbuffers_sdk::data_objects::PointwiseMode;
|
|
static const std::unordered_set<PM> s_supportedActivations = {PM::RELU_FWD};
|
|
|
|
if(s_supportedActivations.count(actAttr.operation()) == 0)
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm fusion currently only supports RELU_FWD activation");
|
|
}
|
|
|
|
// in_0 must be the batchnorm inference output (forward path)
|
|
if(actAttr.in_0_tensor_uid() != bnInfAttr.y_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation in_0 must be the batchnorm inference output tensor (y)");
|
|
}
|
|
|
|
// Check for virtual tensors
|
|
const auto& bnInfTensorX
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.x_tensor_uid());
|
|
const auto& bnInfTensorMean
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.mean_tensor_uid());
|
|
const auto& bnInfTensorInvVar
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.inv_variance_tensor_uid());
|
|
const auto& bnInfTensorScale
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.scale_tensor_uid());
|
|
const auto& bnInfTensorBias
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.bias_tensor_uid());
|
|
const auto& bnInfTensorY
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.y_tensor_uid());
|
|
|
|
if(bnInfTensorX.virtual_() || bnInfTensorMean.virtual_() || bnInfTensorInvVar.virtual_()
|
|
|| bnInfTensorScale.virtual_() || bnInfTensorBias.virtual_() || !bnInfTensorY.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm inference input tensors must be non-virtual, output tensor must be virtual");
|
|
}
|
|
|
|
const auto& actTensorIn0
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.in_0_tensor_uid());
|
|
const auto& actTensorOut
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.out_0_tensor_uid());
|
|
|
|
if(!actTensorIn0.virtual_() || actTensorOut.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation input from batchnorm must be virtual, output must be non virtual");
|
|
}
|
|
}
|
|
|
|
bool batchnormBwdFusionCheckTensorsLogErrors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormBackwardAttributes& bnBwdAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
try
|
|
{
|
|
batchnormBwdFusionCheckTensors(bnInfAttr, actAttr, bnBwdAttr, tensorMap);
|
|
return true;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool batchnormFwdFusionCheckTensorsLogErrors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
try
|
|
{
|
|
batchnormFwdFusionCheckTensors(bnInfAttr, actAttr, tensorMap);
|
|
return true;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void batchnormFwdFusionCheckTensors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributesVarianceExt& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
using PM = hipdnn_flatbuffers_sdk::data_objects::PointwiseMode;
|
|
static const std::unordered_set<PM> s_supportedActivations = {PM::RELU_FWD};
|
|
|
|
if(s_supportedActivations.count(actAttr.operation()) == 0)
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm fusion currently only supports RELU_FWD activation");
|
|
}
|
|
|
|
// in_0 must be the batchnorm inference output (forward path)
|
|
if(actAttr.in_0_tensor_uid() != bnInfAttr.y_tensor_uid())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation in_0 must be the batchnorm inference output tensor (y)");
|
|
}
|
|
|
|
// Check for virtual tensors
|
|
const auto& bnInfTensorX
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.x_tensor_uid());
|
|
const auto& bnInfTensorMean
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.mean_tensor_uid());
|
|
const auto& bnInfTensorVariance
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.variance_tensor_uid());
|
|
const auto& bnInfTensorScale
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.scale_tensor_uid());
|
|
const auto& bnInfTensorBias
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.bias_tensor_uid());
|
|
const auto& bnInfTensorY
|
|
= miopen_utils::findTensorAttributes(tensorMap, bnInfAttr.y_tensor_uid());
|
|
|
|
if(bnInfTensorX.virtual_() || bnInfTensorMean.virtual_() || bnInfTensorVariance.virtual_()
|
|
|| bnInfTensorScale.virtual_() || bnInfTensorBias.virtual_() || !bnInfTensorY.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Batchnorm inference input tensors must be non-virtual, output tensor must be virtual");
|
|
}
|
|
|
|
const auto& actTensorIn0
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.in_0_tensor_uid());
|
|
const auto& actTensorOut
|
|
= miopen_utils::findTensorAttributes(tensorMap, actAttr.out_0_tensor_uid());
|
|
|
|
if(!actTensorIn0.virtual_() || actTensorOut.virtual_())
|
|
{
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Activation input from batchnorm must be virtual, output must be non virtual");
|
|
}
|
|
}
|
|
|
|
bool batchnormFwdFusionCheckTensorsLogErrors(
|
|
const hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributesVarianceExt& bnInfAttr,
|
|
const hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes& actAttr,
|
|
const std::unordered_map<int64_t,
|
|
const hipdnn_flatbuffers_sdk::data_objects::TensorAttributes*>&
|
|
tensorMap)
|
|
{
|
|
try
|
|
{
|
|
batchnormFwdFusionCheckTensors(bnInfAttr, actAttr, tensorMap);
|
|
return true;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool MiopenBatchnormPlanBuilder::isApplicable(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph) const
|
|
{
|
|
// Execute-time override shapes can diverge from the compile-time dims this
|
|
// builder matched exactly; the plan bakes those dims into the MIOpen
|
|
// descriptors it builds, so decline rather than risk a mismatch (RFC 0008 §4.6).
|
|
if(opGraph.getGraph().is_override_shape_enabled())
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO("Batchnorm plan builder does not support override shapes");
|
|
return false;
|
|
}
|
|
|
|
auto anyNodeIsNotF32Compute = [&]() {
|
|
return !std::all_of(
|
|
opGraph.nodeWrappers().begin(), opGraph.nodeWrappers().end(), [](const auto& node) {
|
|
return node->computeDataType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::DataType::FLOAT;
|
|
});
|
|
};
|
|
|
|
switch(opGraph.nodeCount())
|
|
{
|
|
case 1:
|
|
{
|
|
if(anyNodeIsNotF32Compute())
|
|
{
|
|
HIPDNN_PLUGIN_LOG_ERROR("Batchnorm plan builder only supports nodes with an fp32 "
|
|
"compute_data_type");
|
|
return false;
|
|
}
|
|
|
|
if(!opGraph.hasOnlySupportedAttributes(std::set<hipdnn_flatbuffers_sdk::data_objects::
|
|
NodeAttributes>{
|
|
hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormAttributes,
|
|
hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormInferenceAttributes,
|
|
hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::
|
|
BatchnormInferenceAttributesVarianceExt,
|
|
hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormBackwardAttributes}))
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO("Batchnorm plan builder is not applicable for this graph");
|
|
return false;
|
|
}
|
|
|
|
const auto& node = opGraph.getNode(0);
|
|
|
|
// Only batchnorm training (BatchnormAttributes) has running statistics
|
|
if(node.attributes_type()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormAttributes)
|
|
{
|
|
const auto* attr = node.attributes_as_BatchnormAttributes();
|
|
if(attr != nullptr && attr->prev_running_mean_tensor_uid().has_value()
|
|
&& attr->prev_running_variance_tensor_uid().has_value()
|
|
&& attr->momentum_tensor_uid().has_value()
|
|
&& attr->next_running_mean_tensor_uid().has_value()
|
|
&& attr->next_running_variance_tensor_uid().has_value())
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Batchnorm plan builder does not support running statistics");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
switch(node.attributes_type())
|
|
{
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormAttributes:
|
|
checkBatchnormFwdTrainingTensorConfigSupported(
|
|
*node.attributes_as_BatchnormAttributes(), opGraph.getTensorMap());
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormInferenceAttributes:
|
|
checkBatchnormInferenceTensorConfigSupported(
|
|
*node.attributes_as_BatchnormInferenceAttributes(), opGraph.getTensorMap());
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::
|
|
BatchnormInferenceAttributesVarianceExt:
|
|
checkBatchnormInferenceVarianceExtTensorConfigSupported(
|
|
*node.attributes_as_BatchnormInferenceAttributesVarianceExt(),
|
|
opGraph.getTensorMap());
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormBackwardAttributes:
|
|
checkBatchnormBackwardTensorConfigSupported(
|
|
*node.attributes_as_BatchnormBackwardAttributes(), opGraph.getTensorMap());
|
|
break;
|
|
default:
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(HIPDNN_PLUGIN_STATUS_INTERNAL_ERROR,
|
|
"Unexpected node attribute type");
|
|
}
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
case 2:
|
|
{
|
|
if(anyNodeIsNotF32Compute())
|
|
{
|
|
HIPDNN_PLUGIN_LOG_ERROR("Batchnorm plan builder only supports nodes with an fp32 "
|
|
"compute_data_type");
|
|
return false;
|
|
}
|
|
|
|
const auto& node0 = opGraph.getNodeWrapper(0);
|
|
const auto& node1 = opGraph.getNodeWrapper(1);
|
|
|
|
const bool isFwdInferenceFirst
|
|
= node0.attributesType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormInferenceAttributes;
|
|
const bool isFwdInferenceWithVarianceFirst
|
|
= node0.attributesType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::
|
|
BatchnormInferenceAttributesVarianceExt;
|
|
const bool isPointwiseSecond
|
|
= node1.attributesType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::PointwiseAttributes;
|
|
|
|
if(!((isFwdInferenceFirst || isFwdInferenceWithVarianceFirst) && isPointwiseSecond))
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Batchnorm plan builder is not applicable for this graph node order and types");
|
|
return false;
|
|
}
|
|
|
|
if(isFwdInferenceFirst)
|
|
{
|
|
const auto& bnInfAttr = node0.attributesAs<
|
|
hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes>();
|
|
const auto& actAttr
|
|
= node1.attributesAs<hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes>();
|
|
if(!batchnormFwdFusionCheckTensorsLogErrors(bnInfAttr, actAttr, opGraph.getTensorMap()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Since MIOpen does not provide an API to validate batchnorm applicability, we perform
|
|
// the checks manually.
|
|
try
|
|
{
|
|
checkBatchnormInferenceActivationTensorConfigSupported(
|
|
bnInfAttr, actAttr, opGraph.getTensorMap());
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const auto& bnInfAttr = node0.attributesAs<
|
|
hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributesVarianceExt>();
|
|
const auto& actAttr
|
|
= node1.attributesAs<hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes>();
|
|
|
|
if(!batchnormFwdFusionCheckTensorsLogErrors(bnInfAttr, actAttr, opGraph.getTensorMap()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
checkBatchnormInferenceVarianceExtActivationTensorConfigSupported(
|
|
bnInfAttr, actAttr, opGraph.getTensorMap());
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
HIPDNN_PLUGIN_LOG_INFO("Batchnorm plan builder applicable for batchnorm inference + "
|
|
"activation fusion");
|
|
return true;
|
|
}
|
|
case 3:
|
|
{
|
|
// batchnorm inference -> activation -> batchnorm backward
|
|
if(anyNodeIsNotF32Compute())
|
|
{
|
|
HIPDNN_PLUGIN_LOG_ERROR("Batchnorm plan builder only supports nodes with an fp32 "
|
|
"compute_data_type");
|
|
return false;
|
|
}
|
|
const auto nodeAttrs = getBatchnormBackwardFusionNodeAttrsLogErrors(opGraph);
|
|
if(!nodeAttrs.has_value())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!batchnormBwdFusionCheckTensorsLogErrors(std::get<0>(nodeAttrs.value()),
|
|
std::get<1>(nodeAttrs.value()),
|
|
std::get<2>(nodeAttrs.value()),
|
|
opGraph.getTensorMap()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Since MIOpen does not provide an API to validate batchnorm applicability, we perform the
|
|
// checks manually.
|
|
try
|
|
{
|
|
checkBatchnormInferenceActivationBackwardTensorConfigSupported(
|
|
std::get<0>(nodeAttrs.value()),
|
|
std::get<1>(nodeAttrs.value()),
|
|
std::get<2>(nodeAttrs.value()),
|
|
opGraph.getTensorMap());
|
|
checkBatchnormBwdActivationModeSupported(std::get<1>(nodeAttrs.value()));
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(e.what());
|
|
return false;
|
|
}
|
|
|
|
HIPDNN_PLUGIN_LOG_INFO("Batchnorm plan builder applicable for batchnorm inference + "
|
|
"activation + batchnorm backward fusion");
|
|
return true;
|
|
}
|
|
default:
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Batchnorm plan builder is applicable only for 1, 2 or 3 node graphs. "
|
|
"Graph has "
|
|
<< opGraph.nodeCount() << " nodes");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t MiopenBatchnormPlanBuilder::getMaxWorkspaceSize(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
[[maybe_unused]] const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
[[maybe_unused]] const HipdnnMiopenSettings& executionSettings) const
|
|
{
|
|
// batchnorm plan builder does not require workspace size
|
|
return 0u;
|
|
}
|
|
|
|
void MiopenBatchnormPlanBuilder::initializeExecutionSettings(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
[[maybe_unused]] const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
[[maybe_unused]] const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IEngineConfig&
|
|
engineConfig,
|
|
[[maybe_unused]] HipdnnMiopenSettings& executionSettings) const
|
|
{
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
void buildPlanInferenceSingleNode(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::INodeWrapper& nodeWrapper,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& attr
|
|
= nodeWrapper
|
|
.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes>();
|
|
|
|
BatchnormFwdInferenceParams params(attr, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormFwdInferencePlan>(std::move(params),
|
|
executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanInferenceWithVarianceSingleNode(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::INodeWrapper& nodeWrapper,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& attr = nodeWrapper.attributesAs<
|
|
hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributesVarianceExt>();
|
|
|
|
BatchnormFwdInferenceWithVarianceParams params(attr, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormFwdInferenceWithVariancePlan>(
|
|
std::move(params), executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanFwdTrainingSingleNode(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::INodeWrapper& nodeWrapper,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& attr
|
|
= nodeWrapper.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormAttributes>();
|
|
|
|
BatchnormFwdTrainingParams params(attr, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormFwdTrainingPlan>(std::move(params),
|
|
executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanBwdSingleNode(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::INodeWrapper& nodeWrapper,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& attr
|
|
= nodeWrapper
|
|
.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormBackwardAttributes>();
|
|
|
|
BatchnormBwdParams params(attr, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormBwdPlan>(std::move(params),
|
|
executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanFusedBackwardsActivation(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto [bnInfAttr, actAttr, bnBwdAttr] = getBatchnormBackwardFusionNodeAttrs(opGraph);
|
|
batchnormBwdFusionCheckTensors(bnInfAttr, actAttr, bnBwdAttr, opGraph.getTensorMap());
|
|
|
|
BatchnormBwdParams params(bnBwdAttr, actAttr, bnInfAttr, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormBwdPlan>(std::move(params),
|
|
executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanFusedFwdInferenceActivation(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& node0 = opGraph.getNodeWrapper(0);
|
|
const auto& node1 = opGraph.getNodeWrapper(1);
|
|
|
|
const auto& fwdInference
|
|
= node0.attributesAs<hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributes>();
|
|
const auto& activation
|
|
= node1.attributesAs<hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes>();
|
|
|
|
BatchnormFwdInferenceParams params(fwdInference, activation, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormFwdInferencePlan>(std::move(params),
|
|
executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
void buildPlanFusedFwdInferenceWithVarianceActivation(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
HipdnnMiopenContext& executionContext)
|
|
{
|
|
const auto& node0 = opGraph.getNodeWrapper(0);
|
|
const auto& node1 = opGraph.getNodeWrapper(1);
|
|
|
|
const auto& fwdInference = node0.attributesAs<
|
|
hipdnn_flatbuffers_sdk::data_objects::BatchnormInferenceAttributesVarianceExt>();
|
|
const auto& activation
|
|
= node1.attributesAs<hipdnn_flatbuffers_sdk::data_objects::PointwiseAttributes>();
|
|
|
|
BatchnormFwdInferenceWithVarianceParams params(
|
|
fwdInference, activation, opGraph.getTensorMap());
|
|
auto plan = std::make_unique<BatchnormFwdInferenceWithVariancePlan>(
|
|
std::move(params), executionContext.executionSettings());
|
|
executionContext.setPlan(std::move(plan));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void MiopenBatchnormPlanBuilder::buildPlan(
|
|
const HipdnnMiopenHandle& handle,
|
|
const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph,
|
|
[[maybe_unused]] const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IEngineConfig&
|
|
engineConfig,
|
|
HipdnnMiopenContext& executionContext) const
|
|
{
|
|
if(opGraph.nodeCount() == 2)
|
|
{
|
|
const auto& node0 = opGraph.getNodeWrapper(0);
|
|
if(node0.attributesType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormInferenceAttributes)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO("Building batchnorm inference + activation fusion plan");
|
|
buildPlanFusedFwdInferenceActivation(handle, opGraph, executionContext);
|
|
}
|
|
else if(node0.attributesType()
|
|
== hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::
|
|
BatchnormInferenceAttributesVarianceExt)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Building batchnorm inference with variance + activation fusion plan");
|
|
buildPlanFusedFwdInferenceWithVarianceActivation(handle, opGraph, executionContext);
|
|
}
|
|
return;
|
|
}
|
|
if(opGraph.nodeCount() == 3)
|
|
{
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Building batchnorm inference + activation + batchnorm backward fusion plan");
|
|
buildPlanFusedBackwardsActivation(handle, opGraph, executionContext);
|
|
return;
|
|
}
|
|
|
|
const auto& nodeWrapper = opGraph.getNodeWrapper(0);
|
|
const auto nodeName = nodeWrapper.name();
|
|
|
|
switch(nodeWrapper.attributesType())
|
|
{
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormInferenceAttributes:
|
|
HIPDNN_PLUGIN_LOG_INFO("Building batchnorm fwd inference plan for node: " << nodeName);
|
|
buildPlanInferenceSingleNode(handle, opGraph, nodeWrapper, executionContext);
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::
|
|
BatchnormInferenceAttributesVarianceExt:
|
|
HIPDNN_PLUGIN_LOG_INFO(
|
|
"Building batchnorm fwd inference with variance plan for node: " << nodeName);
|
|
buildPlanInferenceWithVarianceSingleNode(handle, opGraph, nodeWrapper, executionContext);
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormAttributes:
|
|
HIPDNN_PLUGIN_LOG_INFO("Building batchnorm fwd training plan for node: " << nodeName);
|
|
buildPlanFwdTrainingSingleNode(handle, opGraph, nodeWrapper, executionContext);
|
|
break;
|
|
case hipdnn_flatbuffers_sdk::data_objects::NodeAttributes::BatchnormBackwardAttributes:
|
|
HIPDNN_PLUGIN_LOG_INFO("Building batchnorm backward plan for node: " << nodeName);
|
|
buildPlanBwdSingleNode(handle, opGraph, nodeWrapper, executionContext);
|
|
break;
|
|
default:
|
|
throw hipdnn_plugin_sdk::HipdnnPluginException(
|
|
HIPDNN_PLUGIN_STATUS_BAD_PARAM,
|
|
"Unsupported node type for batchnorm plan builder: "
|
|
+ std::string(
|
|
hipdnn_flatbuffers_sdk::data_objects::toString(nodeWrapper.attributesType())));
|
|
}
|
|
}
|
|
|
|
std::vector<hipdnn_flatbuffers_sdk::data_objects::KnobT> MiopenBatchnormPlanBuilder::getCustomKnobs(
|
|
[[maybe_unused]] const HipdnnMiopenHandle& handle,
|
|
[[maybe_unused]] const hipdnn_flatbuffers_sdk::flatbuffer_utilities::IGraph& opGraph) const
|
|
{
|
|
return {};
|
|
}
|
|
|
|
} // namespace miopen_plugin
|