// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once #include "core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h" #include "core/common//common.h" struct NoisyReluShapeInferrer : winrt::implements { STDMETHOD(InferOutputShapes)(IMLOperatorShapeInferenceContext* context) noexcept { try { uint32_t inputDimsSize; context->GetInputTensorDimensionCount(0, &inputDimsSize); uint32_t* inputDims = new uint32_t[inputDimsSize]; context->GetInputTensorShape(0, inputDimsSize, inputDims); context->SetOutputTensorShape(0, inputDimsSize, inputDims); return S_OK; } catch (...) { return winrt::to_hresult(); } } }; struct NoisyReluOperator : winrt::implements { float m_mean; float m_variance; NoisyReluOperator(float mean, float variance) : m_mean(mean), m_variance(variance) {} // Computes the outputs of the kernel. This may be called multiple times // simultaneously within the same instance of the class. Implementations // of this method must be thread-safe. STDMETHOD(Compute)(IMLOperatorKernelContext* context) { try { // Get the input tensor winrt::com_ptr inputTensor; context->GetInputTensor(0, inputTensor.put()); // Get the output tensor winrt::com_ptr outputTensor; context->GetOutputTensor(0, outputTensor.put()); // Get the input and output shape sizes uint32_t inputDimsSize = inputTensor->GetDimensionCount(); uint32_t outputDimsSize = outputTensor->GetDimensionCount(); if (inputDimsSize != outputDimsSize) { return E_UNEXPECTED; } // Get the input shape std::vector inputDims(inputDimsSize); outputTensor->GetShape(inputDimsSize, inputDims.data()); // Get the output shape std::vector outputDims(outputDimsSize); outputTensor->GetShape(outputDimsSize, outputDims.data()); // For the number of total elements in the input and output shapes auto outputDataSize = std::accumulate(outputDims.begin(), outputDims.end(), 1, std::multiplies()); auto inputDataSize = std::accumulate(inputDims.begin(), inputDims.end(), 1, std::multiplies()); if (outputDataSize != inputDataSize) { return E_UNEXPECTED; } // If the tensor types are both float type if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Float) { // For cpu data if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); } } else if (outputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double && inputTensor->GetTensorDataType() == MLOperatorTensorDataType::Double) { // For cpu data if (outputTensor->IsCpuData() && inputTensor->IsCpuData()) { ComputeInternal(inputTensor.get(), outputTensor.get(), inputDataSize); } } return S_OK; } catch (...) { return winrt::to_hresult(); } } template void ComputeInternal(IMLOperatorTensor* pInputTensor, IMLOperatorTensor* pOutputTensor, uint32_t size) { // Create a normal distribution std::normal_distribution<> dist{m_mean, m_variance}; std::random_device rd{}; std::mt19937 gen{rd()}; auto inputData = static_cast(pInputTensor->GetData()); auto outputData = static_cast(pOutputTensor->GetData()); for (uint32_t i = 0; i < size; i++) { outputData[i] = static_cast(std::max(0, static_cast(inputData[i] + dist(gen)))); } } }; struct NoisyReluOperatorFactory : winrt::implements { STDMETHOD(CreateKernel)(IMLOperatorKernelCreationContext* context, IMLOperatorKernel** kernel) { try { float mean; context->GetAttribute("mean", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&mean)); float variance; context->GetAttribute( "variance", MLOperatorAttributeType::Float, 1, sizeof(float), reinterpret_cast(&variance) ); auto noisyReluOperator = winrt::make(mean, variance); noisyReluOperator.copy_to(kernel); return S_OK; } catch (...) { return winrt::to_hresult(); } } static MLOperatorEdgeDescription CreateEdgeDescriptor(MLOperatorEdgeType type, MLOperatorTensorDataType dataType) { ORT_UNUSED_PARAMETER(type); MLOperatorEdgeDescription desc; desc.edgeType = MLOperatorEdgeType::Tensor; desc.tensorDataType = dataType; return desc; } static void RegisterNoisyReluSchema(winrt::com_ptr registry) { MLOperatorSetId operatorSetId; operatorSetId.domain = ""; operatorSetId.version = 7; MLOperatorSchemaDescription noisyReluSchema; noisyReluSchema.name = "NoisyRelu"; noisyReluSchema.operatorSetVersionAtLastChange = 1; MLOperatorSchemaEdgeDescription noisyReluXInput; noisyReluXInput.options = MLOperatorParameterOptions::Single; noisyReluXInput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; noisyReluXInput.typeLabel = "T"; std::vector inputs{noisyReluXInput}; noisyReluSchema.inputs = inputs.data(); noisyReluSchema.inputCount = static_cast(inputs.size()); MLOperatorSchemaEdgeDescription noisyReluXOutput; noisyReluXOutput.options = MLOperatorParameterOptions::Single; noisyReluXOutput.typeFormat = MLOperatorSchemaEdgeTypeFormat::Label; noisyReluXOutput.typeLabel = "T"; std::vector outputs{noisyReluXOutput}; noisyReluSchema.outputs = outputs.data(); noisyReluSchema.outputCount = static_cast(outputs.size()); MLOperatorEdgeTypeConstrant typeConstraint; typeConstraint.typeLabel = "T"; std::vector allowedEdges{ CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) }; typeConstraint.allowedTypes = allowedEdges.data(); typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); std::vector typeConstraints{typeConstraint}; noisyReluSchema.typeConstraints = typeConstraints.data(); noisyReluSchema.typeConstraintCount = static_cast(typeConstraints.size()); MLOperatorAttribute noisyReluMeanAttribute; noisyReluMeanAttribute.name = "mean"; noisyReluMeanAttribute.required = false; noisyReluMeanAttribute.type = MLOperatorAttributeType::Float; MLOperatorAttribute noisyReluVarianceAttribute; noisyReluVarianceAttribute.name = "variance"; noisyReluVarianceAttribute.required = false; noisyReluVarianceAttribute.type = MLOperatorAttributeType::Float; std::vector attributes{noisyReluMeanAttribute, noisyReluVarianceAttribute}; noisyReluSchema.attributes = attributes.data(); noisyReluSchema.attributeCount = static_cast(attributes.size()); MLOperatorAttributeNameValue noisyReluMeanAttributeValue; noisyReluMeanAttributeValue.name = "mean"; noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; noisyReluMeanAttributeValue.valueCount = 1; static float defaultMeans[] = {0.f}; noisyReluMeanAttributeValue.floats = defaultMeans; MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; noisyReluVarianceAttributeValue.name = "variance"; noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; noisyReluVarianceAttributeValue.valueCount = 1; static float defaultVariance[] = {1.f}; noisyReluVarianceAttributeValue.floats = defaultVariance; std::vector attributeDefaultValues{ noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue }; noisyReluSchema.defaultAttributes = attributeDefaultValues.data(); noisyReluSchema.defaultAttributeCount = static_cast(attributeDefaultValues.size()); std::vector schemas{&noisyReluSchema}; registry->RegisterOperatorSetSchema( &operatorSetId, 6 /* baseline version */, schemas.data(), static_cast(schemas.size()), nullptr, nullptr ); } static void RegisterNoisyReluKernel(winrt::com_ptr registry) { MLOperatorKernelDescription kernelDescription; kernelDescription.domain = ""; kernelDescription.name = "NoisyRelu"; kernelDescription.minimumOperatorSetVersion = 1; kernelDescription.executionType = MLOperatorExecutionType::Cpu; MLOperatorEdgeTypeConstrant typeConstraint; typeConstraint.typeLabel = "T"; std::vector allowedEdges{ CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Double), CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float), CreateEdgeDescriptor(MLOperatorEdgeType::Tensor, MLOperatorTensorDataType::Float16) }; typeConstraint.allowedTypes = allowedEdges.data(); typeConstraint.allowedTypeCount = static_cast(allowedEdges.size()); std::vector typeConstraints{typeConstraint}; kernelDescription.typeConstraints = typeConstraints.data(); kernelDescription.typeConstraintCount = static_cast(typeConstraints.size()); MLOperatorAttributeNameValue noisyReluMeanAttributeValue; noisyReluMeanAttributeValue.name = "mean"; noisyReluMeanAttributeValue.type = MLOperatorAttributeType::Float; noisyReluMeanAttributeValue.valueCount = 1; static float defaultMeans[] = {0.f}; noisyReluMeanAttributeValue.floats = defaultMeans; MLOperatorAttributeNameValue noisyReluVarianceAttributeValue; noisyReluVarianceAttributeValue.name = "variance"; noisyReluVarianceAttributeValue.type = MLOperatorAttributeType::Float; noisyReluVarianceAttributeValue.valueCount = 1; static float defaultVariance[] = {1.f}; noisyReluVarianceAttributeValue.floats = defaultVariance; std::vector attributeDefaultValues{ noisyReluMeanAttributeValue, noisyReluVarianceAttributeValue }; kernelDescription.defaultAttributes = attributeDefaultValues.data(); kernelDescription.defaultAttributeCount = static_cast(attributeDefaultValues.size()); kernelDescription.options = MLOperatorKernelOptions::None; kernelDescription.executionOptions = 0; auto factory = winrt::make(); auto shareInferrer = winrt::make(); registry->RegisterOperatorKernel(&kernelDescription, factory.get(), shareInferrer.get()); } };