diff --git a/docs/MO_DG/prepare_model/Supported_Frameworks_Layers.md b/docs/MO_DG/prepare_model/Supported_Frameworks_Layers.md index be1918ae621..10c1f974292 100644 --- a/docs/MO_DG/prepare_model/Supported_Frameworks_Layers.md +++ b/docs/MO_DG/prepare_model/Supported_Frameworks_Layers.md @@ -98,7 +98,7 @@ Standard MXNet\* symbols: | InstanceNorm | No | | L2Normalization | only 4D input is supported | | LRN | No | -| LeakyReLU | No | +| LeakyReLU | supported "act_type" = "prelu", "elu", "leaky", "gelu" | | Pad | No | | Pooling | No | | ROIPooling | No | diff --git a/docs/doxygen/ie_docs.xml b/docs/doxygen/ie_docs.xml index 07d9df15051..bbf8443fb07 100644 --- a/docs/doxygen/ie_docs.xml +++ b/docs/doxygen/ie_docs.xml @@ -82,6 +82,7 @@ limitations under the License. + @@ -145,6 +146,7 @@ limitations under the License. + diff --git a/docs/ops/activation/GELU_7.md b/docs/ops/activation/GELU_7.md new file mode 100644 index 00000000000..1619894d173 --- /dev/null +++ b/docs/ops/activation/GELU_7.md @@ -0,0 +1,89 @@ +## GELU- Gaussian Error Linear Unit {#openvino_docs_ops_activation_GELU_7} + +**Versioned name**: *Gelu-7* + +**Category**: *Activation* + +**Short description**: Calculates Gaussian error linear. + +**Detailed description**: `Gelu(x) = x * Φ(x)`, where `Φ(x)` is the Cumulative Distribution Function for Gaussian Distribution. +The Gelu operation is introduced in the [paper](https://arxiv.org/abs/1606.08415). + +**Attributes** + +* *approximation_mode* + + * **Description**: Specifies the formulae to calculate the output. + * **Range of values**: + * `erf` -- calculate output using the Gauss error function. + * `tanh` -- calculate output using tanh approximation + * **Type**: `string` + * **Default value**: `erf` + * **Required**: *no* + + +**Mathematical Formulation** + +For the `erf` approximation mode: +\f[ + Gelu(x) = 0.5 \cdot x \cdot (1.0 + erf((x) / \sqrt{2}) +\f] + +For the `tanh` approximation mode: + +\f[ + Gelu(x) \approx 0.5 \cdot x \cdot (1.0 + tanh(\sqrt{2.0/pi} \cdot (x + 0.044715 \cdot x ^ 3)) +\f] + +**Inputs**: + +* **1**: Multidimensional input tensor of type *T*. Required. + +**Outputs**: + +* **1**: Floating point tensor with shape and type *T* matching the input tensor. + +**Types** + +* *T*: any floating point type. + +**Examples** + +```xml + + + + + 1 + 128 + + + + + 1 + 128 + + + +``` + +```xml + + + + + 3 + 7 + 9 + + + + + 3 + 7 + 9 + + + + +``` diff --git a/docs/ops/opset.md b/docs/ops/opset.md index 72c72549d02..e114f5b2267 100644 --- a/docs/ops/opset.md +++ b/docs/ops/opset.md @@ -6,6 +6,7 @@ This topic provides a complete list of available sets of operations supported in | OpenVINO™ Version | Actual Operations Set | | :---------------- | :------------------------------- | +| 2021.4 | [opset7](opset7.md) | | 2021.3 | [opset6](opset6.md) | | 2021.2 | [opset5](opset5.md) | | 2021.1 | [opset4](opset4.md) | diff --git a/docs/ops/opset7.md b/docs/ops/opset7.md new file mode 100644 index 00000000000..a5fe09684db --- /dev/null +++ b/docs/ops/opset7.md @@ -0,0 +1,158 @@ +# Operation Set `opset7` Specification {#openvino_docs_ops_opset7} + +This specification document describes `opset7` operation set supported in OpenVINO. +Support for each particular operation from the list below depends on the capabilities available in a inference plugin +and may vary among different hardware platforms and devices. Examples of operation instances are expressed as IR V10 xml +snippets. Such IR is generated by the Model Optimizer. The semantics match corresponding nGraph operation classes +declared in `namespace opset7`. + + +## Table of Contents + +* [Abs](arithmetic/Abs_1.md) +* [Acos](arithmetic/Acos_1.md) +* [Acosh](arithmetic/Acosh_3.md) +* [Add](arithmetic/Add_1.md) +* [Asin](arithmetic/Asin_1.md) +* [Asinh](arithmetic/Asinh_3.md) +* [Assign](infrastructure/Assign_3.md) +* [Atan](arithmetic/Atan_1.md) +* [Atanh](arithmetic/Atanh_3.md) +* [AvgPool](pooling/AvgPool_1.md) +* [BatchNormInference](normalization/BatchNormInference_5.md) +* [BatchToSpace](movement/BatchToSpace_2.md) +* [BinaryConvolution](convolution/BinaryConvolution_1.md) +* [Broadcast](movement/Broadcast_3.md) +* [Bucketize](condition/Bucketize_3.md) +* [CTCGreedyDecoder](sequence/CTCGreedyDecoder_1.md) +* [CTCGreedyDecoderSeqLen](sequence/CTCGreedyDecoderSeqLen_6.md) +* [CTCLoss](sequence/CTCLoss_4.md) +* [Ceiling](arithmetic/Ceiling_1.md) +* [Clamp](activation/Clamp_1.md) +* [Concat](movement/Concat_1.md) +* [Constant](infrastructure/Constant_1.md) +* [Convert](type/Convert_1.md) +* [ConvertLike](type/ConvertLike_1.md) +* [Convolution](convolution/Convolution_1.md) +* [ConvolutionBackpropData](convolution/ConvolutionBackpropData_1.md) +* [Cos](arithmetic/Cos_1.md) +* [Cosh](arithmetic/Cosh_1.md) +* [CumSum](arithmetic/CumSum_3.md) +* [DeformableConvolution](convolution/DeformableConvolution_1.md) +* [DeformablePSROIPooling](detection/DeformablePSROIPooling_1.md) +* [DepthToSpace](movement/DepthToSpace_1.md) +* [DetectionOutput](detection/DetectionOutput_1.md) +* [Divide](arithmetic/Divide_1.md) +* [Elu](activation/Elu_1.md) +* [EmbeddingBagOffsetsSum](sparse/EmbeddingBagOffsetsSum_3.md) +* [EmbeddingBagPackedSum](sparse/EmbeddingBagPackedSum_3.md) +* [EmbeddingSegmentsSum](sparse/EmbeddingSegmentsSum_3.md) +* [Equal](comparison/Equal_1.md) +* [Erf](arithmetic/Erf_1.md) +* [Exp](activation/Exp_1.md) +* [ExtractImagePatches](movement/ExtractImagePatches_3.md) +* [FakeQuantize](quantization/FakeQuantize_1.md) +* [Floor](arithmetic/Floor_1.md) +* [FloorMod](arithmetic/FloorMod_1.md) +* [Gather](movement/Gather_1.md) +* [GatherElements](movement/GatherElements_6.md) +* [GatherND_5](movement/GatherND_5.md) +* [GatherTree](movement/GatherTree_1.md) +* [Gelu](activation/GELU_7.md) +* [Greater](comparison/Greater_1.md) +* [GreaterEqual](comparison/GreaterEqual_1.md) +* [GRN](normalization/GRN_1.md) +* [GroupConvolution](convolution/GroupConvolution_1.md) +* [GroupConvolutionBackpropData](convolution/GroupConvolutionBackpropData_1.md) +* [GRUCell](sequence/GRUCell_3.md) +* [GRUSequence](sequence/GRUSequence_5.md) +* [HardSigmoid](activation/HardSigmoid_1.md) +* [HSigmoid](activation/HSigmoid_5.md) +* [HSwish](activation/HSwish_4.md) +* [Interpolate](image/Interpolate_4.md) +* [Less](comparison/Less_1.md) +* [LessEqual](comparison/LessEqual_1.md) +* [Log](arithmetic/Log_1.md) +* [LogicalAnd](logical/LogicalAnd_1.md) +* [LogicalNot](logical/LogicalNot_1.md) +* [LogicalOr](logical/LogicalOr_1.md) +* [LogicalXor](logical/LogicalXor_1.md) +* [LogSoftmax](activation/LogSoftmax_5.md) +* [Loop](infrastructure/Loop_5.md) +* [LRN](normalization/LRN_1.md) +* [LSTMCell](sequence/LSTMCell_1.md) +* [LSTMSequence](sequence/LSTMSequence_1.md) +* [MatMul](matrix/MatMul_1.md) +* [MaxPool](pooling/MaxPool_1.md) +* [Maximum](arithmetic/Maximum_1.md) +* [Minimum](arithmetic/Minimum_1.md) +* [Mish](activation/Mish_4.md) +* [Mod](arithmetic/Mod_1.md) +* [MVN](normalization/MVN_6.md) +* [Multiply](arithmetic/Multiply_1.md) +* [Negative](arithmetic/Negative_1.md) +* [NonMaxSuppression](sort/NonMaxSuppression_5.md) +* [NonZero](condition/NonZero_3.md) +* [NormalizeL2](normalization/NormalizeL2_1.md) +* [NotEqual](comparison/NotEqual_1.md) +* [OneHot](sequence/OneHot_1.md) +* [Pad](movement/Pad_1.md) +* [Parameter](infrastructure/Parameter_1.md) +* [Power](arithmetic/Power_1.md) +* [PReLU](activation/PReLU_1.md) +* [PriorBoxClustered](detection/PriorBoxClustered_1.md) +* [PriorBox](detection/PriorBox_1.md) +* [Proposal](detection/Proposal_4.md) +* [PSROIPooling](detection/PSROIPooling_1.md) +* [Range](generation/Range_4.md) +* [ReLU](activation/ReLU_1.md) +* [ReadValue](infrastructure/ReadValue_3.md) +* [ReduceL1](reduction/ReduceL1_4.md) +* [ReduceL2](reduction/ReduceL2_4.md) +* [ReduceLogicalAnd](reduction/ReduceLogicalAnd_1.md) +* [ReduceLogicalOr](reduction/ReduceLogicalOr_1.md) +* [ReduceMax](reduction/ReduceMax_1.md) +* [ReduceMean](reduction/ReduceMean_1.md) +* [ReduceMin](reduction/ReduceMin_1.md) +* [ReduceProd](reduction/ReduceProd_1.md) +* [ReduceSum](reduction/ReduceSum_1.md) +* [RegionYolo](detection/RegionYolo_1.md) +* [ReorgYolo](detection/ReorgYolo_1.md) +* [Reshape](shape/Reshape_1.md) +* [Result](infrastructure/Result_1.md) +* [ReverseSequence](movement/ReverseSequence_1.md) +* [RNNCell](sequence/RNNCell_3.md) +* [RNNSequence](sequence/RNNSequence_5.md) +* [ROIAlign](detection/ROIAlign_3.md) +* [ROIPooling](detection/ROIPooling_1.md) +* [Round](arithmetic/Round_5.md) +* [ScatterElementsUpdate](movement/ScatterElementsUpdate_3.md) +* [ScatterNDUpdate](movement/ScatterNDUpdate_3.md) +* [ScatterUpdate](movement/ScatterUpdate_3.md) +* [Select](condition/Select_1.md) +* [Selu](arithmetic/Selu_1.md) +* [ShapeOf](shape/ShapeOf_3.md) +* [ShuffleChannels](movement/ShuffleChannels_1.md) +* [Sigmoid](activation/Sigmoid_1.md) +* [Sign](arithmetic/Sign_1.md) +* [Sin](arithmetic/Sin_1.md) +* [Sinh](arithmetic/Sinh_1.md) +* [SoftMax](activation/SoftMax_1.md) +* [SoftPlus](activation/SoftPlus_4.md) +* [SpaceToBatch](movement/SpaceToBatch_2.md) +* [SpaceToDepth](movement/SpaceToDepth_1.md) +* [Split](movement/Split_1.md) +* [Sqrt](arithmetic/Sqrt_1.md) +* [SquaredDifference](arithmetic/SquaredDifference_1.md) +* [Squeeze](shape/Squeeze_1.md) +* [StridedSlice](movement/StridedSlice_1.md) +* [Subtract](arithmetic/Subtract_1.md) +* [Swish](activation/Swish_4.md) +* [Tan](arithmetic/Tan_1.md) +* [Tanh](arithmetic/Tanh_1.md) +* [TensorIterator](infrastructure/TensorIterator_1.md) +* [Tile](movement/Tile_1.md) +* [TopK](sort/TopK_3.md) +* [Transpose](movement/Transpose_1.md) +* [Unsqueeze](shape/Unsqueeze_1.md) +* [VariadicSplit](movement/VariadicSplit_1.md) diff --git a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp index 75a0841d8f6..862ee03fb0e 100644 --- a/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp +++ b/inference-engine/src/mkldnn_plugin/mkldnn_plugin.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,7 @@ static void Transformation(CNNNetwork& clonedNetwork, const Config& conf) { // List of enabled/disabled transformations pass_config->disable(); + pass_config->disable(); pass_config->disable(); pass_config->disable(); pass_config->disable(); diff --git a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp index 213f50f78b2..8d86b5a7bc7 100644 --- a/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp +++ b/inference-engine/src/readers/ir_reader/ie_ir_parser.cpp @@ -865,6 +865,7 @@ V10Parser::V10Parser(const std::vector& exts) : _exts(exts) { opsets["opset4"] = ngraph::get_opset4(); opsets["opset5"] = ngraph::get_opset5(); opsets["opset6"] = ngraph::get_opset6(); + opsets["opset7"] = ngraph::get_opset7(); // Load custom opsets for (const auto& ext : exts) { diff --git a/inference-engine/src/transformations/include/transformations/op_conversions/gelu7_downgrade.hpp b/inference-engine/src/transformations/include/transformations/op_conversions/gelu7_downgrade.hpp new file mode 100644 index 00000000000..dc538f37635 --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/op_conversions/gelu7_downgrade.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ngraph { +namespace pass { + + class TRANSFORMATIONS_API Gelu7Downgrade; + +} // namespace pass +} // namespace ngraph + +/** + * @ingroup ie_transformation_common_api + * @brief Gelu7Downgrade converts v7::Gelu operation to v2::Gelu unconditionally. This is done because only limited + * set of plugins support v7::Gelu which has an attribute specifying approximation mode. For other plugins the + * behaviour is to use v2 version of the operation which does not support the approximation mode. + */ +class ngraph::pass::Gelu7Downgrade : public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + Gelu7Downgrade(); +}; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp index cba231b2aa9..ca0fe06eb19 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp @@ -15,7 +15,6 @@ #include "transformations/common_optimizations/fq_reshape_fusion.hpp" #include "transformations/common_optimizations/depth_to_space_fusion.hpp" #include "transformations/common_optimizations/optimize_strided_slice.hpp" -#include "transformations/common_optimizations/mish_fusion.hpp" #include "transformations/common_optimizations/softplus_fusion.hpp" #include "transformations/common_optimizations/softplus_to_mish_fusion.hpp" #include "transformations/common_optimizations/swish_fusion.hpp" @@ -45,6 +44,7 @@ #include "transformations/op_conversions/convert_gelu.hpp" #include "transformations/op_conversions/convert_interpolate1_to_interpolate4.hpp" #include "transformations/op_conversions/batch_norm_decomposition.hpp" +#include "transformations/op_conversions/gelu7_downgrade.hpp" #include "transformations/op_conversions/reduce_l1_decomposition.hpp" #include "transformations/op_conversions/reduce_l2_decomposition.hpp" #include "transformations/op_conversions/hswish_decomposition.hpp" @@ -102,6 +102,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr(); auto decomp = manager.register_pass(); + decomp->add_matcher(); decomp->add_matcher(); decomp->add_matcher(); decomp->add_matcher(); diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/convert_gelu.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/convert_gelu.cpp index a3c683d1537..4ac7b88476a 100644 --- a/inference-engine/src/transformations/src/transformations/op_conversions/convert_gelu.cpp +++ b/inference-engine/src/transformations/src/transformations/op_conversions/convert_gelu.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/gelu7_downgrade.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/gelu7_downgrade.cpp new file mode 100644 index 00000000000..d9ec7a162db --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/op_conversions/gelu7_downgrade.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/gelu7_downgrade.hpp" + +#include + +#include +#include +#include +#include +#include "itt.hpp" + +NGRAPH_RTTI_DEFINITION(ngraph::pass::Gelu7Downgrade, "Gelu7Downgrade", 0); + +ngraph::pass::Gelu7Downgrade::Gelu7Downgrade() { + MATCHER_SCOPE(Gelu7Downgrade); + auto gelu = ngraph::pattern::wrap_type(); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher& m) { + auto& pattern_to_output = m.get_pattern_value_map(); + auto gelu_node = std::dynamic_pointer_cast(pattern_to_output.at(gelu).get_node_shared_ptr()); + + if (gelu_node == nullptr || transformation_callback(gelu_node)) { + return false; + } + + auto new_gelu_node = std::make_shared(gelu_node->input_value(0)); + new_gelu_node->set_friendly_name(gelu_node->get_friendly_name()); + ngraph::copy_runtime_info(gelu_node, new_gelu_node); + ngraph::replace_node(gelu_node, new_gelu_node); + return true; + }; + + auto m = std::make_shared(gelu, matcher_name); + register_matcher(m, callback); +} diff --git a/inference-engine/src/transformations/src/transformations/serialize.cpp b/inference-engine/src/transformations/src/transformations/serialize.cpp index 2336b8f95f3..7457b97e560 100644 --- a/inference-engine/src/transformations/src/transformations/serialize.cpp +++ b/inference-engine/src/transformations/src/transformations/serialize.cpp @@ -392,9 +392,10 @@ const std::vector create_edge_mapping( std::string get_opset_name( const ngraph::Node* n, const std::map& custom_opsets) { - auto opsets = std::array, 6>{ + auto opsets = std::array, 7>{ ngraph::get_opset1(), ngraph::get_opset2(), ngraph::get_opset3(), - ngraph::get_opset4(), ngraph::get_opset5(), ngraph::get_opset6()}; + ngraph::get_opset4(), ngraph::get_opset5(), ngraph::get_opset6(), + ngraph::get_opset7()}; auto special_opset = get_special_opset_for_op(n->get_type_info()); if (!special_opset.empty()) { diff --git a/inference-engine/tests/functional/inference_engine/ngraph_reader/gelu_tests.cpp b/inference-engine/tests/functional/inference_engine/ngraph_reader/gelu_tests.cpp index 4e3b508014a..bf603a0e931 100644 --- a/inference-engine/tests/functional/inference_engine/ngraph_reader/gelu_tests.cpp +++ b/inference-engine/tests/functional/inference_engine/ngraph_reader/gelu_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2020 Intel Corporation +// Copyright (C) 2018-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 // @@ -32,103 +32,103 @@ TEST_F(NGraphReaderTests, ReadGeluNetwork) { std::string model_v7 = R"V0G0N( - - - - - 1 - 128 - - - - - - - - 1 - 128 - - - - - 1 - 128 - - - - - - - - 1 - 128 - - - - - 1 - 128 - - - - - - - 1 - 128 - - - - - 1 - 128 - - - - - - - - 1 - 128 - - - - - 1 - 128 - - - - - - - - 1 - 128 - - - 1 - 128 - - - - - 1 - 128 - - - - - - - - - - - - - + + + + + 1 + 128 + + + + + + + + 1 + 128 + + + + + 1 + 128 + + + + + + + + 1 + 128 + + + + + 1 + 128 + + + + + + + 1 + 128 + + + + + 1 + 128 + + + + + + + + 1 + 128 + + + + + 1 + 128 + + + + + + + + 1 + 128 + + + 1 + 128 + + + + + 1 + 128 + + + + + + + + + + + + + )V0G0N"; @@ -136,3 +136,174 @@ TEST_F(NGraphReaderTests, ReadGeluNetwork) { compareIRs(model_v10, model_v7, 0); } + + +TEST_F(NGraphReaderTests, ReadGelu6TanhNetwork) { + std::string model = R"V0G0N( + + + + + + + 1 + 3 + 4 + + + + + + + + 1 + 3 + 4 + + + + + 1 + 3 + 4 + + + + + + + 1 + 3 + 4 + + + + + + + + + +)V0G0N"; + std::string modelV7 = R"V0G0N( + + + + + + 1 + 3 + 4 + + + + + + + + 1 + 3 + 4 + + + + + 1 + 3 + 4 + + + + + + + + +)V0G0N"; + compareIRs(model, modelV7); +} + +TEST_F(NGraphReaderTests, ReadGelu6ErfNetwork) { + std::string model = R"V0G0N( + + + + + + + 1 + 3 + 4 + + + + + + + + 1 + 3 + 4 + + + + + 1 + 3 + 4 + + + + + + + 1 + 3 + 4 + + + + + + + + + +)V0G0N"; + std::string modelV7 = R"V0G0N( + + + + + + 1 + 3 + 4 + + + + + + + + 1 + 3 + 4 + + + + + 1 + 3 + 4 + + + + + + + + +)V0G0N"; + compareIRs(model, modelV7); +} \ No newline at end of file diff --git a/inference-engine/tests/functional/inference_engine/transformations/gelu7_downgrade.cpp b/inference-engine/tests/functional/inference_engine/transformations/gelu7_downgrade.cpp new file mode 100644 index 00000000000..c17a4fc39d2 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/gelu7_downgrade.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + + +#include +#include +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +using namespace testing; + +TEST(TransformationTests, Gelu7Downgrade) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 2, 3}); + auto gelu = std::make_shared(input, ngraph::op::GeluApproximationMode::ERF); + gelu->set_friendly_name("gelu7"); + + f = std::make_shared(ngraph::NodeVector{gelu}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{1, 2, 3}); + auto gelu = std::make_shared(input); + gelu->set_friendly_name("gelu7"); + + f_ref = std::make_shared(ngraph::NodeVector{gelu}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; + + auto result_node_of_converted_f = f->get_output_op(0); + auto output_node = result_node_of_converted_f->input(0).get_source_output().get_node_shared_ptr(); + ASSERT_TRUE(output_node->get_friendly_name() == "gelu7") << "Transformation Gelu7Downgrade should keep output names.\n"; +} + diff --git a/inference-engine/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp b/inference-engine/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp index d26b00bf45b..b490ee1093f 100644 --- a/inference-engine/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp +++ b/inference-engine/tests/functional/shared_test_classes/src/base/layer_test_utils.cpp @@ -73,6 +73,7 @@ void TestEnvironment::TearDown() { opsets.push_back(ngraph::get_opset4()); opsets.push_back(ngraph::get_opset5()); opsets.push_back(ngraph::get_opset6()); + opsets.push_back(ngraph::get_opset7()); std::set opsInfo; for (const auto &opset : opsets) { const auto &type_info_set = opset.get_type_info_set(); diff --git a/model-optimizer/extensions/front/GeLUMerger_Erf.py b/model-optimizer/extensions/front/GeLUMerger_Erf.py index d95fe2c8dff..8620171af44 100644 --- a/model-optimizer/extensions/front/GeLUMerger_Erf.py +++ b/model-optimizer/extensions/front/GeLUMerger_Erf.py @@ -126,7 +126,7 @@ class GeLUMergerErf(FrontReplacementPattern): # check that the values match the approximation if fabs(div_param - sqrt2) < 1e-06 and mul_param == 0.5 and add_param == 1.0: log.debug('Confirmed Erf-based GELU pattern after {} with name {}'.format(inp_node.op, inp_name)) - gelu = GeLUOP(graph, dict(name=inp_name + '/GELU_')).create_node() + gelu = GeLUOP(graph, dict(name=inp_name + '/GELU_', approximation='erf')).create_node() div.in_port(0).get_connection().set_destination(gelu.in_port(0)) out_node.out_port(0).get_connection().set_source(gelu.out_port(0)) rename_nodes([(out_node, node_name + '/TBD'), (gelu, node_name)]) diff --git a/model-optimizer/extensions/front/GeLUMerger_Erf_test.py b/model-optimizer/extensions/front/GeLUMerger_Erf_test.py index 8f3a4ebca3d..0c09156cd1f 100644 --- a/model-optimizer/extensions/front/GeLUMerger_Erf_test.py +++ b/model-optimizer/extensions/front/GeLUMerger_Erf_test.py @@ -23,7 +23,7 @@ from mo.utils.ir_engine.compare_graphs import compare_graphs from mo.utils.unittest.graph import build_graph, const, regular_op, result, build_graph ref_nodes = {**regular_op('input', {'type': 'Parameter'}), - **regular_op('gelu', {'type': 'Gelu', 'name': 'final_mul'}), + **regular_op('gelu', {'type': 'Gelu', 'approximation': 'erf', 'name': 'final_mul'}), **result('result') } ref_edges = [('input', 'gelu'), ('gelu', 'result')] @@ -65,6 +65,7 @@ class GeLUMergerErfTest(unittest.TestCase): (flag, resp) = compare_graphs(graph, graph_ref, 'result') self.assertTrue(flag, resp) + self.assertTrue(graph.get_op_nodes(op='Gelu')[0].approximation == 'erf') self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and graph.get_op_nodes(name='final_mul')[0].op == 'Gelu') @@ -89,6 +90,7 @@ class GeLUMergerErfTest(unittest.TestCase): (flag, resp) = compare_graphs(graph, graph_ref, 'result') self.assertTrue(flag, resp) + self.assertTrue(graph.get_op_nodes(op='Gelu')[0].approximation == 'erf') self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and graph.get_op_nodes(name='final_mul')[0].op == 'Gelu') @@ -113,5 +115,6 @@ class GeLUMergerErfTest(unittest.TestCase): (flag, resp) = compare_graphs(graph, graph_ref, 'result') self.assertTrue(flag, resp) + self.assertTrue(graph.get_op_nodes(op='Gelu')[0].approximation == 'erf') self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and graph.get_op_nodes(name='final_mul')[0].op == 'Gelu') diff --git a/model-optimizer/extensions/front/GeLUMerger_Tanh.py b/model-optimizer/extensions/front/GeLUMerger_Tanh.py index 3b9a568df4b..c7f0aaa93a3 100644 --- a/model-optimizer/extensions/front/GeLUMerger_Tanh.py +++ b/model-optimizer/extensions/front/GeLUMerger_Tanh.py @@ -74,6 +74,6 @@ class GeLUMergerTanh(FrontReplacementSubgraph): # check that the values match the approximation if fabs(mul0_param - sqrt2pi) < 1e-06 and fabs(mul_param - 0.044715) < 1e-06 and mul1_param == 0.5: log.debug('Confirmed TanH-based GELU pattern after {} with name {}'.format(inp.op, inp.name)) - gelu = GeLUOP(graph, dict(name=inp.name + '/GELU_')).create_node() + gelu = GeLUOP(graph, dict(name=inp.name + '/GELU_', approximation='tanh')).create_node() inp_port.connect(gelu.in_port(0)) match['mul2'].out_port(0).get_connection().set_source(gelu.out_port(0)) diff --git a/model-optimizer/extensions/front/GeLUMerger_test.py b/model-optimizer/extensions/front/GeLUMerger_Tanh_test.py similarity index 70% rename from model-optimizer/extensions/front/GeLUMerger_test.py rename to model-optimizer/extensions/front/GeLUMerger_Tanh_test.py index 931a368f472..fd3ab98c2a4 100644 --- a/model-optimizer/extensions/front/GeLUMerger_test.py +++ b/model-optimizer/extensions/front/GeLUMerger_Tanh_test.py @@ -15,11 +15,10 @@ """ import unittest - -import numpy as np from math import sqrt -from extensions.front.GeLUMerger_Erf import GeLUMergerErf +import numpy as np + from extensions.front.GeLUMerger_Tanh import GeLUMergerTanh from mo.utils.ir_engine.compare_graphs import compare_graphs from mo.utils.unittest.graph import build_graph @@ -55,42 +54,13 @@ nodes_attributes_tanh = { nodes_attributes_ref = { 'inp': {'kind': 'op', 'op': 'AnyOp'}, - 'gelu': {'kind': 'op', 'op': 'Gelu'}, + 'gelu': {'kind': 'op', 'op': 'Gelu', 'approximation': 'tanh'}, 'out': {'kind': 'op', 'op': 'AnyOp'}, } + class TestGeLUMergerReplacement(unittest.TestCase): - def test_GeLUMergerErf_test_1(self): - graph = build_graph(nodes_attributes_erf, - [('inp', 'mul0', {'out': 0}), - ('inp', 'div', {'out': 0}), - ('mul', 'mul0'), - ('div', 'erf'), - ('erf', 'add'), - ('add', 'mul0'), - ('mul_param', 'mul'), - ('div_param', 'div'), - ('add_param', 'add'), - ('mul0', 'out'), - ], - {'mul_param': {'shape': np.array([1]), 'value': np.array(0.5)}, - 'add_param': {'shape': np.array([1]), 'value': np.array(1.0)}, - 'div_param': {'shape': np.array([1]), 'value': np.array(sqrt(2.0))} - }, - nodes_with_edges_only=True) - graph_ref = build_graph(nodes_attributes_ref, - [('inp', 'gelu'), - ('gelu', 'out')], - {}, nodes_with_edges_only=True) - graph.stage = 'front' - - replacer = GeLUMergerErf() - replacer.find_and_replace_pattern(graph) - - (flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True) - self.assertTrue(flag, resp) - - def test_GeLUMergerTanh_test_2(self): + def test_GeLUMergerTanh(self): graph = build_graph(nodes_attributes_tanh, [('inp', 'mul2', {'out': 0}), ('inp', 'add', {'out': 0}), @@ -122,4 +92,4 @@ class TestGeLUMergerReplacement(unittest.TestCase): replacer.find_and_replace_pattern(graph) (flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True) - self.assertTrue(flag, resp) \ No newline at end of file + self.assertTrue(flag, resp) diff --git a/model-optimizer/extensions/front/mxnet/leaky_relu.py b/model-optimizer/extensions/front/mxnet/leaky_relu.py index fd5991de6d4..0c72edafcc4 100644 --- a/model-optimizer/extensions/front/mxnet/leaky_relu.py +++ b/model-optimizer/extensions/front/mxnet/leaky_relu.py @@ -15,6 +15,7 @@ """ from extensions.ops.activation_ops import Elu, LeakyReLU, ReLU +from extensions.ops.gelu import GeLUOP from extensions.ops.prelu import PReLU from mo.front.extractor import FrontExtractorOp from mo.front.mxnet.extractors.utils import get_mxnet_layer_attrs @@ -50,6 +51,8 @@ class LeakyReLUFrontExtractor(FrontExtractorOp): ReLU.update_node_stat(node) else: LeakyReLU.update_node_stat(node, {'negative_slope': negative_slope}) + elif act_type == 'gelu': + GeLUOP.update_node_stat(node, {'approximation': 'erf'}) else: raise Error( "Operation '{}' not supported. Please register it as custom op. " + diff --git a/model-optimizer/extensions/ops/gelu.py b/model-optimizer/extensions/ops/gelu.py index 14a89d021d5..c51b8e24176 100644 --- a/model-optimizer/extensions/ops/gelu.py +++ b/model-optimizer/extensions/ops/gelu.py @@ -24,11 +24,17 @@ class GeLUOP(Op): def __init__(self, graph: Graph, attrs: dict): mandatory_props = { - 'type': __class__.op, - 'op': __class__.op, + 'type': self.op, + 'op': self.op, 'in_ports_count': 1, 'out_ports_count': 1, - 'version': 'opset2', + 'version': 'opset7', 'infer': copy_shape_infer } - super().__init__(graph, mandatory_props, attrs) \ No newline at end of file + super().__init__(graph, mandatory_props, attrs) + + def backend_attrs(self): + if self.get_opset() == 'opset7': + return ['approximation'] + else: + return [] diff --git a/ngraph/core/include/ngraph/op/gelu.hpp b/ngraph/core/include/ngraph/op/gelu.hpp index 48f35d20216..d9ec6b15892 100644 --- a/ngraph/core/include/ngraph/op/gelu.hpp +++ b/ngraph/core/include/ngraph/op/gelu.hpp @@ -19,13 +19,13 @@ #include "ngraph/node.hpp" #include "ngraph/op/op.hpp" #include "ngraph/op/util/fused_op.hpp" - -NGRAPH_SUPPRESS_DEPRECATED_START +#include "ngraph/op/util/unary_elementwise_arithmetic.hpp" namespace ngraph { namespace op { + NGRAPH_SUPPRESS_DEPRECATED_START namespace v0 { /// \brief Gaussian Error Linear Unit @@ -36,7 +36,7 @@ namespace ngraph static constexpr NodeTypeInfo type_info{"Gelu", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } Gelu(); - /// \brief Constructs an Gelu operation. + /// \brief Constructs a Gelu operation. /// /// \param data Input tensor Gelu(const Output& data); @@ -51,7 +51,64 @@ namespace ngraph }; } using v0::Gelu; - } -} + NGRAPH_SUPPRESS_DEPRECATED_END -NGRAPH_SUPPRESS_DEPRECATED_END + /// \brief Specifies the approximation to calculate Gelu + enum class GeluApproximationMode + { + TANH, + ERF + }; + NGRAPH_API std::ostream& operator<<(std::ostream& s, const GeluApproximationMode& type); + + namespace v7 + { + /// \brief Gaussian Error Linear Unit + /// f(x) = 0.5 * x * (1 + erf( x / sqrt(2) ) for "approximation" = "erf" + /// f(x) = 0.5 * x * (1 + tanh([sqrt(2 / pi)] * [x + 0.044715^3]) for "approximation" = + /// "tanh" + class NGRAPH_API Gelu : public util::UnaryElementwiseArithmetic + { + public: + NGRAPH_RTTI_DECLARATION; + + Gelu() = default; + /// \brief Constructs a Gelu operation. + /// + /// \param data Input tensor + /// \param mode Approximation mode + Gelu(const Output& data, + GeluApproximationMode mode = GeluApproximationMode::ERF); + + bool visit_attributes(AttributeVisitor& visitor) override; + + void validate_and_infer_types() override; + + bool evaluate(const HostTensorVector& outputs, + const HostTensorVector& inputs) const override; + + std::shared_ptr + clone_with_new_inputs(const OutputVector& new_args) const override; + + GeluApproximationMode get_approximation_mode() const; + + private: + GeluApproximationMode m_approximation_mode = GeluApproximationMode::ERF; + }; + } + } + template <> + class NGRAPH_API AttributeAdapter + : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::GeluApproximationMode& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", + 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; +} diff --git a/ngraph/core/include/ngraph/opsets/opset.hpp b/ngraph/core/include/ngraph/opsets/opset.hpp index 5b4b9ef4ba9..d3f6489f4bb 100644 --- a/ngraph/core/include/ngraph/opsets/opset.hpp +++ b/ngraph/core/include/ngraph/opsets/opset.hpp @@ -134,4 +134,5 @@ namespace ngraph const NGRAPH_API OpSet& get_opset4(); const NGRAPH_API OpSet& get_opset5(); const NGRAPH_API OpSet& get_opset6(); + const NGRAPH_API OpSet& get_opset7(); } diff --git a/ngraph/core/include/ngraph/opsets/opset7.hpp b/ngraph/core/include/ngraph/opsets/opset7.hpp new file mode 100644 index 00000000000..4197e159ce4 --- /dev/null +++ b/ngraph/core/include/ngraph/opsets/opset7.hpp @@ -0,0 +1,29 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//***************************************************************************** + +#pragma once + +#include "ngraph/ops.hpp" + +namespace ngraph +{ + namespace opset7 + { +#define NGRAPH_OP(a, b) using b::a; +#include "ngraph/opsets/opset7_tbl.hpp" +#undef NGRAPH_OP + } // namespace opset7 +} // namespace ngraph diff --git a/ngraph/core/include/ngraph/opsets/opset7_tbl.hpp b/ngraph/core/include/ngraph/opsets/opset7_tbl.hpp new file mode 100644 index 00000000000..cded75c8cc6 --- /dev/null +++ b/ngraph/core/include/ngraph/opsets/opset7_tbl.hpp @@ -0,0 +1,185 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//***************************************************************************** + +#ifndef NGRAPH_OP +#warning "NGRAPH_OP not defined" +#define NGRAPH_OP(x, y) +#endif + +NGRAPH_OP(Abs, ngraph::op::v0) +NGRAPH_OP(Acos, ngraph::op::v0) +NGRAPH_OP(Add, ngraph::op::v1) +NGRAPH_OP(Asin, ngraph::op::v0) +NGRAPH_OP(Atan, ngraph::op::v0) +NGRAPH_OP(AvgPool, ngraph::op::v1) +NGRAPH_OP(BatchNormInference, ngraph::op::v5) +NGRAPH_OP(BinaryConvolution, ngraph::op::v1) +NGRAPH_OP(Broadcast, ngraph::op::v3) +NGRAPH_OP(Bucketize, ngraph::op::v3) +NGRAPH_OP(CTCGreedyDecoder, ngraph::op::v0) +NGRAPH_OP(Ceiling, ngraph::op::v0) +NGRAPH_OP(Clamp, ngraph::op::v0) +NGRAPH_OP(Concat, ngraph::op::v0) +NGRAPH_OP(Constant, ngraph::op) +NGRAPH_OP(Convert, ngraph::op::v0) +NGRAPH_OP(ConvertLike, ngraph::op::v1) +NGRAPH_OP(Convolution, ngraph::op::v1) +NGRAPH_OP(ConvolutionBackpropData, ngraph::op::v1) +NGRAPH_OP(Cos, ngraph::op::v0) +NGRAPH_OP(Cosh, ngraph::op::v0) +NGRAPH_OP(CumSum, ngraph::op::v0) +NGRAPH_OP(DeformableConvolution, ngraph::op::v1) +NGRAPH_OP(DeformablePSROIPooling, ngraph::op::v1) +NGRAPH_OP(DepthToSpace, ngraph::op::v0) +NGRAPH_OP(DetectionOutput, ngraph::op::v0) +NGRAPH_OP(Divide, ngraph::op::v1) +NGRAPH_OP(Elu, ngraph::op::v0) +NGRAPH_OP(Erf, ngraph::op::v0) +NGRAPH_OP(Equal, ngraph::op::v1) +NGRAPH_OP(Exp, ngraph::op::v0) +NGRAPH_OP(ExtractImagePatches, ngraph::op::v3) +NGRAPH_OP(FakeQuantize, ngraph::op::v0) +NGRAPH_OP(Floor, ngraph::op::v0) +NGRAPH_OP(FloorMod, ngraph::op::v1) +NGRAPH_OP(Gather, ngraph::op::v1) +NGRAPH_OP(GatherTree, ngraph::op::v1) +NGRAPH_OP(Greater, ngraph::op::v1) +NGRAPH_OP(GreaterEqual, ngraph::op::v1) +NGRAPH_OP(GroupConvolution, ngraph::op::v1) +NGRAPH_OP(GroupConvolutionBackpropData, ngraph::op::v1) +NGRAPH_OP(GRN, ngraph::op::v0) +NGRAPH_OP(HardSigmoid, ngraph::op::v0) +NGRAPH_OP(Less, ngraph::op::v1) +NGRAPH_OP(LessEqual, ngraph::op::v1) +NGRAPH_OP(Log, ngraph::op::v0) +NGRAPH_OP(LogicalAnd, ngraph::op::v1) +NGRAPH_OP(LogicalNot, ngraph::op::v1) +NGRAPH_OP(LogicalOr, ngraph::op::v1) +NGRAPH_OP(LogicalXor, ngraph::op::v1) +NGRAPH_OP(LRN, ngraph::op::v0) +NGRAPH_OP(LSTMCell, ngraph::op::v4) +NGRAPH_OP(MatMul, ngraph::op::v0) +NGRAPH_OP(MaxPool, ngraph::op::v1) +NGRAPH_OP(Maximum, ngraph::op::v1) +NGRAPH_OP(Minimum, ngraph::op::v1) +NGRAPH_OP(Mod, ngraph::op::v1) +NGRAPH_OP(Multiply, ngraph::op::v1) +NGRAPH_OP(Negative, ngraph::op::v0) +NGRAPH_OP(NormalizeL2, ngraph::op::v0) +NGRAPH_OP(NotEqual, ngraph::op::v1) +NGRAPH_OP(OneHot, ngraph::op::v1) +NGRAPH_OP(PRelu, ngraph::op::v0) +NGRAPH_OP(PSROIPooling, ngraph::op::v0) +NGRAPH_OP(Pad, ngraph::op::v1) +NGRAPH_OP(Parameter, ngraph::op::v0) +NGRAPH_OP(Power, ngraph::op::v1) +NGRAPH_OP(PriorBox, ngraph::op::v0) +NGRAPH_OP(PriorBoxClustered, ngraph::op::v0) +NGRAPH_OP(Proposal, ngraph::op::v4) +NGRAPH_OP(Range, ngraph::op::v4) +NGRAPH_OP(Relu, ngraph::op::v0) +NGRAPH_OP(ReduceMax, ngraph::op::v1) +NGRAPH_OP(ReduceLogicalAnd, ngraph::op::v1) +NGRAPH_OP(ReduceLogicalOr, ngraph::op::v1) +NGRAPH_OP(ReduceMean, ngraph::op::v1) +NGRAPH_OP(ReduceMin, ngraph::op::v1) +NGRAPH_OP(ReduceProd, ngraph::op::v1) +NGRAPH_OP(ReduceSum, ngraph::op::v1) +NGRAPH_OP(RegionYolo, ngraph::op::v0) +NGRAPH_OP(ReorgYolo, ngraph::op::v0) +NGRAPH_OP(Reshape, ngraph::op::v1) +NGRAPH_OP(Result, ngraph::op::v0) +NGRAPH_OP(ReverseSequence, ngraph::op::v0) +NGRAPH_OP(ROIPooling, ngraph::op::v0) +NGRAPH_OP(ScatterNDUpdate, ngraph::op::v3) +NGRAPH_OP(Select, ngraph::op::v1) +NGRAPH_OP(Selu, ngraph::op::v0) +NGRAPH_OP(Sign, ngraph::op::v0) +NGRAPH_OP(Sigmoid, ngraph::op::v0) +NGRAPH_OP(Sin, ngraph::op::v0) +NGRAPH_OP(Sinh, ngraph::op::v0) +NGRAPH_OP(Softmax, ngraph::op::v1) +NGRAPH_OP(Sqrt, ngraph::op::v0) +NGRAPH_OP(SpaceToDepth, ngraph::op::v0) +NGRAPH_OP(Split, ngraph::op::v1) +NGRAPH_OP(SquaredDifference, ngraph::op::v0) +NGRAPH_OP(Squeeze, ngraph::op::v0) +NGRAPH_OP(StridedSlice, ngraph::op::v1) +NGRAPH_OP(Subtract, ngraph::op::v1) +NGRAPH_OP(Tan, ngraph::op::v0) +NGRAPH_OP(Tanh, ngraph::op::v0) +NGRAPH_OP(TensorIterator, ngraph::op::v0) +NGRAPH_OP(Tile, ngraph::op::v0) +NGRAPH_OP(Transpose, ngraph::op::v1) +NGRAPH_OP(Unsqueeze, ngraph::op::v0) +NGRAPH_OP(VariadicSplit, ngraph::op::v1) + +// New operations added in opset2 +NGRAPH_OP(BatchToSpace, ngraph::op::v1) +NGRAPH_OP(SpaceToBatch, ngraph::op::v1) + +// New operations added in opset3 +NGRAPH_OP(EmbeddingBagPackedSum, ngraph::op::v3) +NGRAPH_OP(EmbeddingSegmentsSum, ngraph::op::v3) +NGRAPH_OP(EmbeddingBagOffsetsSum, ngraph::op::v3) +NGRAPH_OP(GRUCell, ngraph::op::v3) +NGRAPH_OP(NonZero, ngraph::op::v3) +NGRAPH_OP(RNNCell, ngraph::op::v0) +NGRAPH_OP(ROIAlign, ngraph::op::v3) +NGRAPH_OP(ScatterElementsUpdate, ngraph::op::v3) +NGRAPH_OP(ScatterUpdate, ngraph::op::v3) +NGRAPH_OP(ShuffleChannels, ngraph::op::v0) +NGRAPH_OP(ShapeOf, ngraph::op::v3) +NGRAPH_OP(TopK, ngraph::op::v3) + +// New operations added in opset4 +NGRAPH_OP(Acosh, ngraph::op::v3) +NGRAPH_OP(Asinh, ngraph::op::v3) +NGRAPH_OP(Atanh, ngraph::op::v3) +NGRAPH_OP(CTCLoss, ngraph::op::v4) +NGRAPH_OP(HSwish, ngraph::op::v4) +NGRAPH_OP(Interpolate, ngraph::op::v4) +NGRAPH_OP(Mish, ngraph::op::v4) +NGRAPH_OP(ReduceL1, ngraph::op::v4) +NGRAPH_OP(ReduceL2, ngraph::op::v4) +NGRAPH_OP(SoftPlus, ngraph::op::v4) +NGRAPH_OP(Swish, ngraph::op::v4) + +// New operations added in opset5 +NGRAPH_OP(GatherND, ngraph::op::v5) +NGRAPH_OP(GRUSequence, ngraph::op::v5) +NGRAPH_OP(HSigmoid, ngraph::op::v5) +NGRAPH_OP(LogSoftmax, ngraph::op::v5) +NGRAPH_OP(Loop, ngraph::op::v5) +NGRAPH_OP(LSTMSequence, ngraph::op::v5) +NGRAPH_OP(NonMaxSuppression, ngraph::op::v5) +NGRAPH_OP(RNNSequence, ngraph::op::v5) +NGRAPH_OP(Round, ngraph::op::v5) + +// New operations added in opset6 +NGRAPH_OP(CTCGreedyDecoderSeqLen, ngraph::op::v6) +NGRAPH_OP(ExperimentalDetectronDetectionOutput, ngraph::op::v6) +NGRAPH_OP(ExperimentalDetectronGenerateProposalsSingleImage, ngraph::op::v6) +NGRAPH_OP(ExperimentalDetectronPriorGridGenerator, ngraph::op::v6) +NGRAPH_OP(ExperimentalDetectronROIFeatureExtractor, ngraph::op::v6) +NGRAPH_OP(ExperimentalDetectronTopKROIs, ngraph::op::v6) +NGRAPH_OP(GatherElements, ngraph::op::v6) +NGRAPH_OP(MVN, ngraph::op::v6) +NGRAPH_OP(Assign, ngraph::op::v6) // new version +NGRAPH_OP(ReadValue, ngraph::op::v6) // new version + +// New operations added in opset7 +NGRAPH_OP(Gelu, ngraph::op::v7) diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/gelu.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/gelu.hpp index 757e3514df4..f74516bd386 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/gelu.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/gelu.hpp @@ -18,6 +18,7 @@ #include #include +#include namespace ngraph { @@ -26,11 +27,25 @@ namespace ngraph namespace reference { template - void gelu(const T* arg, T* out, size_t count) + void gelu(const T* arg, T* out, op::GeluApproximationMode mode, size_t count) { - for (size_t i = 0; i < count; i++) + if (mode == op::GeluApproximationMode::ERF) { - out[i] = 0.5 * arg[i] * (1 + erf(arg[i] / std::sqrt(2))); + for (size_t i = 0; i < count; i++) + { + out[i] = 0.5 * arg[i] * (1 + erf(arg[i] / std::sqrt(2.0))); + } + } + else if (mode == op::GeluApproximationMode::TANH) + { + const auto pi = atan(1.0) * 4.0; + const auto sqpi = std::sqrt(2.0 / pi); + for (size_t i = 0; i < count; i++) + { + auto& x = arg[i]; + out[i] = + 0.5 * x * (1.0 + std::tanh(sqpi * (x + 0.044715 * std::pow(x, 3)))); + } } } } diff --git a/ngraph/core/src/op/gelu.cpp b/ngraph/core/src/op/gelu.cpp index 7b98d28ab12..4eeabd31ec7 100644 --- a/ngraph/core/src/op/gelu.cpp +++ b/ngraph/core/src/op/gelu.cpp @@ -17,6 +17,7 @@ #include #include "itt.hpp" +#include #include "ngraph/builder/make_constant.hpp" #include "ngraph/op/add.hpp" #include "ngraph/op/divide.hpp" @@ -26,6 +27,7 @@ #include "ngraph/op/multiply.hpp" #include "ngraph/op/negative.hpp" #include "ngraph/op/subtract.hpp" +#include "ngraph/runtime/reference/gelu.hpp" using namespace std; using namespace ngraph; @@ -34,18 +36,18 @@ NGRAPH_SUPPRESS_DEPRECATED_START constexpr NodeTypeInfo op::Gelu::type_info; -op::Gelu::Gelu() +op::v0::Gelu::Gelu() : FusedOp() { } -op::Gelu::Gelu(const Output& data) +op::v0::Gelu::Gelu(const Output& data) : FusedOp({data}) { constructor_validate_and_infer_types(); } -bool ngraph::op::v0::Gelu::visit_attributes(AttributeVisitor& visitor) +bool op::v0::Gelu::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v0_Gelu_visit_attributes); return true; @@ -72,17 +74,17 @@ OutputVector op::Gelu::decompose_op() const return {std::make_shared(multiply, add)}; } -shared_ptr op::Gelu::clone_with_new_inputs(const OutputVector& new_args) const +shared_ptr op::v0::Gelu::clone_with_new_inputs(const OutputVector& new_args) const { NGRAPH_OP_SCOPE(v0_Gelu_clone_with_new_inputs); if (new_args.size() != 1) { throw ngraph_error("Incorrect number of new arguments"); } - return make_shared(new_args.at(0)); + return make_shared(new_args.at(0)); } -void op::Gelu::pre_validate_and_infer_types() +void op::v0::Gelu::pre_validate_and_infer_types() { element::Type input_element_type = get_input_element_type(0); PartialShape input_pshape = get_input_partial_shape(0); @@ -93,8 +95,110 @@ void op::Gelu::pre_validate_and_infer_types() input_element_type, ")."); - if (input_pshape.is_dynamic()) + set_output_type(0, input_element_type, input_pshape); +} + +// ------------------------------ V7 ------------------------------ + +namespace ngraph +{ + template <> + NGRAPH_API EnumNames& EnumNames::get() { - set_output_type(0, input_element_type, input_pshape); + static auto enum_names = EnumNames( + "op::GeluApproximationMode", + {{"TANH", op::GeluApproximationMode::TANH}, {"ERF", op::GeluApproximationMode::ERF}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::GeluApproximationMode& type) + { + return s << as_string(type); + } +} // namespace ngraph + +NGRAPH_RTTI_DEFINITION(op::v7::Gelu, "Gelu", 7); + +op::v7::Gelu::Gelu(const Output& data, GeluApproximationMode mode) + : UnaryElementwiseArithmetic(data) + , m_approximation_mode(mode) +{ + constructor_validate_and_infer_types(); +} + +bool op::v7::Gelu::visit_attributes(AttributeVisitor& visitor) +{ + NGRAPH_OP_SCOPE(v7_Gelu_visit_attributes); + visitor.on_attribute("approximation_mode", m_approximation_mode); + return true; +} + +shared_ptr op::v7::Gelu::clone_with_new_inputs(const OutputVector& new_args) const +{ + NGRAPH_OP_SCOPE(v7_Gelu_clone_with_new_inputs); + if (new_args.size() != 1) + { + throw ngraph_error("Incorrect number of new arguments"); + } + return make_shared(new_args.at(0), m_approximation_mode); +} + +void op::v7::Gelu::validate_and_infer_types() +{ + NGRAPH_OP_SCOPE(v7_Gelu_validate_and_infer_types); + element::Type input_element_type = get_input_element_type(0); + PartialShape input_pshape = get_input_partial_shape(0); + + NODE_VALIDATION_CHECK(this, + input_element_type.is_dynamic() || input_element_type.is_real(), + "Argument element type must be f16, bf16, f32, f64 or dynamic (got ", + input_element_type, + ")."); + + set_output_type(0, input_element_type, input_pshape); +} + +op::GeluApproximationMode op::v7::Gelu::get_approximation_mode() const +{ + return m_approximation_mode; +} + +namespace gelu +{ + template + inline bool evaluate(const HostTensorPtr& arg0, + const HostTensorPtr& out, + op::GeluApproximationMode mode, + const size_t count) + { + using T = typename element_type_traits::value_type; + runtime::reference::gelu(arg0->get_data_ptr(), out->get_data_ptr(), mode, count); + return true; + } + + bool evaluate_gelu(const HostTensorPtr& arg0, + const HostTensorPtr& out, + op::GeluApproximationMode mode, + const size_t count) + { + bool rc = true; + out->set_unary(arg0); + + switch (arg0->get_element_type()) + { + NGRAPH_TYPE_CASE(evaluate_gelu, f16, arg0, out, mode, count); + NGRAPH_TYPE_CASE(evaluate_gelu, f32, arg0, out, mode, count); + default: rc = false; break; + } + return rc; } } + +bool op::v7::Gelu::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const +{ + NGRAPH_OP_SCOPE(v7_Gelu_evaluate); + return gelu::evaluate_gelu( + inputs[0], outputs[0], m_approximation_mode, shape_size(get_output_shape(0))); +} diff --git a/ngraph/core/src/opsets/opset.cpp b/ngraph/core/src/opsets/opset.cpp index 29c135ddc76..b0a5f83d928 100644 --- a/ngraph/core/src/opsets/opset.cpp +++ b/ngraph/core/src/opsets/opset.cpp @@ -157,3 +157,22 @@ const ngraph::OpSet& ngraph::get_opset6() } return opset; } + +const ngraph::OpSet& ngraph::get_opset7() +{ + static std::mutex init_mutex; + static bool opset_is_initialized = false; + static OpSet opset; + if (!opset_is_initialized) + { + std::lock_guard guard(init_mutex); + if (!opset_is_initialized) + { +#define NGRAPH_OP(NAME, NAMESPACE) opset.insert(); +#include "ngraph/opsets/opset7_tbl.hpp" +#undef NGRAPH_OP + opset_is_initialized = true; + } + } + return opset; +} diff --git a/ngraph/python/setup.py b/ngraph/python/setup.py index dcc1ce44cbc..d79eaa3ed1d 100644 --- a/ngraph/python/setup.py +++ b/ngraph/python/setup.py @@ -46,6 +46,7 @@ packages = [ "ngraph.opset4", "ngraph.opset5", "ngraph.opset6", + "ngraph.opset7", "ngraph.utils", "ngraph.impl", "ngraph.impl.op", diff --git a/ngraph/python/src/ngraph/opset7/__init__.py b/ngraph/python/src/ngraph/opset7/__init__.py new file mode 100644 index 00000000000..f2a46a7a614 --- /dev/null +++ b/ngraph/python/src/ngraph/opset7/__init__.py @@ -0,0 +1,166 @@ +# ****************************************************************************** +# Copyright 2017-2021 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ****************************************************************************** + + +from ngraph.opset1.ops import absolute +from ngraph.opset1.ops import absolute as abs +from ngraph.opset1.ops import acos +from ngraph.opset4.ops import acosh +from ngraph.opset1.ops import add +from ngraph.opset1.ops import asin +from ngraph.opset4.ops import asinh +from ngraph.opset3.ops import assign +from ngraph.opset1.ops import atan +from ngraph.opset4.ops import atanh +from ngraph.opset1.ops import avg_pool +from ngraph.opset5.ops import batch_norm_inference +from ngraph.opset2.ops import batch_to_space +from ngraph.opset1.ops import binary_convolution +from ngraph.opset3.ops import broadcast +from ngraph.opset3.ops import bucketize +from ngraph.opset1.ops import ceiling +from ngraph.opset1.ops import ceiling as ceil +from ngraph.opset1.ops import clamp +from ngraph.opset1.ops import concat +from ngraph.opset1.ops import constant +from ngraph.opset1.ops import convert +from ngraph.opset1.ops import convert_like +from ngraph.opset1.ops import convolution +from ngraph.opset1.ops import convolution_backprop_data +from ngraph.opset1.ops import cos +from ngraph.opset1.ops import cosh +from ngraph.opset1.ops import ctc_greedy_decoder +from ngraph.opset6.ops import ctc_greedy_decoder_seq_len +from ngraph.opset4.ops import ctc_loss +from ngraph.opset3.ops import cum_sum +from ngraph.opset3.ops import cum_sum as cumsum +from ngraph.opset1.ops import deformable_convolution +from ngraph.opset1.ops import deformable_psroi_pooling +from ngraph.opset1.ops import depth_to_space +from ngraph.opset1.ops import detection_output +from ngraph.opset1.ops import divide +from ngraph.opset1.ops import elu +from ngraph.opset3.ops import embedding_bag_offsets_sum +from ngraph.opset3.ops import embedding_bag_packed_sum +from ngraph.opset3.ops import embedding_segments_sum +from ngraph.opset3.ops import extract_image_patches +from ngraph.opset1.ops import equal +from ngraph.opset1.ops import erf +from ngraph.opset1.ops import exp +from ngraph.opset1.ops import fake_quantize +from ngraph.opset1.ops import floor +from ngraph.opset1.ops import floor_mod +from ngraph.opset1.ops import gather +from ngraph.opset6.ops import gather_elements +from ngraph.opset5.ops import gather_nd +from ngraph.opset1.ops import gather_tree +from ngraph.opset7.ops import gelu +from ngraph.opset1.ops import greater +from ngraph.opset1.ops import greater_equal +from ngraph.opset1.ops import grn +from ngraph.opset1.ops import group_convolution +from ngraph.opset1.ops import group_convolution_backprop_data +from ngraph.opset3.ops import gru_cell +from ngraph.opset5.ops import gru_sequence +from ngraph.opset1.ops import hard_sigmoid +from ngraph.opset5.ops import hsigmoid +from ngraph.opset4.ops import hswish +from ngraph.opset1.ops import interpolate +from ngraph.opset1.ops import less +from ngraph.opset1.ops import less_equal +from ngraph.opset1.ops import log +from ngraph.opset1.ops import logical_and +from ngraph.opset1.ops import logical_not +from ngraph.opset1.ops import logical_or +from ngraph.opset1.ops import logical_xor +from ngraph.opset5.ops import log_softmax +from ngraph.opset5.ops import loop +from ngraph.opset1.ops import lrn +from ngraph.opset4.ops import lstm_cell +from ngraph.opset1.ops import lstm_sequence +from ngraph.opset1.ops import matmul +from ngraph.opset1.ops import max_pool +from ngraph.opset1.ops import maximum +from ngraph.opset1.ops import minimum +from ngraph.opset4.ops import mish +from ngraph.opset1.ops import mod +from ngraph.opset1.ops import multiply +from ngraph.opset6.ops import mvn +from ngraph.opset1.ops import negative +from ngraph.opset5.ops import non_max_suppression +from ngraph.opset3.ops import non_zero +from ngraph.opset1.ops import normalize_l2 +from ngraph.opset1.ops import not_equal +from ngraph.opset1.ops import one_hot +from ngraph.opset1.ops import pad +from ngraph.opset1.ops import parameter +from ngraph.opset1.ops import power +from ngraph.opset1.ops import prelu +from ngraph.opset1.ops import prior_box +from ngraph.opset1.ops import prior_box_clustered +from ngraph.opset1.ops import psroi_pooling +from ngraph.opset4.ops import proposal +from ngraph.opset1.ops import range +from ngraph.opset3.ops import read_value +from ngraph.opset4.ops import reduce_l1 +from ngraph.opset4.ops import reduce_l2 +from ngraph.opset1.ops import reduce_logical_and +from ngraph.opset1.ops import reduce_logical_or +from ngraph.opset1.ops import reduce_max +from ngraph.opset1.ops import reduce_mean +from ngraph.opset1.ops import reduce_min +from ngraph.opset1.ops import reduce_prod +from ngraph.opset1.ops import reduce_sum +from ngraph.opset1.ops import region_yolo +from ngraph.opset2.ops import reorg_yolo +from ngraph.opset1.ops import relu +from ngraph.opset1.ops import reshape +from ngraph.opset1.ops import result +from ngraph.opset1.ops import reverse_sequence +from ngraph.opset3.ops import rnn_cell +from ngraph.opset5.ops import rnn_sequence +from ngraph.opset3.ops import roi_align +from ngraph.opset2.ops import roi_pooling +from ngraph.opset5.ops import round +from ngraph.opset3.ops import scatter_elements_update +from ngraph.opset3.ops import scatter_update +from ngraph.opset1.ops import select +from ngraph.opset1.ops import selu +from ngraph.opset3.ops import shape_of +from ngraph.opset3.ops import shuffle_channels +from ngraph.opset1.ops import sigmoid +from ngraph.opset1.ops import sign +from ngraph.opset1.ops import sin +from ngraph.opset1.ops import sinh +from ngraph.opset1.ops import softmax +from ngraph.opset4.ops import softplus +from ngraph.opset2.ops import space_to_batch +from ngraph.opset1.ops import space_to_depth +from ngraph.opset1.ops import split +from ngraph.opset1.ops import sqrt +from ngraph.opset1.ops import squared_difference +from ngraph.opset1.ops import squeeze +from ngraph.opset1.ops import strided_slice +from ngraph.opset1.ops import subtract +from ngraph.opset4.ops import swish +from ngraph.opset1.ops import tan +from ngraph.opset1.ops import tanh +from ngraph.opset1.ops import tensor_iterator +from ngraph.opset1.ops import tile +from ngraph.opset3.ops import topk +from ngraph.opset1.ops import transpose +from ngraph.opset1.ops import unsqueeze +from ngraph.opset1.ops import variadic_split diff --git a/ngraph/python/src/ngraph/opset7/ops.py b/ngraph/python/src/ngraph/opset7/ops.py new file mode 100644 index 00000000000..3d0b80b815a --- /dev/null +++ b/ngraph/python/src/ngraph/opset7/ops.py @@ -0,0 +1,80 @@ +# ****************************************************************************** +# Copyright 2017-2021 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ****************************************************************************** + +"""Factory functions for all ngraph ops.""" +from typing import Callable, Iterable, List, Optional, Set, Union + +import numpy as np +from functools import partial + +from ngraph.impl import Node, Shape +from ngraph.impl.op import Constant, Parameter +from ngraph.opset_utils import _get_node_factory +from ngraph.utils.decorators import binary_op, nameable_op, unary_op +from ngraph.utils.input_validation import ( + assert_list_of_ints, + check_valid_attributes, + is_non_negative_value, + is_positive_value, +) +from ngraph.utils.node_factory import NodeFactory +from ngraph.utils.tensor_iterator_types import ( + GraphBody, + TensorIteratorSliceInputDesc, + TensorIteratorMergedInputDesc, + TensorIteratorInvariantInputDesc, + TensorIteratorBodyOutputDesc, + TensorIteratorConcatOutputDesc, +) +from ngraph.utils.types import ( + NodeInput, + NumericData, + NumericType, + ScalarData, + TensorShape, + as_node, + as_nodes, + get_dtype, + get_element_type, + get_element_type_str, + make_constant_node, +) + +_get_node_factory_opset7 = partial(_get_node_factory, "opset7") + +# -------------------------------------------- ops ------------------------------------------------ + + +@nameable_op +def gelu( + data: Node, + approximation_mode: str, + name: Optional[str] = None, +) -> Node: + """Return a node which performs Gelu activation function. + + @param data: The node with data tensor. + @param approximation_mode: defines which approximation to use ('tanh' or 'erf') + @param name: Optional output node name. + @return The new node performing a Gelu activation with the input tensor. + """ + inputs = as_nodes(data) + + attributes = { + "approximation_mode": approximation_mode + } + + return _get_node_factory_opset7().create("Gelu", inputs, attributes) diff --git a/ngraph/python/src/pyngraph/node_factory.cpp b/ngraph/python/src/pyngraph/node_factory.cpp index a003dd75fdf..4df46202a07 100644 --- a/ngraph/python/src/pyngraph/node_factory.cpp +++ b/ngraph/python/src/pyngraph/node_factory.cpp @@ -93,6 +93,7 @@ namespace {"opset4", OpsetFunction(ngraph::get_opset4)}, {"opset5", OpsetFunction(ngraph::get_opset5)}, {"opset6", OpsetFunction(ngraph::get_opset6)}, + {"opset7", OpsetFunction(ngraph::get_opset7)}, }; auto it = s_opsets.find(opset_ver); @@ -103,7 +104,7 @@ namespace return it->second(); } - const ngraph::OpSet& m_opset = ngraph::get_opset6(); + const ngraph::OpSet& m_opset = ngraph::get_opset7(); }; } // namespace diff --git a/ngraph/python/tests/__init__.py b/ngraph/python/tests/__init__.py index 46d5f2e3c46..e99c3641dcb 100644 --- a/ngraph/python/tests/__init__.py +++ b/ngraph/python/tests/__init__.py @@ -195,3 +195,4 @@ xfail_issue_49750 = xfail_test(reason="RuntimeError: Unsupported dynamic ops: v4 xfail_issue_49752 = xfail_test(reason="RuntimeError: Unsupported dynamic ops: v1::Pad") xfail_issue_49753 = xfail_test(reason="RuntimeError: Unsupported dynamic ops: v1::StridedSlice") xfail_issue_49754 = xfail_test(reason="RuntimeError: Unsupported dynamic ops: v1::TopKIE") +xfail_issue_49913 = xfail_test(reason="CPU supports Gelu with tanh mode only") diff --git a/ngraph/python/tests/test_ngraph/test_ops_fused.py b/ngraph/python/tests/test_ngraph/test_ops_fused.py index eec2bc7b4b5..4aa63fffaa6 100644 --- a/ngraph/python/tests/test_ngraph/test_ops_fused.py +++ b/ngraph/python/tests/test_ngraph/test_ops_fused.py @@ -222,36 +222,6 @@ def test_batch_to_space(): assert np.allclose(result, expected) -def test_gelu_operator_with_parameters(): - runtime = get_runtime() - - data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) - - data_shape = [2, 2] - parameter_data = ng.parameter(data_shape, name="Data", dtype=np.float32) - - model = ng.gelu(parameter_data) - computation = runtime.computation(model, parameter_data) - - result = computation(data_value) - expected = np.array([[-1.4901161e-06, 8.4134471e-01], [-4.5500278e-02, 2.9959502]], dtype=np.float32) - assert np.allclose(result, expected, 0.007, 0.007) - - -def test_gelu_operator_with_array(): - runtime = get_runtime() - - data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) - - model = ng.gelu(data_value) - computation = runtime.computation(model) - - result = computation() - expected = np.array([[-1.4901161e-06, 8.4134471e-01], [-4.5500278e-02, 2.9959502]], dtype=np.float32) - - assert np.allclose(result, expected, 0.007, 0.007) - - def test_clamp_operator(): runtime = get_runtime() diff --git a/ngraph/python/tests/test_ngraph/test_ops_unary.py b/ngraph/python/tests/test_ngraph/test_ops_unary.py index c796da1b32b..667f3778783 100644 --- a/ngraph/python/tests/test_ngraph/test_ops_unary.py +++ b/ngraph/python/tests/test_ngraph/test_ops_unary.py @@ -18,8 +18,9 @@ import pytest import ngraph as ng from ngraph.impl import Shape, Type +from tests.runtime import get_runtime from tests.test_ngraph.util import run_op_node -from tests import xfail_issue_44970 +from tests import xfail_issue_44970, xfail_issue_49913 @pytest.mark.parametrize( @@ -185,3 +186,64 @@ def test_hsigmoid(): assert node.get_output_size() == 1 assert list(node.get_output_shape(0)) == [3, 10] assert node.get_output_element_type(0) == Type.f32 + + +@xfail_issue_49913 +def test_gelu_operator_with_parameters(): + runtime = get_runtime() + + data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) + + data_shape = [2, 2] + parameter_data = ng.parameter(data_shape, name="Data", dtype=np.float32) + + model = ng.gelu(parameter_data, "erf") + computation = runtime.computation(model, parameter_data) + + result = computation(data_value) + expected = np.array([[-1.6391277e-06, 8.4134471e-01], [-4.5500278e-02, 2.9959502]], dtype=np.float32) + assert np.allclose(result, expected) + + +@xfail_issue_49913 +def test_gelu_operator_with_array(): + runtime = get_runtime() + + data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) + + model = ng.gelu(data_value, "erf") + computation = runtime.computation(model) + + result = computation() + expected = np.array([[-1.6391277e-06, 8.4134471e-01], [-4.5500278e-02, 2.9959502]], dtype=np.float32) + assert np.allclose(result, expected) + + +def test_gelu_tanh_operator_with_parameters(): + runtime = get_runtime() + + data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) + + data_shape = [2, 2] + parameter_data = ng.parameter(data_shape, name="Data", dtype=np.float32) + + model = ng.gelu(parameter_data, "tanh") + computation = runtime.computation(model, parameter_data) + + result = computation(data_value) + expected = np.array([[0.0, 0.841192], [-0.04540223, 2.9963627]], dtype=np.float32) + assert np.allclose(result, expected, 1e-6, 1e-6) + + +def test_gelu_tanh_operator_with_array(): + runtime = get_runtime() + + data_value = np.array([[-5, 1], [-2, 3]], dtype=np.float32) + + model = ng.gelu(data_value, "tanh") + computation = runtime.computation(model) + + result = computation() + expected = np.array([[0.0, 0.841192], [-0.04540223, 2.9963627]], dtype=np.float32) + + assert np.allclose(result, expected, 1e-6, 1e-6) diff --git a/ngraph/test/CMakeLists.txt b/ngraph/test/CMakeLists.txt index 8f77fc97f00..8dd5469cef9 100644 --- a/ngraph/test/CMakeLists.txt +++ b/ngraph/test/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC op.cpp op_eval/bucketize.cpp op_eval/floor_mod.cpp + op_eval/gelu.cpp op_eval/hsigmoid.cpp op_eval/hswish.cpp op_eval/interpolate.cpp diff --git a/ngraph/test/op_eval/gelu.cpp b/ngraph/test/op_eval/gelu.cpp new file mode 100644 index 00000000000..5830d6a9197 --- /dev/null +++ b/ngraph/test/op_eval/gelu.cpp @@ -0,0 +1,72 @@ +//***************************************************************************** +// Copyright 2017-2021 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//***************************************************************************** + +#include +#include + +#include "gtest/gtest.h" + +#include "ngraph/op/gelu.hpp" +#include "ngraph/runtime/host_tensor.hpp" +#include "ngraph/validation_util.hpp" +#include "util/test_tools.hpp" + +using namespace std; +using namespace ngraph; + +TEST(op_eval, gelu_tanh) +{ + auto p = make_shared(element::f32, Shape{}); + auto gelu = make_shared(p, op::GeluApproximationMode::TANH); + auto fun = make_shared(OutputVector{gelu}, ParameterVector{p}); + + std::vector> inputs{{-1.0}, {-0.5}, {0}, {0.5}, {1.0}}; + std::vector> expected_result{ + {-0.15880796}, {-0.154286}, {0}, {0.345714}, {0.841192}}; + + for (size_t i = 0; i < inputs.size(); i++) + { + auto result = make_shared(); + ASSERT_TRUE( + fun->evaluate({result}, {make_host_tensor(Shape{}, inputs[i])})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), (Shape{})); + auto result_data = read_vector(result); + EXPECT_NEAR(result_data[0], expected_result[i][0], 0.000001); + } +} + +TEST(op_eval, gelu_erf) +{ + auto p = make_shared(element::f32, Shape{}); + auto gelu = make_shared(p, op::GeluApproximationMode::ERF); + auto fun = make_shared(OutputVector{gelu}, ParameterVector{p}); + + std::vector> inputs{{-1.0}, {-0.5}, {0}, {0.5}, {1.0}}; + std::vector> expected_result{ + {-0.15865529}, {-0.15426877}, {0}, {0.34573123}, {0.8413447}}; + + for (size_t i = 0; i < inputs.size(); i++) + { + auto result = make_shared(); + ASSERT_TRUE( + fun->evaluate({result}, {make_host_tensor(Shape{}, inputs[i])})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), (Shape{})); + auto result_data = read_vector(result); + EXPECT_NEAR(result_data[0], expected_result[i][0], 0.000001); + } +} diff --git a/ngraph/test/provenance.cpp b/ngraph/test/provenance.cpp index 85fca785056..77172951930 100644 --- a/ngraph/test/provenance.cpp +++ b/ngraph/test/provenance.cpp @@ -398,7 +398,7 @@ TEST(provenance, fused_copy_origin_tags) auto p1 = make_shared(element::f32, PartialShape{2, 3, 4}); p1->add_provenance_tag("P1"); - auto g = make_shared(p1); + auto g = make_shared(p1); g->add_provenance_tag("G"); auto r = make_shared(g); auto f = make_shared(ResultVector{r}, ParameterVector{p1}); @@ -420,7 +420,7 @@ TEST(provenance, fused_copy_origin_tags) else { EXPECT_TRUE(tags.find("G") != tags.end()); - EXPECT_TRUE(tags.find("") != tags.end()); + EXPECT_TRUE(tags.find("") != tags.end()); } }); } diff --git a/ngraph/test/runtime/interpreter/evaluates_map.cpp b/ngraph/test/runtime/interpreter/evaluates_map.cpp index f786643c555..1cd0f01ee04 100644 --- a/ngraph/test/runtime/interpreter/evaluates_map.cpp +++ b/ngraph/test/runtime/interpreter/evaluates_map.cpp @@ -1108,6 +1108,20 @@ namespace using T = typename element_type_traits::value_type; runtime::reference::gelu(inputs[0]->get_data_ptr(), outputs[0]->get_data_ptr(), + op::GeluApproximationMode::ERF, + shape_size(inputs[0]->get_shape())); + return true; + } + + template + bool evaluate(const shared_ptr& op, + const HostTensorVector& outputs, + const HostTensorVector& inputs) + { + using T = typename element_type_traits::value_type; + runtime::reference::gelu(inputs[0]->get_data_ptr(), + outputs[0]->get_data_ptr(), + op->get_approximation_mode(), shape_size(inputs[0]->get_shape())); return true; } diff --git a/ngraph/test/util/engine/ie_engines.cpp b/ngraph/test/util/engine/ie_engines.cpp index 57155bb3d1a..03ff866c3b8 100644 --- a/ngraph/test/util/engine/ie_engines.cpp +++ b/ngraph/test/util/engine/ie_engines.cpp @@ -311,6 +311,8 @@ std::set test::IE_Engine::get_ie_ops() const ie_ops.insert(opset5.begin(), opset5.end()); const auto& opset6 = get_opset6().get_type_info_set(); ie_ops.insert(opset6.begin(), opset6.end()); + const auto& opset7 = get_opset7().get_type_info_set(); + ie_ops.insert(opset7.begin(), opset7.end()); return ie_ops; }