diff --git a/.ci/onnx/jenkins/Jenkinsfile b/.ci/onnx/jenkins/Jenkinsfile index ecdcaa77e60..ac7b6f64e40 100644 --- a/.ci/onnx/jenkins/Jenkinsfile +++ b/.ci/onnx/jenkins/Jenkinsfile @@ -113,10 +113,10 @@ pipeline { WORKDIR = "${WORKSPACE}/${BUILD_NUMBER}" JENKINS_GITHUB_CREDENTIAL_ID = "7157091e-bc04-42f0-99fd-dc4da2922a55" CI_DIR = "ngraph-onnx/.ci/jenkins" - NGRAPH_ONNX_REPO_ADDRESS = "https://github.com/NervanaSystems/ngraph-onnx.git" - NGRAPH_REPO_ADDRESS = "https://github.com/NervanaSystems/ngraph.git" - NGRAPH_ONNX_BRANCH="${CHANGE_BRANCH}" - NGRAPH_BRANCH="${CHANGE_BRANCH}" + NGRAPH_ONNX_REPO_ADDRESS = "git@github.com:NervanaSystems/ngraph-onnx.git" + NGRAPH_REPO_ADDRESS = "git@github.com:NervanaSystems/ngraph.git" + NGRAPH_ONNX_BRANCH = "${CHANGE_BRANCH}" + NGRAPH_BRANCH = "${CHANGE_BRANCH}" } options { skipDefaultCheckout true diff --git a/CMakeLists.txt b/CMakeLists.txt index 39d2992bcd9..269e14804ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,14 +69,6 @@ if (UNIX AND NOT APPLE) set(LINUX TRUE) endif() -if ("${CMAKE_GENERATOR}" MATCHES "^Visual Studio.*$") - set(MSVS TRUE) -endif() - -if (CMAKE_CXX_COMPILER_ID MATCHES MSVC) - add_definitions(/bigobj) -endif() - # APPLE: Set CMAKE_OSX_SYSROOT if not set already. if (APPLE) execute_process(COMMAND sw_vers -productVersion @@ -151,7 +143,7 @@ if (CMAKE_OSX_SYSROOT) ) endif() -if (NOT MSVS) +if (NOT MSVC) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) endif() @@ -361,7 +353,16 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang$" AND NOT NGRAPH_BUILD_DI endif() if (WIN32) - set(CMAKE_CXX_FLAGS "/W0 /EHsc /MP") + string(REPLACE "/W3" "/W0" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP") + + if (CMAKE_CXX_COMPILER_ID MATCHES MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") + # C4251 needs to have dll-interface to be used by clients of class + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") + # C4275 non dll-interface class used as base for dll-interface class + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4275") + endif() else() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") @@ -461,36 +462,36 @@ if (NOT DEFINED NGRAPH_TBB_ENABLE) set(NGRAPH_TBB_ENABLE ${NGRAPH_CPU_ENABLE}) endif() -# Since UNIX and APPLE support Bash we can use a Bash script to do the clang-format functions +# Since UNIX support Bash we can use a Bash script to do the clang-format functions # This is much faster than the cmake method -if (UNIX OR APPLE) +if (UNIX) add_custom_target(style-check COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/maint/check-code-format.sh) add_custom_target(style-apply COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/maint/apply-code-format.sh) add_custom_target(style COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/maint/apply-code-format.sh) else() add_custom_target(style-check COMMAND ${CMAKE_COMMAND} - -DNGRAPH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" - -P ${CMAKE_MODULE_PATH}style_check.cmake + -DNGRAPH_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/style_check.cmake ) add_custom_target(style-apply COMMAND ${CMAKE_COMMAND} - -DNGRAPH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" - -P ${CMAKE_MODULE_PATH}style_apply.cmake + -DNGRAPH_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/style_apply.cmake ) add_custom_target(style COMMAND ${CMAKE_COMMAND} - -DNGRAPH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" - -P ${CMAKE_MODULE_PATH}style_apply.cmake + -DNGRAPH_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/style_apply.cmake ) endif() add_custom_target(fix-mode COMMAND ${CMAKE_COMMAND} - -DNGRAPH_SOURCE_DIR="${CMAKE_SOURCE_DIR}" - -P ${CMAKE_MODULE_PATH}fix_mode.cmake + -DNGRAPH_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/fix_mode.cmake ) #----------------------------------------------------------------------------------------------- @@ -545,13 +546,13 @@ if(NOT DEFINED EXTERNAL_PROJECTS_ROOT) endif() if (NGRAPH_ONNX_IMPORT_ENABLE) - if (MSVS) + if (MSVC) # When we build dll libraries. These flags make sure onnx and protobuf build with /MD, not /MT. # These two options can't be mixed, because they requires link two imcompatiable runtime. set(ONNX_USE_MSVC_STATIC_RUNTIME OFF) set(protobuf_WITH_ZLIB OFF CACHE BOOL "" FORCE) set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Link protobuf to static runtime libraries" FORCE) - endif(MSVS) + endif() if (NOT NGRAPH_USE_SYSTEM_PROTOBUF) include(cmake/external_protobuf.cmake) else() @@ -591,7 +592,7 @@ endif() if(NGRAPH_CODEGEN_ENABLE) if (NGRAPH_USE_PREBUILT_LLVM OR DEFINED LLVM_TARBALL_URL) include(cmake/external_llvm_prebuilt.cmake) - elseif (NOT MSVS) + elseif (NOT MSVC) include(cmake/external_llvm.cmake) else() message(FATAL_ERROR "CODEGEN is not supported on Windows!") diff --git a/cmake/Modules/fix_mode.cmake b/cmake/Modules/fix_mode.cmake index 2f781befea3..53ac0ae73a8 100644 --- a/cmake/Modules/fix_mode.cmake +++ b/cmake/Modules/fix_mode.cmake @@ -16,7 +16,8 @@ function(MODE_APPLY_FILE PATH) execute_process(COMMAND git update-index --add --chmod=-x ${PATH} - OUTPUT_VARIABLE RESULT) + OUTPUT_VARIABLE RESULT + ERROR_QUIET) endfunction() set(DIRECTORIES_OF_INTEREST diff --git a/cmake/external_gtest.cmake b/cmake/external_gtest.cmake index f16cebaec8b..4b98360b57c 100644 --- a/cmake/external_gtest.cmake +++ b/cmake/external_gtest.cmake @@ -35,6 +35,12 @@ if(WIN32) ) endif() +if(CMAKE_BUILD_TYPE) + list(APPEND GTEST_CMAKE_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + ) +endif() + if(UNIX) # workaround for compile error # related: https://github.com/intel/mkl-dnn/issues/55 @@ -43,6 +49,17 @@ else() set(GTEST_CXX_FLAGS ${CMAKE_CXX_FLAGS}) endif() +#Build for ninja +if(UNIX) + SET(GTEST_PATHS ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/gtest/libgtest.a + ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/libgmock.a) +else() + SET(GTEST_PATHS ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/gtest/gtest.lib + ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/gtest/gmock.lib + ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/gtest/gtestd.lib + ${CMAKE_BINARY_DIR}/ngraph/gtest/build/googlemock/gtest/gmockd.lib) +endif() + ExternalProject_Add( ext_gtest PREFIX gtest @@ -60,6 +77,7 @@ ExternalProject_Add( ${GTEST_CMAKE_ARGS} BINARY_DIR "${EXTERNAL_PROJECTS_ROOT}/gtest/build" EXCLUDE_FROM_ALL TRUE + BUILD_BYPRODUCTS ${GTEST_PATHS} ) #------------------------------------------------------------------------------ diff --git a/cmake/external_mlir.cmake b/cmake/external_mlir.cmake index 3aa46a7cacf..5cb841fda87 100644 --- a/cmake/external_mlir.cmake +++ b/cmake/external_mlir.cmake @@ -20,8 +20,8 @@ set(MLIR_LLVM_REPO_URL https://github.com/llvm/llvm-project.git) set(MLIR_REPO_URL https://github.com/tensorflow/mlir.git) # Change these commit IDs to move to latest stable versions -set(MLIR_LLVM_COMMIT_ID 0845ac7331e) -set(MLIR_COMMIT_ID 1f7893e0) +set(MLIR_LLVM_COMMIT_ID e0f1d9d8729) +set(MLIR_COMMIT_ID c61db4bb) # MLIR environment variables. Some of them are used by LIT tool. set(MLIR_PROJECT_ROOT ${CMAKE_CURRENT_BINARY_DIR}/mlir_project) diff --git a/cmake/external_protobuf.cmake b/cmake/external_protobuf.cmake index bea4561a9b4..bf99662bda8 100644 --- a/cmake/external_protobuf.cmake +++ b/cmake/external_protobuf.cmake @@ -23,7 +23,12 @@ include(ExternalProject) # This version of PROTOBUF is required by Microsoft ONNX Runtime. set(NGRAPH_PROTOBUF_GIT_REPO_URL "https://github.com/protocolbuffers/protobuf") -set(NGRAPH_PROTOBUF_GIT_TAG "v3.5.2") + +if(NGRAPH_ONNX_IMPORT_ENABLE) + set(NGRAPH_PROTOBUF_GIT_TAG "v3.5.2") +else() + set(NGRAPH_PROTOBUF_GIT_TAG "v3.6.1") +endif() if (WIN32) ExternalProject_Add( @@ -103,14 +108,32 @@ if (WIN32) else() set(Protobuf_LIBRARY ${Protobuf_INSTALL_PREFIX}/lib/libprotobuf.a) endif() -set(Protobuf_LIBRARIES ${Protobuf_LIBRARY}) -if (NOT TARGET protobuf::libprotobuf) - add_library(protobuf::libprotobuf UNKNOWN IMPORTED) - set_target_properties(protobuf::libprotobuf PROPERTIES - INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}" - IMPORTED_LOCATION "${Protobuf_LIBRARY}") - add_dependencies(protobuf::libprotobuf ext_protobuf) +if(NGRAPH_ONNX_IMPORT_ENABLE) + if (NOT TARGET libprotobuf) + add_library(libprotobuf INTERFACE) + if (WIN32) + target_link_libraries(libprotobuf INTERFACE + debug ${Protobuf_INSTALL_PREFIX}/lib/libprotobufd.lib + optimized ${Protobuf_INSTALL_PREFIX}/lib/libprotobuf.lib) + else() + target_link_libraries(libprotobuf INTERFACE + ${Protobuf_INSTALL_PREFIX}/lib/libprotobuf.a) + endif() + set_target_properties(libprotobuf PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}") + add_dependencies(libprotobuf ext_protobuf) + endif() + set(Protobuf_LIBRARIES libprotobuf) +else() + if (NOT TARGET protobuf::libprotobuf) + add_library(protobuf::libprotobuf UNKNOWN IMPORTED) + set_target_properties(protobuf::libprotobuf PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${Protobuf_INCLUDE_DIR}" + IMPORTED_LOCATION "${Protobuf_LIBRARY}") + add_dependencies(protobuf::libprotobuf ext_protobuf) + endif() + set(Protobuf_LIBRARIES protobuf::libprotobuf) endif() if (NOT TARGET protobuf::protoc) diff --git a/doc/examples/dynamic_tensor/partial_shape.cpp b/doc/examples/dynamic_tensor/partial_shape.cpp new file mode 100644 index 00000000000..f7bb4acdc75 --- /dev/null +++ b/doc/examples/dynamic_tensor/partial_shape.cpp @@ -0,0 +1,68 @@ +//***************************************************************************** +// Copyright 2017-2019 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 + +using namespace ngraph; + +int main() +{ + // Create and compile a graph where the provided info of shape of x is + // (2,?) + auto x_shape_info = PartialShape{2, Dimension::dynamic()}; + auto x = make_shared(element::i32, x_shape_info); + auto a = x + x; + auto f = make_shared({a}, {x}); + auto be = runtime::backend::create(); + auto ex = be->compile(f); + + // Create a dynamic tensor of shape (2,?) + auto t_out = be->create_dynamic_tensor(element::i32, x_shape_info); + + // Call the graph to write a value with shape (2,3) to t_out + auto t_in = be->create_tensor(element::i32, Shape{2, 3}); + t_in->write(); + ex->call({t_out}, {t_in}) + + // Call the graph again, to write a value with a different shape to + // t_out. + t_in = be->create_tensor(element::i32, Shape{2, 20}); + t_in->write(); + ex->call({t_out}, {t_in}) + + // Get the result. At this point t_out->get_shape() would return + // Shape{2,20}, + // but t_out->get_partial_shape() would return "(2,?)" + + float r[2][3]; + t_result->read(&r, 0, sizeof(r)); + + std::cout << "[" << std::endl; + for (size_t i = 0; i < s[0]; ++i) + { + std::cout << " ["; + for (size_t j = 0; j < s[1]; ++j) + { + std::cout << r[i][j] << ' '; + } + std::cout << ']' << std::endl; + } + std::cout << ']' << std::endl; + + return 0; +} diff --git a/doc/sphinx/ngraph_theme/layout.html b/doc/sphinx/ngraph_theme/layout.html index ea95cba18f6..abc80193f8a 100644 --- a/doc/sphinx/ngraph_theme/layout.html +++ b/doc/sphinx/ngraph_theme/layout.html @@ -38,7 +38,9 @@ {% endif %} - + + + {% for cssfile in css_files %} @@ -84,14 +86,13 @@ + diff --git a/doc/sphinx/ngraph_theme/ngversions.html b/doc/sphinx/ngraph_theme/ngversions.html index 52f685d46bb..cdc30be0d4b 100644 --- a/doc/sphinx/ngraph_theme/ngversions.html +++ b/doc/sphinx/ngraph_theme/ngversions.html @@ -2,16 +2,15 @@ nGraph Compiler stack v: {{ version }} - +
-
{{ _('Recent Versions') }}
+
{{ _('Recent Versions') }}
    - -
  • Prerelease 0.26
  • -
  • 0.25.1
  • +
  • 0.26.0
  • +
  • 0.25.1
  • 0.25.0
  • 0.24.0
  • 0.22.2
  • diff --git a/doc/sphinx/ngraph_theme/static/css/theme.css b/doc/sphinx/ngraph_theme/static/css/theme.css index 3c4cb1f1c9d..ab4bc961415 100644 --- a/doc/sphinx/ngraph_theme/static/css/theme.css +++ b/doc/sphinx/ngraph_theme/static/css/theme.css @@ -49,24 +49,19 @@ div.menu-float { text-align: center; background: #393F4D; opacity: 0.9717; - /* margin-left: 55%; */ - /* margin-right: 3%; */ padding: 3px; border-top: 1px solid #999999; border-left: 1px solid #999999; border-right: 1px solid #999999; margin-top: -2px; margin-left: -2px; - /* -moz-box-shadow: 2px 3px 2px #d3d3d3; */ - /* -webkit-box-shadow: 2px 3px 2px #d3d3d3 */ - /* box-shadow: 3px 4px 3px #d3d3d3; */ -webkit-border-radius: 0.1px; -moz-border-radius: 0.1px; border-radius: 0.1px; z-index:1000; } -div.menu-float a, div.floating-menu h3 {display:inline-block; margin:0 0.5em; font-size: 143%; line-height: 1.41em; color: #fcfcfc; } +div.menu-float a, div.floating-menu h3 {display:inline-block; margin:0 0.5em; font-size: 133%; line-height: 1.31em; color: #fcfcfc; } #nav { @@ -1535,7 +1530,7 @@ a:hover { } a:visited { - color: #FFA400; + color: #DC700D; } html { @@ -1644,7 +1639,6 @@ h1 { h2 { font-size: 133%; - text-decoration: underline 4px dotted #D3D3D3; margin-top: -2px; } @@ -1761,7 +1755,7 @@ div[class^='highlight'] td.code { .wy-menu-vertical p.caption { font-family: Nunito, 'Nunito Sans', Helvetica, 'Helvetica Neue', sans; - text-decoration: underline 2px #393F4D; + /* text-decoration: underline 2px #393F4D; */ font-size: 110%; color: #23221d; background-color: #FAFBFD; @@ -2215,6 +2209,10 @@ div[class^='highlight'] pre { padding: 6px; color: #FDC939; } +.rst-other-versions a:hover { + color: #555; + background-color: #e0e0e0; +} .rst-versions.rst-badge { width: auto; bottom: 20px; @@ -2430,7 +2428,6 @@ div[class^='highlight'] pre { .rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { font-size: 91% !important; color: #152a58; - text-decoration: underline 2px dotted #cdcac5; background-color: #fff; line-height: 0.8955em; } @@ -2666,7 +2663,7 @@ span[id*='MathJax-Span'] { font-family: 'Nunito Sans', Nunito, Helvetica, 'Helvetica Neue', sans; font-weight: bolder; border-top: 5px dotted #FFA400; - border-bottom: 29px solid #d3d3d3; + border-bottom: 28px solid #d3d3d3; font-size: 131%; color: #393F4D; width: auto; @@ -2816,15 +2813,12 @@ span[id*='MathJax-Span'] { } .wy-menu-vertical a:hover { background-color: #fafbfd; - text-decoration: underline 1.33em dotted; - cursor: pointer; } .wy-menu-vertical a:hover span.toctree-expand { color: #e8e8e8; } .wy-menu-vertical a:active { background-color: #FAFBFD; - cursor: pointer; color: #555; } .wy-menu-vertical a:active span.toctree-expand { diff --git a/doc/sphinx/source/backends/index.rst b/doc/sphinx/source/backends/index.rst index c07988f389c..d4472f9c857 100644 --- a/doc/sphinx/source/backends/index.rst +++ b/doc/sphinx/source/backends/index.rst @@ -51,7 +51,7 @@ How to use? #. A single iteration of the executable is executed by calling the ``call`` method on the ``Executable`` object. -.. figure:: ../graphics/ExecutionInterfaceRunGraphs.png +.. figure:: ../graphics/execution-interface-run-graph.svg :width: 650px The execution interface for nGraph diff --git a/doc/sphinx/source/buildlb.rst b/doc/sphinx/source/buildlb.rst index 6e89c65d6e1..8f4eeca9fa5 100644 --- a/doc/sphinx/source/buildlb.rst +++ b/doc/sphinx/source/buildlb.rst @@ -106,7 +106,7 @@ The process documented here will work on Ubuntu\* 16.04 (LTS) or on Ubuntu .. code-block:: console - $ cmake .. [-DNGRAPH_USE_PREBUILT_LLVM=OFF] [-DNGRAPH_TARGET_ARCH=skylake-avx512] + $ cmake .. [-DNGRAPH_TARGET_ARCH=skylake-avx512] #. Run ``$ make`` and ``make install`` to install ``libngraph.so`` and the header files to ``~/ngraph_dist``: diff --git a/doc/sphinx/source/core/constructing-graphs/distribute-train.rst b/doc/sphinx/source/core/constructing-graphs/distribute-train.rst index 96d6dc0fdb2..4f6f0fd57ac 100644 --- a/doc/sphinx/source/core/constructing-graphs/distribute-train.rst +++ b/doc/sphinx/source/core/constructing-graphs/distribute-train.rst @@ -33,7 +33,7 @@ Finally, to run the training using two nGraph devices, invoke .. code-block:: console - $ mpirun + mpirun To deploy data-parallel training, the ``AllReduce`` op should be added after the steps needed to complete the :doc:`backpropagation <../constructing-graphs/derive-for-training>`; @@ -48,7 +48,7 @@ See the `full code`_ in the ``examples`` folder ``/doc/examples/mnist_mlp/dist_m .. code-block:: console - $ mpirun -np 2 dist_mnist_mlp + mpirun -np 2 dist_mnist_mlp .. _Intel MLSL: https://github.com/intel/MLSL/releases diff --git a/doc/sphinx/source/core/constructing-graphs/execute.rst b/doc/sphinx/source/core/constructing-graphs/execute.rst index a53cb6bacbf..491c215218b 100644 --- a/doc/sphinx/source/core/constructing-graphs/execute.rst +++ b/doc/sphinx/source/core/constructing-graphs/execute.rst @@ -5,17 +5,40 @@ Execute a computation ###################### This section explains how to manually perform the steps that would normally be -performed by a framework :term:`bridge` to execute a computation. The nGraph -library is targeted toward automatic construction; it is far easier for a -processing unit (GPU, CPU, or an `Intel Nervana NNP`_) to run a computation than -it is for a human to map out how that computation happens. Unfortunately, things +performed by a framework :term:`bridge` to execute a computation. nGraph graphs +are targeted toward automatic construction; it is far easier for a processor +(a CPU, GPU, or `purpose-built silicon`_) to execute a computation than it is +for a human to map out how that computation happens. Unfortunately, things that make by-hand graph construction simpler tend to make automatic construction more difficult, and vice versa. -Here we will do all the bridge steps manually. The :term:`model description` -walk-through below is based on the :file:`abc.cpp` code in the ``/doc/examples/`` -directory. We'll be deconstructing the steps that must happen (either programmatically -or manually) in order to successfully execute a computation: +Nevertheless, it can be helpful to break down what is happening during graph +construction. The documetation that follows explains two approaches frameworks +can use to compile with nGraph operations: + +* :ref:`Using complete shapes ` +* :ref:`Using partial shapes ` + +The nGraph :abbr:`Intermediate Representation (IR)` uses a strong, dynamic +type system, including static shapes. This means that at compilation, every +tensor (or, equivalently, every node output) in the graph is assigned +**complete shape information**; that is, one and only one shape. The static +process by which this assignment takes place is called :term:`shape propagation`. + +In the :ref:`first scenario `, the :term:`model description` +walk-through is based on the :file:`abc.cpp` code in the ``/doc/examples/abc`` +directory, and it deconstructs the steps that must happen (either programmatically +or manually) in order to successfully execute a computation given complete +shape information. + +.. _scenario_one: + +Scenario One: Using Complete Shapes +=================================== + +A step-by-step example of how a framework might execute with complete shape +information is provided here. For a step-by-step example using dynamic +shapes, see :ref:`scenario_two`. * :ref:`define_cmp` * :ref:`specify_backend` @@ -25,13 +48,11 @@ or manually) in order to successfully execute a computation: * :ref:`invoke_cmp` * :ref:`access_outputs` -The full code is at the :ref:`end of this page `. - .. _define_cmp: Define the computation -====================== +---------------------- To a :term:`framework`, a computation is simply a transformation of inputs to outputs. While a :term:`bridge` can programmatically construct the graph @@ -111,10 +132,10 @@ function, in the order they are to be passed to the compiled function. A .. _specify_backend: Specify the backend upon which to run the computation -===================================================== +----------------------------------------------------- For a framework bridge, a *backend* is the environment that can perform the -computations; it can be done with a CPU, GPU, or an Intel Nervana NNP. A +computations; it can be done with a CPU, GPU, or `purpose-built silicon`_. A *transformer* can compile computations for a backend, allocate and deallocate tensors, and invoke computations. @@ -123,7 +144,7 @@ and allocate backends. A backend is somewhat analogous to a multi-threaded process. There are two backends for the CPU: the optimized ``"CPU"`` backend, which uses -the `Intel MKL-DNN`_, and the ``"INTERPRETER"`` backend, which runs reference +the `DNNL`_, and the ``"INTERPRETER"`` backend, which runs reference versions of kernels that favor implementation clarity over speed. The ``"INTERPRETER"`` backend can be slow, and is primarily intended for testing. See the documentation on :doc:`runtime options for various backends <../../backends/index>` @@ -139,7 +160,7 @@ To continue with our original example and select the ``"CPU_Backend"``: .. _compile_cmp: Compile the computation -======================= +----------------------- Compilation triggers something that can be used as a factory for producing a ``CallFrame`` which is a *function* and its associated *state* that can run @@ -152,7 +173,7 @@ thread needs to execute the function at the same time, create multiple .. _allocate_backend_storage: Allocate backend storage for the inputs and outputs -=================================================== +--------------------------------------------------- At the graph level, functions are stateless. They do have internal state related to execution, but there is no user-visible state. Variables must be passed as @@ -182,7 +203,7 @@ with ``Tensor``. .. _initialize_inputs: Initialize the inputs -===================== +--------------------- Next we need to copy some data into the tensors. @@ -196,7 +217,7 @@ copying data to/from the tensor. .. _invoke_cmp: Invoke the computation -====================== +---------------------- To invoke the function, we simply pass argument and resultant tensors to the call frame: @@ -209,7 +230,7 @@ call frame: .. _access_outputs: Access the outputs -================== +------------------ We can use the ``read`` method to access the result: @@ -217,10 +238,10 @@ We can use the ``read`` method to access the result: :language: cpp :lines: 60-77 -.. _all_together: +.. _sshp: -Put it all together -=================== +Compiling with Complete Shape Information +----------------------------------------- .. literalinclude:: ../../../../examples/abc/abc.cpp :language: cpp @@ -228,7 +249,96 @@ Put it all together :caption: "The (a + b) * c example for executing a computation on nGraph" +.. _scenario_two: + +Scenario Two: Known Partial Shape +================================= + +The :ref:`second scenario ` involves the use of dynamic tensors. +A :term:`dynamic tensor` is a tensor whose shape can change from one "iteration" +to the next. When a dynamic tensor is created, a framework :term:`bridge` might +supply only *partial* shape information: it might be **all** the tensor +dimensions, **some** of the tensor dimensions, or **none** of the tensor +dimensions; furthermore, the rank of the tensor may be left unspecified. +The "actual" shape of the tensor is not specified until some function writes +some value to it. The actual shape can change when the value of the tensor +is overwritten. It is the backend’s responsibility to set the actual shape. +The :term:`model description` for the second scenario based on the +:file:`partial_shape.cpp` code in the ``/doc/examples/dynamic_tensor`` +directory, and it deconstructs the steps that must happen (either +programmatically or manually) in order to successfully retreive shape data. + +* :ref:`create_dyn_tensor` +* :ref:`call_graph_vw_` +* :ref:`call_graph_vwnew` +* :ref:`kpsh` + + +Create and compile a graph for ``f(x) = x + x`` where the provided info +of shape ``x`` is ``(2,?)``: + +.. literalinclude:: ../../../../examples/dynamic_tensor/partial_shape.cpp + :language: cpp + :lines: 27-32 + + +.. _create_dyn_tensor: + +Create a dynamic tensor +----------------------- + +Create a dynamic tensor of shape ``(2,?)`` + +.. literalinclude:: ../../../../examples/dynamic_tensor/partial_shape.cpp + :language: cpp + :lines: 35 + +At this point, ``t_out->get_shape()`` would throw an exception, while +``t_out->get_partial_shape()`` would return ``"(2,?)"``. + + +.. _call_graph_vw_: + +Write shape +----------- + +Call the graph to write a value with shape (2,3) to t_out + +.. literalinclude:: ../../../../examples/dynamic_tensor/partial_shape.cpp + :language: cpp + :lines: 38-40 + +At this point, ``t_out->get_shape()`` would return ``Shape{2,3}``, +while ``t_out->get_partial_shape()`` would return ``"(2,?)"``. + + +.. _call_graph_vwnew: + +Write new shape +--------------- + +Call the graph again, to write a value with a different shape to ``t_out``. + +.. literalinclude:: ../../../../examples/dynamic_tensor/partial_shape.cpp + :language: cpp + :lines: 44-45 + +At this point, ``t_out->get_shape()`` would return ``Shape{2,20}``, +while ``t_out->get_partial_shape()`` would return ``"(2,?)"``. + + +.. _kpsh: + +Compiling with Known Partial Shape +---------------------------------- + +.. literalinclude:: ../../../../examples/dynamic_tensor/partial_shape.cpp + :language: cpp + :linenos: + :caption: "Full code for compiling with dynamic tensors and partial shape" + + +.. _purpose-built silicon: https://www.intel.ai/nervana-nnp +.. _DNNL: https://intel.github.io/mkl-dnn/ -.. _Intel MKL-DNN: https://01.org/mkl-dnn -.. _Intel Nervana NNP: https://ai.intel.com/intel-nervana-neural-network-processors-nnp-redefine-ai-silicon/ diff --git a/doc/sphinx/source/core/constructing-graphs/index.rst b/doc/sphinx/source/core/constructing-graphs/index.rst index 16a90ecd40c..e618dc8e0b5 100644 --- a/doc/sphinx/source/core/constructing-graphs/index.rst +++ b/doc/sphinx/source/core/constructing-graphs/index.rst @@ -30,34 +30,5 @@ resources, it can either: .. note:: This section is aimed at intermediate-level developers. It assumes an understanding of the concepts in the previous sections. It does not assume - knowledge of any particular frontend framework. - -Since our primary audience is developers who are pushing the boundaries of deep -learning systems, we go beyond the use of deep learning primitives, and include -APIs and documentation for developers who want the ability to write programs -that use custom backends. For example, we know that GPU resources can be useful -backends for *some* kinds of algorithmic operations while they impose inherent -limitations or slow down others. - -One of our goals with the nGraph library is to enable developers with tools to -quickly build programs that access and process data from a breadth of edge and -networked devices. This might mean bringing compute resources closer to edge -devices, or it might mean programatically adjusting a model or the compute -resources it requires, at an unknown or arbitrary time after it has been deemed -to be trained well enough. - -To get started, we've provided a basic example for how to :doc:`execute` a -computation that can run on an nGraph backend; this is analogous to a -framework bridge. We also provide a larger example for training and -evaluating a simple MNIST MLP model. - -For data scientists or algorithm developers who are trying to extract specifics -about the state of a model at a certain node, or who want to optimize a model -at a more granular level, we provide an example for how to :doc:`import` and -run inference after it has been exported from a DL framework. - -This section is under development; we'll continually populate it with more -articles geared toward data scientists, algorithm designers, framework developers, -backend engineers, and others. We welcome ideas and contributions from the -community. + knowledge of any particular frontend framework. diff --git a/doc/sphinx/source/core/overview.rst b/doc/sphinx/source/core/overview.rst index e873ccbb036..5c04219f803 100644 --- a/doc/sphinx/source/core/overview.rst +++ b/doc/sphinx/source/core/overview.rst @@ -1,7 +1,7 @@ .. core/overview.rst: -Basic concepts +Basic Concepts ============== .. figure:: ../graphics/nGraphCompilerstack.png diff --git a/doc/sphinx/source/core/passes/passes.rst b/doc/sphinx/source/core/passes/passes.rst index 0658c70bd6b..d9b591d3cad 100644 --- a/doc/sphinx/source/core/passes/passes.rst +++ b/doc/sphinx/source/core/passes/passes.rst @@ -62,7 +62,7 @@ hardware-specific primitives; here they get matched via Intel® MKL-DNN. .. _figure-simple-compiler: -.. figure:: ../../graphics/simple-compiler-passes.png +.. figure:: ../../graphics/simple-compiler-passes.svg :width: 750px :alt: Simple kernel fusion diff --git a/doc/sphinx/source/core/quantization.rst b/doc/sphinx/source/core/quantization.rst new file mode 100644 index 00000000000..51bb7432a55 --- /dev/null +++ b/doc/sphinx/source/core/quantization.rst @@ -0,0 +1,169 @@ +.. core/quantization.rst: + + +.. _quantization: + +Quantization +============ + +:term:`Quantization` refers the process of reducing the number of bits that +represent a number. In a :abbr:`DL (Deep Learning)` context, weights and +activations can be represented using 8-bit integers (INT8) to compress the +model size of a trained neural network without any significant loss in model +accuracy. INT8 is one kind of quantization. Compared with 32-bit floating point +(FP32), using arithmetic with lower precision, such as INT8, to calculate +weights and activation requires less memory. + + +Implementing a quantized model with nGraph +------------------------------------------ + +To implement a quantized model with nGraph, provide a partially (or fully) +quantized model (where the convolution layer in the model is replaced +with a quantized convolution, for example) to the nGraph Library along with +quantized parameters: weights, activations, scale, and zero point. + +.. note:: As of version |version|, only quantization for inference is supported. + +nGraph Quantized Operators (Ops) +-------------------------------- + +nGraph uses scale and zero point (also used by ONNX) to map real values to +quantized values. All quantized ops use scale and zero point +and can be used just like any other nGraph op. + +**Scale**: the quantization scale of the tensor + +**Zero point**: the zero point of the tensor + +**Round mode**: used in combination with scale and zero point to round real +values to quantized values + +.. table:: Quantization Ops + + + +-----------------------------------------------------------------+------------------------------------------------+ + | Op | Description | + +=================================================================+================================================+ + | :doc:`Quantize <../ops/quantize>` | Maps real values (r) to quantized values (q) | + | | using scale (s), zero point (z), | + | | and round mode; produces a quantized tensor. | + +-----------------------------------------------------------------+------------------------------------------------+ + | :doc:`Dequantize <../ops/dequantize>` | Maps quantized values (q) to real values (r) | + | | using scale (s) and zero point (z); converts | + | | a quantized tensor to a floating-point tensor. | + +-----------------------------------------------------------------+------------------------------------------------+ + | :mod:`FakeQuantize ` | Performs element-wise linear quantization. | + +-----------------------------------------------------------------+------------------------------------------------+ + | :mod:`QuantizedConvolution ` | Performs 8-bit convolution. | + +-----------------------------------------------------------------+------------------------------------------------+ + | :mod:`QuantizedDot ` | Performs 8-bit dot. | + +-----------------------------------------------------------------+------------------------------------------------+ + +Some frameworks such as TensorFlow\* have fused ops. nGraph provides optional +operations to help users easily translate (map) any quantized model created from +frameworks with fused ops to nGraph. Unlike builders, experimental ops take +scale and zero point instead of min and max. + +.. table:: Experimental Quantized Ops (optional) + + + +-----------------------------------+-------------------------------------+ + | Operator | Description | + +===================================+=====================================+ + | QuantizedConvolutionBias | This experimental op can be | + | | fused with a ReLU op. | + +-----------------------------------+-------------------------------------+ + | QuantizedConvolutionBiasAdd | This experimental op constructs a | + | | quantized convolution with bias and | + | | optional ReLU. And then takes input | + | | for the add operation. | + +-----------------------------------+-------------------------------------+ + | QuantizedConvolutionBiasSignedAdd | Same as QuantizedConvolutionBiasAdd | + | | but with signed add. | + +-----------------------------------+-------------------------------------+ + | QuantizedConvolutionRelu | This experimental op is designed | + | | for a particular use case that | + | | would require convolution | + | | and ReLU to be combined. | + +-----------------------------------+-------------------------------------+ + | QuantizedDotBias | This experimental op can be fused | + | | with a ReLU op. | + +-----------------------------------+-------------------------------------+ + +nGraph Quantization Design +-------------------------- + +The goal of nGraph quantization is to flexibly support a wide variety of +frameworks and users. The use of scale and zero point as well as quantized +builders in the nGraph design helps to achieve this goal. + +Scale and Zero Point +~~~~~~~~~~~~~~~~~~~~ + +Using scale and zero point allows nGraph to be framework agnostic (i.e., it +can equally support all deep learning frameworks). nGraph Bridges will +automatically convert min and max (provided by a DL framework) to scale and zero +point as needed. Quantized builders are available to help the bridges perform +this calculation. However, if users are directly using nGraph (and not using a +bridge), they are required to provide scale and zero point for quantized ops. + +Another advantage of using scale and zero point to express quantization +parameters is that users can flexibly implement quantized ops into various +nGraph backends. When implementing quantized ops, all current nGraph backends +will directly use scale and zero point (and not min and max) to perform +the quantized computation. + +Quantized Builders +~~~~~~~~~~~~~~~~~~ + +Quantized builders are helper utilities to assist framework integrators to +enable quantized models with nGraph. They serve as an API (interface) between +framework bridges and nGraph, allowing framework bridges to directly construct +ops in the nGraph Abstraction Layer. + +Quantized builders help nGraph framework bridges by: + +* Breaking down a fused quantized operator in the framework to a subgraph (of + quantized and non-quantized operators) in the nGraph core IR + +* Converting from min and max to scale and zero point based on the quantization + mode described by the DL framework + +.. note:: Fused ops and quantized builders serve the same purpose. + In the future, fused ops will replace quantized builders. + +.. table:: nGraph Quantized Builders + + +--------------------------+-----------------------------------+-----------------------------------------+ + | Category | Builder | Description | + +==========================+===================================+=========================================+ + | Scaled Mode | ScaledQuantize | Converts min and max to scale | + | Min / Max Builders | | and zero point using a scaled mode | + | | | calculation and then constructs and | + | | | returns an nGraph Quantize operator. | + | +-----------------------------------+-----------------------------------------+ + | | ScaledDequantize | Converts min and max to scale | + | | | and zero point using a scaled mode | + | | | calculation and then constructs and | + | | | returns an nGraph Dequantize operator. | + +--------------------------+-----------------------------------+-----------------------------------------+ + | Quantized Convolution | ScaledQuantizedConvolution | Constructs a quantized convolution | + | and Variants | | with an optional ReLU. | + | +-----------------------------------+-----------------------------------------+ + | | ScaledQuantizedConvolutionBias | Constructs a quantized convolution | + | | | with bias and an optional ReLU. | + | +-----------------------------------+-----------------------------------------+ + | | ScaledQuantizedConvolutionBiasAdd | Constructs a quantized convolution | + | | | with bias and an optional ReLU, where | + | | | the output is added to the output | + | | | of another convolution (sum_input). | + +--------------------------+-----------------------------------+-----------------------------------------+ + | Quantized Dot (Matmul) | ScaledQuantizedDot | Constructs a quantized dot (Matmul) | + | and Variants | | with an optional ReLU. | + | +-----------------------------------+-----------------------------------------+ + | | ScaledQuantizedDotBias | Constructs a quantized dot (Matmul) | + | | | with bias and an optional ReLU. | + +--------------------------+-----------------------------------+-----------------------------------------+ + | Quantized Concat | ScaledQuantizedConcat | Constructs a quantized concatenation. | + +--------------------------+-----------------------------------+-----------------------------------------+ diff --git a/doc/sphinx/source/dynamic/index.rst b/doc/sphinx/source/dynamic/index.rst new file mode 100644 index 00000000000..7808eabf961 --- /dev/null +++ b/doc/sphinx/source/dynamic/index.rst @@ -0,0 +1,41 @@ +.. dynamic/index.rst: + + +Dynamic Shapes +============== + +For an example on how to use dynamic shapes, see the :ref:`scenario_two` +documentation. + +Runtime Error Checking +---------------------- + +Static type-checking in the presence of dynamic shapes will make optimistic +assumptions about things like shape mismatches. For example, if an elementwise +op is provided inputs of shapes ``(2,?)`` and ``(?,5)``, the type checker will +proceed under the assumption that the user is not going to pass tensors with +inconsistent shape at runtime, and therefore infer an output shape of ``(2,5)``. +That means that shape mismatches can now occur at runtime. + + +.. _partial_shapes: + +PartialShape, Dimension, and Rank Classes +----------------------------------------- + +Partial shape information is expressed via the ``PartialShape``, ``Dimension``, +and ``Rank`` classes. + +.. note:: ``Rank`` is an alias for ``Dimension``, used when the value represents + the number of axes in a shape, rather than the size of one dimension in a shape. + + +.. doxygenclass:: ngraph::PartialShape + :project: ngraph + :members: + + +.. doxygenclass:: ngraph::Dimension + :project: ngraph + :members: + diff --git a/doc/sphinx/source/frameworks/index.rst b/doc/sphinx/source/frameworks/index.rst index a87d7622f0d..a1eaaf4bdae 100644 --- a/doc/sphinx/source/frameworks/index.rst +++ b/doc/sphinx/source/frameworks/index.rst @@ -1,3 +1,5 @@ +:orphan: + .. frameworks/index.rst Working with Frameworks @@ -11,4 +13,4 @@ Working with Frameworks onnx_integ.rst paddle_integ.rst tensorflow_connect.rst - other.rst + other/index.rst diff --git a/doc/sphinx/source/frameworks/onnx_integ.rst b/doc/sphinx/source/frameworks/onnx_integ.rst index db40ed7262d..6c4739d6c9c 100644 --- a/doc/sphinx/source/frameworks/onnx_integ.rst +++ b/doc/sphinx/source/frameworks/onnx_integ.rst @@ -1,7 +1,7 @@ .. frameworks/onnx_integ.rst: -ONNX overview -============= +ONNX +==== nGraph is able to import and execute ONNX models. Models are converted to nGraph's :abbr:`Intermediate Representation (IR)` and converted to ``Function`` diff --git a/doc/sphinx/source/frameworks/other.rst b/doc/sphinx/source/frameworks/other/index.rst similarity index 93% rename from doc/sphinx/source/frameworks/other.rst rename to doc/sphinx/source/frameworks/other/index.rst index f9c9809db97..d3bae434f3b 100644 --- a/doc/sphinx/source/frameworks/other.rst +++ b/doc/sphinx/source/frameworks/other/index.rst @@ -1,16 +1,18 @@ -.. frameworks/other.rst: +.. frameworks/other/index.rst: .. _fw_other: +.. contents:: + Integrating other frameworks ============================ This section details some of the *configuration options* and some of the *environment variables* that can be used to tune for optimal performance when your system already has a version of nGraph installed with one or more of our -supported :doc:`../backends/index`. +supported :doc:`../../backends/index`. -Regardless of the framework, after the :doc:`../buildlb` step, a good place +Regardless of the framework, after the :doc:`../../buildlb` step, a good place to start usually involves making the libraries available to the framework. On Linux\* systems built on Intel® Architecture, that command tends to looks something like: @@ -24,7 +26,7 @@ something like: Find or display version ----------------------- -If you're working with the :doc:`../python_api/index`, the following command +If you're working with the :doc:`../../python_api/index`, the following command may be useful: .. code-block:: console @@ -92,10 +94,10 @@ Training Deep Neural Networks ----------------------------- Before tweaking various environment variables, be aware that how the computation -gets executed depends upon the ordering of the data format that the model is -using. ``NHWC`` and ``NCHW`` are the two more common layouts in Deep Learning -models. Your ultimate runtime can vary greatly -- even when all other factors -are exactly the same -- when this detail is overlooked. +gets executed depends on the data layout that the model is using. ``NHWC`` and +``NCHW`` are common layouts in Deep Learning models. Your ultimate +runtime can vary greatly -- even when all other factors are exactly the same -- +when this detail is overlooked. For CPU (and most cuDNN) backends, the preferred layout is currently ``NCHW``. @@ -110,7 +112,7 @@ Intel® Math Kernel Library for Deep Neural Networks --------------------------------------------------- .. important:: Intel® MKL-DNN is automatically enabled as part of an - nGraph default :doc:`build <../buildlb>`; you do *not* need to add it + nGraph default :doc:`build <../../buildlb>`; you do *not* need to add it separately or as an additional component to be able to use these configuration settings. @@ -229,4 +231,3 @@ thus can make more efficient use of the underlying hardware. .. _BUILDING.md: https://github.com/NervanaSystems/ngraph/blob/master/python/BUILDING.md .. _GCC wiki for details: https://gcc.gnu.org/wiki/FunctionMultiVersioning .. _following article may be helpful: https://clearlinux.org/documentation/clear-linux/tutorials/fmv - diff --git a/doc/sphinx/source/frameworks/overview.rst b/doc/sphinx/source/frameworks/overview.rst index 1c2712f4690..da3312e3b7b 100644 --- a/doc/sphinx/source/frameworks/overview.rst +++ b/doc/sphinx/source/frameworks/overview.rst @@ -16,8 +16,9 @@ the nGraph Compiler, it helps to familiarize yourself with some basic concepts. We use the term :term:`bridge` to describe code that connects to any nGraph device backend(s) while maintaining the framework's programmatic or user interface. We have a `bridge for the TensorFlow framework`_. We also have a -:doc:`paddle_integ` bridge. Intel previously :doc:`contributed work to an MXNet bridge <../project/extras/testing_latency>`; -however, support for the MXNet bridge is no longer active. +:doc:`paddle_integ` bridge. Intel previously :doc:`contributed work to an MXNet +bridge <../project/extras/testing_latency>`; however, support for the MXNet +bridge is no longer active. `ONNX`_ on its own is not a framework; it can be used with nGraph's :doc:`../python_api/index` to import and execute ONNX models. @@ -37,7 +38,7 @@ data scientists, or for deployment in cloud container environments, nGraph's We invite anyone working on new and novel frameworks or neural network designs to explore our highly-modularized stack of components. -Please read the :doc:`other` section for other framework-agnostic +Please read the :doc:`other/index` section for other framework-agnostic configurations available to users of the nGraph Compiler stack. .. figure:: ../graphics/overview-translation-flow.svg diff --git a/doc/sphinx/source/frameworks/paddle_integ.rst b/doc/sphinx/source/frameworks/paddle_integ.rst index 024ff424d7a..9c9d5ab76e0 100644 --- a/doc/sphinx/source/frameworks/paddle_integ.rst +++ b/doc/sphinx/source/frameworks/paddle_integ.rst @@ -1,7 +1,7 @@ .. frameworks/paddle_integ.rst: -PaddlePaddle integration -======================== +PaddlePaddle\* +============== PaddlePaddle is an open source deep learning framework developed by Baidu. It aims to enable performant large-scale distributed computation for deep learning. @@ -47,8 +47,8 @@ nGraph code in one place allows for easy maintenance. .. _figure-paddle-design: -.. figure:: ../graphics/paddlepaddle_design.png - :width: 555px +.. figure:: ../graphics/paddlepaddle_design.svg + :width: 100% :alt: *Figure A* above depicts nGraph access from PaddlePaddle. The PaddlePaddle @@ -65,7 +65,7 @@ is organized in the following file structure: .. _figure-paddle-dir: .. figure:: ../graphics/PaddlePaddleDir.svg - :width: 555px + :width: 100% :alt: Compilation of nGraph is handled by the ``ngraph.cmake`` file in the diff --git a/doc/sphinx/source/frameworks/quickstart.rst b/doc/sphinx/source/frameworks/quickstart.rst index 005258db9fa..ae4e3c8e278 100644 --- a/doc/sphinx/source/frameworks/quickstart.rst +++ b/doc/sphinx/source/frameworks/quickstart.rst @@ -79,7 +79,7 @@ Other integration paths If you are considering incorporating components from the nGraph Compiler stack in your framework or neural network design, another useful doc is the section -on :doc:`other` . Contents here are also useful if you are working on +on :doc:`other/index` . Contents here are also useful if you are working on something built-from-scratch, or on an existing framework that is less widely-supported than the popular frameworks like TensorFlow and PyTorch. diff --git a/doc/sphinx/source/frameworks/tensorflow_connect.rst b/doc/sphinx/source/frameworks/tensorflow_connect.rst index a73360210e4..5719ee0f67c 100644 --- a/doc/sphinx/source/frameworks/tensorflow_connect.rst +++ b/doc/sphinx/source/frameworks/tensorflow_connect.rst @@ -1,7 +1,7 @@ .. frameworks/tensorflow_connect.rst: -nGraph Bridge for TensorFlow -============================ +TensorFlow\* +============ See the `README`_ on the `ngraph_bridge repo`_ for the many ways to connect diff --git a/doc/sphinx/source/glossary.rst b/doc/sphinx/source/glossary.rst index f6199a54d28..63e9e348096 100644 --- a/doc/sphinx/source/glossary.rst +++ b/doc/sphinx/source/glossary.rst @@ -101,11 +101,25 @@ Glossary In the context of a function graph, the term "result" refers to what stands in for the returned value. + dynamic tensor + + A tensor whose shape can change from one "iteration" to the next. When + created, a framework :term:`bridge` might supply only *partial* shape + information: it might be **all** the tensor dimensions, **some** of the + tensor dimensions, or **none** of the tensor dimensions; furthermore, + the rank of the tensor may be left unspecified. + shape The shape of a tensor is a tuple of non-negative integers that represents an exclusive upper bound for coordinate values. + shape propagation + + The static process by which assignment of every tensor (or, + equivalently, every node output) in the graph is assigned + **complete shape information**. + shared pointer The C++ standard template library has the template diff --git a/doc/sphinx/source/graphics/ExecutionInterfaceRunGraphs.png b/doc/sphinx/source/graphics/ExecutionInterfaceRunGraphs.png deleted file mode 100644 index d3bfceacccf..00000000000 Binary files a/doc/sphinx/source/graphics/ExecutionInterfaceRunGraphs.png and /dev/null differ diff --git a/doc/sphinx/source/graphics/dl-current-state.png b/doc/sphinx/source/graphics/dl-current-state.png deleted file mode 100644 index d652d749b23..00000000000 Binary files a/doc/sphinx/source/graphics/dl-current-state.png and /dev/null differ diff --git a/doc/sphinx/source/graphics/dl-current-state.xcf b/doc/sphinx/source/graphics/dl-current-state.xcf deleted file mode 100644 index 367d521a372..00000000000 Binary files a/doc/sphinx/source/graphics/dl-current-state.xcf and /dev/null differ diff --git a/doc/sphinx/source/graphics/execution-interface-run-graph.svg b/doc/sphinx/source/graphics/execution-interface-run-graph.svg new file mode 100644 index 00000000000..a7350f65a42 --- /dev/null +++ b/doc/sphinx/source/graphics/execution-interface-run-graph.svg @@ -0,0 +1 @@ + diff --git a/doc/sphinx/source/graphics/paddlepaddle_design.png b/doc/sphinx/source/graphics/paddlepaddle_design.png deleted file mode 100644 index bf289aa4e50..00000000000 Binary files a/doc/sphinx/source/graphics/paddlepaddle_design.png and /dev/null differ diff --git a/doc/sphinx/source/graphics/paddlepaddle_design.svg b/doc/sphinx/source/graphics/paddlepaddle_design.svg new file mode 100644 index 00000000000..e85952a7821 --- /dev/null +++ b/doc/sphinx/source/graphics/paddlepaddle_design.svg @@ -0,0 +1 @@ + diff --git a/doc/sphinx/source/graphics/scalability-matters.png b/doc/sphinx/source/graphics/scalability-matters.png deleted file mode 100644 index 221da00a8cd..00000000000 Binary files a/doc/sphinx/source/graphics/scalability-matters.png and /dev/null differ diff --git a/doc/sphinx/source/graphics/scalability-matters.xcf b/doc/sphinx/source/graphics/scalability-matters.xcf deleted file mode 100644 index 3d1c564531d..00000000000 Binary files a/doc/sphinx/source/graphics/scalability-matters.xcf and /dev/null differ diff --git a/doc/sphinx/source/graphics/simple-compiler-passes.png b/doc/sphinx/source/graphics/simple-compiler-passes.png deleted file mode 100644 index e1c6eb8830e..00000000000 Binary files a/doc/sphinx/source/graphics/simple-compiler-passes.png and /dev/null differ diff --git a/doc/sphinx/source/graphics/simple-compiler-passes.svg b/doc/sphinx/source/graphics/simple-compiler-passes.svg new file mode 100644 index 00000000000..7bfa2aaec8e --- /dev/null +++ b/doc/sphinx/source/graphics/simple-compiler-passes.svg @@ -0,0 +1 @@ + diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst index 11cec06a752..1e297fc1dbf 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/sphinx/source/index.rst @@ -39,38 +39,58 @@ nGraph Compiler Stack Documentation introduction.rst .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: Framework Support - frameworks/index.rst - frameworks/validated/list.rst - + frameworks/overview.rst + frameworks/tensorflow_connect.rst + frameworks/onnx_integ.rst + frameworks/paddle_integ.rst + frameworks/other/index.rst .. toctree:: :maxdepth: 1 :caption: nGraph Core - buildlb.rst core/overview.rst - core/fusion/index.rst - nGraph Core Ops + buildlb.rst core/constructing-graphs/index.rst core/passes/passes.rst + core/fusion/index.rst + nGraph Core Ops provenance/index.rst + Graph Execution API + core/quantization.rst + dynamic/index.rst .. toctree:: :maxdepth: 1 - :caption: APIs + :caption: Backend Support + + Basic Concepts + backends/plaidml-ng-api/index.rst + Integrating Other Backends + + +.. toctree:: + :maxdepth: 1 + :caption: Training + + training/index.rst + training/qat.rst + + +.. toctree:: + :maxdepth: 1 + :caption: Validated Workloads - python_api/index.rst - backends/index.rst - backends/cpp-api.rst + frameworks/validated/list.rst .. toctree:: :maxdepth: 1 - :caption: Inspecting Graphs + :caption: Debugging Graphs inspection/index.rst diff --git a/doc/sphinx/source/ops/add.rst b/doc/sphinx/source/ops/add.rst index bd5e0efdf8b..0171e9670e5 100644 --- a/doc/sphinx/source/ops/add.rst +++ b/doc/sphinx/source/ops/add.rst @@ -58,6 +58,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Add +.. doxygenclass:: ngraph::op::v0::Add :project: ngraph :members: diff --git a/doc/sphinx/source/ops/and.rst b/doc/sphinx/source/ops/and.rst index 19456bcdcc7..c7fe81f6bd6 100644 --- a/doc/sphinx/source/ops/and.rst +++ b/doc/sphinx/source/ops/and.rst @@ -50,6 +50,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::And +.. doxygenclass:: ngraph::op::v0::And :project: ngraph :members: diff --git a/doc/sphinx/source/ops/broadcast.rst b/doc/sphinx/source/ops/broadcast.rst index 2e027084533..8242ea0fc7e 100644 --- a/doc/sphinx/source/ops/broadcast.rst +++ b/doc/sphinx/source/ops/broadcast.rst @@ -91,6 +91,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Broadcast +.. doxygenclass:: ngraph::op::v0::Broadcast :project: ngraph :members: diff --git a/doc/sphinx/source/ops/divide.rst b/doc/sphinx/source/ops/divide.rst index 56f190bf99b..554de7db677 100644 --- a/doc/sphinx/source/ops/divide.rst +++ b/doc/sphinx/source/ops/divide.rst @@ -56,6 +56,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Divide +.. doxygenclass:: ngraph::op::v0::Divide :project: ngraph :members: diff --git a/doc/sphinx/source/ops/equal.rst b/doc/sphinx/source/ops/equal.rst index 807bd2932b5..5eb845b94e1 100644 --- a/doc/sphinx/source/ops/equal.rst +++ b/doc/sphinx/source/ops/equal.rst @@ -49,6 +49,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Equal +.. doxygenclass:: ngraph::op::v0::Equal :project: ngraph :members: diff --git a/doc/sphinx/source/ops/greater.rst b/doc/sphinx/source/ops/greater.rst index 34aeda8c2a3..187d3be95f8 100644 --- a/doc/sphinx/source/ops/greater.rst +++ b/doc/sphinx/source/ops/greater.rst @@ -48,6 +48,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Greater +.. doxygenclass:: ngraph::op::v0::Greater :project: ngraph :members: diff --git a/doc/sphinx/source/ops/greater_eq.rst b/doc/sphinx/source/ops/greater_eq.rst index 57880e10730..b7add4a37bf 100644 --- a/doc/sphinx/source/ops/greater_eq.rst +++ b/doc/sphinx/source/ops/greater_eq.rst @@ -48,6 +48,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::GreaterEq +.. doxygenclass:: ngraph::op::v0::GreaterEq :project: ngraph :members: diff --git a/doc/sphinx/source/ops/index.rst b/doc/sphinx/source/ops/index.rst index 0c6c0641028..76d8904c3af 100644 --- a/doc/sphinx/source/ops/index.rst +++ b/doc/sphinx/source/ops/index.rst @@ -4,7 +4,7 @@ List of Core ``ops`` #################### -Not currently a comprehensive list. +Some operations are experimental. :ref:`more_about` @@ -160,10 +160,9 @@ Not currently a comprehensive list. More about Core Ops ------------------- -An ``Op``'s primary role is to function as a node in a ddirected acyclic +An ``Op``'s primary role is to function as a node in a directed acyclic computation graph. - *Core ops* are ops that are available and generally useful to all framework bridges and that can be compiled by all transformers. A framework bridge may define framework-specific ops to simplify graph construction, provided that the @@ -188,14 +187,6 @@ where there is no ambiguity. If a framework supports extending the set of ops it offers, a bridge may even expose transformer-specific ops to the framework user. - -.. figure:: ../graphics/tablengraphops.png - :width: 535px - :alt: Operations Available in the nGraph IR - - Operations Available in the nGraph IR - - .. important:: Our design philosophy is that the graph is not a script for running kernels; rather, our compilation will match ``ops`` to appropriate kernels for the backend(s) in use. Thus, we expect that adding of new Core diff --git a/doc/sphinx/source/ops/less.rst b/doc/sphinx/source/ops/less.rst index 51e8251c03f..3d163c13347 100644 --- a/doc/sphinx/source/ops/less.rst +++ b/doc/sphinx/source/ops/less.rst @@ -48,6 +48,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Less +.. doxygenclass:: ngraph::op::v0::Less :project: ngraph :members: diff --git a/doc/sphinx/source/ops/less_eq.rst b/doc/sphinx/source/ops/less_eq.rst index 6f7b84011b0..3e446581f96 100644 --- a/doc/sphinx/source/ops/less_eq.rst +++ b/doc/sphinx/source/ops/less_eq.rst @@ -48,6 +48,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::LessEq +.. doxygenclass:: ngraph::op::v0::LessEq :project: ngraph :members: diff --git a/doc/sphinx/source/ops/maximum.rst b/doc/sphinx/source/ops/maximum.rst index 243bbeb6047..c7a22a168d8 100644 --- a/doc/sphinx/source/ops/maximum.rst +++ b/doc/sphinx/source/ops/maximum.rst @@ -56,6 +56,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Maximum +.. doxygenclass:: ngraph::op::v0::Maximum :project: ngraph :members: diff --git a/doc/sphinx/source/ops/minimum.rst b/doc/sphinx/source/ops/minimum.rst index 2d82245bf0c..a2fb51f2f21 100644 --- a/doc/sphinx/source/ops/minimum.rst +++ b/doc/sphinx/source/ops/minimum.rst @@ -56,6 +56,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Minimum +.. doxygenclass:: ngraph::op::v0::Minimum :project: ngraph :members: diff --git a/doc/sphinx/source/ops/multiply.rst b/doc/sphinx/source/ops/multiply.rst index e8ccbe3024b..a08887a21da 100644 --- a/doc/sphinx/source/ops/multiply.rst +++ b/doc/sphinx/source/ops/multiply.rst @@ -56,6 +56,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Multiply +.. doxygenclass:: ngraph::op::v0::Multiply :project: ngraph :members: diff --git a/doc/sphinx/source/ops/not.rst b/doc/sphinx/source/ops/not.rst index b8257e50563..5a0dde3e3c5 100644 --- a/doc/sphinx/source/ops/not.rst +++ b/doc/sphinx/source/ops/not.rst @@ -46,6 +46,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Not +.. doxygenclass:: ngraph::op::v0::Not :project: ngraph :members: diff --git a/doc/sphinx/source/ops/not_equal.rst b/doc/sphinx/source/ops/not_equal.rst index 5bd35f7722b..e3907710a73 100644 --- a/doc/sphinx/source/ops/not_equal.rst +++ b/doc/sphinx/source/ops/not_equal.rst @@ -49,6 +49,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::NotEqual +.. doxygenclass:: ngraph::op::v0::NotEqual :project: ngraph :members: diff --git a/doc/sphinx/source/ops/one_hot.rst b/doc/sphinx/source/ops/one_hot.rst index 7cb152fc78a..469e73b96f4 100644 --- a/doc/sphinx/source/ops/one_hot.rst +++ b/doc/sphinx/source/ops/one_hot.rst @@ -57,6 +57,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::OneHot +.. doxygenclass:: ngraph::op::v0::OneHot :project: ngraph :members: diff --git a/doc/sphinx/source/ops/or.rst b/doc/sphinx/source/ops/or.rst index 1c4805a4a05..b94d9c4c9e3 100644 --- a/doc/sphinx/source/ops/or.rst +++ b/doc/sphinx/source/ops/or.rst @@ -50,6 +50,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Or +.. doxygenclass:: ngraph::op::v0::Or :project: ngraph :members: diff --git a/doc/sphinx/source/ops/power.rst b/doc/sphinx/source/ops/power.rst index a1db1054b51..3ac1ed3e663 100644 --- a/doc/sphinx/source/ops/power.rst +++ b/doc/sphinx/source/ops/power.rst @@ -54,6 +54,6 @@ Backprop C++ Interface ============= -.. doxygenclass:: ngraph::op::Power +.. doxygenclass:: ngraph::op::v0::Power :project: ngraph :members: diff --git a/doc/sphinx/source/ops/slice.rst b/doc/sphinx/source/ops/slice.rst index 94417c0eece..1bfcfc336e6 100644 --- a/doc/sphinx/source/ops/slice.rst +++ b/doc/sphinx/source/ops/slice.rst @@ -65,7 +65,7 @@ where :math:`I=I_1, I_2, \ldots, I_n` is a coordinate of the output. C++ Interface ============= -.. doxygenclass:: ngraph::op::Slice +.. doxygenclass:: ngraph::op::v0::Slice :project: ngraph :members: diff --git a/doc/sphinx/source/ops/xor.rst b/doc/sphinx/source/ops/xor.rst index f6cf467a929..52d2ea2900f 100644 --- a/doc/sphinx/source/ops/xor.rst +++ b/doc/sphinx/source/ops/xor.rst @@ -50,6 +50,6 @@ Mathematical Definition C++ Interface ============= -.. doxygenclass:: ngraph::op::Xor +.. doxygenclass:: ngraph::op::v0::Xor :project: ngraph :members: diff --git a/doc/sphinx/source/project/release-notes.rst b/doc/sphinx/source/project/release-notes.rst index 3a416335f4a..be14a68d376 100644 --- a/doc/sphinx/source/project/release-notes.rst +++ b/doc/sphinx/source/project/release-notes.rst @@ -21,6 +21,27 @@ We are pleased to announce the release of version |version|. Core updates for |version| -------------------------- ++ New ops ++ Provenance improvements from 0.25.1 ++ More dynamic shape ops ++ More informative errors + + + +Latest documentation updates +---------------------------- + ++ Additional details on quantization ++ Index updates ++ API updates + +.. important:: Pre-releases (``-rc-0.*``) have newer features, and are less stable. + + + +Changelog on Previous Releases +============================== + + All ops support ``Output`` arguments + Additional ops + ONNX handling unknown domains @@ -31,21 +52,16 @@ Core updates for |version| + Negative indices/axes fixes + Better support for MKL-DNN 1.0 (DNNL) + Additional constant element types - -Latest documentation updates ----------------------------- - + Add new Sphinx-friendly theme (can be built natively for an alternative to ngraph.ai docs). + Update PaddlePaddle documentation to reflect demo directories instead of example directory. + Update doc regarding the validation of ``Sum`` op. -.. important:: Pre-releases (``-rc-0.*``) have newer features, and are less stable. +0.26.1 +------ ++ Performance increase for ``ConstantFolding`` pass -Changelog on Previous Releases -============================== - 0.25.1 ------ @@ -155,6 +171,7 @@ Changelog on Previous Releases pre-0.20 -------- + + More dynamic shape preparation + Distributed interface factored out + fp16 and bfloat16 types @@ -168,8 +185,6 @@ pre-0.20 + Additional ONNX ops + Add graph visualization tools to doc + Update doxygen to be friendlier to frontends - -.. 0.18 + Python formatting issue + mkl-dnn work-around + Event tracing improvements @@ -177,16 +192,12 @@ pre-0.20 + Begin tracking framework node names + ONNX quantization + More fusions - -.. 0.17 + Allow negative padding in more places + Add code generation for some quantized ops + Preliminary dynamic shape support + initial distributed ops + Pad op takes CoordinateDiff instead of Shape pad values to allow for negative padding. - -.. 0.16 + NodeInput and NodeOutput classes prepare for simplifications of Node + Test improvements + Additional quantization ops diff --git a/doc/sphinx/source/provenance/index.rst b/doc/sphinx/source/provenance/index.rst index 5b790a5a89b..824fb9acb8b 100644 --- a/doc/sphinx/source/provenance/index.rst +++ b/doc/sphinx/source/provenance/index.rst @@ -3,8 +3,10 @@ Provenance ########## + +.. include:: overview.rst + .. toctree:: :maxdepth: 1 - - overview.rst -.. other.rst + +.. other.rst \ No newline at end of file diff --git a/doc/sphinx/source/training/data_ingest.rst b/doc/sphinx/source/training/data_ingest.rst new file mode 100644 index 00000000000..1c09760d662 --- /dev/null +++ b/doc/sphinx/source/training/data_ingest.rst @@ -0,0 +1,31 @@ +.. training/data_ingest.rst: + +Data Ingestion +############## + + +Using TensorFlow +---------------- + +.. include:: tf_dist.rst + + +Using PaddlePaddle +------------------ + +.. include:: paddle_dist.rst + + +Using a custom framework +------------------------ + +.. include:: ../core/constructing-graphs/distribute-train.rst + +To synchronize gradients across all workers, the essential operation for data +parallel training, due to its simplicity and scalability over parameter servers, +is ``allreduce``. The AllReduce op is one of the nGraph Library’s core ops. To +enable gradient synchronization for a network, we simply inject the AllReduce op +into the computation graph, connecting the graph for the autodiff computation +and optimizer update (which then becomes part of the nGraph graph). The +nGraph Backend will handle the rest. + diff --git a/doc/sphinx/source/training/index.rst b/doc/sphinx/source/training/index.rst new file mode 100644 index 00000000000..c35b7a14d03 --- /dev/null +++ b/doc/sphinx/source/training/index.rst @@ -0,0 +1,13 @@ +.. training/index.rst: + + +Distributed Training +#################### + + +.. toctree:: + :maxdepth: 1 + + overview.rst + data_ingest.rst + diff --git a/doc/sphinx/source/training/overview.rst b/doc/sphinx/source/training/overview.rst new file mode 100644 index 00000000000..fbf844ceda1 --- /dev/null +++ b/doc/sphinx/source/training/overview.rst @@ -0,0 +1,31 @@ +.. training/overview.rst: + + +Basic Concepts +============== + +.. important:: Distributed training is not officially supported as of version + |version|; however, some configuration options have worked for nGraph + devices in testing environments. + + +Data scientists with locally-scalable rack or cloud-based resources will likely +find it worthwhile to experiment with different modes or variations of +distributed training. Deployments using nGraph Library with supported backends +can be configured to train with data parallelism and will soon work with model +parallelism. Distributing workloads is increasingly important, as more data and +bigger models mean the ability to :doc:`../core/constructing-graphs/distribute-train` +work with larger and larger datasets, or to work with models having many layers +that aren't designed to fit to a single device. + +Distributed training with data parallelism splits the data and each worker +node has the same model; during each iteration, the gradients are aggregated +across all workers with an op that performs "allreduce", and applied to update +the weights. + +Using multiple machines helps to scale and speed up deep learning. With large +mini-batch training, one could train ResNet-50 with Imagenet-1k data to the +*Top 5* classifier in minutes using thousands of CPU nodes. See +`arxiv.org/abs/1709.05011`_. + +.. _arxiv.org/abs/1709.05011: https://arxiv.org/format/1709.05011 \ No newline at end of file diff --git a/doc/sphinx/source/training/paddle_dist.rst b/doc/sphinx/source/training/paddle_dist.rst new file mode 100644 index 00000000000..347f52d330b --- /dev/null +++ b/doc/sphinx/source/training/paddle_dist.rst @@ -0,0 +1,7 @@ +.. training/paddle_dist.rst: + +Distributed Training with PaddlePaddle +====================================== + + + diff --git a/doc/sphinx/source/training/qat.rst b/doc/sphinx/source/training/qat.rst new file mode 100644 index 00000000000..3c87270e311 --- /dev/null +++ b/doc/sphinx/source/training/qat.rst @@ -0,0 +1,32 @@ +.. training/qat.rst: + + +Quantization-Aware Training +=========================== + +:abbr:`Quantization-Aware Training (QAT)` is a technique used to +quantize models during the training process. The main idea is that +the quantization is emulated in the forward path by inserting some +"Quantization" and "De-Quantization" nodes (Q-DQ) several places in +the network to emulate the inference quantization noise. The +expectation is the backward propagation will alter the weights so +that they will adapt to this noise, and the result loss will be much +better than traditional Post-Training Quantization. + +For the weights, it is also common to take different quantization +functions that cut off outliers. Some examples are available in the +`Distiller guide`_. Distiller is an open-source Python package for +neural network compression research. Network compression can reduce +the footprint of a neural network, increase its inference speed, and +save energy. Additionally, a framework for pruning, regularization +and quantization algorithms is provided. A set of tools for analyzing +and evaluating compression performance on previously-known +State-of-the-Art (SotA) algorithms + +When using :abbr:`QAT (Quantization-Aware Training)` techniques, the +position in which the Q-DQ ops are placed needs to align with the +fusions hardware does for inference. + + +.. _Distiller guide: https://nervanasystems.github.io/distiller/algo_quantization.html#quantization-aware-training + diff --git a/doc/sphinx/source/training/tf_dist.rst b/doc/sphinx/source/training/tf_dist.rst new file mode 100644 index 00000000000..96fff54540f --- /dev/null +++ b/doc/sphinx/source/training/tf_dist.rst @@ -0,0 +1,7 @@ +.. training/tf_dist.rst: + +Distributed Training with TensorFlow +==================================== + + + diff --git a/python/ngraph/ops.py b/python/ngraph/ops.py index 753322fbd63..3b808d89bec 100644 --- a/python/ngraph/ops.py +++ b/python/ngraph/ops.py @@ -310,7 +310,7 @@ def scale_shift(data, scale, shift, name=None): # type: (Node, Node, Node, str) @nameable_op -def space_to_depth(data, block_size, name=None): # type: (Node, int, str) -> Node +def space_to_depth(data, mode, block_size, name=None): # type: (Node, str, int, str) -> Node """Perform SpaceToDepth operation on the input tensor. SpaceToDepth rearranges blocks of spatial data into depth. @@ -318,11 +318,16 @@ def space_to_depth(data, block_size, name=None): # type: (Node, int, str) -> No and width dimensions are moved to the depth dimension. :param data: The node with data tensor. + :param mode: Specifies how the output depth dimension is gathered from block coordinates. + + blocks_first: The output depth is gathered from [block_size, ..., block_size, C] + depth_first: The output depth is gathered from [C, block_size, ..., block_size] + :param block_size: The size of the block of values to be moved. Scalar value. :param name: Optional output node name. :return: The new node performing a SpaceToDepth operation on input tensor. """ - return SpaceToDepth(data, block_size) + return SpaceToDepth(data, mode, block_size) @nameable_op diff --git a/python/pyngraph/ops/fused/hard_sigmoid.cpp b/python/pyngraph/ops/fused/hard_sigmoid.cpp index c5e32bdddef..d5759acbf0e 100644 --- a/python/pyngraph/ops/fused/hard_sigmoid.cpp +++ b/python/pyngraph/ops/fused/hard_sigmoid.cpp @@ -27,5 +27,7 @@ void regclass_pyngraph_op_HardSigmoid(py::module m) py::class_, ngraph::op::Op> hardsigmoid(m, "HardSigmoid"); hardsigmoid.doc() = "ngraph.impl.op.HardSigmoid wraps ngraph::op::HardSigmoid"; - hardsigmoid.def(py::init&, float&, float&>()); + hardsigmoid.def(py::init&, + const std::shared_ptr&, + const std::shared_ptr&>()); } diff --git a/python/pyngraph/ops/fused/space_to_depth.cpp b/python/pyngraph/ops/fused/space_to_depth.cpp index a23277e3426..65ffee867da 100644 --- a/python/pyngraph/ops/fused/space_to_depth.cpp +++ b/python/pyngraph/ops/fused/space_to_depth.cpp @@ -27,5 +27,5 @@ void regclass_pyngraph_op_SpaceToDepth(py::module m) py::class_, ngraph::op::Op> spacetodepth(m, "SpaceToDepth"); spacetodepth.doc() = "ngraph.impl.op.SpaceToDepth wraps ngraph::op::SpaceToDepth"; - spacetodepth.def(py::init&, int&>()); + spacetodepth.def(py::init&, const std::string&, int&>()); } diff --git a/python/test/ngraph/test_ops_fused.py b/python/test/ngraph/test_ops_fused.py index 28f37a62a87..bf7bb23857d 100644 --- a/python/test/ngraph/test_ops_fused.py +++ b/python/test/ngraph/test_ops_fused.py @@ -351,17 +351,19 @@ def test_hard_sigmoid_operator(): runtime = get_runtime() data_shape = [3] - alpha = np.float32(0.5) - beta = np.float32(0.6) + alpha_value = np.float32(0.5) + beta_value = np.float32(0.6) data_value = np.array([-1, 0, 1], dtype=np.float32) parameter_data = ng.parameter(data_shape, name='Data', dtype=np.float32) + parameter_alpha = ng.parameter([], name='Alpha', dtype=np.float32) + parameter_beta = ng.parameter([], name='Beta', dtype=np.float32) - model = ng.hard_sigmoid(parameter_data, alpha, beta) - computation = runtime.computation(model, parameter_data) + model = ng.hard_sigmoid(parameter_data, parameter_alpha, parameter_beta) + computation = runtime.computation(model, parameter_data, parameter_alpha, parameter_beta) - result = computation(data_value) + result = computation(data_value, alpha_value, beta_value) expected = [0.1, 0.6, 1.] assert np.allclose(result, expected) @@ -429,11 +431,12 @@ def test_space_to_depth_operator(): data_shape = [1, 2, 4, 4] data_value = np.arange(start=0, stop=32, step=1.0, dtype=np.float32).reshape(data_shape) + mode = 'blocks_first' block_size = 2 parameter_data = ng.parameter(data_shape, name='Data', dtype=np.float32) - model = ng.space_to_depth(parameter_data, block_size) + model = ng.space_to_depth(parameter_data, mode, block_size) computation = runtime.computation(model, parameter_data) result = computation(data_value) diff --git a/src/contrib/mlir/CMakeLists.txt b/src/contrib/mlir/CMakeLists.txt index 45bad89b191..a252f8fb60a 100644 --- a/src/contrib/mlir/CMakeLists.txt +++ b/src/contrib/mlir/CMakeLists.txt @@ -61,9 +61,9 @@ target_link_libraries( # some libs need whole archive linkage because of Globals static initialization function(whole_archive_link target) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") - set(link_flags "-Llib -Wl,-all_load ") + set(link_flags "-L${LLVM_BUILD_LIBRARY_DIR} -Wl,-force_load ") FOREACH(LIB ${ARGN}) - string(CONCAT link_flags ${link_flags} "${LIB}") + string(CONCAT link_flags ${link_flags} "${LIB} ") ENDFOREACH(LIB) else() set(link_flags "-Llib -Wl,--whole-archive,") @@ -77,10 +77,11 @@ function(whole_archive_link target) set_target_properties(${target} PROPERTIES LINK_FLAGS ${link_flags}) endfunction(whole_archive_link) -whole_archive_link(mlir_backend +set(LIBS ${LLVM_BUILD_LIBRARY_DIR}/libMLIRAffineOps.a ${LLVM_BUILD_LIBRARY_DIR}/libMLIRStandardOps.a ) +whole_archive_link(mlir_backend ${LIBS}) # Link LLVM libs target_link_libraries( mlir_backend PRIVATE diff --git a/src/contrib/mlir/backend/pass/affine_lowerer.cpp b/src/contrib/mlir/backend/pass/affine_lowerer.cpp index e4ad584246d..70d80a4e2fb 100644 --- a/src/contrib/mlir/backend/pass/affine_lowerer.cpp +++ b/src/contrib/mlir/backend/pass/affine_lowerer.cpp @@ -183,7 +183,20 @@ namespace void runOnModule() override; SmallVector buildOutputDefs(Operation* op, PatternRewriter& rewriter); - Value* createTempTensor(Type type, PatternRewriter& rewriter); + /// Allocates a linear buffer for a temporary tensor + Value* createTempBuffer(Type type, PatternRewriter& rewriter); + + /// Creates an allocation or view of a memref. + /// type MemRef Type + /// buffer Optional buffer value to create view over + /// offset Optional offset into the buffer this view starts at + /// + /// If buffer is null, a new allocation of a memref is created. + /// Offset is ignored. If buffer is non-null, then we create a temp + /// view over a pre-allocated buffer (see createTempBuffer) + + Value* + createTempMemref(Type type, Value* buffer, unsigned offset, PatternRewriter& rewriter); /// Inserts dealloc Ops for each temporary allocated by AllocOp void insertDeallocs(PatternRewriter& rewriter); @@ -313,44 +326,63 @@ namespace } else { + // For temporaries, we create two instructions: + // 1. Linear buffer allocation: If the ng value already has a buffer ID assigned, + // we re-use that linear buffer SSA value, else generate an AllocOp. + // 2. View creation: Create a view with the tensor shape and an N-D to 1 map over + // the linear buffer. + // If two memrefs are defined via 2 Views over the same buffer, then they share and + // will re-use the same buffer. auto tensorType = origResult->getType().cast(); - Value* newResult; + Value* newResult = nullptr; Attribute bufferIdAttr = getBufferId(op); + Type memRefType = typeConverter.convertType(tensorType); + + Value* bufferValue = nullptr; if (!bufferIdAttr) { // Allocate new memref - newResult = createTempTensor(typeConverter.convertType(tensorType), rewriter); + newResult = createTempMemref(memRefType, nullptr, 0, rewriter); } else { unsigned bufferId = bufferIdAttr.cast().getInt(); - // Re-use a memref if it exist, else create a new one and update map + // Re-use a buffer if it exist, else create a new one and update map IdToMemRefMap::iterator it = m_id_to_memref.find(bufferId); if (it == m_id_to_memref.end()) { - // create a new memref - newResult = - createTempTensor(typeConverter.convertType(tensorType), rewriter); - m_id_to_memref[bufferId] = newResult; + // create a new buffer + bufferValue = createTempBuffer(memRefType, rewriter); + m_id_to_memref[bufferId] = bufferValue; } else { - newResult = it->second; + bufferValue = it->second; } + // Create a temp view over the linear buffer + newResult = createTempMemref(memRefType, bufferValue, 0, rewriter); } + NGRAPH_CHECK(newResult != nullptr, "Temp memref value is not set"); newResults.push_back(newResult); } } return newResults; } - Value* DialectLoweringPass::createTempTensor(Type type, PatternRewriter& rewriter) + Value* DialectLoweringPass::createTempBuffer(Type type, PatternRewriter& rewriter) { MemRefType memRefType = type.cast(); NGRAPH_CHECK(memRefType.hasStaticShape(), "Dynamic shapes are not supported"); - Value* alloc = rewriter.create(rewriter.getUnknownLoc(), memRefType); + // deduce linear buffer shape + unsigned sizeInBytes = memRefType.getSizeInBits() / 8; + + MemRefType bufferType = + MemRefType::get({sizeInBytes}, IntegerType::get(8, type.getContext()), {}); + + Value* alloc = rewriter.create(rewriter.getUnknownLoc(), bufferType); + memRefsToDealloc.push_back(alloc); // TODO: @@ -366,6 +398,45 @@ namespace return alloc; } + Value* DialectLoweringPass::createTempMemref(Type type, + Value* buffer, + unsigned offset, + PatternRewriter& rewriter) + { + NGRAPH_CHECK(offset == 0, "Only zero offset is supported"); + MemRefType memRefType = type.cast(); + if (buffer) + { + // We have a buffer to map to. Create a view over it. + + // Create the N-D to 1D affine expression mapping the memref shape to the underlying + // linear + // buffer + // This is simply (d0, d1, d2, .. dN-1) --> d0 * S0 + d1 * S1 ... + dN-1 * SN-1 + // Where Si is the stride along the i_th dimension + auto shape = memRefType.getShape(); + SmallVector strides(shape.size(), 0); + strides[shape.size() - 1] = 1; + for (int64_t i = shape.size() - 2; i >= 0; i--) + { + strides[i] = strides[i + 1] * shape[i + 1]; + } + + auto map = makeStridedLinearLayoutMap(strides, offset, rewriter.getContext()); + MemRefType newMemRefType = MemRefType::get(shape, memRefType.getElementType(), map); + auto viewOp = rewriter.create( + buffer->getDefiningOp()->getLoc(), newMemRefType, buffer, llvm::None); + return viewOp.getResult(); + } + + // No buffer, create an atomic memref without underlying buffer + NGRAPH_CHECK(memRefType.hasStaticShape(), "Dynamic shapes are not supported"); + + Value* alloc = rewriter.create(rewriter.getUnknownLoc(), memRefType); + memRefsToDealloc.push_back(alloc); + return alloc; + } + /// Add llvm.noalias attribute to all the memref function arguments. We know that this is safe /// by nGraph op semantics. void DialectLoweringPass::insertNoAliasArgAttrs() @@ -521,7 +592,7 @@ namespace NGRAPH_CHECK(lhs->getType().isa()); Type elemTy = lhs->getType().dyn_cast().getElementType(); - LoopNestBuilder(pivs, lbs, ubs, steps)([&] { + AffineLoopNestBuilder(pivs, lbs, ubs, steps)([&] { ValueHandle val = iLHS(ivs); ValueHandle zero = createZeroConstant(elemTy); iRes(ivs) = intrinsics::select(val > zero, val, zero); @@ -591,12 +662,14 @@ namespace { IndexHandle n, k; - LoopBuilder(&n, nLb, nUb, nStep)( - [&] { LoopBuilder(&k, kLb, kUb, kStep)([&] { iRes(n, k) = zeroInit; }); }); + LoopBuilder::makeAffine(&n, nLb, nUb, nStep)([&] { + LoopBuilder::makeAffine(&k, kLb, kUb, kStep)([&] { iRes(n, k) = zeroInit; }); + }); } - LoopBuilder(&n, nLb, nUb, nStep)([&] { - LoopBuilder(&m, mLb, mUb, mStep)([&] { - LoopBuilder(&k, kLb, kUb, kStep)([&] { iRes(n, k) += iLhs(n, m) * iRhs(m, k); }); + LoopBuilder::makeAffine(&n, nLb, nUb, nStep)([&] { + LoopBuilder::makeAffine(&m, mLb, mUb, mStep)([&] { + LoopBuilder::makeAffine(&k, kLb, kUb, kStep)( + [&] { iRes(n, k) += iLhs(n, m) * iRhs(m, k); }); }); }); @@ -658,7 +731,7 @@ namespace indexVarSteps.push_back(vOperand.step(i)); } - LoopNestBuilder(indexVarPtrs, indexVarLbs, indexVarUbs, indexVarSteps)([&] { + AffineLoopNestBuilder(indexVarPtrs, indexVarLbs, indexVarUbs, indexVarSteps)([&] { IndexedValue ivRes(result); IndexedValue ivOperand(operand); @@ -758,12 +831,12 @@ namespace // params[P_0, P_1, .. P_(A-1), indices[I_0, .., I_(M-1)], // P_(A+1), ... P_(N-1)]; - LoopNestBuilder(indicesIVPtrs, indicesLbs, indicesUbs, indicesSteps)([&] { + AffineLoopNestBuilder(indicesIVPtrs, indicesLbs, indicesUbs, indicesSteps)([&] { // Load axis value from indices array and cast it to Index Type ValueHandle axisIdx = ValueHandle::create( (ValueHandle)iIndices(indicesIVs), rewriter.getIndexType()); - LoopNestBuilder(paramsIVPtrs, paramsLbs, paramsUbs, paramsSteps)([&] { + AffineLoopNestBuilder(paramsIVPtrs, paramsLbs, paramsUbs, paramsSteps)([&] { // construct indices for param // [P_0, P_1, .. P_axis-1, Indices[I0, I1, .. I_k-1], P_axis+1, P_axis+2, .. P_n-1] for (auto i = 0, j = 0; i < vParams.rank(); i++) @@ -965,8 +1038,7 @@ namespace NGRAPH_CHECK(affineExprs.size() == isEq.size() && isEq.size() == 2 * spatialRank, "Invalid number of expressions in the IntegerSet"); - nonPaddedRange = - rewriter.getIntegerSet(spatialRank, 2 * spatialRank, affineExprs, isEq); + nonPaddedRange = IntegerSet::get(spatialRank, 2 * spatialRank, affineExprs, isEq); } // Initialize output to zero @@ -975,9 +1047,9 @@ namespace auto resSpatialIndices = makeIndexHandles(spatialRank); auto resSpatialIndicesPtrs = makeIndexHandlePointers(resSpatialIndices); - LoopBuilder(&n, batchLb, batchUb, 1)([&] { - LoopBuilder(&k, numFiltersLb, numFiltersUb, 1)([&] { - LoopNestBuilder( + LoopBuilder::makeAffine(&n, batchLb, batchUb, 1)([&] { + LoopBuilder::makeAffine(&k, numFiltersLb, numFiltersUb, 1)([&] { + AffineLoopNestBuilder( resSpatialIndicesPtrs, resSpatialLbs, resSpatialUbs, resSteps)([&] { SmallVector resIndices; // Result indices @@ -994,13 +1066,13 @@ namespace IndexHandle n, k, c; // Convolution loop - LoopBuilder(&n, batchLb, batchUb, 1)([&] { + LoopBuilder::makeAffine(&n, batchLb, batchUb, 1)([&] { // Number of filters loop - LoopBuilder(&k, numFiltersLb, numFiltersUb, 1)([&] { + LoopBuilder::makeAffine(&k, numFiltersLb, numFiltersUb, 1)([&] { // Channels loop - LoopBuilder(&c, numChannelsLb, numChannelsUb, 1)([&] { + LoopBuilder::makeAffine(&c, numChannelsLb, numChannelsUb, 1)([&] { // Results loop - LoopNestBuilder( + AffineLoopNestBuilder( resSpatialIndicesPtrs, resSpatialLbs, resSpatialUbs, resSteps)([&] { // Compute image start indices SmallVector imgStartIndices; @@ -1017,10 +1089,10 @@ namespace resIndices.insert( resIndices.end(), resSpatialIndices.begin(), resSpatialIndices.end()); // Filters spatial loop - LoopNestBuilder(filtersSpatialIndicesPtrs, - filtersSpatialLbs, - filtersSpatialUbs, - filtersSteps)([&] { + AffineLoopNestBuilder(filtersSpatialIndicesPtrs, + filtersSpatialLbs, + filtersSpatialUbs, + filtersSteps)([&] { SmallVector imgIndices, filtersIndices; // Image indices // Here we compute the virtual start index into the padded image. @@ -1131,7 +1203,7 @@ namespace NGRAPH_CHECK(lhs->getType().isa()); Type elemTy = lhs->getType().cast().getElementType(); - LoopNestBuilder(pivs, lbs, ubs, steps)([&] { + AffineLoopNestBuilder(pivs, lbs, ubs, steps)([&] { ValueHandle val = iLHS(ivs); if (isa(op)) { @@ -1173,7 +1245,7 @@ namespace auto pivs = makeIndexHandlePointers(ivs); // Steps auto steps = vLHS.getSteps(); - LoopNestBuilder(pivs, lbs, ubs, steps)( + AffineLoopNestBuilder(pivs, lbs, ubs, steps)( // single stmt body [&] { if (isa(op)) @@ -1266,7 +1338,7 @@ namespace auto pivs = makeIndexHandlePointers(ivs); auto steps = vRes.getSteps(); auto initVal = vArg.lb(axis); - LoopNestBuilder(pivs, resLbs, resUbs, steps)( + AffineLoopNestBuilder(pivs, resLbs, resUbs, steps)( [&] { iRes(ivs) = ValueHandle::create(initVal, resTy); }); } @@ -1282,7 +1354,7 @@ namespace "Expected integer result type in index reduction"); // iterate over all argument dimensions - LoopNestBuilder(pAllIVs, argLbs, argUbs, steps)([&] { + AffineLoopNestBuilder(pAllIVs, argLbs, argUbs, steps)([&] { // build a list of non-reduction IVs for (auto i = 0; i < vArg.rank(); i++) { diff --git a/src/contrib/mlir/core/compiler.cpp b/src/contrib/mlir/core/compiler.cpp index 564e064474a..2859608b663 100644 --- a/src/contrib/mlir/core/compiler.cpp +++ b/src/contrib/mlir/core/compiler.cpp @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include diff --git a/src/contrib/mlir/core/compiler.hpp b/src/contrib/mlir/core/compiler.hpp index 49bb3a179fe..cbe8772dac6 100644 --- a/src/contrib/mlir/core/compiler.hpp +++ b/src/contrib/mlir/core/compiler.hpp @@ -24,7 +24,6 @@ #include "ngraph/descriptor/tensor.hpp" #include "ngraph/node.hpp" -#include #include #include #include diff --git a/src/contrib/mlir/core/ngraph_dialect/dialect.cpp b/src/contrib/mlir/core/ngraph_dialect/dialect.cpp index dc13d2b6868..d7ce4f5ca04 100644 --- a/src/contrib/mlir/core/ngraph_dialect/dialect.cpp +++ b/src/contrib/mlir/core/ngraph_dialect/dialect.cpp @@ -18,12 +18,12 @@ // not expose public API to the rest of nGraph codebase and heavily depends on MLIR API. #include "dialect.hpp" +#include +#include #include "ngraph/check.hpp" #include "ops.hpp" #include "type.hpp" -#include - using namespace mlir; NGraphOpsDialect::NGraphOpsDialect(mlir::MLIRContext* ctx) @@ -39,63 +39,64 @@ NGraphOpsDialect::NGraphOpsDialect(mlir::MLIRContext* ctx) >(); } -mlir::Type NGraphOpsDialect::parseType(llvm::StringRef tyData, mlir::Location loc) const +mlir::Type NGraphOpsDialect::parseType(mlir::DialectAsmParser& parser) const { - StringRef origTypeStr = tyData; MLIRContext* context = getContext(); // Process nGraph tensor type. - if (tyData.consume_front("tensor")) + // failure is true + if (!parser.parseOptionalKeyword("tensor")) { - if (!tyData.consume_front("<") || !tyData.consume_back(">")) + llvm::SMLoc typeLoc = parser.getCurrentLocation(); + if (parser.parseLess()) { - return (emitError(loc, "expected '<' and '>' enclosing the tensor shape: " + tyData), - Type()); + parser.emitError(typeLoc, "expected '<' and '>' enclosing the tensor shape"); + return Type(); } - // Get x-separated sub-strings. - SmallVector subStrings; - tyData.split(subStrings, "x"); - // Parse shape dimensions. SmallVector shape; - for (unsigned i = 0, end = subStrings.size() - 1; i < end; ++i) - { - StringRef dimStr = subStrings[i]; - int64_t dim = -1; - // NOTE: `consumeInteger` returns false if an integer was parsed successfully. - if (dimStr.consumeInteger(/*Radix=*/10, dim) || !dimStr.empty()) - { - return ( - emitError(loc, "expected a list of '[0-9]+x' dimension specifiers: " + tyData), - Type()); - } - - shape.push_back(dim); - } + parser.parseDimensionList(shape); + + // Parse the current element type. + Type eltType; - // Parse nGraph element type. - auto elem_ty = mlir::parseType(subStrings.back(), context); - if (!elem_ty) + parser.parseType(eltType); + if (!eltType) { - return (emitError(loc, "Unexpected element type in tensor type: " + tyData), Type()); + typeLoc = parser.getCurrentLocation(); + parser.emitError(typeLoc, "Invalid tensor element type"); } - - return NGTensorType::get(context, elem_ty, shape); + parser.parseGreater(); + return NGTensorType::get(context, eltType, shape); } + else + { + // parse nGraph scalar type + return parseEltType(parser); + } +} +mlir::Type NGraphOpsDialect::parseEltType(mlir::DialectAsmParser& parser) const +{ // Process nGraph integer element types. + MLIRContext* context = getContext(); + int width = 0; + bool isSigned = false; + llvm::SMLoc loc = parser.getCurrentLocation(); + + StringRef tyData = parser.getFullSymbolSpec(); + StringRef origTypeStr = tyData; + if (tyData.startswith("i") || tyData.startswith("u")) { - bool isSigned = tyData.consume_front("i"); - bool isUnsigned = tyData.consume_front("u"); - NGRAPH_CHECK(isSigned != isUnsigned, "nGraph integer cannot be signed and unsigned"); - + isSigned = tyData.consume_front("i"); + tyData.consume_front("u"); unsigned width = 0; // NOTE: `consumeInteger` returns false if an integer was parsed successfully. if (tyData.consumeInteger(/*Radix=*/10, width) || width == 0 || !tyData.empty()) { - return (emitError(loc, "Unexpected nGraph integer type: " + origTypeStr), Type()); + parser.emitError(loc, "Unexpected nGraph integer type: " + origTypeStr); } switch (width) @@ -108,9 +109,7 @@ mlir::Type NGraphOpsDialect::parseType(llvm::StringRef tyData, mlir::Location lo return isSigned ? NGIntegerType::getInt32(context) : NGIntegerType::getUInt32(context); case 64: return isSigned ? NGIntegerType::getInt64(context) : NGIntegerType::getUInt64(context); - default: - return (emitError(loc, "Unexpected width for nGraph integer type: " + origTypeStr), - Type()); + default: parser.emitError(loc, "Unexpected width for nGraph integer type: " + origTypeStr); } } @@ -119,43 +118,49 @@ mlir::Type NGraphOpsDialect::parseType(llvm::StringRef tyData, mlir::Location lo "Floating point types should be processed by standard parser"); // NOTE: We may hit this error if the nGraph type is not yet supported in parser. - return (emitError(loc, "Unknown nGraph type: " + origTypeStr), Type()); + parser.emitError(loc, "Unknown nGraph type: " + origTypeStr); + + return Type(); } -void NGraphOpsDialect::printType(mlir::Type type, raw_ostream& os) const +void NGraphOpsDialect::printType(mlir::Type type, mlir::DialectAsmPrinter& printer) const { switch (type.getKind()) { case NG_TENSOR_TYPE_ID: { - os << "tensor<"; + printer << "tensor<"; auto tensorTy = type.cast(); for (auto dim : tensorTy.getShape()) { - os << dim << 'x'; + printer << dim << 'x'; } - os << tensorTy.getElementType() << '>'; + printer << tensorTy.getElementType() << '>'; return; } case NG_I8_TYPE_ID: case NG_I16_TYPE_ID: case NG_I32_TYPE_ID: case NG_I64_TYPE_ID: + { + auto intTy = type.cast(); + printer << "i" << intTy.getWidth(); + return; + } case NG_U8_TYPE_ID: case NG_U16_TYPE_ID: case NG_U32_TYPE_ID: case NG_U64_TYPE_ID: { auto intTy = type.cast(); - os << "i" << intTy.getWidth(); + printer << "u" << intTy.getWidth(); return; } case NG_BOOL_TYPE_ID: { - os << "bool"; + printer << "bool"; return; } - default: { NGRAPH_CHECK(false, "Incorrect type to print?"); - } + default: NGRAPH_UNREACHABLE("Incorrect type to print?"); } } diff --git a/src/contrib/mlir/core/ngraph_dialect/dialect.hpp b/src/contrib/mlir/core/ngraph_dialect/dialect.hpp index 32b4f4a4b42..b9c7fa90b89 100644 --- a/src/contrib/mlir/core/ngraph_dialect/dialect.hpp +++ b/src/contrib/mlir/core/ngraph_dialect/dialect.hpp @@ -34,9 +34,12 @@ namespace mlir { public: explicit NGraphOpsDialect(mlir::MLIRContext* ctx); - mlir::Type parseType(llvm::StringRef tyData, mlir::Location loc) const override; - void printType(mlir::Type type, llvm::raw_ostream& os) const override; + + mlir::Type parseType(mlir::DialectAsmParser& parser) const override; + void printType(mlir::Type type, mlir::DialectAsmPrinter& printer) const override; static StringRef getDialectNamespace() { return "ng"; } + private: + mlir::Type parseEltType(mlir::DialectAsmParser& parser) const; }; } diff --git a/src/contrib/mlir/core/ngraph_dialect/fused_ops.td b/src/contrib/mlir/core/ngraph_dialect/fused_ops.td index 826c04fab45..df0c21de3bb 100644 --- a/src/contrib/mlir/core/ngraph_dialect/fused_ops.td +++ b/src/contrib/mlir/core/ngraph_dialect/fused_ops.td @@ -21,9 +21,10 @@ #ifdef NG_FUSED_OPS #else #define NG_FUSED_OPS + // Squeeze Op def NGSqueezeOp : - NG_OneResult_Op<"squeeze", [NoSideEffect, FusedOp]>, + NG_OneResult_Op<"squeeze", [NoSideEffect, DeclareOpInterfaceMethods]>, Arguments<(ins NG_TensorType:$data, NG_TensorType:$axes)> { let summary = "Squeeze Op"; @@ -32,14 +33,988 @@ def NGSqueezeOp : }]; let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; +} + +// Unsqueeze Op +def NGUnSqueezeOp : + NG_OneResult_Op<"unsqueeze", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, NG_TensorType:$axes)> +{ + let summary = "Unsqueeze Op"; + let description = [{ + Unsqueeze Op + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; +} + +// Squared Difference Op +def NGSquaredDiffOp : + NG_Binary_Op<"sqrdDiff", [DeclareOpInterfaceMethods]> +{ + let summary = "Squared Difference Op"; + let description = [{ + Squared Difference Op + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; +} + +// Split Op +def NGSplitOp : + NG_Variadic_Result_Op<"split", [DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, I64Attr:$axis, I64ArrayAttr:$numSplits)> +{ + let summary = "Split op"; + let description = [{ + Splits the input tensor into a list of smaller tensors ("pieces") + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let extraClassDeclaration = [{ + void setAxis(const Attribute& attr) { this->setAttr("axis", attr); } + void setNumSplits(const ArrayAttr& arrayAttr) { this->setAttr("numSplits", arrayAttr); } + }]; + +} + +// SpaceToDepth Op +def NGSpaceToDepthOp : + NG_OneResult_Op<"spaceToDepth", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, + DefaultValuedAttr:$blockSize, + DepthSpaceModeEnumAttr:$mode)> +{ + let summary = "Space to depth op"; + let description = [{ + SpaceToDepth permutes input tensor blocks of spatial data into depth dimension. + Values from the height and width dimensions are moved to the depth dimension. + Output node produces a tensor with shape: + [N, C * blocksize * blocksize, H / blocksize, W / blocksize] + + data Node producing the input tensor + blockSize The size of the block of values to be moved + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let extraClassDeclaration = [{ + void setBlockSize(const Attribute& attr) { this->setAttr("blockSize", attr); } + void setMode(const Attribute& attr) { this->setAttr("mode", attr); } + }]; +} + +// ShuffleChannels Op +def NGShuffleChannelsOp : + NG_OneResult_Op<"shuffleChannels", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, I64Attr:$axis, I64Attr:$groups)> +{ + let summary = "Shuffle Channels op"; + let description = [{ + Constructs a ShuffleChannels node. + data Node producing the input tensor + axis channel dimension index in the data tensor. A negative value means + that the index should be calculated from the back of the input data + shape. + groups number of groups the channel dimension specified by axis should be + split into + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let extraClassDeclaration = [{ + void setAxis(const Attribute& axis) { this->setAttr("axis", axis); } + void setGroups(const Attribute& groups) { this->setAttr("groups", groups); } + }]; +} + +// ScaleShift Op +def NGScaleShiftOp : + NG_Ternary_Op<"scaleShift", [DeclareOpInterfaceMethods]> +{ + let summary = "scaleShift op"; + let description = [{ + Operator performing Scale Shift transformation. + Y = Scale * Data + Shift + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; +} + +// RNN Cell Op +def NGRNNCellOp : + NG_OneResult_Op<"rnnCell", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$X, NG_TensorType:$W, NG_TensorType:$R, NG_TensorType:$H_t, + Variadic:$optionalArgs, + DefaultValuedAttr:$activations, + DefaultValuedAttr:$activationAlpha, + DefaultValuedAttr:$activationBeta, + DefaultValuedAttr:$clip, + I64Attr:$hiddenSize)> +{ + let summary = "RNN Cell"; + let description = [{ + RNN Cell + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *X, Value* W, Value* R, Value* H_t, " + "Attribute hiddenSize, ArrayAttr activations," + "ArrayAttr activationAlpha, ArrayAttr activationBeta, Attribute clip", [{ + tblgen_state.addOperands({X, W, R, H_t}); + tblgen_state.addAttribute("hiddenSize", hiddenSize); + tblgen_state.addAttribute("activations", activations); + tblgen_state.addAttribute("activationAlpha", activationAlpha); + tblgen_state.addAttribute("activationBeta", activationBeta); + tblgen_state.addAttribute("clip", clip); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + void setHiddenSize(const Attribute& attr) { this->setAttr("hiddenSize", attr); } + void setActivations(const ArrayAttr& attr) { this->setAttr("activations", attr); } + void setActivationAlpha(const ArrayAttr& attr) { this->setAttr("activationAlpha", attr); } + void setActivationBeta(const ArrayAttr& attr) { this->setAttr("activationBeta", attr); } + void setClip(const Attribute& attr) { this->setAttr("clip", attr); } + + // get bias operand if present + Value* B() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + }]; +} + +// Prelu Op +def NGPrelu : + NG_OneResult_Op<"prelu", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, NG_TensorType:$slope)> +{ + let summary = "Prelu op"; + let description = [{ + Prametrized Relu + x < 0 => f(x) = x * slope + x >= 0 => f(x) = x + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; +} + +// Normalize L2 Op +def NGNormalizeL2Op : + NG_OneResult_Op<"normalizeL2", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, NG_TensorType:$axis, F32Attr:$eps, EpsModeEnumAttr:$epsMode)> +{ + let summary = "NormalizeL2 op"; + let description = [{ + Constructs a Normalize operation. + data - Node producing the input tensor + axes - Node indicating axes along which reduction is + calculated + eps - The epsilon added to L2 norm. + eps_mode - Specifies how eps is combined with L2 value calculated + before division + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let extraClassDeclaration = [{ + void setEpsMode(const Attribute& epsMode) { this->setAttr("epsMOde", epsMode); } + void setEps(const Attribute& eps) { this->setAttr("eps", eps); } + }]; +} + +// MVN Op +def NGMVN : + NG_OneResult_Op<"mvn", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, + DefaultValuedAttr: $acrossChannels, + DefaultValuedAttr: $normalizeVariance, + DefaultValuedAttr : $eps)> +{ + let summary = "MVN op"; + let description = [{ + data Input tensor with data + normalize_variance flag that denotes whether to perform variance + normalization. + across_channels flag that denotes if mean values are shared across channels. + eps the number to be added to the variance to avoid division by zero when + normalizing the value + reduction_axes a list of axes, along which to reduce. + }]; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *data, ArrayAttr reductionAxes, Attribute normalizeVariance," + "Attribute eps", [{ + tblgen_state.addOperands(data); + tblgen_state.addAttribute("reductionAxes", reductionAxes); + tblgen_state.addAttribute("normalizeVariance", normalizeVariance); + tblgen_state.addAttribute("eps", eps); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + void setAcrossChannels(const Attribute& attr) { this->setAttr("acrossChannels", attr); } + void setNormalizeVariance(const Attribute& attr) { this->setAttr("normalizeVariance", attr); } + void setEps(const Attribute& attr) { this->setAttr("eps", attr); } + void setReductionAxes(const ArrayAttr& attr) { this->setAttr("reductionAxes", attr); } + }]; +} + +// MatMul Op +def NGMatMul : + NG_OneResult_Op<"matmul", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$A, NG_TensorType:$B, + DefaultValuedAttr:$transposeA, + DefaultValuedAttr:$transposeB)> +{ + let summary = "MatMul op"; + let description = [{ + A Matrix A + B Matrix B + transpose_a If matrix A should be transposed. + transpose_b If matrix B should be transposed. + }]; + + let extraClassDeclaration = [{ + void setTransposeA(const Attribute& attr) { this->setAttr("transposeA", attr); } + void setTransposeB(const Attribute& attr) { this->setAttr("transposeB", attr); } + }]; +} + +// LSTM Cell Op +// +def NGLSTMCellOp : + NG_OneResult_Op<"lstmCell", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$X, NG_TensorType:$W, NG_TensorType:$R, + NG_TensorType:$H_t, NG_TensorType:$C_t, + Variadic:$optionalArgs, + I64Attr:$hiddenSize, + DefaultValuedAttr(MLIRLSTMWeightsFormat::IFCO)">:$weightFormat, + DefaultValuedAttr:$activations, + DefaultValuedAttr:$activationAlpha, + DefaultValuedAttr:$activationBeta, + DefaultValuedAttr:$clip, + DefaultValuedAttr:$inputForget)> +{ + let summary = "LSTM Cell"; + let description = [{ + LSTM Cell + X The input tensor with shape: [batch_size, + + H_t The hidden state tensor at current time step with shape: [batch_size, hidden_size]. + + C_t The cell state tensor at current time step with shape: [batch_size, hidden_size]. + + W The weight tensor with shape: [4*hidden_size, input_size]. + + R The recurrence weight tensor with shape: [4*hidden_size, hidden_size]. + + B [Optional] The bias tensor for gates with shape: [4*hidden_size]. + + P [Optional] The weight tensor for peepholes with shape: + [3*hidden_size] - 3 equals to only iof gates. + The order is: input, output, forget gates. + + hiddenSize The number of hidden units for recurrent cell. + + weightsFormat The order of gates in weights tensors. + The default format is IFCO since it is used by DNNL. + + activations The vector of activation functions used inside + recurrent cell. + + activationsAlpha The vector of alpha parameters for activation + functions in order respective to activation list. + + activationsBeta The vector of beta parameters for activation + functions in order respective to activation list. + + clip The value defining clipping range [-clip, clip] on + input of activation functions. + + inputForget Controls coupling input and forget gates. + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ + return mlir::success(); /* TBD */ + }]; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *X, Value* W, Value* R, Value* H_t, Value* C_t," + "Attribute hiddenSize, ArrayAttr activations," + "ArrayAttr activationAlpha, ArrayAttr activationBeta," + "Attribute clip, Attribute inputForget", [{ + tblgen_state.addOperands({X, W, R, H_t, C_t}); + tblgen_state.addAttribute("hiddenSize", hiddenSize); + tblgen_state.addAttribute("activations", activations); + tblgen_state.addAttribute("activationAlpha", activationAlpha); + tblgen_state.addAttribute("activationBeta", activationBeta); + tblgen_state.addAttribute("clip", clip); + tblgen_state.addAttribute("inputForget", inputForget); + tblgen_state.addTypes(res); + }]>, + + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *X, Value* W, Value* R, Value* H_t, Value* C_t," + "Attribute hiddenSize", + [{ + tblgen_state.addOperands({X, W, R, H_t, C_t}); + tblgen_state.addAttribute("hiddenSize", hiddenSize); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + // get bias operand if present + Value* B() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + // get peephole weights operand if present + Value* P() + { + auto varArgs = optionalArgs(); + auto it = varArgs.begin(); + it = std::next(it); + if (it == varArgs.end()) + return nullptr; + it = std::next(it); + return it == varArgs.end() ? *it : nullptr; + } + + void setHiddenSize (const Attribute& attr) { this->setAttr("hiddenSize", attr); } + void setActivations (const ArrayAttr& attr) { this->setAttr("activation", attr); } + void setActivationsAlpha (const ArrayAttr& attr) { this->setAttr("activatiAlpha", attr); } + void setActivationsBeta (const ArrayAttr& attr) { this->setAttr("activatiBeta", attr); } + void setClip(const Attribute& attr) { this->setAttr("clip", attr); } + }]; +} + +// LSTM Sequence Op +def NGLSTMSequenceOp : + NG_OneResult_Op<"lstmSeq", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$X, NG_TensorType:$H_t, NG_TensorType:$C_t, + NG_TensorType:$S_l, NG_TensorType:$W, NG_TensorType:$R, + NG_TensorType:$B, Variadic:$optionalArgs, + I64Attr:$hiddenSize, + LSTMSeqDirectionsEnumAttr:$direction, + DefaultValuedAttr(MLIRLSTMWeightsFormat::IFCO)">:$weightFormat, + DefaultValuedAttr:$activations, + DefaultValuedAttr:$activationAlpha, + DefaultValuedAttr:$activationBeta, + DefaultValuedAttr:$clip, + DefaultValuedAttr:$inputForget)> +{ + let summary = "LSTM Sequence"; + let description = [{ + + Class for lstm sequence node. + + It follows notation and equations defined as in ONNX standard: + https://github.com/onnx/onnx/blob/master/docs/Operators.md#LSTM + + See: LSTMCell, RNNCell, GRUCell + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ + return mlir::success(); /* TBD */ + }]; - let verifier = [{ return verifyOp(this); }]; + let extraClassDeclaration = [{ + void setHiddenSize (const Attribute& attr) { this->setAttr("hiddenSize", attr); } + void setActivations (const ArrayAttr& attr) { this->setAttr("activation", attr); } + void setActivationsAlpha (const ArrayAttr& attr) { this->setAttr("activatiAlpha", attr); } + void setActivationsBeta (const ArrayAttr& attr) { this->setAttr("activatiBeta", attr); } + void setClip(const Attribute& attr) { this->setAttr("clip", attr); } + + Value* P() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + }]; +} + +// GRU Cell Op +def NGGRUCellOp : + NG_OneResult_Op<"gruCell", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$X, NG_TensorType:$W, NG_TensorType:$R, + NG_TensorType:$H_t, Variadic:$optionalArgs, + I64Attr:$hiddenSize, + DefaultValuedAttr:$activations, + DefaultValuedAttr:$activationAlpha, + DefaultValuedAttr:$activationBeta, + DefaultValuedAttr:$clip, + DefaultValuedAttr:$linearBeforeReset)> +{ + let summary = "This class represents only single *cell* and not whole GRU *layer*"; + let description = [{ + X The input tensor with shape: [batch_size, input_size]. + W The weight tensor with shape: + [gates_count * hidden_size, input_size]. + R The recurrence weight tensor with shape: + [gates_count * hidden_size, hidden_size]. + H_t The hidden state tensor at current time step with + shape: [batch_size, hidden_size]. + hidden_size The number of hidden units for recurrent cell. + B[Optional] The bias tensor for input gate with shape: + [2 * gates_count * hidden_size]. + activations The vector of activation functions used inside + recurrent cell. + activation_alpha The vector of alpha parameters for activation + functions in order respective to activation list. + activation_beta The vector of beta parameters for activation functions + in order respective to activation list. + clip The value defining clipping range [-clip, clip] on + input of activation functions. + }]; + + let parser = [{ NGRAPH_CHECK(false, "No parser support"); return mlir::failure(); }]; + let verifier = [{ return mlir::success(); /* TBD */ }]; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *X, Value* W, Value* R, Value* H_t," + "Attribute hiddenSize, ArrayAttr activations," + "ArrayAttr activationAlpha, ArrayAttr activationBeta," + "Attribute clip, Attribute linearBeforeReset", [{ + tblgen_state.addOperands({X, W, R, H_t}); + tblgen_state.addAttribute("hiddenSize", hiddenSize); + tblgen_state.addAttribute("activations", activations); + tblgen_state.addAttribute("activationAlpha", activationAlpha); + tblgen_state.addAttribute("activationBeta", activationBeta); + tblgen_state.addAttribute("linearBeforeReset", linearBeforeReset); + tblgen_state.addTypes(res); + }]>, + + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *X, Value* W, Value* R, Value* H_t," + "Attribute hiddenSize", + [{ + tblgen_state.addOperands({X, W, R, H_t}); + tblgen_state.addAttribute("hiddenSize", hiddenSize); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + void setHiddenSize (const Attribute& attr) { this->setAttr("hiddenSize", attr); } + void setActivations (const ArrayAttr& attr) { this->setAttr("activation", attr); } + void setActivationsAlpha (const ArrayAttr& attr) { this->setAttr("activatiAlpha", attr); } + void setActivationsBeta (const ArrayAttr& attr) { this->setAttr("activatiBeta", attr); } + void setLinearBeforeReset(const Attribute& attr) { this->setAttr("linearBeforeReset", attr); } + + // get Bias operand if present + Value* P() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + }]; +} + +// LayerNorm Op +// Op produces 3 results when keepStats is true +// Op is defined with 3 results, 2 of which are invalid/dead if keepStats is false +def NGLayerNormOp : + NG_Op<"layernorm", [NoSideEffect, DeclareOpInterfaceMethods]>, + Results<(outs NG_TensorType:$res, NG_TensorType:$mean, NG_TensorType:$var)>, + Arguments<(ins NG_TensorType:$data, Variadic:$optionalArgs, + DefaultValuedAttr:$keepStats, + DefaultValuedAttr :$beginNormAxis, + DefaultValuedAttr :$epsilon)> +{ + let summary = "LayerNorm Op"; + let description = "Constructs a LayerNorm operation."; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, ArrayRef res," + "Value *data, Attribute keepStats, Attribute beginNormAxis, Attribute epsilon", [{ + tblgen_state.addOperands(data); + tblgen_state.addAttribute("keepStats", keepStats); + tblgen_state.addAttribute("beginNormAxis", beginNormAxis); + tblgen_state.addAttribute("epsilon", epsilon); + tblgen_state.addTypes(res); + }]> + ]; let extraClassDeclaration = [{ - void decompose() { - //TODO: Call a templatized helper: decompose(this) to do the actual decomposition + // get Scale operand if present + Value* Scale() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + // get Bias operand if present + Value* Bias() + { + auto varArgs = optionalArgs(); + auto it = varArgs.begin(); + it = std::next(it); + if (it == varArgs.end()) + return nullptr; + it = std::next(it); + return it == varArgs.end() ? *it : nullptr; } + + void setKeepstats(const Attribute& attr) { this->setAttr("keepStats", attr); } + void setBeginNormAxis(const Attribute& attr) { this->setAttr("beginNormAxis", attr);} + void setEpsilonAxis(const Attribute& attr) { this->setAttr("epsilon", attr); } + }]; +} + + +// LayerNormBackprop Op +// Scale can be optional, in which case use a constant op of 0 +def NGLayerNormBackpropOp : + NG_Op<"layernormBackprop", [NoSideEffect, DeclareOpInterfaceMethods]>, + Results<(outs NG_TensorType:$d_data, NG_TensorType:$d_scale, NG_TensorType:$d_bias)>, + Arguments<(ins NG_TensorType:$data, NG_TensorType:$delta, NG_TensorType:$scale, + Variadic:$optionalArgs, + DefaultValuedAttr:$beginNormAxis, + DefaultValuedAttr:$epsilon)> +{ + let summary = "LayerNorm Op"; + let description = "Constructs an LayerNorm operation."; + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, ArrayRef res," + "Value *data, Value *delta, Value *mean, Value *variance," + "Attribute beginNormAxis, Attribute epsilon", [{ + tblgen_state.addOperands({data, delta, mean, variance}); + tblgen_state.addAttribute("beginNormAxis", beginNormAxis); + tblgen_state.addAttribute("epsilon", epsilon); + tblgen_state.addTypes(res); + }]>, + + OpBuilder< + "Builder *builder, OperationState &tblgen_state, ArrayRef res," + "Value *data, Value *delta, Value *scale," + "Attribute beginNormAxis, Attribute epsilon", [{ + tblgen_state.addOperands({data, delta, scale}); + tblgen_state.addAttribute("beginNormAxis", beginNormAxis); + tblgen_state.addAttribute("epsilon", epsilon); + tblgen_state.addTypes(res); + }]>, + + OpBuilder< + "Builder *builder, OperationState &tblgen_state, ArrayRef res," + "Value *data, Value *delta," + "Attribute beginNormAxis, Attribute epsilon", [{ + tblgen_state.addOperands({data, delta}); + tblgen_state.addAttribute("beginNormAxis", beginNormAxis); + tblgen_state.addAttribute("epsilon", epsilon); + tblgen_state.addTypes(res); + }]>, + ]; + + let extraClassDeclaration = [{ + // get Mean operand if present + Value* Mean() + { + auto varArgs = optionalArgs(); + return varArgs.begin() != varArgs.end() ? *varArgs.begin() : nullptr; + } + // get Variance operand if present + Value* Variance() + { + auto varArgs = optionalArgs(); + auto it = varArgs.begin(); + it = std::next(it); + if (it == varArgs.end()) + return nullptr; + it = std::next(it); + return it == varArgs.end() ? *it : nullptr; + } + + void setBeginNormAxis(const Attribute& attr) { this->setAttr("beginNormAxis", attr);} + void setEpsilonAxis(const Attribute& attr) { this->setAttr("epsilon", attr); } + }]; +} + +// HardSigmoid Op +def NGHardSigmoid : + NG_OneResult_Op<"hardSigmoid", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, + F32Attr:$alpha, F32Attr:$beta)> +{ + let summary = "Hard sigmoid op"; + let description = [{ + Parameterized, bounded sigmoid-like, piecewise linear + function. min(max(alpha*x + beta, 0), 1) + }]; + + let extraClassDeclaration = [{ + void setAlpha(const Attribute& attr) { this->setAttr("alpha", attr); } + void setBeta(const Attribute& attr) { this->setAttr("beta", attr); } + }]; +} + +// Gemm Op +def NGGemmOp : + NG_OneResult_Op<"gemm", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$A, NG_TensorType:$B, NG_TensorType:$C, + DefaultValuedAttr:$alpha, + DefaultValuedAttr:$beta, + DefaultValuedAttr:$transA, + DefaultValuedAttr:$transB)> +{ + let summary = "Gemm Op"; + let description = [{ + A' = transpose(A) if transA else A + B' = transpose(B) if transB else B + Compute Y = alpha * A' * B' + beta * C + }]; + + let extraClassDeclaration = [{ + void setAlpha(const Attribute& attr) { this->setAttr("alpha", attr);} + void setBeta(const Attribute& attr) { this->setAttr("beta", attr); } + + void setTransA(const Attribute& attr) { this->setAttr("transA", attr); } + void setTransB(const Attribute& attr) { this->setAttr("transB", attr); } + }]; +} + +// GroupConv Op +def NGGroupConvOp : + NG_OneResult_Op<"groupConv", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$images, NG_TensorType:$filters, + I64ArrayAttr:$strides, + I64ArrayAttr:$padBelow, + I64ArrayAttr:$padAbove, + I64Attr:$groups, + DefaultValuedAttr(MLIRPadType::EXPLICIT)">:$padType)> +{ + let summary = "Group Convolution Op"; + let description = [{ + Group Convolution + }]; + + let builders = [ + // Builder without padType + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res, Value *images," + "Value *filters, ArrayAttr strides, ArrayAttr padBelow, ArrayAttr padAbove," + "Attribute groups", + [{ + tblgen_state.addOperands({images, filters}); + tblgen_state.addAttribute("strides", strides); + tblgen_state.addAttribute("padBelow", padBelow); + tblgen_state.addAttribute("padAbove", padAbove); + tblgen_state.addAttribute("groups", groups); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + void setStrides(const ArrayAttr& attr) { this->setAttr("strides", attr); } + void setPadAbove(const ArrayAttr& attr) { this->setAttr("padAbove", attr); } + void setPadBelow(const ArrayAttr& attr) { this->setAttr("padBelow", attr); } + void setPadType(const Attribute& attr) { this->setAttr("padType", attr); } + }]; +} + +// GroupConvTranspose Op +def NGGroupConvTransposeOp : + NG_OneResult_Op<"groupConvTranspose", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$images, NG_TensorType:$filters, + I64ArrayAttr:$strides, I64ArrayAttr:$padBelow, I64ArrayAttr:$padAbove, + I64ArrayAttr:$outputPad, + DefaultValuedAttr:$groups, + DefaultValuedAttr(MLIRPadType::EXPLICIT)">:$padType, + I64ArrayAttr:$outputShape)> +{ + let summary = "Group Transpose Convolution (Deconvolution)"; + let description = [{ + images The node producing input images data. + filters The node producing filters data. + strides The strides along each feature axis. + padBelow The padding added at the beggining of each feature axis. + padAbove The padding added at the end of each feature axis. + outputPad The zero-padding (adjustment) added to one side of the + output. + groups The number of groups the input channels and output + channels are divided into. + padType The provided padding type. + outputShape The output shape. When provided padding values are + automatically inferred. + }]; + + let builders = [ + OpBuilder<"Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters, Attribute groups", [{ + tblgen_state.addOperands({images, filters}); + tblgen_state.addAttribute("groups", groups); + tblgen_state.addTypes(res); + }]>, + OpBuilder<"Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters", [{ + tblgen_state.addOperands({images, filters}); + tblgen_state.addTypes(res); + }]>, + OpBuilder<"Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters, ArrayAttr strides," + "ArrayAttr outputPad, ArrayAttr outputShape," + "Attribute groups", [{ + tblgen_state.addOperands({images, filters}); + tblgen_state.addAttribute("strides", strides); + tblgen_state.addAttribute("outputPad", outputPad); + tblgen_state.addAttribute("outputShape", outputShape); + tblgen_state.addAttribute("groups", groups); + }]>, + OpBuilder<"Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters," + "ArrayAttr outputShape, Attribute groups", [{ + tblgen_state.addOperands({images, filters}); + tblgen_state.addAttribute("outputShape", outputShape); + tblgen_state.addAttribute("groups", groups); + }]> + ]; + + let extraClassDeclaration = [{ + void setStrides(const ArrayAttr& attr) { this->setAttr("strides", attr); } + void setPadAbove(const ArrayAttr& attr) { this->setAttr("padAbove", attr); } + void setPadBelow(const ArrayAttr& attr) { this->setAttr("padBelow", attr); } + void setPadType(const Attribute& attr) { this->setAttr("padType", attr); } + void setOutputPad(const ArrayAttr& attr) { this->setAttr("outputPad", attr);} + void setOutputShape(const ArrayAttr& attr){ this->setAttr("outputShape", attr);} + }]; +} + + +// GRN Op +def NGGRNOp : + NG_OneResult_Op<"grn", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, + DefaultValuedAttr:$bias)> +{ + let summary = "GRN Op"; + let description = [{ + Global Response Normalization with L2 norm (across channels only) + data - Node producing the input tensor + bias - The bias added to the variance. + }]; + + let extraClassDeclaration = [{ + void setBias(const Attribute& attr) { this->setAttr("bias", attr); } }]; } + +// Clamp Op +def NGClampOp : + NG_OneResult_Op<"clamp", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, F64Attr:$min, F64Attr:$max)> +{ + let summary = "Clamp Op"; + let description = [{ + Performs a clipping operation on all elements of the input node + + All input values that are outside of the range are set to 'min' or 'max' + depending on which side of the range they are. The values that fall into + this range remain unchanged. + }]; + + let extraClassDeclaration = [{ + void setMin(const Attribute& attr) { this->setAttr("min", attr); } + void setMax(const Attribute& attr) { this->setAttr("max", attr); } + }]; +} + +// Gelu Op +def NGGeluOp : + NG_OneResult_Op<"gelu", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data)> +{ + let summary = "Gelu Op"; + let description = [{ + Gaussian Error Linear Unit + f(x) = 0.5 * x * (1 + erf( x / sqrt(2) ) + }]; +} + +// GeluBackpropFactor Op +def NGGeluBackpropFactorOp : + NG_OneResult_Op<"geluBackpropFactor", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data)> +{ + let summary = "Gelu Backprop Op"; + let description = [{ + Backprop for Gelu(x) is GeluBackprop(x) * delta + }]; +} + +// Elu Op +def NGEluOp : + NG_OneResult_Op<"elu", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, F64Attr:$alpha)> +{ + let summary = "Elu Op"; + let description = [{ + Exponential Linear Unit + x < 0 => f(x) = alpha * (exp(x) - 1.) + x >= 0 => f(x) = x + }]; + + let extraClassDeclaration = [{ + void setAlpha(const Attribute& attr) { this->setAttr("alpha", attr); } + }]; +} + +// FakeQuant Op +def NGFakeQuantOp : + NG_OneResult_Op<"fakeQuant", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, NG_TensorType:$inputLow, NG_TensorType:$inputHigh, + NG_TensorType:$outputLow, NG_TensorType:$outputHigh, + I64Attr:$levels, + DefaultValuedAttr(MLIRPadType::EXPLICIT)">:$autoBroadcast)> +{ + let summary = "Op performing element-wise linear quantization."; + let description = [{ + Input floating point values are quantized into a discrete + set of floating point values. + + Implementation This class creates a node which performs the following + operation: + round((data - input_low) / (input_high - input_low) * (levels-1)) / + (levels-1) * (output_high - output_low) + output_low + }]; + + let extraClassDeclaration = [{ + void setLevels(const Attribute& attr) { this->setAttr("levels", attr); } + void setAutoBroadcast(const Attribute& attr) { this->setAttr("autoBroadcast", attr); } + }]; +} + +// DepthToSpace Op +def NGDepthToSpaceOp : + NG_OneResult_Op<"depthToSpace", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$data, + DefaultValuedAttr:$blockSize, + DepthSpaceModeEnumAttr:$mode)> +{ + let summary = "DepthToSpace Op"; + let description = [{ + DepthToSpace permutes data from the depth dimension of the input blob into + spatial dimensions. + Values from the depth dimension (assuming NCHW layout) are moved in + spatial blocks to the height and width dimensions. + Output node produces a tensor with shape: + [N, C/(blocksize * blocksize), H * blocksize, W * blocksize] + }]; + + let extraClassDeclaration = [{ + void setBlockSize(const Attribute& attr) { this->setAttr("blockSize", attr);} + void setMode(const Attribute& attr) { this->setAttr("mode", attr); } + }]; +} + +// ConvolutionBias Op +def NGConvBiasOp : + NG_OneResult_Op<"convBias", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$images, NG_TensorType:$filters, NG_TensorType:$bias, + I64ArrayAttr:$strides, I64ArrayAttr:$padBelow, I64ArrayAttr:$padAbove, + DefaultValuedAttr:$withRelu)> +{ + let summary = "Convolution Bias Op"; + let description = "Convolution + bias forward prop for batched convolution operation."; + + let builders = [ + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters, Value *bias, Attribute withRelu", [{ + tblgen_state.addOperands({images, filters, bias}); + tblgen_state.addAttribute("withRelu", withRelu); + tblgen_state.addTypes(res); + }]>, + + OpBuilder< + "Builder *builder, OperationState &tblgen_state, Type res," + "Value *images, Value *filters, Value *bias", [{ + tblgen_state.addOperands({images, filters, bias}); + tblgen_state.addTypes(res); + }]> + ]; + + let extraClassDeclaration = [{ + void setStrides(const ArrayAttr& attr) { this->setAttr("strides", attr); } + void setPadAbove(const ArrayAttr& attr) { this->setAttr("padAbove", attr); } + void setPadBelow(const ArrayAttr& attr) { this->setAttr("padBelow", attr); } + void setWithRelu(const Attribute& attr) {this->setAttr("withRelu", attr); } + }]; +} + +// ConvBiasBackpropFiltersBias Op +def NGConvBiasBackpropFiltersBias : + NG_Op<"convBiasBackpropFiltersBias", [NoSideEffect, DeclareOpInterfaceMethods]>, + Results<(outs NG_TensorType:$filter, NG_TensorType:$bias)>, + Arguments<(ins NG_TensorType:$images, NG_TensorType:$outputDelta, + I64ArrayAttr:$filtersShape, I64ArrayAttr:$biasShape, + I64ArrayAttr:$strides, I64ArrayAttr:$padBelow, I64ArrayAttr:$padAbove)> +{ + let extraClassDeclaration = [{ + void setFiltersShape(const ArrayAttr& attr) { this->setAttr("filtersShape", attr); } + void setBiasShape(const ArrayAttr& attr) { this->setAttr("biasShape", attr); } + + void setStrides(const ArrayAttr& attr) { this->setAttr("strides", attr); } + void setPadAbove(const ArrayAttr& attr) { this->setAttr("padAbove", attr); } + void setPadBelow(const ArrayAttr& attr) { this->setAttr("padBelow", attr); } + }]; +} + +// ConvBiasAdd Op +def NGConvBiasAddOp : + NG_OneResult_Op<"convBiasAdd", [NoSideEffect, DeclareOpInterfaceMethods]>, + Arguments<(ins NG_TensorType:$images, NG_TensorType:$filters, + NG_TensorType:$bias, NG_TensorType:$sumInput, + I64ArrayAttr:$strides, I64ArrayAttr:$padBelow, I64ArrayAttr:$padAbove, + DefaultValuedAttr:$withRelu)> +{ + let summary = "Convolution Bias Add Op"; + let description = "Convolution + bias + add forward prop for batched convolution operation."; + + let extraClassDeclaration = [{ + void setStrides(const ArrayAttr& attr) { this->setAttr("strides", attr); } + void setPadAbove(const ArrayAttr& attr) { this->setAttr("padAbove", attr); } + void setPadBelow(const ArrayAttr& attr) { this->setAttr("padBelow", attr); } + void setWithRelu(const Attribute& attr) {this->setAttr("withRelu", attr); } + }]; +} + + #endif //NG_FUSED_OPS diff --git a/src/contrib/mlir/core/ngraph_dialect/ops.cpp b/src/contrib/mlir/core/ngraph_dialect/ops.cpp index a0b5e76e52e..690efd01f08 100644 --- a/src/contrib/mlir/core/ngraph_dialect/ops.cpp +++ b/src/contrib/mlir/core/ngraph_dialect/ops.cpp @@ -335,3 +335,100 @@ namespace mlir #define GET_OP_CLASSES #include "ops.cpp.inc" } + +// Fused Ops decompose +// Stubs for now +// TODO: Implement and move to another file +void mlir::NGSpaceToDepthOp::decompose() +{ +} +void mlir::NGSplitOp::decompose() +{ +} +void mlir::NGScaleShiftOp::decompose() +{ +} +void mlir::NGUnSqueezeOp::decompose() +{ +} +void mlir::NGSquaredDiffOp::decompose() +{ +} +void mlir::NGSqueezeOp::decompose() +{ +} +void mlir::NGShuffleChannelsOp::decompose() +{ +} +void mlir::NGRNNCellOp::decompose() +{ +} +void mlir::NGFakeQuantOp::decompose() +{ +} +void mlir::NGMVN::decompose() +{ +} +void mlir::NGHardSigmoid::decompose() +{ +} +void mlir::NGGRNOp::decompose() +{ +} +void mlir::NGNormalizeL2Op::decompose() +{ +} +void mlir::NGConvBiasBackpropFiltersBias::decompose() +{ +} +void mlir::NGPrelu::decompose() +{ +} +void mlir::NGLayerNormBackpropOp::decompose() +{ +} +void mlir::NGGemmOp::decompose() +{ +} +void mlir::NGClampOp::decompose() +{ +} +void mlir::NGGroupConvTransposeOp::decompose() +{ +} +void mlir::NGConvBiasOp::decompose() +{ +} +void mlir::NGConvBiasAddOp::decompose() +{ +} +void mlir::NGGRUCellOp::decompose() +{ +} +void mlir::NGGroupConvOp::decompose() +{ +} +void mlir::NGGeluOp::decompose() +{ +} +void mlir::NGGeluBackpropFactorOp::decompose() +{ +} +void mlir::NGLSTMCellOp::decompose() +{ +} +void mlir::NGLSTMSequenceOp::decompose() +{ +} +void mlir::NGMatMul::decompose() +{ +} +void mlir::NGLayerNormOp::decompose() +{ +} +void mlir::NGDepthToSpaceOp::decompose() +{ +} +void mlir::NGEluOp::decompose() +{ +} diff --git a/src/contrib/mlir/core/ngraph_dialect/ops.td b/src/contrib/mlir/core/ngraph_dialect/ops.td index cb6a729e13d..78e3adb890d 100644 --- a/src/contrib/mlir/core/ngraph_dialect/ops.td +++ b/src/contrib/mlir/core/ngraph_dialect/ops.td @@ -140,7 +140,9 @@ class NG_Terminator_Op traits = []> : NG_Op, Arguments<(ins Variadic:$args)>, Results<(outs)> {} - +class NG_Variadic_Result_Op traits = []> : + NG_Op, + Results<(outs Variadic:$args)> {} // Terminator Ops def NGReturnOp : NG_Terminator_Op<"return">; diff --git a/src/contrib/mlir/core/ngraph_dialect/ops_attributes.td b/src/contrib/mlir/core/ngraph_dialect/ops_attributes.td index 10fe1d00c51..b5e20cbc3ca 100644 --- a/src/contrib/mlir/core/ngraph_dialect/ops_attributes.td +++ b/src/contrib/mlir/core/ngraph_dialect/ops_attributes.td @@ -56,7 +56,8 @@ def PadModeEdge : I32EnumAttrCase<"EDGE", 1> ; def PadModeReflect : I32EnumAttrCase<"REFLECT", 2> ; def PadModeSymmetric: I32EnumAttrCase<"SYMMETRIC", 3> ; -def PadModeEnumAttr : I32EnumAttr<"MLIRPadMode", "Padding modes for pad operator", +def PadModeEnumAttr : I32EnumAttr<"MLIRPadMode", + "Padding modes for pad operator", [PadModeConstant, PadModeEdge, PadModeReflect, PadModeSymmetric]>; // Sort Types for TopK @@ -67,4 +68,51 @@ def SortTypeValues : I32EnumAttrCase<"VALUES", 2>; def SortTypeEnumAttr : I32EnumAttr<"MLIRSortType", "Sort types for topk operator", [SortTypeNone, SortTypeIndices, SortTypeValues]>; +// Modes for normalizeL2 +def EpsModeAdd : I32EnumAttrCase<"ADD", 0>; +def EpsModeMax : I32EnumAttrCase<"MAX", 1>; + +def EpsModeEnumAttr : I32EnumAttr<"MLIREpsMode", + "Specifies how eps is combined with L2 value", + [EpsModeAdd, EpsModeMax]>; + + +def AutoBroadcastNone : I32EnumAttrCase<"NONE", 0>; +def AutoBroadcastExplicit : I32EnumAttrCase<"EXPLICIT", 1>; +def AutoBroadcastNumPy : I32EnumAttrCase<"NUMPY", 2>; +def AutoBroadcastPDPD : I32EnumAttrCase<"PDPD", 3>; + +def AutoBroadcastEnumAttr : I32EnumAttr<"MLIRAutoBroadcastMode", + "Specifies auto-broadcast for an op", + [AutoBroadcastNone, AutoBroadcastExplicit, + AutoBroadcastNumPy, AutoBroadcastPDPD]>; + + +def DepthSpaceModeBlocks : I32EnumAttrCase<"BLOCKS_FIRST", 0>; +def DepthSpaceModeDepth : I32EnumAttrCase<"DEPTH_FIRST", 1>; + +def DepthSpaceModeEnumAttr: I32EnumAttr<"MLIRDepthToSpaceMode", + "Specifies how the input depth dimension is split to block coordinates", + [DepthSpaceModeBlocks, DepthSpaceModeDepth]>; + +def LSTMWeightsFormatFICO : I32EnumAttrCase<"FICO", 0>; // IE +def LSTMWeightsFormatICOF : I32EnumAttrCase<"ICOF", 1>; // PyTorch +def LSTMWeightsFormatIFCO : I32EnumAttrCase<"IFCO", 2>; // DNNL, TF, MxNet +def LSTMWeightsFormatIFOC : I32EnumAttrCase<"IFOC", 3>; // Caffe +def LSTMWeightsFormatIOFC : I32EnumAttrCase<"IOFC", 4>; // ONNX + +def LSTMWeightsFormatEnumAttr: I32EnumAttr<"MLIRLSTMWeightsFormat", + "LSTM Cell Weights Format", + [LSTMWeightsFormatFICO, LSTMWeightsFormatICOF, + LSTMWeightsFormatIFCO, LSTMWeightsFormatIFOC, + LSTMWeightsFormatIOFC]>; + +def LSTMSeqDirectionFWD : I32EnumAttrCase<"FORWARD", 0>; +def LSTMSeqDirectionRVS : I32EnumAttrCase<"REVERSE", 1>; +def LSTMSeqDirectionBID : I32EnumAttrCase<"BIDIRECTIONAL", 2>; + +def LSTMSeqDirectionsEnumAttr: I32EnumAttr<"MLIRLSTMSeqDirection", + "LSTM Sequence Direction", + [LSTMSeqDirectionFWD, LSTMSeqDirectionRVS, + LSTMSeqDirectionBID]>; #endif // NG_OP_ATTRIBUTES diff --git a/src/contrib/mlir/core/ngraph_dialect/ops_v0.td b/src/contrib/mlir/core/ngraph_dialect/ops_v0.td index 81f409b0338..6ed1fb11413 100644 --- a/src/contrib/mlir/core/ngraph_dialect/ops_v0.td +++ b/src/contrib/mlir/core/ngraph_dialect/ops_v0.td @@ -500,7 +500,7 @@ def NGMaxPoolBackPropOp : } // OneHot -def NGOneHOtOp : +def NGOneHotOp : NG_OneResult_Op<"oneHot", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType :$arg, I64ArrayAttr :$shape, @@ -552,7 +552,7 @@ def NGPadOp : } // ReplaceSlice -def NGReplaceSlice : +def NGReplaceSliceOp : NG_OneResult_Op<"replaceSlice", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType:$arg0, NG_TensorType :$arg1, @@ -583,7 +583,7 @@ def NGReplaceSlice : } // slice -def NGSlice : +def NGSliceOp : NG_OneResult_Op<"slice", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType:$arg, I64ArrayAttr :$lowerBounds, @@ -611,7 +611,7 @@ def NGSlice : } // reshape -def NGReshape : +def NGReshapeOp : NG_OneResult_Op<"reshape", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType:$arg, I64ArrayAttr :$axisOrder, @@ -636,7 +636,7 @@ def NGReshape : } // softmax -def NGSoftMax : +def NGSoftMaxOp : NG_OneResult_Op<"softmax", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType :$arg, I64ArrayAttr :$axes)> @@ -655,7 +655,7 @@ def NGSoftMax : } // topk -def NGTopK : +def NGTopKOp : NG_OneResult_Op<"topk", [NoSideEffect, OpVersion0]>, Arguments<(ins NG_TensorType :$arg, NG_TensorType :$k, diff --git a/src/contrib/mlir/core/pass/ng_dialect_builder.cpp b/src/contrib/mlir/core/pass/ng_dialect_builder.cpp index d5855520857..4e731b0bacb 100644 --- a/src/contrib/mlir/core/pass/ng_dialect_builder.cpp +++ b/src/contrib/mlir/core/pass/ng_dialect_builder.cpp @@ -46,32 +46,6 @@ #include "ngraph/op/util/index_reduction.hpp" #include "ngraph/type/element_type.hpp" -#include "contrib/mlir/utils.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - // Defines a new LLVM debug type for this file to be used by LLVM_DEBUG macro. #define DEBUG_TYPE "mlir-compiler" @@ -264,6 +238,7 @@ mlir::Type NgDialectConversionPass::getMlirType(const element::Type& type) { case ngraph::element::Type_t::undefined: case ngraph::element::Type_t::dynamic: + case ngraph::element::Type_t::u1: default: NGRAPH_CHECK(false, "MLIR: Unsupported NGraph types"); break; case ngraph::element::Type_t::bf16: return mlir::NGFloatType::getBF16(m_context); case ngraph::element::Type_t::f16: return mlir::NGFloatType::getF16(m_context); diff --git a/src/contrib/mlir/core/pass/ng_dialect_builder.hpp b/src/contrib/mlir/core/pass/ng_dialect_builder.hpp index 6883be4ed53..ce2e9d34625 100644 --- a/src/contrib/mlir/core/pass/ng_dialect_builder.hpp +++ b/src/contrib/mlir/core/pass/ng_dialect_builder.hpp @@ -20,21 +20,13 @@ #pragma once #include "contrib/mlir/core/compiler.hpp" -#include "contrib/mlir/runtime/cpu/memory_manager.hpp" + #include "ngraph/check.hpp" #include "ngraph/descriptor/tensor.hpp" #include "ngraph/node.hpp" -#include -#include -#include -#include #include -#include -#include -#include - using namespace ngraph::runtime::ngmlir; namespace ngraph diff --git a/src/contrib/mlir/runtime/cpu/cpu_runtime.cpp b/src/contrib/mlir/runtime/cpu/cpu_runtime.cpp index 8598ad2f6e5..7723f7e11c6 100644 --- a/src/contrib/mlir/runtime/cpu/cpu_runtime.cpp +++ b/src/contrib/mlir/runtime/cpu/cpu_runtime.cpp @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include #include @@ -81,7 +81,7 @@ void MLIRCPURuntime::bindArguments(std::vector& externalTensors) { NGRAPH_CHECK(m_module, "MLIR module is not ready."); - mlir::FuncOp func = m_module->lookupSymbol("main"); + auto func = m_module->lookupSymbol("main"); NGRAPH_CHECK(func && !func.getBlocks().empty(), "Function not found"); // Set external arguments @@ -90,7 +90,7 @@ void MLIRCPURuntime::bindArguments(std::vector& externalTensors) // Create list with a type-erased double pointer for each invocation arguments. // We currently use 'allocateMemrefArgs', which creates the arguments list per call ABI (see // comment below). - // StaticFloatMemref is just a struct with the actual pointer to the data. + // StaticMemRef is just a struct with the actual pointer to the data. auto expectedArguments = allocateMemrefArgs(); NGRAPH_CHECK(expectedArguments.size(), "Arguments can't be created"); @@ -102,7 +102,7 @@ void MLIRCPURuntime::bindArguments(std::vector& externalTensors) // Assign external tensor pointers to invocation arguments. for (size_t i = 0, numArgs = m_invokeArgs.size(); i < numArgs; ++i) { - auto* memRefArg = *(reinterpret_cast(m_invokeArgs[i])); + auto* memRefArg = *(reinterpret_cast(m_invokeArgs[i])); memRefArg->data = reinterpret_cast((*m_externalTensors)[i]); } } @@ -129,18 +129,18 @@ void MLIRCPURuntime::cleanup() // Free void double pointer arguments without freeing external tensor data. for (auto* arg : m_invokeArgs) { - auto* memRefArg = *(reinterpret_cast(arg)); + auto* memRefArg = *(reinterpret_cast(arg)); free(memRefArg); free(arg); } } // The current call ABI takes a single arg pointer (argPtr) pointing to a list of args. -// Each arg is a pointer to a StaticFloatMemRef which contains a data pointer +// Each arg is a pointer to a StaticMemRef which contains a data pointer // // The args are laid out as follows -// argPtr-> arg[0]-> StaticFloatMemRef -> -// arg[1]-> StaticFloatMemRef -> +// argPtr-> arg[0]-> StaticMemRef -> +// arg[1]-> StaticMemRef -> // ... SmallVector MLIRCPURuntime::allocateMemrefArgs() { @@ -148,20 +148,18 @@ SmallVector MLIRCPURuntime::allocateMemrefArgs() for (auto i = 0; i < m_externalTensors->size(); i++) { auto descriptor = allocateMemrefDescriptor(); - mlir::StaticFloatMemRef** arg = - reinterpret_cast(malloc(sizeof(mlir::StaticFloatMemRef*))); + StaticMemRef** arg = reinterpret_cast(malloc(sizeof(StaticMemRef*))); *arg = descriptor; args.push_back(arg); } return args; } -mlir::StaticFloatMemRef* MLIRCPURuntime::allocateMemrefDescriptor() +StaticMemRef* MLIRCPURuntime::allocateMemrefDescriptor() { - // We only use StaticFloatMemRef because that's what MLIR currently offers. + // We only use StaticMemRef because that's what MLIR currently offers. // We should expand this with different types and dynamic MemRefs - auto* descriptor = - reinterpret_cast(malloc(sizeof(mlir::StaticFloatMemRef))); + auto* descriptor = reinterpret_cast(malloc(sizeof(StaticMemRef))); NGRAPH_CHECK(descriptor != nullptr, "NULL MemRef descriptor"); descriptor->data = nullptr; return descriptor; diff --git a/src/contrib/mlir/runtime/cpu/cpu_runtime.hpp b/src/contrib/mlir/runtime/cpu/cpu_runtime.hpp index 65b123d022b..07f9e231f80 100644 --- a/src/contrib/mlir/runtime/cpu/cpu_runtime.hpp +++ b/src/contrib/mlir/runtime/cpu/cpu_runtime.hpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -34,6 +33,10 @@ namespace ngraph { namespace ngmlir { + struct StaticMemRef + { + void* data; + }; /// A CPU Runtime is an MLIR runtime that owns an MLIR context and a module /// The module should be in LLVM dialect and ready to be lowered via an MLIR /// ExecutionEngine. The runtime owns the context and must out-live any MLIR @@ -57,7 +60,7 @@ namespace ngraph llvm::SmallVector allocateMemrefArgs(); /// Helper to allocate a mem ref object. Handles static shapes only for now. - mlir::StaticFloatMemRef* allocateMemrefDescriptor(); + StaticMemRef* allocateMemrefDescriptor(); private: // Pointers to externally allocated memory for sub-graph's input and output tensors. diff --git a/src/contrib/mlir/runtime/runtime.hpp b/src/contrib/mlir/runtime/runtime.hpp index 67e039fb54e..2326202558e 100644 --- a/src/contrib/mlir/runtime/runtime.hpp +++ b/src/contrib/mlir/runtime/runtime.hpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/src/ngraph/CMakeLists.txt b/src/ngraph/CMakeLists.txt index 0c3db4e4b89..c0bb7b890a8 100644 --- a/src/ngraph/CMakeLists.txt +++ b/src/ngraph/CMakeLists.txt @@ -16,6 +16,9 @@ set (SRC assertion.hpp + attribute_adapter.cpp + attribute_adapter.hpp + attribute_visitor.hpp autodiff/adjoints.cpp autodiff/adjoints.hpp axis_set.cpp @@ -77,7 +80,10 @@ set (SRC dimension.hpp distributed.cpp distributed.hpp + enum_names.hpp except.hpp + factory.cpp + factory.hpp file_util.cpp file_util.hpp function.cpp @@ -132,12 +138,20 @@ set (SRC op/constant.hpp op/convert.cpp op/convert.hpp + op/convert_like.cpp + op/convert_like.hpp op/convolution.cpp op/convolution.hpp op/cos.cpp op/cos.hpp op/cosh.cpp op/cosh.hpp + op/cum_sum.cpp + op/cum_sum.hpp + op/crop_and_resize.cpp + op/crop_and_resize.hpp + op/deformable_psroi_pooling.cpp + op/deformable_psroi_pooling.hpp op/dequantize.cpp op/dequantize.hpp op/divide.cpp @@ -207,10 +221,14 @@ set (SRC op/strided_slice.hpp op/floor.cpp op/floor.hpp + op/floor_mod.cpp + op/floor_mod.hpp op/gather.cpp op/gather.hpp op/gather_nd.cpp op/gather_nd.hpp + op/gather_tree.cpp + op/gather_tree.hpp op/get_output_element.cpp op/get_output_element.hpp op/greater.cpp @@ -259,6 +277,10 @@ set (SRC op/power.hpp op/product.cpp op/product.hpp + op/reduce_logical_and.cpp + op/reduce_logical_and.hpp + op/reduce_logical_or.cpp + op/reduce_logical_or.hpp op/reduce_prod.cpp op/reduce_prod.hpp op/reduce_mean.cpp @@ -315,6 +337,8 @@ set (SRC op/subtract.hpp op/sum.cpp op/sum.hpp + op/variadic_split.cpp + op/variadic_split.hpp op/tan.cpp op/tan.hpp op/tanh.cpp @@ -325,10 +349,14 @@ set (SRC op/topk.hpp op/xor.cpp op/xor.hpp + op/fused/batch_mat_mul_transpose.cpp + op/fused/batch_mat_mul_transpose.hpp op/fused/clamp.cpp op/fused/clamp.hpp op/fused/conv_fused.cpp op/fused/conv_fused.hpp + op/fused/crossentropy.cpp + op/fused/crossentropy.hpp op/fused/hard_sigmoid.cpp op/fused/hard_sigmoid.hpp op/fused/depth_to_space.cpp @@ -351,12 +379,16 @@ set (SRC op/fused/gru_cell.hpp op/fused/layer_norm.cpp op/fused/layer_norm.hpp + op/fused/log_softmax.cpp + op/fused/log_softmax.hpp op/fused/lstm_cell.cpp op/fused/lstm_cell.hpp op/fused/lstm_sequence.cpp op/fused/lstm_sequence.hpp op/fused/matmul.cpp op/fused/matmul.hpp + op/fused/mod.cpp + op/fused/mod.hpp op/fused/mvn.cpp op/fused/mvn.hpp op/fused/normalize_l2.cpp @@ -365,6 +397,8 @@ set (SRC op/fused/partial_slice.hpp op/fused/prelu.cpp op/fused/prelu.hpp + op/fused/reciprocal.cpp + op/fused/reciprocal.hpp op/fused/rnn_cell.cpp op/fused/rnn_cell.hpp op/fused/scale_shift.cpp @@ -405,12 +439,16 @@ set (SRC op/util/fused_op.hpp op/util/index_reduction.cpp op/util/index_reduction.hpp + op/util/logical_reduction_keep_dims.hpp + op/util/logical_reduction_keep_dims.cpp op/util/logical_reduction.cpp op/util/logical_reduction.hpp op/util/rnn_cell_base.cpp op/util/rnn_cell_base.hpp op/util/unary_elementwise_arithmetic.cpp op/util/unary_elementwise_arithmetic.hpp + ops.hpp + opsets/opset.cpp partial_shape.cpp partial_shape.hpp pass/algebraic_simplification.cpp @@ -443,6 +481,7 @@ set (SRC pass/constant_folding_unsqueeze.cpp pass/constant_folding_shape_of.cpp pass/constant_folding_slice.cpp + pass/constant_folding_strided_slice.cpp pass/constant_folding_transpose.cpp pass/constant_folding_unary.cpp pass/constant_folding.cpp @@ -555,6 +594,7 @@ set (SRC type/float16.cpp type/float16.hpp type/element_type.cpp + type.hpp util.cpp util.hpp validation_util.cpp @@ -626,7 +666,6 @@ target_compile_definitions(ngraph PRIVATE SHARED_LIB_PREFIX="${CMAKE_SHARED_LIBRARY_PREFIX}" SHARED_LIB_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}" - NGRAPH_DLL_EXPORTS ) if(NGRAPH_LIB_VERSIONING_ENABLE) set_target_properties(ngraph PROPERTIES diff --git a/src/ngraph/attribute_adapter.cpp b/src/ngraph/attribute_adapter.cpp new file mode 100644 index 00000000000..ea7a2a8721f --- /dev/null +++ b/src/ngraph/attribute_adapter.cpp @@ -0,0 +1,225 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/attribute_adapter.hpp" +#include "ngraph/axis_set.hpp" +#include "ngraph/coordinate.hpp" +#include "ngraph/coordinate_diff.hpp" +#include "ngraph/partial_shape.hpp" +#include "ngraph/shape.hpp" +#include "ngraph/strides.hpp" +#include "ngraph/type.hpp" +#include "ngraph/type/element_type.hpp" + +using namespace std; +using namespace ngraph; + +namespace ngraph +{ + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const double& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const double& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const double& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const double& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + const int64_t& AttributeAdapter::get() + { + if (!m_buffer_valid) + { + m_buffer = m_value; + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter::set(const int64_t& value) + { + m_value = value; + m_buffer_valid = false; + } + + constexpr DiscreteTypeInfo AttributeAdapter>::type_info; + + const vector& AttributeAdapter>::get() { return m_value; } + void AttributeAdapter>::set(const vector& value) { m_value = value; } + constexpr DiscreteTypeInfo AttributeAdapter>::type_info; + + const vector& AttributeAdapter>::get() + { + if (!m_buffer_valid) + { + m_buffer = copy_from>(m_value); + m_buffer_valid = true; + } + return m_buffer; + } + + void AttributeAdapter>::set(const vector& value) + { + m_value = copy_from>(value); + m_buffer_valid = false; + } +} diff --git a/src/ngraph/attribute_adapter.hpp b/src/ngraph/attribute_adapter.hpp new file mode 100644 index 00000000000..2eb3f57d2e5 --- /dev/null +++ b/src/ngraph/attribute_adapter.hpp @@ -0,0 +1,294 @@ +//***************************************************************************** +// Copyright 2017-2019 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 +#include + +#include "ngraph/enum_names.hpp" +#include "ngraph/type.hpp" + +namespace ngraph +{ + template + class ValueAccessor; + + /// ValueAccessor is for values that do not provide + template <> + class NGRAPH_API ValueAccessor + { + public: + virtual const DiscreteTypeInfo& get_type_info() const = 0; + virtual ~ValueAccessor() {} + }; + + /// ValueAccessor represents values that support get/set through T + template + class ValueAccessor : public ValueAccessor + { + public: + virtual const DiscreteTypeInfo& get_type_info() const = 0; + /// Returns the value + virtual const T& get() = 0; + /// Sets the value + virtual void set(const T& value) = 0; + + protected: + T m_buffer; + bool m_buffer_valid{false}; + }; + + template + class ValueReference + { + public: + operator Type&() const { return m_value; } + protected: + ValueReference(Type& value) + : m_value(value) + { + } + Type& m_value; + }; + + template + class AttributeAdapter + { + }; + + template + class EnumAttributeAdapterBase : public ValueReference, public ValueAccessor + { + public: + EnumAttributeAdapterBase(Type& value) + : ValueReference(value) + { + } + + const std::string& get() override { return as_string(ValueReference::m_value); } + void set(const std::string& value) override + { + ValueReference::m_value = as_enum(value); + } + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(float& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const double& get() override; + void set(const double& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(double& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const double& get() override; + void set(const double& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(int8_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(int16_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(int32_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(int64_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(uint8_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(uint16_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(uint32_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(uint64_t& value) + : ValueReference(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const int64_t& get() override; + void set(const int64_t& value) override; + }; + + /// Note: These class bodies cannot be defined with templates because of interactions + /// between dllexport and templates on Windows. + template <> + class NGRAPH_API AttributeAdapter> + : public ValueReference>, public ValueAccessor> + { + public: + AttributeAdapter(std::vector& value) + : ValueReference>(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter>", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; + }; + + template <> + class NGRAPH_API AttributeAdapter> + : public ValueReference>, public ValueAccessor> + { + public: + AttributeAdapter(std::vector& value) + : ValueReference>(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter>", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; + }; + + template + A copy_from(B& b) + { + A result(b.size()); + for (int i = 0; i < b.size(); ++i) + { + result[i] = + static_cast::type>(b[i]); + } + return result; + } +} diff --git a/src/ngraph/attribute_visitor.hpp b/src/ngraph/attribute_visitor.hpp new file mode 100644 index 00000000000..505239cbe31 --- /dev/null +++ b/src/ngraph/attribute_visitor.hpp @@ -0,0 +1,72 @@ +//***************************************************************************** +// Copyright 2017-2019 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 +#include + +#include "ngraph/partial_shape.hpp" +#include "ngraph/type.hpp" +#include "ngraph/type/element_type.hpp" + +namespace ngraph +{ + template + class ValueAccessor; + + /// \brief Visits the attributes of a node. + /// + /// Attributes are the values set when building a graph which are not + /// computed as the graph executes. Values computed from the graph topology and attributes + /// during compilation are not attributes. + class AttributeVisitor + { + public: + virtual ~AttributeVisitor() {} + // Must implement these methods + virtual void on_attribute(const std::string& name, std::string& value) = 0; + virtual void on_attribute(const std::string& name, bool& value) = 0; + virtual void on_adapter(const std::string& name, ValueAccessor& adapter) = 0; + // The remaining adapter methods fall back on the void adapter if not implemented + virtual void on_adapter(const std::string& name, ValueAccessor& adapter) + { + on_adapter(name, static_cast&>(adapter)); + }; + virtual void on_adapter(const std::string& name, + ValueAccessor>& adapter) + { + on_adapter(name, static_cast&>(adapter)); + } + virtual void on_adapter(const std::string& name, ValueAccessor& adapter) + { + on_adapter(name, static_cast&>(adapter)); + } + virtual void on_adapter(const std::string& name, ValueAccessor& adapter) + { + on_adapter(name, static_cast&>(adapter)); + } + + // Use an adapter for non-primitive types + template + // typename std::enable_if::value, void>::type + void on_attribute(const std::string& name, T& value) + { + AttributeAdapter adapter(value); + on_adapter(name, adapter); + } + }; +} diff --git a/src/ngraph/axis_set.cpp b/src/ngraph/axis_set.cpp index 17848dc1e0b..cb343059bc4 100644 --- a/src/ngraph/axis_set.cpp +++ b/src/ngraph/axis_set.cpp @@ -17,6 +17,48 @@ #include "ngraph/axis_set.hpp" #include "ngraph/util.hpp" +ngraph::AxisSet::AxisSet() + : std::set() +{ +} + +ngraph::AxisSet::AxisSet(const std::initializer_list& axes) + : std::set(axes) +{ +} + +ngraph::AxisSet::AxisSet(const std::set& axes) + : std::set(axes) +{ +} + +ngraph::AxisSet::AxisSet(const std::vector& axes) + : std::set(axes.begin(), axes.end()) +{ +} + +ngraph::AxisSet::AxisSet(const AxisSet& axes) + : std::set(axes) +{ +} + +ngraph::AxisSet& ngraph::AxisSet::operator=(const AxisSet& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::AxisSet& ngraph::AxisSet::operator=(AxisSet&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} + +std::vector ngraph::AxisSet::to_vector() const +{ + return std::vector(this->begin(), this->end()); +} + std::ostream& ngraph::operator<<(std::ostream& s, const AxisSet& axis_set) { s << "AxisSet{"; @@ -24,3 +66,27 @@ std::ostream& ngraph::operator<<(std::ostream& s, const AxisSet& axis_set) s << "}"; return s; } + +const std::vector& ngraph::AttributeAdapter::get() +{ + if (!m_buffer_valid) + { + for (auto elt : m_value) + { + m_buffer.push_back(elt); + } + } + return m_buffer; +} + +void ngraph::AttributeAdapter::set(const std::vector& value) +{ + m_value = AxisSet(); + for (auto elt : value) + { + m_value.insert(elt); + } + m_buffer_valid = false; +} + +constexpr ngraph::DiscreteTypeInfo ngraph::AttributeAdapter::type_info; diff --git a/src/ngraph/axis_set.hpp b/src/ngraph/axis_set.hpp index fae63674c48..f6621f46d94 100644 --- a/src/ngraph/axis_set.hpp +++ b/src/ngraph/axis_set.hpp @@ -21,49 +21,46 @@ #include #include +#include "ngraph/attribute_adapter.hpp" +#include "ngraph/ngraph_visibility.hpp" + namespace ngraph { /// \brief A set of axes. class AxisSet : public std::set { public: - AxisSet() {} - AxisSet(const std::initializer_list& axes) - : std::set(axes) - { - } + NGRAPH_API AxisSet(); - AxisSet(const std::set& axes) - : std::set(axes) - { - } + NGRAPH_API AxisSet(const std::initializer_list& axes); - AxisSet(const std::vector& axes) - : std::set(axes.begin(), axes.end()) - { - } + NGRAPH_API AxisSet(const std::set& axes); - AxisSet(const AxisSet& axes) - : std::set(axes) - { - } + NGRAPH_API AxisSet(const std::vector& axes); - AxisSet& operator=(const AxisSet& v) - { - static_cast*>(this)->operator=(v); - return *this; - } + NGRAPH_API AxisSet(const AxisSet& axes); - AxisSet& operator=(AxisSet&& v) - { - static_cast*>(this)->operator=(v); - return *this; - } + NGRAPH_API AxisSet& operator=(const AxisSet& v); - std::vector to_vector() const + NGRAPH_API AxisSet& operator=(AxisSet&& v) noexcept; + + NGRAPH_API std::vector to_vector() const; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor> + { + public: + AttributeAdapter(AxisSet& value) + : ValueReference(value) { - return std::vector(this->begin(), this->end()); } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; }; std::ostream& operator<<(std::ostream& s, const AxisSet& axis_set); diff --git a/src/ngraph/axis_vector.cpp b/src/ngraph/axis_vector.cpp index e1a981b24aa..b668752dbf1 100644 --- a/src/ngraph/axis_vector.cpp +++ b/src/ngraph/axis_vector.cpp @@ -24,3 +24,43 @@ std::ostream& ngraph::operator<<(std::ostream& s, const AxisVector& axis_vector) s << "}"; return s; } + +ngraph::AxisVector::AxisVector(const std::initializer_list& axes) + : std::vector(axes) +{ +} + +ngraph::AxisVector::AxisVector(const std::vector& axes) + : std::vector(axes) +{ +} + +ngraph::AxisVector::AxisVector(const AxisVector& axes) + : std::vector(axes) +{ +} + +ngraph::AxisVector::AxisVector(size_t n) + : std::vector(n) +{ +} + +ngraph::AxisVector::AxisVector() +{ +} + +ngraph::AxisVector::~AxisVector() +{ +} + +ngraph::AxisVector& ngraph::AxisVector::operator=(const AxisVector& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::AxisVector& ngraph::AxisVector::operator=(AxisVector&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} diff --git a/src/ngraph/axis_vector.hpp b/src/ngraph/axis_vector.hpp index f3a0d3ba686..36cd03e628e 100644 --- a/src/ngraph/axis_vector.hpp +++ b/src/ngraph/axis_vector.hpp @@ -20,31 +20,21 @@ #include #include +#include "ngraph/ngraph_visibility.hpp" + namespace ngraph { /// \brief A vector of axes. class AxisVector : public std::vector { public: - AxisVector(const std::initializer_list& axes) - : std::vector(axes) - { - } + NGRAPH_API AxisVector(const std::initializer_list& axes); - AxisVector(const std::vector& axes) - : std::vector(axes) - { - } + NGRAPH_API AxisVector(const std::vector& axes); - AxisVector(const AxisVector& axes) - : std::vector(axes) - { - } + NGRAPH_API AxisVector(const AxisVector& axes); - explicit AxisVector(size_t n) - : std::vector(n) - { - } + NGRAPH_API explicit AxisVector(size_t n); template AxisVector(InputIterator first, InputIterator last) @@ -52,17 +42,13 @@ namespace ngraph { } - AxisVector() {} - AxisVector& operator=(const AxisVector& v) - { - static_cast*>(this)->operator=(v); - return *this; - } - AxisVector& operator=(AxisVector&& v) - { - static_cast*>(this)->operator=(v); - return *this; - } + NGRAPH_API AxisVector(); + + NGRAPH_API ~AxisVector(); + + NGRAPH_API AxisVector& operator=(const AxisVector& v); + + NGRAPH_API AxisVector& operator=(AxisVector&& v) noexcept; }; std::ostream& operator<<(std::ostream& s, const AxisVector& axis_vector); diff --git a/src/ngraph/builder/make_constant.hpp b/src/ngraph/builder/make_constant.hpp index f3482df0c64..86e212652f8 100644 --- a/src/ngraph/builder/make_constant.hpp +++ b/src/ngraph/builder/make_constant.hpp @@ -94,6 +94,8 @@ namespace ngraph throw ngraph_error("make_constant: Unsupported element type 'dynamic'"); case element::Type_t::boolean: throw ngraph_error("make_constant: Unsupported element type 'boolean'"); + case element::Type_t::u1: + throw ngraph_error("make_constant: Unsupported element type 'u1'"); case element::Type_t::undefined: throw ngraph_error("make_constant: Unsupported element type 'undefined'"); } diff --git a/src/ngraph/coordinate.cpp b/src/ngraph/coordinate.cpp index d7a61a758e8..9855b741ae3 100644 --- a/src/ngraph/coordinate.cpp +++ b/src/ngraph/coordinate.cpp @@ -17,6 +17,9 @@ #include "ngraph/coordinate.hpp" #include "ngraph/util.hpp" +using namespace std; +using namespace ngraph; + std::ostream& ngraph::operator<<(std::ostream& s, const Coordinate& coordinate) { s << "Coordinate{"; @@ -24,3 +27,66 @@ std::ostream& ngraph::operator<<(std::ostream& s, const Coordinate& coordinate) s << "}"; return s; } + +ngraph::Coordinate::Coordinate() +{ +} + +ngraph::Coordinate::Coordinate(const std::initializer_list& axes) + : std::vector(axes) +{ +} + +ngraph::Coordinate::Coordinate(const Shape& shape) + : std::vector(static_cast&>(shape)) +{ +} + +ngraph::Coordinate::Coordinate(const std::vector& axes) + : std::vector(axes) +{ +} + +ngraph::Coordinate::Coordinate(const Coordinate& axes) + : std::vector(axes) +{ +} + +ngraph::Coordinate::Coordinate(size_t n, size_t initial_value) + : std::vector(n, initial_value) +{ +} + +ngraph::Coordinate::~Coordinate() +{ +} + +ngraph::Coordinate& ngraph::Coordinate::operator=(const Coordinate& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::Coordinate& ngraph::Coordinate::operator=(Coordinate&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} + +const vector& AttributeAdapter::get() +{ + if (!m_buffer_valid) + { + m_buffer = copy_from>(m_value); + m_buffer_valid = true; + } + return m_buffer; +} + +void AttributeAdapter::set(const vector& value) +{ + m_value = copy_from(m_value); + m_buffer_valid = false; +} + +constexpr ngraph::DiscreteTypeInfo ngraph::AttributeAdapter::type_info; diff --git a/src/ngraph/coordinate.hpp b/src/ngraph/coordinate.hpp index 7c285ad3cdc..878a8835788 100644 --- a/src/ngraph/coordinate.hpp +++ b/src/ngraph/coordinate.hpp @@ -19,6 +19,7 @@ #include #include +#include "ngraph/attribute_adapter.hpp" #include "ngraph/axis_set.hpp" #include "ngraph/shape.hpp" @@ -28,31 +29,18 @@ namespace ngraph class Coordinate : public std::vector { public: - Coordinate() {} - Coordinate(const std::initializer_list& axes) - : std::vector(axes) - { - } + NGRAPH_API Coordinate(); + NGRAPH_API Coordinate(const std::initializer_list& axes); - Coordinate(const Shape& shape) - : std::vector(static_cast&>(shape)) - { - } + NGRAPH_API Coordinate(const Shape& shape); - Coordinate(const std::vector& axes) - : std::vector(axes) - { - } + NGRAPH_API Coordinate(const std::vector& axes); - Coordinate(const Coordinate& axes) - : std::vector(axes) - { - } + NGRAPH_API Coordinate(const Coordinate& axes); - Coordinate(size_t n, size_t initial_value = 0) - : std::vector(n, initial_value) - { - } + NGRAPH_API Coordinate(size_t n, size_t initial_value = 0); + + NGRAPH_API ~Coordinate(); template Coordinate(InputIterator first, InputIterator last) @@ -60,17 +48,25 @@ namespace ngraph { } - Coordinate& operator=(const Coordinate& v) - { - static_cast*>(this)->operator=(v); - return *this; - } + NGRAPH_API Coordinate& operator=(const Coordinate& v); - Coordinate& operator=(Coordinate&& v) + NGRAPH_API Coordinate& operator=(Coordinate&& v) noexcept; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor> + { + public: + AttributeAdapter(Coordinate& value) + : ValueReference(value) { - static_cast*>(this)->operator=(v); - return *this; } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; }; std::ostream& operator<<(std::ostream& s, const Coordinate& coordinate); diff --git a/src/ngraph/coordinate_diff.cpp b/src/ngraph/coordinate_diff.cpp index ad62a642636..7666a708434 100644 --- a/src/ngraph/coordinate_diff.cpp +++ b/src/ngraph/coordinate_diff.cpp @@ -17,6 +17,9 @@ #include "ngraph/coordinate_diff.hpp" #include "ngraph/util.hpp" +using namespace std; +using namespace ngraph; + std::ostream& ngraph::operator<<(std::ostream& s, const CoordinateDiff& coordinate_diff) { s << "CoordinateDiff{"; @@ -24,3 +27,61 @@ std::ostream& ngraph::operator<<(std::ostream& s, const CoordinateDiff& coordina s << "}"; return s; } + +ngraph::CoordinateDiff::CoordinateDiff(const std::initializer_list& diffs) + : std::vector(diffs) +{ +} + +ngraph::CoordinateDiff::CoordinateDiff(const std::vector& diffs) + : std::vector(diffs) +{ +} + +ngraph::CoordinateDiff::CoordinateDiff(const CoordinateDiff& diffs) + : std::vector(diffs) +{ +} + +ngraph::CoordinateDiff::CoordinateDiff(size_t n, std::ptrdiff_t initial_value) + : std::vector(n, initial_value) +{ +} + +ngraph::CoordinateDiff::CoordinateDiff() +{ +} + +ngraph::CoordinateDiff::~CoordinateDiff() +{ +} + +ngraph::CoordinateDiff& ngraph::CoordinateDiff::operator=(const CoordinateDiff& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::CoordinateDiff& ngraph::CoordinateDiff::operator=(CoordinateDiff&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} + +const vector& AttributeAdapter::get() +{ + if (!m_buffer_valid) + { + m_buffer = copy_from>(m_value); + m_buffer_valid = true; + } + return m_buffer; +} + +void AttributeAdapter::set(const vector& value) +{ + m_value = copy_from(m_value); + m_buffer_valid = false; +} + +constexpr ngraph::DiscreteTypeInfo ngraph::AttributeAdapter::type_info; diff --git a/src/ngraph/coordinate_diff.hpp b/src/ngraph/coordinate_diff.hpp index 0658493cff1..658b83f845e 100644 --- a/src/ngraph/coordinate_diff.hpp +++ b/src/ngraph/coordinate_diff.hpp @@ -20,31 +20,22 @@ #include #include +#include "ngraph/attribute_adapter.hpp" +#include "ngraph/ngraph_visibility.hpp" + namespace ngraph { /// \brief A difference (signed) of tensor element coordinates. class CoordinateDiff : public std::vector { public: - CoordinateDiff(const std::initializer_list& diffs) - : std::vector(diffs) - { - } + NGRAPH_API CoordinateDiff(const std::initializer_list& diffs); - CoordinateDiff(const std::vector& diffs) - : std::vector(diffs) - { - } + NGRAPH_API CoordinateDiff(const std::vector& diffs); - CoordinateDiff(const CoordinateDiff& diffs) - : std::vector(diffs) - { - } + NGRAPH_API CoordinateDiff(const CoordinateDiff& diffs); - explicit CoordinateDiff(size_t n, std::ptrdiff_t initial_value = 0) - : std::vector(n, initial_value) - { - } + NGRAPH_API explicit CoordinateDiff(size_t n, std::ptrdiff_t initial_value = 0); template CoordinateDiff(InputIterator first, InputIterator last) @@ -52,17 +43,29 @@ namespace ngraph { } - CoordinateDiff() {} - CoordinateDiff& operator=(const CoordinateDiff& v) - { - static_cast*>(this)->operator=(v); - return *this; - } - CoordinateDiff& operator=(CoordinateDiff&& v) + NGRAPH_API ~CoordinateDiff(); + + NGRAPH_API CoordinateDiff(); + + NGRAPH_API CoordinateDiff& operator=(const CoordinateDiff& v); + + NGRAPH_API CoordinateDiff& operator=(CoordinateDiff&& v) noexcept; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor> + { + public: + AttributeAdapter(CoordinateDiff& value) + : ValueReference(value) { - static_cast*>(this)->operator=(v); - return *this; } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; }; std::ostream& operator<<(std::ostream& s, const CoordinateDiff& coordinate_diff); diff --git a/src/ngraph/coordinate_transform.hpp b/src/ngraph/coordinate_transform.hpp index c509715f5e2..cc1d9e54f10 100644 --- a/src/ngraph/coordinate_transform.hpp +++ b/src/ngraph/coordinate_transform.hpp @@ -24,7 +24,7 @@ namespace ngraph { - class CoordinateTransform + class NGRAPH_API CoordinateTransform { public: CoordinateTransform(const Shape& source_shape, @@ -72,7 +72,7 @@ namespace ngraph const Strides& get_source_strides() const { return m_source_strides; } const AxisVector& get_source_axis_order() const { return m_source_axis_order; } const Strides& get_target_dilation_strides() const { return m_target_dilation_strides; } - class Iterator + class NGRAPH_API Iterator { public: Iterator(const Shape& target_shape, bool is_end = false); diff --git a/src/ngraph/descriptor/input.hpp b/src/ngraph/descriptor/input.hpp index 12860055ab9..cbb7d09b9b9 100644 --- a/src/ngraph/descriptor/input.hpp +++ b/src/ngraph/descriptor/input.hpp @@ -29,7 +29,7 @@ namespace ngraph class Output; // Describes a tensor that is an input to an op, directly or indirectly via a tuple - class Input + class NGRAPH_API Input { friend class ngraph::Node; @@ -99,6 +99,10 @@ namespace ngraph /// \return the element type of the connected output const element::Type& get_element_type() const; + Input(const Input&) = default; + Input(Input&&) = default; + Input& operator=(const Input&) = default; + protected: // owner of an argument node (in lieu of m_arguments) std::shared_ptr m_src_node; @@ -109,9 +113,6 @@ namespace ngraph private: bool m_is_relevant_to_shape; bool m_is_relevant_to_value; - Input(const Input&) = delete; - Input(Input&&) = delete; - Input& operator=(const Input&) = delete; }; } } diff --git a/src/ngraph/descriptor/layout/dense_tensor_layout.hpp b/src/ngraph/descriptor/layout/dense_tensor_layout.hpp index a6898df0bec..c5d35c5f1cb 100644 --- a/src/ngraph/descriptor/layout/dense_tensor_layout.hpp +++ b/src/ngraph/descriptor/layout/dense_tensor_layout.hpp @@ -33,7 +33,7 @@ namespace ngraph /// permutations and slices. /// /// The linearized offset of an index I is dot(I, strides) + offset. - class DenseTensorLayout : public TensorLayout + class NGRAPH_API DenseTensorLayout : public TensorLayout { public: ~DenseTensorLayout() override {} diff --git a/src/ngraph/descriptor/layout/tensor_layout.hpp b/src/ngraph/descriptor/layout/tensor_layout.hpp index 9bd20ffd209..fd4ab378c13 100644 --- a/src/ngraph/descriptor/layout/tensor_layout.hpp +++ b/src/ngraph/descriptor/layout/tensor_layout.hpp @@ -35,7 +35,7 @@ namespace ngraph /// \brief Interface for describing implementations of tensors. /// /// Kernel selection will need to pay attention to the layout. - class TensorLayout + class NGRAPH_API TensorLayout { protected: TensorLayout(const ngraph::descriptor::Tensor& tensor); diff --git a/src/ngraph/descriptor/output.hpp b/src/ngraph/descriptor/output.hpp index 952b2a5a70f..71ac7903858 100644 --- a/src/ngraph/descriptor/output.hpp +++ b/src/ngraph/descriptor/output.hpp @@ -34,7 +34,7 @@ namespace ngraph namespace descriptor { // Describes an output tensor of an op - class Output + class NGRAPH_API Output { public: /// \param node Node that owns this output. @@ -60,16 +60,15 @@ namespace ngraph /// \return the element type of the output const element::Type& get_element_type() const; + Output(const Output&) = default; + Output(Output&&) = default; + Output& operator=(const Output&) = default; + protected: Node* m_node; size_t m_index; std::shared_ptr m_tensor; std::vector m_inputs; - - private: - Output(const Output&) = delete; - Output(Output&&) = delete; - Output& operator=(const Output&) = delete; }; } } diff --git a/src/ngraph/descriptor/tensor.hpp b/src/ngraph/descriptor/tensor.hpp index 825bf9b314a..880c971dc3d 100644 --- a/src/ngraph/descriptor/tensor.hpp +++ b/src/ngraph/descriptor/tensor.hpp @@ -19,7 +19,6 @@ #include #include -#include "ngraph/descriptor/tensor.hpp" #include "ngraph/partial_shape.hpp" #include "ngraph/shape.hpp" #include "ngraph/type/element_type.hpp" @@ -36,7 +35,7 @@ namespace ngraph } /// \brief Compile-time descriptor of a first-class value that is a tensor. - class Tensor + class NGRAPH_API Tensor { Tensor(const Tensor&) = delete; Tensor& operator=(const Tensor&) = delete; diff --git a/src/ngraph/dimension.hpp b/src/ngraph/dimension.hpp index 8b830608155..99f4abbe846 100644 --- a/src/ngraph/dimension.hpp +++ b/src/ngraph/dimension.hpp @@ -20,6 +20,8 @@ #include #include +#include "ngraph/ngraph_visibility.hpp" + namespace ngraph { /// \brief Class representing a dimension, which may be dynamic (undetermined until runtime), @@ -29,7 +31,7 @@ namespace ngraph /// constructed with Dimension() or Dimension::dynamic(). /// /// XXX: THIS CLASS IS NOT IN USE YET AND THE ENTIRE DESIGN IS SUBJECT TO CHANGE. - class Dimension + class NGRAPH_API Dimension { public: /// \brief Construct a static dimension. diff --git a/src/ngraph/distributed.cpp b/src/ngraph/distributed.cpp index 4ab63a362e3..7f2cd5f9e2d 100644 --- a/src/ngraph/distributed.cpp +++ b/src/ngraph/distributed.cpp @@ -19,28 +19,30 @@ #include "ngraph/distributed/null.hpp" #include "ngraph/distributed/open_mpi.hpp" #include "ngraph/log.hpp" +#include "ngraph/type.hpp" using namespace ngraph; -std::ostream& reduction::operator<<(std::ostream& out, const reduction::Type& obj) +namespace ngraph { -#if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8) -#pragma GCC diagnostic push -#pragma GCC diagnostic error "-Wswitch" -#pragma GCC diagnostic error "-Wswitch-enum" -#endif - switch (obj) + template <> + EnumNames& EnumNames::get() { - case reduction::Type::SUM: out << "SUM"; break; - case reduction::Type::PROD: out << "PROD"; break; - case reduction::Type::MIN: out << "MIN"; break; - case reduction::Type::MAX: out << "MAX"; break; + static auto enum_names = EnumNames("reduction::Type", + {{"SUM", reduction::Type::SUM}, + {"PROD", reduction::Type::PROD}, + {"MIN", reduction::Type::MIN}, + {"MAX", reduction::Type::MAX}}); + return enum_names; } -#if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8) -#pragma GCC diagnostic pop -#endif - return out; -}; + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; +} + +std::ostream& reduction::operator<<(std::ostream& out, const reduction::Type& obj) +{ + return out << as_string(obj); +} static std::unique_ptr s_distributed_interface; diff --git a/src/ngraph/distributed.hpp b/src/ngraph/distributed.hpp index 879b2bd9ad7..6cc207f70e2 100644 --- a/src/ngraph/distributed.hpp +++ b/src/ngraph/distributed.hpp @@ -20,6 +20,8 @@ #include #include +#include "ngraph/attribute_visitor.hpp" +#include "ngraph/type.hpp" #include "ngraph/type/element_type.hpp" namespace ngraph @@ -37,6 +39,20 @@ namespace ngraph std::ostream& operator<<(std::ostream& out, const Type& obj); } + template <> + class AttributeAdapter : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(reduction::Type& value) + : EnumAttributeAdapterBase(value) + { + } + + NGRAPH_API + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + class DistributedInterface { public: diff --git a/src/ngraph/distributed/open_mpi.hpp b/src/ngraph/distributed/open_mpi.hpp index b00030866de..f65963d8992 100644 --- a/src/ngraph/distributed/open_mpi.hpp +++ b/src/ngraph/distributed/open_mpi.hpp @@ -196,6 +196,7 @@ namespace ngraph case element::Type_t::u64: m_type = MPI_UNSIGNED_LONG; break; case element::Type_t::bf16: case element::Type_t::f16: + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::dynamic: throw std::runtime_error("unsupported type"); } diff --git a/src/ngraph/enum_names.hpp b/src/ngraph/enum_names.hpp new file mode 100644 index 00000000000..02f8dc11f72 --- /dev/null +++ b/src/ngraph/enum_names.hpp @@ -0,0 +1,88 @@ +//***************************************************************************** +// Copyright 2017-2019 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 +#include + +#include "ngraph/check.hpp" + +namespace ngraph +{ + /// Uses a pairings defined by EnumTypes::get() to convert between strings + /// and enum values. + template + class EnumNames + { + public: + /// Converts strings to enum values + static EnumType as_enum(const std::string& name) + { + for (auto p : get().m_string_enums) + { + if (p.first == name) + { + return p.second; + } + } + NGRAPH_CHECK(false, "\"", name, "\"", " is not a member of enum ", get().m_enum_name); + } + + /// Converts enum values to strings + static const std::string& as_string(EnumType e) + { + for (auto& p : get().m_string_enums) + { + if (p.second == e) + { + return p.first; + } + } + NGRAPH_CHECK(false, " invalid member of enum ", get().m_enum_name); + } + + private: + /// Creates the mapping. + EnumNames(const std::string& enum_name, + const std::vector> string_enums) + : m_enum_name(enum_name) + , m_string_enums(string_enums) + { + } + + /// Must be defined to returns a singleton for each supported enum class + static EnumNames& get(); + + const std::string m_enum_name; + std::vector> m_string_enums; + }; + + /// Returns the enum value matching the string + template + typename std::enable_if::value, Type>::type + as_enum(const Value& value) + { + return EnumNames::as_enum(value); + } + + /// Returns the string matching the enum value + template + const std::string& as_string(Value value) + { + return EnumNames::as_string(value); + } +} diff --git a/src/ngraph/factory.cpp b/src/ngraph/factory.cpp new file mode 100644 index 00000000000..7cef4f66bf0 --- /dev/null +++ b/src/ngraph/factory.cpp @@ -0,0 +1,53 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/factory.hpp" +#include "ngraph/node.hpp" +#include "ngraph/ops.hpp" + +using namespace std; + +namespace ngraph +{ + mutex& get_registry_mutex() + { + static mutex registry_mutex; + return registry_mutex; + } + + template class NGRAPH_API FactoryRegistry; + + template <> + FactoryRegistry& FactoryRegistry::get() + { + static FactoryRegistry registry; + static mutex init_guard; + // TODO: Add a lock + if (registry.m_factory_map.size() == 0) + { + lock_guard guard(init_guard); + if (registry.m_factory_map.size() == 0) + { +#define NGRAPH_OP(NAME, NAMESPACE, VERSION) registry.register_factory(); +#include "ngraph/op/op_version_tbl.hpp" +#undef NGRAPH_OP + } + } + return registry; + } +} diff --git a/src/ngraph/factory.hpp b/src/ngraph/factory.hpp new file mode 100644 index 00000000000..4dc5f574e6a --- /dev/null +++ b/src/ngraph/factory.hpp @@ -0,0 +1,60 @@ +//***************************************************************************** +// Copyright 2017-2019 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 +#include +#include +#include "ngraph/ngraph_visibility.hpp" + +namespace ngraph +{ + NGRAPH_API std::mutex& get_registry_mutex(); + + template + class FactoryRegistry + { + public: + using Factory = std::function; + using FactoryMap = std::map; + + template + void register_factory() + { + std::lock_guard guard(get_registry_mutex()); + m_factory_map[U::type_info] = []() { return new U(); }; + } + + bool has_factory(const decltype(T::type_info) & info) + { + std::lock_guard guard(get_registry_mutex()); + return m_factory_map.find(info) != m_factory_map.end(); + } + + T* create(const decltype(T::type_info) & info) + { + std::lock_guard guard(get_registry_mutex()); + auto it = m_factory_map.find(info); + return it == m_factory_map.end() ? nullptr : it->second(); + } + static FactoryRegistry& get(); + + protected: + // Need a Compare on type_info + FactoryMap m_factory_map; + }; +} diff --git a/src/ngraph/frontend/onnx_import/CMakeLists.txt b/src/ngraph/frontend/onnx_import/CMakeLists.txt index e530b8b4d93..c74b67a9804 100644 --- a/src/ngraph/frontend/onnx_import/CMakeLists.txt +++ b/src/ngraph/frontend/onnx_import/CMakeLists.txt @@ -75,6 +75,8 @@ add_library(onnx_import STATIC op/conv_integer.hpp op/conv_transpose.cpp op/conv_transpose.hpp + op/cum_sum.cpp + op/cum_sum.hpp op/depth_to_space.cpp op/depth_to_space.hpp op/dequantize_linear.cpp @@ -112,6 +114,7 @@ add_library(onnx_import STATIC op/leaky_relu.hpp op/less.hpp op/log.hpp + op/log_softmax.cpp op/log_softmax.hpp op/lp_norm.cpp op/lp_norm.hpp @@ -121,7 +124,6 @@ add_library(onnx_import STATIC op/lrn.hpp op/lstm.cpp op/lstm.hpp - op/matmul.cpp op/matmul.hpp op/matmul_integer.cpp op/matmul_integer.hpp @@ -133,6 +135,8 @@ add_library(onnx_import STATIC op/mean_variance_normalization.cpp op/mean_variance_normalization.hpp op/min.hpp + op/mod.hpp + op/mod.cpp op/mul.hpp op/neg.hpp op/not.hpp @@ -216,11 +220,11 @@ add_library(onnx_import STATIC set(ONNX_IMPORT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "") -add_dependencies(onnx_import_interface protobuf::libprotobuf onnx::libonnx onnx::libonnx_proto) +add_dependencies(onnx_import_interface onnx::libonnx onnx::libonnx_proto) add_dependencies(onnx_import onnx_import_interface) set_property(TARGET onnx_import PROPERTY POSITION_INDEPENDENT_CODE ON) -target_include_directories(onnx_import +target_include_directories(onnx_import SYSTEM PRIVATE ${ONNX_IMPORT_INCLUDE_DIR} ${NGRAPH_INCLUDE_PATH} SYSTEM PRIVATE ${ONNX_INCLUDE_DIR} ${ONNX_PROTO_INCLUDE_DIR} ${Protobuf_INCLUDE_DIR}) target_link_libraries(onnx_import PRIVATE ${Protobuf_LIBRARIES} ${ONNX_PROTO_LIBRARY}) @@ -241,3 +245,6 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang$") -Wno-invalid-offsetof -Wno-shorten-64-to-32 -Wno-unused-macros -Wno-missing-variable-declarations -Wno-unused-private-field -Wno-shadow -Wno-deprecated PUBLIC -Wno-undefined-func-template) endif() + +target_compile_definitions(onnx_import PRIVATE ngraph_EXPORTS) +target_compile_definitions(onnx_import_interface PRIVATE ngraph_EXPORTS) diff --git a/src/ngraph/frontend/onnx_import/onnx.hpp b/src/ngraph/frontend/onnx_import/onnx.hpp index f9734427180..b3ffb1a7158 100644 --- a/src/ngraph/frontend/onnx_import/onnx.hpp +++ b/src/ngraph/frontend/onnx_import/onnx.hpp @@ -37,6 +37,7 @@ namespace ngraph /// \param version version of the operator (opset), /// \param domain domain the operator belongs to, /// \param fn function providing the implementation of the operator. + NGRAPH_API void register_operator(const std::string& name, std::int64_t version, const std::string& domain, @@ -49,6 +50,7 @@ namespace ngraph /// /// \return The set containing names of supported operators. /// + NGRAPH_API std::set get_supported_operators(std::int64_t version, const std::string& domain); @@ -60,6 +62,7 @@ namespace ngraph /// /// \return True if operator is supported, False otherwise. /// + NGRAPH_API bool is_operator_supported(const std::string& op_name, std::int64_t version, const std::string& domain = "ai.onnx"); @@ -73,6 +76,7 @@ namespace ngraph /// and providing through this parameters is invalid (the weights from /// the model will take precedence). /// \return The function returns a nGraph function representing single output from graph. + NGRAPH_API std::shared_ptr import_onnx_model(std::istream& sin, const Weights& weights = {}); /// \brief Convert an ONNX model to nGraph functions @@ -84,6 +88,7 @@ namespace ngraph /// and providing through this parameters is invalid (the weights from /// the model will take precedence). /// \return The function returns a nGraph function representing single output from graph. + NGRAPH_API std::shared_ptr import_onnx_model(const std::string& filename, const Weights& weights = {}); diff --git a/src/ngraph/frontend/onnx_import/op/matmul.cpp b/src/ngraph/frontend/onnx_import/op/cum_sum.cpp similarity index 53% rename from src/ngraph/frontend/onnx_import/op/matmul.cpp rename to src/ngraph/frontend/onnx_import/op/cum_sum.cpp index 8d838f71ef4..6aaff508bc3 100644 --- a/src/ngraph/frontend/onnx_import/op/matmul.cpp +++ b/src/ngraph/frontend/onnx_import/op/cum_sum.cpp @@ -14,8 +14,11 @@ // limitations under the License. //***************************************************************************** -#include "matmul.hpp" -#include "ngraph/builder/matmul_factory.hpp" +#include + +#include "cum_sum.hpp" +#include "ngraph/op/constant.hpp" +#include "ngraph/op/cum_sum.hpp" namespace ngraph { @@ -25,24 +28,26 @@ namespace ngraph { namespace set_1 { - NodeVector matmul(const Node& node) + NodeVector cum_sum(const Node& node) { - auto ng_inputs = node.get_ng_inputs(); - auto factory = builder::MatmulFactory( - (OutputVector(std::begin(ng_inputs), std::end(ng_inputs)))); - std::size_t left_rank{ng_inputs.at(0)->get_shape().size()}; - std::size_t right_rank{ng_inputs.at(1)->get_shape().size()}; + auto inputs = node.get_ng_inputs(); + auto data = inputs.at(0); + bool exclusive = node.get_attribute_value("exclusive", 0); + bool reverse = node.get_attribute_value("reverse", 0); + std::shared_ptr axis; - if (left_rank == 0 || right_rank == 0) + if (inputs.size() > 1) + { + axis = inputs.at(1); // optional input, 0-D tensor + } + else { - NGRAPH_WARN - << (node) << " " - << "ONNX standard doesn't allow scalar operands, however nGraph " - "accepts them. Consider use of element-wise multiplication instead " - "to conform with ONNX standard."; + axis = ngraph::op::Constant::create(element::i64, Shape{}, {0}); // default } - return factory.make_matmul_op(); + return NodeVector{ + std::make_shared(data, axis, exclusive, reverse)}; } + } // namespace set_1 } // namespace op diff --git a/src/ngraph/frontend/onnx_import/op/cum_sum.hpp b/src/ngraph/frontend/onnx_import/op/cum_sum.hpp new file mode 100644 index 00000000000..1c729cd7939 --- /dev/null +++ b/src/ngraph/frontend/onnx_import/op/cum_sum.hpp @@ -0,0 +1,38 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "core/node.hpp" +#include "ngraph/node.hpp" + +namespace ngraph +{ + namespace onnx_import + { + namespace op + { + namespace set_1 + { + NodeVector cum_sum(const Node& node); + + } // namespace set_1 + + } // namespace op + + } // namespace onnx_import + +} // namespace ngraph diff --git a/src/ngraph/frontend/onnx_import/op/gemm.cpp b/src/ngraph/frontend/onnx_import/op/gemm.cpp index 81333ff0f43..4a543a1d0e3 100644 --- a/src/ngraph/frontend/onnx_import/op/gemm.cpp +++ b/src/ngraph/frontend/onnx_import/op/gemm.cpp @@ -17,8 +17,11 @@ #include #include "gemm.hpp" +#include "ngraph/builder/reshape.hpp" +#include "ngraph/op/add.hpp" #include "ngraph/op/constant.hpp" -#include "ngraph/op/fused/gemm.hpp" +#include "ngraph/op/fused/matmul.hpp" +#include "ngraph/op/multiply.hpp" namespace ngraph { @@ -45,18 +48,87 @@ namespace ngraph input_b->get_element_type(), ngraph::Shape{}, {0}); } - double alpha = node.get_attribute_value("alpha", 1); - double beta = node.get_attribute_value("beta", 1); + const auto alpha = node.get_attribute_value("alpha", 1); + const auto beta = node.get_attribute_value("beta", 1); - bool trans_a = node.get_attribute_value("transA", 0); - bool trans_b = node.get_attribute_value("transB", 0); + const auto alpha_node = ngraph::op::Constant::create( + element::Type_t::f32, Shape{}, std::vector{alpha}); + const auto beta_node = ngraph::op::Constant::create( + element::Type_t::f32, Shape{}, std::vector{beta}); - return NodeVector{std::make_shared( - input_a, input_b, input_c, alpha, beta, trans_a, trans_b)}; + const bool trans_a = node.get_attribute_value("transA", 0); + const bool trans_b = node.get_attribute_value("transB", 0); + + if (trans_a) + { + input_a = ngraph::builder::transpose(input_a); + } + + if (trans_b) + { + input_b = ngraph::builder::transpose(input_b); + } + + input_a = ngraph::builder::flatten(input_a, 1); + input_b = ngraph::builder::flatten(input_b, 1); + + auto matmul_node = std::make_shared(input_a, input_b); + + auto alpha_times_product = + std::make_shared(alpha_node, matmul_node); + auto beta_times_input_c = + std::make_shared(beta_node, input_c); + + return NodeVector{std::make_shared(alpha_times_product, + beta_times_input_c)}; } } // namespace set_1 + namespace set_6 + { + NodeVector gemm(const Node& node) + { + NodeVector inputs{node.get_ng_inputs()}; + std::shared_ptr input_a = inputs.at(0); + std::shared_ptr input_b = inputs.at(1); + std::shared_ptr input_c; + + if (inputs.size() == 3) + { + input_c = inputs.at(2); + } + else + { + input_c = ngraph::op::Constant::create( + input_b->get_element_type(), ngraph::Shape{}, {0}); + } + + const auto alpha = node.get_attribute_value("alpha", 1); + const auto beta = node.get_attribute_value("beta", 1); + + const auto alpha_node = ngraph::op::Constant::create( + element::Type_t::f32, Shape{}, std::vector{alpha}); + const auto beta_node = ngraph::op::Constant::create( + element::Type_t::f32, Shape{}, std::vector{beta}); + + const bool trans_a = node.get_attribute_value("transA", 0); + const bool trans_b = node.get_attribute_value("transB", 0); + + auto matmul_node = + std::make_shared(input_a, input_b, trans_a, trans_b); + + auto alpha_times_product = + std::make_shared(alpha_node, matmul_node); + auto beta_times_input_c = + std::make_shared(beta_node, input_c); + + return NodeVector{std::make_shared(alpha_times_product, + beta_times_input_c)}; + } + + } // namespace set_6 + } // namespace op } // namespace onnx_import diff --git a/src/ngraph/frontend/onnx_import/op/gemm.hpp b/src/ngraph/frontend/onnx_import/op/gemm.hpp index 27e50caa3ef..74c746dcb0b 100644 --- a/src/ngraph/frontend/onnx_import/op/gemm.hpp +++ b/src/ngraph/frontend/onnx_import/op/gemm.hpp @@ -31,6 +31,12 @@ namespace ngraph } // namespace set_1 + namespace set_6 + { + NodeVector gemm(const Node& node); + + } // namespace set_6 + } // namespace op } // namespace onnx_import diff --git a/src/ngraph/frontend/onnx_import/op/hard_sigmoid.cpp b/src/ngraph/frontend/onnx_import/op/hard_sigmoid.cpp index d11cd4f4078..5650103d7ca 100644 --- a/src/ngraph/frontend/onnx_import/op/hard_sigmoid.cpp +++ b/src/ngraph/frontend/onnx_import/op/hard_sigmoid.cpp @@ -17,6 +17,7 @@ #include #include "hard_sigmoid.hpp" +#include "ngraph/op/constant.hpp" #include "ngraph/op/fused/hard_sigmoid.hpp" using namespace ngraph::op; @@ -31,10 +32,17 @@ namespace ngraph { NodeVector hard_sigmoid(const Node& node) { - auto data = node.get_ng_inputs().at(0); + const auto data = node.get_ng_inputs().at(0); - double alpha = node.get_attribute_value("alpha", 0.2); - double beta = node.get_attribute_value("beta", 0.5); + const auto alpha = Constant::create( + data->get_element_type(), + Shape{}, + std::vector{node.get_attribute_value("alpha", 0.2)}); + + const auto beta = Constant::create( + data->get_element_type(), + Shape{}, + std::vector{node.get_attribute_value("beta", 0.5)}); return {std::make_shared(data, alpha, beta)}; } diff --git a/src/ngraph/frontend/onnx_import/op/log_softmax.cpp b/src/ngraph/frontend/onnx_import/op/log_softmax.cpp new file mode 100644 index 00000000000..99d0806299c --- /dev/null +++ b/src/ngraph/frontend/onnx_import/op/log_softmax.cpp @@ -0,0 +1,48 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "core/node.hpp" +#include "ngraph/node.hpp" +#include "ngraph/op/fused/log_softmax.hpp" +#include "utils/common.hpp" + +namespace ngraph +{ + namespace onnx_import + { + namespace op + { + namespace set_1 + { + NodeVector log_softmax(const Node& node) + { + NodeVector inputs{node.get_ng_inputs()}; + auto data = inputs.at(0); + auto data_shape = data->get_shape(); + int axis = node.get_attribute_value("axis", 1); + + return {std::make_shared(data, axis)}; + } + + } // namespace set_1 + + } // namespace op + + } // namespace onnx_import + +} // namespace ngraph diff --git a/src/ngraph/frontend/onnx_import/op/log_softmax.hpp b/src/ngraph/frontend/onnx_import/op/log_softmax.hpp index 9ed1577c903..53b526ad148 100644 --- a/src/ngraph/frontend/onnx_import/op/log_softmax.hpp +++ b/src/ngraph/frontend/onnx_import/op/log_softmax.hpp @@ -19,9 +19,7 @@ #include #include "core/node.hpp" -#include "ngraph/frontend/onnx_import/op/softmax.hpp" #include "ngraph/node.hpp" -#include "ngraph/op/log.hpp" namespace ngraph { @@ -31,10 +29,7 @@ namespace ngraph { namespace set_1 { - inline NodeVector log_softmax(const Node& node) - { - return {std::make_shared(softmax(node).at(0))}; - } + NodeVector log_softmax(const Node& node); } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/matmul.hpp b/src/ngraph/frontend/onnx_import/op/matmul.hpp index 483119edd16..ecc71150731 100644 --- a/src/ngraph/frontend/onnx_import/op/matmul.hpp +++ b/src/ngraph/frontend/onnx_import/op/matmul.hpp @@ -18,6 +18,7 @@ #include "core/node.hpp" #include "ngraph/node.hpp" +#include "ngraph/op/fused/matmul.hpp" namespace ngraph { @@ -27,7 +28,11 @@ namespace ngraph { namespace set_1 { - NodeVector matmul(const Node& node); + NodeVector matmul(const Node& node) + { + return {std::make_shared(node.get_ng_inputs().at(0), + node.get_ng_inputs().at(1))}; + } } // namespace set_1 } // namespace op diff --git a/src/ngraph/frontend/onnx_import/op/mod.cpp b/src/ngraph/frontend/onnx_import/op/mod.cpp new file mode 100644 index 00000000000..85d1a9c115b --- /dev/null +++ b/src/ngraph/frontend/onnx_import/op/mod.cpp @@ -0,0 +1,50 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "mod.hpp" +#include "ngraph/frontend/onnx_import/exceptions.hpp" +#include "ngraph/op/abs.hpp" +#include "ngraph/op/fused/mod.hpp" +#include "ngraph/op/util/attr_types.hpp" + +namespace ngraph +{ + namespace onnx_import + { + namespace op + { + namespace set_1 + { + NodeVector mod(const Node& node) + { + std::shared_ptr dividend{node.get_ng_inputs().at(0)}; + std::shared_ptr divisor{node.get_ng_inputs().at(1)}; + + std::int64_t fmod = node.get_attribute_value("fmod", 0); + ASSERT_IS_SUPPORTED(node, fmod == 1) + << "Only 'fmod=1' mode is supported for mod operator."; + + return {std::make_shared(dividend, divisor)}; + } + + } // namespace set_1 + + } // namespace op + + } // namespace onnx_import + +} // namespace ngraph diff --git a/src/ngraph/frontend/onnx_import/op/mod.hpp b/src/ngraph/frontend/onnx_import/op/mod.hpp new file mode 100644 index 00000000000..375be5defe0 --- /dev/null +++ b/src/ngraph/frontend/onnx_import/op/mod.hpp @@ -0,0 +1,39 @@ +//***************************************************************************** +// Copyright 2017-2019 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 + +#include "core/node.hpp" +#include "ngraph/node.hpp" + +namespace ngraph +{ + namespace onnx_import + { + namespace op + { + namespace set_1 + { + NodeVector mod(const Node& node); + } // namespace set_1 + + } // namespace op + + } // namespace onnx_import + +} // namespace ngraph diff --git a/src/ngraph/frontend/onnx_import/op/onehot.cpp b/src/ngraph/frontend/onnx_import/op/onehot.cpp index 62f5500b961..c0c81a1c0a0 100644 --- a/src/ngraph/frontend/onnx_import/op/onehot.cpp +++ b/src/ngraph/frontend/onnx_import/op/onehot.cpp @@ -17,18 +17,12 @@ #include #include -#include "exceptions.hpp" -#include "ngraph/coordinate.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/constant.hpp" #include "ngraph/op/convert.hpp" -#include "ngraph/op/multiply.hpp" #include "ngraph/op/one_hot.hpp" #include "ngraph/op/slice.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/util/broadcasting.hpp" #include "onehot.hpp" #include "utils/common.hpp" +#include "utils/reshape.hpp" namespace ngraph { @@ -43,49 +37,18 @@ namespace ngraph NodeVector inputs{node.get_ng_inputs()}; auto indices = std::make_shared(inputs.at(0), element::i64); - auto indices_shape = indices->get_shape(); - auto depth = inputs.at(1); - auto values = inputs.at(2); - std::shared_ptr off_value = - std::make_shared(values, Coordinate{0}, Coordinate{1}); - std::shared_ptr on_value = - std::make_shared(values, Coordinate{1}, Coordinate{2}); - auto axis = node.get_attribute_value("axis", -1); - - // Accepted range for axis is [-r-1, r] where r = rank(indices). Validate - // against rank+1. - std::size_t valid_axis = common::validate_axis(node, - axis, - indices_shape.size() + 1, - -indices_shape.size() - 1, - indices_shape.size()); + auto depth = reshape::interpret_as_scalar(inputs.at(1)); - auto constant_depth = ngraph::as_type_ptr(depth); - - ASSERT_VALID_ARGUMENT(node, constant_depth) - << "Only constant values for depth input are supported for the OneHot " - "operator."; + auto values = inputs.at(2); + std::shared_ptr off_value = reshape::interpret_as_scalar( + std::make_shared(values, Coordinate{0}, Coordinate{1})); + std::shared_ptr on_value = reshape::interpret_as_scalar( + std::make_shared(values, Coordinate{1}, Coordinate{2})); - std::int64_t depth_value = constant_depth->get_vector()[0]; - auto output_shape = indices_shape; - // Insert OneHot axis on position pointed by an axis attribute. - // example: - // data_shape = (2, 2) - // axis = 1 - // depth = 10 - // output_shape = (2, 10, 2) - output_shape.insert(std::next(std::begin(output_shape), valid_axis), - depth_value); + auto axis = node.get_attribute_value("axis", -1); - std::shared_ptr one_hot = std::make_shared( - std::make_shared(indices, output_shape, valid_axis), - values->get_element_type()); - auto broadcasted_values = - ngraph::op::numpy_style_broadcast({one_hot, on_value, off_value}); - on_value = broadcasted_values[1]; - off_value = broadcasted_values[2]; - one_hot = one_hot * (on_value - off_value) + off_value; - return {one_hot}; + return {std::make_shared( + indices, depth, on_value, off_value, axis)}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/reciprocal.cpp b/src/ngraph/frontend/onnx_import/op/reciprocal.cpp index 93cf240bb10..999f393ea0a 100644 --- a/src/ngraph/frontend/onnx_import/op/reciprocal.cpp +++ b/src/ngraph/frontend/onnx_import/op/reciprocal.cpp @@ -17,8 +17,7 @@ #include #include -#include "ngraph/op/constant.hpp" -#include "ngraph/op/divide.hpp" +#include "ngraph/op/fused/reciprocal.hpp" #include "ngraph/op/util/broadcasting.hpp" #include "ngraph/shape.hpp" @@ -36,11 +35,7 @@ namespace ngraph { auto data = node.get_ng_inputs().at(0); - std::shared_ptr one_node = std::make_shared( - data->get_element_type(), Shape{}, std::vector{1}); - one_node = ngraph::op::make_broadcast_node(one_node, data->get_shape()); - - return {one_node / data}; + return {std::make_shared(data)}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/selu.cpp b/src/ngraph/frontend/onnx_import/op/selu.cpp index 862f93998cb..96e3d0e9235 100644 --- a/src/ngraph/frontend/onnx_import/op/selu.cpp +++ b/src/ngraph/frontend/onnx_import/op/selu.cpp @@ -45,7 +45,7 @@ namespace ngraph auto gamma_node = std::make_shared( data->get_element_type(), data->get_shape(), std::vector{gamma}); - return {std::make_shared(data, alpha_node, gamma_node)}; + return {std::make_shared(data, alpha_node, gamma_node)}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/softmax.cpp b/src/ngraph/frontend/onnx_import/op/softmax.cpp index b39fe81a503..dac2c3a042f 100644 --- a/src/ngraph/frontend/onnx_import/op/softmax.cpp +++ b/src/ngraph/frontend/onnx_import/op/softmax.cpp @@ -14,9 +14,8 @@ // limitations under the License. //***************************************************************************** -#include +#include -#include "exceptions.hpp" #include "ngraph/op/softmax.hpp" #include "softmax.hpp" #include "utils/common.hpp" @@ -38,10 +37,7 @@ namespace ngraph int axis = node.get_attribute_value("axis", 1); std::size_t valid_axis = common::validate_axis(node, axis, data_shape.size()); - // create vector of capacity data_dimensions - axis_divider position - std::vector axes(data_shape.size() - valid_axis); - std::iota(std::begin(axes), std::end(axes), valid_axis); - return {std::make_shared(data, axes)}; + return {std::make_shared(data, valid_axis)}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/softmax.hpp b/src/ngraph/frontend/onnx_import/op/softmax.hpp index 107df82a0fb..bb131733d85 100644 --- a/src/ngraph/frontend/onnx_import/op/softmax.hpp +++ b/src/ngraph/frontend/onnx_import/op/softmax.hpp @@ -16,9 +16,8 @@ #pragma once -#include - #include "core/node.hpp" +#include "ngraph/node.hpp" namespace ngraph { diff --git a/src/ngraph/frontend/onnx_import/op/space_to_depth.cpp b/src/ngraph/frontend/onnx_import/op/space_to_depth.cpp index a1efa91c0e3..71bf487c4b5 100644 --- a/src/ngraph/frontend/onnx_import/op/space_to_depth.cpp +++ b/src/ngraph/frontend/onnx_import/op/space_to_depth.cpp @@ -29,7 +29,9 @@ namespace ngraph { auto data = node.get_ng_inputs().at(0); std::size_t block_size = node.get_attribute_value("blocksize"); - return NodeVector{std::make_shared(data, block_size)}; + const auto mode = ngraph::op::SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST; + return NodeVector{ + std::make_shared(data, mode, block_size)}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/split.cpp b/src/ngraph/frontend/onnx_import/op/split.cpp index c2beafe1e28..a3d3bbf43c2 100644 --- a/src/ngraph/frontend/onnx_import/op/split.cpp +++ b/src/ngraph/frontend/onnx_import/op/split.cpp @@ -17,6 +17,7 @@ #include #include +#include "ngraph/op/constant.hpp" #include "ngraph/op/fused/split.hpp" #include "op/split.hpp" #include "utils/common.hpp" @@ -32,30 +33,25 @@ namespace ngraph NodeVector split(const Node& node) { const auto input = node.get_ng_inputs().at(0); - const auto outputs_number = node.get_output_names().size(); const auto axis = node.get_attribute_value("axis", 0); - std::size_t valid_axis = - common::validate_axis(node, axis, input->get_shape().size()); + const auto axis_node = + ngraph::op::Constant::create(element::i64, Shape{}, {axis}); - try + std::shared_ptr fused_split; + if (node.has_attribute("split")) { const auto length_parts = node.get_attribute_value>("split"); - const auto fused_split = - std::make_shared(input, valid_axis, length_parts); - - return fused_split->decompose_op(); + fused_split = + std::make_shared(input, axis_node, length_parts); } - catch (const error::node::UnknownAttribute&) + else { - // an exception will be caught if the input node does not contain - // the 'split' attribute - this means we should split the input tensor - // into same-length parts equal to the number of node outputs - const auto fused_split = - std::make_shared(input, valid_axis, outputs_number); - - return fused_split->decompose_op(); + const auto outputs_number = node.get_output_names().size(); + fused_split = + std::make_shared(input, axis_node, outputs_number); } + return common::get_outputs(fused_split); } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/op/sub.hpp b/src/ngraph/frontend/onnx_import/op/sub.hpp index 1ffddf96fd6..9087587b7fd 100644 --- a/src/ngraph/frontend/onnx_import/op/sub.hpp +++ b/src/ngraph/frontend/onnx_import/op/sub.hpp @@ -48,10 +48,8 @@ namespace ngraph { inline NodeVector sub(const Node& node) { - return {std::make_shared( - node.get_ng_inputs().at(0), - node.get_ng_inputs().at(1), - ngraph::op::AutoBroadcastSpec(ngraph::op::AutoBroadcastType::NUMPY))}; + return {std::make_shared(node.get_ng_inputs().at(0), + node.get_ng_inputs().at(1))}; } } // namespace set_1 diff --git a/src/ngraph/frontend/onnx_import/ops_bridge.cpp b/src/ngraph/frontend/onnx_import/ops_bridge.cpp index 4013da81d74..2e2e19b788d 100644 --- a/src/ngraph/frontend/onnx_import/ops_bridge.cpp +++ b/src/ngraph/frontend/onnx_import/ops_bridge.cpp @@ -45,6 +45,7 @@ #include "op/conv_transpose.hpp" #include "op/cos.hpp" #include "op/cosh.hpp" +#include "op/cum_sum.hpp" #include "op/depth_to_space.hpp" #include "op/dequantize_linear.hpp" #include "op/div.hpp" @@ -81,6 +82,7 @@ #include "op/mean.hpp" #include "op/mean_variance_normalization.hpp" #include "op/min.hpp" +#include "op/mod.hpp" #include "op/mul.hpp" #include "op/neg.hpp" #include "op/not.hpp" @@ -257,6 +259,7 @@ namespace ngraph REGISTER_OPERATOR("ConvTranspose", 1, conv_transpose); REGISTER_OPERATOR("Cos", 1, cos); REGISTER_OPERATOR("Cosh", 1, cosh); + REGISTER_OPERATOR("CumSum", 1, cum_sum); REGISTER_OPERATOR("DepthToSpace", 1, depth_to_space); REGISTER_OPERATOR("DequantizeLinear", 1, dequantize_linear); REGISTER_OPERATOR("Div", 1, div); @@ -272,6 +275,7 @@ namespace ngraph REGISTER_OPERATOR("Floor", 1, floor); REGISTER_OPERATOR("Gather", 1, gather); REGISTER_OPERATOR("Gemm", 1, gemm); + REGISTER_OPERATOR("Gemm", 6, gemm); REGISTER_OPERATOR("GlobalAveragePool", 1, global_average_pool); REGISTER_OPERATOR("GlobalLpPool", 1, global_lp_pool); REGISTER_OPERATOR("GlobalMaxPool", 1, global_max_pool); @@ -298,6 +302,7 @@ namespace ngraph REGISTER_OPERATOR("MeanVarianceNormalization", 9, mean_variance_normalization); REGISTER_OPERATOR("Min", 1, min); REGISTER_OPERATOR("Min", 8, min); + REGISTER_OPERATOR("Mod", 1, mod); REGISTER_OPERATOR("Mul", 1, mul); REGISTER_OPERATOR("Mul", 7, mul); REGISTER_OPERATOR("Neg", 1, neg); diff --git a/src/ngraph/frontend/onnx_import/utils/common.cpp b/src/ngraph/frontend/onnx_import/utils/common.cpp index cba36d20d13..64fcad1020f 100644 --- a/src/ngraph/frontend/onnx_import/utils/common.cpp +++ b/src/ngraph/frontend/onnx_import/utils/common.cpp @@ -16,6 +16,8 @@ #include // onnx types #include "common.hpp" +#include "ngraph/op/get_output_element.hpp" +#include "validation_util.hpp" namespace ngraph { @@ -60,23 +62,8 @@ namespace ngraph std::int64_t axis_range_min, std::int64_t axis_range_max) { - // Accepted range of value for axis is [axis_range_min, axis_range_max]. - NGRAPH_CHECK(((axis >= axis_range_min) && (axis <= axis_range_max)), - node.get_description(), - "Parameter axis ", - axis, - " out of the tensor rank [-", - axis_range_min, - ", ", - axis_range_max, - "]."); - - if (axis < 0) - { - axis = axis + tensor_rank; - } - - return static_cast(axis); + return ngraph::normalize_axis( + node.get_description(), axis, tensor_rank, axis_range_min, axis_range_max); } std::vector validate_axes(const ngraph::onnx_import::Node& node, @@ -93,6 +80,24 @@ namespace ngraph return new_axes; } + ngraph::NodeVector get_outputs(const std::shared_ptr& node) + { + const auto outputs_number = node->get_output_size(); + ngraph::NodeVector outputs(outputs_number); + for (int i = 0; i < outputs_number; ++i) + { + if (node->output(i).get_node_shared_ptr()->get_output_size() == 1) + { + outputs[i] = node->get_output_as_single_output_node(i); + } + else + { + outputs[i] = std::make_shared(node, i); + } + } + return outputs; + } + } // namespace common } // namespace onnx_import } // namespace ngraph diff --git a/src/ngraph/frontend/onnx_import/utils/common.hpp b/src/ngraph/frontend/onnx_import/utils/common.hpp index bac91027954..f32d865770f 100644 --- a/src/ngraph/frontend/onnx_import/utils/common.hpp +++ b/src/ngraph/frontend/onnx_import/utils/common.hpp @@ -115,6 +115,13 @@ namespace ngraph std::vector axes, std::int64_t tensor_rank); + /// \brief Return the outputs of the node as vector. + /// + /// \param[in] node Node with multiple outputs. + /// + /// \return Vector of outputs of input node. + ngraph::NodeVector get_outputs(const std::shared_ptr& node); + /// \brief Creates a shifted square identity matrix. /// \note Shifting in the context of this operator means that /// the matrix can be created with elements equal to 1 not only in the main diff --git a/src/ngraph/function.hpp b/src/ngraph/function.hpp index 65c42fb0073..974b331f83a 100644 --- a/src/ngraph/function.hpp +++ b/src/ngraph/function.hpp @@ -31,7 +31,7 @@ namespace ngraph { /// A user-defined function. - class Function : public Lambda + class NGRAPH_API Function : public Lambda { public: static constexpr DiscreteTypeInfo type_info{"Function", 0}; diff --git a/src/ngraph/graph_util.hpp b/src/ngraph/graph_util.hpp index b7e8d2fd721..40d5378f298 100644 --- a/src/ngraph/graph_util.hpp +++ b/src/ngraph/graph_util.hpp @@ -210,9 +210,11 @@ namespace ngraph /// auto new_N = N->copy_with_new_args(N->get_arguments()); /// shared_ptr M = make_shared(new_N); /// replace_node(N, M); + NGRAPH_API void replace_node(std::shared_ptr target, std::shared_ptr replacement, const std::vector& output_order); + NGRAPH_API void replace_node(std::shared_ptr target, std::shared_ptr replacement); /// \brief Replace multiple nodes in a function. diff --git a/src/ngraph/lambda.hpp b/src/ngraph/lambda.hpp index 5f13f81adc6..af230fdf793 100644 --- a/src/ngraph/lambda.hpp +++ b/src/ngraph/lambda.hpp @@ -16,13 +16,14 @@ #pragma once +#include "ngraph/ngraph_visibility.hpp" #include "ngraph/node.hpp" #include "ngraph/op/parameter.hpp" #include "ngraph/op/result.hpp" namespace ngraph { - class Lambda + class NGRAPH_API Lambda { public: static constexpr DiscreteTypeInfo type_info{"Lamdba", 0}; diff --git a/src/ngraph/ngraph.hpp b/src/ngraph/ngraph.hpp index 3f3dd464e21..3e948b62970 100644 --- a/src/ngraph/ngraph.hpp +++ b/src/ngraph/ngraph.hpp @@ -61,6 +61,8 @@ namespace ngraph /// \brief Convenience functions that create addional graph nodes to implement commonly-used /// recipes, for example auto-broadcast. +#include "ngraph/attribute_adapter.hpp" +#include "ngraph/attribute_visitor.hpp" #include "ngraph/builder/autobroadcast.hpp" #include "ngraph/builder/dequantize_builder.hpp" #include "ngraph/builder/numpy_transpose.hpp" @@ -80,145 +82,16 @@ namespace ngraph #include "ngraph/descriptor/tensor.hpp" #include "ngraph/dimension.hpp" #include "ngraph/except.hpp" +#include "ngraph/factory.hpp" #include "ngraph/function.hpp" #include "ngraph/lambda.hpp" #include "ngraph/node.hpp" -#include "ngraph/op/abs.hpp" -#include "ngraph/op/acos.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/all.hpp" -#include "ngraph/op/allreduce.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/any.hpp" -#include "ngraph/op/argmax.hpp" -#include "ngraph/op/argmin.hpp" -#include "ngraph/op/asin.hpp" -#include "ngraph/op/atan.hpp" -#include "ngraph/op/atan2.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/binary_convolution.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/broadcast_distributed.hpp" -#include "ngraph/op/ceiling.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convert.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/cos.hpp" -#include "ngraph/op/cosh.hpp" -#include "ngraph/op/dequantize.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/embedding_lookup.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/erf.hpp" -#include "ngraph/op/exp.hpp" -#include "ngraph/op/experimental/batch_mat_mul.hpp" -#include "ngraph/op/experimental/dyn_broadcast.hpp" -#include "ngraph/op/experimental/dyn_pad.hpp" -#include "ngraph/op/experimental/dyn_replace_slice.hpp" -#include "ngraph/op/experimental/dyn_reshape.hpp" -#include "ngraph/op/experimental/dyn_slice.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/experimental/random_uniform.hpp" -#include "ngraph/op/experimental/range.hpp" -#include "ngraph/op/experimental/shape_of.hpp" -#include "ngraph/op/experimental/tile.hpp" -#include "ngraph/op/experimental/transpose.hpp" -#include "ngraph/op/floor.hpp" -#include "ngraph/op/fused/clamp.hpp" -#include "ngraph/op/fused/conv_fused.hpp" -#include "ngraph/op/fused/depth_to_space.hpp" -#include "ngraph/op/fused/elu.hpp" -#include "ngraph/op/fused/fake_quantize.hpp" -#include "ngraph/op/fused/gelu.hpp" -#include "ngraph/op/fused/gemm.hpp" -#include "ngraph/op/fused/grn.hpp" -#include "ngraph/op/fused/group_conv.hpp" -#include "ngraph/op/fused/group_conv_transpose.hpp" -#include "ngraph/op/fused/gru_cell.hpp" -#include "ngraph/op/fused/hard_sigmoid.hpp" -#include "ngraph/op/fused/layer_norm.hpp" -#include "ngraph/op/fused/lstm_cell.hpp" -#include "ngraph/op/fused/lstm_sequence.hpp" -#include "ngraph/op/fused/matmul.hpp" -#include "ngraph/op/fused/mvn.hpp" -#include "ngraph/op/fused/normalize_l2.hpp" -#include "ngraph/op/fused/partial_slice.hpp" -#include "ngraph/op/fused/prelu.hpp" -#include "ngraph/op/fused/rnn_cell.hpp" -#include "ngraph/op/fused/scale_shift.hpp" -#include "ngraph/op/fused/selu.hpp" -#include "ngraph/op/fused/shuffle_channels.hpp" -#include "ngraph/op/fused/softmax_crossentropy.hpp" -#include "ngraph/op/fused/space_to_depth.hpp" -#include "ngraph/op/fused/split.hpp" -#include "ngraph/op/fused/squared_difference.hpp" -#include "ngraph/op/fused/squeeze.hpp" -#include "ngraph/op/fused/unsqueeze.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/gather_nd.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/log.hpp" -#include "ngraph/op/lrn.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/min.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/negative.hpp" -#include "ngraph/op/not.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/op.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/quantize.hpp" -#include "ngraph/op/quantized_convolution.hpp" -#include "ngraph/op/quantized_dot.hpp" -#include "ngraph/op/recv.hpp" -#include "ngraph/op/reduce_mean.hpp" -#include "ngraph/op/reduce_prod.hpp" -#include "ngraph/op/reduce_sum.hpp" -#include "ngraph/op/relu.hpp" -#include "ngraph/op/replace_slice.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/reverse_sequence.hpp" -#include "ngraph/op/scatter_add.hpp" -#include "ngraph/op/scatter_nd_add.hpp" -#include "ngraph/op/select.hpp" -#include "ngraph/op/send.hpp" -#include "ngraph/op/sigmoid.hpp" -#include "ngraph/op/sign.hpp" -#include "ngraph/op/sin.hpp" -#include "ngraph/op/sinh.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/stop_gradient.hpp" -#include "ngraph/op/strided_slice.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/tan.hpp" -#include "ngraph/op/tanh.hpp" -#include "ngraph/op/tensor_iterator.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/util/attr_types.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/ops.hpp" #include "ngraph/partial_shape.hpp" #include "ngraph/runtime/backend.hpp" #include "ngraph/runtime/tensor.hpp" #include "ngraph/shape.hpp" #include "ngraph/shape_util.hpp" #include "ngraph/specialize_function.hpp" +#include "ngraph/type.hpp" #include "ngraph/type/element_type.hpp" diff --git a/src/ngraph/ngraph_visibility.hpp b/src/ngraph/ngraph_visibility.hpp index ac47f4ee918..21e637289dd 100644 --- a/src/ngraph/ngraph_visibility.hpp +++ b/src/ngraph/ngraph_visibility.hpp @@ -20,8 +20,13 @@ // NGRAPH_API is used for the public API symbols. It either DLL imports or DLL exports // (or does nothing for static build) -#ifdef NGRAPH_DLL_EXPORTS // defined if we are building the NGRAPH DLL (instead of using it) +#ifdef _WIN32 +#pragma warning(disable : 4251) +#pragma warning(disable : 4275) +#endif + +#ifdef ngraph_EXPORTS // defined if we are building the NGRAPH DLL (instead of using it) #define NGRAPH_API NGRAPH_HELPER_DLL_EXPORT #else #define NGRAPH_API NGRAPH_HELPER_DLL_IMPORT -#endif // NGRAPH_DLL_EXPORTS +#endif // ngraph_EXPORTS diff --git a/src/ngraph/node.cpp b/src/ngraph/node.cpp index 8b5fc32b402..51fb3146bb0 100644 --- a/src/ngraph/node.cpp +++ b/src/ngraph/node.cpp @@ -105,13 +105,45 @@ std::shared_ptr Node::copy_with_new_inputs(const OutputVector& inputs, const std::vector>& control_dependencies) const { - bool for_get_output_element = is_type(this); - NodeVector args; - for (const Output& input : inputs) + shared_ptr clone; + if (is_type(this)) { - args.push_back(get_output_element(input, for_get_output_element)); + auto& value = inputs.at(0); + clone = make_shared(value.get_node_shared_ptr(), value.get_index()); + } + else + { + NodeVector args; + for (const Output& input : inputs) + { + args.push_back(get_output_element(input, false)); + } + for (int i = 0; i < inputs.size(); ++i) + { + auto in_val = inputs.at(i); + if (is_type(in_val.get_node())) + { + in_val = as_type_ptr(in_val.get_node_shared_ptr()) + ->get_as_output(); + } + auto in_index = in_val.get_index(); + auto arg = args.at(i); + size_t out_index = 0; + if (is_type(arg)) + { + out_index = as_type_ptr(arg)->get_n(); + } + if (in_index != out_index) + { + cerr << "Mismatch in: " << in_index << " arg: " << out_index << endl; + cerr << "ARG: " << *arg << endl; + cerr << "IN: " << *inputs.at(i).get_node() << endl; + cerr << "INV: " << *in_val.get_node() << endl; + cerr << "In node " << *this << endl; + } + } + clone = copy_with_new_args(args); } - shared_ptr clone = copy_with_new_args(args); for (auto& cdep : control_dependencies) { clone->add_control_dependency(cdep); diff --git a/src/ngraph/node.hpp b/src/ngraph/node.hpp index 4cf995a4c3d..e5bd426f95f 100644 --- a/src/ngraph/node.hpp +++ b/src/ngraph/node.hpp @@ -50,6 +50,7 @@ namespace ngraph template class Output; + class AttributeVisitor; class Variant; class Node; using NodeVector = std::vector>; @@ -71,16 +72,18 @@ namespace ngraph class Adjoints; } + NGRAPH_API std::string node_validation_failure_loc_string(const Node* node); const std::shared_ptr& check_single_output_arg(const std::shared_ptr& node, size_t i); + NGRAPH_API const NodeVector& check_single_output_args(const NodeVector& args); const std::shared_ptr& check_single_output_arg(const std::shared_ptr& node, size_t i); - const NodeVector& check_single_output_args(const NodeVector& args); + NGRAPH_API OutputVector as_output_vector(const NodeVector& args); NodeVector as_node_vector(const OutputVector& values); /// Returns a ResultVector referencing values. @@ -94,7 +97,7 @@ namespace ngraph /// Nodes are the backbone of the graph of Value dataflow. Every node has /// zero or more nodes as arguments and one value, which is either a tensor /// or a (possibly empty) tuple of values. - class Node : public std::enable_shared_from_this + class NGRAPH_API Node : public std::enable_shared_from_this { // For access to generate_adjoints. friend class autodiff::Adjoints; @@ -110,13 +113,14 @@ namespace ngraph template friend class Output; - protected: + public: /// Throws if the node is invalid. virtual void validate_and_infer_types(); // Called in constructors during transition void constructor_validate_and_infer_types(); + protected: std::tuple validate_and_infer_elementwise_args( const op::AutoBroadcastSpec& autob = op::AutoBroadcastSpec()); void validate_and_infer_elementwise_arithmetic( @@ -152,11 +156,11 @@ namespace ngraph void safe_delete(NodeVector& nodes, bool recurse); public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Node", 0}; virtual ~Node(); + virtual bool visit_attributes(AttributeVisitor& visitor) { return false; } virtual bool is_unary_elementwise_arithmetic() const { return false; } virtual bool is_binary_elementwise_arithmetic() const { return false; } virtual bool is_binary_elementwise_comparison() const { return false; } @@ -175,7 +179,7 @@ namespace ngraph /// Returns the NodeTypeInfo for the node's class. /// During transition to type_info, returns a dummy type_info for Node if the class /// has not been updated yet. - virtual const NodeTypeInfo& get_type_info() const { return type_info; } + virtual const NodeTypeInfo& get_type_info() const = 0; virtual const char* get_type_name() const { auto& info = get_type_info(); @@ -267,7 +271,7 @@ namespace ngraph virtual bool is_dynamic() const; virtual bool has_state() const { return false; } size_t get_instance_id() const { return m_instance_id; } - friend std::ostream& operator<<(std::ostream&, const Node&); + friend NGRAPH_API std::ostream& operator<<(std::ostream&, const Node&); virtual std::ostream& write_short_description(std::ostream&) const; virtual std::ostream& write_long_description(std::ostream&) const; @@ -515,7 +519,6 @@ namespace ngraph size_t m_instance_id{m_next_instance_id.fetch_add(1)}; std::string m_friendly_name; std::string m_unique_name; - NGRAPH_API static std::atomic m_next_instance_id; std::unordered_set m_provenance_tags; std::set> m_provenance_group; @@ -716,6 +719,9 @@ namespace ngraph size_t m_index{0}; }; + template class NGRAPH_API Input; + template class NGRAPH_API Output; + inline Input Node::input(size_t input_index) { if (input_index >= m_inputs.size()) diff --git a/src/ngraph/op/abs.hpp b/src/ngraph/op/abs.hpp index 00d74acefe5..56b1cffb63e 100644 --- a/src/ngraph/op/abs.hpp +++ b/src/ngraph/op/abs.hpp @@ -24,31 +24,34 @@ namespace ngraph { namespace op { - /// \brief Elementwise absolute value operation. - /// - class Abs : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Abs", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an absolute value operation. - Abs() = default; - - /// \brief Constructs an absolute value operation. - /// - /// \param arg Output that produces the input tensor.
    - /// `[d1, ...]` - /// - /// Output `[d1, ...]` + /// \brief Elementwise absolute value operation. /// - Abs(const Output& arg); + class NGRAPH_API Abs : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Abs", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an absolute value operation. + Abs() = default; + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + /// \brief Constructs an absolute value operation. + /// + /// \param arg Output that produces the input tensor.
    + /// `[d1, ...]` + /// + /// Output `[d1, ...]` + /// + Abs(const Output& arg); - std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Abs; } } diff --git a/src/ngraph/op/acos.hpp b/src/ngraph/op/acos.hpp index 3cb863e2fb4..4095ffc5160 100644 --- a/src/ngraph/op/acos.hpp +++ b/src/ngraph/op/acos.hpp @@ -24,30 +24,33 @@ namespace ngraph { namespace op { - /// \brief Elementwise inverse cosine (arccos) operation. - /// - class Acos : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Acos", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an arccos operation. - Acos() = default; - /// \brief Constructs an arccos operation. + /// \brief Elementwise inverse cosine (arccos) operation. /// - /// \param arg Output that produces the input tensor.
    - /// `[d1, ...]` - /// - /// Output `[d1, ...]` - /// - Acos(const Output& arg); - - std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + class NGRAPH_API Acos : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Acos", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an arccos operation. + Acos() = default; + /// \brief Constructs an arccos operation. + /// + /// \param arg Output that produces the input tensor.
    + /// `[d1, ...]` + /// + /// Output `[d1, ...]` + /// + Acos(const Output& arg); + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Acos; } } diff --git a/src/ngraph/op/add.cpp b/src/ngraph/op/add.cpp index 79329140fb3..c2924fc0e39 100644 --- a/src/ngraph/op/add.cpp +++ b/src/ngraph/op/add.cpp @@ -37,6 +37,12 @@ shared_ptr op::v0::Add::copy_with_new_args(const NodeVector& new_args) con return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); } +bool op::v0::Add::visit_attributes(AttributeVisitor& visitor) +{ + BinaryElementwiseArithmetic::visit_attributes(visitor); + return true; +} + void op::v0::Add::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) { if (get_autob().m_type != op::AutoBroadcastType::NONE) @@ -70,6 +76,12 @@ op::v1::Add::Add(const Output& arg0, constructor_validate_and_infer_types(); } +bool op::v1::Add::visit_attributes(AttributeVisitor& visitor) +{ + BinaryElementwiseArithmetic::visit_attributes(visitor); + return true; +} + shared_ptr op::v1::Add::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); diff --git a/src/ngraph/op/add.hpp b/src/ngraph/op/add.hpp index f9b28f8ecb4..997c123bd66 100644 --- a/src/ngraph/op/add.hpp +++ b/src/ngraph/op/add.hpp @@ -28,14 +28,16 @@ namespace ngraph { /// \brief Elementwise addition operation. /// - class Add : public util::BinaryElementwiseArithmetic + class NGRAPH_API Add : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Add", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an uninitialized addition operation - Add() = default; + Add() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs an addition operation. /// @@ -53,6 +55,7 @@ namespace ngraph std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override; virtual bool is_commutative() const override { return true; } protected: virtual void generate_adjoints(autodiff::Adjoints& adjoints, @@ -64,14 +67,16 @@ namespace ngraph { /// \brief Elementwise addition operation. /// - class Add : public util::BinaryElementwiseArithmetic + class NGRAPH_API Add : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Add", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an uninitialized addition operation - Add() = default; + Add() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } /// \brief Constructs an addition operation. /// @@ -90,17 +95,18 @@ namespace ngraph AutoBroadcastSpec(AutoBroadcastType::NUMPY)); std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - + bool visit_attributes(AttributeVisitor& visitor) override; virtual bool is_commutative() const override { return true; } size_t get_version() const override { return 1; } protected: virtual void generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) override; }; - } // namespace v1 + } // namespace v1 using v0::Add; } // namespace op + NGRAPH_API std::shared_ptr operator+(const Output& arg0, const Output& arg1); } // namespace ngraph diff --git a/src/ngraph/op/all.hpp b/src/ngraph/op/all.hpp index c40b5e35a2e..bfe820756f3 100644 --- a/src/ngraph/op/all.hpp +++ b/src/ngraph/op/all.hpp @@ -22,30 +22,33 @@ namespace ngraph { namespace op { - /// \brief Logical "all" reduction operation. - class All : public util::LogicalReduction + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"All", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an "all" reduction operation. - All() = default; - /// \brief Constructs an "all" reduction operation. - /// - /// \param arg The tensor to be reduced. - /// \param reduction_axes The axis positions (0-based) to be eliminated. - All(const Output& arg, const AxisSet& reduction_axes); - /// \brief Constructs an "all" reduction operation. - /// - /// \param arg The tensor to be reduced. - /// \param reduction_axes The axis positions (0-based) to be eliminated. - All(const Output& arg, const Output& reduction_axes); + /// \brief Logical "all" reduction operation. + class NGRAPH_API All : public util::LogicalReduction + { + public: + static constexpr NodeTypeInfo type_info{"All", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an "all" reduction operation. + All() = default; + /// \brief Constructs an "all" reduction operation. + /// + /// \param arg The tensor to be reduced. + /// \param reduction_axes The axis positions (0-based) to be eliminated. + All(const Output& arg, const AxisSet& reduction_axes); + /// \brief Constructs an "all" reduction operation. + /// + /// \param arg The tensor to be reduced. + /// \param reduction_axes The axis positions (0-based) to be eliminated. + All(const Output& arg, const Output& reduction_axes); + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - - /// \return The default value for All. - virtual std::shared_ptr get_default_value() const override; - }; + /// \return The default value for All. + virtual std::shared_ptr get_default_value() const override; + }; + } + using v0::All; } } diff --git a/src/ngraph/op/allreduce.cpp b/src/ngraph/op/allreduce.cpp index b76d6d46468..cb2bfe4add4 100644 --- a/src/ngraph/op/allreduce.cpp +++ b/src/ngraph/op/allreduce.cpp @@ -15,6 +15,8 @@ //***************************************************************************** #include "ngraph/op/allreduce.hpp" +#include "ngraph/attribute_visitor.hpp" +#include "ngraph/type.hpp" using namespace std; using namespace ngraph; @@ -47,6 +49,12 @@ shared_ptr op::AllReduce::copy_with_new_args(const NodeVector& new_args) c return make_shared(new_args.at(0), get_reduce_type()); } +bool op::AllReduce::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("reduce_type", m_reduce_type); + return true; +} + reduction::Type op::AllReduce::get_reduce_type() const { return m_reduce_type; diff --git a/src/ngraph/op/allreduce.hpp b/src/ngraph/op/allreduce.hpp index e8d65ff0135..904668f5819 100644 --- a/src/ngraph/op/allreduce.hpp +++ b/src/ngraph/op/allreduce.hpp @@ -23,23 +23,28 @@ namespace ngraph { namespace op { - class AllReduce : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"AllReduce", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - AllReduce() = default; - AllReduce(const Output& arg, reduction::Type reduce_type = reduction::Type::SUM); + class NGRAPH_API AllReduce : public Op + { + public: + static constexpr NodeTypeInfo type_info{"AllReduce", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + AllReduce() = default; + AllReduce(const Output& arg, + reduction::Type reduce_type = reduction::Type::SUM); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - reduction::Type get_reduce_type() const; - void set_reduce_type(reduction::Type reduce_type); + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + reduction::Type get_reduce_type() const; + void set_reduce_type(reduction::Type reduce_type); + bool visit_attributes(AttributeVisitor& visitor) override; - private: - reduction::Type m_reduce_type{reduction::Type::SUM}; - }; + private: + reduction::Type m_reduce_type{reduction::Type::SUM}; + }; + } + using v0::AllReduce; } } diff --git a/src/ngraph/op/and.cpp b/src/ngraph/op/and.cpp index c403b4c5b5f..c96232c3ce3 100644 --- a/src/ngraph/op/and.cpp +++ b/src/ngraph/op/and.cpp @@ -29,6 +29,12 @@ op::v1::LogicalAnd::LogicalAnd(const Output& arg0, constructor_validate_and_infer_types(); } +bool op::v1::LogicalAnd::visit_attributes(AttributeVisitor& visitor) +{ + BinaryElementwiseLogical::visit_attributes(visitor); + return true; +} + shared_ptr op::v1::LogicalAnd::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); @@ -45,6 +51,12 @@ op::v0::And::And(const Output& arg0, constructor_validate_and_infer_types(); } +bool op::v0::And::visit_attributes(AttributeVisitor& visitor) +{ + BinaryElementwiseLogical::visit_attributes(visitor); + return true; +} + shared_ptr op::v0::And::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); diff --git a/src/ngraph/op/and.hpp b/src/ngraph/op/and.hpp index b508fadb08c..27ef20efae9 100644 --- a/src/ngraph/op/and.hpp +++ b/src/ngraph/op/and.hpp @@ -28,10 +28,9 @@ namespace ngraph { /// \brief Elementwise logical-and operation. /// - class LogicalAnd : public util::BinaryElementwiseLogical + class NGRAPH_API LogicalAnd : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LogicalAnd", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a logical-and operation. @@ -53,7 +52,7 @@ namespace ngraph AutoBroadcastSpec(AutoBroadcastType::NUMPY)); std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - + bool visit_attributes(AttributeVisitor& visitor) override; virtual bool is_commutative() const override { return true; } }; } // namespace v0 @@ -61,10 +60,9 @@ namespace ngraph { /// \brief Elementwise logical-and operation. /// - class And : public util::BinaryElementwiseLogical + class NGRAPH_API And : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"And", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a logical-and operation. @@ -85,7 +83,7 @@ namespace ngraph const AutoBroadcastSpec& auto_broadcast = AutoBroadcastSpec()); std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - + bool visit_attributes(AttributeVisitor& visitor) override; virtual bool is_commutative() const override { return true; } }; } diff --git a/src/ngraph/op/any.hpp b/src/ngraph/op/any.hpp index b8f961befd3..973f586a18b 100644 --- a/src/ngraph/op/any.hpp +++ b/src/ngraph/op/any.hpp @@ -23,10 +23,9 @@ namespace ngraph namespace op { /// \brief Logical "any" reduction operation. - class Any : public util::LogicalReduction + class NGRAPH_API Any : public util::LogicalReduction { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Any", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an "any" reduction operation. @@ -44,7 +43,7 @@ namespace ngraph virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - + bool visit_attributes(AttributeVisitor& visitor) override { return true; } /// \return The default value for Any. virtual std::shared_ptr get_default_value() const override; }; diff --git a/src/ngraph/op/argmax.cpp b/src/ngraph/op/argmax.cpp index 7754d39a899..26839563385 100644 --- a/src/ngraph/op/argmax.cpp +++ b/src/ngraph/op/argmax.cpp @@ -28,6 +28,12 @@ op::ArgMax::ArgMax(const Output& arg, size_t axis, const element::Type& in constructor_validate_and_infer_types(); } +bool op::ArgMax::visit_attributes(AttributeVisitor& visitor) +{ + IndexReduction::visit_attributes(visitor); + return true; +} + shared_ptr op::ArgMax::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); diff --git a/src/ngraph/op/argmax.hpp b/src/ngraph/op/argmax.hpp index 8406bb155c6..185a2153bd2 100644 --- a/src/ngraph/op/argmax.hpp +++ b/src/ngraph/op/argmax.hpp @@ -22,27 +22,32 @@ namespace ngraph { namespace op { - /// \brief Computes minimum index along a specified axis for a given tensor - class ArgMax : public op::util::IndexReduction + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ArgMax", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ArgMax operation. - ArgMax() = default; - /// \brief Constructs a ArgMax operation. - /// - /// \param arg The input tensor - /// \param axis The axis along which to compute an index for maximum - /// \param index_element_type produce indices. Currently, only int64 or int32 are - /// supported - ArgMax(const Output& arg, size_t axis, const element::Type& index_element_type); + /// \brief Computes minimum index along a specified axis for a given tensor + class NGRAPH_API ArgMax : public op::util::IndexReduction + { + public: + static constexpr NodeTypeInfo type_info{"ArgMax", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a ArgMax operation. + ArgMax() = default; + /// \brief Constructs a ArgMax operation. + /// + /// \param arg The input tensor + /// \param axis The axis along which to compute an index for maximum + /// \param index_element_type produce indices. Currently, only int64 or int32 are + /// supported + ArgMax(const Output& arg, + size_t axis, + const element::Type& index_element_type); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual std::shared_ptr get_default_value() const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override; + virtual std::shared_ptr get_default_value() const override; + }; + } + using v0::ArgMax; } } diff --git a/src/ngraph/op/argmin.cpp b/src/ngraph/op/argmin.cpp index 150ae6f666e..2054859f7a2 100644 --- a/src/ngraph/op/argmin.cpp +++ b/src/ngraph/op/argmin.cpp @@ -28,6 +28,12 @@ op::ArgMin::ArgMin(const Output& arg, size_t axis, const element::Type& in constructor_validate_and_infer_types(); } +bool op::ArgMin::visit_attributes(AttributeVisitor& visitor) +{ + IndexReduction::visit_attributes(visitor); + return true; +} + shared_ptr op::ArgMin::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); diff --git a/src/ngraph/op/argmin.hpp b/src/ngraph/op/argmin.hpp index eca2b1e00af..c49dbea696a 100644 --- a/src/ngraph/op/argmin.hpp +++ b/src/ngraph/op/argmin.hpp @@ -22,28 +22,33 @@ namespace ngraph { namespace op { - /// \brief Computes minimum index along a specified axis for a given tensor - class ArgMin : public op::util::IndexReduction + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ArgMin", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ArgMin operation. - ArgMin() = default; + /// \brief Computes minimum index along a specified axis for a given tensor + class NGRAPH_API ArgMin : public op::util::IndexReduction + { + public: + static constexpr NodeTypeInfo type_info{"ArgMin", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a ArgMin operation. + ArgMin() = default; - /// \brief Constructs a ArgMin operation. - /// - /// \param arg The input tensor - /// \param axis The axis along which to compute an index for minimum - /// \param index_element_type produce indices. Currently, only int64 or int32 are - /// supported - ArgMin(const Output& arg, size_t axis, const element::Type& index_element_type); + /// \brief Constructs a ArgMin operation. + /// + /// \param arg The input tensor + /// \param axis The axis along which to compute an index for minimum + /// \param index_element_type produce indices. Currently, only int64 or int32 are + /// supported + ArgMin(const Output& arg, + size_t axis, + const element::Type& index_element_type); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual std::shared_ptr get_default_value() const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override; + virtual std::shared_ptr get_default_value() const override; + }; + } + using v0::ArgMin; } } diff --git a/src/ngraph/op/asin.hpp b/src/ngraph/op/asin.hpp index f8292212f6f..6ec9e6d3a32 100644 --- a/src/ngraph/op/asin.hpp +++ b/src/ngraph/op/asin.hpp @@ -24,31 +24,34 @@ namespace ngraph { namespace op { - /// \brief Elementwise inverse sine (arcsin) operation. - /// - class Asin : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Asin", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an arcsin operation. - Asin() = default; - /// \brief Constructs an arcsin operation. + /// \brief Elementwise inverse sine (arcsin) operation. /// - /// \param arg Output that produces the input tensor.
    - /// `[d1, ...]` - /// - /// Output `[d1, ...]` - /// - Asin(const Output& arg); - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + class NGRAPH_API Asin : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Asin", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an arcsin operation. + Asin() = default; + /// \brief Constructs an arcsin operation. + /// + /// \param arg Output that produces the input tensor.
    + /// `[d1, ...]` + /// + /// Output `[d1, ...]` + /// + Asin(const Output& arg); - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Asin; } } diff --git a/src/ngraph/op/atan.hpp b/src/ngraph/op/atan.hpp index f6440adbf3e..c6411e01fae 100644 --- a/src/ngraph/op/atan.hpp +++ b/src/ngraph/op/atan.hpp @@ -24,32 +24,35 @@ namespace ngraph { namespace op { - /// \brief Elementwise inverse tangent (arctan) operation. - /// - class Atan : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Atan", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an arctan operation. - Atan() = default; - - /// \brief Constructs an arctan operation. - /// - /// \param arg Output that produces the input tensor.
    - /// `[d1, ...]` - /// - /// Output `[d1, ...]` + /// \brief Elementwise inverse tangent (arctan) operation. /// - Atan(const Output& arg); + class NGRAPH_API Atan : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Atan", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an arctan operation. + Atan() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + /// \brief Constructs an arctan operation. + /// + /// \param arg Output that produces the input tensor.
    + /// `[d1, ...]` + /// + /// Output `[d1, ...]` + /// + Atan(const Output& arg); - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Atan; } } diff --git a/src/ngraph/op/atan2.hpp b/src/ngraph/op/atan2.hpp index b44298cca3b..dae716f4d44 100644 --- a/src/ngraph/op/atan2.hpp +++ b/src/ngraph/op/atan2.hpp @@ -25,13 +25,15 @@ namespace ngraph namespace op { /// \brief Elementwise full arctan operation - class Atan2 : public util::BinaryElementwiseArithmetic + class NGRAPH_API Atan2 : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Atan2", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } - Atan2() = default; + Atan2() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief atan2(y,x) is the angle from the origin to the point (x,y) (note reversed /// order). diff --git a/src/ngraph/op/avg_pool.cpp b/src/ngraph/op/avg_pool.cpp index 28b038f05dc..829851921d9 100644 --- a/src/ngraph/op/avg_pool.cpp +++ b/src/ngraph/op/avg_pool.cpp @@ -78,6 +78,19 @@ op::v0::AvgPool::AvgPool(const Output& arg, { } +bool op::v0::AvgPool::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("window_shape", m_window_shape); + visitor.on_attribute("window_movement_strides", m_window_movement_strides); + visitor.on_attribute("padding_below", m_padding_below); + visitor.on_attribute("padding_above", m_padding_above); + visitor.on_attribute("include_padding_in_avg_computation", + m_include_padding_in_avg_computation); + visitor.on_attribute("pad_type", m_pad_type); + visitor.on_attribute("ceil_mode", m_ceil_mode); + return true; +} + void op::v0::AvgPool::validate_and_infer_types() { if (0 == m_window_movement_strides.size()) @@ -251,6 +264,18 @@ op::v0::AvgPoolBackprop::AvgPoolBackprop(const Shape& forward_arg_shape, constructor_validate_and_infer_types(); } +bool op::v0::AvgPoolBackprop::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("forward_arg_shape", m_forward_arg_shape); + visitor.on_attribute("window_shape", m_window_shape); + visitor.on_attribute("window_movement_strides", m_window_movement_strides); + visitor.on_attribute("padding_below", m_padding_below); + visitor.on_attribute("padding_above", m_padding_above); + visitor.on_attribute("include_padding_in_avg_computation", + m_include_padding_in_avg_computation); + return true; +} + void op::v0::AvgPoolBackprop::validate_and_infer_types() { // infer_batched_forward_pooling wants CoordinateDiffs for these, while the pooling ops for @@ -420,6 +445,18 @@ op::v1::AvgPool::AvgPool(const Output& arg, { } +bool op::v1::AvgPool::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("kernel", m_kernel); + visitor.on_attribute("strides", m_strides); + visitor.on_attribute("pads_begin", m_pads_begin); + visitor.on_attribute("pads_end", m_pads_end); + visitor.on_attribute("exclude_pad", m_exclude_pad); + visitor.on_attribute("auto_pad", m_auto_pad); + visitor.on_attribute("rounding_type", m_rounding_type); + return true; +} + void op::v1::AvgPool::validate_and_infer_types() { if (0 == m_strides.size()) @@ -575,6 +612,16 @@ op::v1::AvgPoolBackprop::AvgPoolBackprop(const Output& delta, constructor_validate_and_infer_types(); } +bool op::v1::AvgPoolBackprop::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("kernel", m_kernel); + visitor.on_attribute("strides", m_strides); + visitor.on_attribute("pads_begin", m_pads_begin); + visitor.on_attribute("pads_end", m_pads_end); + visitor.on_attribute("exclude_pad", m_exclude_pad); + return true; +} + const Shape op::v1::AvgPoolBackprop::get_forward_arg_shape() const { Shape shape; diff --git a/src/ngraph/op/avg_pool.hpp b/src/ngraph/op/avg_pool.hpp index 1125a804bdd..be0d16e4d67 100644 --- a/src/ngraph/op/avg_pool.hpp +++ b/src/ngraph/op/avg_pool.hpp @@ -27,10 +27,9 @@ namespace ngraph { /// \brief Batched average pooling operation, with optional padding and window stride. /// - class AvgPool : public Op + class NGRAPH_API AvgPool : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"AvgPool", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched average pooling operation. @@ -130,6 +129,8 @@ namespace ngraph /// `[n]` AvgPool(const Output& arg, const Shape& window_shape); + bool visit_attributes(AttributeVisitor& visitor) override; + void validate_and_infer_types() override; virtual std::shared_ptr @@ -171,10 +172,9 @@ namespace ngraph bool m_ceil_mode{false}; }; - class AvgPoolBackprop : public Op + class NGRAPH_API AvgPoolBackprop : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"AvgPoolBackprop", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } AvgPoolBackprop() = default; @@ -187,6 +187,7 @@ namespace ngraph bool include_padding_in_avg_computation); void validate_and_infer_types() override; + bool visit_attributes(AttributeVisitor& visitor) override; virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; @@ -219,10 +220,9 @@ namespace ngraph { /// \brief Batched average pooling operation. /// - class AvgPool : public Op + class NGRAPH_API AvgPool : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"AvgPool", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched average pooling operation. @@ -281,6 +281,7 @@ namespace ngraph size_t get_version() const override { return 1; } void validate_and_infer_types() override; + bool visit_attributes(AttributeVisitor& visitor) override; virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; @@ -320,10 +321,9 @@ namespace ngraph op::RoundingType m_rounding_type{op::RoundingType::FLOOR}; }; - class AvgPoolBackprop : public Op + class NGRAPH_API AvgPoolBackprop : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"AvgPoolBackprop", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } AvgPoolBackprop() = default; @@ -337,6 +337,7 @@ namespace ngraph size_t get_version() const override { return 1; } void validate_and_infer_types() override; + bool visit_attributes(AttributeVisitor& visitor) override; virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; diff --git a/src/ngraph/op/batch_norm.cpp b/src/ngraph/op/batch_norm.cpp index 10d5bc0dbad..5b70de64a3c 100644 --- a/src/ngraph/op/batch_norm.cpp +++ b/src/ngraph/op/batch_norm.cpp @@ -46,6 +46,12 @@ op::BatchNormTraining::BatchNormTraining(double eps, constructor_validate_and_infer_types(); } +bool op::BatchNormTraining::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("epsilon", m_epsilon); + return true; +} + void op::BatchNormTraining::validate_and_infer_types() { element::Type result_et; @@ -129,6 +135,12 @@ op::BatchNormInference::BatchNormInference(double eps, constructor_validate_and_infer_types(); } +bool op::BatchNormInference::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("epsilon", m_epsilon); + return true; +} + void op::BatchNormInference::validate_and_infer_types() { element::Type result_et; @@ -191,6 +203,12 @@ op::BatchNormTrainingBackprop::BatchNormTrainingBackprop(double epsilon, constructor_validate_and_infer_types(); } +bool op::BatchNormTrainingBackprop::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("epsilon", m_epsilon); + return true; +} + void op::BatchNormTrainingBackprop::validate_and_infer_types() { PartialShape input_and_delta_shape{get_input_partial_shape(INPUT_DATA)}; diff --git a/src/ngraph/op/batch_norm.hpp b/src/ngraph/op/batch_norm.hpp index e3b34b3dc6f..e28aa1700aa 100644 --- a/src/ngraph/op/batch_norm.hpp +++ b/src/ngraph/op/batch_norm.hpp @@ -26,179 +26,190 @@ namespace ngraph { namespace op { - /// \brief Batchnorm for training operation - class BatchNormTraining : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"BatchNormTraining", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - BatchNormTraining() = default; - /// \param input Must have rank >= 2, [., C, ...] - /// \param gamma gamma scaling for normalized value. [C] - /// \param beta bias added to the scaled normalized value [C] - /// \param epsilon Avoids divsion by 0 if input has 0 variance - BatchNormTraining(const Output& input, - const Output& gamma, - const Output& beta, - double epsilon); - - NGRAPH_DEPRECATED_DOC - /// In this version of BatchNorm: - /// - /// MEAN AND VARIANCE: computed directly from the content of 'input'. - /// - /// OUTPUT VALUE: A tuple with the following structure: - /// [0] - The normalization of 'input'. - /// [1] - The per-channel means of (pre-normalized) 'input'. - /// [2] - The per-channel variances of (pre-normalized) 'input'. - /// - /// AUTODIFF SUPPORT: yes: 'generate_adjoints(...)' works as expected. - /// - /// SHAPE DETAILS: - /// gamma: must have rank 1, with the same span as input's channel axis. - /// beta: must have rank 1, with the same span as input's channel axis. - /// input: must have rank >= 2. The second dimension represents the channel axis - /// and must have a span of at least 1. - /// output[0]: shall have the same shape as 'input'. - /// output[1]: shall have rank 1, with the same span as input's channel axis. - /// output[2]: shall have rank 1, with the same span as input's channel axis. - NGRAPH_DEPRECATED("Use another constructor") - BatchNormTraining(double eps, - const Output& gamma, - const Output& beta, - const Output& input); - - void validate_and_infer_types() override; - - double get_eps_value() const { return m_epsilon; } - void set_eps_value(double epsilon) { m_epsilon = epsilon; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - - static constexpr size_t INPUT_GAMMA = 0; - static constexpr size_t INPUT_BETA = 1; - static constexpr size_t INPUT_DATA = 2; - - private: - double m_epsilon; - }; - - class BatchNormInference : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"BatchNormInference", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - BatchNormInference() = default; - /// \param input [., C, ...] - /// \param gamma gamma scaling for normalized value. [C] - /// \param beta bias added to the scaled normalized value [C] - /// \param mean value for mean normalization [C] - /// \param variance value for variance normalization [C] - /// \param epsilon Avoids divsion by 0 if input has 0 variance - BatchNormInference(const Output& input, - const Output& gamma, - const Output& beta, - const Output& mean, - const Output& variance, - double epsilon); - - NGRAPH_DEPRECATED_DOC - /// In this version of BatchNorm: - /// - /// MEAN AND VARIANCE: provided by the 'mean' and 'variance' parameters. - /// - /// OUTPUT VALUE: a single tensor with the normalized value of 'input'. - /// - /// AUTODIFF SUPPORT: - /// - 'generate_adjoints(...) may throw an exception. - /// - /// SHAPE DETAILS: - /// gamma: must have rank 1, with the same span as input's channel axis. - /// beta: must have rank 1, with the same span as input's channel axis. - /// input: must have rank >= 2. The second dimension represents the channel axis - /// and must have a span of at least 1. - /// mean: must have rank 1, with the same span as input's channel axis. - /// variance: must have rank 1, with the same span as input's channel axis. - /// output: shall have the same shape as 'input'. - NGRAPH_DEPRECATED("Use another constructor") - BatchNormInference(double eps, - const Output& gamma, - const Output& beta, - const Output& input, - const Output& mean, - const Output& variance); - - void validate_and_infer_types() override; - - double get_eps_value() const { return m_epsilon; } - void set_eps_value(double epsilon) { m_epsilon = epsilon; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - protected: - virtual void generate_adjoints(autodiff::Adjoints& /* adjoints */, - const NodeVector& /* deltas */) override + /// \brief Batchnorm for training operation + class NGRAPH_API BatchNormTraining : public Op { - throw ngraph_error("Invalid operation"); - } - - private: - static constexpr size_t INPUT_GAMMA = 0; - static constexpr size_t INPUT_BETA = 1; - static constexpr size_t INPUT_DATA = 2; - static constexpr size_t INPUT_MEAN = 3; - static constexpr size_t INPUT_VARIANCE = 4; - - double m_epsilon; - }; - - class BatchNormTrainingBackprop : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"BatchNormTrainingBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - BatchNormTrainingBackprop() = default; - BatchNormTrainingBackprop(const Output& input, - const Output& gamma, - const Output& beta, - const Output& mean, - const Output& variance, - const Output& delta, - double epsilon); - - NGRAPH_DEPRECATED_DOC - NGRAPH_DEPRECATED("Use another constructor") - BatchNormTrainingBackprop(double epsilon, - const Output& gamma, - const Output& beta, - const Output& input, - const Output& mean, - const Output& variance, - const Output& delta); - - void validate_and_infer_types() override; - - double get_eps_value() const { return m_epsilon; } - void set_eps_value(double epsilon) { m_epsilon = epsilon; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - private: - static constexpr size_t INPUT_GAMMA = 0; - static constexpr size_t INPUT_BETA = 1; - static constexpr size_t INPUT_DATA = 2; - static constexpr size_t INPUT_MEAN = 3; - static constexpr size_t INPUT_VARIANCE = 4; - static constexpr size_t INPUT_DELTA = 5; - - double m_epsilon; - }; + public: + static constexpr NodeTypeInfo type_info{"BatchNormTraining", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + BatchNormTraining() = default; + /// \param input Must have rank >= 2, [., C, ...] + /// \param gamma gamma scaling for normalized value. [C] + /// \param beta bias added to the scaled normalized value [C] + /// \param epsilon Avoids divsion by 0 if input has 0 variance + BatchNormTraining(const Output& input, + const Output& gamma, + const Output& beta, + double epsilon); + + bool visit_attributes(AttributeVisitor& visitor) override; + + NGRAPH_DEPRECATED_DOC + /// In this version of BatchNorm: + /// + /// MEAN AND VARIANCE: computed directly from the content of 'input'. + /// + /// OUTPUT VALUE: A tuple with the following structure: + /// [0] - The normalization of 'input'. + /// [1] - The per-channel means of (pre-normalized) 'input'. + /// [2] - The per-channel variances of (pre-normalized) 'input'. + /// + /// AUTODIFF SUPPORT: yes: 'generate_adjoints(...)' works as expected. + /// + /// SHAPE DETAILS: + /// gamma: must have rank 1, with the same span as input's channel axis. + /// beta: must have rank 1, with the same span as input's channel axis. + /// input: must have rank >= 2. The second dimension represents the channel + /// axis + /// and must have a span of at least 1. + /// output[0]: shall have the same shape as 'input'. + /// output[1]: shall have rank 1, with the same span as input's channel axis. + /// output[2]: shall have rank 1, with the same span as input's channel axis. + NGRAPH_DEPRECATED("Use another constructor") + BatchNormTraining(double eps, + const Output& gamma, + const Output& beta, + const Output& input); + + void validate_and_infer_types() override; + + double get_eps_value() const { return m_epsilon; } + void set_eps_value(double epsilon) { m_epsilon = epsilon; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + static constexpr size_t INPUT_GAMMA = 0; + static constexpr size_t INPUT_BETA = 1; + static constexpr size_t INPUT_DATA = 2; + + private: + double m_epsilon; + }; + + class NGRAPH_API BatchNormInference : public Op + { + public: + static constexpr NodeTypeInfo type_info{"BatchNormInference", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + BatchNormInference() = default; + /// \param input [., C, ...] + /// \param gamma gamma scaling for normalized value. [C] + /// \param beta bias added to the scaled normalized value [C] + /// \param mean value for mean normalization [C] + /// \param variance value for variance normalization [C] + /// \param epsilon Avoids divsion by 0 if input has 0 variance + BatchNormInference(const Output& input, + const Output& gamma, + const Output& beta, + const Output& mean, + const Output& variance, + double epsilon); + + bool visit_attributes(AttributeVisitor& visitor) override; + + NGRAPH_DEPRECATED_DOC + /// In this version of BatchNorm: + /// + /// MEAN AND VARIANCE: provided by the 'mean' and 'variance' parameters. + /// + /// OUTPUT VALUE: a single tensor with the normalized value of 'input'. + /// + /// AUTODIFF SUPPORT: + /// - 'generate_adjoints(...) may throw an exception. + /// + /// SHAPE DETAILS: + /// gamma: must have rank 1, with the same span as input's channel axis. + /// beta: must have rank 1, with the same span as input's channel axis. + /// input: must have rank >= 2. The second dimension represents the channel + /// axis + /// and must have a span of at least 1. + /// mean: must have rank 1, with the same span as input's channel axis. + /// variance: must have rank 1, with the same span as input's channel axis. + /// output: shall have the same shape as 'input'. + NGRAPH_DEPRECATED("Use another constructor") + BatchNormInference(double eps, + const Output& gamma, + const Output& beta, + const Output& input, + const Output& mean, + const Output& variance); + + void validate_and_infer_types() override; + + double get_eps_value() const { return m_epsilon; } + void set_eps_value(double epsilon) { m_epsilon = epsilon; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + protected: + virtual void generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) override + { + throw ngraph_error("Invalid operation"); + } + + private: + static constexpr size_t INPUT_GAMMA = 0; + static constexpr size_t INPUT_BETA = 1; + static constexpr size_t INPUT_DATA = 2; + static constexpr size_t INPUT_MEAN = 3; + static constexpr size_t INPUT_VARIANCE = 4; + + double m_epsilon; + }; + + class NGRAPH_API BatchNormTrainingBackprop : public Op + { + public: + static constexpr NodeTypeInfo type_info{"BatchNormTrainingBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + BatchNormTrainingBackprop() = default; + BatchNormTrainingBackprop(const Output& input, + const Output& gamma, + const Output& beta, + const Output& mean, + const Output& variance, + const Output& delta, + double epsilon); + + bool visit_attributes(AttributeVisitor& visitor) override; + + NGRAPH_DEPRECATED_DOC + NGRAPH_DEPRECATED("Use another constructor") + BatchNormTrainingBackprop(double epsilon, + const Output& gamma, + const Output& beta, + const Output& input, + const Output& mean, + const Output& variance, + const Output& delta); + + void validate_and_infer_types() override; + + double get_eps_value() const { return m_epsilon; } + void set_eps_value(double epsilon) { m_epsilon = epsilon; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + private: + static constexpr size_t INPUT_GAMMA = 0; + static constexpr size_t INPUT_BETA = 1; + static constexpr size_t INPUT_DATA = 2; + static constexpr size_t INPUT_MEAN = 3; + static constexpr size_t INPUT_VARIANCE = 4; + static constexpr size_t INPUT_DELTA = 5; + + double m_epsilon; + }; + } + using v0::BatchNormInference; + using v0::BatchNormTraining; + using v0::BatchNormTrainingBackprop; } } diff --git a/src/ngraph/op/binary_convolution.cpp b/src/ngraph/op/binary_convolution.cpp index 7eaf4f4e68b..7c05e812606 100644 --- a/src/ngraph/op/binary_convolution.cpp +++ b/src/ngraph/op/binary_convolution.cpp @@ -114,18 +114,7 @@ void op::v1::BinaryConvolution::validate_and_infer_types() } } - element::Type result_et; PartialShape result_shape; - - NODE_VALIDATION_CHECK( - this, - element::Type::merge(result_et, data_batch_et, filters_et), - "Element types for data batch and filters do not match (data batch element type: ", - data_batch_et, - ", filters element type: ", - filters_et, - ")."); - result_shape = infer_convolution_forward(this, data_batch_shape, @@ -136,7 +125,7 @@ void op::v1::BinaryConvolution::validate_and_infer_types() m_strides, m_dilations); - set_output_type(0, result_et, result_shape); + set_output_type(0, data_batch_et, result_shape); } shared_ptr op::v1::BinaryConvolution::copy_with_new_args(const NodeVector& new_args) const diff --git a/src/ngraph/op/binary_convolution.hpp b/src/ngraph/op/binary_convolution.hpp index 35c353f6259..9b6bce230d6 100644 --- a/src/ngraph/op/binary_convolution.hpp +++ b/src/ngraph/op/binary_convolution.hpp @@ -26,7 +26,7 @@ namespace ngraph { namespace v1 { - class BinaryConvolution : public Op + class NGRAPH_API BinaryConvolution : public Op { public: enum class BinaryConvolutionMode @@ -35,7 +35,6 @@ namespace ngraph XNOR_POPCOUNT }; - NGRAPH_API static constexpr NodeTypeInfo type_info{"BinaryConvolution", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a binary convolution operation. diff --git a/src/ngraph/op/broadcast.cpp b/src/ngraph/op/broadcast.cpp index 01028a42e47..3696304530d 100644 --- a/src/ngraph/op/broadcast.cpp +++ b/src/ngraph/op/broadcast.cpp @@ -46,6 +46,12 @@ op::v1::Broadcast::Broadcast(const Output& arg, constructor_validate_and_infer_types(); } +bool op::v1::Broadcast::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("broadcast_spec", m_broadcast_spec); + return true; +} + std::pair op::v1::Broadcast::get_broadcast_axes() const { AxisSet broadcast_axes; @@ -286,6 +292,13 @@ op::v0::Broadcast::Broadcast(const Output& arg, { } +bool op::v0::Broadcast::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("shape", m_shape); + visitor.on_attribute("broadcast_axes", m_broadcast_axes); + return true; +} + void op::v0::Broadcast::validate_and_infer_types() { infer_shape(); @@ -355,6 +368,14 @@ op::v0::BroadcastLike::BroadcastLike(const Output& arg, constructor_validate_and_infer_types(); } +bool op::v0::BroadcastLike::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("shape", m_shape); + visitor.on_attribute("broadcast_axes", m_broadcast_axes); + visitor.on_attribute("initial_broadcast_axes", m_initial_broadcast_axes); + return true; +} + shared_ptr op::v0::BroadcastLike::copy_with_new_args(const NodeVector& new_args) const { if (new_args.size() != 2) diff --git a/src/ngraph/op/broadcast.hpp b/src/ngraph/op/broadcast.hpp index 66bc55c7808..586c2925d39 100644 --- a/src/ngraph/op/broadcast.hpp +++ b/src/ngraph/op/broadcast.hpp @@ -28,10 +28,9 @@ namespace ngraph { /// \brief Operation which "adds" axes to an input tensor, replicating elements from the /// input as needed along the new axes. - class Broadcast : public Op + class NGRAPH_API Broadcast : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Broadcast", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a broadcast operation. @@ -46,7 +45,7 @@ namespace ngraph Broadcast(const Output& arg, const Shape& shape, const AxisSet& broadcast_axes); - + bool visit_attributes(AttributeVisitor& visitor) override; void validate_and_infer_types() override; virtual std::shared_ptr @@ -74,10 +73,9 @@ namespace ngraph }; /// \brief Broadcast arg to the same shape as like_arg. - class BroadcastLike : public v0::Broadcast + class NGRAPH_API BroadcastLike : public v0::Broadcast { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"BroadcastLike", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Broadcast arg to the same shape as like_arg. @@ -94,7 +92,7 @@ namespace ngraph BroadcastLike(const Output& arg, const Output& like_arg, const AxisSet& initial_broadcast_axes); - + bool visit_attributes(AttributeVisitor& visitor) override; virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; @@ -117,10 +115,9 @@ namespace ngraph { /// \brief Operation which "adds" axes to an input tensor, replicating elements from the /// input as needed along the new axes. - class Broadcast : public Op + class NGRAPH_API Broadcast : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Broadcast", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a broadcast operation. @@ -154,7 +151,7 @@ namespace ngraph const Output& target_shape, const AutoBroadcastSpec& broadcast_spec = AutoBroadcastSpec(AutoBroadcastType::NUMPY)); - + bool visit_attributes(AttributeVisitor& visitor) override; size_t get_version() const override { return 1; } void validate_and_infer_types() override; diff --git a/src/ngraph/op/broadcast_distributed.cpp b/src/ngraph/op/broadcast_distributed.cpp index 02988e5ba76..41ce597cd09 100644 --- a/src/ngraph/op/broadcast_distributed.cpp +++ b/src/ngraph/op/broadcast_distributed.cpp @@ -21,13 +21,19 @@ using namespace ngraph; constexpr NodeTypeInfo op::BroadcastDistributed::type_info; -op::BroadcastDistributed::BroadcastDistributed(const Output& arg, int root_id) +op::BroadcastDistributed::BroadcastDistributed(const Output& arg, int64_t root_id) : Op({arg}) , m_root_id(root_id) { constructor_validate_and_infer_types(); } +bool op::BroadcastDistributed::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("root_id", m_root_id); + return true; +} + void op::BroadcastDistributed::validate_and_infer_types() { NODE_VALIDATION_CHECK(this, @@ -47,12 +53,12 @@ shared_ptr op::BroadcastDistributed::copy_with_new_args(const NodeVector& return make_shared(new_args.at(0), m_root_id); } -int op::BroadcastDistributed::get_root_id() const +int64_t op::BroadcastDistributed::get_root_id() const { return m_root_id; } -void op::BroadcastDistributed::set_root_id(int root_id) +void op::BroadcastDistributed::set_root_id(int64_t root_id) { m_root_id = root_id; } diff --git a/src/ngraph/op/broadcast_distributed.hpp b/src/ngraph/op/broadcast_distributed.hpp index 10ca1595373..f7031fa94fb 100644 --- a/src/ngraph/op/broadcast_distributed.hpp +++ b/src/ngraph/op/broadcast_distributed.hpp @@ -24,24 +24,27 @@ namespace ngraph { namespace op { - class BroadcastDistributed : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"BroadcastDistributed", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - BroadcastDistributed() = default; - BroadcastDistributed(const Output& arg, int root_id = 0); + class NGRAPH_API BroadcastDistributed : public Op + { + public: + static constexpr NodeTypeInfo type_info{"BroadcastDistributed", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + BroadcastDistributed() = default; + BroadcastDistributed(const Output& arg, int64_t root_id = 0); + bool visit_attributes(AttributeVisitor& visitor) override; + void validate_and_infer_types() override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + int64_t get_root_id() const; + void set_root_id(int64_t root_id); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - int get_root_id() const; - void set_root_id(int root_id); - - private: - int m_root_id; - }; + private: + int64_t m_root_id; + }; + } + using v0::BroadcastDistributed; } } diff --git a/src/ngraph/op/ceiling.hpp b/src/ngraph/op/ceiling.hpp index b8c86dcfd02..08f8f8f8449 100644 --- a/src/ngraph/op/ceiling.hpp +++ b/src/ngraph/op/ceiling.hpp @@ -22,22 +22,26 @@ namespace ngraph { namespace op { - /// \brief Elementwise ceiling operation. - class Ceiling : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Ceiling", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ceiling operation. - Ceiling() = default; - /// \brief Constructs a ceiling operation. - /// - /// \param arg Node that produces the input tensor. - Ceiling(const Output& arg); + /// \brief Elementwise ceiling operation. + class NGRAPH_API Ceiling : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Ceiling", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a ceiling operation. + Ceiling() = default; + /// \brief Constructs a ceiling operation. + /// + /// \param arg Node that produces the input tensor. + Ceiling(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + bool visit_attributes(AttributeVisitor& visitor) override { return true; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Ceiling; } } diff --git a/src/ngraph/op/concat.cpp b/src/ngraph/op/concat.cpp index 92511613ef1..34cbc63bfd6 100644 --- a/src/ngraph/op/concat.cpp +++ b/src/ngraph/op/concat.cpp @@ -36,6 +36,12 @@ op::Concat::Concat(const NodeVector& args, int64_t axis) { } +bool op::Concat::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("axis", m_axis); + return true; +} + void op::Concat::validate_and_infer_types() { NODE_VALIDATION_CHECK(this, get_input_size() >= 1, "At least one argument required."); diff --git a/src/ngraph/op/concat.hpp b/src/ngraph/op/concat.hpp index 80c3b04ff31..acf89b305b0 100644 --- a/src/ngraph/op/concat.hpp +++ b/src/ngraph/op/concat.hpp @@ -24,48 +24,52 @@ namespace ngraph { namespace op { - /// \brief Concatenation operation. - class Concat : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Concat", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a concatenation operation. - Concat() = default; - /// \brief Constructs a concatenation operation. - /// - /// \param args The outputs producing the input tensors. - /// \param axis The axis along which to concatenate the input tensors. - Concat(const OutputVector& args, int64_t axis); + /// \brief Concatenation operation. + class NGRAPH_API Concat : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Concat", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a concatenation operation. + Concat() = default; + /// \brief Constructs a concatenation operation. + /// + /// \param args The outputs producing the input tensors. + /// \param axis The axis along which to concatenate the input tensors. + Concat(const OutputVector& args, int64_t axis); - /// \brief Constructs a concatenation operation. - /// - /// \param args The nodes producing the input tensors. - /// \param axis The axis along which to concatenate the input tensors. - Concat(const NodeVector& args, int64_t axis); + /// \brief Constructs a concatenation operation. + /// + /// \param args The nodes producing the input tensors. + /// \param axis The axis along which to concatenate the input tensors. + Concat(const NodeVector& args, int64_t axis); - void validate_and_infer_types() override; + bool visit_attributes(AttributeVisitor& visitor) override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - /// \return The concatenation axis. - int64_t get_concatenation_axis() const { return m_concat_axis; } - void set_concatenation_axis(int64_t concatenation_axis) - { - m_concat_axis = concatenation_axis; - } - /// \return The concatenation axis. - int64_t get_axis() const { return m_axis; } - void set_axis(int64_t axis) { m_axis = axis; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - /// \ brief m_axis stores default value for all iterations - int64_t m_axis; - /// \brief m_concat_axis stores m_axis plus the number of rank for each iteration - int64_t m_concat_axis = -1; - }; + /// \return The concatenation axis. + int64_t get_concatenation_axis() const { return m_concat_axis; } + void set_concatenation_axis(int64_t concatenation_axis) + { + m_concat_axis = concatenation_axis; + } + /// \return The concatenation axis. + int64_t get_axis() const { return m_axis; } + void set_axis(int64_t axis) { m_axis = axis; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + /// \ brief m_axis stores default value for all iterations + int64_t m_axis; + /// \brief m_concat_axis stores m_axis plus the number of rank for each iteration + int64_t m_concat_axis = -1; + }; + } + using v0::Concat; } } diff --git a/src/ngraph/op/constant.cpp b/src/ngraph/op/constant.cpp index 06097b77e4d..69eec76372a 100644 --- a/src/ngraph/op/constant.cpp +++ b/src/ngraph/op/constant.cpp @@ -74,6 +74,9 @@ string op::Constant::convert_value_to_string(size_t index) const case element::Type_t::i16: rc = to_string(get_vector()[index]); break; case element::Type_t::i32: rc = to_string(get_vector()[index]); break; case element::Type_t::i64: rc = to_string(get_vector()[index]); break; + case element::Type_t::u1: + rc = to_string((get_vector()[index / 8] >> (7 - (index % 8))) & 1); + break; case element::Type_t::u8: rc = to_string(get_vector()[index]); break; case element::Type_t::u16: rc = to_string(get_vector()[index]); break; case element::Type_t::u32: rc = to_string(get_vector()[index]); break; @@ -176,6 +179,7 @@ vector op::Constant::get_value_strings() const rc.push_back(to_string(value)); } break; + case element::Type_t::u1: throw runtime_error("unsupported type"); case element::Type_t::undefined: throw runtime_error("unsupported type"); case element::Type_t::dynamic: throw runtime_error("unsupported type"); } @@ -323,6 +327,7 @@ bool op::Constant::are_all_data_elements_bitwise_identical() const rc = test_bitwise_identical(this); break; } + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::dynamic: break; } diff --git a/src/ngraph/op/constant.hpp b/src/ngraph/op/constant.hpp index 8bd961dc3c4..a19eb27ee88 100644 --- a/src/ngraph/op/constant.hpp +++ b/src/ngraph/op/constant.hpp @@ -30,12 +30,12 @@ namespace ngraph namespace op { /// \brief Class for constants. - class Constant : public Op + class NGRAPH_API Constant : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Constant", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + Constant() = default; /// \brief Constructs a tensor constant. /// /// \param type The element type of the tensor constant. @@ -338,6 +338,7 @@ namespace ngraph case element::Type_t::u64: write_buffer(target, source, target_element_count); break; + case element::Type_t::u1: throw std::runtime_error("unsupported type"); case element::Type_t::undefined: throw std::runtime_error("unsupported type"); case element::Type_t::dynamic: throw std::runtime_error("unsupported type"); } @@ -355,13 +356,13 @@ namespace ngraph Constant operator=(const Constant&) = delete; }; - class ScalarConstantLikeBase : public Constant + class NGRAPH_API ScalarConstantLikeBase : public Constant { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ScalarConstantLikeBase", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } std::shared_ptr as_constant() const; + ScalarConstantLikeBase() = default; protected: ScalarConstantLikeBase(const OutputVector& args) @@ -371,7 +372,7 @@ namespace ngraph }; /// \brief A scalar constant whose element type is the same as like. - class ScalarConstantLike : public ScalarConstantLikeBase + class NGRAPH_API ScalarConstantLike : public ScalarConstantLikeBase { public: /// \brief A scalar constant whose element type is the same as like. diff --git a/src/ngraph/op/convert.hpp b/src/ngraph/op/convert.hpp index c66420cc70a..ba4b169416a 100644 --- a/src/ngraph/op/convert.hpp +++ b/src/ngraph/op/convert.hpp @@ -22,42 +22,44 @@ namespace ngraph { namespace op { - /// \brief Elementwise type conversion operation. - class Convert : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Convert", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a conversion operation. - Convert() = default; - /// \brief Constructs a conversion operation. - /// - /// \param arg Node that produces the input tensor. - /// \param destination_type Element type for the output tensor. - Convert(const Output& arg, const ngraph::element::Type& destination_type); - - void validate_and_infer_types() override; + /// \brief Elementwise type conversion operation. + class NGRAPH_API Convert : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Convert", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a conversion operation. + Convert() = default; + /// \brief Constructs a conversion operation. + /// + /// \param arg Node that produces the input tensor. + /// \param destination_type Element type for the output tensor. + Convert(const Output& arg, const ngraph::element::Type& destination_type); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - const element::Type& get_destination_type() const { return m_destination_type; } - void set_destination_type(const element::Type& destination_type) - { - m_destination_type = destination_type; - } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + const element::Type& get_destination_type() const { return m_destination_type; } + void set_destination_type(const element::Type& destination_type) + { + m_destination_type = destination_type; + } - const element::Type& get_convert_element_type() const { return m_destination_type; } - void set_convert_element_type(const element::Type& destination_type) - { - m_destination_type = destination_type; - } + const element::Type& get_convert_element_type() const { return m_destination_type; } + void set_convert_element_type(const element::Type& destination_type) + { + m_destination_type = destination_type; + } - protected: - ngraph::element::Type m_destination_type; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + ngraph::element::Type m_destination_type; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Convert; } } diff --git a/src/ngraph/op/convert_like.cpp b/src/ngraph/op/convert_like.cpp new file mode 100644 index 00000000000..9af074e2fed --- /dev/null +++ b/src/ngraph/op/convert_like.cpp @@ -0,0 +1,48 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/convert_like.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::ConvertLike::type_info; + +op::v1::ConvertLike::ConvertLike(const Output& data, const Output& like) + : Op({data, like}) +{ + constructor_validate_and_infer_types(); +} + +void op::v1::ConvertLike::validate_and_infer_types() +{ + set_output_type(0, get_input_element_type(1), get_input_partial_shape(0)); +} + +shared_ptr op::v1::ConvertLike::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1)); +} + +void op::v1::ConvertLike::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) +{ + const auto delta = deltas.at(0); + + adjoints.add_delta(input_value(0), make_shared(delta, input_value(1))); +} diff --git a/src/ngraph/op/convert_like.hpp b/src/ngraph/op/convert_like.hpp new file mode 100644 index 00000000000..3371467e4cb --- /dev/null +++ b/src/ngraph/op/convert_like.hpp @@ -0,0 +1,52 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Elementwise type conversion operation. + class ConvertLike : public Op + { + public: + NGRAPH_API + static constexpr NodeTypeInfo type_info{"ConvertLike", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a conversion operation. + ConvertLike() = default; + /// \brief Constructs a conversion operation. + /// \param data Node that produces the input tensor. + /// \param like Node which provides the target type information for the conversion. + ConvertLike(const Output& data, const Output& like); + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + } +} diff --git a/src/ngraph/op/convolution.cpp b/src/ngraph/op/convolution.cpp index baaeb886a4f..d7121d4b121 100644 --- a/src/ngraph/op/convolution.cpp +++ b/src/ngraph/op/convolution.cpp @@ -102,15 +102,14 @@ void op::v1::Convolution::validate_and_infer_types() filters_et, ")."); - result_shape = - infer_convolution_forward(this, - data_batch_shape, - Strides(static_cast(data_batch_shape.rank()) - 2, 1), - m_pads_begin, - m_pads_end, - filters_shape, - m_strides, - m_dilations); + result_shape = infer_convolution_forward(this, + data_batch_shape, + Strides(m_strides.size(), 1), // dummy data dilations + m_pads_begin, + m_pads_end, + filters_shape, + m_strides, + m_dilations); set_output_type(0, result_et, result_shape); } @@ -139,11 +138,24 @@ void op::v1::Convolution::generate_adjoints(autodiff::Adjoints& adjoints, const adjoints.add_delta(x, make_shared( - f, delta, x, m_strides, m_dilations, m_pads_begin, m_pads_end)); + delta, + f, + op::Constant::create(element::i64, Shape{x_shape.size()}, x_shape), + m_strides, + m_pads_begin, + m_pads_end, + m_dilations, + m_auto_pad)); adjoints.add_delta(f, make_shared( - x, delta, f, m_strides, m_dilations, m_pads_begin, m_pads_end)); + x, + delta, + op::Constant::create(element::i64, Shape{x_shape.size()}, f_shape), + m_strides, + m_dilations, + m_pads_begin, + m_pads_end)); } constexpr NodeTypeInfo op::v1::ConvolutionBackpropData::type_info; @@ -152,141 +164,171 @@ shared_ptr op::v1::Convolution::get_default_value() const return ngraph::make_constant_from_string("0", get_element_type(), get_shape()); } -op::v1::ConvolutionBackpropData::ConvolutionBackpropData(const Output& filters, - const Output& output_delta, - const Output& data_batch_shape, +op::v1::ConvolutionBackpropData::ConvolutionBackpropData(const Output& data, + const Output& filters, + const Output& output_shape, const Strides& strides, + const CoordinateDiff& pads_begin, + const CoordinateDiff& pads_end, const Strides& dilations, + const PadType& auto_pad, + const CoordinateDiff& output_padding) + : Op({data, filters, output_shape}) + , m_strides(strides) + , m_dilations(dilations) + , m_pads_begin(pads_begin) + , m_pads_end(pads_end) + , m_auto_pad(auto_pad) + , m_output_padding(output_padding) +{ + constructor_validate_and_infer_types(); +} + +op::v1::ConvolutionBackpropData::ConvolutionBackpropData(const Output& data, + const Output& filters, + const Strides& strides, const CoordinateDiff& pads_begin, - const CoordinateDiff& pads_end) - : Op({filters, output_delta, data_batch_shape}) + const CoordinateDiff& pads_end, + const Strides& dilations, + const PadType& auto_pad, + const CoordinateDiff& output_padding) + : Op({data, filters}) , m_strides(strides) , m_dilations(dilations) , m_pads_begin(pads_begin) , m_pads_end(pads_end) + , m_auto_pad(auto_pad) + , m_output_padding(output_padding) { constructor_validate_and_infer_types(); } -const Shape op::v1::ConvolutionBackpropData::get_data_batch_shape() const +const PartialShape op::v1::ConvolutionBackpropData::get_output_shape() const { - Shape shape; - if (auto const_op = as_type(input_value(2).get_node())) + PartialShape shape{PartialShape::dynamic()}; + bool is_output_shape_present = get_inputs().size() == 3; + if (is_output_shape_present) { - shape = const_op->get_shape_val(); + if (auto const_op = as_type(input_value(2).get_node())) + { + shape = const_op->get_shape_val(); + } } return shape; } -void op::v1::ConvolutionBackpropData::set_data_batch_shape(const Shape& shape) +void op::v1::ConvolutionBackpropData::set_output_shape(const Shape& shape) { this->input(2).replace_source_output( op::Constant::create(element::i64, Shape{shape.size()}, shape)->output(0)); } + void op::v1::ConvolutionBackpropData::validate_and_infer_types() { - // Backprop to data is itself convolution, with inputs/outputs/attributes transmogrified as - // follows. - // - // Forward Backward - // "N" axis for data batch 0 0 - // "C" axis for data batch 1 1 - // "Co" axis for filters 0 0 - // "Ci" axis for filters 1 1 - // "N" axis for output 0 0 - // "C" axis for output 1 1 - // Data batch x delta - // Data batch shape S_x S_o - // Filters f reverse(f) [on spatial axes] - // Filters shape S_f S_f - // Window movement strides q_x p_x - // Window dilation strides p_f p_f - // Padding below a_x (S_f - 1)p_f - a_x - // Padding above b_x (S_f - 1)p_f + - // + ((a_x + (S_x - 1)p_x + b_x - (S_f - 1)p_f) - // % q_x) - // - b_x - // Output shape S_o S_x - // - // To _validate_, we simply need to check/infer the output shape of the forward convolution, - // then check to make sure that the incoming delta has the same shape as the forward output. - const PartialShape& filters_shape = get_input_partial_shape(0); - element::Type filters_et = get_input_element_type(0); - const PartialShape& delta_shape = get_input_partial_shape(1); - element::Type delta_et = get_input_element_type(1); - - element::Type forward_result_et; - PartialShape forward_result_shape; - PartialShape data_batch_shape{PartialShape::dynamic()}; + auto data_pshape = get_input_partial_shape(0); + element::Type delta_et = get_input_element_type(0); + const PartialShape& filters_pshape = get_input_partial_shape(1); + element::Type filters_et = get_input_element_type(1); - if (input_value(2).get_node_shared_ptr()->is_constant()) - { - data_batch_shape = get_data_batch_shape(); - } + bool is_output_shape_present = get_inputs().size() == 3; + PartialShape output_pshape = get_output_shape(); + element::Type result_et; NODE_VALIDATION_CHECK( this, - element::Type::merge(forward_result_et, delta_et, filters_et), + element::Type::merge(result_et, delta_et, filters_et), "Element types for data batch and filters do not match (data batch element type: ", delta_et, ", filters element type: ", filters_et, ")."); - if (input_value(2).get_node_shared_ptr()->is_constant()) + if (m_auto_pad == PadType::SAME_UPPER || m_auto_pad == PadType::SAME_LOWER) { - forward_result_shape = infer_convolution_forward( - this, - data_batch_shape, - Strides(static_cast(get_data_batch_shape().size()) - 2, 1), - m_pads_begin, - m_pads_end, - filters_shape, - m_strides, - m_dilations); - NODE_VALIDATION_CHECK(this, - forward_result_shape.compatible(delta_shape), - "Inferred forward output shape (", - forward_result_shape, - ") does not match shape of ", - "delta (", - delta_shape, - ")."); + is_output_shape_present, + "Selected Pad type: ", + m_auto_pad, + "requires an output_shape input which is missing."); + if (output_pshape.is_static() && filters_pshape.is_static()) + { + m_pads_begin.clear(); + m_pads_end.clear(); + auto filter_shape = filters_pshape.to_shape(); + filter_shape.erase(filter_shape.begin(), filter_shape.begin() + 2); // Remove {O,I} + infer_auto_padding(output_pshape.to_shape(), + filter_shape, + m_strides, + m_dilations, + m_auto_pad, + m_pads_end, + m_pads_begin); + } + } + + PartialShape result_shape; + if (is_output_shape_present) + { + set_input_is_relevant_to_shape(2); + if (output_pshape.is_static() && data_pshape.is_static()) + { + auto data_shape = data_pshape.to_shape(); + auto output_shape = output_pshape.to_shape(); + output_shape.insert(output_shape.begin(), data_shape.begin(), data_shape.begin() + 1); + output_pshape = output_shape; + } } + else + { + if (filters_pshape.is_static() && data_pshape.is_static()) + { + auto filters_shape = filters_pshape.to_shape(); + auto data_shape = data_pshape.to_shape(); + + Shape output_shape; + auto data_spatial_rank = data_shape.size() - 2; + auto output_padding = get_output_padding(); + if (output_padding.size() == 0) + { + output_padding.insert(output_padding.begin(), data_spatial_rank, 0); + } + for (size_t i = 0; i < data_spatial_rank; ++i) + { + size_t tmp = m_strides[i] * (data_shape[i + 2] - 1) + + ((filters_shape[i] + 2 - 1) * m_dilations[i] + 1) - m_pads_begin[i] - + m_pads_end[i] + output_padding[i]; + output_shape.push_back(tmp); + output_pshape = output_shape; + } + output_shape.insert(output_shape.begin(), data_shape.begin(), data_shape.begin() + 1); + } + } + set_input_is_relevant_to_shape(0); set_input_is_relevant_to_shape(1); - set_input_is_relevant_to_shape(2); - set_output_type(0, forward_result_et, data_batch_shape); + set_output_type(0, result_et, output_pshape); } void op::v1::ConvolutionBackpropData::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) { - if (input_value(2).get_node_shared_ptr()->is_constant()) - { - } - else - { - throw ngraph_error("Autodiff not supported with dynamic shapes"); - } auto delta = deltas.at(0); - auto x = input_value(1); + auto x = input_value(0); const auto x_shape = x.get_shape(); - auto f = input_value(0); + auto f = input_value(1); const auto f_shape = f.get_shape(); auto data_conv = make_shared( - delta, f, m_strides, m_pads_begin, m_pads_end, m_dilations); + delta, f, m_strides, m_pads_begin, m_pads_end, m_dilations, m_auto_pad); adjoints.add_delta(x, data_conv); Strides strides = m_dilations; CoordinateDiff pads_begin; CoordinateDiff pads_end; - const Shape& filters_shape = get_input_shape(0); + const Shape& filters_shape = get_input_shape(1); for (size_t i = 0; i < f_shape.size() - 2; i++) { ptrdiff_t pads_begin_backward = @@ -295,8 +337,9 @@ void op::v1::ConvolutionBackpropData::generate_adjoints(autodiff::Adjoints& adjo ptrdiff_t pads_end_backward = (static_cast(filters_shape[i + 2]) - 1) * m_dilations[i] + - ((m_pads_begin[i] + ((get_data_batch_shape()[i + 2]) - 1) * m_strides[i] + - m_pads_end[i] - (static_cast(filters_shape[i + 2]) - 1) * m_dilations[i]) % + ((m_pads_begin[i] + + (static_cast(get_output_shape()[i + 2]) - 1) * m_strides[i] + m_pads_end[i] - + (static_cast(filters_shape[i + 2]) - 1) * m_dilations[i]) % m_strides[i]) - m_pads_end[i]; @@ -322,7 +365,7 @@ void op::v1::ConvolutionBackpropData::generate_adjoints(autodiff::Adjoints& adjo x = swap_NC(x); shared_ptr filter_deconv_bprop = make_shared( - x, delta, strides, pads_begin, pads_end, Strides(x.get_shape().size() - 2, 1)); + x, delta, strides, pads_begin, pads_end, Strides(x.get_shape().size() - 2, 1), m_auto_pad); AxisSet axes; for (size_t i = 2; i < filter_deconv_bprop->get_shape().size(); ++i) { @@ -336,58 +379,29 @@ shared_ptr op::v1::ConvolutionBackpropData::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), - new_args.at(1), - new_args.at(2), - m_strides, - m_dilations, - m_pads_begin, - m_pads_end); -} - -CoordinateDiff op::v1::ConvolutionBackpropData::compute_backward_delta_out_pad_below() const -{ - auto& in_shape = get_data_batch_shape(); - auto& filter_dilation = get_dilations(); - auto& filter_shape = get_input_shape(0); - auto& in_pad_below = get_pads_begin(); - size_t spatial_dim_count = static_cast(in_shape.size()) - 2; - - CoordinateDiff backward_delta_out_pad_below; - backward_delta_out_pad_below.resize(spatial_dim_count); - - for (size_t i = 0; i < spatial_dim_count; i++) + if (new_args.size() == 3) { - backward_delta_out_pad_below[i] = - (static_cast(filter_shape[i + 2]) - 1) * filter_dilation[i] - - in_pad_below[i]; + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + m_strides, + m_pads_begin, + m_pads_end, + m_dilations, + m_auto_pad, + m_output_padding); } - return backward_delta_out_pad_below; -} - -CoordinateDiff op::v1::ConvolutionBackpropData::compute_backward_delta_out_pad_above() const -{ - auto& in_shape = get_data_batch_shape(); - auto& filter_dilation = get_dilations(); - auto& filter_shape = get_input_shape(0); - auto& in_pad_below = get_pads_begin(); - auto& in_pad_above = get_pads_end(); - auto& stride = get_strides(); - size_t spatial_dim_count = static_cast(in_shape.size()) - 2; - - CoordinateDiff backward_delta_out_pad_above; - backward_delta_out_pad_above.resize(spatial_dim_count); - - for (size_t i = 0; i < spatial_dim_count; i++) + else { - backward_delta_out_pad_above[i] = - (static_cast(filter_shape[i + 2]) - 1) * filter_dilation[i] + - ((in_pad_below[i] + ((in_shape[i + 2]) - 1) + in_pad_above[i] - - (static_cast(filter_shape[i + 2]) - 1) * filter_dilation[i]) % - stride[i]) - - in_pad_above[i]; + return make_shared(new_args.at(0), + new_args.at(1), + m_strides, + m_pads_begin, + m_pads_end, + m_dilations, + m_auto_pad, + m_output_padding); } - return backward_delta_out_pad_above; } constexpr NodeTypeInfo op::v1::ConvolutionBackpropFilters::type_info; diff --git a/src/ngraph/op/convolution.hpp b/src/ngraph/op/convolution.hpp index 0e7aa667835..e01c1bbcec9 100644 --- a/src/ngraph/op/convolution.hpp +++ b/src/ngraph/op/convolution.hpp @@ -28,10 +28,9 @@ namespace ngraph { /// \brief Batched convolution operation, with optional window dilation and stride. /// - class Convolution : public Op + class NGRAPH_API Convolution : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Convolution", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched convolution operation. @@ -63,7 +62,6 @@ namespace ngraph const Strides& dilations, const PadType& auto_pad = PadType::EXPLICIT); - size_t get_version() const override { return 1; } void validate_and_infer_types() override; virtual std::shared_ptr @@ -98,32 +96,57 @@ namespace ngraph }; /// \brief Data batch backprop for batched convolution operation. - class ConvolutionBackpropData : public Op + class NGRAPH_API ConvolutionBackpropData : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ConvolutionBackpropData", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched-convolution data batch-backprop operation. ConvolutionBackpropData() = default; + // clang-format off /// \brief Constructs a batched-convolution data batch-backprop operation. /// - /// \param data_batch_shape The shape of the data batch from forward-prop. - /// \param filters The node producing the filters from forward-prop. - /// \param output_delta The node producing output delta. - /// \param strides The strides from forward-prop. - /// \param dilations The dilations from forward-prop. - /// \param pads_begin The padding-below sizes from forward-prop. - /// \param pads_end The padding-above sizes from forward-prop. - ConvolutionBackpropData(const Output& filters, - const Output& output_delta, - const Output& data_batch_shape, + /// \param data The node producing data from forward-prop. + /// \param filters The node producing the filters from forward-prop. + /// \param output_shape The shape of the data batch from forward-prop. + /// \param strides The strides from forward-prop. + /// \param pads_begin The padding-below sizes from forward-prop. + /// \param pads_end The padding-above sizes from forward-prop. + /// \param dilations The dilations from forward-prop. + /// \param auto_pad The pad type for automatically computing padding sizes. + /// \param output_padding The output padding adds additional amount of paddings per each spatial axis in the output tensor. + // clang-format on + ConvolutionBackpropData(const Output& data, + const Output& filters, + const Output& output_shape, const Strides& strides, + const CoordinateDiff& pads_begin, + const CoordinateDiff& pads_end, const Strides& dilations, + const PadType& auto_pad = PadType::EXPLICIT, + const CoordinateDiff& output_padding = {}); + + // clang-format off + /// \brief Constructs a batched-convolution data batch-backprop operation. + /// + /// \param data The node producing data from forward-prop. + /// \param filters The node producing the filters from forward-prop. + /// \param strides The strides from forward-prop. + /// \param pads_begin The padding-below sizes from forward-prop. + /// \param pads_end The padding-above sizes from forward-prop. + /// \param dilations The dilations from forward-prop. + /// \param auto_pad The pad type for automatically computing padding sizes. + /// \param output_padding The output padding adds additional amount of paddings per each spatial axis in the output tensor. + // clang-format on + ConvolutionBackpropData(const Output& data, + const Output& filters, + const Strides& strides, const CoordinateDiff& pads_begin, - const CoordinateDiff& pads_end); + const CoordinateDiff& pads_end, + const Strides& dilations, + const PadType& auto_pad = PadType::EXPLICIT, + const CoordinateDiff& output_padding = {}); - size_t get_version() const override { return 1; } void validate_and_infer_types() override; void generate_adjoints(autodiff::Adjoints& adjoints, @@ -132,8 +155,8 @@ namespace ngraph copy_with_new_args(const NodeVector& new_args) const override; /// \return The data batch shape. - const Shape get_data_batch_shape() const; - void set_data_batch_shape(const Shape& data_batch_shape); + const PartialShape get_output_shape() const; + void set_output_shape(const Shape& output_shape); /// \return The strides from the forward prop. const Strides& get_strides() const { return m_strides; } void set_strides(const Strides& strides) { m_strides = strides; } @@ -146,22 +169,29 @@ namespace ngraph /// \return The padding-above sizes (possibly negative) from the forward prop. const CoordinateDiff& get_pads_end() const { return m_pads_end; } void set_pads_end(const CoordinateDiff& pads_end) { m_pads_end = pads_end; } - // Compute the pad_above values to be used if in a convolution - CoordinateDiff compute_backward_delta_out_pad_above() const; - CoordinateDiff compute_backward_delta_out_pad_below() const; + /// \return The auto pad. + const PadType& get_auto_pad() const { return m_auto_pad; } + void set_auto_pad(const PadType& auto_pad) { m_auto_pad = auto_pad; } + /// \return The output padding. + const CoordinateDiff& get_output_padding() const { return m_output_padding; } + void set_output_padding(const CoordinateDiff& output_padding) + { + m_output_padding = output_padding; + } protected: Strides m_strides; Strides m_dilations; CoordinateDiff m_pads_begin; CoordinateDiff m_pads_end; + PadType m_auto_pad; + CoordinateDiff m_output_padding; }; /// \brief Filters backprop for batched convolution operation. - class ConvolutionBackpropFilters : public Op + class NGRAPH_API ConvolutionBackpropFilters : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ConvolutionBackpropFilters", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched-convolution filter-backprop operation. @@ -183,7 +213,6 @@ namespace ngraph const CoordinateDiff& pads_begin, const CoordinateDiff& pads_end); - size_t get_version() const override { return 1; } void validate_and_infer_types() override; virtual std::shared_ptr @@ -219,10 +248,9 @@ namespace ngraph { /// \brief Batched convolution operation, with optional window dilation and stride. /// - class Convolution : public Op + class NGRAPH_API Convolution : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Convolution", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched convolution operation. @@ -394,10 +422,9 @@ namespace ngraph }; /// \brief Data batch backprop for batched convolution operation. - class ConvolutionBackpropData : public Op + class NGRAPH_API ConvolutionBackpropData : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ConvolutionBackpropData", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched-convolution data batch-backprop operation. @@ -406,7 +433,7 @@ namespace ngraph /// /// \param data_batch_shape The shape of the data batch from forward-prop. /// \param filters The node producing the filters from forward-prop. - /// \param output_delta The node producing output delta. + /// \param data The node producing output delta. /// \param window_movement_strides_forward The window movement strides from /// forward-prop. /// \param window_dilation_strides_forward The window dilation strides from @@ -417,7 +444,7 @@ namespace ngraph /// forward-prop. ConvolutionBackpropData(const Shape& data_batch_shape, const Output& filters, - const Output& output_delta, + const Output& data, const Strides& window_movement_strides_forward, const Strides& window_dilation_strides_forward, const CoordinateDiff& padding_below_forward, @@ -499,10 +526,9 @@ namespace ngraph }; /// \brief Filters backprop for batched convolution operation. - class ConvolutionBackpropFilters : public Op + class NGRAPH_API ConvolutionBackpropFilters : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ConvolutionBackpropFilters", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched-convolution filter-backprop operation. @@ -601,6 +627,7 @@ namespace ngraph // This is a legacy function, retained because the CPU backend uses it for now. // TODO: Update CPU backend to use the new stuff in validation_util.hpp, and remove this // function. + NGRAPH_API Shape infer_convolution_output_shape(const Node* node, const Shape& data_batch_shape, const Shape& filters_shape, diff --git a/src/ngraph/op/cos.hpp b/src/ngraph/op/cos.hpp index c83b227322d..ef41aed866f 100644 --- a/src/ngraph/op/cos.hpp +++ b/src/ngraph/op/cos.hpp @@ -22,26 +22,29 @@ namespace ngraph { namespace op { - /// \brief Elementwise cosine operation. - class Cos : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Cos", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a cosine operation. - Cos() = default; - /// \brief Constructs a cosine operation. - /// - /// \param arg Node that produces the input tensor. - Cos(const Output& arg); + /// \brief Elementwise cosine operation. + class NGRAPH_API Cos : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Cos", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a cosine operation. + Cos() = default; + /// \brief Constructs a cosine operation. + /// + /// \param arg Node that produces the input tensor. + Cos(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Cos; } } diff --git a/src/ngraph/op/cosh.hpp b/src/ngraph/op/cosh.hpp index 3bbaba0c73e..c0181c29aaf 100644 --- a/src/ngraph/op/cosh.hpp +++ b/src/ngraph/op/cosh.hpp @@ -22,26 +22,29 @@ namespace ngraph { namespace op { - /// \brief Elementwise hyperbolic cosine (cosh) operation. - class Cosh : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Cosh", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a hyperbolic cosine operation. - Cosh() = default; - /// \brief Constructs a hyperbolic cosine operation. - /// - /// \param arg Node that produces the input tensor. - Cosh(const Output& arg); + /// \brief Elementwise hyperbolic cosine (cosh) operation. + class NGRAPH_API Cosh : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Cosh", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a hyperbolic cosine operation. + Cosh() = default; + /// \brief Constructs a hyperbolic cosine operation. + /// + /// \param arg Node that produces the input tensor. + Cosh(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Cosh; } } diff --git a/src/ngraph/op/crop_and_resize.cpp b/src/ngraph/op/crop_and_resize.cpp new file mode 100644 index 00000000000..5c09d6172ba --- /dev/null +++ b/src/ngraph/op/crop_and_resize.cpp @@ -0,0 +1,198 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/constant.hpp" +#include "ngraph/op/crop_and_resize.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::CropAndResize::type_info; + +op::CropAndResize::CropAndResize(const Output& image, + const Output& boxes, + const Output& box_indices, + const Output& crop_size, + ResizeMethod resize_method, + float extrapolation_value) + : Op({image, boxes, box_indices, crop_size}) + , m_resize_method(resize_method) + , m_extrapolation_value(extrapolation_value) +{ + constructor_validate_and_infer_types(); +} + +void op::CropAndResize::validate_and_infer_types() +{ + NODE_VALIDATION_CHECK(this, get_input_size() == 4); + NODE_VALIDATION_CHECK( + this, m_resize_method != ResizeMethod::unspecified, "Resize method not specified"); + auto image = input_value(0); + auto& image_et = image.get_element_type(); + + // Will override if we can determine the shape + set_output_type(0, image_et, {}); + + auto image_shape = image.get_partial_shape(); + Dimension image_depth; + if (image_shape.is_static()) + { + NODE_VALIDATION_CHECK( + this, static_cast(image_shape.rank()) == 4, "Image must be NHWC"); + image_depth = image_shape[3]; + } + + auto boxes = input_value(1); + auto boxes_shape = boxes.get_partial_shape(); + if (boxes_shape.is_static()) + { + auto boxes_rank = boxes_shape.rank(); + NODE_VALIDATION_CHECK(this, static_cast(boxes_rank) == 2, "Boxes must be 2d"); + auto boxes_dim1 = boxes_shape[1]; + NODE_VALIDATION_CHECK( + this, static_cast(boxes_dim1) == 4, "Second boxes dimension must be 4"); + } + NODE_VALIDATION_CHECK( + this, boxes.get_element_type().is_real(), "Boxes must be real values in [0, 1]"); + + auto box_indices = input_value(2); + auto box_indices_shape = box_indices.get_partial_shape(); + Dimension num_boxes; + if (box_indices_shape.is_static()) + { + NODE_VALIDATION_CHECK(this, + static_cast(box_indices_shape.rank()) == 1, + "Box indices must have rank 1"); + num_boxes = box_indices_shape[0]; + } + NODE_VALIDATION_CHECK( + this, box_indices.get_element_type().is_integral(), "Box indices must be integers"); + + auto crop_size = input_value(3); + auto crop_size_shape = crop_size.get_partial_shape(); + auto crop_size_rank = crop_size_shape.rank(); + NODE_VALIDATION_CHECK(this, + crop_size_shape.is_static() || crop_size_rank.is_dynamic(), + "Dynamic crop_size not supported"); + + NODE_VALIDATION_CHECK( + this, static_cast(crop_size_rank) == 1, "crop_size must be a vector"); + NODE_VALIDATION_CHECK(this, + static_cast(crop_size_shape[0]) == 2, + "crop_size must be a vector of length 2"); + auto& crop_size_et = crop_size.get_element_type(); + NODE_VALIDATION_CHECK(this, crop_size_et.is_integral(), "crops_size must be integral"); + auto crop_size_node = crop_size.get_node_shared_ptr(); + NODE_VALIDATION_CHECK(this, crop_size_node->is_constant(), "crop_size must be a constant"); + auto crop_size_const = static_pointer_cast(crop_size_node); + if (crop_size_et == element::i8) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::u8) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::i16) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::u16) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::i32) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::u32) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::i64) + { + auto v = crop_size_const->get_vector(); + set_output_type(0, image_et, {num_boxes, v[0], v[1], image_depth}); + } + else if (crop_size_et == element::u64) + { + auto v = crop_size_const->get_vector(); + set_output_type( + 0, + image_et, + {num_boxes, static_cast(v[0]), static_cast(v[1]), image_depth}); + } + else + { + NODE_VALIDATION_CHECK(this, false, "Unknown integral type for crop size"); + } +} + +shared_ptr op::CropAndResize::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + new_args.at(3), + m_resize_method, + m_extrapolation_value); +} + +static const vector>& get_resize_pairs() +{ + static vector> pairs{ + {"unspecified", op::CropAndResize::ResizeMethod::unspecified}, + {"bilinear", op::CropAndResize::ResizeMethod::bilinear}, + {"nearest", op::CropAndResize::ResizeMethod::nearest}}; + return pairs; +} + +const string& ngraph::as_string(op::CropAndResize::ResizeMethod resize_method) +{ + for (auto& p : get_resize_pairs()) + { + if (p.second == resize_method) + { + return p.first; + } + } + throw ngraph_error("Internal error: unhandled resize method"); +} + +namespace ngraph +{ + template <> + op::CropAndResize::ResizeMethod as_type(const std::string& s) + { + for (auto& p : get_resize_pairs()) + { + if (p.first == s) + { + return p.second; + } + } + throw ngraph_error("Internal error: unhandled resize method name"); + } +} diff --git a/src/ngraph/op/crop_and_resize.hpp b/src/ngraph/op/crop_and_resize.hpp new file mode 100644 index 00000000000..fbba380fcbc --- /dev/null +++ b/src/ngraph/op/crop_and_resize.hpp @@ -0,0 +1,75 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/op.hpp" + +namespace ngraph +{ + namespace op + { + class NGRAPH_API CropAndResize : public Op + { + public: + enum class ResizeMethod + { + unspecified, + bilinear, + nearest + }; + + static constexpr NodeTypeInfo type_info{"CropAndResize", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a crop and resize operation. + CropAndResize() = default; + + /// \param image [N, H, W, C] + /// \param boxes [NUM_BOXES, 4] where boxes[box] is [y1, x1, y2, x2] each in [0, 1] + /// \param box_indices [NUM_BOXES] in [0, N) + /// \param crop_size [crop_height, crop_width] + CropAndResize(const Output& image, + const Output& boxes, + const Output& box_indices, + const Output& crop_size, + ResizeMethod resize_method, + float extrapolation_value); + + void validate_and_infer_types() override; + + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + + ResizeMethod get_resize_method() const { return m_resize_method; } + void set_resize_method(ResizeMethod resize_method) { m_resize_method = resize_method; } + float get_extrapolation_value() const { return m_extrapolation_value; } + void set_extrapolation_value(float extrapolation_value) + { + m_extrapolation_value = extrapolation_value; + } + + private: + ResizeMethod m_resize_method{ResizeMethod::unspecified}; + float m_extrapolation_value{0}; + }; + } + + const std::string& as_string(op::CropAndResize::ResizeMethod); + template + T as_type(const std::string&); + + template <> + op::CropAndResize::ResizeMethod as_type(const std::string&); +} diff --git a/src/ngraph/op/cum_sum.cpp b/src/ngraph/op/cum_sum.cpp new file mode 100644 index 00000000000..4115992d2e6 --- /dev/null +++ b/src/ngraph/op/cum_sum.cpp @@ -0,0 +1,60 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/cum_sum.hpp" +#include "ngraph/graph_util.hpp" +#include "ngraph/op/broadcast.hpp" +#include "ngraph/op/constant.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::CumSum::type_info; + +op::CumSum::CumSum(const Output& arg, + const Output& axis, + const bool exclusive, + const bool reverse) + : Op({arg, axis}) + , m_exclusive(exclusive) + , m_reverse(reverse) +{ + NODE_VALIDATION_CHECK(this, + axis.get_element_type() == element::i32 || + axis.get_element_type() == element::i64, + "axis element type must be either int64_t or int32_t but got (", + axis.get_element_type(), + ")."); + set_output_type(0, arg.get_element_type(), arg.get_shape()); +} + +shared_ptr op::CumSum::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), m_exclusive, m_reverse); +} + +void op::CumSum::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) +{ + auto delta = deltas.at(0); + auto input_tensor = input_value(0); + adjoints.add_delta(input_tensor, delta); +} + +shared_ptr op::CumSum::get_default_value() const +{ + return ngraph::make_constant_from_string("0", get_element_type(), get_shape()); +} diff --git a/src/ngraph/op/cum_sum.hpp b/src/ngraph/op/cum_sum.hpp new file mode 100644 index 00000000000..34b9d974bd3 --- /dev/null +++ b/src/ngraph/op/cum_sum.hpp @@ -0,0 +1,109 @@ +//***************************************************************************** +// Copyright 2017-2019 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/axis_set.hpp" +#include "ngraph/op/op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v0 + { + /// \brief Tensor cumulative sum operation. + /// + /// Compute the cumulative sum of the input tensor along the axis specified. + /// + /// ## Parameters + /// + /// | | Description | + /// | -------------------- | + /// --------------------------------------------------------------------------------------------------| + /// | `exclusive` | If set to 1 will return exclusive sum in which the top + /// element + /// is not included. | + /// | | In other terms, if set to 1, the j-th output element + /// would be + /// the + /// sum of the first (j-1) elements.| + /// | | Otherwise, it would be the sum of the first j elements. + /// | + /// + /// | | Description | + /// | -------------------- | -------------------------------------------------- | + /// | `reverse` | if set to 1, performs the sum in reverse direction | + /// + /// ## Inputs + /// + /// | | Description | + /// | ----- | ------------------------------------------------------ | + /// | `arg` | An input tensor of any shape and numeric element type. | + /// + /// | | Description | + /// | ----- | + /// ------------------------------------------------------------------------------------------------| + /// | `axis`| zero dimension tensor specifying axis position along which cumulative sum + /// must + /// be performed. | + /// + /// ## Output + /// + /// | Description | + /// | + /// ------------------------------------------------------------------------------------| + /// | Output tensor of the same type as `arg` with cumulative sums of the arg's elements + /// | + + class NGRAPH_API CumSum : public Op + { + public: + static constexpr NodeTypeInfo type_info{"CumSum", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a cumulative summation operation. + CumSum() = default; + + /// \brief Constructs a cumulative summation operation. + /// + /// \param arg The tensor to be summed. + /// \param axis zero dimension tensor specifying axis position along which + /// cumulative + /// sum must be performed + CumSum(const Output& arg, + const Output& axis, + const bool exclusive = false, + const bool reverse = false); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + /// \return The default value for CumSum. + virtual std::shared_ptr get_default_value() const override; + bool is_exclusive() const { return m_exclusive; } + bool is_reverse() const { return m_reverse; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + private: + bool m_exclusive; + bool m_reverse; + }; + } + using v0::CumSum; + } +} diff --git a/src/ngraph/op/deformable_psroi_pooling.cpp b/src/ngraph/op/deformable_psroi_pooling.cpp new file mode 100644 index 00000000000..392056a6210 --- /dev/null +++ b/src/ngraph/op/deformable_psroi_pooling.cpp @@ -0,0 +1,115 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "deformable_psroi_pooling.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::DeformablePSROIPooling::type_info; + +op::v1::DeformablePSROIPooling::DeformablePSROIPooling(const Output& input, + const Output& coords, + const Output& offsets, + const int64_t output_dim, + const float spatial_scale, + const int64_t group_size, + const std::string mode, + int64_t spatial_bins_x, + int64_t spatial_bins_y, + float trans_std, + int64_t part_size) + : Op({input, coords, offsets}) + , m_output_dim(output_dim) + , m_spatial_scale(spatial_scale) + , m_group_size(group_size) + , m_mode(mode) + , m_spatial_bins_x(spatial_bins_x) + , m_spatial_bins_y(spatial_bins_y) + , m_trans_std(trans_std) + , m_part_size(part_size) +{ + constructor_validate_and_infer_types(); +} + +void op::v1::DeformablePSROIPooling::validate_and_infer_types() +{ + const auto& input_et = get_input_element_type(0); + + const auto& input_pshape = get_input_partial_shape(0); + const auto& box_coords_pshape = get_input_partial_shape(1); + + NODE_VALIDATION_CHECK(this, + input_pshape.rank().is_dynamic() || + static_cast(input_pshape.rank()) == 4, + "Feature map input rank must equal to 4 (input rank: ", + static_cast(input_pshape.rank()), + ")"); + NODE_VALIDATION_CHECK(this, + box_coords_pshape.rank().is_dynamic() || + static_cast(box_coords_pshape.rank()) == 2, + "Box coordinates input rank must equal to 2 (input rank: ", + static_cast(box_coords_pshape.rank()), + ")"); + + if (get_input_size() == 3) // offsets input is provided + { + const auto& offsets_pshape = get_input_partial_shape(2); + NODE_VALIDATION_CHECK(this, + offsets_pshape.rank().is_dynamic() || + static_cast(offsets_pshape.rank()) == 4, + "Offsets input rank must equal to 4 (input rank: ", + static_cast(offsets_pshape.rank()), + ")"); + } + int64_t output_rank = 4; + std::vector output_dim_vec(output_rank, Dimension::dynamic()); + if (box_coords_pshape[0].is_static()) + { + output_dim_vec[0] = box_coords_pshape.to_shape()[0]; + } + output_dim_vec[1] = m_output_dim; + for (int i = 2; i < output_rank; ++i) + { + output_dim_vec[i] = m_group_size; + } + + set_output_type(0, input_et, PartialShape(output_dim_vec)); +} + +shared_ptr + op::v1::DeformablePSROIPooling::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + if (new_args.size() == 3) + { + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + m_output_dim, + m_spatial_scale, + m_group_size, + m_mode, + m_spatial_bins_x, + m_spatial_bins_y, + m_trans_std, + m_part_size); + } + else + { + throw ngraph_error("Not supported number of DeformablePSROIPooling args"); + } +} diff --git a/src/ngraph/op/deformable_psroi_pooling.hpp b/src/ngraph/op/deformable_psroi_pooling.hpp new file mode 100644 index 00000000000..ceb90bf31ba --- /dev/null +++ b/src/ngraph/op/deformable_psroi_pooling.hpp @@ -0,0 +1,93 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + class NGRAPH_API DeformablePSROIPooling : public Op + { + public: + static constexpr NodeTypeInfo type_info{"DeformablePSROIPooling", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + DeformablePSROIPooling() = default; + /// \brief Constructs a DeformablePSROIPooling operation + /// + /// \param input Input tensor with feature maps + /// \param coords Input tensor describing box consisting + /// of five element tuples + /// \param offsets Input blob with transformation values + /// \param output_dim Pooled output channel number + /// \param group_size Number of groups to encode position-sensitive score maps + /// \param spatial_scale Multiplicative spatial scale factor to translate ROI + /// coordinates from their input scale to the scale used when + /// pooling + /// \param mode Specifies mode for pooling. + /// \param spatial_bins_x Specifies numbers of bins to divide the input feature + /// maps over width + /// \param spatial_bins_y Specifies numbers of bins to divide the input feature + /// maps over height + /// \param no_trans The flag that specifies whenever third input exists + /// and contains transformation (offset) values + /// \param trans_std The value that all transformation (offset) values are + /// multiplied with + /// \param part_size The number of parts the output tensor spatial dimensions + /// are divided into. Basically it is the height + /// and width of the third input + DeformablePSROIPooling(const Output& input, + const Output& coords, + const Output& offsets, + const int64_t output_dim, + const float spatial_scale, + const int64_t group_size = 1, + const std::string mode = "bilinear_deformable", + int64_t spatial_bins_x = 1, + int64_t spatial_bins_y = 1, + float trans_std = 1, + int64_t part_size = 1); + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + int64_t get_output_dim() const { return m_output_dim; } + int64_t get_group_size() const { return m_group_size; } + float get_spatial_scale() const { return m_spatial_scale; } + const std::string& get_mode() const { return m_mode; } + int64_t get_spatial_bins_x() const { return m_spatial_bins_x; } + int64_t get_spatial_bins_y() const { return m_spatial_bins_y; } + float get_trans_std() const { return m_trans_std; } + int64_t get_part_size() const { return m_part_size; } + private: + int64_t m_output_dim; + float m_spatial_scale; + int64_t m_group_size; + std::string m_mode; + int64_t m_spatial_bins_x; + int64_t m_spatial_bins_y; + float m_trans_std; + int64_t m_part_size; + }; + } + } +} diff --git a/src/ngraph/op/dequantize.hpp b/src/ngraph/op/dequantize.hpp index 2476bb8776a..1632aee8862 100644 --- a/src/ngraph/op/dequantize.hpp +++ b/src/ngraph/op/dequantize.hpp @@ -27,10 +27,9 @@ namespace ngraph /// \brief Dequantize operation /// Maps quantized input (q) to real output (r) using scale (s) and zero point (z): /// r = (q - o) * s - class Dequantize : public ngraph::op::Op + class NGRAPH_API Dequantize : public ngraph::op::Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Dequantize", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a Dequantize operation diff --git a/src/ngraph/op/divide.hpp b/src/ngraph/op/divide.hpp index d84d78733a5..306a4c709fc 100644 --- a/src/ngraph/op/divide.hpp +++ b/src/ngraph/op/divide.hpp @@ -25,14 +25,16 @@ namespace ngraph namespace v0 { /// \brief Elementwise division operation. - class Divide : public util::BinaryElementwiseArithmetic + class NGRAPH_API Divide : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Divide", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a division operation. - Divide() = default; + Divide() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs a division operation. /// /// \param arg0 Node that produces the first input tensor. @@ -69,14 +71,17 @@ namespace ngraph namespace v1 { /// \brief Elementwise division operation. - class Divide : public util::BinaryElementwiseArithmetic + class NGRAPH_API Divide : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Divide", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a division operation. - Divide() = default; + Divide() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + /// \brief Constructs a division operation. /// /// \param arg0 Node that produces the first input tensor. diff --git a/src/ngraph/op/dot.hpp b/src/ngraph/op/dot.hpp index c380ea56f8f..16b77cc0fce 100644 --- a/src/ngraph/op/dot.hpp +++ b/src/ngraph/op/dot.hpp @@ -24,68 +24,76 @@ namespace ngraph { namespace op { - /// \brief Generalized dot product operation, including scalar-tensor product, matrix-vector - /// product, and matrix multiplication. - class Dot : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Dot", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a dot product operation. - Dot() = default; - /// \brief Constructs a dot product operation. - /// - /// \param arg0 The node producing the first argument. - /// \param arg1 The node producing the second argument. - /// \param reduction_axes_count The number of axes to dot. - Dot(const Output& arg0, - const Output& arg1, - size_t reduction_axes_count, - bool has_reduction_axes_count = true); + /// \brief Generalized dot product operation, including scalar-tensor product, + /// matrix-vector + /// product, and matrix multiplication. + class NGRAPH_API Dot : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Dot", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a dot product operation. + Dot() = default; + /// \brief Constructs a dot product operation. + /// + /// \param arg0 The node producing the first argument. + /// \param arg1 The node producing the second argument. + /// \param reduction_axes_count The number of axes to dot. + Dot(const Output& arg0, + const Output& arg1, + size_t reduction_axes_count, + bool has_reduction_axes_count = true); - /// \brief Constructs a dot product operation with default dot-axis selection depending - /// on the inputs. - /// - /// If `arg0` or `arg1` is a scalar, there are no dot-axes. Else, there is one dot-axis. - /// - /// (Note that in particular, this results in scalar-tensor products where one or the - /// other argument is a scalar, a matrix-vector products where `arg0` is a matrix and - /// `arg1` is a vector, and a matrix multiplication where `arg0` and `arg1` are both - /// matrices.) - /// - /// \param arg0 The node producing the first argument. - /// \param arg1 The node producing the second argument. - Dot(const Output& arg0, const Output& arg1); + /// \brief Constructs a dot product operation with default dot-axis selection + /// depending + /// on the inputs. + /// + /// If `arg0` or `arg1` is a scalar, there are no dot-axes. Else, there is one + /// dot-axis. + /// + /// (Note that in particular, this results in scalar-tensor products where one or + /// the + /// other argument is a scalar, a matrix-vector products where `arg0` is a matrix + /// and + /// `arg1` is a vector, and a matrix multiplication where `arg0` and `arg1` are both + /// matrices.) + /// + /// \param arg0 The node producing the first argument. + /// \param arg1 The node producing the second argument. + Dot(const Output& arg0, const Output& arg1); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr get_default_value() const override; + virtual std::shared_ptr get_default_value() const override; - size_t get_reduction_axes_count() const { return m_reduction_axes_count; } - void set_reduction_axes_count(size_t reduction_axes_count) - { - m_reduction_axes_count = reduction_axes_count; - } - bool get_has_reduction_axes_count() const { return m_has_reduction_axes_count; } - void set_has_reduction_axes_count(bool has_reduction_axes_count) - { - m_has_reduction_axes_count = has_reduction_axes_count; - } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override - { - check_new_args_count(this, new_args); - return std::make_shared( - new_args.at(0), new_args.at(1), m_reduction_axes_count); - } + size_t get_reduction_axes_count() const { return m_reduction_axes_count; } + void set_reduction_axes_count(size_t reduction_axes_count) + { + m_reduction_axes_count = reduction_axes_count; + } + bool get_has_reduction_axes_count() const { return m_has_reduction_axes_count; } + void set_has_reduction_axes_count(bool has_reduction_axes_count) + { + m_has_reduction_axes_count = has_reduction_axes_count; + } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override + { + check_new_args_count(this, new_args); + return std::make_shared( + new_args.at(0), new_args.at(1), m_reduction_axes_count); + } - protected: - size_t m_reduction_axes_count; - bool m_has_reduction_axes_count; + protected: + size_t m_reduction_axes_count; + bool m_has_reduction_axes_count; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Dot; } } diff --git a/src/ngraph/op/embedding_lookup.hpp b/src/ngraph/op/embedding_lookup.hpp index 135bfb69e67..ec97312fa27 100644 --- a/src/ngraph/op/embedding_lookup.hpp +++ b/src/ngraph/op/embedding_lookup.hpp @@ -23,39 +23,43 @@ namespace ngraph { namespace op { - /// \brief Returns embeddings for given indices - class EmbeddingLookup : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"EmbeddingLookup", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a EmbeddingLookup operation. - EmbeddingLookup() = default; - /// \brief Constructs a EmbeddingLookup operation. - /// - /// EmbeddingLookup constructs an output tensor by replacing every index in a given - /// input tensor with a row (from the weights matrix) at that index - /// - /// \param data The input indices for tokens to be translated into embeddings - /// \param weights is a dense matrix [N,M] where each row 0..N - /// corresponds to an embedding (i.e. typically, a vector of real numbers) of length M - EmbeddingLookup(const Output& data, const Output& weights) - : Op({data, weights}) + /// \brief Returns embeddings for given indices + class NGRAPH_API EmbeddingLookup : public Op { - constructor_validate_and_infer_types(); - } + public: + static constexpr NodeTypeInfo type_info{"EmbeddingLookup", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a EmbeddingLookup operation. + EmbeddingLookup() = default; + /// \brief Constructs a EmbeddingLookup operation. + /// + /// EmbeddingLookup constructs an output tensor by replacing every index in a given + /// input tensor with a row (from the weights matrix) at that index + /// + /// \param data The input indices for tokens to be translated into embeddings + /// \param weights is a dense matrix [N,M] where each row 0..N + /// corresponds to an embedding (i.e. typically, a vector of real numbers) of length + /// M + EmbeddingLookup(const Output& data, const Output& weights) + : Op({data, weights}) + { + constructor_validate_and_infer_types(); + } - void validate_and_infer_types() override; + void validate_and_infer_types() override; - void generate_adjoints(autodiff::Adjoints& /* adjoints */, - const NodeVector& /* deltas */) override - { - throw ngraph_error("Not yet implemented"); - } + void generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) override + { + throw ngraph_error("Not yet implemented"); + } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::EmbeddingLookup; } } diff --git a/src/ngraph/op/equal.hpp b/src/ngraph/op/equal.hpp index e6c78025f42..c4a4432f0df 100644 --- a/src/ngraph/op/equal.hpp +++ b/src/ngraph/op/equal.hpp @@ -41,10 +41,9 @@ namespace ngraph /// | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | /// | \f$\texttt{bool}[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = 1\text{ if }\texttt{arg0}[i_1,\dots,i_n] = \texttt{arg1}[i_1,\dots,i_n]\text{, else } 0\f$ | // clang-format on - class Equal : public util::BinaryElementwiseComparison + class NGRAPH_API Equal : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Equal", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an equal operation. @@ -84,10 +83,9 @@ namespace ngraph /// | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | /// | \f$\texttt{bool}[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = 1\text{ if }\texttt{arg0}[i_1,\dots,i_n] = \texttt{arg1}[i_1,\dots,i_n]\text{, else } 0\f$ | // clang-format on - class Equal : public util::BinaryElementwiseComparison + class NGRAPH_API Equal : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Equal", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an equal operation. diff --git a/src/ngraph/op/erf.hpp b/src/ngraph/op/erf.hpp index 34e3804b8f5..0568ba7ffb1 100644 --- a/src/ngraph/op/erf.hpp +++ b/src/ngraph/op/erf.hpp @@ -22,17 +22,20 @@ namespace ngraph { namespace op { - class Erf : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Erf", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Erf() = default; - Erf(const Output& arg); + class NGRAPH_API Erf : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Erf", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Erf() = default; + Erf(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Erf; } } diff --git a/src/ngraph/op/exp.hpp b/src/ngraph/op/exp.hpp index 753e4169473..e2d8c882e47 100644 --- a/src/ngraph/op/exp.hpp +++ b/src/ngraph/op/exp.hpp @@ -22,25 +22,28 @@ namespace ngraph { namespace op { - /// \brief Elementwise natural exponential (exp) operation. - class Exp : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Exp", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an exponential operation. - Exp() = default; - /// \brief Constructs an exponential operation. - /// - /// \param arg Node that produces the input tensor. - Exp(const Output& arg); + /// \brief Elementwise natural exponential (exp) operation. + class NGRAPH_API Exp : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Exp", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an exponential operation. + Exp() = default; + /// \brief Constructs an exponential operation. + /// + /// \param arg Node that produces the input tensor. + Exp(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Exp; } } diff --git a/src/ngraph/op/experimental/batch_mat_mul.hpp b/src/ngraph/op/experimental/batch_mat_mul.hpp index 0b8bf3665b8..20c1c289cda 100644 --- a/src/ngraph/op/experimental/batch_mat_mul.hpp +++ b/src/ngraph/op/experimental/batch_mat_mul.hpp @@ -29,10 +29,9 @@ namespace ngraph /// For example, for `a` with shape `(batch_size, n, k)`, and `b` with /// shape `(batch_size, k, m)`, the result of BatchMatMul will have shape /// `(batch_size, n, m)`, and `BatchMatMul(a, b)[i] = Dot(a[i], b[i])`. - class BatchMatMul : public Op + class NGRAPH_API BatchMatMul : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"BatchMatMul", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } BatchMatMul() = default; diff --git a/src/ngraph/op/experimental/compiled_kernel.hpp b/src/ngraph/op/experimental/compiled_kernel.hpp index 0176b99a460..0865ff5a145 100644 --- a/src/ngraph/op/experimental/compiled_kernel.hpp +++ b/src/ngraph/op/experimental/compiled_kernel.hpp @@ -28,10 +28,9 @@ namespace ngraph /// This op can be used to delimit sub-graphs that with special compilation requirements /// within a function. For example, we currently use it to delimit sub-graphs that will be /// independently compiled and executed by MLIR backend. - class CompiledKernel : public ngraph::op::Op + class NGRAPH_API CompiledKernel : public ngraph::op::Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"CompiledKernel", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } CompiledKernel() = default; diff --git a/src/ngraph/op/experimental/dyn_broadcast.hpp b/src/ngraph/op/experimental/dyn_broadcast.hpp index 46212047146..622ce4c2e01 100644 --- a/src/ngraph/op/experimental/dyn_broadcast.hpp +++ b/src/ngraph/op/experimental/dyn_broadcast.hpp @@ -27,10 +27,9 @@ namespace ngraph /// input as needed along the new axes. /// /// This is basically the "dynamic shape" version of the static Broadcast op. - class DynBroadcast : public Op + class NGRAPH_API DynBroadcast : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"DynBroadcast", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } DynBroadcast() = default; diff --git a/src/ngraph/op/experimental/dyn_pad.hpp b/src/ngraph/op/experimental/dyn_pad.hpp index 2a9707bf13d..7d6cd8ed85b 100644 --- a/src/ngraph/op/experimental/dyn_pad.hpp +++ b/src/ngraph/op/experimental/dyn_pad.hpp @@ -24,10 +24,9 @@ namespace ngraph { /// \brief Generic padding operation which takes padding below and above as dynamic shapes. /// This is similar to existing Pad operation except padding values are dynamic. - class DynPad : public Op + class NGRAPH_API DynPad : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"DynPad", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } DynPad() = default; diff --git a/src/ngraph/op/experimental/dyn_replace_slice.hpp b/src/ngraph/op/experimental/dyn_replace_slice.hpp index 0cf4dc39b04..9d08689b452 100644 --- a/src/ngraph/op/experimental/dyn_replace_slice.hpp +++ b/src/ngraph/op/experimental/dyn_replace_slice.hpp @@ -25,10 +25,9 @@ namespace ngraph { /// \brief Takes a slice of an input tensor, i.e., the sub-tensor that resides within a /// bounding box, optionally with stride. - class DynReplaceSlice : public Op + class NGRAPH_API DynReplaceSlice : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"DynReplaceSlice", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } DynReplaceSlice() = default; diff --git a/src/ngraph/op/experimental/dyn_reshape.hpp b/src/ngraph/op/experimental/dyn_reshape.hpp index 80af3a5208a..5e9b7bbf142 100644 --- a/src/ngraph/op/experimental/dyn_reshape.hpp +++ b/src/ngraph/op/experimental/dyn_reshape.hpp @@ -30,10 +30,9 @@ namespace ngraph /// "Converts" an input tensor into a new shape with the same number of elements. /// This op does not touch the actual data. If needed, use Transpose for that purpose. /// - class DynReshape : public Op + class NGRAPH_API DynReshape : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"DynReshape", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } DynReshape() = default; diff --git a/src/ngraph/op/experimental/dyn_slice.hpp b/src/ngraph/op/experimental/dyn_slice.hpp index 3f978275dc2..afc36342ab0 100644 --- a/src/ngraph/op/experimental/dyn_slice.hpp +++ b/src/ngraph/op/experimental/dyn_slice.hpp @@ -25,10 +25,9 @@ namespace ngraph { /// \brief Takes a slice of an input tensor, i.e., the sub-tensor that resides within a /// bounding box, optionally with stride. - class DynSlice : public Op + class NGRAPH_API DynSlice : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"DynSlice", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } DynSlice() = default; diff --git a/src/ngraph/op/experimental/generate_mask.hpp b/src/ngraph/op/experimental/generate_mask.hpp index a7d5df87da9..28520e1d48d 100644 --- a/src/ngraph/op/experimental/generate_mask.hpp +++ b/src/ngraph/op/experimental/generate_mask.hpp @@ -28,10 +28,9 @@ namespace ngraph { /// \brief GenerateMask /// - class GenerateMask : public op::Op + class NGRAPH_API GenerateMask : public op::Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"GenerateMask", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a GenerateMask node with a given shape, seed, @@ -87,10 +86,9 @@ namespace ngraph { /// \brief GenerateMask /// - class GenerateMask : public op::Op + class NGRAPH_API GenerateMask : public op::Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"GenerateMask", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a GenerateMask node with a given shape, seed, diff --git a/src/ngraph/op/experimental/layers/ctc_greedy_decoder.hpp b/src/ngraph/op/experimental/layers/ctc_greedy_decoder.hpp index 5a07930059f..7d325947425 100644 --- a/src/ngraph/op/experimental/layers/ctc_greedy_decoder.hpp +++ b/src/ngraph/op/experimental/layers/ctc_greedy_decoder.hpp @@ -22,29 +22,33 @@ namespace ngraph { namespace op { - class CTCGreedyDecoder : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"CTCGreedyDecoder", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a CTCGreedyDecoder operation - /// - /// \param input Logits on which greedy decoding is performed - /// \param seq_len Sequence lengths - /// \param ctc_merge_repeated Whether to merge repeated labels - CTCGreedyDecoder(const Output& input, - const Output& seq_len, - const bool ctc_merge_repeated); + class NGRAPH_API CTCGreedyDecoder : public Op + { + public: + static constexpr NodeTypeInfo type_info{"CTCGreedyDecoder", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + CTCGreedyDecoder() = default; + /// \brief Constructs a CTCGreedyDecoder operation + /// + /// \param input Logits on which greedy decoding is performed + /// \param seq_len Sequence lengths + /// \param ctc_merge_repeated Whether to merge repeated labels + CTCGreedyDecoder(const Output& input, + const Output& seq_len, + const bool ctc_merge_repeated); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - bool get_ctc_merge_repeated() const { return m_ctc_merge_repeated; } - private: - bool m_ctc_merge_repeated; - }; + bool get_ctc_merge_repeated() const { return m_ctc_merge_repeated; } + private: + bool m_ctc_merge_repeated; + }; + } + using v0::CTCGreedyDecoder; } } diff --git a/src/ngraph/op/experimental/layers/detection_output.cpp b/src/ngraph/op/experimental/layers/detection_output.cpp index ddff252db14..0abd81a54d2 100644 --- a/src/ngraph/op/experimental/layers/detection_output.cpp +++ b/src/ngraph/op/experimental/layers/detection_output.cpp @@ -33,6 +33,16 @@ op::DetectionOutput::DetectionOutput(const Output& box_logits, constructor_validate_and_infer_types(); } +op::DetectionOutput::DetectionOutput(const Output& box_logits, + const Output& class_preds, + const Output& proposals, + const DetectionOutputAttrs& attrs) + : Op({box_logits, class_preds, proposals}) + , m_attrs(attrs) +{ + constructor_validate_and_infer_types(); +} + void op::DetectionOutput::validate_and_infer_types() { if (get_input_partial_shape(0).is_static()) @@ -50,6 +60,24 @@ void op::DetectionOutput::validate_and_infer_types() shared_ptr op::DetectionOutput::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared( - new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), new_args.at(4), m_attrs); + + auto num_args = new_args.size(); + + NODE_VALIDATION_CHECK( + this, num_args == 3 || num_args == 5, "DetectionOutput accepts 3 or 5 inputs."); + + if (num_args == 3) + { + return make_shared( + new_args.at(0), new_args.at(1), new_args.at(2), m_attrs); + } + else + { + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + new_args.at(3), + new_args.at(4), + m_attrs); + } } diff --git a/src/ngraph/op/experimental/layers/detection_output.hpp b/src/ngraph/op/experimental/layers/detection_output.hpp index 1c9c25f427c..fcf85559a4c 100644 --- a/src/ngraph/op/experimental/layers/detection_output.hpp +++ b/src/ngraph/op/experimental/layers/detection_output.hpp @@ -42,37 +42,52 @@ namespace ngraph float objectness_score = 0; } DetectionOutputAttrs; - /// \brief Layer which performs non-max suppression to - /// generate detection output using location and confidence predictions - class DetectionOutput : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"DetectionOutput", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a DetectionOutput operation - /// - /// \param box_logits Box logits - /// \param class_preds Class predictions - /// \param proposals Proposals - /// \param aux_class_preds Auxilary class predictions - /// \param aux_box_preds Auxilary box predictions - /// \param attrs Detection Output attributes - DetectionOutput(const Output& box_logits, - const Output& class_preds, - const Output& proposals, - const Output& aux_class_preds, - const Output& aux_box_preds, - const DetectionOutputAttrs& attrs); + /// \brief Layer which performs non-max suppression to + /// generate detection output using location and confidence predictions + class NGRAPH_API DetectionOutput : public Op + { + public: + static constexpr NodeTypeInfo type_info{"DetectionOutput", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + DetectionOutput() = default; + /// \brief Constructs a DetectionOutput operation + /// + /// \param box_logits Box logits + /// \param class_preds Class predictions + /// \param proposals Proposals + /// \param aux_class_preds Auxilary class predictions + /// \param aux_box_preds Auxilary box predictions + /// \param attrs Detection Output attributes + DetectionOutput(const Output& box_logits, + const Output& class_preds, + const Output& proposals, + const Output& aux_class_preds, + const Output& aux_box_preds, + const DetectionOutputAttrs& attrs); - void validate_and_infer_types() override; + /// \brief Constructs a DetectionOutput operation + /// + /// \param box_logits Box logits + /// \param class_preds Class predictions + /// \param proposals Proposals + /// \param attrs Detection Output attributes + DetectionOutput(const Output& box_logits, + const Output& class_preds, + const Output& proposals, + const DetectionOutputAttrs& attrs); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - const DetectionOutputAttrs& get_attrs() const { return m_attrs; } - private: - DetectionOutputAttrs m_attrs; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + const DetectionOutputAttrs& get_attrs() const { return m_attrs; } + private: + DetectionOutputAttrs m_attrs; + }; + } + using v0::DetectionOutput; } } diff --git a/src/ngraph/op/experimental/layers/interpolate.hpp b/src/ngraph/op/experimental/layers/interpolate.hpp index 9b5cfa2ed81..c01d7ee21b4 100644 --- a/src/ngraph/op/experimental/layers/interpolate.hpp +++ b/src/ngraph/op/experimental/layers/interpolate.hpp @@ -32,30 +32,34 @@ namespace ngraph std::vector pads_end; } InterpolateAttrs; - /// \brief Layer which performs bilinear interpolation - class Interpolate : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Interpolate", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a Interpolate operation - /// - /// \param image Input image - /// \param output_shape Output shape of spatial axes - /// \param attrs Interpolation attributes - Interpolate(const Output& image, - const Output& output_shape, - const InterpolateAttrs& attrs); + /// \brief Layer which performs bilinear interpolation + class NGRAPH_API Interpolate : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Interpolate", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Interpolate() = default; + /// \brief Constructs a Interpolate operation + /// + /// \param image Input image + /// \param output_shape Output shape of spatial axes + /// \param attrs Interpolation attributes + Interpolate(const Output& image, + const Output& output_shape, + const InterpolateAttrs& attrs); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const InterpolateAttrs& get_attrs() const { return m_attrs; } - private: - InterpolateAttrs m_attrs; - }; + const InterpolateAttrs& get_attrs() const { return m_attrs; } + private: + InterpolateAttrs m_attrs; + }; + } + using v0::Interpolate; } } diff --git a/src/ngraph/op/experimental/layers/prior_box.hpp b/src/ngraph/op/experimental/layers/prior_box.hpp index 9e98837e3e4..b963e1cf0ed 100644 --- a/src/ngraph/op/experimental/layers/prior_box.hpp +++ b/src/ngraph/op/experimental/layers/prior_box.hpp @@ -44,31 +44,35 @@ namespace ngraph bool scale_all_sizes = false; }; - /// \brief Layer which generates prior boxes of specified sizes - /// normalized to input image size - class PriorBox : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PriorBox", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a PriorBox operation - /// - /// \param layer_shape Shape of layer for which prior boxes are computed - /// \param image_shape Shape of image to which prior boxes are scaled - /// \param attrs PriorBox attributes - PriorBox(const Output& layer_shape, - const Output& image_shape, - const PriorBoxAttrs& attrs); + /// \brief Layer which generates prior boxes of specified sizes + /// normalized to input image size + class NGRAPH_API PriorBox : public Op + { + public: + static constexpr NodeTypeInfo type_info{"PriorBox", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PriorBox() = default; + /// \brief Constructs a PriorBox operation + /// + /// \param layer_shape Shape of layer for which prior boxes are computed + /// \param image_shape Shape of image to which prior boxes are scaled + /// \param attrs PriorBox attributes + PriorBox(const Output& layer_shape, + const Output& image_shape, + const PriorBoxAttrs& attrs); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const PriorBoxAttrs& get_attrs() const { return m_attrs; } - private: - PriorBoxAttrs m_attrs; - }; + const PriorBoxAttrs& get_attrs() const { return m_attrs; } + private: + PriorBoxAttrs m_attrs; + }; + } + using v0::PriorBox; } } diff --git a/src/ngraph/op/experimental/layers/prior_box_clustered.hpp b/src/ngraph/op/experimental/layers/prior_box_clustered.hpp index 06852ad326d..c891763b46a 100644 --- a/src/ngraph/op/experimental/layers/prior_box_clustered.hpp +++ b/src/ngraph/op/experimental/layers/prior_box_clustered.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace op { - struct PriorBoxClusteredAttrs + struct NGRAPH_API PriorBoxClusteredAttrs { // widths Desired widths of prior boxes // heights Desired heights of prior boxes @@ -40,31 +40,35 @@ namespace ngraph std::vector variances; }; - /// \brief Layer which generates prior boxes of specified sizes - /// normalized to input image size - class PriorBoxClustered : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PriorBoxClustered", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a PriorBoxClustered operation - /// - /// \param layer_shape Shape of layer for which prior boxes are computed - /// \param image_shape Shape of image to which prior boxes are scaled - /// \param attrs PriorBoxClustered attributes - PriorBoxClustered(const Output& layer_shape, - const Output& image_shape, - const PriorBoxClusteredAttrs& attrs); + /// \brief Layer which generates prior boxes of specified sizes + /// normalized to input image size + class NGRAPH_API PriorBoxClustered : public Op + { + public: + static constexpr NodeTypeInfo type_info{"PriorBoxClustered", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PriorBoxClustered() = default; + /// \brief Constructs a PriorBoxClustered operation + /// + /// \param layer_shape Shape of layer for which prior boxes are computed + /// \param image_shape Shape of image to which prior boxes are scaled + /// \param attrs PriorBoxClustered attributes + PriorBoxClustered(const Output& layer_shape, + const Output& image_shape, + const PriorBoxClusteredAttrs& attrs); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const PriorBoxClusteredAttrs& get_attrs() const { return m_attrs; } - private: - PriorBoxClusteredAttrs m_attrs; - }; + const PriorBoxClusteredAttrs& get_attrs() const { return m_attrs; } + private: + PriorBoxClusteredAttrs m_attrs; + }; + } + using v0::PriorBoxClustered; } } diff --git a/src/ngraph/op/experimental/layers/proposal.hpp b/src/ngraph/op/experimental/layers/proposal.hpp index 220811dce80..fbd205663ee 100644 --- a/src/ngraph/op/experimental/layers/proposal.hpp +++ b/src/ngraph/op/experimental/layers/proposal.hpp @@ -54,31 +54,35 @@ namespace ngraph std::string framework; }; - class Proposal : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Proposal", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a Proposal operation - /// - /// \param class_probs Class probability scores - /// \param class_logits Class prediction logits - /// \param image_shape Shape of image - /// \param attrs Proposal op attributes - Proposal(const Output& class_probs, - const Output& class_logits, - const Output& image_shape, - const ProposalAttrs& attrs); + class NGRAPH_API Proposal : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Proposal", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Proposal() = default; + /// \brief Constructs a Proposal operation + /// + /// \param class_probs Class probability scores + /// \param class_logits Class prediction logits + /// \param image_shape Shape of image + /// \param attrs Proposal op attributes + Proposal(const Output& class_probs, + const Output& class_logits, + const Output& image_shape, + const ProposalAttrs& attrs); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const ProposalAttrs& get_attrs() const { return m_attrs; } - private: - ProposalAttrs m_attrs; - }; + const ProposalAttrs& get_attrs() const { return m_attrs; } + private: + ProposalAttrs m_attrs; + }; + } + using v0::Proposal; } } diff --git a/src/ngraph/op/experimental/layers/psroi_pooling.hpp b/src/ngraph/op/experimental/layers/psroi_pooling.hpp index 35654c57500..f447465e790 100644 --- a/src/ngraph/op/experimental/layers/psroi_pooling.hpp +++ b/src/ngraph/op/experimental/layers/psroi_pooling.hpp @@ -22,49 +22,55 @@ namespace ngraph { namespace op { - class PSROIPooling : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PSROIPooling", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a PSROIPooling operation - /// - /// \param input Input feature map {N, C, ...} - /// \param coords Coordinates of bounding boxes - /// \param output_dim Output channel number - /// \param group_size Number of groups to encode position-sensitive scores - /// \param spatial_scale Ratio of input feature map over input image size - /// \param spatial_bins_x Numbers of bins to divide the input feature maps over width - /// \param spatial_bins_y Numbers of bins to divide the input feature maps over height - /// \param mode Mode of pooling - Avg or Bilinear - PSROIPooling(const Output& input, - const Output& coords, - const size_t output_dim, - const size_t group_size, - const float spatial_scale, - int spatial_bins_x, - int spatial_bins_y, - const std::string& mode); + class NGRAPH_API PSROIPooling : public Op + { + public: + static constexpr NodeTypeInfo type_info{"PSROIPooling", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PSROIPooling() = default; + /// \brief Constructs a PSROIPooling operation + /// + /// \param input Input feature map {N, C, ...} + /// \param coords Coordinates of bounding boxes + /// \param output_dim Output channel number + /// \param group_size Number of groups to encode position-sensitive scores + /// \param spatial_scale Ratio of input feature map over input image size + /// \param spatial_bins_x Numbers of bins to divide the input feature maps over + /// width + /// \param spatial_bins_y Numbers of bins to divide the input feature maps over + /// height + /// \param mode Mode of pooling - Avg or Bilinear + PSROIPooling(const Output& input, + const Output& coords, + const size_t output_dim, + const size_t group_size, + const float spatial_scale, + int spatial_bins_x, + int spatial_bins_y, + const std::string& mode); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - size_t get_output_dim() const { return m_output_dim; } - size_t get_group_size() const { return m_group_size; } - float get_spatial_scale() const { return m_spatial_scale; } - int get_spatial_bins_x() const { return m_spatial_bins_x; } - int get_spatial_bins_y() const { return m_spatial_bins_y; } - const std::string& get_mode() const { return m_mode; } - private: - size_t m_output_dim; - size_t m_group_size; - float m_spatial_scale; - int m_spatial_bins_x; - int m_spatial_bins_y; - std::string m_mode; - }; + size_t get_output_dim() const { return m_output_dim; } + size_t get_group_size() const { return m_group_size; } + float get_spatial_scale() const { return m_spatial_scale; } + int get_spatial_bins_x() const { return m_spatial_bins_x; } + int get_spatial_bins_y() const { return m_spatial_bins_y; } + const std::string& get_mode() const { return m_mode; } + private: + size_t m_output_dim; + size_t m_group_size; + float m_spatial_scale; + int m_spatial_bins_x; + int m_spatial_bins_y; + std::string m_mode; + }; + } + using v0::PSROIPooling; } } diff --git a/src/ngraph/op/experimental/layers/region_yolo.hpp b/src/ngraph/op/experimental/layers/region_yolo.hpp index 0557783b9e0..f43270db2fc 100644 --- a/src/ngraph/op/experimental/layers/region_yolo.hpp +++ b/src/ngraph/op/experimental/layers/region_yolo.hpp @@ -22,58 +22,63 @@ namespace ngraph { namespace op { - class RegionYolo : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"RegionYolo", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// - /// \brief Constructs a RegionYolo operation - /// - /// \param[in] input Input - /// \param[in] num_coords Number of coordinates for each region - /// \param[in] num_classes Number of classes for each region - /// \param[in] num_regions Number of regions - /// \param[in] do_softmax Compute softmax - /// \param[in] mask Mask - /// \param[in] axis Axis to begin softmax on - /// \param[in] end_axis Axis to end softmax on - /// \param[in] anchors A flattened list of pairs `[width, height]` that describes - /// prior box sizes. - /// - RegionYolo(const Output& input, - const size_t num_coords, - const size_t num_classes, - const size_t num_regions, - const bool do_softmax, - const std::vector& mask, - const int axis, - const int end_axis, - const std::vector& anchors = std::vector{}); + class NGRAPH_API RegionYolo : public Op + { + public: + static constexpr NodeTypeInfo type_info{"RegionYolo", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + RegionYolo() = default; + /// + /// \brief Constructs a RegionYolo operation + /// + /// \param[in] input Input + /// \param[in] num_coords Number of coordinates for each region + /// \param[in] num_classes Number of classes for each region + /// \param[in] num_regions Number of regions + /// \param[in] do_softmax Compute softmax + /// \param[in] mask Mask + /// \param[in] axis Axis to begin softmax on + /// \param[in] end_axis Axis to end softmax on + /// \param[in] anchors A flattened list of pairs `[width, height]` that + /// describes + /// prior box sizes. + /// + RegionYolo(const Output& input, + const size_t num_coords, + const size_t num_classes, + const size_t num_regions, + const bool do_softmax, + const std::vector& mask, + const int axis, + const int end_axis, + const std::vector& anchors = std::vector{}); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - size_t get_num_coords() const { return m_num_coords; } - size_t get_num_classes() const { return m_num_classes; } - size_t get_num_regions() const { return m_num_regions; } - bool get_do_softmax() const { return m_do_softmax; } - const std::vector& get_mask() const { return m_mask; } - const std::vector& get_anchors() const { return m_anchors; } - int get_axis() const { return m_axis; } - int get_end_axis() const { return m_end_axis; } - private: - size_t m_num_coords; - size_t m_num_classes; - size_t m_num_regions; - bool m_do_softmax; - std::vector m_mask; - std::vector m_anchors{}; - int m_axis; - int m_end_axis; - }; + size_t get_num_coords() const { return m_num_coords; } + size_t get_num_classes() const { return m_num_classes; } + size_t get_num_regions() const { return m_num_regions; } + bool get_do_softmax() const { return m_do_softmax; } + const std::vector& get_mask() const { return m_mask; } + const std::vector& get_anchors() const { return m_anchors; } + int get_axis() const { return m_axis; } + int get_end_axis() const { return m_end_axis; } + private: + size_t m_num_coords; + size_t m_num_classes; + size_t m_num_regions; + bool m_do_softmax; + std::vector m_mask; + std::vector m_anchors{}; + int m_axis; + int m_end_axis; + }; + } + using v0::RegionYolo; } } diff --git a/src/ngraph/op/experimental/layers/reorg_yolo.hpp b/src/ngraph/op/experimental/layers/reorg_yolo.hpp index 242e91def91..fc2c6fc833a 100644 --- a/src/ngraph/op/experimental/layers/reorg_yolo.hpp +++ b/src/ngraph/op/experimental/layers/reorg_yolo.hpp @@ -22,26 +22,30 @@ namespace ngraph { namespace op { - class ReorgYolo : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ReorgYolo", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ReorgYolo operation - /// - /// \param input Input - /// \param strides Stride to reorganize input by - ReorgYolo(const Output& input, const Strides& strides); + class NGRAPH_API ReorgYolo : public Op + { + public: + static constexpr NodeTypeInfo type_info{"ReorgYolo", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReorgYolo() = default; + /// \brief Constructs a ReorgYolo operation + /// + /// \param input Input + /// \param strides Stride to reorganize input by + ReorgYolo(const Output& input, const Strides& strides); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const Strides get_strides() const { return m_strides; } - private: - Strides m_strides; - }; + const Strides get_strides() const { return m_strides; } + private: + Strides m_strides; + }; + } + using v0::ReorgYolo; } } diff --git a/src/ngraph/op/experimental/layers/roi_pooling.hpp b/src/ngraph/op/experimental/layers/roi_pooling.hpp index a482ed38c42..c50b9a6260a 100644 --- a/src/ngraph/op/experimental/layers/roi_pooling.hpp +++ b/src/ngraph/op/experimental/layers/roi_pooling.hpp @@ -22,37 +22,41 @@ namespace ngraph { namespace op { - class ROIPooling : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ROIPooling", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ROIPooling operation - /// - /// \param input Input feature map {N, C, ...} - /// \param coords Coordinates of bounding boxes - /// \param output_size Height/Width of ROI output features - /// \param spatial_scale Ratio of input feature map over input image size - /// \param method Method of pooling - Max or Bilinear - ROIPooling(const Output& input, - const Output& coords, - const Shape& output_size, - const float spatial_scale, - const std::string& method); + class NGRAPH_API ROIPooling : public Op + { + public: + static constexpr NodeTypeInfo type_info{"ROIPooling", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ROIPooling() = default; + /// \brief Constructs a ROIPooling operation + /// + /// \param input Input feature map {N, C, ...} + /// \param coords Coordinates of bounding boxes + /// \param output_size Height/Width of ROI output features + /// \param spatial_scale Ratio of input feature map over input image size + /// \param method Method of pooling - Max or Bilinear + ROIPooling(const Output& input, + const Output& coords, + const Shape& output_size, + const float spatial_scale, + const std::string& method); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const Shape& get_output_size() const { return m_output_size; } - float get_spatial_scale() const { return m_spatial_scale; } - const std::string& get_method() const { return m_method; } - private: - Shape m_output_size; - float m_spatial_scale; - std::string m_method; - }; + const Shape& get_output_size() const { return m_output_size; } + float get_spatial_scale() const { return m_spatial_scale; } + const std::string& get_method() const { return m_method; } + private: + Shape m_output_size; + float m_spatial_scale; + std::string m_method; + }; + } + using v0::ROIPooling; } } diff --git a/src/ngraph/op/experimental/quantized_conv_bias.hpp b/src/ngraph/op/experimental/quantized_conv_bias.hpp index b044fac0420..de872008cb1 100644 --- a/src/ngraph/op/experimental/quantized_conv_bias.hpp +++ b/src/ngraph/op/experimental/quantized_conv_bias.hpp @@ -24,10 +24,9 @@ namespace ngraph namespace op { /// \brief Convolution + bias forward prop for batched convolution operation. - class QuantizedConvolutionBias : public Op + class NGRAPH_API QuantizedConvolutionBias : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"QuantizedConvolutionBias", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } QuantizedConvolutionBias() = default; @@ -63,12 +62,12 @@ namespace ngraph bool m_with_relu; }; - class QuantizedConvolutionBiasAdd : public Op + class NGRAPH_API QuantizedConvolutionBiasAdd : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"QuantizedConvolutionBiasAdd", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + QuantizedConvolutionBiasAdd() = default; QuantizedConvolutionBiasAdd(const Output& data_batch, const Output& filters, const Output& bias, @@ -103,12 +102,12 @@ namespace ngraph bool m_with_relu; }; - class QuantizedConvolutionBiasSignedAdd : public Op + class NGRAPH_API QuantizedConvolutionBiasSignedAdd : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"QuantizedConvolutionBiasSignedAdd", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + QuantizedConvolutionBiasSignedAdd() = default; QuantizedConvolutionBiasSignedAdd(const Output& data_batch, const Output& filters, const Output& bias, diff --git a/src/ngraph/op/experimental/quantized_conv_relu.hpp b/src/ngraph/op/experimental/quantized_conv_relu.hpp index 2d5150fb312..0dd9dfbbfed 100644 --- a/src/ngraph/op/experimental/quantized_conv_relu.hpp +++ b/src/ngraph/op/experimental/quantized_conv_relu.hpp @@ -24,10 +24,9 @@ namespace ngraph namespace op { /// \brief Relu(Convolution) forward prop for batched convolution operation. - class QuantizedConvolutionRelu : public Op + class NGRAPH_API QuantizedConvolutionRelu : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"QuantizedConvolutionRelu", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } QuantizedConvolutionRelu() = default; diff --git a/src/ngraph/op/experimental/quantized_dot_bias.hpp b/src/ngraph/op/experimental/quantized_dot_bias.hpp index 3b923afa0ba..6d650fcd024 100644 --- a/src/ngraph/op/experimental/quantized_dot_bias.hpp +++ b/src/ngraph/op/experimental/quantized_dot_bias.hpp @@ -24,10 +24,9 @@ namespace ngraph { namespace op { - class QuantizedDotBias : public Op + class NGRAPH_API QuantizedDotBias : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"QuantizedDotBias", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } QuantizedDotBias() = default; diff --git a/src/ngraph/op/experimental/random_uniform.hpp b/src/ngraph/op/experimental/random_uniform.hpp index 01a98e68803..1aaf4fe6164 100644 --- a/src/ngraph/op/experimental/random_uniform.hpp +++ b/src/ngraph/op/experimental/random_uniform.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace op { /// \brief Generates a tensor populated with random values of a uniform distribution. - class RandomUniform : public op::Op + class NGRAPH_API RandomUniform : public op::Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"RandomUniform", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs an uninitialized RandomUniform node. diff --git a/src/ngraph/op/experimental/range.cpp b/src/ngraph/op/experimental/range.cpp index 06e130cc3fe..dec3bb18aa1 100644 --- a/src/ngraph/op/experimental/range.cpp +++ b/src/ngraph/op/experimental/range.cpp @@ -230,6 +230,7 @@ void op::Range::validate_and_infer_types() case element::Type_t::u32: result_shape = infer_output_shape(this, result_et); break; case element::Type_t::u64: result_shape = infer_output_shape(this, result_et); break; case element::Type_t::dynamic: result_shape = PartialShape::dynamic(1); break; + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::boolean: NODE_VALIDATION_CHECK( diff --git a/src/ngraph/op/experimental/range.hpp b/src/ngraph/op/experimental/range.hpp index 4d289446bfe..1844c24e865 100644 --- a/src/ngraph/op/experimental/range.hpp +++ b/src/ngraph/op/experimental/range.hpp @@ -23,30 +23,35 @@ namespace ngraph { namespace op { - /// \brief Range operation, analogous to `range()` in Python. - class Range : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Range", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an unitialized range operation. - Range() = default; + /// \brief Range operation, analogous to `range()` in Python. + class NGRAPH_API Range : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Range", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an unitialized range operation. + Range() = default; - /// \brief Constructs a range operation. - /// - /// \param start The tensor producing the start value. Must be a scalar of integer - /// element type, and same element type as `stop` and `step`. - /// \param stop The tensor producing the stop value. Must be a scalar of integer - /// element type, and same element type as `start` and `step`. - /// \param step The tensor producing the step value. Must be a scalar of integer - /// element type, and same element type as `start` and `stop`. - Range(const Output& start, const Output& stop, const Output& step); + /// \brief Constructs a range operation. + /// + /// \param start The tensor producing the start value. Must be a scalar of integer + /// element type, and same element type as `stop` and `step`. + /// \param stop The tensor producing the stop value. Must be a scalar of integer + /// element type, and same element type as `start` and `step`. + /// \param step The tensor producing the step value. Must be a scalar of integer + /// element type, and same element type as `start` and `stop`. + Range(const Output& start, + const Output& stop, + const Output& step); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Range; } } diff --git a/src/ngraph/op/experimental/shape_of.hpp b/src/ngraph/op/experimental/shape_of.hpp index f1b2da18588..2a105140be8 100644 --- a/src/ngraph/op/experimental/shape_of.hpp +++ b/src/ngraph/op/experimental/shape_of.hpp @@ -22,21 +22,24 @@ namespace ngraph { namespace op { - /// \brief Operation that returns the shape of its input argument as a tensor. - class ShapeOf : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ShapeOf", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ShapeOf() = default; - /// \brief Constructs a shape-of operation. - ShapeOf(const Output& arg); + /// \brief Operation that returns the shape of its input argument as a tensor. + class NGRAPH_API ShapeOf : public Op + { + public: + static constexpr NodeTypeInfo type_info{"ShapeOf", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ShapeOf() = default; + /// \brief Constructs a shape-of operation. + ShapeOf(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; - }; + void validate_and_infer_types() override; + }; + } + using v0::ShapeOf; } } diff --git a/src/ngraph/op/experimental/tile.hpp b/src/ngraph/op/experimental/tile.hpp index 7f5d0b0cdf1..0530b93efd8 100644 --- a/src/ngraph/op/experimental/tile.hpp +++ b/src/ngraph/op/experimental/tile.hpp @@ -22,29 +22,32 @@ namespace ngraph { namespace op { - /// \brief Dynamic Tiling operation which repeats a tensor multiple times - /// along each dimension - class Tile : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Tile", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Tile() = default; - /// \brief Perform dynamic padding of a tensor - /// - /// \param data The node producing input tensor to be padded. - /// \param repeats The node producing the per-dimension replication factor - Tile(const Output& data, const Output& repeats); + /// \brief Dynamic Tiling operation which repeats a tensor multiple times + /// along each dimension + class NGRAPH_API Tile : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Tile", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Tile() = default; + /// \brief Perform dynamic padding of a tensor + /// + /// \param data The node producing input tensor to be padded. + /// \param repeats The node producing the per-dimension replication factor + Tile(const Output& data, const Output& repeats); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Tile; } } diff --git a/src/ngraph/op/experimental/transpose.hpp b/src/ngraph/op/experimental/transpose.hpp index 6b38d93ddb6..60bdd306e5b 100644 --- a/src/ngraph/op/experimental/transpose.hpp +++ b/src/ngraph/op/experimental/transpose.hpp @@ -24,31 +24,34 @@ namespace ngraph { namespace op { - /// \brief Tensor transpose operation. - class Transpose : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Transpose", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Transpose() = default; - /// \brief Constructs a transpose operation. - /// - /// \param arg Node producing the tensor to be transposed. - /// \param input_order Node producing the permutation to apply to the axes of the - /// input shape. Must be a vector of element type element::i64, - /// with shape [n], where n is the rank of arg. The tensor's - /// value must contain every integer in the range [0,n-1]. - Transpose(const Output& arg, const Output& input_order); + /// \brief Tensor transpose operation. + class NGRAPH_API Transpose : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Transpose", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Transpose() = default; + /// \brief Constructs a transpose operation. + /// + /// \param arg Node producing the tensor to be transposed. + /// \param input_order Node producing the permutation to apply to the axes of the + /// input shape. Must be a vector of element type element::i64, + /// with shape [n], where n is the rank of arg. The tensor's + /// value must contain every integer in the range [0,n-1]. + Transpose(const Output& arg, const Output& input_order); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Transpose; } } diff --git a/src/ngraph/op/floor.hpp b/src/ngraph/op/floor.hpp index 9e8dc64bf2d..b6073e66f0e 100644 --- a/src/ngraph/op/floor.hpp +++ b/src/ngraph/op/floor.hpp @@ -22,22 +22,25 @@ namespace ngraph { namespace op { - /// \brief Elementwise floor operation. - class Floor : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Floor", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a floor operation. - Floor() = default; - /// \brief Constructs a floor operation. - /// - /// \param arg Node that produces the input tensor. - Floor(const Output& arg); + /// \brief Elementwise floor operation. + class NGRAPH_API Floor : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Floor", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a floor operation. + Floor() = default; + /// \brief Constructs a floor operation. + /// + /// \param arg Node that produces the input tensor. + Floor(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Floor; } } diff --git a/src/ngraph/op/floor_mod.cpp b/src/ngraph/op/floor_mod.cpp new file mode 100644 index 00000000000..8e9ff5c1625 --- /dev/null +++ b/src/ngraph/op/floor_mod.cpp @@ -0,0 +1,36 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/floor_mod.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::FloorMod::type_info; + +op::v1::FloorMod::FloorMod(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast) + : BinaryElementwiseArithmetic(arg0, arg1, auto_broadcast) +{ + constructor_validate_and_infer_types(); +} + +shared_ptr op::v1::FloorMod::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); +} diff --git a/src/ngraph/op/floor_mod.hpp b/src/ngraph/op/floor_mod.hpp new file mode 100644 index 00000000000..5bf73fc1e2f --- /dev/null +++ b/src/ngraph/op/floor_mod.hpp @@ -0,0 +1,60 @@ +//***************************************************************************** +// Copyright 2017-2019 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 + +#include "ngraph/op/util/binary_elementwise_arithmetic.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Elementwise FloorMod operation. + /// + class NGRAPH_API FloorMod : public util::BinaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"FloorMod", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an uninitialized addition operation + FloorMod() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY){}; + + /// \brief Constructs an Floor Mod operation. + /// + /// \param arg0 Output that produces the first input tensor.
    + /// `[d0, ...]` + /// \param arg1 Output that produces the second input tensor.
    + /// `[d0, ...]` + /// \param auto_broadcast Auto broadcast specification + /// + /// Output `[d0, ...]` + /// + FloorMod(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast = AutoBroadcastType::NUMPY); + + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + }; + } // namespace v1 + + using v1::FloorMod; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.cpp b/src/ngraph/op/fused/batch_mat_mul_transpose.cpp similarity index 67% rename from src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.cpp rename to src/ngraph/op/fused/batch_mat_mul_transpose.cpp index 7b22c3bbcb0..ef65214587b 100644 --- a/src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.cpp +++ b/src/ngraph/op/fused/batch_mat_mul_transpose.cpp @@ -17,9 +17,12 @@ #include "batch_mat_mul_transpose.hpp" #include "ngraph/dimension.hpp" #include "ngraph/log.hpp" +#include "ngraph/op/concat.hpp" +#include "ngraph/op/dot.hpp" #include "ngraph/op/experimental/batch_mat_mul.hpp" #include "ngraph/op/experimental/dyn_reshape.hpp" #include "ngraph/op/reshape.hpp" +#include "ngraph/op/slice.hpp" #include "ngraph/util.hpp" using namespace std; @@ -31,13 +34,68 @@ op::BatchMatMulTranspose::BatchMatMulTranspose(const Output& arg0, const Output& arg1, bool transpose_arg0, bool transpose_arg1) - : Op({arg0, arg1}) + : FusedOp({arg0, arg1}) , m_transpose_arg0(transpose_arg0) , m_transpose_arg1(transpose_arg1) { constructor_validate_and_infer_types(); } +NodeVector op::BatchMatMulTranspose::decompose_op() const +{ + const PartialShape& arg0_pshape = get_input_partial_shape(0); + const PartialShape& arg1_pshape = get_input_partial_shape(1); + NODE_VALIDATION_CHECK(this, + !arg0_pshape.is_dynamic(), + "Arg0 needs to have static shape to decompose, but got shape ", + arg0_pshape); + + NODE_VALIDATION_CHECK(this, + !arg1_pshape.is_dynamic(), + "Arg1 needs to have static shape to decompose, but got shape ", + arg1_pshape); + + const auto arg0_shape = get_input_shape(0); + const auto num_batches = arg0_shape.at(0); + + OutputVector dot_inputs; + + for (size_t i = 0; i < 2; i++) + { + const auto arg_shape = get_input_shape(i); + const auto arg_shape_res = Shape{arg_shape.at(1), arg_shape.at(2)}; + const auto arg_shape_res_trans = Shape{arg_shape.at(2), arg_shape.at(1)}; + + const bool transpose = i == 0 ? m_transpose_arg0 : m_transpose_arg1; + for (size_t j = 0; j < num_batches; j++) + { + auto slice = + std::make_shared(input_value(i), + Coordinate{j, 0, 0}, + Coordinate{j + 1, arg_shape.at(1), arg_shape.at(2)}); + auto reshape_slice = + std::make_shared(slice, AxisVector{0, 1, 2}, arg_shape_res); + + dot_inputs.push_back(transpose ? std::make_shared(reshape_slice, + AxisVector{1, 0}, + arg_shape_res_trans) + : reshape_slice); + } + } + NodeVector concat_inputs; + for (size_t i = 0; i < num_batches; i++) + { + auto dot = std::make_shared(dot_inputs[i], dot_inputs[i + num_batches]); + auto dot_shape = dot->get_shape(); + auto dot_reshape = std::make_shared( + dot, AxisVector{0, 1}, Shape{1, dot_shape.at(0), dot_shape.at(1)}); + concat_inputs.push_back(dot_reshape); + } + + auto concat_result = std::make_shared(concat_inputs, 0); + return {concat_result}; +} + shared_ptr op::BatchMatMulTranspose::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); diff --git a/src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp b/src/ngraph/op/fused/batch_mat_mul_transpose.hpp similarity index 91% rename from src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp rename to src/ngraph/op/fused/batch_mat_mul_transpose.hpp index dd242441c7e..da54638811b 100644 --- a/src/ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp +++ b/src/ngraph/op/fused/batch_mat_mul_transpose.hpp @@ -17,7 +17,8 @@ #pragma once #include "ngraph/op/op.hpp" -#include "ngraph/runtime/cpu/cpu_backend_visibility.h" +#include "ngraph/op/util/attr_types.hpp" +#include "ngraph/op/util/fused_op.hpp" namespace ngraph { @@ -32,12 +33,12 @@ namespace ngraph /// For example, for `a` with shape `(batch_size, n, k)`, and `b` with /// shape `(batch_size, k, m)`, the result of BatchMatMul will have shape /// `(batch_size, n, m)`, and `BatchMatMulTranspose(a, b)[i] = Dot(a[i], b[i])`. - class BatchMatMulTranspose : public Op + class NGRAPH_API BatchMatMulTranspose : public ngraph::op::util::FusedOp { public: - CPU_BACKEND_API static constexpr NodeTypeInfo type_info{"BatchMatMulTranspose", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + BatchMatMulTranspose() = default; /// \brief Constructs a batch of matmul product operation. /// /// \param arg0 The node producing the first argument. @@ -56,6 +57,8 @@ namespace ngraph virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + virtual NodeVector decompose_op() const override; + protected: virtual void generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) override; diff --git a/src/ngraph/op/fused/clamp.hpp b/src/ngraph/op/fused/clamp.hpp index e650a0943a6..b06164520de 100644 --- a/src/ngraph/op/fused/clamp.hpp +++ b/src/ngraph/op/fused/clamp.hpp @@ -24,36 +24,40 @@ namespace ngraph { namespace op { - /// \brief Performs a clipping operation on all elements of the input node - /// - /// All input values that are outside of the range are set to 'min' or 'max' - /// depending on which side of the range they are. The values that fall into - /// this range remain unchanged. - class Clamp : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Clamp", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a Clamp node. + /// \brief Performs a clipping operation on all elements of the input node /// - /// \param data - Node producing the input tensor - /// \param min - the lower bound of the range - /// \param max - the upper bound of the range - Clamp(const Output& data, const double min, const double max); + /// All input values that are outside of the range are set to 'min' or 'max' + /// depending on which side of the range they are. The values that fall into + /// this range remain unchanged. + class NGRAPH_API Clamp : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Clamp", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Clamp() = default; + /// \brief Constructs a Clamp node. + /// + /// \param data - Node producing the input tensor + /// \param min - the lower bound of the range + /// \param max - the upper bound of the range + Clamp(const Output& data, const double min, const double max); - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - double get_min() const { return m_min; } - double get_max() const { return m_max; } - private: - const double m_min; - const double m_max; - }; + double get_min() const { return m_min; } + double get_max() const { return m_max; } + private: + double m_min; + double m_max; + }; + } + using v0::Clamp; } } diff --git a/src/ngraph/op/fused/conv_fused.hpp b/src/ngraph/op/fused/conv_fused.hpp index af5aef60ed4..75e931d22e7 100644 --- a/src/ngraph/op/fused/conv_fused.hpp +++ b/src/ngraph/op/fused/conv_fused.hpp @@ -24,200 +24,215 @@ namespace ngraph { namespace op { - /// \brief Convolution + bias forward prop for batched convolution operation. - class ConvolutionBias : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ConvolutionBias", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ConvolutionBias() = default; - ConvolutionBias(const std::shared_ptr& conv, - const Output& bias, - const bool with_relu = false); - - ConvolutionBias(const Output& data_batch, - const Output& filters, - const Output& bias, - const Strides& window_movement_strides, - const Strides& window_dilation_strides, - const CoordinateDiff& padding_below, - const CoordinateDiff& padding_above, - const Strides& data_dilation_strides, - const bool with_relu = false); - - ConvolutionBias(const Output& data_batch, - const Output& filters, - const Output& bias); - - const Strides& get_window_movement_strides() const { return m_window_movement_strides; } - const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; } - const CoordinateDiff& get_padding_below() const { return m_padding_below; } - const CoordinateDiff& get_padding_above() const { return m_padding_above; } - const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } - Output get_bias() { return input_value(2); } - Output get_filters() { return input_value(1); } - Output get_data_batch() { return input_value(0); } - bool with_relu() const { return m_with_relu; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual NodeVector decompose_op() const override; - - virtual void validate_and_infer_types() override; - - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - - protected: - Strides m_window_movement_strides; - Strides m_window_dilation_strides; - CoordinateDiff m_padding_below; - CoordinateDiff m_padding_above; - Strides m_data_dilation_strides; - bool m_with_relu; - }; - - /// \brief Filters and bias backprop for batched convolution operation. Data backprop is - /// the same as regular convolution backprop for data. - class ConvolutionBiasBackpropFiltersBias : public ngraph::op::util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ConvolutionBiasBackpropFiltersBias", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ConvolutionBiasBackpropFiltersBias() = default; - ConvolutionBiasBackpropFiltersBias(const Output& data_batch, - const Shape& filters_shape, - const Shape& bias_shape, - const Output& output_delta, - const Strides& window_movement_strides_forward, - const Strides& window_dilation_strides_forward, - const CoordinateDiff& padding_below_forward, - const CoordinateDiff& padding_above_forward, - const Strides& data_dilation_strides_forward); - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - /// \return The filters tensor shape. - const Shape& get_filters_shape() const { return m_filters_shape; } - /// \return The bias tensor shape. - const Shape& get_bias_shape() const { return m_bias_shape; } - /// \return The window movement strides from the forward prop. - const Strides& get_window_movement_strides_forward() const - { - return m_window_movement_strides_forward; - } - /// \return The window dilation strides from the forward prop. - const Strides& get_window_dilation_strides_forward() const - { - return m_window_dilation_strides_forward; - } - /// \return The padding-below sizes (possibly negative) from the forward prop. - const CoordinateDiff& get_padding_below_forward() const - { - return m_padding_below_forward; - } - /// \return The padding-above sizes (possibly negative) from the forward prop. - const CoordinateDiff& get_padding_above_forward() const - { - return m_padding_above_forward; - } - /// \return The data dilation strides from the forward prop. - const Strides& get_data_dilation_strides_forward() const + /// \brief Convolution + bias forward prop for batched convolution operation. + class NGRAPH_API ConvolutionBias : public ngraph::op::util::FusedOp { - return m_data_dilation_strides_forward; - } - - /// \return The window movement strides for the backward prop. - const Strides& get_window_movement_strides_backward() const - { - return m_window_movement_strides_backward; - } - /// \return The window dilation strides for the backward prop. - const Strides& get_window_dilation_strides_backward() const - { - return m_window_dilation_strides_backward; - } - /// \return The padding-below sizes (possibly negative) for the backward prop. - const CoordinateDiff& get_padding_below_backward() const + public: + static constexpr NodeTypeInfo type_info{"ConvolutionBias", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ConvolutionBias() = default; + ConvolutionBias(const std::shared_ptr& conv, + const Output& bias, + const bool with_relu = false); + + ConvolutionBias(const Output& data_batch, + const Output& filters, + const Output& bias, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const Strides& data_dilation_strides, + const bool with_relu = false); + + ConvolutionBias(const Output& data_batch, + const Output& filters, + const Output& bias); + + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } + Output get_bias() { return input_value(2); } + Output get_filters() { return input_value(1); } + Output get_data_batch() { return input_value(0); } + bool with_relu() const { return m_with_relu; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual NodeVector decompose_op() const override; + + virtual void validate_and_infer_types() override; + + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + Strides m_data_dilation_strides; + bool m_with_relu; + }; + + /// \brief Filters and bias backprop for batched convolution operation. Data backprop is + /// the same as regular convolution backprop for data. + class NGRAPH_API ConvolutionBiasBackpropFiltersBias : public ngraph::op::util::FusedOp { - return m_padding_below_backward; - } - /// \return The padding-above sizes (possibly negative) for the backward prop. - const CoordinateDiff& get_padding_above_backward() const + public: + static constexpr NodeTypeInfo type_info{"ConvolutionBiasBackpropFiltersBias", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ConvolutionBiasBackpropFiltersBias() = default; + ConvolutionBiasBackpropFiltersBias(const Output& data_batch, + const Shape& filters_shape, + const Shape& bias_shape, + const Output& output_delta, + const Strides& window_movement_strides_forward, + const Strides& window_dilation_strides_forward, + const CoordinateDiff& padding_below_forward, + const CoordinateDiff& padding_above_forward, + const Strides& data_dilation_strides_forward); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + /// \return The filters tensor shape. + const Shape& get_filters_shape() const { return m_filters_shape; } + /// \return The bias tensor shape. + const Shape& get_bias_shape() const { return m_bias_shape; } + /// \return The window movement strides from the forward prop. + const Strides& get_window_movement_strides_forward() const + { + return m_window_movement_strides_forward; + } + /// \return The window dilation strides from the forward prop. + const Strides& get_window_dilation_strides_forward() const + { + return m_window_dilation_strides_forward; + } + /// \return The padding-below sizes (possibly negative) from the forward prop. + const CoordinateDiff& get_padding_below_forward() const + { + return m_padding_below_forward; + } + /// \return The padding-above sizes (possibly negative) from the forward prop. + const CoordinateDiff& get_padding_above_forward() const + { + return m_padding_above_forward; + } + /// \return The data dilation strides from the forward prop. + const Strides& get_data_dilation_strides_forward() const + { + return m_data_dilation_strides_forward; + } + + /// \return The window movement strides for the backward prop. + const Strides& get_window_movement_strides_backward() const + { + return m_window_movement_strides_backward; + } + /// \return The window dilation strides for the backward prop. + const Strides& get_window_dilation_strides_backward() const + { + return m_window_dilation_strides_backward; + } + /// \return The padding-below sizes (possibly negative) for the backward prop. + const CoordinateDiff& get_padding_below_backward() const + { + return m_padding_below_backward; + } + /// \return The padding-above sizes (possibly negative) for the backward prop. + const CoordinateDiff& get_padding_above_backward() const + { + return m_padding_above_backward; + } + /// \return The data dilation strides for the backward prop. + const Strides& get_data_dilation_strides_backward() const + { + return m_data_dilation_strides_backward; + } + + virtual NodeVector decompose_op() const override; + + protected: + Shape m_filters_shape; + Shape m_bias_shape; + Strides m_window_movement_strides_forward; + Strides m_window_dilation_strides_forward; + CoordinateDiff m_padding_below_forward; + CoordinateDiff m_padding_above_forward; + Strides m_data_dilation_strides_forward; + + Strides m_window_movement_strides_backward; + Strides m_window_dilation_strides_backward; + CoordinateDiff m_padding_below_backward; + CoordinateDiff m_padding_above_backward; + Strides m_data_dilation_strides_backward; + }; + + class NGRAPH_API ConvolutionBiasAdd : public ngraph::op::util::FusedOp { - return m_padding_above_backward; - } - /// \return The data dilation strides for the backward prop. - const Strides& get_data_dilation_strides_backward() const - { - return m_data_dilation_strides_backward; - } - - virtual NodeVector decompose_op() const override; - - protected: - Shape m_filters_shape; - Shape m_bias_shape; - Strides m_window_movement_strides_forward; - Strides m_window_dilation_strides_forward; - CoordinateDiff m_padding_below_forward; - CoordinateDiff m_padding_above_forward; - Strides m_data_dilation_strides_forward; - - Strides m_window_movement_strides_backward; - Strides m_window_dilation_strides_backward; - CoordinateDiff m_padding_below_backward; - CoordinateDiff m_padding_above_backward; - Strides m_data_dilation_strides_backward; - }; - - class ConvolutionBiasAdd : public ngraph::op::util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ConvolutionBiasAdd", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ConvolutionBiasAdd() = default; - ConvolutionBiasAdd(const std::shared_ptr& conv, - const Output& sum_input, - bool with_relu = false); - - ConvolutionBiasAdd(const Output& data_batch, - const Output& filters, - const Output& bias, - const Output& sum_input, - const Strides& window_movement_strides, - const Strides& window_dilation_strides, - const CoordinateDiff& padding_below, - const CoordinateDiff& padding_above, - const Strides& data_dilation_strides, - bool with_relu = false); - - const Strides& get_window_movement_strides() const { return m_window_movement_strides; } - const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; } - const CoordinateDiff& get_padding_below() const { return m_padding_below; } - const CoordinateDiff& get_padding_above() const { return m_padding_above; } - const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } - Output get_filters() { return input_value(1); } - Output get_data_batch() { return input_value(0); } - bool with_relu() const { return m_with_relu; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual NodeVector decompose_op() const override; - - virtual void validate_and_infer_types() override; - - protected: - Strides m_window_movement_strides; - Strides m_window_dilation_strides; - CoordinateDiff m_padding_below; - CoordinateDiff m_padding_above; - Strides m_data_dilation_strides; - bool m_with_relu; - }; + public: + static constexpr NodeTypeInfo type_info{"ConvolutionBiasAdd", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ConvolutionBiasAdd() = default; + ConvolutionBiasAdd(const std::shared_ptr& conv, + const Output& sum_input, + bool with_relu = false); + + ConvolutionBiasAdd(const Output& data_batch, + const Output& filters, + const Output& bias, + const Output& sum_input, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const Strides& data_dilation_strides, + bool with_relu = false); + + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } + Output get_filters() { return input_value(1); } + Output get_data_batch() { return input_value(0); } + bool with_relu() const { return m_with_relu; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual NodeVector decompose_op() const override; + + virtual void validate_and_infer_types() override; + + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + Strides m_data_dilation_strides; + bool m_with_relu; + }; + } + using v0::ConvolutionBias; + using v0::ConvolutionBiasBackpropFiltersBias; + using v0::ConvolutionBiasAdd; } } diff --git a/src/ngraph/op/fused/crossentropy.cpp b/src/ngraph/op/fused/crossentropy.cpp new file mode 100644 index 00000000000..a0fe2444b7f --- /dev/null +++ b/src/ngraph/op/fused/crossentropy.cpp @@ -0,0 +1,292 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/fused/crossentropy.hpp" + +#include "ngraph/builder/make_constant.hpp" +#include "ngraph/op/constant.hpp" +#include "ngraph/op/convert.hpp" +#include "ngraph/op/divide.hpp" +#include "ngraph/op/log.hpp" +#include "ngraph/op/multiply.hpp" +#include "ngraph/op/negative.hpp" +#include "ngraph/op/not_equal.hpp" +#include "ngraph/op/one_hot.hpp" +#include "ngraph/op/reshape.hpp" +#include "ngraph/op/subtract.hpp" +#include "ngraph/op/sum.hpp" +#include "ngraph/op/util/broadcasting.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::CrossEntropy::type_info; + +op::CrossEntropy::CrossEntropy(const Output& arg1, + const Output& arg2, + bool soft_label, + int64_t ignore_index) + : FusedOp({arg1, arg2}) + , m_soft_label(soft_label) + , m_ignore_index(ignore_index) +{ + constructor_validate_and_infer_types(); +} + +static AxisVector get_axis_vector(size_t rank) +{ + AxisVector axis_vector; + + for (size_t i = 0; i < rank; i++) + { + axis_vector.push_back(i); + } + return axis_vector; +} + +static Shape get_result_shape(Shape& target_shape, int start, int end) +{ + Shape result; + for (size_t i = start; i < end; i++) + { + result.push_back(target_shape[i]); + } + return result; +} + +static Output get_2d_tensor(Output node) +{ + if (node.get_shape().size() == 2) + { + return node; + } + Shape node_shape = node.get_shape(); + size_t rank = node_shape.size(); + Shape result_shape{(shape_size(node_shape) / node_shape[rank - 1]), node_shape[rank - 1]}; + + auto reshape = std::make_shared(node, get_axis_vector(rank), result_shape); + return reshape; +} + +static std::shared_ptr expand_shape(std::shared_ptr result, Output original) +{ + Shape result_shape = result->get_shape(); + Shape original_shape = original.get_shape(); + + if (result_shape == original_shape && result_shape.size() == 2) + { + return result; + } + size_t original_rank = original_shape.size(); + size_t result_rank = result_shape.size(); + + // expand the first dimension of the computed result to match the original tensor shape + Shape new_shape = get_result_shape(original_shape, 0, original_rank - 1); + + // restore the last dimension of computed result + new_shape.push_back(result_shape[result_rank - 1]); + + if (new_shape.size() != original_shape.size()) + { + throw ngraph_error( + "CrossEntropy shape size mismatch in restoring the original tensor shape"); + } + auto reshape = std::make_shared(result, AxisVector{0, 1}, new_shape); + return reshape; +} + +// create mask based on ignore_index +static std::shared_ptr + create_mask(Output labels, Output input, int64_t ignore_index) +{ + auto mask_constant = + ngraph::op::Constant::create(labels.get_element_type(), labels.get_shape(), {ignore_index}); + auto not_equal = std::make_shared(labels, mask_constant); + auto convert = std::make_shared(not_equal, input.get_element_type()); + return convert; +} + +NodeVector op::CrossEntropy::decompose_op() const +{ + // we will reshape the labels and input tensor to 2d + auto input_to_normalize = get_2d_tensor(input_value(0)); + auto labels = get_2d_tensor(input_value(1)); + auto reduction_axis = input_to_normalize.get_shape().size() - 1; + + auto create_xe = [&](const Output& one_hot, const Output& input) { + auto node_log = std::make_shared(input); + auto node_mul = one_hot * node_log; + auto node_sum = std::make_shared( + node_mul, AxisSet{static_cast(reduction_axis)}); + return -node_sum; + }; + + // mask + std::shared_ptr mask = create_mask(labels, input_to_normalize, m_ignore_index); + + if (m_soft_label) + { + // insert dtype conversion if required + if (labels.get_element_type() != input_to_normalize.get_element_type()) + { + labels = std::make_shared(labels, + input_to_normalize.get_element_type()); + } + + if (labels.get_shape()[reduction_axis] == 1) + { + auto reshape_labels = std::make_shared( + labels, AxisVector{0, 1}, Shape{labels.get_shape().at(0)}); + labels = std::make_shared( + reshape_labels, + input_to_normalize.get_shape(), + AxisSet{input_to_normalize.get_shape().size() - 1}); + } + auto xe = create_xe(labels, input_to_normalize); + auto reshape_xe = std::make_shared( + xe, AxisVector{0}, Shape{xe->get_shape().at(0), 1}); + return {expand_shape(reshape_xe, input_value(0))}; + } + else + { + // we will have one_hot encoding on labels if softmax_labels = false + size_t one_hot_axis = input_to_normalize.get_shape().size() - 1; + auto reshape_labels = + make_shared(labels, AxisVector{0, 1}, Shape{labels.get_shape().at(0)}); + auto one_hot_labels = std::make_shared( + reshape_labels, input_to_normalize.get_shape(), one_hot_axis); + auto convert_one_hot = std::make_shared( + one_hot_labels, input_to_normalize.get_element_type()); + + // calculate loss + auto xe = create_xe(convert_one_hot, input_to_normalize); + auto reshape_xe = std::make_shared( + xe, AxisVector{0}, Shape{xe->get_shape().at(0), 1}); + if (m_ignore_index > 0) + { + return {reshape_xe * mask}; + } + return {expand_shape(reshape_xe, input_value(0))}; + } +} + +shared_ptr op::CrossEntropy::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), m_soft_label, m_ignore_index); +} + +void op::CrossEntropy::pre_validate_and_infer_types() +{ + element::Type input_element_type = get_input_element_type(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, get_input_element_type(0), PartialShape::dynamic()); + + if (is_dynamic()) + { + return; + } +} + +constexpr NodeTypeInfo op::CrossEntropyBackprop::type_info; + +op::CrossEntropyBackprop::CrossEntropyBackprop(const Output& input, + const Output& labels, + const Output& delta, + bool soft_label, + int64_t ignore_index) + : FusedOp({input, labels, delta}) + , m_soft_label(soft_label) + , m_ignore_index(ignore_index) +{ + constructor_validate_and_infer_types(); +} + +void op::CrossEntropyBackprop::pre_validate_and_infer_types() +{ + element::Type input_element_type = get_input_element_type(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, get_input_element_type(0), PartialShape::dynamic()); +} + +shared_ptr op::CrossEntropyBackprop::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared( + new_args.at(0), new_args.at(1), new_args.at(2), m_soft_label, m_ignore_index); +} + +NodeVector op::CrossEntropyBackprop::decompose_op() const +{ + auto input = get_2d_tensor(input_value(0)); + auto labels = get_2d_tensor(input_value(1)); + auto delta = get_2d_tensor(input_value(2)); + auto rank = input.get_shape().size(); + + size_t one_hot_axis = delta.get_shape().size() - 1; + + // always reduces the sum on the last axis + auto reduction_axis = delta.get_shape().size() - 1; + + // mask + std::shared_ptr mask = nullptr; + + // remove trailing ones from delta + auto delta_reshape = std::make_shared( + delta, AxisVector{0, 1}, Shape{delta.get_shape().at(0)}); + auto delta_bcast = std::make_shared( + delta_reshape, input.get_shape(), AxisSet{rank - 1}); + + if (!m_soft_label) + { + // ignore mask + if (m_ignore_index > 0) + { + mask = create_mask(labels, input, m_ignore_index); + mask = std::make_shared( + mask, AxisVector{0, 1}, Shape{mask->get_shape().at(0)}); + mask = + std::make_shared(mask, input.get_shape(), AxisSet{rank - 1}); + } + if (labels.get_shape()[reduction_axis] == 1) + { + labels = + make_shared(labels, AxisVector{0, 1}, Shape{labels.get_shape().at(0)}); + } + // one hot encoding of labels + auto one_hot = + std::make_shared(labels, input.get_shape(), one_hot_axis); + labels = std::make_shared(one_hot, input.get_element_type()); + } + + std::shared_ptr xe_grad = + std::make_shared(-labels * delta_bcast, input); + + if (!m_soft_label && m_ignore_index > 0) + { + xe_grad = xe_grad * mask; + } + return {expand_shape(xe_grad, input_value(0))}; +} diff --git a/src/ngraph/op/fused/crossentropy.hpp b/src/ngraph/op/fused/crossentropy.hpp new file mode 100644 index 00000000000..c39af7f1ea5 --- /dev/null +++ b/src/ngraph/op/fused/crossentropy.hpp @@ -0,0 +1,93 @@ +//***************************************************************************** +// Copyright 2017-2019 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/node.hpp" +#include "ngraph/op/op.hpp" +#include "ngraph/op/util/fused_op.hpp" + +namespace ngraph +{ + namespace op + { + class NGRAPH_API CrossEntropy : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"CrossEntropy", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + CrossEntropy() = default; + /// \brief CrossEntropy for computing loss + /// \param arg1 Node that produces the input tensor + /// \param arg2 Node that produces ground truth lables for the input + /// \param soft_label flag indicating whether to interpretate the given labels as soft + /// labels + /// \param ignore_index Specifies a target value that is ignored and does not contribute + /// to the input gradient Only valid if soft_label is set to False + CrossEntropy(const Output& arg1, + const Output& arg2, + bool soft_label = false, + int64_t ignore_index = -100); + + virtual NodeVector decompose_op() const override; + + void pre_validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + bool get_soft_label() const { return m_soft_label; } + int64_t get_ignore_index() const { return m_ignore_index; } + private: + bool m_soft_label; + int64_t m_ignore_index; + }; + + class NGRAPH_API CrossEntropyBackprop : public util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"CrossEntropyBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + CrossEntropyBackprop() = default; + + /// \brief Backprop for CrossEntropy + /// \param input Node that produces tensor from the fprop + /// \param labels Node that produces ground truth labels for input + /// \param delta Node that produces the delta during bprop + /// \param soft_label flag indicating whether to interpretate the given labels as soft + /// labels + /// \param ignore_index Specifies a target value that is ignored and does not contribute + /// to the input gradient Only valid if soft_label is set to False + CrossEntropyBackprop(const Output& input, + const Output& labels, + const Output& delta, + bool soft_label = false, + int64_t ignore_index = -100); + + virtual NodeVector decompose_op() const override; + + void pre_validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool get_soft_label() const { return m_soft_label; } + int64_t get_ignore_index() const { return m_ignore_index; } + private: + bool m_soft_label; + int64_t m_ignore_index; + }; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/op/fused/depth_to_space.hpp b/src/ngraph/op/fused/depth_to_space.hpp index 7f2d4c58e4e..e685feea570 100644 --- a/src/ngraph/op/fused/depth_to_space.hpp +++ b/src/ngraph/op/fused/depth_to_space.hpp @@ -24,53 +24,57 @@ namespace ngraph { namespace op { - /// \brief DepthToSpace permutes data from the depth dimension of the input blob into - /// spatial dimensions. - /// - /// \note Values from the depth dimension (assuming NCHW layout) are moved in - /// spatial blocks to the height and width dimensions. - /// - /// Output node produces a tensor with shape: - /// [N, C/(blocksize * blocksize), H * blocksize, W * blocksize] - class DepthToSpace : public ngraph::op::util::FusedOp + namespace v0 { - public: - enum class DepthToSpaceMode + /// \brief DepthToSpace permutes data from the depth dimension of the input blob into + /// spatial dimensions. + /// + /// \note Values from the depth dimension (assuming NCHW layout) are moved in + /// spatial blocks to the height and width dimensions. + /// + /// Output node produces a tensor with shape: + /// [N, C/(blocksize * blocksize), H * blocksize, W * blocksize] + class NGRAPH_API DepthToSpace : public ngraph::op::util::FusedOp { - // The input depth is divided to [block_size, ..., block_size, new_depth] - BLOCKS_FIRST, - // The input depth is divided to [new_depth, block_size, ..., block_size] - DEPTH_FIRST - }; + public: + enum class DepthToSpaceMode + { + // The input depth is divided to [block_size, ..., block_size, new_depth] + BLOCKS_FIRST, + // The input depth is divided to [new_depth, block_size, ..., block_size] + DEPTH_FIRST + }; - NGRAPH_API - static constexpr NodeTypeInfo type_info{"DepthToSpace", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - DepthToSpace() = default; - /// \brief Constructs a DepthToSpace operation. - /// - /// \param data Node producing the input tensor - /// \param mode Specifies how the input depth dimension is split to block coordinates - /// \param block_size The size of the block of values to be moved - DepthToSpace(const Output& data, - const DepthToSpaceMode& mode, - std::size_t block_size = 1); + static constexpr NodeTypeInfo type_info{"DepthToSpace", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + DepthToSpace() = default; + /// \brief Constructs a DepthToSpace operation. + /// + /// \param data Node producing the input tensor + /// \param mode Specifies how the input depth dimension is split to block + /// coordinates + /// \param block_size The size of the block of values to be moved + DepthToSpace(const Output& data, + const DepthToSpaceMode& mode, + std::size_t block_size = 1); - DepthToSpace(const Output& data, - const std::string& mode, - std::size_t block_size = 1); + DepthToSpace(const Output& data, + const std::string& mode, + std::size_t block_size = 1); - std::size_t get_block_size() const { return m_blocksize; } - DepthToSpaceMode get_mode() const { return m_mode; } - virtual NodeVector decompose_op() const override; + std::size_t get_block_size() const { return m_blocksize; } + DepthToSpaceMode get_mode() const { return m_mode; } + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - std::size_t m_blocksize; - DepthToSpaceMode m_mode; - DepthToSpaceMode mode_from_string(const std::string& mode) const; - }; + protected: + std::size_t m_blocksize; + DepthToSpaceMode m_mode; + DepthToSpaceMode mode_from_string(const std::string& mode) const; + }; + } + using v0::DepthToSpace; } } diff --git a/src/ngraph/op/fused/elu.hpp b/src/ngraph/op/fused/elu.hpp index d5b9a649c88..aea1750328a 100644 --- a/src/ngraph/op/fused/elu.hpp +++ b/src/ngraph/op/fused/elu.hpp @@ -24,31 +24,34 @@ namespace ngraph { namespace op { - /// \brief Exponential Linear Unit - /// x < 0 => f(x) = alpha * (exp(x) - 1.) - /// x >= 0 => f(x) = x - /// - class Elu : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Elu", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Elu() = default; - /// \brief Constructs an Elu operation. + /// \brief Exponential Linear Unit + /// x < 0 => f(x) = alpha * (exp(x) - 1.) + /// x >= 0 => f(x) = x /// - /// \param data Input tensor - /// \param alpha Multiplier for negative values - Elu(const Output& data, const double alpha); + class NGRAPH_API Elu : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Elu", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Elu() = default; + /// \brief Constructs an Elu operation. + /// + /// \param data Input tensor + /// \param alpha Multiplier for negative values + Elu(const Output& data, const double alpha); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - double get_alpha() const { return m_alpha; } - private: - double m_alpha; - }; + double get_alpha() const { return m_alpha; } + private: + double m_alpha; + }; + } + using v0::Elu; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/fake_quantize.hpp b/src/ngraph/op/fused/fake_quantize.hpp index 00f8768951c..b4e94dd1d44 100644 --- a/src/ngraph/op/fused/fake_quantize.hpp +++ b/src/ngraph/op/fused/fake_quantize.hpp @@ -25,64 +25,67 @@ namespace ngraph { namespace op { - /// - /// \brief Class performing element-wise linear quantization. - /// - /// \note Input floating point values are quantized into a discrete - /// set of floating point values. - /// - /// \paragraph Implementation This class creates a node which performs the following - /// operation: - /// - /// round((data - input_low) / (input_high - input_low) * (levels-1)) / - /// (levels-1) * (output_high - output_low) + output_low - /// - /// - class FakeQuantize : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"FakeQuantize", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - FakeQuantize() = default; /// - /// \brief Constructs a FakeQuantize operation node. + /// \brief Class performing element-wise linear quantization. /// - /// \param[in] data The input data tensor. - /// \param[in] input_low The minimum limit for input values. - /// \param[in] input_high The maximum limit for input values. - /// \param[in] output_low The minimum quantized value. - /// \param[in] output_high The maximum quantized value. - /// \param[in] levels The number of quantization levels. - /// \param[in] auto_broadcast AutoBroadcast mode to be used for broadcasting - /// limit values + /// \note Input floating point values are quantized into a discrete + /// set of floating point values. /// - FakeQuantize(const Output& data, - const Output& input_low, - const Output& input_high, - const Output& output_low, - const Output& output_high, - std::size_t levels, - const AutoBroadcastSpec& auto_broadcast = - AutoBroadcastSpec(AutoBroadcastType::NUMPY)); + /// \paragraph Implementation This class creates a node which performs the following + /// operation: + /// + /// round((data - input_low) / (input_high - input_low) * (levels-1)) / + /// (levels-1) * (output_high - output_low) + output_low + /// + /// + class NGRAPH_API FakeQuantize : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"FakeQuantize", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + FakeQuantize() = default; + /// + /// \brief Constructs a FakeQuantize operation node. + /// + /// \param[in] data The input data tensor. + /// \param[in] input_low The minimum limit for input values. + /// \param[in] input_high The maximum limit for input values. + /// \param[in] output_low The minimum quantized value. + /// \param[in] output_high The maximum quantized value. + /// \param[in] levels The number of quantization levels. + /// \param[in] auto_broadcast AutoBroadcast mode to be used for broadcasting + /// limit values + /// + FakeQuantize(const Output& data, + const Output& input_low, + const Output& input_high, + const Output& output_low, + const Output& output_high, + std::size_t levels, + const AutoBroadcastSpec& auto_broadcast = + AutoBroadcastSpec(AutoBroadcastType::NUMPY)); - virtual NodeVector decompose_op() const override; - virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; + virtual void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - std::size_t get_levels() const { return m_levels; } - void set_levels(std::size_t levels) { m_levels = levels; } - const AutoBroadcastSpec& get_auto_broadcast() const { return m_auto_broadcast; } - void set_auto_broadcast(const AutoBroadcastSpec& auto_broadcast) - { - m_auto_broadcast = auto_broadcast; - } + std::size_t get_levels() const { return m_levels; } + void set_levels(std::size_t levels) { m_levels = levels; } + const AutoBroadcastSpec& get_auto_broadcast() const { return m_auto_broadcast; } + void set_auto_broadcast(const AutoBroadcastSpec& auto_broadcast) + { + m_auto_broadcast = auto_broadcast; + } - private: - std::size_t m_levels; - AutoBroadcastSpec m_auto_broadcast; - }; + private: + std::size_t m_levels; + AutoBroadcastSpec m_auto_broadcast; + }; + } + using v0::FakeQuantize; } } diff --git a/src/ngraph/op/fused/gelu.cpp b/src/ngraph/op/fused/gelu.cpp index 2f9fa6ddfa3..cc26abd68fc 100644 --- a/src/ngraph/op/fused/gelu.cpp +++ b/src/ngraph/op/fused/gelu.cpp @@ -66,12 +66,18 @@ shared_ptr op::Gelu::copy_with_new_args(const NodeVector& new_args) const void op::Gelu::pre_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, ")."); + + if (input_pshape.is_dynamic()) + { + set_output_type(0, input_element_type, input_pshape); + } } void op::Gelu::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) @@ -94,12 +100,18 @@ op::GeluBackpropFactor::GeluBackpropFactor(const Output& x) void op::GeluBackpropFactor::pre_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, ")."); + + if (input_pshape.is_dynamic()) + { + set_output_type(0, input_element_type, input_pshape); + } } shared_ptr op::GeluBackpropFactor::copy_with_new_args(const NodeVector& new_args) const diff --git a/src/ngraph/op/fused/gelu.hpp b/src/ngraph/op/fused/gelu.hpp index a6de75c8d8f..6f7708f759f 100644 --- a/src/ngraph/op/fused/gelu.hpp +++ b/src/ngraph/op/fused/gelu.hpp @@ -24,49 +24,52 @@ namespace ngraph { namespace op { - /// \brief Gaussian Error Linear Unit - /// f(x) = 0.5 * x * (1 + erf( x / sqrt(2) ) - class Gelu : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Gelu", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Gelu() = default; - /// \brief Constructs an Gelu operation. - /// - /// \param data Input tensor - Gelu(const Output& data); + /// \brief Gaussian Error Linear Unit + /// f(x) = 0.5 * x * (1 + erf( x / sqrt(2) ) + class NGRAPH_API Gelu : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Gelu", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Gelu() = default; + /// \brief Constructs an Gelu operation. + /// + /// \param data Input tensor + Gelu(const Output& data); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; - /// \brief Backprop for Gelu(x) is GeluBackprop(x) * delta - class GeluBackpropFactor : public util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GeluBackpropFactor", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - GeluBackpropFactor() = default; + /// \brief Backprop for Gelu(x) is GeluBackprop(x) * delta + class NGRAPH_API GeluBackpropFactor : public util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GeluBackpropFactor", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GeluBackpropFactor() = default; - GeluBackpropFactor(const Output& x); + GeluBackpropFactor(const Output& x); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Gelu; + using v0::GeluBackpropFactor; } } diff --git a/src/ngraph/op/fused/gemm.hpp b/src/ngraph/op/fused/gemm.hpp index 7a9ad0b342e..475c6a000b9 100644 --- a/src/ngraph/op/fused/gemm.hpp +++ b/src/ngraph/op/fused/gemm.hpp @@ -24,54 +24,57 @@ namespace ngraph { namespace op { - /// \brief Operator performing General Matrix multiplication. - /// - /// \note More information: - /// https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3 - /// - /// A' = transpose(A) if transA else A - /// B' = transpose(B) if transB else B - /// - /// Compute Y = alpha * A' * B' + beta * C - /// - class Gemm : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Gemm", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Gemm() = default; - /// \brief Constructs an Gemm operation. + /// \brief Operator performing General Matrix multiplication. /// - /// \param A Input tensor A - /// \param B Input tensor B - /// \param C Input tensor C - /// \param alpha Scalar multiplier for the product of input tensors A * B - /// \param beta Scalar multiplier for input tensor C - /// \param transA Whether A should be transposed - /// \param transB Whether B should be transposed - Gemm(const Output& A, - const Output& B, - const Output& C, - double alpha = 1.0, - double beta = 1.0, - bool transA = false, - bool transB = false); + /// \note More information: + /// https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3 + /// + /// A' = transpose(A) if transA else A + /// B' = transpose(B) if transB else B + /// + /// Compute Y = alpha * A' * B' + beta * C + /// + class NGRAPH_API Gemm : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Gemm", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Gemm() = default; + /// \brief Constructs an Gemm operation. + /// + /// \param A Input tensor A + /// \param B Input tensor B + /// \param C Input tensor C + /// \param alpha Scalar multiplier for the product of input tensors A * B + /// \param beta Scalar multiplier for input tensor C + /// \param transA Whether A should be transposed + /// \param transB Whether B should be transposed + Gemm(const Output& A, + const Output& B, + const Output& C, + double alpha = 1.0, + double beta = 1.0, + bool transA = false, + bool transB = false); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - double get_alpha() const { return m_alpha; } - double get_beta() const { return m_beta; } - bool get_transA() const { return m_transA; } - bool get_transB() const { return m_transB; } - private: - double m_alpha; - double m_beta; - bool m_transA; - bool m_transB; - }; + double get_alpha() const { return m_alpha; } + double get_beta() const { return m_beta; } + bool get_transA() const { return m_transA; } + bool get_transB() const { return m_transB; } + private: + double m_alpha; + double m_beta; + bool m_transA; + bool m_transB; + }; + } + using v0::Gemm; } } diff --git a/src/ngraph/op/fused/grn.hpp b/src/ngraph/op/fused/grn.hpp index 504e790bdbb..9c15a2305ed 100644 --- a/src/ngraph/op/fused/grn.hpp +++ b/src/ngraph/op/fused/grn.hpp @@ -25,31 +25,34 @@ namespace ngraph { namespace op { - /// \brief Global Response Normalization with L2 norm (across channels only). - /// - class GRN : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GRN", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - GRN() = default; - /// \brief Constructs a GRN operation. + /// \brief Global Response Normalization with L2 norm (across channels only). /// - /// \param data - Node producing the input tensor - /// \param bias - The bias added to the variance. - /// - GRN(const Output& data, float bias); + class NGRAPH_API GRN : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GRN", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GRN() = default; + /// \brief Constructs a GRN operation. + /// + /// \param data - Node producing the input tensor + /// \param bias - The bias added to the variance. + /// + GRN(const Output& data, float bias); - float get_bias() const { return m_bias; } - virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + float get_bias() const { return m_bias; } + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - float m_bias = 1.0f; - }; + protected: + float m_bias = 1.0f; + }; + } + using v0::GRN; } } diff --git a/src/ngraph/op/fused/group_conv.cpp b/src/ngraph/op/fused/group_conv.cpp index e1150da3703..ab4c067617a 100644 --- a/src/ngraph/op/fused/group_conv.cpp +++ b/src/ngraph/op/fused/group_conv.cpp @@ -82,7 +82,7 @@ void op::GroupConvolution::pre_validate_and_infer_types() // Update groups if (has_groups_in_filters_shape()) { - m_groups = get_input_partial_shape(1)[0]; + m_groups = static_cast(get_input_partial_shape(1)[0]); } // Data channels @@ -100,6 +100,10 @@ void op::GroupConvolution::pre_validate_and_infer_types() get_groups()) == data_shape.to_shape()[1], "Incorrect number of channels per filter"); } + else + { + set_output_type(0, get_input_element_type(0), PartialShape::dynamic()); + } } void op::GroupConvolution::post_validate_and_infer_types() @@ -148,14 +152,6 @@ Shape op::GroupConvolution::get_weights_dimensions() const return weights_shape_groups; } -size_t ngraph::op::GroupConvolution::get_groups() const -{ - NODE_VALIDATION_CHECK(this, - m_groups.is_static(), - "get_groups() can only be called if the number of groups is static."); - return static_cast(m_groups); -} - shared_ptr op::GroupConvolution::copy_with_new_args(const NodeVector& new_args) const { if (new_args.size() != 2) @@ -225,3 +221,225 @@ bool ngraph::op::GroupConvolution::has_groups_in_filters_shape() const // dim. return ((get_input_shape(0).size() + 1) == get_input_shape(1).size()); } + +constexpr NodeTypeInfo op::GroupConvolutionBackpropData::type_info; + +op::GroupConvolutionBackpropData::GroupConvolutionBackpropData( + const Output& data_batch, + const Output& filters, + const Output& output_delta, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const size_t groups) + : FusedOp({data_batch, filters, output_delta}) + , m_window_movement_strides(window_movement_strides) + , m_window_dilation_strides(window_dilation_strides) + , m_padding_below(padding_below) + , m_padding_above(padding_above) + , m_groups(groups) +{ + constructor_validate_and_infer_types(); +} + +void op::GroupConvolutionBackpropData::pre_validate_and_infer_types() +{ + element::Type data_element_type = get_input_element_type(0); + PartialShape data_pshape = get_input_partial_shape(0); + PartialShape filters_pshape = get_input_partial_shape(1); + PartialShape delta_pshape = get_input_partial_shape(2); + + NODE_VALIDATION_CHECK(this, + data_element_type.is_dynamic() || data_element_type.is_real(), + "Argument element type must be f16, bf16, f32, f64 or dynamic (got ", + data_element_type, + ")."); + + if (data_pshape.is_dynamic() || filters_pshape.is_dynamic() || delta_pshape.is_dynamic()) + { + set_output_type(0, data_element_type, PartialShape::dynamic()); + } +} + +shared_ptr + op::GroupConvolutionBackpropData::copy_with_new_args(const NodeVector& new_args) const +{ + if (new_args.size() != 3) + { + throw ngraph_error("Incorrect number of new arguments"); + } + + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + get_window_movement_strides(), + get_window_dilation_strides(), + get_padding_below(), + get_padding_above(), + get_groups()); +} + +NodeVector op::GroupConvolutionBackpropData::decompose_op() const +{ + auto data_batch = input_value(0); + auto filters = input_value(1); + auto output_delta = input_value(2); + + auto data_shape = get_input_shape(0); + auto filters_shape = get_input_shape(1); + auto delta_shape = get_input_shape(2); + + NodeVector sliced_inputs; + + for (size_t i = 0; i < get_groups(); ++i) + { + size_t channel_step = filters_shape.at(1); + + const Coordinate data_lower_bound{0, i * channel_step, 0, 0}; + const Coordinate data_upper_bound{ + data_shape.at(0), (i + 1) * channel_step, data_shape.at(2), data_shape.at(3)}; + auto sliced_data = + std::make_shared(data_batch, data_lower_bound, data_upper_bound); + + size_t filters_step = filters_shape.at(0) / get_groups(); + + const Coordinate filters_lower_bound{i * filters_step, 0, 0, 0}; + const Coordinate filters_upper_bound{ + (i + 1) * filters_step, filters_shape.at(1), filters_shape.at(2), filters_shape.at(3)}; + auto sliced_filters = + std::make_shared(filters, filters_lower_bound, filters_upper_bound); + + const Coordinate delta_lower_bound{0, i * filters_step, 0, 0}; + const Coordinate delta_upper_bound{ + delta_shape.at(0), (i + 1) * filters_step, delta_shape.at(2), delta_shape.at(3)}; + auto sliced_delta = + std::make_shared(output_delta, delta_lower_bound, delta_upper_bound); + + auto sliced_conv = + std::make_shared(sliced_data->get_shape(), + sliced_filters, + sliced_delta, + get_window_movement_strides(), + get_window_dilation_strides(), + get_padding_below(), + get_padding_above(), + Strides{1, 1}); + + sliced_inputs.push_back(sliced_conv); + } + + size_t concatenation_axis = 1; + return {std::make_shared(sliced_inputs, concatenation_axis)}; +} + +constexpr NodeTypeInfo op::GroupConvolutionBackpropFilters::type_info; + +op::GroupConvolutionBackpropFilters::GroupConvolutionBackpropFilters( + const Output& data_batch, + const Output& filters, + const Output& output_delta, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const size_t groups) + : FusedOp({data_batch, filters, output_delta}) + , m_window_movement_strides(window_movement_strides) + , m_window_dilation_strides(window_dilation_strides) + , m_padding_below(padding_below) + , m_padding_above(padding_above) + , m_groups(groups) +{ + constructor_validate_and_infer_types(); +} + +void op::GroupConvolutionBackpropFilters::pre_validate_and_infer_types() +{ + element::Type filters_element_type = get_input_element_type(1); + PartialShape data_pshape = get_input_partial_shape(0); + PartialShape filters_pshape = get_input_partial_shape(1); + PartialShape delta_pshape = get_input_partial_shape(2); + + NODE_VALIDATION_CHECK(this, + filters_element_type.is_dynamic() || filters_element_type.is_real(), + "Argument element type must be f16, bf16, f32, f64 or dynamic (got ", + filters_element_type, + ")."); + + if (data_pshape.is_dynamic() || filters_pshape.is_dynamic() || delta_pshape.is_dynamic()) + { + set_output_type(0, filters_element_type, PartialShape::dynamic()); + } +} + +shared_ptr + op::GroupConvolutionBackpropFilters::copy_with_new_args(const NodeVector& new_args) const +{ + if (new_args.size() != 3) + { + throw ngraph_error("Incorrect number of new arguments"); + } + + return make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + get_window_movement_strides(), + get_window_dilation_strides(), + get_padding_below(), + get_padding_above(), + get_groups()); +} + +NodeVector op::GroupConvolutionBackpropFilters::decompose_op() const +{ + auto data_batch = input_value(0); + auto filters = input_value(1); + auto output_delta = input_value(2); + + auto data_shape = get_input_shape(0); + auto filters_shape = get_input_shape(1); + auto delta_shape = get_input_shape(2); + + NodeVector sliced_inputs; + + for (size_t i = 0; i < get_groups(); ++i) + { + size_t channel_step = filters_shape.at(1); + + const Coordinate data_lower_bound{0, i * channel_step, 0, 0}; + const Coordinate data_upper_bound{ + data_shape.at(0), (i + 1) * channel_step, data_shape.at(2), data_shape.at(3)}; + auto sliced_data = + std::make_shared(data_batch, data_lower_bound, data_upper_bound); + + size_t filters_step = filters_shape.at(0) / get_groups(); + + const Coordinate filters_lower_bound{i * filters_step, 0, 0, 0}; + const Coordinate filters_upper_bound{ + (i + 1) * filters_step, filters_shape.at(1), filters_shape.at(2), filters_shape.at(3)}; + auto sliced_filters = + std::make_shared(filters, filters_lower_bound, filters_upper_bound); + + const Coordinate delta_lower_bound{0, i * filters_step, 0, 0}; + const Coordinate delta_upper_bound{ + delta_shape.at(0), (i + 1) * filters_step, delta_shape.at(2), delta_shape.at(3)}; + auto sliced_delta = + std::make_shared(output_delta, delta_lower_bound, delta_upper_bound); + + auto sliced_conv = + std::make_shared(sliced_data, + sliced_filters->get_shape(), + sliced_delta, + get_window_movement_strides(), + get_window_dilation_strides(), + get_padding_below(), + get_padding_above(), + Strides{1, 1}); + + sliced_inputs.push_back(sliced_conv); + } + + size_t concatenation_axis = 0; + return {std::make_shared(sliced_inputs, concatenation_axis)}; +} diff --git a/src/ngraph/op/fused/group_conv.hpp b/src/ngraph/op/fused/group_conv.hpp index 273f8968c52..0ac304f6cc5 100644 --- a/src/ngraph/op/fused/group_conv.hpp +++ b/src/ngraph/op/fused/group_conv.hpp @@ -25,65 +25,161 @@ namespace ngraph { namespace op { - /// \brief Group Convolution - class GroupConvolution : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GroupConvolution", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - GroupConvolution() = default; - GroupConvolution(const Output& data_batch, - const Output& filters, - const Strides& window_movement_strides, - const Strides& window_dilation_strides, - const CoordinateDiff& padding_below, - const CoordinateDiff& padding_above, - const Strides& data_dilation_strides, - const size_t groups, - const PadType& pad_type = PadType::EXPLICIT); - - // constructor which accept groups included in filters shape. - GroupConvolution(const Output& data_batch, - const Output& filters, - const Strides& window_movement_strides, - const Strides& window_dilation_strides, - const CoordinateDiff& padding_below, - const CoordinateDiff& padding_above, - const Strides& data_dilation_strides, - const PadType& pad_type = PadType::EXPLICIT); - Shape get_weights_dimensions() const; - const Strides& get_window_movement_strides() const { return m_window_movement_strides; } - const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; } - const CoordinateDiff& get_padding_below() const { return m_padding_below; } - const CoordinateDiff& get_padding_above() const { return m_padding_above; } - const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } - Output get_filters() { return input_value(1); } - Output get_data_batch() { return input_value(0); } - size_t get_groups() const; - const PadType& get_pad_type() const { return m_pad_type; } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual NodeVector decompose_op() const override; - - virtual void pre_validate_and_infer_types() override; - virtual void post_validate_and_infer_types() override; - - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - - protected: - Strides m_window_movement_strides; - Strides m_window_dilation_strides; - CoordinateDiff m_padding_below; - CoordinateDiff m_padding_above; - Strides m_data_dilation_strides; - Dimension m_groups; - PadType m_pad_type{PadType::NOTSET}; - - private: - bool has_groups_in_filters_shape() const; - }; + /// \brief Group Convolution + class NGRAPH_API GroupConvolution : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GroupConvolution", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GroupConvolution() = default; + GroupConvolution(const Output& data_batch, + const Output& filters, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const Strides& data_dilation_strides, + const size_t groups, + const PadType& pad_type = PadType::EXPLICIT); + + // constructor which accept groups included in filters shape. + GroupConvolution(const Output& data_batch, + const Output& filters, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const Strides& data_dilation_strides, + const PadType& pad_type = PadType::EXPLICIT); + Shape get_weights_dimensions() const; + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } + Output get_filters() { return input_value(1); } + Output get_data_batch() { return input_value(0); } + size_t get_groups() const { return m_groups; }; + const PadType& get_pad_type() const { return m_pad_type; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual NodeVector decompose_op() const override; + + virtual void pre_validate_and_infer_types() override; + virtual void post_validate_and_infer_types() override; + + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + Strides m_data_dilation_strides; + size_t m_groups; + PadType m_pad_type{PadType::NOTSET}; + + private: + bool has_groups_in_filters_shape() const; + }; + + /// \brief Group Convolution data batch backprop + class NGRAPH_API GroupConvolutionBackpropData : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GroupConvolutionBackpropData", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GroupConvolutionBackpropData() = default; + GroupConvolutionBackpropData(const Output& data_batch, + const Output& filters, + const Output& output_delta, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const size_t groups); + + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + size_t get_groups() const { return m_groups; }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual NodeVector decompose_op() const override; + + virtual void pre_validate_and_infer_types() override; + + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + size_t m_groups; + }; + + /// \brief Group Convolution filters backprop + class NGRAPH_API GroupConvolutionBackpropFilters : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GroupConvolutionBackpropFilters", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GroupConvolutionBackpropFilters() = default; + GroupConvolutionBackpropFilters(const Output& data_batch, + const Output& filters, + const Output& output_delta, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const size_t groups); + + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + size_t get_groups() const { return m_groups; } + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual NodeVector decompose_op() const override; + + virtual void pre_validate_and_infer_types() override; + + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + size_t m_groups; + }; + } + + using v0::GroupConvolution; + using v0::GroupConvolutionBackpropData; + using v0::GroupConvolutionBackpropFilters; } } diff --git a/src/ngraph/op/fused/group_conv_transpose.hpp b/src/ngraph/op/fused/group_conv_transpose.hpp index aa32319a113..8ac9956c5cd 100644 --- a/src/ngraph/op/fused/group_conv_transpose.hpp +++ b/src/ngraph/op/fused/group_conv_transpose.hpp @@ -31,126 +31,133 @@ namespace ngraph { namespace op { - /// \brief Group Transpose Convolution (Deconvolution) - class GroupConvolutionTranspose : public util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GroupConvolutionTranspose", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - GroupConvolutionTranspose() = default; - /// - /// \brief Constructs GroupConvolutionTranspose operation. - /// - /// \param[in] data The node producing input data. - /// \param[in] filters The node producing filters data. - /// \param[in] strides The strides along each feature axis. - /// \param[in] dilations The dilations along each feature axis. - /// \param[in] padding_begin The padding added at the beggining of each feature axis. - /// \param[in] padding_end The padding added at the end of each feature axis. - /// \param[in] output_padding The zero-padding (adjustment) added to one side of the - /// output. - /// \param[in] groups The number of groups the input channels and output - /// channels are divided into. - /// \param[in] pad_type The provided padding type. - /// \param[in] output_shape The output shape. When provided padding values are - /// automatically inferred. - /// - GroupConvolutionTranspose(const Output& data, - const Output& filters, - const Strides& strides, - const Strides& dilations, - const CoordinateDiff& padding_begin, - const CoordinateDiff& padding_end, - const CoordinateDiff& output_padding, - const std::size_t groups = 1UL, - const PadType& pad_type = PadType::EXPLICIT, - const Shape& output_shape = Shape{}); + /// \brief Group Transpose Convolution (Deconvolution) + class NGRAPH_API GroupConvolutionTranspose : public util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"GroupConvolutionTranspose", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GroupConvolutionTranspose() = default; + /// + /// \brief Constructs GroupConvolutionTranspose operation. + /// + /// \param[in] data The node producing input data. + /// \param[in] filters The node producing filters data. + /// \param[in] strides The strides along each feature axis. + /// \param[in] dilations The dilations along each feature axis. + /// \param[in] padding_begin The padding added at the beggining of each feature + /// axis. + /// \param[in] padding_end The padding added at the end of each feature axis. + /// \param[in] output_padding The zero-padding (adjustment) added to one side of + /// the + /// output. + /// \param[in] groups The number of groups the input channels and output + /// channels are divided into. + /// \param[in] pad_type The provided padding type. + /// \param[in] output_shape The output shape. When provided padding values are + /// automatically inferred. + /// + GroupConvolutionTranspose(const Output& data, + const Output& filters, + const Strides& strides, + const Strides& dilations, + const CoordinateDiff& padding_begin, + const CoordinateDiff& padding_end, + const CoordinateDiff& output_padding, + const std::size_t groups = 1UL, + const PadType& pad_type = PadType::EXPLICIT, + const Shape& output_shape = Shape{}); - /// - /// \brief Constructs GroupConvolutionTranspose operation. - /// - /// \param[in] data The node producing input data. - /// \param[in] filters The node producing filters data. - /// \param[in] groups The number of groups the input channels and output channels - /// are divided into. - /// - GroupConvolutionTranspose(const Output& data, - const Output& filters, - const std::size_t groups = 1UL); + /// + /// \brief Constructs GroupConvolutionTranspose operation. + /// + /// \param[in] data The node producing input data. + /// \param[in] filters The node producing filters data. + /// \param[in] groups The number of groups the input channels and output + /// channels + /// are divided into. + /// + GroupConvolutionTranspose(const Output& data, + const Output& filters, + const std::size_t groups = 1UL); - /// - /// \brief Constructs GroupConvolutionTranspose operation. - /// - /// \param[in] data The node producing input data. - /// \param[in] filters The node producing filters data. - /// \param[in] strides The strides along each feature axis. - /// \param[in] dilations The dilations along each feature axis. - /// \param[in] output_padding The zero-padding (adjustment) added to one side of the - /// output. - /// \param[in] output_shape The output shape. When provided padding values are - /// automatically inferred. - /// \param[in] groups The number of groups the input channels and output - /// channels are divided into. - /// - GroupConvolutionTranspose(const Output& data, - const Output& filters, - const Strides& strides, - const Strides& dilations, - const CoordinateDiff& output_padding, - const Shape& output_shape, - const std::size_t groups = 1UL); + /// + /// \brief Constructs GroupConvolutionTranspose operation. + /// + /// \param[in] data The node producing input data. + /// \param[in] filters The node producing filters data. + /// \param[in] strides The strides along each feature axis. + /// \param[in] dilations The dilations along each feature axis. + /// \param[in] output_padding The zero-padding (adjustment) added to one side of + /// the + /// output. + /// \param[in] output_shape The output shape. When provided padding values are + /// automatically inferred. + /// \param[in] groups The number of groups the input channels and output + /// channels are divided into. + /// + GroupConvolutionTranspose(const Output& data, + const Output& filters, + const Strides& strides, + const Strides& dilations, + const CoordinateDiff& output_padding, + const Shape& output_shape, + const std::size_t groups = 1UL); - /// - /// \brief Constructs GroupConvolutionTranspose operation. - /// - /// \param[in] data The node producing input data. - /// \param[in] filters The node producing filters data. - /// \param[in] output_shape The output shape. When provided padding values are - /// automatically inferred. - /// \param[in] groups The number of groups the input channels and output - /// channels are divided into. - /// - GroupConvolutionTranspose(const Output& data, - const Output& filters, - const Shape& output_shape, - const std::size_t groups = 1UL); + /// + /// \brief Constructs GroupConvolutionTranspose operation. + /// + /// \param[in] data The node producing input data. + /// \param[in] filters The node producing filters data. + /// \param[in] output_shape The output shape. When provided padding values are + /// automatically inferred. + /// \param[in] groups The number of groups the input channels and output + /// channels are divided into. + /// + GroupConvolutionTranspose(const Output& data, + const Output& filters, + const Shape& output_shape, + const std::size_t groups = 1UL); - Output get_data() { return input_value(0); } - Output get_filters() { return input_value(1); } - const Strides& get_strides() const { return m_strides; } - const Strides& get_dilations() const { return m_dilations; } - const CoordinateDiff& get_padding_begin() const { return m_padding_begin; } - const CoordinateDiff& get_padding_end() const { return m_padding_end; } - const CoordinateDiff& get_output_padding() const { return m_output_padding; } - std::size_t get_groups() const { return m_groups; } - const PadType& get_pad_type() const { return m_pad_type; } - const Shape& get_output_shape() const { return m_output_shape; } - virtual void pre_validate_and_infer_types() override; - virtual void post_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + Output get_data() { return input_value(0); } + Output get_filters() { return input_value(1); } + const Strides& get_strides() const { return m_strides; } + const Strides& get_dilations() const { return m_dilations; } + const CoordinateDiff& get_padding_begin() const { return m_padding_begin; } + const CoordinateDiff& get_padding_end() const { return m_padding_end; } + const CoordinateDiff& get_output_padding() const { return m_output_padding; } + std::size_t get_groups() const { return m_groups; } + const PadType& get_pad_type() const { return m_pad_type; } + const Shape& get_output_shape() const { return m_output_shape; } + virtual void pre_validate_and_infer_types() override; + virtual void post_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - private: - /// - /// \brief Calculate the shape of the data batch from forward propagation. - /// - /// \return The data batch shape. - /// - Shape get_data_batch_shape() const; + private: + /// + /// \brief Calculate the shape of the data batch from forward propagation. + /// + /// \return The data batch shape. + /// + Shape get_data_batch_shape() const; - Strides m_strides; - Strides m_dilations; - CoordinateDiff m_padding_begin; - CoordinateDiff m_padding_end; - CoordinateDiff m_output_padding; - std::size_t m_groups; - PadType m_pad_type; - Shape m_output_shape; - }; + Strides m_strides; + Strides m_dilations; + CoordinateDiff m_padding_begin; + CoordinateDiff m_padding_end; + CoordinateDiff m_output_padding; + std::size_t m_groups; + PadType m_pad_type; + Shape m_output_shape; + }; + } + using v0::GroupConvolutionTranspose; } } diff --git a/src/ngraph/op/fused/gru_cell.hpp b/src/ngraph/op/fused/gru_cell.hpp index 5e805499f6f..dd9cca67bc3 100644 --- a/src/ngraph/op/fused/gru_cell.hpp +++ b/src/ngraph/op/fused/gru_cell.hpp @@ -30,137 +30,152 @@ namespace ngraph { namespace op { - /// - /// \brief Class for GRU cell node. - /// - /// \note It follows notation and equations defined as in ONNX standard: - /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#GRU - /// - /// Note this class represents only single *cell* and not whole GRU *layer*. - /// - class GRUCell : public util::FusedOp, public util::RNNCellBase + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GRUCell", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } /// - /// \brief Constructs GRUCell node. - /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] W The weight tensor with shape: - /// [gates_count * hidden_size, input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [gates_count * hidden_size, hidden_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// - GRUCell(const Output& X, - const Output& W, - const Output& R, - const Output& initial_hidden_state, - std::size_t hidden_size); + /// \brief Class for GRU cell node. + /// + /// \note It follows notation and equations defined as in ONNX standard: + /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#GRU + /// + /// Note this class represents only single *cell* and not whole GRU *layer*. + /// + class NGRAPH_API GRUCell : public util::FusedOp, public util::RNNCellBase + { + public: + static constexpr NodeTypeInfo type_info{"GRUCell", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GRUCell() = default; + /// + /// \brief Constructs GRUCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] W The weight tensor with shape: + /// [gates_count * hidden_size, input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [gates_count * hidden_size, hidden_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// + GRUCell(const Output& X, + const Output& W, + const Output& R, + const Output& initial_hidden_state, + std::size_t hidden_size); - /// - /// \brief Constructs GRUCell node. - /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] W The weight tensor with shape: - /// [gates_count * hidden_size, input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [gates_count * hidden_size, hidden_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// - GRUCell(const Output& X, - const Output& W, - const Output& R, - const Output& initial_hidden_state, - std::size_t hidden_size, - const std::vector& activations, - const std::vector& activations_alpha, - const std::vector& activations_beta, - float clip, - bool linear_before_reset); + /// + /// \brief Constructs GRUCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] W The weight tensor with shape: + /// [gates_count * hidden_size, input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [gates_count * hidden_size, hidden_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// + GRUCell(const Output& X, + const Output& W, + const Output& R, + const Output& initial_hidden_state, + std::size_t hidden_size, + const std::vector& activations, + const std::vector& activations_alpha, + const std::vector& activations_beta, + float clip, + bool linear_before_reset); - /// - /// \brief Constructs GRUCell node. - /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] W The weight tensor with shape: [gates_count * - /// hidden_size, input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [gates_count * hidden_size, hidden_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] B The bias tensor for input gate with shape: - /// [2 * gates_count * hidden_size]. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// \param[in] linear_before_reset Whether or not to apply the linear transformation - /// before multiplying by the output of the reset - /// gate. - /// - GRUCell(const Output& X, - const Output& W, - const Output& R, - const Output& initial_hidden_state, - std::size_t hidden_size, - const Output& B, - const std::vector& activations = - std::vector{"sigmoid", "tanh"}, - const std::vector& activations_alpha = {}, - const std::vector& activations_beta = {}, - float clip = 0.f, - bool linear_before_reset = false); + /// + /// \brief Constructs GRUCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] W The weight tensor with shape: [gates_count * + /// hidden_size, input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [gates_count * hidden_size, hidden_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] B The bias tensor for input gate with shape: + /// [2 * gates_count * hidden_size]. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// \param[in] linear_before_reset Whether or not to apply the linear + /// transformation + /// before multiplying by the output of the reset + /// gate. + /// + GRUCell(const Output& X, + const Output& W, + const Output& R, + const Output& initial_hidden_state, + std::size_t hidden_size, + const Output& B, + const std::vector& activations = + std::vector{"sigmoid", "tanh"}, + const std::vector& activations_alpha = {}, + const std::vector& activations_beta = {}, + float clip = 0.f, + bool linear_before_reset = false); - virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - bool get_linear_before_reset() const { return m_linear_before_reset; } - private: - /// brief Add and initialize bias input to all zeros. - void add_default_bias_input(); + bool get_linear_before_reset() const { return m_linear_before_reset; } + private: + /// brief Add and initialize bias input to all zeros. + void add_default_bias_input(); - /// - /// \brief The Activation function f. - /// - util::ActivationFunction m_activation_f; - /// - /// \brief The Activation function g. - /// - util::ActivationFunction m_activation_g; + /// + /// \brief The Activation function f. + /// + util::ActivationFunction m_activation_f; + /// + /// \brief The Activation function g. + /// + util::ActivationFunction m_activation_g; - static constexpr std::size_t s_gates_count{3}; - /// - /// \brief Control whether or not apply the linear transformation. - /// - /// \note The linear transformation may be applied when computing the output of hidden - /// gate. It's done before multiplying by the output of the reset gate. - /// - bool m_linear_before_reset; - }; + static constexpr std::size_t s_gates_count{3}; + /// + /// \brief Control whether or not apply the linear transformation. + /// + /// \note The linear transformation may be applied when computing the output of + /// hidden + /// gate. It's done before multiplying by the output of the reset gate. + /// + bool m_linear_before_reset; + }; + } + using v0::GRUCell; } } diff --git a/src/ngraph/op/fused/hard_sigmoid.cpp b/src/ngraph/op/fused/hard_sigmoid.cpp index bdf96e4e9c6..7c96c3a6312 100644 --- a/src/ngraph/op/fused/hard_sigmoid.cpp +++ b/src/ngraph/op/fused/hard_sigmoid.cpp @@ -29,41 +29,73 @@ using namespace ngraph; constexpr NodeTypeInfo op::HardSigmoid::type_info; -op::HardSigmoid::HardSigmoid(const Output& data, float alpha, float beta) - : FusedOp({data}) - , m_alpha(alpha) - , m_beta(beta) +op::HardSigmoid::HardSigmoid(const Output& data, + const Output& alpha, + const Output& beta) + : FusedOp({data, alpha, beta}) { constructor_validate_and_infer_types(); } +void op::HardSigmoid::pre_validate_and_infer_types() +{ + const auto& alpha_pshape = get_input_partial_shape(1); + const auto& beta_pshape = get_input_partial_shape(2); + + if (alpha_pshape.is_static()) + { + const auto alpha_shape = alpha_pshape.to_shape(); + NODE_VALIDATION_CHECK(this, + is_scalar(alpha_shape), + "A scalar is expected for the 'alpha' input. Got: ", + alpha_shape); + } + + if (beta_pshape.is_static()) + { + const auto beta_shape = beta_pshape.to_shape(); + NODE_VALIDATION_CHECK(this, + is_scalar(beta_shape), + "A scalar is expected for the 'beta' input. Got: ", + beta_shape); + } + + const auto& data_et = input(0).get_element_type(); + const auto& alpha_et = input(1).get_element_type(); + const auto& beta_et = input(2).get_element_type(); + + NODE_VALIDATION_CHECK( + this, + data_et == alpha_et && data_et == beta_et, + "The element types of both alpha and beta inputs must match the data input type."); +} + NodeVector op::HardSigmoid::decompose_op() const { - auto data = input_value(0); - auto data_shape = data.get_shape(); - size_t elem_count = shape_size(data_shape); + const auto data = input_value(0); + + const auto one_node = + ngraph::op::Constant::create(data.get_element_type(), data.get_shape(), {1.0f}); - std::shared_ptr alpha_node = ngraph::op::Constant::create( - data.get_element_type(), data_shape, std::vector(elem_count, m_alpha)); + const auto zero_node = + ngraph::op::Constant::create(data.get_element_type(), data.get_shape(), {0.0f}); - std::shared_ptr beta_node = ngraph::op::Constant::create( - data.get_element_type(), data_shape, std::vector(elem_count, m_beta)); + const auto alpha_node = input_value(1).get_node_shared_ptr(); + const auto beta_node = input_value(2).get_node_shared_ptr(); - std::shared_ptr one_node = ngraph::op::Constant::create( - data.get_element_type(), data_shape, std::vector(elem_count, 1.0)); + std::shared_ptr alpha_x_plus_beta = + std::make_shared(alpha_node, data, AutoBroadcastType::NUMPY); - std::shared_ptr zero_node = ngraph::op::Constant::create( - data.get_element_type(), data_shape, std::vector(elem_count, 0.0)); + alpha_x_plus_beta = + std::make_shared(alpha_x_plus_beta, beta_node, AutoBroadcastType::NUMPY); - return {std::make_shared( - std::make_shared(alpha_node * data + beta_node, zero_node), one_node)}; + return {std::make_shared( + std::make_shared(alpha_x_plus_beta, zero_node), one_node)}; } shared_ptr op::HardSigmoid::copy_with_new_args(const NodeVector& new_args) const { - if (new_args.size() != 1) - { - throw ngraph_error("Incorrect number of new arguments"); - } - return make_shared(new_args.at(0), m_alpha, m_beta); + check_new_args_count(this, new_args); + + return make_shared(new_args.at(0), new_args.at(1), new_args.at(2)); } diff --git a/src/ngraph/op/fused/hard_sigmoid.hpp b/src/ngraph/op/fused/hard_sigmoid.hpp index f3dd97517a3..ac5ea7ecf8c 100644 --- a/src/ngraph/op/fused/hard_sigmoid.hpp +++ b/src/ngraph/op/fused/hard_sigmoid.hpp @@ -24,33 +24,34 @@ namespace ngraph { namespace op { - /// \brief Parameterized, bounded sigmoid-like, piecewise linear - /// function. min(max(alpha*x + beta, 0), 1) - /// - class HardSigmoid : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"HardSigmoid", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - HardSigmoid() = default; - /// \brief Constructs a HardSigmoid operation. + /// \brief Parameterized, bounded sigmoid-like, piecewise linear + /// function. min(max(alpha*x + beta, 0), 1) /// - /// \param data Input tensor. - /// \param[in] alpha The alpha parameter. - /// \param[in] beta The beta parameter. - /// - HardSigmoid(const Output& data, float alpha, float beta); + class NGRAPH_API HardSigmoid : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"HardSigmoid", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + HardSigmoid() = default; - virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + /// \brief Constructs a HardSigmoid operation. + /// + /// \param data Input tensor. + /// \param[in] alpha A scalar value representing the alpha parameter. + /// \param[in] beta A scalar value representing the beta parameter. + /// + HardSigmoid(const Output& data, + const Output& alpha, + const Output& beta); - float get_alpha() const { return m_alpha; } - float get_beta() const { return m_beta; } - private: - float m_alpha; - float m_beta; - }; + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::HardSigmoid; } } diff --git a/src/ngraph/op/fused/layer_norm.cpp b/src/ngraph/op/fused/layer_norm.cpp index 8f675f76e54..13fe18d55b2 100644 --- a/src/ngraph/op/fused/layer_norm.cpp +++ b/src/ngraph/op/fused/layer_norm.cpp @@ -170,7 +170,7 @@ shared_ptr op::LayerNorm::copy_with_new_args(const NodeVector& new_args) c } } -void op::LayerNorm::pre_validate_and_infer_types() +void op::LayerNorm::validate_and_infer_types() { element::Type input_element_type = get_input_element_type(0); @@ -509,7 +509,7 @@ shared_ptr op::LayerNormBackprop::copy_with_new_args(const NodeVector& new } } -void op::LayerNormBackprop::pre_validate_and_infer_types() +void op::LayerNormBackprop::validate_and_infer_types() { element::Type input_element_type = get_input_element_type(0); diff --git a/src/ngraph/op/fused/layer_norm.hpp b/src/ngraph/op/fused/layer_norm.hpp index 919b4d645b4..de9d694cc59 100644 --- a/src/ngraph/op/fused/layer_norm.hpp +++ b/src/ngraph/op/fused/layer_norm.hpp @@ -24,117 +24,120 @@ namespace ngraph { namespace op { - /// \brief Layer Normalization - /// - class LayerNorm : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"LayerNorm", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - LayerNorm() = default; - /// \brief Constructs an LayerNorm operation. + /// \brief Layer Normalization /// - /// \param data Input tensor - /// \param scale Scale tensor - /// \param bias Bias tensor - /// \param keep_stats Generated addition output mean and variance, default true - /// \param begin_norm_axis Axis where normalization starts, default - -1 - /// \param epsilon Small number to add for stability of rsqrt, default 1e-5 - LayerNorm(const Output& data, - const Output& scale, - const Output& bias, - bool keep_stats = true, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - LayerNorm(const Output& data, - bool keep_stats = true, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - virtual NodeVector decompose_op() const override; - - void pre_validate_and_infer_types() override; - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - bool get_keep_stats() const { return m_keep_stats; } - bool get_use_affine() const { return m_use_affine; } - double get_epsilon() const { return m_epsilon; } - int64_t get_begin_norm_axis() const { return m_begin_norm_axis; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - - private: - bool m_keep_stats{true}; - bool m_use_affine{true}; - int64_t m_begin_norm_axis{1}; - double m_epsilon{1e-5}; - }; - - /// \brief Layer Normalization Backprop - /// - class LayerNormBackprop : public ngraph::op::util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"LayerNormBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - LayerNormBackprop() = default; - /// \brief Constructs an LayerNormBackprop operation. + class NGRAPH_API LayerNorm : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"LayerNorm", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + LayerNorm() = default; + /// \brief Constructs an LayerNorm operation. + /// + /// \param data Input tensor + /// \param scale Scale tensor + /// \param bias Bias tensor + /// \param keep_stats Generated addition output mean and variance, default true + /// \param begin_norm_axis Axis where normalization starts, default - -1 + /// \param epsilon Small number to add for stability of rsqrt, default 1e-5 + LayerNorm(const Output& data, + const Output& scale, + const Output& bias, + bool keep_stats = true, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + LayerNorm(const Output& data, + bool keep_stats = true, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + virtual NodeVector decompose_op() const override; + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + bool get_keep_stats() const { return m_keep_stats; } + bool get_use_affine() const { return m_use_affine; } + double get_epsilon() const { return m_epsilon; } + int64_t get_begin_norm_axis() const { return m_begin_norm_axis; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + private: + bool m_keep_stats{true}; + bool m_use_affine{true}; + int64_t m_begin_norm_axis{1}; + double m_epsilon{1e-5}; + }; + + /// \brief Layer Normalization Backprop /// - /// \param data Input tensor - /// \param mean Mean tensor from fprop - /// \param variance Variance tensor from fprop - /// \param delta Delta tensor - /// \param scale Scale tensor - /// \param begin_norm_axis Axis where normalization starts, default - -1 - /// \param epsilon Small number to add for stability of rsqrt, default 1e-5 - LayerNormBackprop(const Output& data, - const Output& delta, - const Output& mean, - const Output& variance, - const Output& scale, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - LayerNormBackprop(const Output& data, - const Output& delta, - const Output& mean, - const Output& variance, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - LayerNormBackprop(const Output& data, - const Output& delta, - const Output& scale, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - LayerNormBackprop(const Output& data, - const Output& delta, - int64_t begin_norm_axis = 1, - double epsilon = 1e-5); - - virtual NodeVector decompose_op() const override; - - void pre_validate_and_infer_types() override; - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - bool get_use_stats() const { return m_use_stats; } - bool get_use_affine() const { return m_use_affine; } - double get_epsilon() const { return m_epsilon; } - int64_t get_begin_norm_axis() const { return m_begin_norm_axis; } - private: - bool m_use_stats{true}; - bool m_use_affine{true}; - int64_t m_begin_norm_axis{1}; - double m_epsilon{1e-5}; - }; + class NGRAPH_API LayerNormBackprop : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"LayerNormBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + LayerNormBackprop() = default; + /// \brief Constructs an LayerNormBackprop operation. + /// + /// \param data Input tensor + /// \param mean Mean tensor from fprop + /// \param variance Variance tensor from fprop + /// \param delta Delta tensor + /// \param scale Scale tensor + /// \param begin_norm_axis Axis where normalization starts, default - -1 + /// \param epsilon Small number to add for stability of rsqrt, default 1e-5 + LayerNormBackprop(const Output& data, + const Output& delta, + const Output& mean, + const Output& variance, + const Output& scale, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + LayerNormBackprop(const Output& data, + const Output& delta, + const Output& mean, + const Output& variance, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + LayerNormBackprop(const Output& data, + const Output& delta, + const Output& scale, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + LayerNormBackprop(const Output& data, + const Output& delta, + int64_t begin_norm_axis = 1, + double epsilon = 1e-5); + + virtual NodeVector decompose_op() const override; + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + bool get_use_stats() const { return m_use_stats; } + bool get_use_affine() const { return m_use_affine; } + double get_epsilon() const { return m_epsilon; } + int64_t get_begin_norm_axis() const { return m_begin_norm_axis; } + private: + bool m_use_stats{true}; + bool m_use_affine{true}; + int64_t m_begin_norm_axis{1}; + double m_epsilon{1e-5}; + }; + } + using v0::LayerNorm; + using v0::LayerNormBackprop; } } diff --git a/src/ngraph/op/fused/log_softmax.cpp b/src/ngraph/op/fused/log_softmax.cpp new file mode 100644 index 00000000000..4807fe61be2 --- /dev/null +++ b/src/ngraph/op/fused/log_softmax.cpp @@ -0,0 +1,54 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/fused/log_softmax.hpp" +#include "ngraph/op/log.hpp" +#include "ngraph/op/softmax.hpp" +#include "ngraph/validation_util.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::LogSoftmax::type_info; + +op::LogSoftmax::LogSoftmax(const Output& data, int64_t axis) + : FusedOp({data}) + , m_axis(axis) +{ + constructor_validate_and_infer_types(); +} + +NodeVector op::LogSoftmax::decompose_op() const +{ + const auto data = input_value(0); + const auto data_shape = data.get_shape(); + + auto axis = ngraph::normalize_axis(this, m_axis, data_shape.size()); + + std::vector axes(data_shape.size() - axis); + std::iota(std::begin(axes), std::end(axes), axis); + + auto softmax = std::make_shared(data, axes); + + return {std::make_shared(softmax)}; +} + +shared_ptr op::LogSoftmax::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), m_axis); +} diff --git a/src/ngraph/op/fused/log_softmax.hpp b/src/ngraph/op/fused/log_softmax.hpp new file mode 100644 index 00000000000..781771be95b --- /dev/null +++ b/src/ngraph/op/fused/log_softmax.hpp @@ -0,0 +1,54 @@ +//***************************************************************************** +// Copyright 2017-2019 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/node.hpp" +#include "ngraph/op/op.hpp" +#include "ngraph/op/util/fused_op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v0 + { + /// \brief LogSoftmax operation + class NGRAPH_API LogSoftmax : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"LogSoftmax", 0}; + LogSoftmax() = default; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a LogSoftmax node. + /// + /// \param data Node that produces the first input tensor + /// \param axis Describes the axis of the inputs when coerced to 2D + LogSoftmax(const Output& data, int64_t axis); + + virtual NodeVector decompose_op() const override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + int64_t get_axis() const { return m_axis; } + protected: + int64_t m_axis; + }; + } + using v0::LogSoftmax; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/op/fused/lstm_cell.hpp b/src/ngraph/op/fused/lstm_cell.hpp index c1d84debb57..e8b737d56c5 100644 --- a/src/ngraph/op/fused/lstm_cell.hpp +++ b/src/ngraph/op/fused/lstm_cell.hpp @@ -40,225 +40,248 @@ namespace ngraph IOFC, // ONNX }; - /// - /// \brief Class for single lstm cell node. - /// - /// \note Following implementation supports: - /// \li \c peepholes Gers & Schmidhuber (2000) - /// https://ieeexplore.ieee.org/document/861302 - /// \li Coupling input and forget gates. - /// - /// \note It calculates following equations: - /// - /// it = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Pi (.) Ct-1 + Wbi + Rbi) - /// ft = f(Xt*(Wf^T) + Ht-1*(Rf^T) + Pf (.) Ct-1 + Wbf + Rbf) - /// ct = g(Xt*(Wc^T) + Ht-1*(Rc^T) + Wbc + Rbc) - /// Ct = ft (.) Ct-1 + it (.) ct - /// ot = f(Xt*(Wo^T) + Ht-1*(Ro^T) + Po (.) Ct + Wbo + Rbo) - /// Ht = ot (.) h(Ct) - /// - /// * - Is a dot product, - /// (.) - is a Hadamard product (element-wise), - /// f, g, h - are activation functions. - /// - /// \note This class represents only single *cell* (for current time step) and not the - /// whole LSTM Sequence layer - /// - /// \sa LSTMSequence, RNNCell, GRUCell - /// - class LSTMCell : public util::FusedOp, public util::RNNCellBase + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"LSTMCell", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } /// - /// \brief Constructs LSTMCell node. + /// \brief Class for single lstm cell node. /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] initial_cell_state The cell state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] W The gate weights tensor with shape: - /// [4*hidden_size, - /// input_size]. - /// \param[in] R The recurrence weights tensor with shape: - /// [4*hidden_size, hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] weights_format The order of gates in weights tensors. The default - /// format is IFCO since it is used by DNNL. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// \param[in] input_forget Controls coupling input and forget gates. + /// \note Following implementation supports: + /// \li \c peepholes Gers & Schmidhuber (2000) + /// https://ieeexplore.ieee.org/document/861302 + /// \li Coupling input and forget gates. /// - LSTMCell(const Output& X, - const Output& initial_hidden_state, - const Output& initial_cell_state, - const Output& W, - const Output& R, - std::size_t hidden_size, - LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, - const std::vector& activations = - std::vector{"sigmoid", "tanh", "tanh"}, - const std::vector& activations_alpha = {}, - const std::vector& activations_beta = {}, - float clip = 0.f, - bool input_forget = false); - - /// - /// \brief Constructs LSTMCell node. + /// \note It calculates following equations: /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] initial_cell_state The cell state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] W The weight tensor with shape: [4*hidden_size, - /// input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [4*hidden_size, hidden_size]. - /// \param[in] B The bias tensor for gates with shape: - /// [4*hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] weights_format The order of gates in weights tensors. The default - /// format is IFCO since it is used by DNNL. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// \param[in] input_forget Controls coupling input and forget gates. + /// it = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Pi (.) Ct-1 + Wbi + Rbi) + /// ft = f(Xt*(Wf^T) + Ht-1*(Rf^T) + Pf (.) Ct-1 + Wbf + Rbf) + /// ct = g(Xt*(Wc^T) + Ht-1*(Rc^T) + Wbc + Rbc) + /// Ct = ft (.) Ct-1 + it (.) ct + /// ot = f(Xt*(Wo^T) + Ht-1*(Ro^T) + Po (.) Ct + Wbo + Rbo) + /// Ht = ot (.) h(Ct) /// - LSTMCell(const Output& X, - const Output& initial_hidden_state, - const Output& initial_cell_state, - const Output& W, - const Output& R, - const Output& B, - std::size_t hidden_size, - LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, - const std::vector& activations = - std::vector{"sigmoid", "tanh", "tanh"}, - const std::vector& activations_alpha = {}, - const std::vector& activations_beta = {}, - float clip = 0.f, - bool input_forget = false); - + /// * - Is a dot product, + /// (.) - is a Hadamard product (element-wise), + /// f, g, h - are activation functions. /// - /// \brief Constructs LSTMCell node. + /// \note This class represents only single *cell* (for current time step) and not + /// the + /// whole LSTM Sequence layer /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] initial_cell_state The cell state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] W The weight tensor with shape: [4*hidden_size, - /// input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [4*hidden_size, hidden_size]. - /// \param[in] B The bias tensor for gates with shape: - /// [4*hidden_size]. - /// \param[in] P The weight tensor for peepholes with shape: - /// [3*hidden_size] - 3 equals to only iof gates. - /// The order is: input, output, forget gates. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] weights_format The order of gates in weights tensors. The default - /// format is IFCO since it is used by DNNL. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// \param[in] input_forget Controls coupling input and forget gates. + /// \sa LSTMSequence, RNNCell, GRUCell /// - LSTMCell(const Output& X, - const Output& initial_hidden_state, - const Output& initial_cell_state, - const Output& W, - const Output& R, - const Output& B, - const Output& P, - std::size_t hidden_size, - LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, - const std::vector& activations = - std::vector{"sigmoid", "tanh", "tanh"}, - const std::vector& activations_alpha = {}, - const std::vector& activations_beta = {}, - float clip = 0.f, - bool input_forget = false); + class NGRAPH_API LSTMCell : public util::FusedOp, public util::RNNCellBase + { + public: + static constexpr NodeTypeInfo type_info{"LSTMCell", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + LSTMCell() = default; + /// + /// \brief Constructs LSTMCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] initial_cell_state The cell state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] W The gate weights tensor with shape: + /// [4*hidden_size, + /// input_size]. + /// \param[in] R The recurrence weights tensor with shape: + /// [4*hidden_size, hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] weights_format The order of gates in weights tensors. The + /// default + /// format is IFCO since it is used by DNNL. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// \param[in] input_forget Controls coupling input and forget gates. + /// + LSTMCell(const Output& X, + const Output& initial_hidden_state, + const Output& initial_cell_state, + const Output& W, + const Output& R, + std::size_t hidden_size, + LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, + const std::vector& activations = + std::vector{"sigmoid", "tanh", "tanh"}, + const std::vector& activations_alpha = {}, + const std::vector& activations_beta = {}, + float clip = 0.f, + bool input_forget = false); - virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + /// + /// \brief Constructs LSTMCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] initial_cell_state The cell state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] W The weight tensor with shape: [4*hidden_size, + /// input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [4*hidden_size, hidden_size]. + /// \param[in] B The bias tensor for gates with shape: + /// [4*hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] weights_format The order of gates in weights tensors. The + /// default + /// format is IFCO since it is used by DNNL. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// \param[in] input_forget Controls coupling input and forget gates. + /// + LSTMCell(const Output& X, + const Output& initial_hidden_state, + const Output& initial_cell_state, + const Output& W, + const Output& R, + const Output& B, + std::size_t hidden_size, + LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, + const std::vector& activations = + std::vector{"sigmoid", "tanh", "tanh"}, + const std::vector& activations_alpha = {}, + const std::vector& activations_beta = {}, + float clip = 0.f, + bool input_forget = false); - bool get_input_forget() const { return m_input_forget; } - LSTMWeightsFormat get_weights_format() const { return m_weights_format; } - /// - /// \brief Change data format of provided node into IFCO. - /// - /// \node The IFCO format was chosen because it's default DNNL format. - /// - /// \param[in] node The input node to be permuted. - /// - /// \return Node representing reshaped tensor according to IFCO weights format. - /// - std::shared_ptr convert_node_format(const Output& node) const; + /// + /// \brief Constructs LSTMCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] initial_cell_state The cell state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] W The weight tensor with shape: [4*hidden_size, + /// input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [4*hidden_size, hidden_size]. + /// \param[in] B The bias tensor for gates with shape: + /// [4*hidden_size]. + /// \param[in] P The weight tensor for peepholes with shape: + /// [3*hidden_size] - 3 equals to only iof gates. + /// The order is: input, output, forget gates. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] weights_format The order of gates in weights tensors. The + /// default + /// format is IFCO since it is used by DNNL. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// \param[in] input_forget Controls coupling input and forget gates. + /// + LSTMCell(const Output& X, + const Output& initial_hidden_state, + const Output& initial_cell_state, + const Output& W, + const Output& R, + const Output& B, + const Output& P, + std::size_t hidden_size, + LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, + const std::vector& activations = + std::vector{"sigmoid", "tanh", "tanh"}, + const std::vector& activations_alpha = {}, + const std::vector& activations_beta = {}, + float clip = 0.f, + bool input_forget = false); - private: - /// - /// \brief Creates the default bias input initialized with zeros. - /// - /// \return The object of Output class. - /// - Output get_default_bias_input() const; + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - /// - /// \brief Creates the default peepholes input initialized with zeros. - /// - /// \return The object of Output class. - /// - Output get_default_peepholes_input() const; - /// - /// \brief The Activation function f. - /// - util::ActivationFunction m_activation_f; - /// - /// \brief The Activation function g. - /// - util::ActivationFunction m_activation_g; - /// - /// \brief The Activation function h. - /// - util::ActivationFunction m_activation_h; - /// - /// \brief Controls whether to couple input and forget gates. - /// - bool m_input_forget = false; + bool get_input_forget() const { return m_input_forget; } + LSTMWeightsFormat get_weights_format() const { return m_weights_format; } + /// + /// \brief Change data format of provided node into IFCO. + /// + /// \node The IFCO format was chosen because it's default DNNL format. + /// + /// \param[in] node The input node to be permuted. + /// + /// \return Node representing reshaped tensor according to IFCO weights format. + /// + std::shared_ptr convert_node_format(const Output& node) const; - /// - /// \brief The order of gates in weights tensors. - /// - LSTMWeightsFormat m_weights_format; + private: + /// + /// \brief Creates the default bias input initialized with zeros. + /// + /// \return The object of Output class. + /// + Output get_default_bias_input() const; - static constexpr std::size_t s_gates_count{4}; - static constexpr std::size_t s_peepholes_count{3}; - }; + /// + /// \brief Creates the default peepholes input initialized with zeros. + /// + /// \return The object of Output class. + /// + Output get_default_peepholes_input() const; + /// + /// \brief The Activation function f. + /// + util::ActivationFunction m_activation_f; + /// + /// \brief The Activation function g. + /// + util::ActivationFunction m_activation_g; + /// + /// \brief The Activation function h. + /// + util::ActivationFunction m_activation_h; + /// + /// \brief Controls whether to couple input and forget gates. + /// + bool m_input_forget = false; + + /// + /// \brief The order of gates in weights tensors. + /// + LSTMWeightsFormat m_weights_format; + + static constexpr std::size_t s_gates_count{4}; + static constexpr std::size_t s_peepholes_count{3}; + }; + } + using v0::LSTMCell; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/lstm_sequence.hpp b/src/ngraph/op/fused/lstm_sequence.hpp index 15415572612..943def72e6c 100644 --- a/src/ngraph/op/fused/lstm_sequence.hpp +++ b/src/ngraph/op/fused/lstm_sequence.hpp @@ -31,148 +31,158 @@ namespace ngraph { namespace op { - /// - /// \brief Class for lstm sequence node. - /// - /// \note It follows notation and equations defined as in ONNX standard: - /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#LSTM - /// - /// \sa LSTMCell, RNNCell, GRUCell - /// - /// - class LSTMSequence : public util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"LSTMSequence", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - LSTMSequence() = default; - - enum class direction + /// + /// \brief Class for lstm sequence node. + /// + /// \note It follows notation and equations defined as in ONNX standard: + /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#LSTM + /// + /// \sa LSTMCell, RNNCell, GRUCell + /// + /// + class NGRAPH_API LSTMSequence : public util::FusedOp { - FORWARD, - REVERSE, - BIDIRECTIONAL - }; + public: + static constexpr NodeTypeInfo type_info{"LSTMSequence", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + LSTMSequence() = default; - explicit LSTMSequence(const Output& X, - const Output& initial_hidden_state, - const Output& initial_cell_state, - const Output& sequence_lengths, - const Output& W, - const Output& R, - const Output& B, - const Output& P, - const std::int64_t hidden_size, - const direction lstm_direction, - LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, - const std::vector activations_alpha = {}, - const std::vector activations_beta = {}, - const std::vector activations = {"sigmoid", - "tanh", - "tanh"}, - const float clip_threshold = 0, - const bool input_forget = false) - : FusedOp( - {X, initial_hidden_state, initial_cell_state, sequence_lengths, W, R, B, P}) - , m_activations_alpha(activations_alpha) - , m_activations_beta(activations_beta) - , m_activations(activations) - , m_clip_threshold(clip_threshold) - , m_direction(lstm_direction) - , m_hidden_size(hidden_size) - , m_input_forget(input_forget) - , m_weights_format(weights_format) - { - constructor_validate_and_infer_types(); - } + enum class direction + { + FORWARD, + REVERSE, + BIDIRECTIONAL + }; - explicit LSTMSequence(const Output& X, - const Output& initial_hidden_state, - const Output& initial_cell_state, - const Output& sequence_lengths, - const Output& W, - const Output& R, - const Output& B, - const std::int64_t hidden_size, - const direction lstm_direction, - LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, - const std::vector activations_alpha = {}, - const std::vector activations_beta = {}, - const std::vector activations = {"sigmoid", - "tanh", - "tanh"}, - const float clip_threshold = 0, - const bool input_forget = false) - : LSTMSequence(X, + explicit LSTMSequence(const Output& X, + const Output& initial_hidden_state, + const Output& initial_cell_state, + const Output& sequence_lengths, + const Output& W, + const Output& R, + const Output& B, + const Output& P, + const std::int64_t hidden_size, + const direction lstm_direction, + LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, + const std::vector activations_alpha = {}, + const std::vector activations_beta = {}, + const std::vector activations = {"sigmoid", + "tanh", + "tanh"}, + const float clip_threshold = 0, + const bool input_forget = false) + : FusedOp({X, initial_hidden_state, initial_cell_state, sequence_lengths, W, R, B, - Constant::create( - element::f32, - Shape{(lstm_direction == direction::BIDIRECTIONAL ? 2UL : 1UL), - 3UL * static_cast(hidden_size)}, - std::vector{0.f}), - hidden_size, - lstm_direction, - weights_format, - activations_alpha, - activations_beta, - activations, - clip_threshold, - input_forget) - { - } + P}) + , m_activations_alpha(activations_alpha) + , m_activations_beta(activations_beta) + , m_activations(activations) + , m_clip_threshold(clip_threshold) + , m_direction(lstm_direction) + , m_hidden_size(hidden_size) + , m_input_forget(input_forget) + , m_weights_format(weights_format) + { + constructor_validate_and_infer_types(); + } - virtual NodeVector decompose_op() const override; + explicit LSTMSequence(const Output& X, + const Output& initial_hidden_state, + const Output& initial_cell_state, + const Output& sequence_lengths, + const Output& W, + const Output& R, + const Output& B, + const std::int64_t hidden_size, + const direction lstm_direction, + LSTMWeightsFormat weights_format = LSTMWeightsFormat::IFCO, + const std::vector activations_alpha = {}, + const std::vector activations_beta = {}, + const std::vector activations = {"sigmoid", + "tanh", + "tanh"}, + const float clip_threshold = 0, + const bool input_forget = false) + : LSTMSequence( + X, + initial_hidden_state, + initial_cell_state, + sequence_lengths, + W, + R, + B, + Constant::create( + element::f32, + Shape{(lstm_direction == direction::BIDIRECTIONAL ? 2UL : 1UL), + 3UL * static_cast(hidden_size)}, + std::vector{0.f}), + hidden_size, + lstm_direction, + weights_format, + activations_alpha, + activations_beta, + activations, + clip_threshold, + input_forget) + { + } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual NodeVector decompose_op() const override; - std::vector get_activations_alpha() const { return m_activations_alpha; } - std::vector get_activations_beta() const { return m_activations_beta; } - std::vector get_activations() const { return m_activations; } - float get_clip_threshold() const { return m_clip_threshold; } - direction get_direction() const { return m_direction; } - std::int64_t get_hidden_size() const { return m_hidden_size; } - bool get_input_forget() const { return m_input_forget; } - LSTMWeightsFormat get_weights_format() const { return m_weights_format; } - private: - /// - /// \brief Gets the masked value according to sequence lenght in a batch. - /// - /// \note Zeros out values or sets them to default value for inputs with - /// sequence lenght shorter than currently procssed time step. - /// - /// \param[in] data The input value. - /// \param[in] time_step The current time step denoting sequence lenght. - /// \param[in] batch_axis The batch axis index of data tensor. - /// \param[in] default_value The default value for masked elements. - /// - /// \return The masked value. - /// - std::shared_ptr get_masked_node(const std::shared_ptr& data, - std::int32_t time_step, - std::size_t batch_axis = 0, - const std::shared_ptr& default_value = { - nullptr}) const; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - NodeVector lstm_pass(bool is_reverse = false) const; + std::vector get_activations_alpha() const { return m_activations_alpha; } + std::vector get_activations_beta() const { return m_activations_beta; } + std::vector get_activations() const { return m_activations; } + float get_clip_threshold() const { return m_clip_threshold; } + direction get_direction() const { return m_direction; } + std::int64_t get_hidden_size() const { return m_hidden_size; } + bool get_input_forget() const { return m_input_forget; } + LSTMWeightsFormat get_weights_format() const { return m_weights_format; } + private: + /// + /// \brief Gets the masked value according to sequence lenght in a batch. + /// + /// \note Zeros out values or sets them to default value for inputs with + /// sequence lenght shorter than currently procssed time step. + /// + /// \param[in] data The input value. + /// \param[in] time_step The current time step denoting sequence lenght. + /// \param[in] batch_axis The batch axis index of data tensor. + /// \param[in] default_value The default value for masked elements. + /// + /// \return The masked value. + /// + std::shared_ptr get_masked_node(const std::shared_ptr& data, + std::int32_t time_step, + std::size_t batch_axis = 0, + const std::shared_ptr& default_value = { + nullptr}) const; - // Split(bi-directional) and squeeze input data to remove 'num_direction' dimension. - std::shared_ptr prepare_input(Output node, bool is_reverse) const; + NodeVector lstm_pass(bool is_reverse = false) const; - std::vector m_activations_alpha; - std::vector m_activations_beta; - std::vector m_activations; - float m_clip_threshold; - direction m_direction; - std::int64_t m_hidden_size; - bool m_input_forget; - LSTMWeightsFormat m_weights_format; - }; + // Split(bi-directional) and squeeze input data to remove 'num_direction' dimension. + std::shared_ptr prepare_input(Output node, bool is_reverse) const; + + std::vector m_activations_alpha; + std::vector m_activations_beta; + std::vector m_activations; + float m_clip_threshold; + direction m_direction; + std::int64_t m_hidden_size; + bool m_input_forget; + LSTMWeightsFormat m_weights_format; + }; + } + using v0::LSTMSequence; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/matmul.cpp b/src/ngraph/op/fused/matmul.cpp index b8dec48266d..00e80fccb09 100644 --- a/src/ngraph/op/fused/matmul.cpp +++ b/src/ngraph/op/fused/matmul.cpp @@ -64,25 +64,10 @@ NodeVector op::MatMul::decompose_op() const auto A = input_value(0); auto B = input_value(1); - // Specification is expecting that A & B have at least 2 dimenstions. - // Missing dimensions are padded with 1. - int a_rank = A.get_shape().size(); - if (a_rank < 2) - { - A = a_rank == 0 ? make_shared(A, AxisVector{}, Shape{1, 1}) - : make_shared(A, AxisVector{1}, Shape{1, A.get_shape()[0]}); - a_rank = 2; - } - - int b_rank = B.get_shape().size(); - if (b_rank < 2) - { - B = b_rank == 0 ? make_shared(B, AxisVector{}, Shape{1, 1}) - : make_shared(B, AxisVector{1}, Shape{1, B.get_shape()[0]}); - b_rank = 2; - } + const auto a_rank = A.get_shape().size(); + const auto b_rank = B.get_shape().size(); - if (m_transpose_a) + if (m_transpose_a && a_rank >= 2) { vector axes_order(a_rank); // generate default axes_order. @@ -92,7 +77,7 @@ NodeVector op::MatMul::decompose_op() const A = builder::reorder_axes(A, axes_order); } - if (m_transpose_b) + if (m_transpose_b && b_rank >= 2) { vector axes_order(b_rank); iota(axes_order.begin(), axes_order.end(), 0); diff --git a/src/ngraph/op/fused/matmul.hpp b/src/ngraph/op/fused/matmul.hpp index c45d4e9addb..deae522a58e 100644 --- a/src/ngraph/op/fused/matmul.hpp +++ b/src/ngraph/op/fused/matmul.hpp @@ -24,37 +24,40 @@ namespace ngraph { namespace op { - /// \brief Operator performing Matrix Multiplication. - class MatMul : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"MatMul", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - MatMul() = default; - /// \brief Constructs an ScaleShift operation. - /// - /// \param A Matrix A - /// \param B Matrix B - /// \param transpose_a If matrix A should be transposed. - /// \param transpose_b If matrix B should be transposed. - MatMul(const Output& A, - const Output& B, - const bool& transpose_a = 0, - const bool& transpose_b = 0); + /// \brief Operator performing Matrix Multiplication. + class NGRAPH_API MatMul : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"MatMul", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + MatMul() = default; + /// \brief Constructs an ScaleShift operation. + /// + /// \param A Matrix A + /// \param B Matrix B + /// \param transpose_a If matrix A should be transposed. + /// \param transpose_b If matrix B should be transposed. + MatMul(const Output& A, + const Output& B, + const bool& transpose_a = 0, + const bool& transpose_b = 0); - virtual void pre_validate_and_infer_types() override; + virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - bool get_transpose_a() const { return m_transpose_a; } - bool get_transpose_b() const { return m_transpose_b; } - private: - bool m_transpose_a; - bool m_transpose_b; - }; + bool get_transpose_a() const { return m_transpose_a; } + bool get_transpose_b() const { return m_transpose_b; } + private: + bool m_transpose_a; + bool m_transpose_b; + }; + } + using v0::MatMul; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/mod.cpp b/src/ngraph/op/fused/mod.cpp new file mode 100644 index 00000000000..be9666dc1b9 --- /dev/null +++ b/src/ngraph/op/fused/mod.cpp @@ -0,0 +1,61 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/fused/mod.hpp" +#include "ngraph/builder/make_constant.hpp" +#include "ngraph/op/abs.hpp" +#include "ngraph/op/convert.hpp" +#include "ngraph/op/divide.hpp" +#include "ngraph/op/multiply.hpp" +#include "ngraph/op/sign.hpp" +#include "ngraph/op/subtract.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::Mod::type_info; + +op::v1::Mod::Mod(const Output& A, + const Output& B, + const AutoBroadcastSpec& auto_broadcast) + : FusedOp({A, B}) + , m_auto_broadcast(auto_broadcast) +{ +} + +NodeVector op::v1::Mod::decompose_op() const +{ + const auto dividend = make_shared(input_value(0)); + const auto dividend_sign = make_shared(input_value(0)); + const auto dividend_et = dividend->get_element_type(); + const auto divisor = make_shared(input_value(1)); + + // truncated(a / b) + auto division = make_shared( + make_shared(dividend, divisor, m_auto_broadcast), ngraph::element::i64); + division = make_shared(division, dividend_et); + // truncated(a / b) * b + const auto multiplication = make_shared(division, divisor, m_auto_broadcast); + // a mod b = a - truncated(a / b) * b + const auto mod = make_shared(dividend, multiplication, m_auto_broadcast); + + // apply sign of dividend + return {make_shared(dividend_sign, mod, m_auto_broadcast)}; +} + +shared_ptr op::v1::Mod::copy_with_new_args(const NodeVector& new_args) const +{ + return make_shared(new_args.at(0), new_args.at(1), m_auto_broadcast); +} diff --git a/src/ngraph/op/fused/mod.hpp b/src/ngraph/op/fused/mod.hpp new file mode 100644 index 00000000000..993b5c6e6d8 --- /dev/null +++ b/src/ngraph/op/fused/mod.hpp @@ -0,0 +1,62 @@ +//***************************************************************************** +// Copyright 2017-2019 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/node.hpp" +#include "ngraph/op/op.hpp" +#include "ngraph/op/util/fused_op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Mod returns an element-wise division reminder with two given tensors applying + /// multi-directional broadcast rules. + class NGRAPH_API Mod : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Mod", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Mod() = default; + /// \brief Constructs a Mod node. + /// + /// \param A - Dividend tensor + /// \param B - Divisor tensor + /// \param auto_broadcast Auto broadcast specification + Mod(const Output& A, + const Output& B, + const AutoBroadcastSpec& auto_broadcast = AutoBroadcastType::NUMPY); + + virtual NodeVector decompose_op() const override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + const AutoBroadcastSpec& get_auto_broadcast() const { return m_auto_broadcast; } + private: + AutoBroadcastSpec m_auto_broadcast; + }; + } + + namespace v0 + { + using v1::Mod; + } + } +} diff --git a/src/ngraph/op/fused/mvn.hpp b/src/ngraph/op/fused/mvn.hpp index c2ab0de761a..64813abe8b1 100644 --- a/src/ngraph/op/fused/mvn.hpp +++ b/src/ngraph/op/fused/mvn.hpp @@ -24,59 +24,63 @@ namespace ngraph { namespace op { - /// \brief Operator performing Mean Variance Normalization - /// - class MVN : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"MVN", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - MVN() = default; - /// \brief Constructs an MVN operation. + /// \brief Operator performing Mean Variance Normalization /// - /// \param data Input tensor with data - /// \param normalize_variance flag that denotes whether to perform variance - /// normalization. - /// \param across_channels flag that denotes if mean values are shared across channels. - /// \param eps the number to be added to the variance to avoid division by zero when - /// normalizing the value - /// - MVN(const Output& data, - bool across_channels = true, - bool normalize_variance = true, - double eps = 1e-9); + class NGRAPH_API MVN : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"MVN", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + MVN() = default; + /// \brief Constructs an MVN operation. + /// + /// \param data Input tensor with data + /// \param normalize_variance flag that denotes whether to perform variance + /// normalization. + /// \param across_channels flag that denotes if mean values are shared across + /// channels. + /// \param eps the number to be added to the variance to avoid division by zero when + /// normalizing the value + /// + MVN(const Output& data, + bool across_channels = true, + bool normalize_variance = true, + double eps = 1e-9); - /// \brief Constructs an MVN operation. - /// - /// \param data Input tensor with data - /// \param reduction_axes A list of axes, along which to reduce. - /// \param normalize_variance flag that denotes whether to perform variance - /// normalization. - /// \param eps the number to be added to the variance to avoid division by zero when - /// normalizing the value - /// - MVN(const Output& data, - AxisSet reduction_axes, - bool normalize_variance = true, - double eps = 1e-9); + /// \brief Constructs an MVN operation. + /// + /// \param data Input tensor with data + /// \param reduction_axes A list of axes, along which to reduce. + /// \param normalize_variance flag that denotes whether to perform variance + /// normalization. + /// \param eps the number to be added to the variance to avoid division by zero when + /// normalizing the value + /// + MVN(const Output& data, + AxisSet reduction_axes, + bool normalize_variance = true, + double eps = 1e-9); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual void pre_validate_and_infer_types() override; + virtual void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - double get_eps() const { return m_eps; } - bool get_normalize_variance() const { return m_normalize_variance; } - AxisSet get_reduction_axes() const { return m_reduction_axes; } - void set_reduction_axes(AxisSet axes) { m_reduction_axes = axes; } - private: - double m_eps; - bool m_across_channels; - bool m_normalize_variance; - AxisSet m_reduction_axes; - }; + double get_eps() const { return m_eps; } + bool get_normalize_variance() const { return m_normalize_variance; } + AxisSet get_reduction_axes() const { return m_reduction_axes; } + void set_reduction_axes(AxisSet axes) { m_reduction_axes = axes; } + private: + double m_eps; + bool m_across_channels; + bool m_normalize_variance; + AxisSet m_reduction_axes; + }; + } + using v0::MVN; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/normalize_l2.hpp b/src/ngraph/op/fused/normalize_l2.hpp index bde810a42f0..c6358a653d8 100644 --- a/src/ngraph/op/fused/normalize_l2.hpp +++ b/src/ngraph/op/fused/normalize_l2.hpp @@ -26,42 +26,46 @@ namespace ngraph { namespace op { - /// \brief Normalization input tensor with L2 norm. - /// - class NormalizeL2 : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"NormalizeL2", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - NormalizeL2() = default; + /// \brief Normalization input tensor with L2 norm. /// - /// \brief Constructs a Normalize operation. - /// - /// \param data - Node producing the input tensor - /// \param axes - Node indicating axes along which reduction is - /// calculated - /// \param eps - The epsilon added to L2 norm. - /// \param eps_mode - Specifies how eps is combined with L2 value calculated - /// before division - /// - NormalizeL2(const Output& data, - const Output& axes, - float eps, - EpsMode eps_mode); + class NGRAPH_API NormalizeL2 : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"NormalizeL2", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + NormalizeL2() = default; + /// + /// \brief Constructs a Normalize operation. + /// + /// \param data - Node producing the input tensor + /// \param axes - Node indicating axes along which reduction is + /// calculated + /// \param eps - The epsilon added to L2 norm. + /// \param eps_mode - Specifies how eps is combined with L2 value + /// calculated + /// before division + /// + NormalizeL2(const Output& data, + const Output& axes, + float eps, + EpsMode eps_mode); - float get_eps() const { return m_eps; } - EpsMode get_eps_mode() const { return m_eps_mode; } - virtual NodeVector decompose_op() const override; - virtual void pre_validate_and_infer_types() override; - AxisSet get_reduction_axes() const; + float get_eps() const { return m_eps; } + EpsMode get_eps_mode() const { return m_eps_mode; } + virtual NodeVector decompose_op() const override; + virtual void pre_validate_and_infer_types() override; + AxisSet get_reduction_axes() const; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - float m_eps; - EpsMode m_eps_mode; - }; + protected: + float m_eps; + EpsMode m_eps_mode; + }; + } + using v0::NormalizeL2; } } diff --git a/src/ngraph/op/fused/partial_slice.hpp b/src/ngraph/op/fused/partial_slice.hpp index f0a9ba097a1..73905ded628 100644 --- a/src/ngraph/op/fused/partial_slice.hpp +++ b/src/ngraph/op/fused/partial_slice.hpp @@ -24,86 +24,89 @@ namespace ngraph { namespace op { - /// \brief pdpd slice op - /// - class PartialSlice : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PartialSlice", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - PartialSlice() = default; - /// \brief Constructs an PartialSlice operation. + /// \brief pdpd slice op /// - /// \param data Input tensor - /// \param axes Axes that lower and upper bounds apply to - /// \param lower_bounds Starting indices of corresponding axis in `axes` - /// \param upper_bounds Ending indices of corresponding axis in `axes` - /// \param decrease_axis Axes to be dropped (dimension will be one) - PartialSlice(const Output& data, - const AxisVector& axes, - const std::vector& lower_bounds, - const std::vector& upper_bounds, - const AxisVector& decrease_axes); + class NGRAPH_API PartialSlice : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"PartialSlice", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PartialSlice() = default; + /// \brief Constructs an PartialSlice operation. + /// + /// \param data Input tensor + /// \param axes Axes that lower and upper bounds apply to + /// \param lower_bounds Starting indices of corresponding axis in `axes` + /// \param upper_bounds Ending indices of corresponding axis in `axes` + /// \param decrease_axis Axes to be dropped (dimension will be one) + PartialSlice(const Output& data, + const AxisVector& axes, + const std::vector& lower_bounds, + const std::vector& upper_bounds, + const AxisVector& decrease_axes); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const AxisVector& get_axes() const { return m_axes; } - const std::vector& get_lower_bounds() const { return m_lower_bounds; } - const std::vector& get_upper_bounds() const { return m_upper_bounds; } - const AxisVector& get_decrease_axes() const { return m_decrease_axes; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + const AxisVector& get_axes() const { return m_axes; } + const std::vector& get_lower_bounds() const { return m_lower_bounds; } + const std::vector& get_upper_bounds() const { return m_upper_bounds; } + const AxisVector& get_decrease_axes() const { return m_decrease_axes; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - private: - AxisVector m_axes; - std::vector m_lower_bounds; - std::vector m_upper_bounds; - AxisVector m_decrease_axes; - }; + private: + AxisVector m_axes; + std::vector m_lower_bounds; + std::vector m_upper_bounds; + AxisVector m_decrease_axes; + }; - /// \brief pdpd slice backprop - /// - class PartialSliceBackprop : public ngraph::op::util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PartialSliceBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - PartialSliceBackprop() = default; - /// \brief Constructs an PartialSliceBackprop operation. + /// \brief pdpd slice backprop /// - /// \param data Input tensor - /// \param dout Onput tensor from fprop - /// \param axes Axes that lower and upper bounds apply to - /// \param lower_bounds Starting indices of corresponding axis in `axes` - /// \param upper_bounds Ending indices of corresponding axis in `axes` - PartialSliceBackprop(const Output& data, - const Output& dout, - const AxisVector& axes, - const std::vector& lower_bounds, - const std::vector& upper_bounds); + class NGRAPH_API PartialSliceBackprop : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"PartialSliceBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PartialSliceBackprop() = default; + /// \brief Constructs an PartialSliceBackprop operation. + /// + /// \param data Input tensor + /// \param dout Onput tensor from fprop + /// \param axes Axes that lower and upper bounds apply to + /// \param lower_bounds Starting indices of corresponding axis in `axes` + /// \param upper_bounds Ending indices of corresponding axis in `axes` + PartialSliceBackprop(const Output& data, + const Output& dout, + const AxisVector& axes, + const std::vector& lower_bounds, + const std::vector& upper_bounds); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - const AxisVector& get_axes() const { return m_axes; } - const std::vector& get_lower_bounds() const { return m_lower_bounds; } - const std::vector& get_upper_bounds() const { return m_upper_bounds; } - private: - AxisVector m_axes; - std::vector m_lower_bounds; - std::vector m_upper_bounds; - }; + const AxisVector& get_axes() const { return m_axes; } + const std::vector& get_lower_bounds() const { return m_lower_bounds; } + const std::vector& get_upper_bounds() const { return m_upper_bounds; } + private: + AxisVector m_axes; + std::vector m_lower_bounds; + std::vector m_upper_bounds; + }; + } + using v0::PartialSlice; + using v0::PartialSliceBackprop; } } diff --git a/src/ngraph/op/fused/prelu.hpp b/src/ngraph/op/fused/prelu.hpp index dfedfa5fb93..41459344847 100644 --- a/src/ngraph/op/fused/prelu.hpp +++ b/src/ngraph/op/fused/prelu.hpp @@ -24,27 +24,30 @@ namespace ngraph { namespace op { - /// \brief Parametrized Relu - /// x < 0 => f(x) = x * slope - /// x >= 0 => f(x) = x - /// - class PRelu : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"PRelu", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - PRelu() = default; - /// \brief Constructs a PRelu operation. + /// \brief Parametrized Relu + /// x < 0 => f(x) = x * slope + /// x >= 0 => f(x) = x /// - /// \param data Input tensor - /// \param slope Multipliers for negative values - PRelu(const Output& data, const Output& slope); + class NGRAPH_API PRelu : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"PRelu", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + PRelu() = default; + /// \brief Constructs a PRelu operation. + /// + /// \param data Input tensor + /// \param slope Multipliers for negative values + PRelu(const Output& data, const Output& slope); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::PRelu; } } diff --git a/src/ngraph/op/fused/reciprocal.cpp b/src/ngraph/op/fused/reciprocal.cpp new file mode 100644 index 00000000000..343be22f6d3 --- /dev/null +++ b/src/ngraph/op/fused/reciprocal.cpp @@ -0,0 +1,43 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/fused/reciprocal.hpp" + +#include "ngraph/op/constant.hpp" +#include "ngraph/op/divide.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::Reciprocal::type_info; + +op::Reciprocal::Reciprocal(const Output& data) + : FusedOp({data}) +{ + constructor_validate_and_infer_types(); +} + +NodeVector op::Reciprocal::decompose_op() const +{ + auto data = input_value(0); + auto one_node = op::Constant::create(data.get_element_type(), data.get_shape(), {1}); + return {make_shared(one_node, data)}; +} + +shared_ptr op::Reciprocal::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0)); +} diff --git a/src/ngraph/op/fused/reciprocal.hpp b/src/ngraph/op/fused/reciprocal.hpp new file mode 100644 index 00000000000..113ae15e1df --- /dev/null +++ b/src/ngraph/op/fused/reciprocal.hpp @@ -0,0 +1,46 @@ +//***************************************************************************** +// Copyright 2017-2019 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/node.hpp" +#include "ngraph/op/op.hpp" +#include "ngraph/op/util/fused_op.hpp" + +namespace ngraph +{ + namespace op + { + /// \brief Reciprocal operation + /// f(x) = 1 / x + class NGRAPH_API Reciprocal : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Reciprocal", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Reciprocal() = default; + /// \brief Constructs a Reciprocal operation. + /// + /// \param data Input tensor + Reciprocal(const Output& data); + + virtual NodeVector decompose_op() const override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/op/fused/rnn_cell.hpp b/src/ngraph/op/fused/rnn_cell.hpp index 2d370888ad1..d0b536aa3f0 100644 --- a/src/ngraph/op/fused/rnn_cell.hpp +++ b/src/ngraph/op/fused/rnn_cell.hpp @@ -30,52 +30,60 @@ namespace ngraph { namespace op { - /// - /// \brief Class for single RNN cell node. - /// - /// \note It follows notation and equations defined as in ONNX standard: - /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#RNN - /// - /// \note It calculates following equations: - /// - /// Ht = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Wbi + Rbi) - /// - /// * - Is a dot product, - /// f - is activation functions. - /// - /// \note This class represents only single *cell* (for current time step) and not the - /// whole LSTM Sequence layer - /// - /// \sa LSTMSequence, LSTMCell, GRUCell - /// - class RNNCell : public util::FusedOp, public util::RNNCellBase + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"RNNCell", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } /// - /// \brief Constructs RNNCell node. + /// \brief Class for single RNN cell node. /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] W The weight tensor with shape: [hidden_size, - /// input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [hidden_size, hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. + /// \note It follows notation and equations defined as in ONNX standard: + /// https://github.com/onnx/onnx/blob/master/docs/Operators.md#RNN /// - RNNCell(const Output& X, + /// \note It calculates following equations: + /// + /// Ht = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Wbi + Rbi) + /// + /// * - Is a dot product, + /// f - is activation functions. + /// + /// \note This class represents only single *cell* (for current time step) and not + /// the + /// whole LSTM Sequence layer + /// + /// \sa LSTMSequence, LSTMCell, GRUCell + /// + class NGRAPH_API RNNCell : public util::FusedOp, public util::RNNCellBase + { + public: + static constexpr NodeTypeInfo type_info{"RNNCell", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + RNNCell() = default; + /// + /// \brief Constructs RNNCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] W The weight tensor with shape: [hidden_size, + /// input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [hidden_size, hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// + RNNCell( + const Output& X, const Output& initial_hidden_state, const Output& W, const Output& R, @@ -85,30 +93,35 @@ namespace ngraph const std::vector& activations_beta = {}, float clip = 0.f); - /// - /// \brief Constructs RNNCell node. - /// - /// \param[in] X The input tensor with shape: [batch_size, - /// input_size]. - /// \param[in] initial_hidden_state The hidden state tensor at current time step with - /// shape: [batch_size, hidden_size]. - /// \param[in] W The weight tensor with shape: [hidden_size, - /// input_size]. - /// \param[in] R The recurrence weight tensor with shape: - /// [hidden_size, hidden_size]. - /// \param[in] B The bias tensor for input gate with shape: - /// [hidden_size]. - /// \param[in] hidden_size The number of hidden units for recurrent cell. - /// \param[in] activations The vector of activation functions used inside - /// recurrent cell. - /// \param[in] activations_alpha The vector of alpha parameters for activation - /// functions in order respective to activation list. - /// \param[in] activations_beta The vector of beta parameters for activation - /// functions in order respective to activation list. - /// \param[in] clip The value defining clipping range [-clip, clip] on - /// input of activation functions. - /// - RNNCell(const Output& X, + /// + /// \brief Constructs RNNCell node. + /// + /// \param[in] X The input tensor with shape: [batch_size, + /// input_size]. + /// \param[in] initial_hidden_state The hidden state tensor at current time step + /// with + /// shape: [batch_size, hidden_size]. + /// \param[in] W The weight tensor with shape: [hidden_size, + /// input_size]. + /// \param[in] R The recurrence weight tensor with shape: + /// [hidden_size, hidden_size]. + /// \param[in] B The bias tensor for input gate with shape: + /// [hidden_size]. + /// \param[in] hidden_size The number of hidden units for recurrent cell. + /// \param[in] activations The vector of activation functions used inside + /// recurrent cell. + /// \param[in] activations_alpha The vector of alpha parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] activations_beta The vector of beta parameters for activation + /// functions in order respective to activation + /// list. + /// \param[in] clip The value defining clipping range [-clip, + /// clip] on + /// input of activation functions. + /// + RNNCell( + const Output& X, const Output& initial_hidden_state, const Output& W, const Output& R, @@ -119,25 +132,27 @@ namespace ngraph const std::vector& activations_beta = {}, float clip = 0.f); - virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - private: - /// - /// \brief Creates the default bias input initialized with zeros. - /// - /// \return The object of Output class. - /// - Output get_default_bias_input() const; + private: + /// + /// \brief Creates the default bias input initialized with zeros. + /// + /// \return The object of Output class. + /// + Output get_default_bias_input() const; - /// - /// \brief The Activation function f. - /// - util::ActivationFunction m_activation_f; + /// + /// \brief The Activation function f. + /// + util::ActivationFunction m_activation_f; - static constexpr std::size_t s_gates_count{1}; - }; + static constexpr std::size_t s_gates_count{1}; + }; + } + using v0::RNNCell; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/scale_shift.hpp b/src/ngraph/op/fused/scale_shift.hpp index f3bf758d0b1..b7f1a4e482f 100644 --- a/src/ngraph/op/fused/scale_shift.hpp +++ b/src/ngraph/op/fused/scale_shift.hpp @@ -24,30 +24,33 @@ namespace ngraph { namespace op { - /// \brief Operator performing Scale Shift transformation. - /// - /// Y = Scale * Data + Shift - /// - class ScaleShift : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ScaleShift", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ScaleShift() = default; - /// \brief Constructs an ScaleShift operation. + /// \brief Operator performing Scale Shift transformation. /// - /// \param data Input tensor - /// \param scale Input tensor that scale input data - /// \param shift Input tensor that shift input data - ScaleShift(const Output& data, - const Output& scale, - const Output& shift); + /// Y = Scale * Data + Shift + /// + class NGRAPH_API ScaleShift : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"ScaleShift", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ScaleShift() = default; + /// \brief Constructs an ScaleShift operation. + /// + /// \param data Input tensor + /// \param scale Input tensor that scale input data + /// \param shift Input tensor that shift input data + ScaleShift(const Output& data, + const Output& scale, + const Output& shift); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::ScaleShift; } } diff --git a/src/ngraph/op/fused/selu.cpp b/src/ngraph/op/fused/selu.cpp index 448f235d9ef..2e9122c5dc6 100644 --- a/src/ngraph/op/fused/selu.cpp +++ b/src/ngraph/op/fused/selu.cpp @@ -26,15 +26,15 @@ using namespace std; using namespace ngraph; -constexpr NodeTypeInfo op::v1::Selu::type_info; +constexpr NodeTypeInfo op::v0::Selu::type_info; -op::v1::Selu::Selu(const Output& data, const Output& alpha, const Output& lambda) +op::v0::Selu::Selu(const Output& data, const Output& alpha, const Output& lambda) : FusedOp({data, alpha, lambda}) { constructor_validate_and_infer_types(); } -NodeVector op::v1::Selu::decompose_op() const +NodeVector op::v0::Selu::decompose_op() const { const auto data = input_value(0); const auto alpha = input_value(1); @@ -47,8 +47,8 @@ NodeVector op::v1::Selu::decompose_op() const alpha)}; } -shared_ptr op::v1::Selu::copy_with_new_args(const NodeVector& new_args) const +shared_ptr op::v0::Selu::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1), new_args.at(2)); + return make_shared(new_args.at(0), new_args.at(1), new_args.at(2)); } diff --git a/src/ngraph/op/fused/selu.hpp b/src/ngraph/op/fused/selu.hpp index 2430e54ed9c..ea56c71f4ca 100644 --- a/src/ngraph/op/fused/selu.hpp +++ b/src/ngraph/op/fused/selu.hpp @@ -24,15 +24,15 @@ namespace ngraph { namespace op { - namespace v1 + namespace v0 { /// \brief Performs a SELU activation function on all elements of the input node - class Selu : public ngraph::op::util::FusedOp + class NGRAPH_API Selu : public ngraph::op::util::FusedOp { public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Selu", 1}; + static constexpr NodeTypeInfo type_info{"Selu", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + Selu() = default; /// \brief Constructs a Selu node. /// /// \param data - Node producing the input tensor @@ -48,6 +48,6 @@ namespace ngraph copy_with_new_args(const NodeVector& new_args) const override; }; } - using v1::Selu; + using v0::Selu; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/shuffle_channels.hpp b/src/ngraph/op/fused/shuffle_channels.hpp index a2aa4e6bba8..a2ecaba65c5 100644 --- a/src/ngraph/op/fused/shuffle_channels.hpp +++ b/src/ngraph/op/fused/shuffle_channels.hpp @@ -25,46 +25,51 @@ namespace ngraph { namespace op { - /// \brief Permutes data in the channel dimension of the input - class ShuffleChannels : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ShuffleChannels", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ShuffleChannels() = default; - /// \brief Constructs a ShuffleChannels node. - /// - /// \param data - Node producing the input tensor - /// \param axis - channel dimension index in the data tensor. A negative value means - /// that the index should be calculated from the back of the input data - /// shape. - /// \param groups - number of groups the channel dimension specified by axis should be - /// split into - ShuffleChannels(const Output& data, - const int axis = 1, - const size_t groups = 1UL); + /// \brief Permutes data in the channel dimension of the input + class NGRAPH_API ShuffleChannels : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"ShuffleChannels", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ShuffleChannels() = default; + /// \brief Constructs a ShuffleChannels node. + /// + /// \param data - Node producing the input tensor + /// \param axis - channel dimension index in the data tensor. A negative value means + /// that the index should be calculated from the back of the input + /// data + /// shape. + /// \param groups - number of groups the channel dimension specified by axis should + /// be + /// split into + ShuffleChannels(const Output& data, + const int axis = 1, + const size_t groups = 1UL); - size_t get_zero_based_axis() const; + size_t get_zero_based_axis() const; - virtual void pre_validate_and_infer_types() override; + virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - int get_axis() const { return m_axis; } - size_t get_groups() const { return m_groups; } - private: - /// \brief Generates a shape required to permute the data - /// - /// \param data_shape - Shape of the original input data tensor - /// \return A 4D tensor to be used to reshape the input data before shuffling it - Shape get_pre_shuffle_shape(const Shape& data_shape) const; + int get_axis() const { return m_axis; } + size_t get_groups() const { return m_groups; } + private: + /// \brief Generates a shape required to permute the data + /// + /// \param data_shape - Shape of the original input data tensor + /// \return A 4D tensor to be used to reshape the input data before shuffling it + Shape get_pre_shuffle_shape(const Shape& data_shape) const; - int m_axis; - size_t m_groups; - }; + int m_axis; + size_t m_groups; + }; + } + using v0::ShuffleChannels; } } diff --git a/src/ngraph/op/fused/softmax_crossentropy.hpp b/src/ngraph/op/fused/softmax_crossentropy.hpp index bcd8ec4cade..9035f134c75 100644 --- a/src/ngraph/op/fused/softmax_crossentropy.hpp +++ b/src/ngraph/op/fused/softmax_crossentropy.hpp @@ -24,70 +24,77 @@ namespace ngraph { namespace op { - class SoftmaxCrossEntropy : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"SoftmaxCrossEntropy", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - SoftmaxCrossEntropy() = default; - /// \brief Softamax + CrossEntropy for numerical stabilization - /// \param arg1 Node that produces the tensor to normalize - /// \param arg2 Node that produces ground truth lables for the input - /// \param soft_label flag indicating whether to interpretate the given labels as soft - /// labels - /// \param ignore_index Specifies a target value that is ignored and does not contribute - /// to the input gradient Only valid if soft_label is set to False - SoftmaxCrossEntropy(const Output& arg1, - const Output& arg2, - bool soft_label = false, - int64_t ignore_index = -100); + class NGRAPH_API SoftmaxCrossEntropy : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"SoftmaxCrossEntropy", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + SoftmaxCrossEntropy() = default; + /// \brief Softamax + CrossEntropy for numerical stabilization + /// \param arg1 Node that produces the tensor to normalize + /// \param arg2 Node that produces ground truth lables for the input + /// \param soft_label flag indicating whether to interpretate the given labels as + /// soft + /// labels + /// \param ignore_index Specifies a target value that is ignored and does not + /// contribute + /// to the input gradient Only valid if soft_label is set to False + SoftmaxCrossEntropy(const Output& arg1, + const Output& arg2, + bool soft_label = false, + int64_t ignore_index = -100); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - bool get_soft_label() const { return m_soft_label; } - int64_t get_ignore_index() const { return m_ignore_index; } - private: - bool m_soft_label; - int64_t m_ignore_index; - }; + bool get_soft_label() const { return m_soft_label; } + int64_t get_ignore_index() const { return m_ignore_index; } + private: + bool m_soft_label; + int64_t m_ignore_index; + }; - class SoftmaxCrossEntropyBackprop : public util::FusedOp - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"SoftmaxCrossEntropyBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - SoftmaxCrossEntropyBackprop() = default; + class NGRAPH_API SoftmaxCrossEntropyBackprop : public util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"SoftmaxCrossEntropyBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + SoftmaxCrossEntropyBackprop() = default; - /// \brief Backprop for SoftmaxCrossEntropy - /// \param delta Node that produces the delta during bprop - /// \param softmax Node that produces softmax from fprop - /// \param labels Node that produces ground truth labels for input - /// \param soft_label flag indicating whether to interpretate the given labels as soft - /// labels - /// \param ignore_index Specifies a target value that is ignored and does not contribute - /// to the input gradient Only valid if soft_label is set to False - SoftmaxCrossEntropyBackprop(const Output& delta, - const Output& softmax, - const Output& labels, - bool soft_label = false, - int64_t ignore_index = -100); + /// \brief Backprop for SoftmaxCrossEntropy + /// \param delta Node that produces the delta during bprop + /// \param softmax Node that produces softmax from fprop + /// \param labels Node that produces ground truth labels for input + /// \param soft_label flag indicating whether to interpretate the given labels as + /// soft + /// labels + /// \param ignore_index Specifies a target value that is ignored and does not + /// contribute + /// to the input gradient Only valid if soft_label is set to False + SoftmaxCrossEntropyBackprop(const Output& delta, + const Output& softmax, + const Output& labels, + bool soft_label = false, + int64_t ignore_index = -100); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - void pre_validate_and_infer_types() override; + void pre_validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - bool get_soft_label() const { return m_soft_label; } - int64_t get_ignore_index() const { return m_ignore_index; } - private: - bool m_soft_label; - int64_t m_ignore_index; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + bool get_soft_label() const { return m_soft_label; } + int64_t get_ignore_index() const { return m_ignore_index; } + private: + bool m_soft_label; + int64_t m_ignore_index; + }; + } + using v0::SoftmaxCrossEntropy; + using v0::SoftmaxCrossEntropyBackprop; } // namespace op } // namespace ngraph diff --git a/src/ngraph/op/fused/space_to_depth.cpp b/src/ngraph/op/fused/space_to_depth.cpp index 75de8aa022e..bf7bcfcb852 100644 --- a/src/ngraph/op/fused/space_to_depth.cpp +++ b/src/ngraph/op/fused/space_to_depth.cpp @@ -25,13 +25,21 @@ using namespace ngraph; constexpr NodeTypeInfo op::SpaceToDepth::type_info; -op::SpaceToDepth::SpaceToDepth(const Output& data, const size_t block_size) +op::SpaceToDepth::SpaceToDepth(const Output& data, + const SpaceToDepthMode& mode, + size_t block_size) : FusedOp({data}) , m_blocksize(block_size) + , m_mode(mode) { constructor_validate_and_infer_types(); } +op::SpaceToDepth::SpaceToDepth(const Output& data, const std::string& mode, size_t block_size) + : SpaceToDepth(data, mode_from_string(mode), block_size) +{ +} + NodeVector op::SpaceToDepth::decompose_op() const { auto data = input_value(0); @@ -74,7 +82,17 @@ NodeVector op::SpaceToDepth::decompose_op() const // rearrange them so as appropriate chunks of data where close to their // destination place. Finally squeeze data from respective dimensions. Output flat_node = builder::reshape(data, Shape{n, c, h_flat, bs, w_flat, bs}); - flat_node = builder::reorder_axes(flat_node, {0, 3, 5, 1, 2, 4}); + switch (m_mode) + { + case SpaceToDepthMode::DEPTH_FIRST: + { + flat_node = builder::reorder_axes(flat_node, {0, 1, 3, 5, 2, 4}); + break; + } + case SpaceToDepthMode::BLOCKS_FIRST: + default: { flat_node = builder::reorder_axes(flat_node, {0, 3, 5, 1, 2, 4}); + } + } return NodeVector{builder::reshape(flat_node, Shape{n, c_high, h_flat, w_flat})}; } @@ -84,5 +102,17 @@ shared_ptr op::SpaceToDepth::copy_with_new_args(const NodeVector& new_args { throw ngraph_error("Incorrect number of new arguments"); } - return make_shared(new_args.at(0), m_blocksize); + return make_shared(new_args.at(0), m_mode, m_blocksize); +} + +op::SpaceToDepth::SpaceToDepthMode op::SpaceToDepth::mode_from_string(const std::string& mode) const +{ + static const std::map allowed_values = { + {"blocks_first", SpaceToDepthMode::BLOCKS_FIRST}, + {"depth_first", SpaceToDepthMode::DEPTH_FIRST}}; + + NODE_VALIDATION_CHECK( + this, allowed_values.count(mode) > 0, "Invalid 'depth_to_space_mode' value passed in."); + + return allowed_values.at(mode); } diff --git a/src/ngraph/op/fused/space_to_depth.hpp b/src/ngraph/op/fused/space_to_depth.hpp index 1e273899ae2..ee2df83203e 100644 --- a/src/ngraph/op/fused/space_to_depth.hpp +++ b/src/ngraph/op/fused/space_to_depth.hpp @@ -23,33 +23,56 @@ namespace ngraph { namespace op { - /// \brief SpaceToDepth permutes input tensor blocks of spatial data into depth dimension. - /// - /// \note Values from the height and width dimensions are moved to the depth dimension. - /// - /// Output node produces a tensor with shape: - /// [N, C * blocksize * blocksize, H / blocksize, W / blocksize] - class SpaceToDepth : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"SpaceToDepth", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - SpaceToDepth() = default; - /// \brief Constructs a SpaceToDepth operation. + /// \brief SpaceToDepth permutes input tensor blocks of spatial data into depth + /// dimension. /// - /// \param data - Node producing the input tensor - /// \param block_size - the size of the block of values to be moved - SpaceToDepth(const Output& data, std::size_t block_size); + /// \note Values from the height and width dimensions are moved to the depth dimension. + /// + /// Output node produces a tensor with shape: + /// [N, C * blocksize * blocksize, H / blocksize, W / blocksize] + class NGRAPH_API SpaceToDepth : public ngraph::op::util::FusedOp + { + public: + enum class SpaceToDepthMode + { + // The output depth is gathered from [block_size, ..., block_size, C] + BLOCKS_FIRST, + // The output depth is gathered from [C, block_size, ..., block_size] + DEPTH_FIRST + }; + + static constexpr NodeTypeInfo type_info{"SpaceToDepth", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + SpaceToDepth() = default; + /// \brief Constructs a SpaceToDepth operation. + /// + /// \param data - Node producing the input tensor + /// \param mode Specifies how the output depth dimension is gathered + /// from block coordinates and the old depth dimension. + /// \param block_size - the size of the block of values to be moved + SpaceToDepth(const Output& data, + const SpaceToDepthMode& mode, + std::size_t block_size = 1); + + SpaceToDepth(const Output& data, + const std::string& mode, + std::size_t block_size = 1); - std::size_t get_block_size() const { return m_blocksize; } - virtual NodeVector decompose_op() const override; + std::size_t get_block_size() const { return m_blocksize; } + SpaceToDepthMode get_mode() const { return m_mode; } + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - std::size_t m_blocksize; - }; + protected: + std::size_t m_blocksize; + SpaceToDepthMode m_mode; + SpaceToDepthMode mode_from_string(const std::string& mode) const; + }; + } + using v0::SpaceToDepth; } } diff --git a/src/ngraph/op/fused/split.cpp b/src/ngraph/op/fused/split.cpp index daa5ad71ec1..b3840e2ed27 100644 --- a/src/ngraph/op/fused/split.cpp +++ b/src/ngraph/op/fused/split.cpp @@ -16,23 +16,36 @@ #include #include "ngraph/builder/split.hpp" +#include "ngraph/op/constant.hpp" #include "ngraph/op/fused/split.hpp" +#include "ngraph/validation_util.hpp" using namespace std; using namespace ngraph; constexpr NodeTypeInfo op::Split::type_info; -op::Split::Split(const Output& data, const int axis, const size_t num_split) - : FusedOp({data}) +op::Split::Split(const Output& data, const Output& axis, const size_t num_split) + : FusedOp({data, axis}) , m_split_evenly{true} - , m_axis{axis} , m_num_split{num_split} { constructor_validate_and_infer_types(); } -op::Split::Split(const Output& data, const int axis, const std::vector& splits) +op::Split::Split(const Output& data, + const Output& axis, + const std::vector& splits) + : FusedOp({data, axis}) + , m_split_evenly{false} + , m_num_split{0} + , m_splits{splits} +{ + constructor_validate_and_infer_types(); +} + +// TODO REMOVE THIS CONSTRUCTOR. INTRODUCED TO PROVIDE CI COMPATIBILITY +op::Split::Split(const Output& data, int axis, const std::vector& splits) : FusedOp({data}) , m_split_evenly{false} , m_axis{axis} @@ -42,8 +55,30 @@ op::Split::Split(const Output& data, const int axis, const std::vector& data, int axis, size_t num_split) + : FusedOp({data}) + , m_split_evenly{true} + , m_axis{axis} + , m_num_split{num_split} +{ + constructor_validate_and_infer_types(); +} + void op::Split::pre_validate_and_infer_types() { + // TODO REMOVE IF CHECK. INTRODUCED TO PROVIDE CI COMPATIBILITY + if (get_input_size() == 2) + { + const auto axis_shape = input(1).get_shape(); + NODE_VALIDATION_CHECK(this, is_scalar(axis_shape), "The 'axis' input node must be scalar"); + + const auto axis_node = input_value(1).get_node_shared_ptr(); + NODE_VALIDATION_CHECK( + this, axis_node->is_constant(), "The 'axis' input node must be constant"); + const auto axis_node_const = as_type_ptr(axis_node); + m_axis = axis_node_const->get_vector()[0]; + } // Create dynamic-typed outputs. Actual shape/type will be computed during shape inference for (size_t i = 0; i < std::max(m_splits.size(), m_num_split); i++) { @@ -57,11 +92,7 @@ void op::Split::pre_validate_and_infer_types() const auto shape = input(0).get_shape(); - m_axis = adjust_axis_value(m_axis, shape.size()); - NODE_VALIDATION_CHECK(this, - m_axis >= 0 && m_axis < static_cast(shape.size()), - "The 'axis' parameter for Split has to point to one of the " - "input tensor's shape dimensions."); + m_axis = ngraph::normalize_axis(this, m_axis, shape.size()); const auto dimension_at_axis = shape.at(m_axis); if (m_split_evenly) @@ -92,6 +123,7 @@ void op::Split::pre_validate_and_infer_types() all_splits_positive == true, "All values of the 'splits' attribute must be greater than zero"); } + set_input_is_relevant_to_shape(0); } NodeVector op::Split::decompose_op() const @@ -101,18 +133,12 @@ NodeVector op::Split::decompose_op() const shared_ptr op::Split::copy_with_new_args(const NodeVector& new_args) const { - check_new_args_count(this, new_args); - return make_shared(new_args.at(0), m_axis, m_splits); -} - -size_t op::Split::adjust_axis_value(const int axis, const size_t input_tensor_rank) const -{ - if (axis < 0) + if (new_args.size() == 2) { - return axis + input_tensor_rank; - } - else - { - return axis; + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), m_splits); } + + // TODO REMOVE THIS RETURN AND IF ABOVE. INTRODUCED TO PROVIDE CI COMPATIBILITY + return make_shared(new_args.at(0), m_axis, m_splits); } diff --git a/src/ngraph/op/fused/split.hpp b/src/ngraph/op/fused/split.hpp index d5f43811037..d36600fe6be 100644 --- a/src/ngraph/op/fused/split.hpp +++ b/src/ngraph/op/fused/split.hpp @@ -26,61 +26,62 @@ namespace ngraph { namespace op { - /// \brief Splits the input tensor into a list of smaller tensors ("pieces") - class Split : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Split", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Split() = default; - /// \brief Constructs a Split op that evenly divides the input tensor. - /// - /// \param data - Node producing the input tensor - /// \param axis - indicates an axis along which the input tensor should be split. - /// Negative values mean counting from the back of the input tensor's - /// shape. - /// \param num_split - a number of "pieces" the input tensor will be split to - Split(const Output& data, const int axis, const size_t num_split); + /// \brief Splits the input tensor into a list of smaller tensors ("pieces") + class NGRAPH_API Split : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Split", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Split() = default; + /// \brief Constructs a Split op that evenly divides the input tensor. + /// + /// \param data Node producing the input tensor + /// \param axis Node producing an axis along which the input tensor + /// should be split. Negative values mean counting from + /// the back of the input tensor's shape. + /// \param num_split a number of "pieces" the input tensor will be split to + Split(const Output& data, const Output& axis, const size_t num_split); - /// \brief Constructs a Split op that splits the input tensor into variable length - /// "pieces" - /// - /// \param data - Node producing the input tensor - /// \param axis - indicates an axis along which the input tensor should be split. - /// Negative values mean counting from the back of the input tensor's - /// shape. - /// \param splits - a list of lengths that the input tensor should be split to. Use this - /// constructor to split the input tensor to variable length chunks. - Split(const Output& data, const int axis, const std::vector& splits); + /// \brief Constructs a Split op that splits the input tensor into variable length + /// "pieces" + /// + /// \param data Node producing the input tensor + /// \param axis Node producing an axis along which the input tensor + /// should be split. Negative values mean counting from + /// the back of the input tensor's shape. + /// \param splits a list of lengths that the input tensor should be + /// split to. Use this constructor to split the input + /// tensor to variable length chunks. + Split(const Output& data, + const Output& axis, + const std::vector& splits); - void pre_validate_and_infer_types() override; + // TODO REMOVE THIS CONSTRUCTOR. INTRODUCED TO PROVIDE CI COMPATIBILITY + Split(const Output& data, int axis, const std::vector& splits); - virtual NodeVector decompose_op() const override; + // TODO REMOVE THIS CONSTRUCTOR. INTRODUCED TO PROVIDE CI COMPATIBILITY + Split(const Output& data, int axis, const size_t num_split); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + void pre_validate_and_infer_types() override; - size_t get_axis() const { return m_axis; } - const std::vector& get_splits() const { return m_splits; } - private: - /// \brief Adjusts the axis for negative values - /// - /// \note Negative values mean that the API consumer wants to point the axis location - /// from the back of the tensor. This is similar to the way NumPy works. - /// - /// \param axis - original axis value; negative values are accepted - /// \param input_tensor_rank - rank of the input data tensor - /// \return Returns a sum of parameters for negative axis value, or axis itself - /// otherwise - size_t adjust_axis_value(const int axis, const size_t input_tensor_rank) const; + virtual NodeVector decompose_op() const override; - /// used internally for validation purposes, indicates which constructor was used - bool m_split_evenly; - int m_axis; - size_t m_num_split; - /// contains lengths of chunks that the input tensor will be split into - std::vector m_splits; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + size_t get_axis() const { return m_axis; } + const std::vector& get_splits() const { return m_splits; } + private: + /// used internally for validation purposes, indicates which constructor was used + bool m_split_evenly; + int64_t m_axis; + size_t m_num_split; + /// contains lengths of chunks that the input tensor will be split into + std::vector m_splits; + }; + } + using v0::Split; } } diff --git a/src/ngraph/op/fused/squared_difference.cpp b/src/ngraph/op/fused/squared_difference.cpp index fa298ecd111..0c0f8913d45 100644 --- a/src/ngraph/op/fused/squared_difference.cpp +++ b/src/ngraph/op/fused/squared_difference.cpp @@ -26,8 +26,11 @@ using namespace ngraph; constexpr NodeTypeInfo op::SquaredDifference::type_info; -op::SquaredDifference::SquaredDifference(const Output& x1, const Output& x2) +op::SquaredDifference::SquaredDifference(const Output& x1, + const Output& x2, + const AutoBroadcastSpec& auto_broadcast) : FusedOp({x1, x2}) + , m_autobroadcast(auto_broadcast) { constructor_validate_and_infer_types(); } @@ -37,19 +40,14 @@ NodeVector op::SquaredDifference::decompose_op() const const auto x1 = input_value(0); const auto x2 = input_value(1); - const auto broadcasted = numpy_style_broadcast_values({x1, x2}); - - const auto difference = broadcasted.at(0) - broadcasted.at(1); + const auto difference = make_shared(x1, x2, m_autobroadcast); return {difference * difference}; } shared_ptr op::SquaredDifference::copy_with_new_args(const NodeVector& new_args) const { - NODE_VALIDATION_CHECK(this, - new_args.size() == 2, - "Expected 2 elements in new_args for the SquaredDifference op but got ", - new_args.size()); + check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1)); + return make_shared(new_args.at(0), new_args.at(1), get_autob()); } diff --git a/src/ngraph/op/fused/squared_difference.hpp b/src/ngraph/op/fused/squared_difference.hpp index 002664b5749..12c2b90ca3d 100644 --- a/src/ngraph/op/fused/squared_difference.hpp +++ b/src/ngraph/op/fused/squared_difference.hpp @@ -24,26 +24,42 @@ namespace ngraph { namespace op { - /// \brief Calculates an element-wise squared difference between two tensors - /// - /// y[i] = (x1[i] - x2[i])^2 - class SquaredDifference : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"SquaredDifference", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - SquaredDifference() = default; - /// \brief Constructs the squared difference operation. + /// \brief Calculates an element-wise squared difference between two tensors /// - /// \param x1 First input tensor - /// \param x2 Second input tensor - SquaredDifference(const Output& x1, const Output& x2); + /// y[i] = (x1[i] - x2[i])^2 + class NGRAPH_API SquaredDifference : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"SquaredDifference", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + SquaredDifference() = default; + /// \brief Constructs the squared difference operation. + /// + /// \param x1 First input tensor + /// \param x2 Second input tensor + /// \param auto_broadcast Auto broadcast specification + SquaredDifference( + const Output& x1, + const Output& x2, + const AutoBroadcastSpec& auto_broadcast = AutoBroadcastType::NUMPY); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; - } -} + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + const AutoBroadcastSpec& get_autob() const override { return m_autobroadcast; } + void set_autob(const AutoBroadcastSpec& auto_broadcast) + { + m_autobroadcast = auto_broadcast; + } + + private: + AutoBroadcastSpec m_autobroadcast; + }; + } + using v0::SquaredDifference; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/op/fused/squeeze.hpp b/src/ngraph/op/fused/squeeze.hpp index 8e5acdd6241..32219c92c85 100644 --- a/src/ngraph/op/fused/squeeze.hpp +++ b/src/ngraph/op/fused/squeeze.hpp @@ -27,19 +27,22 @@ namespace ngraph { namespace op { - class Squeeze : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Squeeze", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Squeeze() = default; - Squeeze(const Output& data, const Output& axes); + class NGRAPH_API Squeeze : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Squeeze", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Squeeze() = default; + Squeeze(const Output& data, const Output& axes); - virtual NodeVector decompose_op() const override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Squeeze; } } diff --git a/src/ngraph/op/fused/unsqueeze.hpp b/src/ngraph/op/fused/unsqueeze.hpp index d9b894c0a4a..342393b8d5f 100644 --- a/src/ngraph/op/fused/unsqueeze.hpp +++ b/src/ngraph/op/fused/unsqueeze.hpp @@ -27,20 +27,23 @@ namespace ngraph { namespace op { - class Unsqueeze : public ngraph::op::util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Unsqueeze", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Unsqueeze() = default; - Unsqueeze(const Output& data, const Output& axes); + class NGRAPH_API Unsqueeze : public ngraph::op::util::FusedOp + { + public: + static constexpr NodeTypeInfo type_info{"Unsqueeze", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Unsqueeze() = default; + Unsqueeze(const Output& data, const Output& axes); - virtual void pre_validate_and_infer_types() override; - virtual NodeVector decompose_op() const override; + virtual void pre_validate_and_infer_types() override; + virtual NodeVector decompose_op() const override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Unsqueeze; } } diff --git a/src/ngraph/op/fused_op_tbl.hpp b/src/ngraph/op/fused_op_tbl.hpp deleted file mode 100644 index 1c184b86f62..00000000000 --- a/src/ngraph/op/fused_op_tbl.hpp +++ /dev/null @@ -1,61 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2019 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. -//***************************************************************************** - -// This collection contains one entry for each fused op. -// - -#ifndef NGRAPH_OP -#warning "NGRAPH_OP not defined" -#define NGRAPH_OP(x, y) -#endif - -NGRAPH_OP(Clamp, ngraph::op) -NGRAPH_OP(ConvolutionBias, ngraph::op) -NGRAPH_OP(ConvolutionBiasAdd, ngraph::op) -NGRAPH_OP(ConvolutionBiasBackpropFiltersBias, ngraph::op) -NGRAPH_OP(DepthToSpace, ngraph::op) -NGRAPH_OP(Elu, ngraph::op) -NGRAPH_OP(FakeQuantize, ngraph::op) -NGRAPH_OP(Gelu, ngraph::op) -NGRAPH_OP(GeluBackpropFactor, ngraph::op) -NGRAPH_OP(Gemm, ngraph::op) -NGRAPH_OP(GRN, ngraph::op) -NGRAPH_OP(GroupConvolution, ngraph::op) -NGRAPH_OP(GroupConvolutionTranspose, ngraph::op) -NGRAPH_OP(GRUCell, ngraph::op) -NGRAPH_OP(HardSigmoid, ngraph::op) -NGRAPH_OP(LayerNorm, ngraph::op) -NGRAPH_OP(LayerNormBackprop, ngraph::op) -NGRAPH_OP(LSTMCell, ngraph::op) -NGRAPH_OP(LSTMSequence, ngraph::op) -NGRAPH_OP(MatMul, ngraph::op) -NGRAPH_OP(MVN, ngraph::op) -NGRAPH_OP(NormalizeL2, ngraph::op) -NGRAPH_OP(PartialSlice, ngraph::op) -NGRAPH_OP(PartialSliceBackprop, ngraph::op) -NGRAPH_OP(PRelu, ngraph::op) -NGRAPH_OP(RNNCell, ngraph::op) -NGRAPH_OP(ScaleShift, ngraph::op) -NGRAPH_OP(Selu, ngraph::op) -NGRAPH_OP(ShuffleChannels, ngraph::op) -NGRAPH_OP(SpaceToDepth, ngraph::op) -NGRAPH_OP(Split, ngraph::op) -NGRAPH_OP(SquaredDifference, ngraph::op) -NGRAPH_OP(SoftmaxCrossEntropy, ngraph::op) -NGRAPH_OP(SoftmaxCrossEntropyBackprop, ngraph::op) -NGRAPH_OP(Squeeze, ngraph::op) -NGRAPH_OP(TensorIterator, ngraph::op) -NGRAPH_OP(Unsqueeze, ngraph::op) diff --git a/src/ngraph/op/gather.hpp b/src/ngraph/op/gather.hpp index e6f07532986..8f8485b3140 100644 --- a/src/ngraph/op/gather.hpp +++ b/src/ngraph/op/gather.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v0 { /// \brief Gather slices from axis of params according to indices - class Gather : public Op + class NGRAPH_API Gather : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Gather", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } Gather() = default; @@ -55,10 +54,9 @@ namespace ngraph namespace v1 { /// \brief Gather slices from axis of params according to indices - class Gather : public Op + class NGRAPH_API Gather : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Gather", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } Gather() = default; diff --git a/src/ngraph/op/gather_nd.hpp b/src/ngraph/op/gather_nd.hpp index 4598a5635b9..8ba5ad81756 100644 --- a/src/ngraph/op/gather_nd.hpp +++ b/src/ngraph/op/gather_nd.hpp @@ -22,32 +22,35 @@ namespace ngraph { namespace op { - /// \brief Gather slices from params with shapes given by indices - class GatherND : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GatherND", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - GatherND() = default; - /// \param params The tensor from which slices are gathered - /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` - GatherND(const Output& params, const Output& indices) - : Op({params, indices}) + /// \brief Gather slices from params with shapes given by indices + class NGRAPH_API GatherND : public Op { - constructor_validate_and_infer_types(); - } + public: + static constexpr NodeTypeInfo type_info{"GatherND", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GatherND() = default; + /// \param params The tensor from which slices are gathered + /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` + GatherND(const Output& params, const Output& indices) + : Op({params, indices}) + { + constructor_validate_and_infer_types(); + } - void validate_and_infer_types() override; + void validate_and_infer_types() override; - void generate_adjoints(autodiff::Adjoints& /* adjoints */, - const NodeVector& /* deltas */) override - { - throw ngraph_error("Not yet implemented"); - } + void generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) override + { + throw ngraph_error("Not yet implemented"); + } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::GatherND; } } diff --git a/src/ngraph/op/gather_tree.cpp b/src/ngraph/op/gather_tree.cpp new file mode 100644 index 00000000000..99bc7d946e8 --- /dev/null +++ b/src/ngraph/op/gather_tree.cpp @@ -0,0 +1,84 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/gather_tree.hpp" +#include "ngraph/shape.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::GatherTree::type_info; + +op::v1::GatherTree::GatherTree(const Output& step_ids, + const Output& parent_idx, + const Output& max_seq_len, + const Output& end_token) + : Op({step_ids, parent_idx, max_seq_len, end_token}) +{ + constructor_validate_and_infer_types(); +} + +shared_ptr op::v1::GatherTree::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared( + new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3)); +} + +void op::v1::GatherTree::validate_and_infer_types() +{ + const auto& step_ids_rank = get_input_partial_shape(0); + const auto& parent_idx_rank = get_input_partial_shape(1); + const auto& max_seq_len_rank = get_input_partial_shape(2); + const auto& end_token_rank = get_input_partial_shape(3); + + NODE_VALIDATION_CHECK(this, + step_ids_rank.rank().is_dynamic() || + static_cast(step_ids_rank.rank()) == 3, + "step_ids input rank must equal to 3 (step_ids rank: ", + static_cast(step_ids_rank.rank()), + ")"); + + NODE_VALIDATION_CHECK(this, + parent_idx_rank.rank().is_dynamic() || + static_cast(parent_idx_rank.rank()) == 3, + "parent_idx input rank must equal to 3 (parent_idx rank: ", + static_cast(parent_idx_rank.rank()), + ")"); + + NODE_VALIDATION_CHECK(this, + max_seq_len_rank.rank().is_dynamic() || + static_cast(max_seq_len_rank.rank()) == 1, + "max_seq_len input rank must equal to 1 (max_seq_len rank: ", + static_cast(max_seq_len_rank.rank()), + ")"); + + NODE_VALIDATION_CHECK(this, + end_token_rank.rank().is_dynamic() || + static_cast(end_token_rank.rank()) == 3, + "end_token input rank must equal to 3 (end_token rank: ", + static_cast(end_token_rank.rank()), + ")"); + + const auto& step_ids_et = get_input_element_type(0); + set_output_type(0, step_ids_et, step_ids_rank); +} + +void op::v1::GatherTree::generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) +{ + throw ngraph_error("generate_adjoints is not implemented for GatherTree"); +} diff --git a/src/ngraph/op/gather_tree.hpp b/src/ngraph/op/gather_tree.hpp new file mode 100644 index 00000000000..95cc3937926 --- /dev/null +++ b/src/ngraph/op/gather_tree.hpp @@ -0,0 +1,58 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/op.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Generates the complete beams from the ids per each step and the parent beam + /// ids. + class NGRAPH_API GatherTree : public Op + { + public: + static constexpr NodeTypeInfo type_info{"GatherTree", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GatherTree() = default; + /// \param step_ids Tensor of shape [MAX_TIME, BATCH_SIZE, BEAM_WIDTH] with + /// indices from per each step + /// \param parent_idx Tensor of shape [MAX_TIME, BATCH_SIZE, BEAM_WIDTH] with + /// parent beam indices + /// \param max_seq_len Tensor of shape [BATCH_SIZE] with maximum lengths for each + /// sequence in the batch + /// \param end_token Tensor of shape [MAX_TIME, BATCH_SIZE, BEAM_WIDTH] + GatherTree(const Output& step_ids, + const Output& parent_idx, + const Output& max_seq_len, + const Output& end_token); + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + } +} diff --git a/src/ngraph/op/get_output_element.hpp b/src/ngraph/op/get_output_element.hpp index 79e994cf491..4c5d3b604bc 100644 --- a/src/ngraph/op/get_output_element.hpp +++ b/src/ngraph/op/get_output_element.hpp @@ -24,35 +24,39 @@ namespace ngraph { NodeVector get_output_elements(const std::shared_ptr& mon); - /// \brief Operation to get an output from a node. - class GetOutputElement : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"GetOutputElement", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a get-tuple-element operation. - /// - /// \param arg The input tuple. - /// \param n The index of the tuple element to get. - GetOutputElement(const std::shared_ptr& arg, size_t n); + /// \brief Operation to get an output from a node. + class NGRAPH_API GetOutputElement : public Op + { + public: + static constexpr NodeTypeInfo type_info{"GetOutputElement", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + GetOutputElement() = default; + /// \brief Constructs a get-tuple-element operation. + /// + /// \param arg The input tuple. + /// \param n The index of the tuple element to get. + GetOutputElement(const std::shared_ptr& arg, size_t n); - /// Return the equilent Output - Output get_as_output() const; + /// Return the equilent Output + Output get_as_output() const; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - /// \return The index of the tuple element to get. - size_t get_n() const { return m_n; } - virtual NodeVector get_arguments() const override; + /// \return The index of the tuple element to get. + size_t get_n() const { return m_n; } + virtual NodeVector get_arguments() const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - size_t m_n; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + size_t m_n; + }; + } + using v0::GetOutputElement; } inline std::shared_ptr get_output_element(const Output& output, diff --git a/src/ngraph/op/greater.hpp b/src/ngraph/op/greater.hpp index 5e1abe9e139..b9d8a8b18ec 100644 --- a/src/ngraph/op/greater.hpp +++ b/src/ngraph/op/greater.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v0 { /// \brief Elementwise greater-than operation. - class Greater : public util::BinaryElementwiseComparison + class NGRAPH_API Greater : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Greater", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a greater-than operation. @@ -50,10 +49,9 @@ namespace ngraph namespace v1 { /// \brief Elementwise greater-than operation. - class Greater : public util::BinaryElementwiseComparison + class NGRAPH_API Greater : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Greater", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a greater-than operation. diff --git a/src/ngraph/op/greater_eq.cpp b/src/ngraph/op/greater_eq.cpp index b4f9cbaef76..1e58289f282 100644 --- a/src/ngraph/op/greater_eq.cpp +++ b/src/ngraph/op/greater_eq.cpp @@ -39,18 +39,18 @@ shared_ptr op::v0::GreaterEq::copy_with_new_args(const NodeVector& new_arg //---------------------------------- v1 ---------------------------------------- -constexpr NodeTypeInfo op::v1::GreaterEq::type_info; +constexpr NodeTypeInfo op::v1::GreaterEqual::type_info; -op::v1::GreaterEq::GreaterEq(const Output& arg0, - const Output& arg1, - const AutoBroadcastSpec& auto_broadcast) +op::v1::GreaterEqual::GreaterEqual(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast) : BinaryElementwiseComparison(arg0, arg1, auto_broadcast) { constructor_validate_and_infer_types(); } -shared_ptr op::v1::GreaterEq::copy_with_new_args(const NodeVector& new_args) const +shared_ptr op::v1::GreaterEqual::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); + return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); } diff --git a/src/ngraph/op/greater_eq.hpp b/src/ngraph/op/greater_eq.hpp index 916cadbc6e1..39d0743bf35 100644 --- a/src/ngraph/op/greater_eq.hpp +++ b/src/ngraph/op/greater_eq.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v0 { /// \brief Elementwise greater-than-or-equal operation. - class GreaterEq : public util::BinaryElementwiseComparison + class NGRAPH_API GreaterEq : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"GreaterEq", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a greater-than-or-equal operation. @@ -50,28 +49,30 @@ namespace ngraph namespace v1 { /// \brief Elementwise greater-than-or-equal operation. - class GreaterEq : public util::BinaryElementwiseComparison + class NGRAPH_API GreaterEqual : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"GreaterEq", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a greater-than-or-equal operation. - GreaterEq() = default; + GreaterEqual() = default; /// \brief Constructs a greater-than-or-equal operation. /// /// \param arg0 Node that produces the first input tensor. /// \param arg1 Node that produces the second input tensor. /// \param auto_broadcast Auto broadcast specification - GreaterEq(const Output& arg0, - const Output& arg1, - const AutoBroadcastSpec& auto_broadcast = - AutoBroadcastSpec(AutoBroadcastType::NUMPY)); + GreaterEqual(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast = + AutoBroadcastSpec(AutoBroadcastType::NUMPY)); virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; size_t get_version() const override { return 1; } }; + + // DO NOT USE. Will be removed once users switch to GreaterEqual + using GreaterEq = GreaterEqual; } // namespace v1 using v0::GreaterEq; diff --git a/src/ngraph/op/less.hpp b/src/ngraph/op/less.hpp index c215a381484..8c47556dcf8 100644 --- a/src/ngraph/op/less.hpp +++ b/src/ngraph/op/less.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v0 { /// \brief Elementwise less-than operation. - class Less : public util::BinaryElementwiseComparison + class NGRAPH_API Less : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Less", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a less-than operation. @@ -50,10 +49,9 @@ namespace ngraph namespace v1 { /// \brief Elementwise less-than operation. - class Less : public util::BinaryElementwiseComparison + class NGRAPH_API Less : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Less", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a less-than operation. diff --git a/src/ngraph/op/less_eq.hpp b/src/ngraph/op/less_eq.hpp index 96ce3c13283..1a4d986db7a 100644 --- a/src/ngraph/op/less_eq.hpp +++ b/src/ngraph/op/less_eq.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v1 { /// \brief Elementwise less-than-or-equal operation. - class LessEqual : public util::BinaryElementwiseComparison + class NGRAPH_API LessEqual : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LessEqual", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a less-than-or-equal operation. @@ -52,15 +51,13 @@ namespace ngraph namespace v0 { /// \brief Elementwise less-than-or-equal operation. - class LessEq : public util::BinaryElementwiseComparison + class NGRAPH_API LessEq : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LessEq", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a less-than-or-equal operation. LessEq() = default; - /// \brief Constructs a less-than-or-equal operation. /// /// \param arg0 Node that produces the first input tensor. diff --git a/src/ngraph/op/log.hpp b/src/ngraph/op/log.hpp index ae288925c8f..77237686991 100644 --- a/src/ngraph/op/log.hpp +++ b/src/ngraph/op/log.hpp @@ -22,25 +22,28 @@ namespace ngraph { namespace op { - /// \brief Elementwise natural log operation. - class Log : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Log", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a natural log operation. - Log() = default; - /// \brief Constructs a natural log operation. - /// - /// \param arg Node that produces the input tensor. - Log(const Output& arg); + /// \brief Elementwise natural log operation. + class NGRAPH_API Log : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Log", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a natural log operation. + Log() = default; + /// \brief Constructs a natural log operation. + /// + /// \param arg Node that produces the input tensor. + Log(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Log; } } diff --git a/src/ngraph/op/lrn.cpp b/src/ngraph/op/lrn.cpp index cdd1e74a303..2ace854192e 100644 --- a/src/ngraph/op/lrn.cpp +++ b/src/ngraph/op/lrn.cpp @@ -64,13 +64,6 @@ void op::LRN::validate_and_infer_types() const PartialShape& input_shape = get_input_partial_shape(0); const auto input_shape_rank = input_shape.rank(); - NODE_VALIDATION_CHECK(this, - input_shape_rank.is_dynamic() || - static_cast(input_shape.rank()) >= 3, - "Argument must have rank >= 3 (argument shape: ", - input_shape, - ")."); - PartialShape axes_shape{PartialShape::dynamic()}; if (get_input_partial_shape(1).is_static()) { diff --git a/src/ngraph/op/lrn.hpp b/src/ngraph/op/lrn.hpp index 6d9b52ef46d..f0f46c52b54 100644 --- a/src/ngraph/op/lrn.hpp +++ b/src/ngraph/op/lrn.hpp @@ -22,7 +22,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Elementwise Local Response Normalization (LRN) operation. /// /// ## Inputs @@ -36,49 +38,50 @@ namespace ngraph /// | Type | Description | /// | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$N[n, c, d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[n, c, d_1,\dots,d_n] = \frac{N[n,i,d_1,\dots,d_n]}{ (bias + alpha * (\sum_{i=max(0,(nsize-1)/2)}^{min(C, (nsize-1)/2)+1} N[n,i,d_1,\dots,d_n]^{2}) ^ {2})}\f$ | - // clang-format on - class LRN : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"LRN", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a LRN operation. - LRN() = default; - /// \brief Constructs a LRN operation. - /// - /// \param arg Node that produces the input tensor. - LRN(const Output& arg, double alpha, double beta, double bias, size_t size); + // clang-format on + class NGRAPH_API LRN : public Op + { + public: + static constexpr NodeTypeInfo type_info{"LRN", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a LRN operation. + LRN() = default; + /// \brief Constructs a LRN operation. + /// + /// \param arg Node that produces the input tensor. + LRN(const Output& arg, double alpha, double beta, double bias, size_t size); - LRN(const Output& arg, - const Output& axes, - double alpha, - double beta, - double bias, - size_t size); + LRN(const Output& arg, + const Output& axes, + double alpha, + double beta, + double bias, + size_t size); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - double get_alpha() const { return m_alpha; } - void set_alpha(double alpha) { m_alpha = alpha; } - double get_beta() const { return m_beta; } - void set_beta(double beta) { m_beta = beta; } - double get_bias() const { return m_bias; } - void set_bias(double bias) { m_bias = bias; } - size_t get_nsize() const { return m_size; } - void set_nsize(size_t size) { m_size = size; } - AxisSet get_reduction_axes() const; + double get_alpha() const { return m_alpha; } + void set_alpha(double alpha) { m_alpha = alpha; } + double get_beta() const { return m_beta; } + void set_beta(double beta) { m_beta = beta; } + double get_bias() const { return m_bias; } + void set_bias(double bias) { m_bias = bias; } + size_t get_nsize() const { return m_size; } + void set_nsize(size_t size) { m_size = size; } + AxisSet get_reduction_axes() const; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - double m_alpha; - double m_beta; - double m_bias; - size_t m_size; - }; + double m_alpha; + double m_beta; + double m_bias; + size_t m_size; + }; + } + using v0::LRN; } } diff --git a/src/ngraph/op/max.cpp b/src/ngraph/op/max.cpp index 30066106900..ca110c349bf 100644 --- a/src/ngraph/op/max.cpp +++ b/src/ngraph/op/max.cpp @@ -75,6 +75,7 @@ shared_ptr op::v0::Max::get_default_value() const case element::Type_t::u64: return make_constant_from_string( to_string(numeric_limits::min()), get_element_type(), get_shape()); + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::dynamic: default: throw runtime_error("Max default value not defined for type"); diff --git a/src/ngraph/op/max.hpp b/src/ngraph/op/max.hpp index 10d50bc583b..b8ae94b0694 100644 --- a/src/ngraph/op/max.hpp +++ b/src/ngraph/op/max.hpp @@ -26,10 +26,9 @@ namespace ngraph namespace v0 { /// \brief Max-reduction operation. - class Max : public util::ArithmeticReduction + class NGRAPH_API Max : public util::ArithmeticReduction { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Max", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } @@ -58,10 +57,9 @@ namespace ngraph namespace v1 { - class ReduceMax : public util::ArithmeticReductionKeepDims + class NGRAPH_API ReduceMax : public util::ArithmeticReductionKeepDims { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ReduceMax", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a summation operation. diff --git a/src/ngraph/op/max_pool.hpp b/src/ngraph/op/max_pool.hpp index 183d1c7c3c9..5d2ef4f3d06 100644 --- a/src/ngraph/op/max_pool.hpp +++ b/src/ngraph/op/max_pool.hpp @@ -26,10 +26,9 @@ namespace ngraph namespace v0 { /// \brief Batched max pooling operation, with optional padding and window stride. - class MaxPool : public Op + class NGRAPH_API MaxPool : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"MaxPool", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched max pooling operation. @@ -147,10 +146,9 @@ namespace ngraph bool m_ceil_mode{false}; }; - class MaxPoolBackprop : public Op + class NGRAPH_API MaxPoolBackprop : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"MaxPoolBackprop", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } MaxPoolBackprop() = default; @@ -207,10 +205,9 @@ namespace ngraph namespace v1 { /// \brief Batched max pooling operation. - class MaxPool : public Op + class NGRAPH_API MaxPool : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"MaxPool", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a batched max pooling operation. @@ -292,10 +289,9 @@ namespace ngraph op::RoundingType m_rounding_type{op::RoundingType::FLOOR}; }; - class MaxPoolBackprop : public Op + class NGRAPH_API MaxPoolBackprop : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"MaxPoolBackprop", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } MaxPoolBackprop() = default; diff --git a/src/ngraph/op/maximum.hpp b/src/ngraph/op/maximum.hpp index 6a89486d1f8..0de1965c520 100644 --- a/src/ngraph/op/maximum.hpp +++ b/src/ngraph/op/maximum.hpp @@ -25,14 +25,16 @@ namespace ngraph namespace v0 { /// \brief Elementwise maximum operation. - class Maximum : public util::BinaryElementwiseArithmetic + class NGRAPH_API Maximum : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Maximum", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a maximum operation. - Maximum() = default; + Maximum() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs a maximum operation. /// /// \param arg0 Node that produces the first input tensor. @@ -55,14 +57,17 @@ namespace ngraph namespace v1 { /// \brief Elementwise maximum operation. - class Maximum : public util::BinaryElementwiseArithmetic + class NGRAPH_API Maximum : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Maximum", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a maximum operation. - Maximum() = default; + Maximum() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + /// \brief Constructs a maximum operation. /// /// \param arg0 Node that produces the first input tensor. diff --git a/src/ngraph/op/min.cpp b/src/ngraph/op/min.cpp index ee20e64cb56..bac79265566 100644 --- a/src/ngraph/op/min.cpp +++ b/src/ngraph/op/min.cpp @@ -75,6 +75,7 @@ shared_ptr op::v0::Min::get_default_value() const case element::Type_t::u64: return make_constant_from_string( to_string(numeric_limits::max()), get_element_type(), get_shape()); + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::dynamic: default: throw runtime_error("Min default value not defined for type"); diff --git a/src/ngraph/op/min.hpp b/src/ngraph/op/min.hpp index 77a258d033a..dba46a40303 100644 --- a/src/ngraph/op/min.hpp +++ b/src/ngraph/op/min.hpp @@ -26,10 +26,9 @@ namespace ngraph namespace v0 { /// \brief Min-reduction operation. - class Min : public util::ArithmeticReduction + class NGRAPH_API Min : public util::ArithmeticReduction { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Min", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } @@ -58,10 +57,9 @@ namespace ngraph namespace v1 { - class ReduceMin : public util::ArithmeticReductionKeepDims + class NGRAPH_API ReduceMin : public util::ArithmeticReductionKeepDims { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ReduceMin", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a summation operation. diff --git a/src/ngraph/op/minimum.hpp b/src/ngraph/op/minimum.hpp index 750ce2f931f..6ddbdff5e1e 100644 --- a/src/ngraph/op/minimum.hpp +++ b/src/ngraph/op/minimum.hpp @@ -25,14 +25,16 @@ namespace ngraph namespace v0 { /// \brief Elementwise minimum operation. - class Minimum : public util::BinaryElementwiseArithmetic + class NGRAPH_API Minimum : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Minimum", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a minimum operation. - Minimum() = default; + Minimum() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs a minimum operation. /// /// \param arg0 Node that produces the first input tensor. @@ -55,14 +57,17 @@ namespace ngraph namespace v1 { /// \brief Elementwise minimum operation. - class Minimum : public util::BinaryElementwiseArithmetic + class NGRAPH_API Minimum : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Minimum", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a minimum operation. - Minimum() = default; + Minimum() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + /// \brief Constructs a minimum operation. /// /// \param arg0 Node that produces the first input tensor. diff --git a/src/ngraph/op/multiply.hpp b/src/ngraph/op/multiply.hpp index ae73d33768b..33a6c66b95c 100644 --- a/src/ngraph/op/multiply.hpp +++ b/src/ngraph/op/multiply.hpp @@ -25,14 +25,16 @@ namespace ngraph namespace v0 { /// \brief Elementwise multiplication operation. - class Multiply : public util::BinaryElementwiseArithmetic + class NGRAPH_API Multiply : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Multiply", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a multiplication operation. - Multiply() = default; + Multiply() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs a multiplication operation. /// /// \param arg0 Node that produces the first input tensor. @@ -55,14 +57,17 @@ namespace ngraph namespace v1 { /// \brief Elementwise multiplication operation. - class Multiply : public util::BinaryElementwiseArithmetic + class NGRAPH_API Multiply : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Multiply", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a multiplication operation. - Multiply() = default; + Multiply() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + /// \brief Constructs a multiplication operation. /// /// \param arg0 Node that produces the first input tensor. @@ -87,5 +92,6 @@ namespace ngraph using v0::Multiply; } // namespace op + NGRAPH_API std::shared_ptr operator*(const Output& arg0, const Output& arg1); } // namespace ngraph diff --git a/src/ngraph/op/negative.hpp b/src/ngraph/op/negative.hpp index 3ee0b3aa306..b36d9d566a2 100644 --- a/src/ngraph/op/negative.hpp +++ b/src/ngraph/op/negative.hpp @@ -22,27 +22,31 @@ namespace ngraph { namespace op { - /// \brief Elementwise negative operation. - class Negative : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Negative", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a negative operation. - Negative() = default; - /// \brief Constructs a negative operation. - /// - /// \param arg Node that produces the input tensor. - Negative(const Output& arg); + /// \brief Elementwise negative operation. + class NGRAPH_API Negative : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Negative", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a negative operation. + Negative() = default; + /// \brief Constructs a negative operation. + /// + /// \param arg Node that produces the input tensor. + Negative(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Negative; } + NGRAPH_API std::shared_ptr operator-(const Output& arg0); } diff --git a/src/ngraph/op/not.hpp b/src/ngraph/op/not.hpp index 1b1e9d130ec..62b73aeea67 100644 --- a/src/ngraph/op/not.hpp +++ b/src/ngraph/op/not.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v1 { /// \brief Elementwise logical negation operation. - class LogicalNot : public Op + class NGRAPH_API LogicalNot : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LogicalNot", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a logical negation operation. @@ -47,10 +46,9 @@ namespace ngraph namespace v0 { /// \brief Elementwise logical negation operation. - class Not : public Op + class NGRAPH_API Not : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Not", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a logical negation operation. diff --git a/src/ngraph/op/not_equal.hpp b/src/ngraph/op/not_equal.hpp index 364e57c7deb..8b3b658d6cd 100644 --- a/src/ngraph/op/not_equal.hpp +++ b/src/ngraph/op/not_equal.hpp @@ -25,10 +25,9 @@ namespace ngraph namespace v0 { /// \brief Elementwise not-equal operation. - class NotEqual : public util::BinaryElementwiseComparison + class NGRAPH_API NotEqual : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"NotEqual", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a not-equal operation. @@ -52,10 +51,9 @@ namespace ngraph namespace v1 { /// \brief Elementwise not-equal operation. - class NotEqual : public util::BinaryElementwiseComparison + class NGRAPH_API NotEqual : public util::BinaryElementwiseComparison { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"NotEqual", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a not-equal operation. diff --git a/src/ngraph/op/one_hot.cpp b/src/ngraph/op/one_hot.cpp index 76f71814538..ea54ba66334 100644 --- a/src/ngraph/op/one_hot.cpp +++ b/src/ngraph/op/one_hot.cpp @@ -15,13 +15,14 @@ //***************************************************************************** #include "ngraph/op/one_hot.hpp" +#include "ngraph/validation_util.hpp" using namespace std; using namespace ngraph; -constexpr NodeTypeInfo op::OneHot::type_info; +constexpr NodeTypeInfo op::v0::OneHot::type_info; -op::OneHot::OneHot(const Output& arg, const PartialShape& shape, size_t one_hot_axis) +op::v0::OneHot::OneHot(const Output& arg, const PartialShape& shape, size_t one_hot_axis) : Op({arg}) , m_shape(shape) , m_one_hot_axis(one_hot_axis) @@ -29,7 +30,7 @@ op::OneHot::OneHot(const Output& arg, const PartialShape& shape, size_t on constructor_validate_and_infer_types(); } -void op::OneHot::validate_and_infer_types() +void op::v0::OneHot::validate_and_infer_types() { element::Type arg_et = get_input_element_type(0); PartialShape arg_shape = get_input_partial_shape(0); @@ -92,8 +93,86 @@ void op::OneHot::validate_and_infer_types() set_output_type(0, arg_et, result_shape); } -shared_ptr op::OneHot::copy_with_new_args(const NodeVector& new_args) const +shared_ptr op::v0::OneHot::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), m_shape, m_one_hot_axis); + return make_shared(new_args.at(0), m_shape, m_one_hot_axis); +} + +constexpr NodeTypeInfo op::v1::OneHot::type_info; + +op::v1::OneHot::OneHot(const Output& indices, + const Output& depth, + const Output& on_value, + const Output& off_value, + int64_t axis) + : Op({indices, depth, on_value, off_value}) + , m_axis(axis) +{ + constructor_validate_and_infer_types(); +} + +void op::v1::OneHot::validate_and_infer_types() +{ + const auto& indices_et = get_input_element_type(0); + const auto& depth_et = get_input_element_type(1); + const auto& on_value_et = get_input_element_type(2); + const auto& off_value_et = get_input_element_type(3); + + NODE_VALIDATION_CHECK(this, + indices_et.is_dynamic() || indices_et.is_integral(), + "Indices must be integral element type."); + + NODE_VALIDATION_CHECK(this, + depth_et.is_dynamic() || depth_et.is_integral(), + "Depth must be integral element type."); + + NODE_VALIDATION_CHECK(this, + on_value_et.compatible(off_value_et), + "on_value element type must be compatible with off_value element type."); + + const auto& indices_shape = get_input_partial_shape(0); + const auto& depth_shape = get_input_partial_shape(1); + const auto& on_value_shape = get_input_partial_shape(2); + const auto& off_value_shape = get_input_partial_shape(3); + + NODE_VALIDATION_CHECK(this, + depth_shape.is_dynamic() || is_scalar(depth_shape.to_shape()), + "depth input must be scalar."); + + NODE_VALIDATION_CHECK(this, + on_value_shape.is_dynamic() || is_scalar(on_value_shape.to_shape()), + "on_value input must be scalar."); + + NODE_VALIDATION_CHECK(this, + off_value_shape.is_dynamic() || is_scalar(off_value_shape.to_shape()), + "off_value input must be scalar."); + + const auto& depth = input_value(1).get_node_shared_ptr(); + PartialShape result_shape{PartialShape::dynamic()}; + + if (indices_shape.is_static() && indices_shape.rank().is_static() && depth->is_constant()) + { + const auto indices_rank = static_cast(indices_shape.rank()); + + std::vector out_dims(indices_rank); + for (auto i = 0; i < indices_rank; i++) + { + out_dims[i] = indices_shape[i]; + } + m_axis = + ngraph::normalize_axis(this, m_axis, indices_rank + 1, -indices_rank - 1, indices_rank); + int64_t depth_val = as_type_ptr(depth)->get_vector()[0]; + out_dims.insert(out_dims.begin() + m_axis, Dimension(depth_val)); + result_shape = out_dims; + } + + set_output_type(0, on_value_et, result_shape); +} + +shared_ptr op::v1::OneHot::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared( + new_args.at(0), new_args.at(1), new_args.at(2), new_args.at(3), m_axis); } diff --git a/src/ngraph/op/one_hot.hpp b/src/ngraph/op/one_hot.hpp index f880a900b8f..a8194772ecb 100644 --- a/src/ngraph/op/one_hot.hpp +++ b/src/ngraph/op/one_hot.hpp @@ -22,53 +22,94 @@ namespace ngraph { namespace op { - // clang-format off - /// \brief One-hot operator. - /// - /// ## Parameters - /// - /// | | Description | - /// | -------------- | ---------------------------------------------------------- | - /// | `shape` | The desired output shape, including the new one-hot axis. | - /// | `one_hot_axis` | The index within the output shape of the new one-hot axis. | - /// - /// ## Inputs - /// - /// | | Type | Description | - /// | ----- | ------------------------------------------------------- | -------------------------------------------------------------- | - /// | `arg` | \f$E[d_1,\dots,d_{m-1},d_{m+1},\dots,d_n]~(n \geq 0)\f$ | A tensor of any shape and any non-floating point element type. | - /// - /// ## Output - /// - /// | Type | Description | - /// | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - /// | \f$E[d_1,\dots,d_n]\f$ | The tensor \f$T'\f$, where \f$T'[i_1,\dots,i_{m-1},i_m,i_{m+1},\dots,i_n] = 1\f$ if \f$T[i_1,\dots,i_{m-1},i_{m+1},\dots,i_n] = i_m\f$, else \f$0\f$. However, \f$T'\f$ is undefined if any non-integral value or any out-of-bounds value is detected in the input tensor. | - // clang-format on - class OneHot : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"OneHot", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a one-hot operation. - OneHot() = default; - /// \brief Constructs a one-hot operation. + // clang-format off + /// \brief One-hot operator. /// - /// \param arg Node that produces the input tensor to be one-hot encoded. - /// \param shape The shape of the output tensor, including the new one-hot axis. - /// \param one_hot_axis The index within the output shape of the new one-hot axis. - OneHot(const Output& arg, const PartialShape& shape, size_t one_hot_axis); + /// ## Parameters + /// + /// | | Description | + /// | -------------- | ---------------------------------------------------------- | + /// | `shape` | The desired output shape, including the new one-hot axis. | + /// | `one_hot_axis` | The index within the output shape of the new one-hot axis. | + /// + /// ## Inputs + /// + /// | | Type | Description | + /// | ----- | ------------------------------------------------------- | -------------------------------------------------------------- | + /// | `arg` | \f$E[d_1,\dots,d_{m-1},d_{m+1},\dots,d_n]~(n \geq 0)\f$ | A tensor of any shape and any non-floating point element type. | + /// + /// ## Output + /// + /// | Type | Description | + /// | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | + /// | \f$E[d_1,\dots,d_n]\f$ | The tensor \f$T'\f$, where \f$T'[i_1,\dots,i_{m-1},i_m,i_{m+1},\dots,i_n] = 1\f$ if \f$T[i_1,\dots,i_{m-1},i_{m+1},\dots,i_n] = i_m\f$, else \f$0\f$. However, \f$T'\f$ is undefined if any non-integral value or any out-of-bounds value is detected in the input tensor. | + // clang-format on + class NGRAPH_API OneHot : public Op + { + public: + static constexpr NodeTypeInfo type_info{"OneHot", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a one-hot operation. + OneHot() = default; + /// \brief Constructs a one-hot operation. + /// + /// \param arg Node that produces the input tensor to be one-hot encoded. + /// \param shape The shape of the output tensor, including the new one-hot + /// axis. + /// \param one_hot_axis The index within the output shape of the new one-hot axis. + OneHot(const Output& arg, const PartialShape& shape, size_t one_hot_axis); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; + + /// \return The index of the one-hot axis. + size_t get_one_hot_axis() const { return m_one_hot_axis; } + void set_one_hot_axis(size_t one_hot_axis) { m_one_hot_axis = one_hot_axis; } + protected: + PartialShape m_shape; + size_t m_one_hot_axis; + }; + } + namespace v1 + { + class NGRAPH_API OneHot : public Op + { + public: + static constexpr NodeTypeInfo type_info{"OneHot", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a one-hot operation. + OneHot() = default; + /// \brief Constructs a one-hot operation. + /// + /// \param indices Input tensor containing indices. + /// \param depth Specifies number of classes and the size of one-hot dimension. + /// \param on_value Specifies value that the locations in output tensor represented + /// by indices in input take. + /// \param off_value Specifies value that the locations in output tensor not + /// represented + /// by indices in input take. + /// \param axis Axis along which one-hot representation in added. + OneHot(const Output& indices, + const Output& depth, + const Output& on_value, + const Output& off_value, + int64_t axis); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - /// \return The index of the one-hot axis. - size_t get_one_hot_axis() const { return m_one_hot_axis; } - void set_one_hot_axis(size_t one_hot_axis) { m_one_hot_axis = one_hot_axis; } - protected: - PartialShape m_shape; - size_t m_one_hot_axis; - }; + /// \return The index of the one-hot axis. + int64_t get_axis() const { return m_axis; } + void set_axis(int64_t axis) { m_axis = axis; } + protected: + int64_t m_axis; + }; + } + // default opset version + using v0::OneHot; } } diff --git a/src/ngraph/op/op.hpp b/src/ngraph/op/op.hpp index 5bfcede8fb9..4d6f4d60556 100644 --- a/src/ngraph/op/op.hpp +++ b/src/ngraph/op/op.hpp @@ -25,7 +25,7 @@ namespace ngraph namespace op { /// Root of all actual ops - class Op : public Node + class NGRAPH_API Op : public Node { public: virtual bool is_op() const override { return true; } diff --git a/src/ngraph/op/op_version_tbl.hpp b/src/ngraph/op/op_version_tbl.hpp new file mode 100644 index 00000000000..6e21b3e54ae --- /dev/null +++ b/src/ngraph/op/op_version_tbl.hpp @@ -0,0 +1,243 @@ +//***************************************************************************** +// Copyright 2017-2019 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License", 0); +// 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. +//***************************************************************************** + +// This collection contains one entry for each op. If an op is added it must be +// added to this list. +// +// In order to use this list you want to define a macro named exactly NGRAPH_OP +// When you are done you should undef the macro +// As an example if you wanted to make a list of all op names as strings you could do this: + +#ifndef NGRAPH_OP +#warning "NGRAPH_OP not defined" +#define NGRAPH_OP(NAME, NAMESPACE, VERSION) +#endif + +NGRAPH_OP(Abs, ngraph::op::v0, 0) +NGRAPH_OP(Acos, ngraph::op::v0, 0) +NGRAPH_OP(Add, ngraph::op::v0, 0) +NGRAPH_OP(Add, ngraph::op::v1, 1) +NGRAPH_OP(All, ngraph::op::v0, 0) +NGRAPH_OP(AllReduce, ngraph::op::v0, 0) +NGRAPH_OP(And, ngraph::op::v0, 0) +NGRAPH_OP(Any, ngraph::op, 0) +NGRAPH_OP(ArgMax, ngraph::op::v0, 0) +NGRAPH_OP(ArgMin, ngraph::op::v0, 0) +NGRAPH_OP(Asin, ngraph::op::v0, 0) +NGRAPH_OP(Atan, ngraph::op, 0) +NGRAPH_OP(Atan2, ngraph::op, 0) +NGRAPH_OP(AvgPool, ngraph::op::v0, 0) +NGRAPH_OP(AvgPool, ngraph::op::v1, 1) +NGRAPH_OP(AvgPoolBackprop, ngraph::op::v0, 0) +NGRAPH_OP(AvgPoolBackprop, ngraph::op::v1, 1) +NGRAPH_OP(BatchMatMul, ngraph::op, 0) +NGRAPH_OP(BatchMatMulTranspose, ngraph::op, 0) +NGRAPH_OP(BatchNormInference, ngraph::op, 0) +NGRAPH_OP(BatchNormTraining, ngraph::op, 0) +NGRAPH_OP(BatchNormTrainingBackprop, ngraph::op, 0) +NGRAPH_OP(BinaryConvolution, ngraph::op::v1, 1) +NGRAPH_OP(Broadcast, ngraph::op::v0, 0) +NGRAPH_OP(Broadcast, ngraph::op::v1, 1) +NGRAPH_OP(BroadcastDistributed, ngraph::op::v0, 0) +NGRAPH_OP(BroadcastLike, ngraph::op::v0, 0) +NGRAPH_OP(CTCGreedyDecoder, ngraph::op::v0, 0) +NGRAPH_OP(Ceiling, ngraph::op::v0, 0) +NGRAPH_OP(Clamp, ngraph::op::v0, 0) +NGRAPH_OP(CompiledKernel, ngraph::op, 0) +NGRAPH_OP(Concat, ngraph::op::v0, 0) +NGRAPH_OP(Constant, ngraph::op, 0) +NGRAPH_OP(Convert, ngraph::op, 0) +NGRAPH_OP(ConvertLike, ngraph::op::v1, 1) +NGRAPH_OP(Convolution, ngraph::op::v0, 0) +NGRAPH_OP(Convolution, ngraph::op::v1, 1) +NGRAPH_OP(ConvolutionBackpropData, ngraph::op::v0, 0) +NGRAPH_OP(ConvolutionBackpropData, ngraph::op::v1, 1) +NGRAPH_OP(ConvolutionBackpropFilters, ngraph::op::v0, 0) +NGRAPH_OP(ConvolutionBackpropFilters, ngraph::op::v1, 1) +NGRAPH_OP(ConvolutionBias, ngraph::op::v0, 0) +NGRAPH_OP(ConvolutionBiasAdd, ngraph::op::v0, 0) +NGRAPH_OP(ConvolutionBiasBackpropFiltersBias, ngraph::op::v0, 0) +NGRAPH_OP(Cos, ngraph::op, 0) +NGRAPH_OP(Cosh, ngraph::op, 0) +NGRAPH_OP(CropAndResize, ngraph::op, 0) +NGRAPH_OP(CrossEntropy, ngraph::op, 0) +NGRAPH_OP(CrossEntropyBackprop, ngraph::op, 0) +NGRAPH_OP(CumSum, ngraph::op::v0, 0) +NGRAPH_OP(DeformablePSROIPooling, ngraph::op::v1, 1) +NGRAPH_OP(DepthToSpace, ngraph::op::v0, 1) +NGRAPH_OP(Dequantize, ngraph::op, 0) +NGRAPH_OP(DetectionOutput, ngraph::op::v0, 0) +NGRAPH_OP(Divide, ngraph::op::v0, 0) +NGRAPH_OP(Divide, ngraph::op::v1, 1) +NGRAPH_OP(Dot, ngraph::op::v0, 0) +NGRAPH_OP(DynBroadcast, ngraph::op, 0) +NGRAPH_OP(DynPad, ngraph::op, 0) +NGRAPH_OP(DynReplaceSlice, ngraph::op, 0) +NGRAPH_OP(DynReshape, ngraph::op::v0, 0) +NGRAPH_OP(DynSlice, ngraph::op, 0) +NGRAPH_OP(Elu, ngraph::op::v0, 0) +NGRAPH_OP(EmbeddingLookup, ngraph::op::v0, 0) +NGRAPH_OP(Equal, ngraph::op::v0, 0) +NGRAPH_OP(Equal, ngraph::op::v1, 1) +NGRAPH_OP(Erf, ngraph::op::v0, 0) +NGRAPH_OP(Exp, ngraph::op::v0, 0) +NGRAPH_OP(FakeQuantize, ngraph::op::v0, 0) +NGRAPH_OP(Floor, ngraph::op::v0, 0) +NGRAPH_OP(FloorMod, ngraph::op::v1, 1) +NGRAPH_OP(GRN, ngraph::op::v0, 0) +NGRAPH_OP(GRUCell, ngraph::op::v0, 0) +NGRAPH_OP(Gather, ngraph::op::v0, 0) +NGRAPH_OP(Gather, ngraph::op::v1, 1) +NGRAPH_OP(GatherND, ngraph::op::v0, 0) +NGRAPH_OP(GatherTree, ngraph::op::v1, 1) +NGRAPH_OP(Gelu, ngraph::op::v0, 0) +NGRAPH_OP(GeluBackpropFactor, ngraph::op::v0, 0) +NGRAPH_OP(Gemm, ngraph::op::v0, 0) +NGRAPH_OP(GenerateMask, ngraph::op::v0, 0) +NGRAPH_OP(GenerateMask, ngraph::op::v1, 1) +NGRAPH_OP(GetOutputElement, ngraph::op::v0, 0) +NGRAPH_OP(Greater, ngraph::op::v0, 0) +NGRAPH_OP(Greater, ngraph::op::v1, 1) +NGRAPH_OP(GreaterEq, ngraph::op::v0, 0) +NGRAPH_OP(GreaterEqual, ngraph::op::v1, 1) +NGRAPH_OP(GroupConvolution, ngraph::op::v0, 0) +NGRAPH_OP(GroupConvolutionBackpropData, ngraph::op::v0, 0) +NGRAPH_OP(GroupConvolutionBackpropFilters, ngraph::op::v0, 0) +NGRAPH_OP(GroupConvolutionTranspose, ngraph::op::v0, 0) +NGRAPH_OP(HardSigmoid, ngraph::op::v0, 0) +NGRAPH_OP(Interpolate, ngraph::op::v0, 0) +NGRAPH_OP(LRN, ngraph::op::v0, 0) +NGRAPH_OP(LSTMCell, ngraph::op::v0, 0) +NGRAPH_OP(LSTMSequence, ngraph::op::v0, 0) +NGRAPH_OP(LayerNorm, ngraph::op::v0, 0) +NGRAPH_OP(LayerNormBackprop, ngraph::op::v0, 0) +NGRAPH_OP(Less, ngraph::op::v0, 0) +NGRAPH_OP(Less, ngraph::op::v1, 1) +NGRAPH_OP(LessEq, ngraph::op::v0, 0) +NGRAPH_OP(LessEqual, ngraph::op::v1, 1) +NGRAPH_OP(Log, ngraph::op, 0) +NGRAPH_OP(LogSoftmax, ngraph::op::v0, 0) +NGRAPH_OP(LogicalAnd, ngraph::op::v1, 1) +NGRAPH_OP(LogicalNot, ngraph::op::v1, 1) +NGRAPH_OP(LogicalOr, ngraph::op::v1, 1) +NGRAPH_OP(LogicalXor, ngraph::op::v1, 1) +NGRAPH_OP(MVN, ngraph::op::v0, 0) +NGRAPH_OP(MatMul, ngraph::op::v0, 0) +NGRAPH_OP(Max, ngraph::op::v0, 0) +NGRAPH_OP(MaxPool, ngraph::op::v0, 0) +NGRAPH_OP(MaxPool, ngraph::op::v1, 1) +NGRAPH_OP(MaxPoolBackprop, ngraph::op::v0, 0) +NGRAPH_OP(MaxPoolBackprop, ngraph::op::v1, 1) +NGRAPH_OP(Maximum, ngraph::op::v0, 0) +NGRAPH_OP(Maximum, ngraph::op::v1, 1) +NGRAPH_OP(Min, ngraph::op::v0, 0) +NGRAPH_OP(Minimum, ngraph::op::v0, 0) +NGRAPH_OP(Minimum, ngraph::op::v1, 1) +NGRAPH_OP(Mod, ngraph::op::v1, 1) +NGRAPH_OP(Multiply, ngraph::op::v0, 0) +NGRAPH_OP(Multiply, ngraph::op::v1, 1) +NGRAPH_OP(Negative, ngraph::op, 0) +NGRAPH_OP(NormalizeL2, ngraph::op::v0, 0) +NGRAPH_OP(Not, ngraph::op::v0, 0) +NGRAPH_OP(NotEqual, ngraph::op::v0, 0) +NGRAPH_OP(NotEqual, ngraph::op::v1, 1) +NGRAPH_OP(OneHot, ngraph::op::v0, 0) +NGRAPH_OP(Or, ngraph::op::v0, 0) +NGRAPH_OP(PRelu, ngraph::op::v0, 0) +NGRAPH_OP(PSROIPooling, ngraph::op::v0, 0) +NGRAPH_OP(Pad, ngraph::op::v0, 0) +NGRAPH_OP(Pad, ngraph::op::v1, 1) +NGRAPH_OP(Parameter, ngraph::op, 0) +NGRAPH_OP(PartialSlice, ngraph::op::v0, 0) +NGRAPH_OP(PartialSliceBackprop, ngraph::op::v0, 0) +NGRAPH_OP(Passthrough, ngraph::op, 0) +NGRAPH_OP(Power, ngraph::op::v0, 0) +NGRAPH_OP(Power, ngraph::op::v1, 1) +NGRAPH_OP(PriorBox, ngraph::op::v0, 0) +NGRAPH_OP(PriorBoxClustered, ngraph::op::v0, 0) +NGRAPH_OP(Product, ngraph::op, 0) +NGRAPH_OP(Proposal, ngraph::op::v0, 0) +NGRAPH_OP(Quantize, ngraph::op::v0, 0) +NGRAPH_OP(QuantizedConvolution, ngraph::op::v0, 0) +NGRAPH_OP(QuantizedConvolutionBias, ngraph::op, 0) +NGRAPH_OP(QuantizedConvolutionBiasAdd, ngraph::op, 0) +NGRAPH_OP(QuantizedConvolutionBiasSignedAdd, ngraph::op, 0) +NGRAPH_OP(QuantizedConvolutionRelu, ngraph::op, 0) +NGRAPH_OP(QuantizedDot, ngraph::op::v0, 0) +NGRAPH_OP(QuantizedDotBias, ngraph::op, 0) +NGRAPH_OP(RNNCell, ngraph::op::v0, 0) +NGRAPH_OP(ROIPooling, ngraph::op::v0, 0) +NGRAPH_OP(RandomUniform, ngraph::op, 0) +NGRAPH_OP(Range, ngraph::op, 0) +NGRAPH_OP(Reciprocal, ngraph::op, 0) +NGRAPH_OP(Recv, ngraph::op::v0, 0) +NGRAPH_OP(ReduceMax, ngraph::op::v1, 1) +NGRAPH_OP(ReduceLogicalAnd, ngraph::op::v1, 1) +NGRAPH_OP(ReduceLogicalOr, ngraph::op::v1, 1) +NGRAPH_OP(ReduceMean, ngraph::op::v1, 1) +NGRAPH_OP(ReduceMin, ngraph::op::v1, 1) +NGRAPH_OP(ReduceProd, ngraph::op::v1, 1) +NGRAPH_OP(ReduceSum, ngraph::op::v1, 1) +NGRAPH_OP(RegionYolo, ngraph::op::v0, 0) +NGRAPH_OP(Relu, ngraph::op::v0, 0) +NGRAPH_OP(ReluBackprop, ngraph::op::v0, 0) +NGRAPH_OP(ReorgYolo, ngraph::op::v0, 0) +NGRAPH_OP(ReplaceSlice, ngraph::op::v0, 0) +NGRAPH_OP(Reshape, ngraph::op::v0, 0) +NGRAPH_OP(Reshape, ngraph::op::v1, 1) +NGRAPH_OP(Result, ngraph::op, 0) +NGRAPH_OP(Reverse, ngraph::op::v0, 0) +NGRAPH_OP(Reverse, ngraph::op::v1, 1) +NGRAPH_OP(ReverseSequence, ngraph::op::v0, 0) +NGRAPH_OP(ScalarConstantLikeBase, ngraph::op, 0) +NGRAPH_OP(ScaleShift, ngraph::op::v0, 0) +NGRAPH_OP(ScatterAdd, ngraph::op::v0, 0) +NGRAPH_OP(ScatterNDAdd, ngraph::op::v0, 0) +NGRAPH_OP(Select, ngraph::op::v0, 0) +NGRAPH_OP(Selu, ngraph::op::v0, 0) +NGRAPH_OP(Send, ngraph::op::v0, 0) +NGRAPH_OP(ShapeOf, ngraph::op::v0, 0) +NGRAPH_OP(ShuffleChannels, ngraph::op::v0, 0) +NGRAPH_OP(Sigmoid, ngraph::op::v0, 0) +NGRAPH_OP(SigmoidBackprop, ngraph::op::v0, 0) +NGRAPH_OP(Sign, ngraph::op::v0, 0) +NGRAPH_OP(Sin, ngraph::op::v0, 0) +NGRAPH_OP(Sinh, ngraph::op::v0, 0) +NGRAPH_OP(Slice, ngraph::op::v0, 0) +NGRAPH_OP(Softmax, ngraph::op::v0, 0) +NGRAPH_OP(Softmax, ngraph::op::v1, 1) +NGRAPH_OP(SoftmaxCrossEntropy, ngraph::op::v0, 0) +NGRAPH_OP(SoftmaxCrossEntropyBackprop, ngraph::op::v0, 0) +NGRAPH_OP(SpaceToDepth, ngraph::op::v0, 0) +NGRAPH_OP(Split, ngraph::op::v0, 0) +NGRAPH_OP(Sqrt, ngraph::op, 0) +NGRAPH_OP(SquaredDifference, ngraph::op::v0, 0) +NGRAPH_OP(Squeeze, ngraph::op::v0, 0) +NGRAPH_OP(StopGradient, ngraph::op::v0, 0) +NGRAPH_OP(StridedSlice, ngraph::op::v1, 1) +NGRAPH_OP(Subtract, ngraph::op::v0, 0) +NGRAPH_OP(Subtract, ngraph::op::v1, 1) +NGRAPH_OP(Sum, ngraph::op::v0, 0) +NGRAPH_OP(Tan, ngraph::op::v0, 0) +NGRAPH_OP(Tanh, ngraph::op::v0, 0) +NGRAPH_OP(TensorIterator, ngraph::op::v0, 0) +NGRAPH_OP(Tile, ngraph::op::v0, 0) +NGRAPH_OP(TopK, ngraph::op::v0, 0) +NGRAPH_OP(TopK, ngraph::op::v1, 1) +NGRAPH_OP(Transpose, ngraph::op::v0, 0) +NGRAPH_OP(Unsqueeze, ngraph::op::v0, 0) +NGRAPH_OP(VariadicSplit, ngraph::op::v1, 1) +NGRAPH_OP(Xor, ngraph::op::v0, 0) diff --git a/src/ngraph/op/or.hpp b/src/ngraph/op/or.hpp index 401b86cba91..d3095ad687a 100644 --- a/src/ngraph/op/or.hpp +++ b/src/ngraph/op/or.hpp @@ -28,12 +28,12 @@ namespace ngraph { /// \brief Elementwise logical-or operation. /// - class LogicalOr : public util::BinaryElementwiseLogical + class NGRAPH_API LogicalOr : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LogicalOr", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } + LogicalOr() = default; /// \brief Constructs a logical-or operation. /// /// \param arg0 Node that produces the first input tensor.
    @@ -59,12 +59,12 @@ namespace ngraph { /// \brief Elementwise logical-or operation. /// - class Or : public util::BinaryElementwiseLogical + class NGRAPH_API Or : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Or", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + Or() = default; /// \brief Constructs a logical-or operation. /// /// \param arg0 Node that produces the first input tensor.
    diff --git a/src/ngraph/op/pad.hpp b/src/ngraph/op/pad.hpp index 3598fc486ca..4e5537a7f14 100644 --- a/src/ngraph/op/pad.hpp +++ b/src/ngraph/op/pad.hpp @@ -27,10 +27,9 @@ namespace ngraph namespace v0 { /// \brief Generic padding operation. - class Pad : public Op + class NGRAPH_API Pad : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Pad", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a generic padding operation. @@ -89,10 +88,9 @@ namespace ngraph namespace v1 { /// \brief Generic padding operation. - class Pad : public Op + class NGRAPH_API Pad : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Pad", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a generic padding operation. diff --git a/src/ngraph/op/parameter.cpp b/src/ngraph/op/parameter.cpp index c085e74d811..8293864ddd9 100644 --- a/src/ngraph/op/parameter.cpp +++ b/src/ngraph/op/parameter.cpp @@ -16,6 +16,7 @@ #include +#include "ngraph/attribute_visitor.hpp" #include "ngraph/op/parameter.hpp" using namespace std; @@ -34,6 +35,14 @@ op::Parameter::Parameter(const element::Type& element_type, constructor_validate_and_infer_types(); } +bool op::Parameter::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("cacheable", m_cacheable); + visitor.on_attribute("shape", m_partial_shape); + visitor.on_attribute("element_type", m_element_type); + return true; +} + void op::Parameter::validate_and_infer_types() { Op::validate_and_infer_types(); diff --git a/src/ngraph/op/parameter.hpp b/src/ngraph/op/parameter.hpp index 647e17083bf..bfd3384e819 100644 --- a/src/ngraph/op/parameter.hpp +++ b/src/ngraph/op/parameter.hpp @@ -28,14 +28,13 @@ namespace ngraph /// Parameters are nodes that represent the arguments that will be passed to user-defined /// functions. Function creation requires a sequence of parameters. Basic graph operations /// do not need parameters attached to a function. - class Parameter : public op::Op + class NGRAPH_API Parameter : public op::Op { protected: virtual void generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) override; public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Parameter", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructions a tensor-typed parameter node. @@ -49,6 +48,8 @@ namespace ngraph const PartialShape& pshape, const bool cacheable = false); + bool visit_attributes(AttributeVisitor& visitor) override; + bool is_parameter() const override { return true; } void validate_and_infer_types() override; diff --git a/src/ngraph/op/passthrough.hpp b/src/ngraph/op/passthrough.hpp index 9998e0316e1..c0cd05e4ab5 100644 --- a/src/ngraph/op/passthrough.hpp +++ b/src/ngraph/op/passthrough.hpp @@ -26,19 +26,22 @@ namespace ngraph { namespace op { - /// An op directly representing backend-specific code. - /// - /// N.B. Not all backends support all operation languages; a - /// given backend might only support a given passthrough - /// operation language in certain modes. - class Passthrough; + namespace v0 + { + /// An op directly representing backend-specific code. + /// + /// N.B. Not all backends support all operation languages; a + /// given backend might only support a given passthrough + /// operation language in certain modes. + class Passthrough; + } + using v0::Passthrough; } } -class ngraph::op::Passthrough final : public Op +class NGRAPH_API ngraph::op::v0::Passthrough final : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Passthrough", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } Passthrough() = default; diff --git a/src/ngraph/op/power.hpp b/src/ngraph/op/power.hpp index 83d5d0b95b6..2de8fc6428b 100644 --- a/src/ngraph/op/power.hpp +++ b/src/ngraph/op/power.hpp @@ -40,13 +40,15 @@ namespace ngraph /// | ---------------------- | -------------------------------------------------------------------------------------------------------------- | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \texttt{arg0}[i_1,\dots,i_n]^{\texttt{arg1}[i_1,\dots,i_n]}\f$ | // clang-format on - class Power : public util::BinaryElementwiseArithmetic + class NGRAPH_API Power : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Power", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } - Power() = default; + Power() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } /// \brief Constructs an exponentiation operation. /// /// \param arg0 Node that produces the first input tensor. @@ -83,13 +85,16 @@ namespace ngraph /// | ---------------------- | -------------------------------------------------------------------------------------------------------------- | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \texttt{arg0}[i_1,\dots,i_n]^{\texttt{arg1}[i_1,\dots,i_n]}\f$ | // clang-format on - class Power : public util::BinaryElementwiseArithmetic + class NGRAPH_API Power : public util::BinaryElementwiseArithmetic { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Power", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } - Power() = default; + Power() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + /// \brief Constructs an exponentiation operation. /// /// \param arg0 Node that produces the first input tensor. diff --git a/src/ngraph/op/product.hpp b/src/ngraph/op/product.hpp index c45b5cc21a7..63671b8e665 100644 --- a/src/ngraph/op/product.hpp +++ b/src/ngraph/op/product.hpp @@ -27,10 +27,9 @@ namespace ngraph /// \brief Product reduction operation. /// /// Reduces the tensor, eliminating the specified reduction axes by taking the product. - class Product : public util::ArithmeticReduction + class NGRAPH_API Product : public util::ArithmeticReduction { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Product", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a product reduction operation. diff --git a/src/ngraph/op/quantize.hpp b/src/ngraph/op/quantize.hpp index 67576da31be..3ba3a1d6713 100644 --- a/src/ngraph/op/quantize.hpp +++ b/src/ngraph/op/quantize.hpp @@ -24,91 +24,95 @@ namespace ngraph { namespace op { - /// \brief Quantize operation - /// Maps real input (r) to quantized output (q) using scale (s), zero point (z) and - /// round mode: q = ROUND(r / s) + o - class Quantize : public ngraph::op::Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Quantize", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - enum class RoundMode + /// \brief Quantize operation + /// Maps real input (r) to quantized output (q) using scale (s), zero point (z) + /// and + /// round mode: q = ROUND(r / s) + o + class NGRAPH_API Quantize : public ngraph::op::Op { - // round to nearest integer - // in case of two equidistant integers round away from zero e.g. - // 2.5 -> 3 - // -3.5 -> -4 - ROUND_NEAREST_TOWARD_INFINITY, - - // round to nearest integer - // in case of two equidistant integers round toward zero e.g. - // 2.5 -> 2 - // -3.5 -> -3 - ROUND_NEAREST_TOWARD_ZERO, - - // round to nearest integer - // in case of two equidistant integers round up e.g. - // 2.5 -> 3 - // -3.5 -> -3 - ROUND_NEAREST_UPWARD, - - // round to nearest integer - // in case of two equidistant integers round down e.g. - // 2.5 -> 2 - // -3.5 -> -4 - ROUND_NEAREST_DOWNWARD, - - // round to nearest integer - // in case of two equidistant integers round to even e.g. - // 2.5 -> 2 - // -3.5 -> -4 - ROUND_NEAREST_TOWARD_EVEN, - - // round to nearest integer away from zero - ROUND_TOWARD_INFINITY, - - // round to nearest integer toward zero - ROUND_TOWARD_ZERO, - - // round to nearest integer toward infinity (ceiling) - ROUND_UP, - - // round to nearest integer toward negative infinity (floor) - ROUND_DOWN, + public: + static constexpr NodeTypeInfo type_info{"Quantize", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + enum class RoundMode + { + // round to nearest integer + // in case of two equidistant integers round away from zero e.g. + // 2.5 -> 3 + // -3.5 -> -4 + ROUND_NEAREST_TOWARD_INFINITY, + + // round to nearest integer + // in case of two equidistant integers round toward zero e.g. + // 2.5 -> 2 + // -3.5 -> -3 + ROUND_NEAREST_TOWARD_ZERO, + + // round to nearest integer + // in case of two equidistant integers round up e.g. + // 2.5 -> 3 + // -3.5 -> -3 + ROUND_NEAREST_UPWARD, + + // round to nearest integer + // in case of two equidistant integers round down e.g. + // 2.5 -> 2 + // -3.5 -> -4 + ROUND_NEAREST_DOWNWARD, + + // round to nearest integer + // in case of two equidistant integers round to even e.g. + // 2.5 -> 2 + // -3.5 -> -4 + ROUND_NEAREST_TOWARD_EVEN, + + // round to nearest integer away from zero + ROUND_TOWARD_INFINITY, + + // round to nearest integer toward zero + ROUND_TOWARD_ZERO, + + // round to nearest integer toward infinity (ceiling) + ROUND_UP, + + // round to nearest integer toward negative infinity (floor) + ROUND_DOWN, + }; + + /// \brief Constructs a Quantize operation + /// \param input real input + /// \param scale scale used for mapping + /// \param zero_point zero point used for mapping + /// \param type output element type + /// \param axes axis positions on which `scale` and `zero_point` are specified + /// \param round_mode describes how to perform ROUND function (see above) + Quantize(const Output& input, + const Output& scale, + const Output& zero_point, + const ngraph::element::Type& type, + const ngraph::AxisSet& axes, + RoundMode round_mode); + + Quantize() = default; + + void validate_and_infer_types() override; + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + const ngraph::AxisSet& get_axes() const { return m_axes; } + RoundMode get_round_mode() const { return m_round_mode; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + + private: + ngraph::element::Type m_type; + ngraph::AxisSet m_axes; + RoundMode m_round_mode; }; - - /// \brief Constructs a Quantize operation - /// \param input real input - /// \param scale scale used for mapping - /// \param zero_point zero point used for mapping - /// \param type output element type - /// \param axes axis positions on which `scale` and `zero_point` are specified - /// \param round_mode describes how to perform ROUND function (see above) - Quantize(const Output& input, - const Output& scale, - const Output& zero_point, - const ngraph::element::Type& type, - const ngraph::AxisSet& axes, - RoundMode round_mode); - - Quantize() = default; - - void validate_and_infer_types() override; - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - const ngraph::AxisSet& get_axes() const { return m_axes; } - RoundMode get_round_mode() const { return m_round_mode; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - - private: - ngraph::element::Type m_type; - ngraph::AxisSet m_axes; - RoundMode m_round_mode; - }; + } + using v0::Quantize; } } diff --git a/src/ngraph/op/quantized_convolution.hpp b/src/ngraph/op/quantized_convolution.hpp index f0c916e8487..67c33bfbe04 100644 --- a/src/ngraph/op/quantized_convolution.hpp +++ b/src/ngraph/op/quantized_convolution.hpp @@ -23,79 +23,88 @@ namespace ngraph { namespace op { - class QuantizedConvolution : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"QuantizedConvolution", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a quantized convolution operation. - /// - /// \param input The node producing the input data batch tensor. - /// \param filters The node producing the filters tensor. - /// \param window_movement_strides The window movement strides. - /// \param window_dilation_strides The window dilation strides. - /// \param padding_below The padding-below sizes. - /// \param padding_above The padding-above sizes. - /// \param data_dilation_strides The data dilation strides. - /// \param input_scale Scale to transform the input - /// \param input_zero_point Zero point used for mapping - /// \param filter_scale Scale to transform the filters - /// \param filter_zero_point Zero point used for mapping - /// \param output_scale Scale to transform the output - /// \param output_zero_point Zero point used for mapping - /// \param output_type Output element type - /// \param input_axes Input axes set for channel wise quantization - /// \param filter_axes Filter axes set for channel wise quantization - /// \param output_axes Output axes set for channel wise quantization - QuantizedConvolution(const Output& input, - const Output& filters, - const Strides& window_movement_strides, - const Strides& window_dilation_strides, - const CoordinateDiff& padding_below, - const CoordinateDiff& padding_above, - const Strides& data_dilation_strides, - const Output& input_scale, - const Output& input_zero_point, - const Output& filter_scale, - const Output& filter_zero_point, - const Output& output_scale, - const Output& output_zero_point, - const ngraph::element::Type& output_type, - const ngraph::AxisSet& input_axes = ngraph::AxisSet{}, - const ngraph::AxisSet& filter_axes = ngraph::AxisSet{}, - const ngraph::AxisSet& output_axes = ngraph::AxisSet{}); + class NGRAPH_API QuantizedConvolution : public Op + { + public: + static constexpr NodeTypeInfo type_info{"QuantizedConvolution", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a quantized convolution operation. + /// + /// \param input The node producing the input data batch tensor. + /// \param filters The node producing the filters tensor. + /// \param window_movement_strides The window movement strides. + /// \param window_dilation_strides The window dilation strides. + /// \param padding_below The padding-below sizes. + /// \param padding_above The padding-above sizes. + /// \param data_dilation_strides The data dilation strides. + /// \param input_scale Scale to transform the input + /// \param input_zero_point Zero point used for mapping + /// \param filter_scale Scale to transform the filters + /// \param filter_zero_point Zero point used for mapping + /// \param output_scale Scale to transform the output + /// \param output_zero_point Zero point used for mapping + /// \param output_type Output element type + /// \param input_axes Input axes set for channel wise quantization + /// \param filter_axes Filter axes set for channel wise quantization + /// \param output_axes Output axes set for channel wise quantization + QuantizedConvolution(const Output& input, + const Output& filters, + const Strides& window_movement_strides, + const Strides& window_dilation_strides, + const CoordinateDiff& padding_below, + const CoordinateDiff& padding_above, + const Strides& data_dilation_strides, + const Output& input_scale, + const Output& input_zero_point, + const Output& filter_scale, + const Output& filter_zero_point, + const Output& output_scale, + const Output& output_zero_point, + const ngraph::element::Type& output_type, + const ngraph::AxisSet& input_axes = ngraph::AxisSet{}, + const ngraph::AxisSet& filter_axes = ngraph::AxisSet{}, + const ngraph::AxisSet& output_axes = ngraph::AxisSet{}); - QuantizedConvolution() = default; + QuantizedConvolution() = default; - const Strides& get_window_movement_strides() const { return m_window_movement_strides; } - const Strides& get_window_dilation_strides() const { return m_window_dilation_strides; } - const CoordinateDiff& get_padding_below() const { return m_padding_below; } - const CoordinateDiff& get_padding_above() const { return m_padding_above; } - const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } - std::shared_ptr get_filters() { return get_argument(1); } - std::shared_ptr get_data_batch() { return get_argument(0); } - const ngraph::element::Type& get_output_type() const { return m_output_type; } - const ngraph::AxisSet& get_input_axes() const { return m_input_axes; } - const ngraph::AxisSet& get_filter_axes() const { return m_filter_axes; } - const ngraph::AxisSet& get_output_axes() const { return m_output_axes; } - void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + const Strides& get_window_movement_strides() const + { + return m_window_movement_strides; + } + const Strides& get_window_dilation_strides() const + { + return m_window_dilation_strides; + } + const CoordinateDiff& get_padding_below() const { return m_padding_below; } + const CoordinateDiff& get_padding_above() const { return m_padding_above; } + const Strides& get_data_dilation_strides() const { return m_data_dilation_strides; } + std::shared_ptr get_filters() { return get_argument(1); } + std::shared_ptr get_data_batch() { return get_argument(0); } + const ngraph::element::Type& get_output_type() const { return m_output_type; } + const ngraph::AxisSet& get_input_axes() const { return m_input_axes; } + const ngraph::AxisSet& get_filter_axes() const { return m_filter_axes; } + const ngraph::AxisSet& get_output_axes() const { return m_output_axes; } + void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - protected: - Strides m_window_movement_strides; - Strides m_window_dilation_strides; - CoordinateDiff m_padding_below; - CoordinateDiff m_padding_above; - Strides m_data_dilation_strides; - ngraph::element::Type m_output_type; - ngraph::AxisSet m_input_axes; - ngraph::AxisSet m_filter_axes; - ngraph::AxisSet m_output_axes; - }; + protected: + Strides m_window_movement_strides; + Strides m_window_dilation_strides; + CoordinateDiff m_padding_below; + CoordinateDiff m_padding_above; + Strides m_data_dilation_strides; + ngraph::element::Type m_output_type; + ngraph::AxisSet m_input_axes; + ngraph::AxisSet m_filter_axes; + ngraph::AxisSet m_output_axes; + }; + } + using v0::QuantizedConvolution; } } diff --git a/src/ngraph/op/quantized_dot.hpp b/src/ngraph/op/quantized_dot.hpp index a2cc3917e4d..a933d79bef4 100644 --- a/src/ngraph/op/quantized_dot.hpp +++ b/src/ngraph/op/quantized_dot.hpp @@ -22,65 +22,69 @@ namespace ngraph { namespace op { - class QuantizedDot : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"QuantizedDot", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a quantized convolution operation. - /// - /// \param input0 The node producing the input data batch tensor. - /// \param input1 The node producing the filters tensor. - /// \param input0_scale Scale to transform the input - /// \param input0_zero_point Zero point used for mapping - /// \param input1_scale Scale to transform the filters - /// \param input1_zero_point Zero point used for mapping - /// \param output_scale Scale to transform the output - /// \param output_zero_point Zero point used for mapping - /// \param output_type Output element type - /// \param input0_axes Input0 axes set for channel wise quantization - /// \param input1_axes Input1 axes set for channel wise quantization - /// \param output_axes Output axes set for channel wise quantization - QuantizedDot(const Output& input0, - const Output& input1, - size_t reduction_axes_count, - const Output& input0_scale, - const Output& input0_zero_point, - const Output& input1_scale, - const Output& input1_zero_point, - const Output& output_scale, - const Output& output_zero_point, - const element::Type& output_type, - const AxisSet& input0_axes = ngraph::AxisSet{}, - const AxisSet& input1_axes = ngraph::AxisSet{}, - const AxisSet& output_axes = ngraph::AxisSet{}); - - std::shared_ptr get_input0() { return get_argument(0); } - std::shared_ptr get_input1() { return get_argument(1); } - const ngraph::element::Type& get_output_type() const { return m_output_type; } - const ngraph::AxisSet& get_input0_axes() const { return m_input0_axes; } - const ngraph::AxisSet& get_input1_axes() const { return m_input1_axes; } - const ngraph::AxisSet& get_output_axes() const { return m_output_axes; } - size_t get_reduction_axes_count() const { return m_reduction_axes_count; } - void set_reduction_axes_count(size_t reduction_axes_count) + class NGRAPH_API QuantizedDot : public Op { - m_reduction_axes_count = reduction_axes_count; - } - void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + public: + static constexpr NodeTypeInfo type_info{"QuantizedDot", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + QuantizedDot() = default; + /// \brief Constructs a quantized convolution operation. + /// + /// \param input0 The node producing the input data batch tensor. + /// \param input1 The node producing the filters tensor. + /// \param input0_scale Scale to transform the input + /// \param input0_zero_point Zero point used for mapping + /// \param input1_scale Scale to transform the filters + /// \param input1_zero_point Zero point used for mapping + /// \param output_scale Scale to transform the output + /// \param output_zero_point Zero point used for mapping + /// \param output_type Output element type + /// \param input0_axes Input0 axes set for channel wise quantization + /// \param input1_axes Input1 axes set for channel wise quantization + /// \param output_axes Output axes set for channel wise quantization + QuantizedDot(const Output& input0, + const Output& input1, + size_t reduction_axes_count, + const Output& input0_scale, + const Output& input0_zero_point, + const Output& input1_scale, + const Output& input1_zero_point, + const Output& output_scale, + const Output& output_zero_point, + const element::Type& output_type, + const AxisSet& input0_axes = ngraph::AxisSet{}, + const AxisSet& input1_axes = ngraph::AxisSet{}, + const AxisSet& output_axes = ngraph::AxisSet{}); + + std::shared_ptr get_input0() { return get_argument(0); } + std::shared_ptr get_input1() { return get_argument(1); } + const ngraph::element::Type& get_output_type() const { return m_output_type; } + const ngraph::AxisSet& get_input0_axes() const { return m_input0_axes; } + const ngraph::AxisSet& get_input1_axes() const { return m_input1_axes; } + const ngraph::AxisSet& get_output_axes() const { return m_output_axes; } + size_t get_reduction_axes_count() const { return m_reduction_axes_count; } + void set_reduction_axes_count(size_t reduction_axes_count) + { + m_reduction_axes_count = reduction_axes_count; + } + void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - protected: - size_t m_reduction_axes_count; - bool m_has_reduction_axes_count; - ngraph::element::Type m_output_type; - ngraph::AxisSet m_input0_axes; - ngraph::AxisSet m_input1_axes; - ngraph::AxisSet m_output_axes; - }; + protected: + size_t m_reduction_axes_count; + bool m_has_reduction_axes_count; + ngraph::element::Type m_output_type; + ngraph::AxisSet m_input0_axes; + ngraph::AxisSet m_input1_axes; + ngraph::AxisSet m_output_axes; + }; + } + using v0::QuantizedDot; } } diff --git a/src/ngraph/op/recv.hpp b/src/ngraph/op/recv.hpp index 5f4c69ee442..e5f02561ae5 100644 --- a/src/ngraph/op/recv.hpp +++ b/src/ngraph/op/recv.hpp @@ -24,28 +24,31 @@ namespace ngraph { namespace op { - class Recv : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Recv", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an unitialized recv operation. - Recv() = default; - /// \brief Constructs a Recv operation. - /// - /// \param arg The node for tensor to receive data - /// \param src_id the source id which could be rank or node id. - Recv(const Output& arg, int src_id); + class NGRAPH_API Recv : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Recv", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an unitialized recv operation. + Recv() = default; + /// \brief Constructs a Recv operation. + /// + /// \param arg The node for tensor to receive data + /// \param src_id the source id which could be rank or node id. + Recv(const Output& arg, int src_id); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - int get_src_id() const; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + int get_src_id() const; - private: - int m_src_id; - }; + private: + int m_src_id; + }; + } + using v0::Recv; } } diff --git a/src/ngraph/op/reduce_logical_and.cpp b/src/ngraph/op/reduce_logical_and.cpp new file mode 100644 index 00000000000..fa31f354d31 --- /dev/null +++ b/src/ngraph/op/reduce_logical_and.cpp @@ -0,0 +1,36 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/reduce_logical_and.hpp" + +using namespace ngraph; +using namespace std; + +constexpr NodeTypeInfo op::v1::ReduceLogicalAnd::type_info; + +op::v1::ReduceLogicalAnd::ReduceLogicalAnd(const Output& data, + const Output& reduction_axes, + const bool keep_dims) + : LogicalReductionKeepDims(data, reduction_axes, keep_dims) +{ + constructor_validate_and_infer_types(); +} + +shared_ptr op::v1::ReduceLogicalAnd::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), get_keep_dims()); +} diff --git a/src/ngraph/op/reduce_logical_and.hpp b/src/ngraph/op/reduce_logical_and.hpp new file mode 100644 index 00000000000..de28818d55e --- /dev/null +++ b/src/ngraph/op/reduce_logical_and.hpp @@ -0,0 +1,53 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/util/logical_reduction_keep_dims.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Performs a reduction using "logical and" + /// + /// The reduction is performed over slices of the first input. The slices shape depends + /// on the values passed to the second input - the axes. + class ReduceLogicalAnd : public util::LogicalReductionKeepDims + { + public: + NGRAPH_API + static constexpr NodeTypeInfo type_info{"ReduceLogicalAnd", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReduceLogicalAnd() = default; + /// \brief Constructs a ReduceLogicalAnd node. + /// + /// \param data - The input tensor with data to be reduced + /// \param reduction_axes - The input tensor with information about axes over which + /// the first tensor should be sliced prior to the reduction operation + /// \param keep_dims - Indicates if the axes used for reduction should be held/kept + ReduceLogicalAnd(const Output& data, + const Output& reduction_axes, + const bool keep_dims = false); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + } +} diff --git a/src/ngraph/op/reduce_logical_or.cpp b/src/ngraph/op/reduce_logical_or.cpp new file mode 100644 index 00000000000..5e29ea35c95 --- /dev/null +++ b/src/ngraph/op/reduce_logical_or.cpp @@ -0,0 +1,36 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/reduce_logical_or.hpp" + +using namespace ngraph; +using namespace std; + +constexpr NodeTypeInfo op::v1::ReduceLogicalOr::type_info; + +op::v1::ReduceLogicalOr::ReduceLogicalOr(const Output& data, + const Output& reduction_axes, + const bool keep_dims) + : LogicalReductionKeepDims(data, reduction_axes, keep_dims) +{ + constructor_validate_and_infer_types(); +} + +shared_ptr op::v1::ReduceLogicalOr::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), get_keep_dims()); +} diff --git a/src/ngraph/op/reduce_logical_or.hpp b/src/ngraph/op/reduce_logical_or.hpp new file mode 100644 index 00000000000..189028960fd --- /dev/null +++ b/src/ngraph/op/reduce_logical_or.hpp @@ -0,0 +1,53 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/util/logical_reduction_keep_dims.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief Performs a reduction using "logical or" + /// + /// The reduction is performed over slices of the first input. The slices shape depends + /// on the values passed to the second input - the axes. + class ReduceLogicalOr : public util::LogicalReductionKeepDims + { + public: + NGRAPH_API + static constexpr NodeTypeInfo type_info{"ReduceLogicalOr", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReduceLogicalOr() = default; + /// \brief Constructs a ReduceLogicalOr node. + /// + /// \param data - The input tensor with data to be reduced + /// \param reduction_axes - The input tensor with information about axes over which + /// the first tensor should be sliced prior to the reduction operation + /// \param keep_dims - Indicates if the axes used for reduction should be held/kept + ReduceLogicalOr(const Output& data, + const Output& reduction_axes, + const bool keep_dims = false); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + } +} diff --git a/src/ngraph/op/reduce_mean.hpp b/src/ngraph/op/reduce_mean.hpp index 600230a2e9a..18eb9c0b72a 100644 --- a/src/ngraph/op/reduce_mean.hpp +++ b/src/ngraph/op/reduce_mean.hpp @@ -25,10 +25,9 @@ namespace ngraph { namespace v1 { - class ReduceMean : public util::ArithmeticReductionKeepDims + class NGRAPH_API ReduceMean : public util::ArithmeticReductionKeepDims { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"ReduceMean", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } ReduceMean() = default; diff --git a/src/ngraph/op/reduce_prod.hpp b/src/ngraph/op/reduce_prod.hpp index d32a9481b31..9de1ec42924 100644 --- a/src/ngraph/op/reduce_prod.hpp +++ b/src/ngraph/op/reduce_prod.hpp @@ -27,11 +27,10 @@ namespace ngraph /// \brief Product reduction operation. /// /// Reduces the tensor, eliminating the specified reduction axes by taking the product. - class ReduceProd : public util::ArithmeticReductionKeepDims + class NGRAPH_API ReduceProd : public util::ArithmeticReductionKeepDims { public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Product", 1}; + static constexpr NodeTypeInfo type_info{"ReduceProd", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a product reduction operation. ReduceProd() = default; diff --git a/src/ngraph/op/reduce_sum.hpp b/src/ngraph/op/reduce_sum.hpp index db8816938d9..531036d23d6 100644 --- a/src/ngraph/op/reduce_sum.hpp +++ b/src/ngraph/op/reduce_sum.hpp @@ -74,11 +74,10 @@ namespace ngraph /// | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | /// | \f$N[\textit{delete}(A,d_1,\dots,d_n)]\f$ | The tensor \f$T\f$, where \f$T\f$ is the input tensor with the `reduction_axes` \f$A\f$ eliminated by summation. | // clang-format off - class ReduceSum : public util::ArithmeticReductionKeepDims + class NGRAPH_API ReduceSum : public util::ArithmeticReductionKeepDims { public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sum", 1}; + static constexpr NodeTypeInfo type_info{"ReduceSum", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a summation operation. ReduceSum() = default; diff --git a/src/ngraph/op/relu.cpp b/src/ngraph/op/relu.cpp index 1a4d64fe291..98892c2ed02 100644 --- a/src/ngraph/op/relu.cpp +++ b/src/ngraph/op/relu.cpp @@ -36,7 +36,7 @@ shared_ptr op::Relu::copy_with_new_args(const NodeVector& new_args) const } op::ReluBackprop::ReluBackprop(shared_ptr arg, shared_ptr delta) - : BinaryElementwiseArithmetic(arg, delta) + : BinaryElementwiseArithmetic(arg, delta, AutoBroadcastSpec::NONE) { constructor_validate_and_infer_types(); } diff --git a/src/ngraph/op/relu.hpp b/src/ngraph/op/relu.hpp index 6bc7525245e..653fa671ea4 100644 --- a/src/ngraph/op/relu.hpp +++ b/src/ngraph/op/relu.hpp @@ -27,42 +27,50 @@ namespace ngraph { namespace op { - /// \brief Elementwise Relu operation. - /// - class Relu : public ngraph::op::util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Relu", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Relu() = default; - /// \brief Constructs a Relu operation. + /// \brief Elementwise Relu operation. /// - /// \param arg Node that produces the input tensor. - Relu(const Output& arg); + class NGRAPH_API Relu : public ngraph::op::util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Relu", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Relu() = default; + /// \brief Constructs a Relu operation. + /// + /// \param arg Node that produces the input tensor. + Relu(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; - /// \brief Elementwise ReluBackprop operation. - /// - class ReluBackprop : public ngraph::op::util::BinaryElementwiseArithmetic - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ReluBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a ReluBackprop operation. + /// \brief Elementwise ReluBackprop operation. /// - /// \param arg Node that produces the relu forward input tensor. - ReluBackprop(std::shared_ptr arg, std::shared_ptr delta); + class NGRAPH_API ReluBackprop : public ngraph::op::util::BinaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"ReluBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReluBackprop() + : BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } + /// \brief Constructs a ReluBackprop operation. + /// + /// \param arg Node that produces the relu forward input tensor. + ReluBackprop(std::shared_ptr arg, + std::shared_ptr delta); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Relu; + using v0::ReluBackprop; } } diff --git a/src/ngraph/op/replace_slice.hpp b/src/ngraph/op/replace_slice.hpp index ac9880530c7..2576d443977 100644 --- a/src/ngraph/op/replace_slice.hpp +++ b/src/ngraph/op/replace_slice.hpp @@ -24,7 +24,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Takes two input tensors of identical rank, with the second tensor no larger than /// the first in any dimension, and returns a copy of the first input tensor with /// the specified slice overwritten by the second input tensor. @@ -49,64 +51,69 @@ namespace ngraph /// | Type | Description | /// | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$E[d_1,\dots,d_n]\f$ | The tensor \f$T\f$ where \f$T[i_1,\dots,i_n] = \texttt{arg1}[j_1,\dots,j_n]\f$ if \f$j_1,\dots,j_n\f$ is in bounds for `arg1` and for all \f$m\f$, \f$i_m = l_m + j_m s_m\f$, otherwise \f$\texttt{arg0}[i_1,\dots,i_n]\f$. | - // clang-format on - class ReplaceSlice : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ReplaceSlice", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ReplaceSlice() = default; - /// \brief Constructs a tensor slice replacement operation. - /// - /// \param arg0 The tensor to overwrite into. - /// \param arg1 The tensor to write into `arg0`. - /// \param lower_bounds The axiswise lower bounds of the slice (inclusive). - /// \param upper_bounds The axiswise upper bounds of the slice (exclusive). - /// \param strides The slicing strides; for example, strides of `{n,m}` means to take - /// every nth row and every mth column of `arg0` as part of the - /// slice to be replaced. - ReplaceSlice(const Output& arg0, - const Output& arg1, - const Coordinate& lower_bounds, - const Coordinate& upper_bounds, - const Strides& strides); + // clang-format on + class NGRAPH_API ReplaceSlice : public Op + { + public: + static constexpr NodeTypeInfo type_info{"ReplaceSlice", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReplaceSlice() = default; + /// \brief Constructs a tensor slice replacement operation. + /// + /// \param arg0 The tensor to overwrite into. + /// \param arg1 The tensor to write into `arg0`. + /// \param lower_bounds The axiswise lower bounds of the slice (inclusive). + /// \param upper_bounds The axiswise upper bounds of the slice (exclusive). + /// \param strides The slicing strides; for example, strides of `{n,m}` means to + /// take + /// every nth row and every mth column of `arg0` as part of the + /// slice to be replaced. + ReplaceSlice(const Output& arg0, + const Output& arg1, + const Coordinate& lower_bounds, + const Coordinate& upper_bounds, + const Strides& strides); - /// \brief Constructs a tensor slice replacement operation with unit strides; i.e., - /// every element inside the bounding box will be overwritten. - /// - /// \param arg0 The tensor to overwrite into. - /// \param arg1 The tensor to write into `arg0`. - /// \param lower_bounds The axiswise lower bounds of the slice (inclusive). - /// \param upper_bounds The axiswise upper bounds of the slice (exclusive). - ReplaceSlice(const Output& arg0, - const Output& arg1, - const Coordinate& lower_bounds, - const Coordinate& upper_bounds); + /// \brief Constructs a tensor slice replacement operation with unit strides; i.e., + /// every element inside the bounding box will be overwritten. + /// + /// \param arg0 The tensor to overwrite into. + /// \param arg1 The tensor to write into `arg0`. + /// \param lower_bounds The axiswise lower bounds of the slice (inclusive). + /// \param upper_bounds The axiswise upper bounds of the slice (exclusive). + ReplaceSlice(const Output& arg0, + const Output& arg1, + const Coordinate& lower_bounds, + const Coordinate& upper_bounds); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - /// \return The inclusive lower-bound coordinates. - const Coordinate& get_lower_bounds() const { return m_lower_bounds; } - void set_lower_bounds(const Coordinate& lower_bounds) { m_lower_bounds = lower_bounds; } - /// \return The exclusive upper-bound coordinates. - const Coordinate& get_upper_bounds() const { return m_upper_bounds; } - void set_uppper_bounds(const Coordinate& upper_bounds) - { - m_upper_bounds = upper_bounds; - } - /// \return The slicing strides. - const Strides& get_strides() const { return m_strides; } - void set_strides(const Strides& strides) { m_strides = strides; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + /// \return The inclusive lower-bound coordinates. + const Coordinate& get_lower_bounds() const { return m_lower_bounds; } + void set_lower_bounds(const Coordinate& lower_bounds) + { + m_lower_bounds = lower_bounds; + } + /// \return The exclusive upper-bound coordinates. + const Coordinate& get_upper_bounds() const { return m_upper_bounds; } + void set_uppper_bounds(const Coordinate& upper_bounds) + { + m_upper_bounds = upper_bounds; + } + /// \return The slicing strides. + const Strides& get_strides() const { return m_strides; } + void set_strides(const Strides& strides) { m_strides = strides; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - Coordinate m_lower_bounds; - Coordinate m_upper_bounds; - Strides m_strides; - }; + Coordinate m_lower_bounds; + Coordinate m_upper_bounds; + Strides m_strides; + }; + } + using v0::ReplaceSlice; } } diff --git a/src/ngraph/op/reshape.cpp b/src/ngraph/op/reshape.cpp index 8849af7788b..fce224ede01 100644 --- a/src/ngraph/op/reshape.cpp +++ b/src/ngraph/op/reshape.cpp @@ -151,7 +151,7 @@ constexpr NodeTypeInfo op::v1::Reshape::type_info; op::v1::Reshape::Reshape(const Output& arg, const Output& pattern, bool zero_flag) : Op({arg, pattern}) - , m_zero_flag(zero_flag) + , m_special_zero(zero_flag) { constructor_validate_and_infer_types(); } @@ -193,7 +193,7 @@ void op::v1::Reshape::validate_and_infer_types() negative_dims, ")"); - if (!(zero_dims && m_zero_flag) && !negative_dims) + if (!(zero_dims && m_special_zero) && !negative_dims) { set_output_type(0, get_input_element_type(0), const_shape->get_shape_val()); } @@ -205,9 +205,9 @@ void op::v1::Reshape::validate_and_infer_types() out_shape_val.end(), partial_shape.begin(), [&](const int64_t& v) { - return (v < 0) - ? Dimension() - : ((v == 0 && m_zero_flag) ? Dimension() : Dimension(v)); + return (v < 0) ? Dimension() + : ((v == 0 && m_special_zero) ? Dimension() + : Dimension(v)); }); if (get_input_partial_shape(0).is_static()) @@ -219,7 +219,7 @@ void op::v1::Reshape::validate_and_infer_types() size_t input_elements = shape_size(input_shape); for (size_t i = 0; i < static_cast(output_rank); i++) { - if (out_shape_val[i] == 0 && m_zero_flag) + if (out_shape_val[i] == 0 && m_special_zero) { // Copy input_shape[i] for zero values NODE_VALIDATION_CHECK( @@ -274,7 +274,7 @@ void op::v1::Reshape::validate_and_infer_types() shared_ptr op::v1::Reshape::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1), m_zero_flag); + return make_shared(new_args.at(0), new_args.at(1), m_special_zero); } void op::v1::Reshape::generate_adjoints(autodiff::Adjoints& /* adjoints */, diff --git a/src/ngraph/op/reshape.hpp b/src/ngraph/op/reshape.hpp index 516ef7db5d0..f9a3ef17d55 100644 --- a/src/ngraph/op/reshape.hpp +++ b/src/ngraph/op/reshape.hpp @@ -24,7 +24,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Tensor reshape operation. /// /// "Converts" an input tensor into a new shape with the same number of elements. @@ -61,50 +63,51 @@ namespace ngraph /// | Type | Description | /// | ------------------------ | ------------------------------------------------------------------------------------------------------ | /// | \f$E[d'_1,\dots,d'_m]\f$ | The tensor \f$T\f$, where \f$T\f$ is the input tensor with its elements rearranged as described above. | - // clang-format on - class Reshape : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Reshape", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a reshape operation. - Reshape() = default; - /// \brief Constructs a reshape operation. - /// - /// \param arg The tensor to be reshaped. - /// \param input_order The order in which to iterate over input axes. This must be a - /// permutation of the sequence \f$(0,\dots,n-1)\f$ where \f$n\f$ is - /// the rank of the input tensor. - /// \param output_shape The output shape. If the input shape is - /// \f$(a_0,\dots,a_{k-1})\f$ then the output shape must - /// be of the form \f$(b_0,\dots,b_{j-1})\f$ where - /// \f$\Pi(a_i) = \Pi(b_i)\f$. - Reshape(const Output& arg, - const AxisVector& input_order, - const Shape& output_shape); + // clang-format on + class NGRAPH_API Reshape : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Reshape", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a reshape operation. + Reshape() = default; + /// \brief Constructs a reshape operation. + /// + /// \param arg The tensor to be reshaped. + /// \param input_order The order in which to iterate over input axes. This must be a + /// permutation of the sequence \f$(0,\dots,n-1)\f$ where \f$n\f$ + /// is + /// the rank of the input tensor. + /// \param output_shape The output shape. If the input shape is + /// \f$(a_0,\dots,a_{k-1})\f$ then the output shape must + /// be of the form \f$(b_0,\dots,b_{j-1})\f$ where + /// \f$\Pi(a_i) = \Pi(b_i)\f$. + Reshape(const Output& arg, + const AxisVector& input_order, + const Shape& output_shape); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - /// \return The order in which to iterate over input axes. - const AxisVector& get_input_order() const { return m_input_order; } - void set_input_order(const AxisVector& input_order) { m_input_order = input_order; } - /// \return The shape of the output tensor. - const Shape& get_output_shape() const { return m_output_shape; } - void set_output_shape(const Shape& output_shape) { m_output_shape = output_shape; } - bool get_is_transpose() const { return m_is_transpose; } - void set_is_transpose(bool is_transpose) { m_is_transpose = is_transpose; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + /// \return The order in which to iterate over input axes. + const AxisVector& get_input_order() const { return m_input_order; } + void set_input_order(const AxisVector& input_order) { m_input_order = input_order; } + /// \return The shape of the output tensor. + const Shape& get_output_shape() const { return m_output_shape; } + void set_output_shape(const Shape& output_shape) { m_output_shape = output_shape; } + bool get_is_transpose() const { return m_is_transpose; } + void set_is_transpose(bool is_transpose) { m_is_transpose = is_transpose; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - AxisVector m_input_order; - Shape m_output_shape; - bool m_is_transpose{false}; - }; + AxisVector m_input_order; + Shape m_output_shape; + bool m_is_transpose{false}; + }; + } namespace v1 { @@ -113,11 +116,10 @@ namespace ngraph /// "Converts" an input tensor into a new shape with the same number of elements. /// This op does not touch the actual data. If needed, use Transpose for that purpose. /// - class Reshape : public Op + class NGRAPH_API Reshape : public Op { public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"DynReshape", 1}; + static constexpr NodeTypeInfo type_info{"Reshape", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } Reshape() = default; /// \brief Constructs a dynamic reshape operation. This operation does not perform @@ -130,11 +132,10 @@ namespace ngraph /// be of the form \f$(b_0,\dots,b_{j-1})\f$ where \f$\Pi(a_i) = \Pi(b_i)\f$. /// A value of -1 is allowed for at most one dimension, in which case the /// dimension size is inferred based on element count of input tensor. - /// \param zero_flag Treats zeros in `pattern` as wildcard flags indicating a copy + /// \param special_zero Treats zeros in `pattern` as wildcard flags indicating a + /// copy /// from input shape at the same index. - Reshape(const Output& arg, - const Output& pattern, - bool zero_flag = false); + Reshape(const Output& arg, const Output& pattern, bool special_zero); void validate_and_infer_types() override; @@ -142,15 +143,16 @@ namespace ngraph virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - bool get_zero_flag() const { return m_zero_flag; } - void set_zero_flag(bool zero_flag) { m_zero_flag = zero_flag; } + bool get_special_zero() const { return m_special_zero; } + void set_special_zero(bool special_zero) { m_special_zero = special_zero; } protected: virtual void generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) override; private: - bool m_zero_flag; + bool m_special_zero; }; } + using v0::Reshape; } } diff --git a/src/ngraph/op/result.hpp b/src/ngraph/op/result.hpp index c64288cf2b0..03dfeae337c 100644 --- a/src/ngraph/op/result.hpp +++ b/src/ngraph/op/result.hpp @@ -24,10 +24,9 @@ namespace ngraph { namespace op { - class Result : public Op + class NGRAPH_API Result : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Result", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Allows a value to be used as a function result. diff --git a/src/ngraph/op/reverse.hpp b/src/ngraph/op/reverse.hpp index 2bc5996a531..e54710262a6 100644 --- a/src/ngraph/op/reverse.hpp +++ b/src/ngraph/op/reverse.hpp @@ -48,10 +48,9 @@ namespace ngraph /// | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$E[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \texttt{arg}[j_1,\dots,j_n]\f$ and \f$j_k = d_k - i_k - 1\f$ if axis \f$k\f$ is in the reverse set; else \f$j_k = i_k\f$. | // clang-format on - class Reverse : public Op + class NGRAPH_API Reverse : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Reverse", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } Reverse() = default; @@ -83,7 +82,7 @@ namespace ngraph namespace v1 { - class Reverse : public Op + class NGRAPH_API Reverse : public Op { public: enum class Mode @@ -92,7 +91,6 @@ namespace ngraph MASK }; - NGRAPH_API static constexpr NodeTypeInfo type_info{"Reverse", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } Reverse() = default; diff --git a/src/ngraph/op/reverse_sequence.cpp b/src/ngraph/op/reverse_sequence.cpp index e3259b9b592..38303cd17ed 100644 --- a/src/ngraph/op/reverse_sequence.cpp +++ b/src/ngraph/op/reverse_sequence.cpp @@ -19,6 +19,7 @@ #include "ngraph/node.hpp" #include "ngraph/op/reverse_sequence.hpp" +#include "ngraph/validation_util.hpp" using namespace std; using namespace ngraph; @@ -27,11 +28,13 @@ constexpr NodeTypeInfo op::ReverseSequence::type_info; op::ReverseSequence::ReverseSequence(const Output& arg, const Output& seq_indices, - size_t batch_axis, - size_t seq_axis) + int64_t batch_axis, + int64_t seq_axis) : Op({arg, seq_indices}) , m_batch_axis(batch_axis) , m_seq_axis(seq_axis) + , m_normalized_batch_axis{0} + , m_normalized_seq_axis{0} { constructor_validate_and_infer_types(); } @@ -41,21 +44,30 @@ void op::ReverseSequence::validate_and_infer_types() auto input_shape = get_input_partial_shape(0); auto input_rank = input_shape.rank(); - NODE_VALIDATION_CHECK(this, - input_rank.is_dynamic() || m_batch_axis < size_t(input_rank), - "Batch axis index (", - m_batch_axis, - ") is out of bounds (argument shape: ", - input_shape, - ")."); - - NODE_VALIDATION_CHECK(this, - input_rank.is_dynamic() || m_seq_axis < size_t(input_rank), - "Sequence axis index (", - m_seq_axis, - ") is out of bounds (argument shape: ", - input_shape, - ")."); + if (m_batch_axis < 0 || m_seq_axis < 0) + { + NODE_VALIDATION_CHECK(this, + input_rank.is_static(), + "In order to handle negative axes input_rank must be static (", + "batch_axis=", + m_batch_axis, + ", seq_axis=", + m_seq_axis, + ")"); + } + else + { + m_normalized_batch_axis = m_batch_axis; + m_normalized_seq_axis = m_seq_axis; + } + + if (input_rank.is_static()) + { + m_normalized_batch_axis = + ngraph::normalize_axis(this, m_batch_axis, static_cast(input_rank)); + m_normalized_seq_axis = + ngraph::normalize_axis(this, m_seq_axis, static_cast(input_rank)); + } auto indices_shape = get_input_partial_shape(1); auto indices_rank = indices_shape.rank(); @@ -73,20 +85,21 @@ void op::ReverseSequence::validate_and_infer_types() { Dimension merged_sequence_length; - NODE_VALIDATION_CHECK( - this, - Dimension::merge(merged_sequence_length, input_shape[m_batch_axis], indices_shape[0]), - "Sequence length (", - indices_shape[0], - ") is not equal to batch axis ", - "dimension (", - input_shape[m_batch_axis], - ") (argument shape: ", - input_shape, - ", sequence indices shape: ", - indices_shape, - ")."); - output_shape[m_batch_axis] = merged_sequence_length; + NODE_VALIDATION_CHECK(this, + Dimension::merge(merged_sequence_length, + input_shape[m_normalized_batch_axis], + indices_shape[0]), + "Sequence length (", + indices_shape[0], + ") is not equal to batch axis ", + "dimension (", + input_shape[m_normalized_batch_axis], + ") (argument shape: ", + input_shape, + ", sequence indices shape: ", + indices_shape, + ")."); + output_shape[m_normalized_batch_axis] = merged_sequence_length; } set_output_type(0, get_input_element_type(0), output_shape); diff --git a/src/ngraph/op/reverse_sequence.hpp b/src/ngraph/op/reverse_sequence.hpp index 0106e742d0f..ad02860d7d2 100644 --- a/src/ngraph/op/reverse_sequence.hpp +++ b/src/ngraph/op/reverse_sequence.hpp @@ -22,37 +22,44 @@ namespace ngraph { namespace op { - class ReverseSequence : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ReverseSequence", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ReverseSequence() = default; - /// \brief Constructs an arcsin operation. - /// - /// \param arg Node that produces the input tensor. - ReverseSequence(const Output& arg, - const Output& seq_lengths, - size_t batch_axis, - size_t seq_axis); + class NGRAPH_API ReverseSequence : public Op + { + public: + static constexpr NodeTypeInfo type_info{"ReverseSequence", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ReverseSequence() = default; + /// \brief Constructs an arcsin operation. + /// + /// \param arg Node that produces the input tensor. + ReverseSequence(const Output& arg, + const Output& seq_lengths, + int64_t batch_axis, + int64_t seq_axis); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - size_t get_batch_axis() const { return m_batch_axis; } - void set_batch_axis(size_t batch_axis) { m_batch_axis = batch_axis; } - size_t get_sequence_axis() const { return m_seq_axis; } - void set_sequence_axis(size_t sequence_axis) { m_seq_axis = sequence_axis; } - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; + size_t get_batch_axis() const { return m_normalized_batch_axis; } + int64_t get_origin_batch_axis() const { return m_batch_axis; } + void set_batch_axis(int64_t batch_axis) { m_batch_axis = batch_axis; } + size_t get_sequence_axis() const { return m_normalized_seq_axis; } + int64_t get_origin_sequence_axis() const { return m_seq_axis; } + void set_sequence_axis(int64_t sequence_axis) { m_seq_axis = sequence_axis; } + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; - private: - size_t m_batch_axis{0}; - size_t m_seq_axis{0}; - }; + private: + int64_t m_batch_axis; + int64_t m_seq_axis; + size_t m_normalized_batch_axis; + size_t m_normalized_seq_axis; + }; + } + using v0::ReverseSequence; } } diff --git a/src/ngraph/op/scatter_add.hpp b/src/ngraph/op/scatter_add.hpp index 7bcc32eaec3..025c5a37c20 100644 --- a/src/ngraph/op/scatter_add.hpp +++ b/src/ngraph/op/scatter_add.hpp @@ -22,35 +22,38 @@ namespace ngraph { namespace op { - /// \brief Add updates to slices from inputs addressed by indices - class ScatterAdd : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ScatterAdd", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ScatterAdd() = default; - /// \param inputs Tensor - /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` - /// \param updates Tensor: Must have same type as inputs - ScatterAdd(const Output& inputs, - const Output& indices, - const Output& updates) - : Op({inputs, indices, updates}) + /// \brief Add updates to slices from inputs addressed by indices + class NGRAPH_API ScatterAdd : public Op { - constructor_validate_and_infer_types(); - } + public: + static constexpr NodeTypeInfo type_info{"ScatterAdd", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ScatterAdd() = default; + /// \param inputs Tensor + /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` + /// \param updates Tensor: Must have same type as inputs + ScatterAdd(const Output& inputs, + const Output& indices, + const Output& updates) + : Op({inputs, indices, updates}) + { + constructor_validate_and_infer_types(); + } - void validate_and_infer_types() override; + void validate_and_infer_types() override; - void generate_adjoints(autodiff::Adjoints& /* adjoints */, - const NodeVector& /* deltas */) override - { - throw ngraph_error("Not yet implemented"); - } + void generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) override + { + throw ngraph_error("Not yet implemented"); + } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::ScatterAdd; } } diff --git a/src/ngraph/op/scatter_nd_add.cpp b/src/ngraph/op/scatter_nd_add.cpp index f8f80d5dea4..f88794b5d48 100644 --- a/src/ngraph/op/scatter_nd_add.cpp +++ b/src/ngraph/op/scatter_nd_add.cpp @@ -77,18 +77,16 @@ void op::ScatterNDAdd::validate_and_infer_types() bool compatible = true; if (inputs_shape.is_static() && indices_shape.is_static() && updates_shape.is_static()) { - for (size_t i = 0; i < static_cast(indices_shape.rank()) - 1; i++) + size_t indices_rank = static_cast(indices_shape.rank()); + size_t updates_rank = static_cast(updates_shape.rank()); + for (size_t i = 0; i < indices_rank - 1; i++) { compatible = compatible && updates_shape[i].same_scheme(indices_shape[i]); } - size_t j = - static_cast(indices_shape[static_cast(indices_shape.rank()) - 1]); - for (size_t i = j; i < static_cast(inputs_shape.rank()); i++) + size_t j = static_cast(indices_shape[indices_rank - 1]); + for (size_t i = indices_rank - 1; i < updates_rank; i++, j++) { - compatible = - compatible && - updates_shape[static_cast(indices_shape.rank()) + i - 2].same_scheme( - inputs_shape[i]); + compatible = compatible && updates_shape[i].same_scheme(inputs_shape[j]); } } diff --git a/src/ngraph/op/scatter_nd_add.hpp b/src/ngraph/op/scatter_nd_add.hpp index 18849e14406..a7fd94d54e7 100644 --- a/src/ngraph/op/scatter_nd_add.hpp +++ b/src/ngraph/op/scatter_nd_add.hpp @@ -22,35 +22,38 @@ namespace ngraph { namespace op { - /// \brief Add updates to slices from inputs addressed by indices - class ScatterNDAdd : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"ScatterNDAdd", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - ScatterNDAdd() = default; - /// \param inputs Tensor - /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` - /// \param updates Tensor: Must have same type as inputs - ScatterNDAdd(const Output& inputs, - const Output& indices, - const Output& updates) - : Op({inputs, indices, updates}) + /// \brief Add updates to slices from inputs addressed by indices + class NGRAPH_API ScatterNDAdd : public Op { - constructor_validate_and_infer_types(); - } + public: + static constexpr NodeTypeInfo type_info{"ScatterNDAdd", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + ScatterNDAdd() = default; + /// \param inputs Tensor + /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` + /// \param updates Tensor: Must have same type as inputs + ScatterNDAdd(const Output& inputs, + const Output& indices, + const Output& updates) + : Op({inputs, indices, updates}) + { + constructor_validate_and_infer_types(); + } - void validate_and_infer_types() override; + void validate_and_infer_types() override; - void generate_adjoints(autodiff::Adjoints& /* adjoints */, - const NodeVector& /* deltas */) override - { - throw ngraph_error("Not yet implemented"); - } + void generate_adjoints(autodiff::Adjoints& /* adjoints */, + const NodeVector& /* deltas */) override + { + throw ngraph_error("Not yet implemented"); + } - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::ScatterNDAdd; } } diff --git a/src/ngraph/op/select.hpp b/src/ngraph/op/select.hpp index c0f71e64e57..7cfb41b2ada 100644 --- a/src/ngraph/op/select.hpp +++ b/src/ngraph/op/select.hpp @@ -22,7 +22,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Elementwise selection operation. /// /// ## Inputs @@ -38,29 +40,32 @@ namespace ngraph /// | Type | Description | /// | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$E[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \texttt{arg1}[i_1,\dots,i_n]\text{ if }\texttt{arg0}[i_1,\dots,i_n] \neq 0\text{, else }\texttt{arg2}[i_1,\dots,i_n]\f$ | - // clang-format on - class Select : public Op - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Select", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a selection operation. - Select() = default; - /// \brief Constructs a selection operation. - /// - /// \param arg0 Node that produces the first input tensor. - /// \param arg1 Node that produces the second input tensor. - /// \param arg2 Node that produces the third input tensor. - Select(const Output& arg0, const Output& arg1, const Output& arg2); + // clang-format on + class NGRAPH_API Select : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Select", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a selection operation. + Select() = default; + /// \brief Constructs a selection operation. + /// + /// \param arg0 Node that produces the first input tensor. + /// \param arg1 Node that produces the second input tensor. + /// \param arg2 Node that produces the third input tensor. + Select(const Output& arg0, + const Output& arg1, + const Output& arg2); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + void validate_and_infer_types() override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Select; } } diff --git a/src/ngraph/op/send.hpp b/src/ngraph/op/send.hpp index d18f1acd8e8..6f2e61f91df 100644 --- a/src/ngraph/op/send.hpp +++ b/src/ngraph/op/send.hpp @@ -24,28 +24,31 @@ namespace ngraph { namespace op { - class Send : public Op + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Send", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs an unitialized send operation. - Send() = default; - /// \brief Constructs a send operation. - /// - /// \param arg The node for input tensor - /// \param dest_id the target id which could be rank of node id. - Send(const Output& arg, int dest_id); + class NGRAPH_API Send : public Op + { + public: + static constexpr NodeTypeInfo type_info{"Send", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs an unitialized send operation. + Send() = default; + /// \brief Constructs a send operation. + /// + /// \param arg The node for input tensor + /// \param dest_id the target id which could be rank of node id. + Send(const Output& arg, int dest_id); - void validate_and_infer_types() override; + void validate_and_infer_types() override; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - int get_dest_id() const; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + int get_dest_id() const; - private: - int m_dest_id; - }; + private: + int m_dest_id; + }; + } + using v0::Send; } } diff --git a/src/ngraph/op/sigmoid.cpp b/src/ngraph/op/sigmoid.cpp index 649e00d0470..c32fe6314f9 100644 --- a/src/ngraph/op/sigmoid.cpp +++ b/src/ngraph/op/sigmoid.cpp @@ -37,7 +37,7 @@ op::Sigmoid::Sigmoid(const Output& arg) } op::SigmoidBackprop::SigmoidBackprop(const Output& arg, const Output& delta) - : BinaryElementwiseArithmetic(arg, delta) + : BinaryElementwiseArithmetic(arg, delta, AutoBroadcastSpec::NONE) { constructor_validate_and_infer_types(); } diff --git a/src/ngraph/op/sigmoid.hpp b/src/ngraph/op/sigmoid.hpp index f9eb451c81d..692fcb497cd 100644 --- a/src/ngraph/op/sigmoid.hpp +++ b/src/ngraph/op/sigmoid.hpp @@ -25,36 +25,43 @@ namespace ngraph { namespace op { - class Sigmoid : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sigmoid", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Sigmoid(const Output& arg); - Sigmoid() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + class NGRAPH_API Sigmoid : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Sigmoid", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Sigmoid(const Output& arg); + Sigmoid() = default; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; - /// \brief Elementwise SigmoidBackprop operation. - /// - class SigmoidBackprop : public util::BinaryElementwiseArithmetic - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"SigmoidBackprop", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - SigmoidBackprop() = default; - /// \brief Constructs a SigmoidBackprop operation. + /// \brief Elementwise SigmoidBackprop operation. /// - /// \param arg Node that produces the Sigmoid forward input tensor. - SigmoidBackprop(const Output& arg, const Output& delta); + class NGRAPH_API SigmoidBackprop : public util::BinaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"SigmoidBackprop", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + SigmoidBackprop() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } + + /// \brief Constructs a SigmoidBackprop operation. + /// + /// \param arg Node that produces the Sigmoid forward input tensor. + SigmoidBackprop(const Output& arg, const Output& delta); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Sigmoid; + using v0::SigmoidBackprop; } } diff --git a/src/ngraph/op/sign.hpp b/src/ngraph/op/sign.hpp index 1153799d4a0..3dc188962be 100644 --- a/src/ngraph/op/sign.hpp +++ b/src/ngraph/op/sign.hpp @@ -22,22 +22,25 @@ namespace ngraph { namespace op { - /// \brief Elementwise sign operation. - /// - class Sign : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sign", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Sign() = default; - /// \brief Constructs an elementwise sign operation. + /// \brief Elementwise sign operation. /// - /// \param arg Node that produces the input tensor. - Sign(const Output& arg); + class NGRAPH_API Sign : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Sign", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Sign() = default; + /// \brief Constructs an elementwise sign operation. + /// + /// \param arg Node that produces the input tensor. + Sign(const Output& arg); - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::Sign; } } diff --git a/src/ngraph/op/sin.hpp b/src/ngraph/op/sin.hpp index 917117fdef5..004cc85a444 100644 --- a/src/ngraph/op/sin.hpp +++ b/src/ngraph/op/sin.hpp @@ -22,7 +22,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Elementwise sine operation. /// /// ## Inputs @@ -36,25 +38,26 @@ namespace ngraph /// | Type | Description | /// | ---------------------- | ------------------------------------------------------------------------------------ | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \sin(\texttt{arg}[i_1,\dots,i_n])\f$ | - // clang-format on - class Sin : public util::UnaryElementwiseArithmetic - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sin", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a sine operation. - /// - /// \param arg Node that produces the input tensor. - Sin(const Output& arg); - Sin() = default; + // clang-format on + class NGRAPH_API Sin : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Sin", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a sine operation. + /// + /// \param arg Node that produces the input tensor. + Sin(const Output& arg); + Sin() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Sin; } } diff --git a/src/ngraph/op/sinh.hpp b/src/ngraph/op/sinh.hpp index fe86361d743..888a092a843 100644 --- a/src/ngraph/op/sinh.hpp +++ b/src/ngraph/op/sinh.hpp @@ -22,25 +22,28 @@ namespace ngraph { namespace op { - /// \brief Elementwise hyperbolic sine (sinh) operation. - class Sinh : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sinh", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a hyperbolic sine operation. - /// - /// \param arg Node that produces the input tensor. - Sinh(const Output& arg); - Sinh() = default; + /// \brief Elementwise hyperbolic sine (sinh) operation. + class NGRAPH_API Sinh : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Sinh", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a hyperbolic sine operation. + /// + /// \param arg Node that produces the input tensor. + Sinh(const Output& arg); + Sinh() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Sinh; } } diff --git a/src/ngraph/op/slice.hpp b/src/ngraph/op/slice.hpp index f94c4765c13..8b36d80bd35 100644 --- a/src/ngraph/op/slice.hpp +++ b/src/ngraph/op/slice.hpp @@ -28,10 +28,9 @@ namespace ngraph { /// \brief Takes a slice of an input tensor, i.e., the sub-tensor that resides within a /// bounding box, optionally with stride. - class Slice : public Op + class NGRAPH_API Slice : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Slice", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a tensor slice operation diff --git a/src/ngraph/op/softmax.hpp b/src/ngraph/op/softmax.hpp index 01127e16d02..74dc7c9c49b 100644 --- a/src/ngraph/op/softmax.hpp +++ b/src/ngraph/op/softmax.hpp @@ -26,10 +26,9 @@ namespace ngraph { /// \brief Softmax operation. /// - class Softmax : public Op + class NGRAPH_API Softmax : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Softmax", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } Softmax() = default; @@ -70,10 +69,9 @@ namespace ngraph namespace v1 { - class Softmax : public Op + class NGRAPH_API Softmax : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Softmax", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } Softmax() diff --git a/src/ngraph/op/sqrt.hpp b/src/ngraph/op/sqrt.hpp index 50db55613a4..089efc89305 100644 --- a/src/ngraph/op/sqrt.hpp +++ b/src/ngraph/op/sqrt.hpp @@ -22,7 +22,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Elementwise square root operation. /// /// ## Inputs @@ -36,25 +38,26 @@ namespace ngraph /// | Type | Description | /// | ---------------------- | ------------------------------------------------------------------------------------- | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \sqrt{\texttt{arg}[i_1,\dots,i_n]}\f$ | - // clang-format on - class Sqrt : public util::UnaryElementwiseArithmetic - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Sqrt", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a square operation. - /// - /// \param arg Node that produces the input tensor. - Sqrt(const Output& arg); - Sqrt() = default; + // clang-format on + class NGRAPH_API Sqrt : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Sqrt", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a square operation. + /// + /// \param arg Node that produces the input tensor. + Sqrt(const Output& arg); + Sqrt() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Sqrt; } } diff --git a/src/ngraph/op/stop_gradient.hpp b/src/ngraph/op/stop_gradient.hpp index 535c7ee4a99..7b2dbf6c076 100644 --- a/src/ngraph/op/stop_gradient.hpp +++ b/src/ngraph/op/stop_gradient.hpp @@ -22,21 +22,24 @@ namespace ngraph { namespace op { - /// \brief create StopGrdient op - class StopGradient : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"StopGradient", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs StopGradient - /// - /// \param arg Node that produces the input tensor. - StopGradient(const Output& arg); - StopGradient() = default; + /// \brief create StopGrdient op + class NGRAPH_API StopGradient : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"StopGradient", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs StopGradient + /// + /// \param arg Node that produces the input tensor. + StopGradient(const Output& arg); + StopGradient() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - }; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } + using v0::StopGradient; } } diff --git a/src/ngraph/op/strided_slice.cpp b/src/ngraph/op/strided_slice.cpp index 6fd62e77664..811a2d55019 100644 --- a/src/ngraph/op/strided_slice.cpp +++ b/src/ngraph/op/strided_slice.cpp @@ -102,13 +102,7 @@ void op::v1::StridedSlice::validate_and_infer_types() NODE_VALIDATION_CHECK( this, are_attr_sizes_eq, "All masks of StridedSlice must have the same size"); - const auto mask_size = m_begin_mask.size(); const auto& data_rank = get_input_partial_shape(0).rank(); - if (data_rank.is_static()) - { - NODE_VALIDATION_CHECK( - this, static_cast(data_rank) == mask_size, "Data rank must be equal mask size"); - } const auto& begin_shape = get_input_partial_shape(1); if (begin_shape.rank().is_static()) { diff --git a/src/ngraph/op/strided_slice.hpp b/src/ngraph/op/strided_slice.hpp index faf684ad95c..f998b790b21 100644 --- a/src/ngraph/op/strided_slice.hpp +++ b/src/ngraph/op/strided_slice.hpp @@ -31,10 +31,9 @@ namespace ngraph { /// \brief Takes a slice of an input tensor, i.e., the sub-tensor that resides within a /// bounding box, optionally with stride. - class StridedSlice : public Op + class NGRAPH_API StridedSlice : public Op { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Slice", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } StridedSlice() = default; diff --git a/src/ngraph/op/subtract.cpp b/src/ngraph/op/subtract.cpp index aec27e0241f..caab4c8a627 100644 --- a/src/ngraph/op/subtract.cpp +++ b/src/ngraph/op/subtract.cpp @@ -20,23 +20,25 @@ using namespace std; using namespace ngraph; -constexpr NodeTypeInfo op::Subtract::type_info; +// ------------------------------- v0 ------------------------------------------ -op::Subtract::Subtract(const Output& arg0, - const Output& arg1, - const AutoBroadcastSpec& auto_broadcast) +constexpr NodeTypeInfo op::v0::Subtract::type_info; + +op::v0::Subtract::Subtract(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast) : BinaryElementwiseArithmetic(arg0, arg1, auto_broadcast) { constructor_validate_and_infer_types(); } -shared_ptr op::Subtract::copy_with_new_args(const NodeVector& new_args) const +shared_ptr op::v0::Subtract::copy_with_new_args(const NodeVector& new_args) const { check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); + return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); } -void op::Subtract::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) +void op::v0::Subtract::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) { if (get_autob().m_type != op::AutoBroadcastType::NONE) { @@ -54,5 +56,39 @@ void op::Subtract::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVec shared_ptr ngraph::operator-(const Output arg0, const Output arg1) { - return make_shared(arg0, arg1); + return make_shared(arg0, arg1); +} + +// ------------------------------- v1 ------------------------------------------ + +constexpr NodeTypeInfo op::v1::Subtract::type_info; + +op::v1::Subtract::Subtract(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast) + : BinaryElementwiseArithmetic(arg0, arg1, auto_broadcast) +{ + constructor_validate_and_infer_types(); +} + +shared_ptr op::v1::Subtract::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); +} + +void op::v1::Subtract::generate_adjoints(autodiff::Adjoints& adjoints, const NodeVector& deltas) +{ + if (get_autob().m_type != op::AutoBroadcastType::NONE) + { + throw ngraph_error("Autodiff not supported with auto broadcasting"); + } + + auto delta = deltas.at(0); + + auto x = input_value(0); + auto y = input_value(1); + + adjoints.add_delta(x, delta); + adjoints.add_delta(y, -delta); } diff --git a/src/ngraph/op/subtract.hpp b/src/ngraph/op/subtract.hpp index 7c209c2f8c1..e719f185892 100644 --- a/src/ngraph/op/subtract.hpp +++ b/src/ngraph/op/subtract.hpp @@ -22,30 +22,69 @@ namespace ngraph { namespace op { - /// \brief Elementwise subtraction operation. - class Subtract : public util::BinaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Subtract", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - Subtract() = default; - /// \brief Constructs a subtraction operation. - /// - /// \param arg0 Node that produces the first input tensor. - /// \param arg1 Node that produces the second input tensor. - /// \param auto_broadcast Auto broadcast specification - Subtract(const Output& arg0, - const Output& arg1, - const AutoBroadcastSpec& auto_broadcast = AutoBroadcastSpec()); - - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; - - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; - } + /// \brief Elementwise subtraction operation. + class NGRAPH_API Subtract : public util::BinaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Subtract", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Subtract() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NONE) + { + } + + /// \brief Constructs a subtraction operation. + /// + /// \param arg0 Node that produces the first input tensor. + /// \param arg1 Node that produces the second input tensor. + /// \param auto_broadcast Auto broadcast specification + Subtract(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast = AutoBroadcastSpec()); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } // namespace v0 + + namespace v1 + { + /// \brief Elementwise subtraction operation. + class NGRAPH_API Subtract : public util::BinaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Subtract", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Subtract() + : util::BinaryElementwiseArithmetic(AutoBroadcastSpec::NUMPY) + { + } + + /// \brief Constructs a subtraction operation. + /// + /// \param arg0 Node that produces the first input tensor. + /// \param arg1 Node that produces the second input tensor. + /// \param auto_broadcast Auto broadcast specification + Subtract(const Output& arg0, + const Output& arg1, + const AutoBroadcastSpec& auto_broadcast = + AutoBroadcastSpec(AutoBroadcastType::NUMPY)); + + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } // namespace v1 + + using v0::Subtract; + } // namespace op std::shared_ptr operator-(const Output arg0, const Output arg1); -} +} // namespace ngraph diff --git a/src/ngraph/op/sum.hpp b/src/ngraph/op/sum.hpp index e95886ed139..2d1b0efc3f9 100644 --- a/src/ngraph/op/sum.hpp +++ b/src/ngraph/op/sum.hpp @@ -74,10 +74,9 @@ namespace ngraph /// | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | /// | \f$N[\textit{delete}(A,d_1,\dots,d_n)]\f$ | The tensor \f$T\f$, where \f$T\f$ is the input tensor with the `reduction_axes` \f$A\f$ eliminated by summation. | // clang-format off - class Sum : public util::ArithmeticReduction + class NGRAPH_API Sum : public util::ArithmeticReduction { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{ "Sum", 0 }; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a summation operation. diff --git a/src/ngraph/op/tan.hpp b/src/ngraph/op/tan.hpp index 1cf37d33a39..2f98eb871de 100644 --- a/src/ngraph/op/tan.hpp +++ b/src/ngraph/op/tan.hpp @@ -22,7 +22,9 @@ namespace ngraph { namespace op { - // clang-format off + namespace v0 + { + // clang-format off /// \brief Elementwise tangent operation. /// /// ## Inputs @@ -36,25 +38,26 @@ namespace ngraph /// | Type | Description | /// | ---------------------- | ------------------------------------------------------------------------------------ | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \tan(\texttt{arg}[i_1,\dots,i_n])\f$ | - // clang-format on - class Tan : public util::UnaryElementwiseArithmetic - { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Tan", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a tangent operation. - /// - /// \param arg Node that produces the input tensor. - Tan(const Output& arg); - Tan() = default; + // clang-format on + class NGRAPH_API Tan : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Tan", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a tangent operation. + /// + /// \param arg Node that produces the input tensor. + Tan(const Output& arg); + Tan() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Tan; } } diff --git a/src/ngraph/op/tanh.hpp b/src/ngraph/op/tanh.hpp index ea9f6dc295e..a1eb604cc81 100644 --- a/src/ngraph/op/tanh.hpp +++ b/src/ngraph/op/tanh.hpp @@ -22,25 +22,28 @@ namespace ngraph { namespace op { - /// \brief Elementwise hyperbolic tangent operation. - class Tanh : public util::UnaryElementwiseArithmetic + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"Tanh", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - /// \brief Constructs a hyperbolic tangent operation. - /// - /// \param arg Node that produces the input tensor. - Tanh(const Output& arg); - Tanh() = default; + /// \brief Elementwise hyperbolic tangent operation. + class NGRAPH_API Tanh : public util::UnaryElementwiseArithmetic + { + public: + static constexpr NodeTypeInfo type_info{"Tanh", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a hyperbolic tangent operation. + /// + /// \param arg Node that produces the input tensor. + Tanh(const Output& arg); + Tanh() = default; - virtual std::shared_ptr - copy_with_new_args(const NodeVector& new_args) const override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; - protected: - virtual void generate_adjoints(autodiff::Adjoints& adjoints, - const NodeVector& deltas) override; - }; + protected: + virtual void generate_adjoints(autodiff::Adjoints& adjoints, + const NodeVector& deltas) override; + }; + } + using v0::Tanh; } } diff --git a/src/ngraph/op/tensor_iterator.cpp b/src/ngraph/op/tensor_iterator.cpp index 36e75fc2ac8..86cc3e92dfc 100644 --- a/src/ngraph/op/tensor_iterator.cpp +++ b/src/ngraph/op/tensor_iterator.cpp @@ -271,6 +271,14 @@ void op::TensorIterator::validate_and_infer_types() std::vector> ends; + auto make_positive = [](int64_t value, uint64_t dim_size) -> int64_t { + if (value < 0) + { + value = dim_size + value; + } + return value; + }; + // Input uint64_t index_it = 0; for (auto input_description : m_input_descriptions) @@ -285,41 +293,26 @@ void op::TensorIterator::validate_and_infer_types() m_body->get_parameters().at(slice_input_description->m_body_parameter_index); auto body_param_partial_shape = body_parameter->get_partial_shape(); auto input_partial_shape = inputs().at(index).get_source_output().get_partial_shape(); - auto start = slice_input_description->m_start; - auto part_size = slice_input_description->m_part_size; - auto end = slice_input_description->m_end; - if (end != -1) + if (input_partial_shape.is_static()) { + auto input_shape = input_partial_shape.to_shape(); + auto axis = slice_input_description->m_axis; + auto part_size = slice_input_description->m_part_size; + + auto dim_size = input_shape[axis]; + auto start = make_positive(slice_input_description->m_start, dim_size); + auto end = make_positive(slice_input_description->m_end, dim_size); + if (m_num_iterations == -1) { - m_num_iterations = end - start; + // +1 because the left and right borders are included [start, end] + m_num_iterations = (abs(end - start) + 1) / part_size; } else { - NODE_VALIDATION_CHECK( - this, m_num_iterations == end - start, "Number of slices not the same"); - } - } - - if (input_partial_shape.is_static()) - { - auto input_shape = input_partial_shape.to_shape(); - auto axis = slice_input_description->m_axis; - if (end == -1) - { - // for simple RNN case where stride is the same as part_size - // when end is -1, we assume that we slice the input from "start" to the very - // end. - end = static_cast(input_shape[axis]) / part_size + start; - if (m_num_iterations == -1) - { - m_num_iterations = end - start; - } - else - { - NODE_VALIDATION_CHECK( - this, m_num_iterations == end - start, "Number of slices not the same"); - } + NODE_VALIDATION_CHECK(this, + m_num_iterations == (abs(end - start) + 1) / part_size, + "Number of slices not the same"); } if (body_param_partial_shape.is_static()) @@ -421,23 +414,10 @@ void op::TensorIterator::validate_and_infer_types() if (body_value_partial_shape.is_static()) { auto body_value_shape = body_value_partial_shape.to_shape(); - auto start = concat_output_description->m_start; auto part_size = concat_output_description->m_part_size; - auto end = concat_output_description->m_end; auto axis = concat_output_description->m_axis; + Shape out_shape{body_value_shape}; - if (end != -1) - { - if (m_num_iterations != -1) - { - NODE_VALIDATION_CHECK( - this, m_num_iterations == end - start, "Number of slices not the same"); - } - else - { - m_num_iterations = end - start; - } - } if (m_num_iterations != -1) { // for simple RNN case where stride is the same as part_size diff --git a/src/ngraph/op/tensor_iterator.hpp b/src/ngraph/op/tensor_iterator.hpp index 0a2de2c849c..f757999d5a0 100644 --- a/src/ngraph/op/tensor_iterator.hpp +++ b/src/ngraph/op/tensor_iterator.hpp @@ -26,275 +26,291 @@ namespace ngraph { namespace op { - /// \brief Iterate a body over tensors, accumulating into tensors. - class TensorIterator : public util::FusedOp + namespace v0 { - public: - NGRAPH_API - static constexpr NodeTypeInfo type_info{"TensorIterator", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } - // Forward declarations - class SliceInputDescription; - class MergedInputDescription; - class InvariantInputDescription; - - TensorIterator() = default; - TensorIterator(const OutputVector& values); - - class BodyLambda : public Lambda + /// \brief Iterate a body over tensors, accumulating into tensors. + class NGRAPH_API TensorIterator : public util::FusedOp { public: - static constexpr DiscreteTypeInfo type_info{"BodyLamdba", 0}; - const DiscreteTypeInfo& get_type_info() const { return type_info; } - BodyLambda(const OutputVector& outputs, const ParameterVector& parameters) - : Lambda(outputs, parameters) + static constexpr NodeTypeInfo type_info{"TensorIterator", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + // Forward declarations + class SliceInputDescription; + class MergedInputDescription; + class InvariantInputDescription; + + TensorIterator() = default; + TensorIterator(const OutputVector& values); + + class NGRAPH_API BodyLambda : public Lambda { - } - BodyLambda(const ResultVector& results, const ParameterVector& parameters) - : Lambda(results, parameters) + public: + static constexpr DiscreteTypeInfo type_info{"BodyLamdba", 0}; + const DiscreteTypeInfo& get_type_info() const { return type_info; } + BodyLambda(const OutputVector& outputs, const ParameterVector& parameters) + : Lambda(outputs, parameters) + { + } + BodyLambda(const ResultVector& results, const ParameterVector& parameters) + : Lambda(results, parameters) + { + } + }; + + /// \brief Describes a connection between a TensorIterator input and the body. + class InputDescription { - } - }; - - /// \brief Describes a connection between a TensorIterator input and the body. - class InputDescription - { - protected: - /// \param input_index Position of the TensorIterator input - /// \param body_parameter Body parameter to receive input - InputDescription(uint64_t input_index, uint64_t body_parameter_index); + protected: + /// \param input_index Position of the TensorIterator input + /// \param body_parameter Body parameter to receive input + InputDescription(uint64_t input_index, uint64_t body_parameter_index); - public: - virtual ~InputDescription() {} - virtual std::shared_ptr copy() const = 0; + public: + virtual ~InputDescription() {} + virtual std::shared_ptr copy() const = 0; - virtual const DiscreteTypeInfo& get_type_info() const = 0; + virtual const DiscreteTypeInfo& get_type_info() const = 0; - uint64_t m_input_index; - uint64_t m_body_parameter_index; - }; + uint64_t m_input_index; + uint64_t m_body_parameter_index; + }; - /// \brief Describes a body input formed from slices of an input to TensorIterator. - class SliceInputDescription : public InputDescription - { - public: - static constexpr DiscreteTypeInfo type_info{"SliceInputDescription", 0}; - const DiscreteTypeInfo& get_type_info() const override { return type_info; } - /// \param input_index Position of the TensorIterator input - /// \param body_parameter_index Body parameter position to receive input - /// \param start First index for slices - /// \param stride Step amount for slices - /// \param part_size Width of slices - /// \param end Last index for slices - /// \param axis Axis being sliced - SliceInputDescription(uint64_t input_index, - uint64_t body_parameter_index, + /// \brief Describes a body input formed from slices of an input to + /// TensorIterator. + class NGRAPH_API SliceInputDescription : public InputDescription + { + public: + static constexpr DiscreteTypeInfo type_info{"SliceInputDescription", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + /// \param input_index Position of the TensorIterator input + /// \param body_parameter_index Body parameter position to receive input + /// \param start First index for slices + /// \param stride Step amount for slices + /// \param part_size Width of slices + /// \param end Last index for slices + /// \param axis Axis being sliced + SliceInputDescription(uint64_t input_index, + uint64_t body_parameter_index, + int64_t start, + int64_t stride, + int64_t part_size, + int64_t end, + int64_t axis); + std::shared_ptr copy() const override; + + int64_t m_start; + int64_t m_stride; + int64_t m_part_size; + int64_t m_end; + int64_t m_axis; + }; + + /// \brief Describes a body input initialized from a TensorIterator input on the + /// first + /// iteration, and then a body output thereafter. + class NGRAPH_API MergedInputDescription : public InputDescription + { + public: + static constexpr DiscreteTypeInfo type_info{"MergedInputDescription", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + /// \param input_index Position of the TensorIterator input supplying a + /// value to + /// body_parameter + /// for the initial iteration. + /// \param body_parameter_index Body parameter position to receive input. + /// \param body_value_index Body value to supply body_parameter for + /// successive + /// iterations. + MergedInputDescription(uint64_t input_index, + uint64_t body_parameter_index, + uint64_t body_value_index); + std::shared_ptr copy() const override; + + uint64_t m_body_value_index; + }; + + class NGRAPH_API InvariantInputDescription : public InputDescription + { + public: + static constexpr DiscreteTypeInfo type_info{"InvariantInputDescription", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + InvariantInputDescription(uint64_t input_index, uint64_t body_parameter_index); + std::shared_ptr copy() const override; + }; + + // Forward declarations + class ConcatOutputDescription; + class BodyOutputDescription; + + /// \brief Describes how a TensorIterator output is produced from the body. + class OutputDescription + { + protected: + /// \param body_value_index A body value that produces the output + /// \param output_index The TensorIterator output index + OutputDescription(uint64_t body_value_index, uint64_t output_index); + + public: + virtual ~OutputDescription() {} + virtual std::shared_ptr copy() const = 0; + virtual const DiscreteTypeInfo& get_type_info() const = 0; + + uint64_t m_body_value_index; + uint64_t m_output_index; + }; + + /// \brief Produces an output by concatenating an output from each iteration + class NGRAPH_API ConcatOutputDescription : public OutputDescription + { + public: + static constexpr DiscreteTypeInfo type_info{"ConcatOutputDescription", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + /// \param body_value_index A body value that produces the output + /// \param output_index The TensorIterator output index + /// \param start First index for slices + /// \param stride Step amount for slices + /// \param part_size Width of slices + /// \param end Last index for slices + /// \param axis Axis being sliced + ConcatOutputDescription(uint64_t body_value_index, + uint64_t output_index, + int64_t start, + int64_t stride, + int64_t part_size, + int64_t end, + int64_t axis); + + virtual std::shared_ptr copy() const override; + + int64_t m_start; + int64_t m_stride; + int64_t m_part_size; + int64_t m_end; + int64_t m_axis; + }; + + /// \brief Produces an output from a specific iteration + class NGRAPH_API BodyOutputDescription : public OutputDescription + { + public: + static constexpr DiscreteTypeInfo type_info{"BodyOutputDescription", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + /// \param body_value_index A body value that produces the output + /// \param output_index The TensorIterator output index + /// \param iteration which iteration (typically -1, final) will supply the + /// value + BodyOutputDescription(uint64_t body_value_index, + uint64_t output_index, + int64_t iteration); + std::shared_ptr copy() const override; + + int64_t m_iteration; + }; + + /// \brief Indicate that a body parameter comes from slices of a value + /// \param parameter The parameter to receive the slices + /// \param value The value to be sliced. This will be added as an input to + /// TensorIterator. + /// \param start First index on axis of the slicing + /// \param stride Stepping of the slice + /// \param part_size Size of the slice on axis + /// \param end The last index on axis of the slicing + /// \param axis The axis to slice along + void set_sliced_input(const std::shared_ptr& parameter, + const Output& value, int64_t start, int64_t stride, int64_t part_size, int64_t end, int64_t axis); - std::shared_ptr copy() const override; - - int64_t m_start; - int64_t m_stride; - int64_t m_part_size; - int64_t m_end; - int64_t m_axis; - }; - - /// \brief Describes a body input initialized from a TensorIterator input on the first - /// iteration, and then a body output thereafter. - class MergedInputDescription : public InputDescription - { - public: - static constexpr DiscreteTypeInfo type_info{"MergedInputDescription", 0}; - const DiscreteTypeInfo& get_type_info() const override { return type_info; } - /// \param input_index Position of the TensorIterator input supplying a value to - /// body_parameter - /// for the initial iteration. - /// \param body_parameter_index Body parameter position to receive input. - /// \param body_value_index Body value to supply body_parameter for successive - /// iterations. - MergedInputDescription(uint64_t input_index, - uint64_t body_parameter_index, - uint64_t body_value_index); - std::shared_ptr copy() const override; - - uint64_t m_body_value_index; - }; - - class InvariantInputDescription : public InputDescription - { - public: - static constexpr DiscreteTypeInfo type_info{"InvariantInputDescription", 0}; - const DiscreteTypeInfo& get_type_info() const override { return type_info; } - InvariantInputDescription(uint64_t input_index, uint64_t body_parameter_index); - std::shared_ptr copy() const override; - }; + /// \brief Indicates that a body parameter has an initial value in the first + /// iteration + /// and computed value thereafter + /// \param initial_value Value for the parameter in first iteration. This will + /// be added + /// as an input to TensorIterator. + /// \param successive_value Value for the parameter in successive iterations. + /// The + /// value is what is active in the most recent completed iteration. + void set_merged_input(const std::shared_ptr& body_parameter, + const Output& initial_value, + const Output& successive_value); + /// \brief Indicates that a body parameter has an invariant value during + /// iteration that + /// may depend on values computed outside of the iteration + /// \param body_parameter The body parameter + /// \param value The value supplied as an input to the block + void set_invariant_input(const std::shared_ptr& body_parameter, + const Output& value); + /// \brief Gets a value for a particular iteration point + /// \param body_value The value + /// \param iteration The iteration that supplies the value. Negative values are + /// from the + /// last iteration. + Output get_iter_value(const Output& body_value, int64_t iteration); + /// \brief Concatenates slices from all iterations + /// \param value The value supplying slice values from each iteration. + /// \param start First index on axis of the slicing + /// \param stride Stepping of the slice + /// \param part_size Size of the slice on axis + /// \param end The last index on axis of the slicing + /// \param axis The axis to slice along + Output get_concatenated_slices(const Output& value, + int64_t start, + int64_t stride, + int64_t part_size, + int64_t end, + int64_t axis); + + std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; + NodeVector decompose_op() const override; + /// \return the body of the iteration + std::shared_ptr get_body() const { return m_body; } + /// \param body set the body of the iteration + void set_body(const std::shared_ptr& body) { m_body = body; } + /// \return a reference to the input descriptions. + const std::vector>& get_input_descriptions() const + { + return m_input_descriptions; + } + /// \return a reference to the input descriptions. Can add input descriptions + /// before + /// validation. + std::vector>& get_input_descriptions() + { + return m_input_descriptions; + } - // Forward declarations - class ConcatOutputDescription; - class BodyOutputDescription; + /// \return a reference to the output descriptions. + const std::vector>& + get_output_descriptions() const + { + return m_output_descriptions; + } - /// \brief Describes how a TensorIterator output is produced from the body. - class OutputDescription - { - protected: - /// \param body_value_index A body value that produces the output - /// \param output_index The TensorIterator output index - OutputDescription(uint64_t body_value_index, uint64_t output_index); + /// \return a reference to the output descriptions. Can add output descriptions + /// before + /// validation. + std::vector>& get_output_descriptions() + { + return m_output_descriptions; + } - public: - virtual ~OutputDescription() {} - virtual std::shared_ptr copy() const = 0; - virtual const DiscreteTypeInfo& get_type_info() const = 0; + virtual void validate_and_infer_types() override; + void revalidate_and_infer_types_for_body_ops(); - uint64_t m_body_value_index; - uint64_t m_output_index; - }; + int64_t get_num_iterations() const { return m_num_iterations; } + private: + // Find an input corresponding to value, adding one if necessary. + Input input_for_value(const Output& value); - /// \brief Produces an output by concatenating an output from each iteration - class ConcatOutputDescription : public OutputDescription - { - public: - static constexpr DiscreteTypeInfo type_info{"ConcatOutputDescription", 0}; - const DiscreteTypeInfo& get_type_info() const override { return type_info; } - /// \param body_value_index A body value that produces the output - /// \param output_index The TensorIterator output index - /// \param start First index for slices - /// \param stride Step amount for slices - /// \param part_size Width of slices - /// \param end Last index for slices - /// \param axis Axis being sliced - ConcatOutputDescription(uint64_t body_value_index, - uint64_t output_index, - int64_t start, - int64_t stride, - int64_t part_size, - int64_t end, - int64_t axis); - - virtual std::shared_ptr copy() const override; - - int64_t m_start; - int64_t m_stride; - int64_t m_part_size; - int64_t m_end; - int64_t m_axis; - }; + std::shared_ptr m_body; + std::vector> m_input_descriptions; + std::vector> m_output_descriptions; - /// \brief Produces an output from a specific iteration - class BodyOutputDescription : public OutputDescription - { - public: - static constexpr DiscreteTypeInfo type_info{"BodyOutputDescription", 0}; - const DiscreteTypeInfo& get_type_info() const override { return type_info; } - /// \param body_value_index A body value that produces the output - /// \param output_index The TensorIterator output index - /// \param iteration which iteration (typically -1, final) will supply the value - BodyOutputDescription(uint64_t body_value_index, - uint64_t output_index, - int64_t iteration); - std::shared_ptr copy() const override; - - int64_t m_iteration; + int64_t m_num_iterations = -1; }; - - /// \brief Indicate that a body parameter comes from slices of a value - /// \param parameter The parameter to receive the slices - /// \param value The value to be sliced. This will be added as an input to - /// TensorIterator. - /// \param start First index on axis of the slicing - /// \param stride Stepping of the slice - /// \param part_size Size of the slice on axis - /// \param end The last index on axis of the slicing - /// \param axis The axis to slice along - void set_sliced_input(const std::shared_ptr& parameter, - const Output& value, - int64_t start, - int64_t stride, - int64_t part_size, - int64_t end, - int64_t axis); - /// \brief Indicates that a body parameter has an initial value in the first iteration - /// and computed value thereafter - /// \param initial_value Value for the parameter in first iteration. This will be added - /// as an input to TensorIterator. - /// \param successive_value Value for the parameter in successive iterations. The - /// value is what is active in the most recent completed iteration. - void set_merged_input(const std::shared_ptr& body_parameter, - const Output& initial_value, - const Output& successive_value); - /// \brief Indicates that a body parameter has an invariant value during iteration that - /// may depend on values computed outside of the iteration - /// \param body_parameter The body parameter - /// \param value The value supplied as an input to the block - void set_invariant_input(const std::shared_ptr& body_parameter, - const Output& value); - /// \brief Gets a value for a particular iteration point - /// \param body_value The value - /// \param iteration The iteration that supplies the value. Negative values are from the - /// last iteration. - Output get_iter_value(const Output& body_value, int64_t iteration); - /// \brief Concatenates slices from all iterations - /// \param value The value supplying slice values from each iteration. - /// \param start First index on axis of the slicing - /// \param stride Stepping of the slice - /// \param part_size Size of the slice on axis - /// \param end The last index on axis of the slicing - /// \param axis The axis to slice along - Output get_concatenated_slices(const Output& value, - int64_t start, - int64_t stride, - int64_t part_size, - int64_t end, - int64_t axis); - - std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override; - NodeVector decompose_op() const override; - /// \return the body of the iteration - std::shared_ptr get_body() const { return m_body; } - /// \param body set the body of the iteration - void set_body(const std::shared_ptr& body) { m_body = body; } - /// \return a reference to the input descriptions. - const std::vector>& get_input_descriptions() const - { - return m_input_descriptions; - } - /// \return a reference to the input descriptions. Can add input descriptions before - /// validation. - std::vector>& get_input_descriptions() - { - return m_input_descriptions; - } - - /// \return a reference to the output descriptions. - const std::vector>& get_output_descriptions() const - { - return m_output_descriptions; - } - - /// \return a reference to the output descriptions. Can add output descriptions before - /// validation. - std::vector>& get_output_descriptions() - { - return m_output_descriptions; - } - - virtual void validate_and_infer_types() override; - void revalidate_and_infer_types_for_body_ops(); - - int64_t get_num_iterations() const { return m_num_iterations; } - private: - // Find an input corresponding to value, adding one if necessary. - Input input_for_value(const Output& value); - - std::shared_ptr m_body; - std::vector> m_input_descriptions; - std::vector> m_output_descriptions; - - int64_t m_num_iterations = -1; - }; + } + using v0::TensorIterator; } } diff --git a/src/ngraph/op/topk.hpp b/src/ngraph/op/topk.hpp index 5911dc5c4b4..92287c06e3f 100644 --- a/src/ngraph/op/topk.hpp +++ b/src/ngraph/op/topk.hpp @@ -29,12 +29,11 @@ namespace ngraph { // \brief Computes indices of top k maximum/minimum index along a specified axis for a // given tensor - class TopK : public Op + class NGRAPH_API TopK : public Op { public: using SortType = TopKSortType; - NGRAPH_API static constexpr NodeTypeInfo type_info{"TopK", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a TopK operation @@ -114,7 +113,7 @@ namespace ngraph { /// \brief Computes indices and values of the k maximum/minimum values /// for each slice along specified axis. - class TopK : public Op + class NGRAPH_API TopK : public Op { public: using SortType = TopKSortType; @@ -125,7 +124,6 @@ namespace ngraph MIN }; - NGRAPH_API static constexpr NodeTypeInfo type_info{"TopK", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } /// \brief Constructs a TopK operation diff --git a/src/ngraph/op/util/activation_functions.cpp b/src/ngraph/op/util/activation_functions.cpp index 5c79f42287b..336641a9a34 100644 --- a/src/ngraph/op/util/activation_functions.cpp +++ b/src/ngraph/op/util/activation_functions.cpp @@ -20,6 +20,7 @@ #include #include "activation_functions.hpp" +#include "ngraph/op/constant.hpp" #include "ngraph/op/fused/hard_sigmoid.hpp" #include "ngraph/op/relu.hpp" #include "ngraph/op/sigmoid.hpp" @@ -45,7 +46,10 @@ static shared_ptr relu(const shared_ptr& arg, float /* alpha */, flo static shared_ptr hardsigmoid(const shared_ptr& arg, float alpha, float beta) { - return make_shared(arg, alpha, beta); + const auto alpha_node = op::Constant::create(arg->get_element_type(), Shape{}, {alpha}); + const auto beta_node = op::Constant::create(arg->get_element_type(), Shape{}, {beta}); + + return make_shared(arg, alpha_node, beta_node); } op::util::ActivationFunction::ActivationFunction(ActivationFunctionType f, float alpha, float beta) diff --git a/src/ngraph/op/util/activation_functions.hpp b/src/ngraph/op/util/activation_functions.hpp index 5935a7f3a8a..eb9249dc272 100644 --- a/src/ngraph/op/util/activation_functions.hpp +++ b/src/ngraph/op/util/activation_functions.hpp @@ -78,12 +78,13 @@ namespace ngraph /// /// \brief Class representing activation function used in RNN cells. /// - class ActivationFunction + class NGRAPH_API ActivationFunction { public: ActivationFunction(ActivationFunctionType f, float alpha, float beta); ActivationFunction(ActivationFunctionType f, float alpha); ActivationFunction(ActivationFunctionType f); + ActivationFunction() = default; /// /// \brief Calls stored activation function with provided node argument. diff --git a/src/ngraph/op/util/arithmetic_reduction.hpp b/src/ngraph/op/util/arithmetic_reduction.hpp index 0e25bb223b2..d4bf172666d 100644 --- a/src/ngraph/op/util/arithmetic_reduction.hpp +++ b/src/ngraph/op/util/arithmetic_reduction.hpp @@ -27,7 +27,7 @@ namespace ngraph /// \brief Abstract base class for arithmetic reduction operations, i.e., operations /// where chosen axes of the input tensors are eliminated (reduced out) by /// repeated application of a particular binary arithmetic operation. - class ArithmeticReduction : public Op + class NGRAPH_API ArithmeticReduction : public Op { protected: /// \brief Constructs an arithmetic reduction operation. diff --git a/src/ngraph/op/util/arithmetic_reductions_keep_dims.hpp b/src/ngraph/op/util/arithmetic_reductions_keep_dims.hpp index 429a36e51a3..9287f44801e 100644 --- a/src/ngraph/op/util/arithmetic_reductions_keep_dims.hpp +++ b/src/ngraph/op/util/arithmetic_reductions_keep_dims.hpp @@ -25,7 +25,7 @@ namespace ngraph { namespace util { - class ArithmeticReductionKeepDims : public util::ArithmeticReduction + class NGRAPH_API ArithmeticReductionKeepDims : public util::ArithmeticReduction { protected: ArithmeticReductionKeepDims() = default; diff --git a/src/ngraph/op/util/attr_types.cpp b/src/ngraph/op/util/attr_types.cpp index 19e4728f466..f26c7a855e0 100644 --- a/src/ngraph/op/util/attr_types.cpp +++ b/src/ngraph/op/util/attr_types.cpp @@ -13,19 +13,134 @@ // See the License for the specific language governing permissions and // limitations under the License. //***************************************************************************** +#include +#include "ngraph/check.hpp" +#include "ngraph/enum_names.hpp" #include "ngraph/op/util/attr_types.hpp" using namespace ngraph; -std::ostream& op::operator<<(std::ostream& s, const op::AutoBroadcastType& type) +const op::AutoBroadcastSpec op::AutoBroadcastSpec::NUMPY(AutoBroadcastType::NUMPY, 0); +const op::AutoBroadcastSpec op::AutoBroadcastSpec::NONE{AutoBroadcastType::NONE, 0}; + +namespace ngraph { - switch (type) + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = EnumNames("op::PadMode", + {{"CONSTANT", op::PadMode::CONSTANT}, + {"EDGE", op::PadMode::EDGE}, + {"REFLECT", op::PadMode::REFLECT}, + {"SYMMETRIC", op::PadMode::SYMMETRIC}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::PadMode& type) + { + return s << as_string(type); + } + + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = EnumNames("op::PadType", + {{"EXPLICIT", op::PadType::EXPLICIT}, + {"SAME_LOWER", op::PadType::SAME_LOWER}, + {"SAME_UPPER", op::PadType::SAME_UPPER}, + {"VALID", op::PadType::VALID}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::PadType& type) + { + return s << as_string(type); + } + + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = EnumNames( + "op::RoundingType", + {{"FLOOR", op::RoundingType::FLOOR}, {"CEIL", op::RoundingType::CEIL}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::RoundingType& type) + { + return s << as_string(type); + } + + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = + EnumNames("op::AutoBroadcastType", + {{"NONE", op::AutoBroadcastType::NONE}, + {"NUMPY", op::AutoBroadcastType::NUMPY}, + {"PDPD", op::AutoBroadcastType::PDPD}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::AutoBroadcastType& type) + { + return s << as_string(type); + } + + template <> + EnumNames& EnumNames::get() { - case op::AutoBroadcastType::NONE: s << "NONE"; break; - case op::AutoBroadcastType::NUMPY: s << "NUMPY"; break; - case op::AutoBroadcastType::PDPD: s << "PDPD"; break; - default: s << "Undefined Type"; + static auto enum_names = EnumNames( + "op::EpsMode", {{"ADD", op::EpsMode::ADD}, {"MAX", op::EpsMode::MAX}}); + return enum_names; } - return s; + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::EpsMode& type) + { + return s << as_string(type); + } + + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = + EnumNames("op::TopKSortType", + {{"NONE", op::TopKSortType::NONE}, + {"SORT_INDICES", op::TopKSortType::SORT_INDICES}, + {"SORT_VALUES", op::TopKSortType::SORT_VALUES}}); + return enum_names; + } + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; + + std::ostream& op::operator<<(std::ostream& s, const op::TopKSortType& type) + { + return s << as_string(type); + } + + op::AutoBroadcastType op::AutoBroadcastSpec::type_from_string(const std::string& type) const + { + static const std::map allowed_values = { + {"NONE", AutoBroadcastType::NONE}, + {"NUMPY", AutoBroadcastType::NUMPY}, + {"PDPD", AutoBroadcastType::PDPD}, + {"EXPLICIT", AutoBroadcastType::EXPLICIT}}; + + NGRAPH_CHECK(allowed_values.count(type) > 0, "Invalid 'type' value passed in."); + + return allowed_values.at(type); + } + + NGRAPH_API constexpr DiscreteTypeInfo AttributeAdapter::type_info; } diff --git a/src/ngraph/op/util/attr_types.hpp b/src/ngraph/op/util/attr_types.hpp index ebdf23062ab..56cee757bdb 100644 --- a/src/ngraph/op/util/attr_types.hpp +++ b/src/ngraph/op/util/attr_types.hpp @@ -19,6 +19,10 @@ #include #include +#include "ngraph/attribute_adapter.hpp" +#include "ngraph/ngraph_visibility.hpp" +#include "ngraph/type.hpp" + namespace ngraph { namespace op @@ -32,6 +36,24 @@ namespace ngraph SYMMETRIC }; + std::ostream& operator<<(std::ostream& s, const PadMode& type); + } + + template <> + class NGRAPH_API AttributeAdapter : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::PadMode& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { /// \brief Padding Type used for `Convolution` and `Pooling` /// /// Follows ONNX padding type definitions @@ -54,6 +76,24 @@ namespace ngraph NOTSET = EXPLICIT, }; + std::ostream& operator<<(std::ostream& s, const PadType& type); + } + + template <> + class NGRAPH_API AttributeAdapter : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::PadType& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { /// \brief Rounding Type used for `Pooling` operators. enum class RoundingType { @@ -61,6 +101,25 @@ namespace ngraph CEIL = 1, }; + std::ostream& operator<<(std::ostream& s, const RoundingType& type); + } + + template <> + class NGRAPH_API AttributeAdapter + : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::RoundingType& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { /// \brief Specifies the algorithm to use for implicit broadcasting of a tensor /// to align with another tensor /// @@ -107,6 +166,25 @@ namespace ngraph PDPD }; + std::ostream& operator<<(std::ostream& s, const AutoBroadcastType& type); + } + + template <> + class NGRAPH_API AttributeAdapter + : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::AutoBroadcastType& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { /// \brief Specifies how eps is combined with L2 value enum class EpsMode { @@ -116,6 +194,24 @@ namespace ngraph MAX }; + std::ostream& operator<<(std::ostream& s, const EpsMode& type); + } + + template <> + class NGRAPH_API AttributeAdapter : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::EpsMode& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { enum class TopKSortType { // Returned values are not sorted @@ -125,9 +221,27 @@ namespace ngraph // Sort result based on element values SORT_VALUES, }; + std::ostream& operator<<(std::ostream& s, const TopKSortType& type); + } + template <> + class NGRAPH_API AttributeAdapter + : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(op::TopKSortType& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + namespace op + { /// \brief Implicit broadcast specification - struct AutoBroadcastSpec + struct NGRAPH_API AutoBroadcastSpec { AutoBroadcastSpec() : m_type(AutoBroadcastType::NONE) @@ -139,6 +253,10 @@ namespace ngraph , m_axis(0) { } + AutoBroadcastSpec(const char* type) + : AutoBroadcastSpec(type_from_string(type)) + { + } AutoBroadcastSpec(AutoBroadcastType type, int64_t axis) : m_type(type) , m_axis(axis) @@ -152,8 +270,26 @@ namespace ngraph { return a.m_type == m_type && a.m_axis == m_axis; } - }; - std::ostream& operator<<(std::ostream& s, const AutoBroadcastType& type); + static const AutoBroadcastSpec NUMPY; + static const AutoBroadcastSpec NONE; + + private: + AutoBroadcastType type_from_string(const std::string& type) const; + }; } + + template <> + class AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(op::AutoBroadcastSpec& value) + : ValueReference(value) + { + } + NGRAPH_API + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; } diff --git a/src/ngraph/op/util/binary_elementwise_arithmetic.cpp b/src/ngraph/op/util/binary_elementwise_arithmetic.cpp index ff446e9d2da..c6cf987aca9 100644 --- a/src/ngraph/op/util/binary_elementwise_arithmetic.cpp +++ b/src/ngraph/op/util/binary_elementwise_arithmetic.cpp @@ -19,7 +19,8 @@ using namespace std; using namespace ngraph; -op::util::BinaryElementwiseArithmetic::BinaryElementwiseArithmetic() +op::util::BinaryElementwiseArithmetic::BinaryElementwiseArithmetic(const AutoBroadcastSpec& autob) + : m_autob(autob) { } @@ -54,3 +55,9 @@ void op::util::BinaryElementwiseArithmetic::validate_and_infer_types() { validate_and_infer_elementwise_arithmetic(m_autob); } + +bool op::util::BinaryElementwiseArithmetic::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("autob", m_autob); + return true; +} diff --git a/src/ngraph/op/util/binary_elementwise_arithmetic.hpp b/src/ngraph/op/util/binary_elementwise_arithmetic.hpp index cdf02d44cfa..5197f2bb4eb 100644 --- a/src/ngraph/op/util/binary_elementwise_arithmetic.hpp +++ b/src/ngraph/op/util/binary_elementwise_arithmetic.hpp @@ -51,15 +51,15 @@ namespace ngraph /// | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \mathit{op}(\texttt{arg0}[i_1,\dots,i_n],\texttt{arg1}[i_1,\dots,i_n])\f$. This will always have the same shape and element type as the input tensors (after auto broadcasting). | // clang-format on - class BinaryElementwiseArithmetic : public Op + class NGRAPH_API BinaryElementwiseArithmetic : public Op { protected: - /// \brief Constructs a binary elementwise arithmetic operation. - BinaryElementwiseArithmetic(); + BinaryElementwiseArithmetic(const AutoBroadcastSpec& autob); + /// \brief Constructs a binary elementwise arithmetic operation. BinaryElementwiseArithmetic(const std::shared_ptr& arg0, const std::shared_ptr& arg1, - const AutoBroadcastSpec& autob = AutoBroadcastSpec()); + const AutoBroadcastSpec& autob); /// \brief Constructs a binary elementwise arithmetic operation. /// @@ -67,7 +67,7 @@ namespace ngraph /// \param arg1 Output that produces the second input tensor. BinaryElementwiseArithmetic(const Output& arg0, const Output& arg1, - const AutoBroadcastSpec& autob = AutoBroadcastSpec()); + const AutoBroadcastSpec& autob); /// \brief Constructs a binary elementwise arithmetic operation. /// @@ -77,7 +77,7 @@ namespace ngraph BinaryElementwiseArithmetic(const std::string& node_type, const std::shared_ptr& arg0, const std::shared_ptr& arg1, - const AutoBroadcastSpec& autob = AutoBroadcastSpec()); + const AutoBroadcastSpec& autob); public: void validate_and_infer_types() override; @@ -86,6 +86,8 @@ namespace ngraph void set_autob(const AutoBroadcastSpec& autob) { m_autob = autob; } bool is_binary_elementwise_arithmetic() const override { return true; } bool supports_auto_broadcast() const override { return true; } + bool visit_attributes(AttributeVisitor& visitor) override; + private: AutoBroadcastSpec m_autob; }; diff --git a/src/ngraph/op/util/binary_elementwise_comparison.cpp b/src/ngraph/op/util/binary_elementwise_comparison.cpp index 143e4d3a157..106bffd51ca 100644 --- a/src/ngraph/op/util/binary_elementwise_comparison.cpp +++ b/src/ngraph/op/util/binary_elementwise_comparison.cpp @@ -55,3 +55,9 @@ void op::util::BinaryElementwiseComparison::validate_and_infer_types() set_output_type(0, element::boolean, args_pshape); } + +bool op::util::BinaryElementwiseComparison::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("autob", m_autob); + return true; +} diff --git a/src/ngraph/op/util/binary_elementwise_comparison.hpp b/src/ngraph/op/util/binary_elementwise_comparison.hpp index f90b8704517..fd37c0c1e58 100644 --- a/src/ngraph/op/util/binary_elementwise_comparison.hpp +++ b/src/ngraph/op/util/binary_elementwise_comparison.hpp @@ -51,7 +51,7 @@ namespace ngraph /// | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | /// | \f$\texttt{bool}[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \mathit{op}(\texttt{arg0}[i_1,\dots,i_n],\texttt{arg1}[i_1,\dots,i_n])\f$. This will always have the same shape as the input tensors, and the element type `bool`. | // clang-format on - class BinaryElementwiseComparison : public Op + class NGRAPH_API BinaryElementwiseComparison : public Op { protected: /// \brief Constructs a binary elementwise comparison operation. @@ -92,6 +92,8 @@ namespace ngraph void set_autob(const AutoBroadcastSpec& autob) { m_autob = autob; } bool supports_auto_broadcast() const override { return true; } bool is_binary_elementwise_comparison() const override { return true; } + bool visit_attributes(AttributeVisitor& visitor) override; + private: AutoBroadcastSpec m_autob; }; diff --git a/src/ngraph/op/util/binary_elementwise_logical.cpp b/src/ngraph/op/util/binary_elementwise_logical.cpp index 305bc91e995..bba28d9ec17 100644 --- a/src/ngraph/op/util/binary_elementwise_logical.cpp +++ b/src/ngraph/op/util/binary_elementwise_logical.cpp @@ -52,3 +52,9 @@ void op::util::BinaryElementwiseLogical::validate_and_infer_types() { validate_and_infer_elementwise_logical(m_autob); } + +bool op::util::BinaryElementwiseLogical::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("autob", m_autob); + return true; +} diff --git a/src/ngraph/op/util/binary_elementwise_logical.hpp b/src/ngraph/op/util/binary_elementwise_logical.hpp index 0a99191fd42..46a46e669a1 100644 --- a/src/ngraph/op/util/binary_elementwise_logical.hpp +++ b/src/ngraph/op/util/binary_elementwise_logical.hpp @@ -50,7 +50,7 @@ namespace ngraph /// | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | /// | \f$\texttt{bool}[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \mathit{op}(\texttt{arg0}[i_1,\dots,i_n],\texttt{arg1}[i_1,\dots,i_n])\f$. This will always have the same shape as the input tensors, and the element type `bool`. | // clang-format on - class BinaryElementwiseLogical : public Op + class NGRAPH_API BinaryElementwiseLogical : public Op { protected: BinaryElementwiseLogical(); @@ -88,6 +88,8 @@ namespace ngraph void set_autob(const AutoBroadcastSpec& autob) { m_autob = autob; } bool supports_auto_broadcast() const override { return true; } bool is_binary_elementwise_logical() const override { return true; } + bool visit_attributes(AttributeVisitor& visitor) override; + private: AutoBroadcastSpec m_autob; }; diff --git a/src/ngraph/op/util/fused_op.hpp b/src/ngraph/op/util/fused_op.hpp index ef4dcad733b..fc01bc3fcc6 100644 --- a/src/ngraph/op/util/fused_op.hpp +++ b/src/ngraph/op/util/fused_op.hpp @@ -27,7 +27,7 @@ namespace ngraph /// \brief Abstract base class for fused ops, i.e ops that can be broken down into core /// ngraph ops /// - class FusedOp : public Op + class NGRAPH_API FusedOp : public Op { public: bool supports_decompose() const override { return true; } diff --git a/src/ngraph/op/util/index_reduction.cpp b/src/ngraph/op/util/index_reduction.cpp index 761a3c48136..735763aa80b 100644 --- a/src/ngraph/op/util/index_reduction.cpp +++ b/src/ngraph/op/util/index_reduction.cpp @@ -26,7 +26,7 @@ op::util::IndexReduction::IndexReduction() } op::util::IndexReduction::IndexReduction(const Output& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type) : Op({arg}) { @@ -35,7 +35,7 @@ op::util::IndexReduction::IndexReduction(const Output& arg, } op::util::IndexReduction::IndexReduction(const std::shared_ptr& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type) : Op(check_single_output_args({arg})) { @@ -45,7 +45,7 @@ op::util::IndexReduction::IndexReduction(const std::shared_ptr& arg, op::util::IndexReduction::IndexReduction(const std::string& node_type, const std::shared_ptr& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type) : Op(node_type, check_single_output_args({arg})) { @@ -53,11 +53,11 @@ op::util::IndexReduction::IndexReduction(const std::string& node_type, set_index_element_type(index_element_type); } -size_t op::util::IndexReduction::get_reduction_axis() const +uint64_t op::util::IndexReduction::get_reduction_axis() const { return m_axis; } -void op::util::IndexReduction::set_reduction_axis(size_t value) +void op::util::IndexReduction::set_reduction_axis(uint64_t value) { m_axis = value; } @@ -125,3 +125,10 @@ void op::util::IndexReduction::generate_adjoints(autodiff::Adjoints& /* adjoints { throw ngraph_error("Forward-propagation-only operation"); } + +bool op::util::IndexReduction::visit_attributes(AttributeVisitor& visitor) +{ + visitor.on_attribute("axis", m_axis); + visitor.on_attribute("index_element_type", m_index_element_type); + return true; +} diff --git a/src/ngraph/op/util/index_reduction.hpp b/src/ngraph/op/util/index_reduction.hpp index d3b32ae0e79..c036b5670a8 100644 --- a/src/ngraph/op/util/index_reduction.hpp +++ b/src/ngraph/op/util/index_reduction.hpp @@ -29,33 +29,34 @@ namespace ngraph { namespace util { - class IndexReduction : public Op + class NGRAPH_API IndexReduction : public Op { protected: IndexReduction(); IndexReduction(const Output& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type); IndexReduction(const std::shared_ptr& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type); IndexReduction(const std::string& node_type, const std::shared_ptr& arg, - size_t axis, + uint64_t axis, const element::Type& index_element_type); public: - size_t get_reduction_axis() const; - void set_reduction_axis(size_t value); + uint64_t get_reduction_axis() const; + void set_reduction_axis(uint64_t value); element::Type get_index_element_type() const; void set_index_element_type(const element::Type& index_element_type); void validate_and_infer_types() override; + bool visit_attributes(AttributeVisitor& visitor) override; protected: - size_t m_axis{0}; + uint64_t m_axis{0}; element::Type m_index_element_type; virtual void generate_adjoints(autodiff::Adjoints& adjoints, diff --git a/src/ngraph/op/util/logical_reduction.hpp b/src/ngraph/op/util/logical_reduction.hpp index addfdab308e..e19afbe51ba 100644 --- a/src/ngraph/op/util/logical_reduction.hpp +++ b/src/ngraph/op/util/logical_reduction.hpp @@ -27,7 +27,7 @@ namespace ngraph /// \brief Abstract base class for logical reduction operations, i.e., operations where /// chosen axes of the input tensors are eliminated (reduced out) by repeated /// application of a particular binary logical operation. - class LogicalReduction : public Op + class NGRAPH_API LogicalReduction : public Op { protected: /// \brief Constructs a logical reduction operation. diff --git a/src/ngraph/op/util/logical_reduction_keep_dims.cpp b/src/ngraph/op/util/logical_reduction_keep_dims.cpp new file mode 100644 index 00000000000..35c6f92713c --- /dev/null +++ b/src/ngraph/op/util/logical_reduction_keep_dims.cpp @@ -0,0 +1,82 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/util/logical_reduction_keep_dims.hpp" +#include "ngraph/op/constant.hpp" + +using namespace std; +using namespace ngraph; + +op::util::LogicalReductionKeepDims::LogicalReductionKeepDims( + const ngraph::Output& arg, + const ngraph::Output& reduction_axes, + const bool keep_dims) + : LogicalReduction(arg, reduction_axes) + , m_keep_dims{keep_dims} +{ +} + +void op::util::LogicalReductionKeepDims::validate_and_infer_types() +{ + if (m_keep_dims) + { + const auto reduction_axes = get_reduction_axes(); + const auto input_shape = get_input_partial_shape(0); + const auto input_rank = input_shape.rank(); + PartialShape result_shape{PartialShape::dynamic()}; + + if (input_rank.is_static()) + { + result_shape = PartialShape::dynamic(input_rank); + } + + if (input_rank.is_static() && reduction_axes_constant()) + { + std::vector dims; + for (const auto axis : reduction_axes) + { + NODE_VALIDATION_CHECK(this, + axis < size_t(input_rank), + "Reduction axis (", + axis, + ") is out of bounds ", + "(argument shape: ", + input_shape, + ", reduction axes: ", + reduction_axes, + ")"); + } + for (size_t i = 0; i < size_t(input_rank); i++) + { + if (reduction_axes.count(i) == 0) + { + dims.push_back(input_shape[i]); + } + else + { + dims.push_back(Dimension{1}); + } + } + result_shape = PartialShape(dims); + } + set_input_is_relevant_to_shape(1); + set_output_type(0, get_input_element_type(0), result_shape); + } + else + { + LogicalReduction::validate_and_infer_types(); + } +} diff --git a/src/ngraph/op/util/logical_reduction_keep_dims.hpp b/src/ngraph/op/util/logical_reduction_keep_dims.hpp new file mode 100644 index 00000000000..0105495a3a9 --- /dev/null +++ b/src/ngraph/op/util/logical_reduction_keep_dims.hpp @@ -0,0 +1,52 @@ +//***************************************************************************** +// Copyright 2017-2019 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/op/op.hpp" +#include "ngraph/op/util/logical_reduction.hpp" + +namespace ngraph +{ + namespace op + { + namespace util + { + class NGRAPH_API LogicalReductionKeepDims : public util::LogicalReduction + { + protected: + LogicalReductionKeepDims() = default; + + /// \param arg The tensor to be reduced. + /// \param reduction_axes The axis positions (0-based) to be eliminated. + /// \param keep_dims If set to 1 it holds axes that are used for reduction. + LogicalReductionKeepDims(const Output& arg, + const Output& reduction_axes, + const bool keep_dims = false); + + public: + void validate_and_infer_types() override; + + /// \return If set to 1 it holds axes that are used for reduction. + /// For each such axis, output dimension is equal to 1. + bool get_keep_dims() const { return m_keep_dims; } + void set_keep_dims(bool keep_dims) { m_keep_dims = keep_dims; } + private: + bool m_keep_dims = false; + }; + } + } +} diff --git a/src/ngraph/op/util/op_annotations.hpp b/src/ngraph/op/util/op_annotations.hpp index 2da54682cb0..f4fa7404e25 100644 --- a/src/ngraph/op/util/op_annotations.hpp +++ b/src/ngraph/op/util/op_annotations.hpp @@ -19,6 +19,7 @@ #include #include "ngraph/except.hpp" +#include "ngraph/ngraph_visibility.hpp" namespace ngraph { @@ -34,7 +35,7 @@ namespace ngraph }; /// \brief Base class for annotations added to graph ops - class OpAnnotations + class NGRAPH_API OpAnnotations { public: virtual ~OpAnnotations() = default; diff --git a/src/ngraph/op/util/rnn_cell_base.hpp b/src/ngraph/op/util/rnn_cell_base.hpp index b2a30376bd7..f7f0b326dfe 100644 --- a/src/ngraph/op/util/rnn_cell_base.hpp +++ b/src/ngraph/op/util/rnn_cell_base.hpp @@ -34,7 +34,7 @@ namespace ngraph /// /// \note It holds all common attributes. /// - class RNNCellBase + class NGRAPH_API RNNCellBase { public: /// @@ -56,6 +56,8 @@ namespace ngraph const std::vector& activations_alpha, const std::vector& activations_beta); + RNNCellBase() = default; + std::size_t get_hidden_size() const { return m_hidden_size; } float get_clip() const { return m_clip; } const std::vector& get_activations() const { return m_activations; } @@ -117,12 +119,12 @@ namespace ngraph /// std::shared_ptr clip(const Output& data) const; - private: - const std::size_t m_hidden_size; - const float m_clip; - const std::vector m_activations; - const std::vector m_activations_alpha; - const std::vector m_activations_beta; + protected: + std::size_t m_hidden_size; + float m_clip; + std::vector m_activations; + std::vector m_activations_alpha; + std::vector m_activations_beta; }; } // namespace util } // namespace op diff --git a/src/ngraph/op/util/unary_elementwise_arithmetic.hpp b/src/ngraph/op/util/unary_elementwise_arithmetic.hpp index 3e17b2f975c..9e54dfe023c 100644 --- a/src/ngraph/op/util/unary_elementwise_arithmetic.hpp +++ b/src/ngraph/op/util/unary_elementwise_arithmetic.hpp @@ -45,7 +45,7 @@ namespace ngraph /// | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | /// | \f$N[d_1,\dots,d_n]\f$ | The tensor \f$T\f$, where \f$T[i_1,\dots,i_n] = \mathit{op}(\texttt{arg}[i_1,\dots,i_n])\f$. This will always have the same shape and element type as the input tensor. | // clang-format on - class UnaryElementwiseArithmetic : public Op + class NGRAPH_API UnaryElementwiseArithmetic : public Op { protected: /// \brief Constructs a unary elementwise arithmetic operation. diff --git a/src/ngraph/op/variadic_split.cpp b/src/ngraph/op/variadic_split.cpp new file mode 100644 index 00000000000..f5a67ddc0ce --- /dev/null +++ b/src/ngraph/op/variadic_split.cpp @@ -0,0 +1,98 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/op/constant.hpp" +#include "ngraph/op/variadic_split.hpp" + +using namespace std; +using namespace ngraph; + +constexpr NodeTypeInfo op::v1::VariadicSplit::type_info; + +op::v1::VariadicSplit::VariadicSplit(const Output& data, + const Output& axis, + const Output& split_lengths) + : Op({data, axis, split_lengths}) +{ + constructor_validate_and_infer_types(); +} + +void ngraph::op::v1::VariadicSplit::validate_and_infer_types() +{ + set_input_is_relevant_to_value(0); + set_input_is_relevant_to_value(1); + set_input_is_relevant_to_value(2); + + auto split_lengths_pshape_rank = get_input_partial_shape(2).rank(); + + if (split_lengths_pshape_rank.is_static()) + { + auto num_outputs = static_cast(split_lengths_pshape_rank); + auto data = input_value(0); + auto axis_input = input_value(1).get_node_shared_ptr(); + auto split_lengths_input = input_value(2).get_node_shared_ptr(); + auto data_shape = data.get_partial_shape(); + auto data_type = data.get_element_type(); + + set_output_size(num_outputs); + if (data_shape.is_static() && axis_input->is_constant() && + split_lengths_input->is_constant()) + { + auto axis = as_type_ptr(axis_input)->get_vector()[0]; + auto split_lengths = as_type_ptr(axis_input)->get_vector(); + + auto splits_length = std::accumulate(split_lengths.begin(), split_lengths.end(), 0UL); + + NODE_VALIDATION_CHECK(this, axis > 0, "Provided axis:", axis, " can not be negative"); + auto data_rank = static_cast(data_shape.rank()); + NODE_VALIDATION_CHECK(this, + axis < data_rank, + "Provided axis:", + axis, + " can not be higher than input data rank: ", + data_rank); + + NODE_VALIDATION_CHECK(this, + splits_length == static_cast(data_shape[axis]), + "Total length of splits:", + splits_length, + " does not sum to length of the choosen axis: ", + static_cast(data_shape[axis])); + + for (size_t output{0}; output < num_outputs; ++output) + { + auto tmp_shape = data_shape.to_shape(); + tmp_shape.at(axis) = split_lengths.at(axis); + set_output_type(output, data_type, tmp_shape); + } + } + else + { + for (size_t output{0}; output < num_outputs; ++output) + { + set_output_type(output, data_type, PartialShape::dynamic()); + } + } + } +} + +shared_ptr op::v1::VariadicSplit::copy_with_new_args(const NodeVector& new_args) const +{ + check_new_args_count(this, new_args); + return make_shared(new_args.at(0), new_args.at(1), new_args.at(2)); +} diff --git a/src/ngraph/op/variadic_split.hpp b/src/ngraph/op/variadic_split.hpp new file mode 100644 index 00000000000..d3643dbaf7d --- /dev/null +++ b/src/ngraph/op/variadic_split.hpp @@ -0,0 +1,59 @@ +//***************************************************************************** +// Copyright 2017-2019 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/coordinate.hpp" +#include "ngraph/op/op.hpp" +#include "ngraph/strides.hpp" + +namespace ngraph +{ + namespace op + { + namespace v1 + { + /// \brief VariadicSplit operation splits an input tensor into pieces along some axis. + /// The pieces may have variadic lengths depending on "split_lengths" attribute. + class NGRAPH_API VariadicSplit : public Op + { + public: + static constexpr NodeTypeInfo type_info{"VariadicSplit", 1}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + /// \brief Constructs a variadic split operation. + VariadicSplit() = default; + /// \brief Constructs a variadic split operation. + /// + /// \param data The tensor to be split. + /// \param axis The index of an axis in "data" along which to perform the + /// split. + /// \param split_lengths A list containing the sizes of each output tensor + /// along the split "axis". Size of "split_lengths" should be equal to the number of + /// + /// outputs. The sum of split_lengths must match data.shape[axis] + VariadicSplit(const Output& data, + const Output& axis, + const Output& split_lengths); + + void validate_and_infer_types() override; + virtual std::shared_ptr + copy_with_new_args(const NodeVector& new_args) const override; + }; + } // namespace v1 + + using v1::VariadicSplit; + } // namespace op +} // namespace ngraph diff --git a/src/ngraph/op/xor.hpp b/src/ngraph/op/xor.hpp index 1a052e4e607..0ed869e2f9f 100644 --- a/src/ngraph/op/xor.hpp +++ b/src/ngraph/op/xor.hpp @@ -28,12 +28,12 @@ namespace ngraph { /// \brief Elementwise logical-xor operation. /// - class LogicalXor : public util::BinaryElementwiseLogical + class NGRAPH_API LogicalXor : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"LogicalXor", 1}; const NodeTypeInfo& get_type_info() const override { return type_info; } + LogicalXor() = default; /// \brief Constructs a logical-xor operation. /// /// \param arg0 Node that produces the first input tensor.
    @@ -59,12 +59,12 @@ namespace ngraph { /// \brief Elementwise logical-xor operation. /// - class Xor : public util::BinaryElementwiseLogical + class NGRAPH_API Xor : public util::BinaryElementwiseLogical { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"Xor", 0}; const NodeTypeInfo& get_type_info() const override { return type_info; } + Xor() = default; /// \brief Constructs a logical-xor operation. /// /// \param arg0 Node that produces the first input tensor.
    diff --git a/src/ngraph/ops.hpp b/src/ngraph/ops.hpp new file mode 100644 index 00000000000..4996c05a168 --- /dev/null +++ b/src/ngraph/ops.hpp @@ -0,0 +1,184 @@ +//***************************************************************************** +// Copyright 2017-2019 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. +//***************************************************************************** + +// All op headers + +#pragma once + +#include "ngraph/op/abs.hpp" +#include "ngraph/op/acos.hpp" +#include "ngraph/op/add.hpp" +#include "ngraph/op/all.hpp" +#include "ngraph/op/allreduce.hpp" +#include "ngraph/op/and.hpp" +#include "ngraph/op/any.hpp" +#include "ngraph/op/argmax.hpp" +#include "ngraph/op/argmin.hpp" +#include "ngraph/op/asin.hpp" +#include "ngraph/op/atan.hpp" +#include "ngraph/op/atan2.hpp" +#include "ngraph/op/avg_pool.hpp" +#include "ngraph/op/batch_norm.hpp" +#include "ngraph/op/binary_convolution.hpp" +#include "ngraph/op/broadcast.hpp" +#include "ngraph/op/broadcast_distributed.hpp" +#include "ngraph/op/ceiling.hpp" +#include "ngraph/op/concat.hpp" +#include "ngraph/op/constant.hpp" +#include "ngraph/op/convert.hpp" +#include "ngraph/op/convert_like.hpp" +#include "ngraph/op/convolution.hpp" +#include "ngraph/op/cos.hpp" +#include "ngraph/op/cosh.hpp" +#include "ngraph/op/crop_and_resize.hpp" +#include "ngraph/op/cum_sum.hpp" +#include "ngraph/op/deformable_psroi_pooling.hpp" +#include "ngraph/op/dequantize.hpp" +#include "ngraph/op/divide.hpp" +#include "ngraph/op/dot.hpp" +#include "ngraph/op/embedding_lookup.hpp" +#include "ngraph/op/equal.hpp" +#include "ngraph/op/erf.hpp" +#include "ngraph/op/exp.hpp" +#include "ngraph/op/experimental/batch_mat_mul.hpp" +#include "ngraph/op/experimental/compiled_kernel.hpp" +#include "ngraph/op/experimental/dyn_broadcast.hpp" +#include "ngraph/op/experimental/dyn_pad.hpp" +#include "ngraph/op/experimental/dyn_replace_slice.hpp" +#include "ngraph/op/experimental/dyn_reshape.hpp" +#include "ngraph/op/experimental/dyn_slice.hpp" +#include "ngraph/op/experimental/generate_mask.hpp" +#include "ngraph/op/experimental/layers/ctc_greedy_decoder.hpp" +#include "ngraph/op/experimental/layers/detection_output.hpp" +#include "ngraph/op/experimental/layers/interpolate.hpp" +#include "ngraph/op/experimental/layers/prior_box.hpp" +#include "ngraph/op/experimental/layers/prior_box_clustered.hpp" +#include "ngraph/op/experimental/layers/proposal.hpp" +#include "ngraph/op/experimental/layers/psroi_pooling.hpp" +#include "ngraph/op/experimental/layers/region_yolo.hpp" +#include "ngraph/op/experimental/layers/reorg_yolo.hpp" +#include "ngraph/op/experimental/layers/roi_pooling.hpp" +#include "ngraph/op/experimental/quantized_conv_bias.hpp" +#include "ngraph/op/experimental/quantized_conv_relu.hpp" +#include "ngraph/op/experimental/quantized_dot_bias.hpp" +#include "ngraph/op/experimental/random_uniform.hpp" +#include "ngraph/op/experimental/range.hpp" +#include "ngraph/op/experimental/shape_of.hpp" +#include "ngraph/op/experimental/tile.hpp" +#include "ngraph/op/experimental/transpose.hpp" +#include "ngraph/op/floor.hpp" +#include "ngraph/op/floor_mod.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" +#include "ngraph/op/fused/clamp.hpp" +#include "ngraph/op/fused/conv_fused.hpp" +#include "ngraph/op/fused/crossentropy.hpp" +#include "ngraph/op/fused/crossentropy.hpp" +#include "ngraph/op/fused/depth_to_space.hpp" +#include "ngraph/op/fused/elu.hpp" +#include "ngraph/op/fused/fake_quantize.hpp" +#include "ngraph/op/fused/gelu.hpp" +#include "ngraph/op/fused/gemm.hpp" +#include "ngraph/op/fused/grn.hpp" +#include "ngraph/op/fused/group_conv.hpp" +#include "ngraph/op/fused/group_conv_transpose.hpp" +#include "ngraph/op/fused/gru_cell.hpp" +#include "ngraph/op/fused/hard_sigmoid.hpp" +#include "ngraph/op/fused/layer_norm.hpp" +#include "ngraph/op/fused/log_softmax.hpp" +#include "ngraph/op/fused/lstm_cell.hpp" +#include "ngraph/op/fused/lstm_sequence.hpp" +#include "ngraph/op/fused/matmul.hpp" +#include "ngraph/op/fused/mod.hpp" +#include "ngraph/op/fused/mvn.hpp" +#include "ngraph/op/fused/normalize_l2.hpp" +#include "ngraph/op/fused/partial_slice.hpp" +#include "ngraph/op/fused/prelu.hpp" +#include "ngraph/op/fused/reciprocal.hpp" +#include "ngraph/op/fused/rnn_cell.hpp" +#include "ngraph/op/fused/scale_shift.hpp" +#include "ngraph/op/fused/selu.hpp" +#include "ngraph/op/fused/shuffle_channels.hpp" +#include "ngraph/op/fused/softmax_crossentropy.hpp" +#include "ngraph/op/fused/space_to_depth.hpp" +#include "ngraph/op/fused/split.hpp" +#include "ngraph/op/fused/squared_difference.hpp" +#include "ngraph/op/fused/squeeze.hpp" +#include "ngraph/op/fused/unsqueeze.hpp" +#include "ngraph/op/gather.hpp" +#include "ngraph/op/gather_nd.hpp" +#include "ngraph/op/gather_tree.hpp" +#include "ngraph/op/get_output_element.hpp" +#include "ngraph/op/greater.hpp" +#include "ngraph/op/greater_eq.hpp" +#include "ngraph/op/less.hpp" +#include "ngraph/op/less_eq.hpp" +#include "ngraph/op/log.hpp" +#include "ngraph/op/lrn.hpp" +#include "ngraph/op/max.hpp" +#include "ngraph/op/max_pool.hpp" +#include "ngraph/op/maximum.hpp" +#include "ngraph/op/min.hpp" +#include "ngraph/op/minimum.hpp" +#include "ngraph/op/multiply.hpp" +#include "ngraph/op/negative.hpp" +#include "ngraph/op/not.hpp" +#include "ngraph/op/not_equal.hpp" +#include "ngraph/op/one_hot.hpp" +#include "ngraph/op/or.hpp" +#include "ngraph/op/pad.hpp" +#include "ngraph/op/parameter.hpp" +#include "ngraph/op/passthrough.hpp" +#include "ngraph/op/power.hpp" +#include "ngraph/op/product.hpp" +#include "ngraph/op/quantize.hpp" +#include "ngraph/op/quantized_convolution.hpp" +#include "ngraph/op/quantized_dot.hpp" +#include "ngraph/op/recv.hpp" +#include "ngraph/op/reduce_logical_and.hpp" +#include "ngraph/op/reduce_logical_or.hpp" +#include "ngraph/op/reduce_mean.hpp" +#include "ngraph/op/reduce_prod.hpp" +#include "ngraph/op/reduce_sum.hpp" +#include "ngraph/op/relu.hpp" +#include "ngraph/op/replace_slice.hpp" +#include "ngraph/op/reshape.hpp" +#include "ngraph/op/result.hpp" +#include "ngraph/op/reverse.hpp" +#include "ngraph/op/reverse_sequence.hpp" +#include "ngraph/op/scatter_add.hpp" +#include "ngraph/op/scatter_nd_add.hpp" +#include "ngraph/op/select.hpp" +#include "ngraph/op/send.hpp" +#include "ngraph/op/sigmoid.hpp" +#include "ngraph/op/sign.hpp" +#include "ngraph/op/sin.hpp" +#include "ngraph/op/sinh.hpp" +#include "ngraph/op/slice.hpp" +#include "ngraph/op/softmax.hpp" +#include "ngraph/op/sqrt.hpp" +#include "ngraph/op/stop_gradient.hpp" +#include "ngraph/op/strided_slice.hpp" +#include "ngraph/op/strided_slice.hpp" +#include "ngraph/op/subtract.hpp" +#include "ngraph/op/sum.hpp" +#include "ngraph/op/tan.hpp" +#include "ngraph/op/tanh.hpp" +#include "ngraph/op/tensor_iterator.hpp" +#include "ngraph/op/topk.hpp" +#include "ngraph/op/util/attr_types.hpp" +#include "ngraph/op/variadic_split.hpp" +#include "ngraph/op/variadic_split.hpp" +#include "ngraph/op/xor.hpp" diff --git a/src/ngraph/opsets/opset.cpp b/src/ngraph/opsets/opset.cpp new file mode 100644 index 00000000000..2604e5a8604 --- /dev/null +++ b/src/ngraph/opsets/opset.cpp @@ -0,0 +1,38 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/opsets/opset.hpp" +#include "ngraph/ops.hpp" + +const ngraph::OpSet& ngraph::get_opset0() +{ + static OpSet opset({ +#define NGRAPH_OP(NAME, NAMESPACE) NAMESPACE::NAME::type_info, +#include "ngraph/opsets/opset1_tbl.hpp" +#undef NGRAPH_OP + }); + return opset; +} + +const ngraph::OpSet& ngraph::get_opset1() +{ + static OpSet opset({ +#define NGRAPH_OP(NAME, NAMESPACE) NAMESPACE::NAME::type_info, +#include "ngraph/opsets/opset1_tbl.hpp" +#undef NGRAPH_OP + }); + return opset; +} \ No newline at end of file diff --git a/src/ngraph/opsets/opset.hpp b/src/ngraph/opsets/opset.hpp new file mode 100644 index 00000000000..4a44fd36ca6 --- /dev/null +++ b/src/ngraph/opsets/opset.hpp @@ -0,0 +1,50 @@ +//***************************************************************************** +// Copyright 2017-2019 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 + +#include "ngraph/node.hpp" + +namespace ngraph +{ + class OpSet + { + public: + OpSet(const std::set& op_types) + : m_op_types(op_types) + { + } + + template + bool contains_type() const + { + return m_op_types.find(T::type_info) != m_op_types.end(); + } + + bool contains_op_type(Node* node) const + { + return m_op_types.find(node->get_type_info()) != m_op_types.end(); + } + + protected: + std::set m_op_types; + }; + + const OpSet& get_opset0(); + const OpSet& get_opset1(); +} \ No newline at end of file diff --git a/src/ngraph/op/op_tbl.hpp b/src/ngraph/opsets/opset0_tbl.hpp similarity index 74% rename from src/ngraph/op/op_tbl.hpp rename to src/ngraph/opsets/opset0_tbl.hpp index 98400ffcebe..3c8febd2470 100644 --- a/src/ngraph/op/op_tbl.hpp +++ b/src/ngraph/opsets/opset0_tbl.hpp @@ -65,22 +65,31 @@ NGRAPH_OP(Atan2, ngraph::op) NGRAPH_OP(AvgPool, ngraph::op) NGRAPH_OP(AvgPoolBackprop, ngraph::op) NGRAPH_OP(BatchMatMul, ngraph::op) +NGRAPH_OP(BatchMatMulTranspose, ngraph::op) NGRAPH_OP(BatchNormInference, ngraph::op) NGRAPH_OP(BatchNormTraining, ngraph::op) NGRAPH_OP(BatchNormTrainingBackprop, ngraph::op) -NGRAPH_OP(BinaryConvolution, ngraph::op) NGRAPH_OP(Broadcast, ngraph::op) NGRAPH_OP(BroadcastDistributed, ngraph::op) NGRAPH_OP(BroadcastLike, ngraph::op) NGRAPH_OP(Ceiling, ngraph::op) +NGRAPH_OP(Clamp, ngraph::op) NGRAPH_OP(Concat, ngraph::op) NGRAPH_OP(Constant, ngraph::op) NGRAPH_OP(Convert, ngraph::op) NGRAPH_OP(Convolution, ngraph::op) NGRAPH_OP(ConvolutionBackpropData, ngraph::op) NGRAPH_OP(ConvolutionBackpropFilters, ngraph::op) +NGRAPH_OP(ConvolutionBias, ngraph::op) +NGRAPH_OP(ConvolutionBiasAdd, ngraph::op) +NGRAPH_OP(ConvolutionBiasBackpropFiltersBias, ngraph::op) NGRAPH_OP(Cos, ngraph::op) NGRAPH_OP(Cosh, ngraph::op) +NGRAPH_OP(CrossEntropy, ngraph::op) +NGRAPH_OP(CrossEntropyBackprop, ngraph::op) +NGRAPH_OP(CropAndResize, ngraph::op) +NGRAPH_OP(CumSum, ngraph::op::v0) +NGRAPH_OP(DepthToSpace, ngraph::op) NGRAPH_OP(Dequantize, ngraph::op) NGRAPH_OP(Divide, ngraph::op) NGRAPH_OP(Dot, ngraph::op) @@ -89,26 +98,41 @@ NGRAPH_OP(DynPad, ngraph::op) NGRAPH_OP(DynReplaceSlice, ngraph::op) NGRAPH_OP(DynReshape, ngraph::op) NGRAPH_OP(DynSlice, ngraph::op) +NGRAPH_OP(Elu, ngraph::op) NGRAPH_OP(EmbeddingLookup, ngraph::op) NGRAPH_OP(Equal, ngraph::op) NGRAPH_OP(Erf, ngraph::op) NGRAPH_OP(Exp, ngraph::op) +NGRAPH_OP(FakeQuantize, ngraph::op) NGRAPH_OP(Floor, ngraph::op) +NGRAPH_OP(GRN, ngraph::op) +NGRAPH_OP(GRUCell, ngraph::op) NGRAPH_OP(Gather, ngraph::op) NGRAPH_OP(GatherND, ngraph::op) +NGRAPH_OP(Gelu, ngraph::op) +NGRAPH_OP(GeluBackpropFactor, ngraph::op) +NGRAPH_OP(Gemm, ngraph::op) NGRAPH_OP(GenerateMask, ngraph::op) NGRAPH_OP(GetOutputElement, ngraph::op) NGRAPH_OP(Greater, ngraph::op) NGRAPH_OP(GreaterEq, ngraph::op) +NGRAPH_OP(GroupConvolution, ngraph::op) +NGRAPH_OP(GroupConvolutionBackpropData, ngraph::op) +NGRAPH_OP(GroupConvolutionBackpropFilters, ngraph::op) +NGRAPH_OP(GroupConvolutionTranspose, ngraph::op) +NGRAPH_OP(HardSigmoid, ngraph::op) +NGRAPH_OP(Interpolate, ngraph::op) +NGRAPH_OP(LayerNorm, ngraph::op) +NGRAPH_OP(LayerNormBackprop, ngraph::op) NGRAPH_OP(Less, ngraph::op) NGRAPH_OP(LessEq, ngraph::op) -NGRAPH_OP(LessEqual, ngraph::op) NGRAPH_OP(Log, ngraph::op) -NGRAPH_OP(LogicalAnd, ngraph::op) -NGRAPH_OP(LogicalNot, ngraph::op) -NGRAPH_OP(LogicalOr, ngraph::op) -NGRAPH_OP(LogicalXor, ngraph::op) +NGRAPH_OP(LogSoftmax, ngraph::op) NGRAPH_OP(LRN, ngraph::op) +NGRAPH_OP(LSTMCell, ngraph::op) +NGRAPH_OP(LSTMSequence, ngraph::op) +NGRAPH_OP(MatMul, ngraph::op) +NGRAPH_OP(NormalizeL2, ngraph::op) NGRAPH_OP(Max, ngraph::op) NGRAPH_OP(Maximum, ngraph::op) NGRAPH_OP(MaxPool, ngraph::op) @@ -116,6 +140,7 @@ NGRAPH_OP(MaxPoolBackprop, ngraph::op) NGRAPH_OP(Min, ngraph::op) NGRAPH_OP(Minimum, ngraph::op) NGRAPH_OP(Multiply, ngraph::op) +NGRAPH_OP(MVN, ngraph::op) NGRAPH_OP(Negative, ngraph::op) NGRAPH_OP(Not, ngraph::op) NGRAPH_OP(NotEqual, ngraph::op) @@ -123,8 +148,11 @@ NGRAPH_OP(OneHot, ngraph::op) NGRAPH_OP(Or, ngraph::op) NGRAPH_OP(Pad, ngraph::op) NGRAPH_OP(Parameter, ngraph::op) +NGRAPH_OP(PartialSlice, ngraph::op) +NGRAPH_OP(PartialSliceBackprop, ngraph::op) NGRAPH_OP(Passthrough, ngraph::op) NGRAPH_OP(Power, ngraph::op) +NGRAPH_OP(PRelu, ngraph::op) NGRAPH_OP(Product, ngraph::op) NGRAPH_OP(Quantize, ngraph::op) NGRAPH_OP(QuantizedConvolution, ngraph::op) @@ -134,9 +162,10 @@ NGRAPH_OP(QuantizedConvolutionBiasSignedAdd, ngraph::op) NGRAPH_OP(QuantizedConvolutionRelu, ngraph::op) NGRAPH_OP(QuantizedDot, ngraph::op) NGRAPH_OP(QuantizedDotBias, ngraph::op) -NGRAPH_OP(Recv, ngraph::op) NGRAPH_OP(RandomUniform, ngraph::op) +NGRAPH_OP(Recv, ngraph::op) NGRAPH_OP(Range, ngraph::op) +NGRAPH_OP(Reciprocal, ngraph::op) NGRAPH_OP(Relu, ngraph::op) NGRAPH_OP(ReluBackprop, ngraph::op) NGRAPH_OP(ReplaceSlice, ngraph::op) @@ -144,12 +173,16 @@ NGRAPH_OP(Reshape, ngraph::op) NGRAPH_OP(Result, ngraph::op) NGRAPH_OP(Reverse, ngraph::op) NGRAPH_OP(ReverseSequence, ngraph::op) +NGRAPH_OP(RNNCell, ngraph::op) NGRAPH_OP(ScalarConstantLike, ngraph::op) +NGRAPH_OP(ScaleShift, ngraph::op) NGRAPH_OP(ScatterAdd, ngraph::op) NGRAPH_OP(ScatterNDAdd, ngraph::op) NGRAPH_OP(Select, ngraph::op) +NGRAPH_OP(Selu, ngraph::op) NGRAPH_OP(Send, ngraph::op) NGRAPH_OP(ShapeOf, ngraph::op) +NGRAPH_OP(ShuffleChannels, ngraph::op) NGRAPH_OP(Sigmoid, ngraph::op) NGRAPH_OP(SigmoidBackprop, ngraph::op) NGRAPH_OP(Sign, ngraph::op) @@ -157,13 +190,21 @@ NGRAPH_OP(Sin, ngraph::op) NGRAPH_OP(Sinh, ngraph::op) NGRAPH_OP(Slice, ngraph::op) NGRAPH_OP(Softmax, ngraph::op) +NGRAPH_OP(SoftmaxCrossEntropy, ngraph::op) +NGRAPH_OP(SoftmaxCrossEntropyBackprop, ngraph::op) +NGRAPH_OP(SpaceToDepth, ngraph::op) +NGRAPH_OP(Split, ngraph::op) NGRAPH_OP(Sqrt, ngraph::op) +NGRAPH_OP(SquaredDifference, ngraph::op) +NGRAPH_OP(Squeeze, ngraph::op) NGRAPH_OP(StopGradient, ngraph::op) NGRAPH_OP(Subtract, ngraph::op) NGRAPH_OP(Sum, ngraph::op) NGRAPH_OP(Tan, ngraph::op) NGRAPH_OP(Tanh, ngraph::op) +NGRAPH_OP(TensorIterator, ngraph::op) NGRAPH_OP(Tile, ngraph::op) -NGRAPH_OP(TopK, ngraph::op) +NGRAPH_OP(TopK, ngraph::op::v0) NGRAPH_OP(Transpose, ngraph::op) +NGRAPH_OP(Unsqueeze, ngraph::op) NGRAPH_OP(Xor, ngraph::op) diff --git a/src/ngraph/opsets/opset1.hpp b/src/ngraph/opsets/opset1.hpp new file mode 100644 index 00000000000..df4d53fccea --- /dev/null +++ b/src/ngraph/opsets/opset1.hpp @@ -0,0 +1,29 @@ +//***************************************************************************** +// Copyright 2017-2019 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/ngraph.hpp" + +namespace ngraph +{ + namespace opset1 + { +#define NGRAPH_OP(a, b) using b::a; +#include "ngraph/opsets/opset1_tbl.hpp" +#undef NGRAPH_OP + } +} diff --git a/src/ngraph/opsets/opset1_tbl.hpp b/src/ngraph/opsets/opset1_tbl.hpp new file mode 100644 index 00000000000..498f6fc6719 --- /dev/null +++ b/src/ngraph/opsets/opset1_tbl.hpp @@ -0,0 +1,159 @@ +//***************************************************************************** +// Copyright 2017-2019 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. +//***************************************************************************** + +// This collection contains one entry for each op. If an op is added it must be +// added to this list. +// +// In order to use this list you want to define a macro named exactly NGRAPH_OP +// When you are done you should undef the macro +// As an example if you wanted to make a list of all op names as strings you could do this: +// +// #define NGRAPH_OP(a,b) #a, +// std::vector op_names{ +// #include "this include file name" +// }; +// #undef NGRAPH_OP +// +// This sample expands to a list like this: +// "Abs", +// "Acos", +// ... +// +// #define NGRAPH_OP(a,b) b::a, +// std::vector op_names{ +// #include "this include file name" +// }; +// #undef NGRAPH_OP +// +// This sample expands to a list like this: +// ngraph::op::Abs, +// ngraph::op::Acos, +// ... +// +// It's that easy. You can use this for fun and profit. + +#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::v0) +NGRAPH_OP(BinaryConvolution, ngraph::op::v1) +NGRAPH_OP(Broadcast, ngraph::op::v1) +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(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(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::v0) +NGRAPH_OP(GRN, ngraph::op::v0) +NGRAPH_OP(HardSigmoid, ngraph::op::v0) +NGRAPH_OP(Interpolate, 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::v0) +NGRAPH_OP(LSTMSequence, ngraph::op::v0) +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) +NGRAPH_OP(Power, ngraph::op::v1) +NGRAPH_OP(PriorBox, ngraph::op::v0) +NGRAPH_OP(PriorBoxClustered, ngraph::op::v0) +NGRAPH_OP(Proposal, ngraph::op::v0) +NGRAPH_OP(Range, ngraph::op::v0) +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(Reshape, ngraph::op::v1) +NGRAPH_OP(Result, ngraph::op) +NGRAPH_OP(Reverse, ngraph::op::v1) +NGRAPH_OP(ReverseSequence, ngraph::op::v0) +NGRAPH_OP(RNNCell, ngraph::op::v0) +NGRAPH_OP(Select, ngraph::op::v0) +NGRAPH_OP(Selu, ngraph::op::v0) +NGRAPH_OP(ShapeOf, ngraph::op::v0) +NGRAPH_OP(ShuffleChannels, 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::v0) +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(TopK, ngraph::op::v1) +NGRAPH_OP(Transpose, ngraph::op::v0) +NGRAPH_OP(Unsqueeze, ngraph::op::v0) +NGRAPH_OP(VariadicSplit, ngraph::op::v1) +NGRAPH_OP(Xor, ngraph::op::v0) diff --git a/src/ngraph/partial_shape.cpp b/src/ngraph/partial_shape.cpp index f1d814b2954..c85a3eab26f 100644 --- a/src/ngraph/partial_shape.cpp +++ b/src/ngraph/partial_shape.cpp @@ -339,3 +339,5 @@ bool PartialShape::all_non_negative() const return true; } + +NGRAPH_API constexpr DiscreteTypeInfo AttributeAdapter::type_info; diff --git a/src/ngraph/partial_shape.hpp b/src/ngraph/partial_shape.hpp index 2cfb20c6178..0edfc848dc4 100644 --- a/src/ngraph/partial_shape.hpp +++ b/src/ngraph/partial_shape.hpp @@ -18,6 +18,7 @@ #include +#include "ngraph/attribute_adapter.hpp" #include "ngraph/dimension.hpp" #include "ngraph/op/util/attr_types.hpp" #include "ngraph/rank.hpp" @@ -41,7 +42,7 @@ namespace ngraph /// (Informal notation examples: `{1,2,?,4}`, `{?,?,?}`) /// \li Static rank, and static dimensions on all axes. /// (Informal notation examples: `{1,2,3,4}`, `{6}`, `{}`) - class PartialShape + class NGRAPH_API PartialShape { public: /// \brief Constructs a shape with static rank from an initializer list of Dimension. @@ -183,7 +184,7 @@ namespace ngraph Dimension& operator[](size_t i) { return m_dimensions[i]; } /// \brief Returns a vector of the dimensions. This has no meaning if dynamic. explicit operator std::vector() const { return m_dimensions; } - friend std::ostream& operator<<(std::ostream& str, const PartialShape& shape); + friend NGRAPH_API std::ostream& operator<<(std::ostream& str, const PartialShape& shape); friend PartialShape operator+(const PartialShape& s1, const PartialShape& s2); /// \brief Try to merge one shape into another. @@ -281,5 +282,20 @@ namespace ngraph /// {1,?,2,3} /// {2,3,4} /// \endcode + NGRAPH_API std::ostream& operator<<(std::ostream& str, const PartialShape& shape); + + template <> + class AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(PartialShape& value) + : ValueReference(value) + { + } + NGRAPH_API + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; } diff --git a/src/ngraph/pass/algebraic_simplification.hpp b/src/ngraph/pass/algebraic_simplification.hpp index 02d2735b51a..28c33ec1565 100644 --- a/src/ngraph/pass/algebraic_simplification.hpp +++ b/src/ngraph/pass/algebraic_simplification.hpp @@ -27,7 +27,7 @@ namespace ngraph } } -class ngraph::pass::AlgebraicSimplification : public FunctionPass +class NGRAPH_API ngraph::pass::AlgebraicSimplification : public FunctionPass { public: AlgebraicSimplification() diff --git a/src/ngraph/pass/batch_fusion.cpp b/src/ngraph/pass/batch_fusion.cpp index c09c3d2727b..0e09b6edc6d 100644 --- a/src/ngraph/pass/batch_fusion.cpp +++ b/src/ngraph/pass/batch_fusion.cpp @@ -29,6 +29,7 @@ #include "ngraph/op/broadcast.hpp" #include "ngraph/op/concat.hpp" #include "ngraph/op/dot.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/op/fused/group_conv.hpp" #include "ngraph/op/reshape.hpp" #include "ngraph/op/slice.hpp" @@ -163,6 +164,81 @@ std::shared_ptr fuse_group_convolution(const std::shared_ptr& n) return move(new_conv); } +std::shared_ptr fuse_batch_mat_mul_transpose(const std::shared_ptr& n) +{ + const int num_op_branches = 2; + std::shared_ptr input[num_op_branches]; + std::shared_ptr reshape[num_op_branches]; + for (int i = 0; i < num_op_branches; ++i) + { + input[i] = std::make_shared(element::f32, Shape{3, 2, 2}); + auto slice = + std::make_shared(input[i], Coordinate{0, 0, 0}, Coordinate{1, 2, 2}); + auto skip = std::make_shared(slice, pattern::has_class()); + reshape[i] = std::make_shared(skip, AxisVector{0, 1, 2}, Shape{2, 2}); + } + auto dot = std::make_shared(reshape[0], reshape[1]); + auto final_reshape = std::make_shared(dot, AxisVector{0, 1}, Shape{1, 2, 2}); + + auto matcher = std::make_shared(final_reshape); + std::shared_ptr fuse_input[num_op_branches]; + bool transpose[num_op_branches] = {false, false}; + const int num_expected_reshape_with_trans = 3; + + // check each input arg matches the pattern + for (auto arg : n->get_arguments()) + { + if (matcher->match(arg)) + { + auto pattern_map = matcher->get_pattern_map(); + int reshape_count[num_op_branches] = {0, 0}; + // we found a match, determine whether we have to transpose for each input by + // counting the number of reshapes in each branch, if transpose is applied, there + // should be 3 reshapes. + for (int i = 0; i < num_op_branches; ++i) + { + auto iter = matcher->get_match_root(); + auto& input_node = pattern_map[input[i]]; + do + { + if (is_type(iter)) + { + ++reshape_count[i]; + if (reshape_count[i] == num_expected_reshape_with_trans) + { + transpose[i] = true; + break; + } + } + // branch to either input 0 or 1 depending on which one we are traversing + iter = + iter->get_input_size() > 1 ? iter->get_argument(i) : iter->get_argument(0); + } while (iter != input_node); + } + // keep track of the input data, make sure they all match + for (int i = 0; i < num_op_branches; ++i) + { + auto& input_node = pattern_map[input[i]]; + if (fuse_input[i] == nullptr) + { + fuse_input[i] = input_node; + } + // found different input nodes between different args, can't fuse. + else if (fuse_input[i] != input_node) + { + return {nullptr}; + } + } + } + } + if (fuse_input[0] && fuse_input[1]) + { + return std::make_shared( + fuse_input[0], fuse_input[1], transpose[0], transpose[1]); + } + return {nullptr}; +} + bool ngraph::pass::BatchFusion::run_on_function(std::shared_ptr func) { bool modified = false; @@ -172,6 +248,14 @@ bool ngraph::pass::BatchFusion::run_on_function(std::shared_ptr func) const Node& node = *n; if (TI(node) == TI(op::Concat)) { + if (m_fusion_type.is_set(FusionType::DIFFERENTIABLE_FUSIONS)) + { + if (auto fused_node = fuse_batch_mat_mul_transpose(n)) + { + func->replace_node(n, fused_node); + modified = true; + } + } if (m_fusion_type.is_set(FusionType::REGULAR_FUSIONS)) { if (auto fused_conv = fuse_group_convolution(n)) diff --git a/src/ngraph/pass/batch_fusion.hpp b/src/ngraph/pass/batch_fusion.hpp index 3597b4bc2ec..9dbeceb91ce 100644 --- a/src/ngraph/pass/batch_fusion.hpp +++ b/src/ngraph/pass/batch_fusion.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace pass { - class BatchFusion : public ngraph::pass::FunctionPass + class NGRAPH_API BatchFusion : public ngraph::pass::FunctionPass { public: BatchFusion(FusionTypeMask type = FusionType::ALL_FUSIONS) diff --git a/src/ngraph/pass/common_function_collection.hpp b/src/ngraph/pass/common_function_collection.hpp index 12295ff6863..65fbb454ffa 100644 --- a/src/ngraph/pass/common_function_collection.hpp +++ b/src/ngraph/pass/common_function_collection.hpp @@ -29,7 +29,7 @@ namespace ngraph } } -class ngraph::pass::CommonFunctionCollection : public ModulePass +class NGRAPH_API ngraph::pass::CommonFunctionCollection : public ModulePass { public: /// \brief Create the CommonFunctionCollection pass diff --git a/src/ngraph/pass/concat_fusion.hpp b/src/ngraph/pass/concat_fusion.hpp index 32433d90f47..4c7478a814a 100644 --- a/src/ngraph/pass/concat_fusion.hpp +++ b/src/ngraph/pass/concat_fusion.hpp @@ -31,7 +31,7 @@ namespace ngraph } } -class ngraph::pass::ConcatElimination : public ngraph::pass::GraphRewrite +class NGRAPH_API ngraph::pass::ConcatElimination : public ngraph::pass::GraphRewrite { public: ConcatElimination() @@ -44,7 +44,7 @@ class ngraph::pass::ConcatElimination : public ngraph::pass::GraphRewrite void construct_concat_elimination(); }; -class ngraph::pass::SelfConcatFusion : public ngraph::pass::FunctionPass +class NGRAPH_API ngraph::pass::SelfConcatFusion : public ngraph::pass::FunctionPass { public: SelfConcatFusion() { set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); } diff --git a/src/ngraph/pass/constant_folding.hpp b/src/ngraph/pass/constant_folding.hpp index 994f2873c18..d06e13265b1 100644 --- a/src/ngraph/pass/constant_folding.hpp +++ b/src/ngraph/pass/constant_folding.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite +class NGRAPH_API ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite { public: enum class CFTransformations @@ -50,6 +50,7 @@ class ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite GATHER, SLICE, DYN_SLICE, + STRIDED_SLICE, DYN_RESHAPE, TRANSPOSE, RANGE, @@ -81,6 +82,7 @@ class ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite construct_constant_gather(); construct_constant_slice(); construct_constant_dyn_slice(); + construct_constant_strided_slice(); construct_constant_dyn_reshape(); construct_constant_transpose(); construct_constant_range(); @@ -121,6 +123,7 @@ class ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite case CFTransformations::GATHER: construct_constant_gather(); break; case CFTransformations::SLICE: construct_constant_slice(); break; case CFTransformations::DYN_SLICE: construct_constant_dyn_slice(); break; + case CFTransformations::STRIDED_SLICE: construct_constant_strided_slice(); break; case CFTransformations::DYN_RESHAPE: construct_constant_dyn_reshape(); break; case CFTransformations::TRANSPOSE: construct_constant_transpose(); break; case CFTransformations::RANGE: construct_constant_range(); break; @@ -149,6 +152,7 @@ class ngraph::pass::ConstantFolding : public ngraph::pass::GraphRewrite void construct_constant_gather(); void construct_constant_slice(); void construct_constant_dyn_slice(); + void construct_constant_strided_slice(); void construct_constant_dyn_reshape(); void construct_constant_transpose(); void construct_constant_range(); diff --git a/src/ngraph/pass/constant_folding_arithmetic_reduction.cpp b/src/ngraph/pass/constant_folding_arithmetic_reduction.cpp index 537a7db403d..eba13997acc 100644 --- a/src/ngraph/pass/constant_folding_arithmetic_reduction.cpp +++ b/src/ngraph/pass/constant_folding_arithmetic_reduction.cpp @@ -189,6 +189,9 @@ static shared_ptr NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_arithmetic_reduction"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_arithmetic_reduction"); + break; case element::Type_t::boolean: return fold_constant_arithmetic_reduction_helper(constant, reduction_node); case element::Type_t::bf16: diff --git a/src/ngraph/pass/constant_folding_binary.cpp b/src/ngraph/pass/constant_folding_binary.cpp index 0f9acc38ed4..4c4309049aa 100644 --- a/src/ngraph/pass/constant_folding_binary.cpp +++ b/src/ngraph/pass/constant_folding_binary.cpp @@ -74,7 +74,7 @@ static shared_ptr fold_constant_binary_logical(shared_ptr(binary)) + if (auto and_v0_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::logical_and(a->get_data_ptr(), @@ -82,21 +82,21 @@ static shared_ptr fold_constant_binary_logical(shared_ptrget_shape(), b->get_shape(), - and_node->get_autob()); + and_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto logical_xor_node = as_type_ptr(binary)) + else if (auto logical_and_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); - runtime::reference::logical_xor(a->get_data_ptr(), + runtime::reference::logical_and(a->get_data_ptr(), b->get_data_ptr(), out_vec.data(), a->get_shape(), b->get_shape(), - logical_xor_node->get_autob()); + logical_and_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto or_node = as_type_ptr(binary)) + else if (auto or_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::logical_or(a->get_data_ptr(), @@ -107,6 +107,17 @@ static shared_ptr fold_constant_binary_logical(shared_ptrget_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } + else if (auto logical_or_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::logical_or(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + logical_or_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } else if (auto xor_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); @@ -118,6 +129,17 @@ static shared_ptr fold_constant_binary_logical(shared_ptrget_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } + else if (auto logical_xor_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::logical_xor(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + logical_xor_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } else { NGRAPH_CHECK( @@ -151,7 +173,18 @@ shared_ptr fold_constant_binary_comparison(shared_ptr(binary)) + if (auto equal_v0_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::equal(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + equal_v0_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto equal_v1_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::equal(a->get_data_ptr(), @@ -159,10 +192,21 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - equal_node->get_autob()); + equal_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto greater_v0_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::greater(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + greater_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto greater_node = as_type_ptr(binary)) + else if (auto greater_v1_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::greater(a->get_data_ptr(), @@ -170,10 +214,10 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - greater_node->get_autob()); + greater_v1_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto greater_eq_node = as_type_ptr(binary)) + else if (auto greater_eq_v0_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::greater_eq(a->get_data_ptr(), @@ -181,10 +225,21 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - greater_eq_node->get_autob()); + greater_eq_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto less_node = as_type_ptr(binary)) + else if (auto greater_eq_v1_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::greater_eq(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + greater_eq_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto less_v0_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::less(a->get_data_ptr(), @@ -192,10 +247,32 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - less_node->get_autob()); + less_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto less_eq_node = as_type_ptr(binary)) + else if (auto less_v1_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::less(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + less_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto less_eq_v0_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::less_eq(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + less_eq_v0_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto less_eq_v1_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::less_eq(a->get_data_ptr(), @@ -203,10 +280,10 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - less_eq_node->get_autob()); + less_eq_v1_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto not_equal_node = as_type_ptr(binary)) + else if (auto not_equal_v0_node = as_type_ptr(binary)) { vector out_vec(shape_size(out_shape)); runtime::reference::not_equal(a->get_data_ptr(), @@ -214,7 +291,18 @@ shared_ptr fold_constant_binary_comparison(shared_ptrget_shape(), b->get_shape(), - not_equal_node->get_autob()); + not_equal_v0_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto not_equal_v1_node = as_type_ptr(binary)) + { + vector out_vec(shape_size(out_shape)); + runtime::reference::not_equal(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + not_equal_v1_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } else @@ -249,7 +337,7 @@ shared_ptr fold_constant_binary_arithmetic(shared_ptr(binary)) + if (auto add_v0_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); @@ -259,26 +347,55 @@ shared_ptr fold_constant_binary_arithmetic(shared_ptrget_shape(), b->get_shape(), - add_node->get_autob()); + add_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto divide_node = as_type_ptr(binary)) + else if (auto add_v1_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); vector out_vec(shape_size(out_shape)); - shared_ptr divop = as_type_ptr(binary); + runtime::reference::add(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + add_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto divide_v0_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + shared_ptr divop = as_type_ptr(binary); bool pythondiv = divop->is_pythondiv(); runtime::reference::divide(a->get_data_ptr(), b->get_data_ptr(), out_vec.data(), a->get_shape(), b->get_shape(), - divide_node->get_autob(), + divide_v0_node->get_autob(), pythondiv); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto maximum_node = as_type_ptr(binary)) + else if (auto divide_v1_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + shared_ptr divop = as_type_ptr(binary); + bool pythondiv = divop->is_pythondiv(); + runtime::reference::divide(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + divide_v1_node->get_autob(), + pythondiv); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto maximum_v0_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); @@ -288,10 +405,36 @@ shared_ptr fold_constant_binary_arithmetic(shared_ptrget_shape(), b->get_shape(), - maximum_node->get_autob()); + maximum_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto minimum_node = as_type_ptr(binary)) + else if (auto maximum_v1_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + runtime::reference::maximum(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + maximum_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto minimum_v0_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + runtime::reference::minimum(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + minimum_v0_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto minimum_v1_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); @@ -301,10 +444,23 @@ shared_ptr fold_constant_binary_arithmetic(shared_ptrget_shape(), b->get_shape(), - minimum_node->get_autob()); + minimum_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto multiply_v0_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + runtime::reference::multiply(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + multiply_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto multiply_node = as_type_ptr(binary)) + else if (auto multiply_v1_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); @@ -314,21 +470,35 @@ shared_ptr fold_constant_binary_arithmetic(shared_ptrget_shape(), b->get_shape(), - multiply_node->get_autob()); + multiply_v1_node->get_autob()); + return make_shared(binary->get_element_type(), out_shape, out_vec); + } + else if (auto power_v0_node = as_type_ptr(binary)) + { + NGRAPH_CHECK(element::from() == element::from(), + "Input/output types do not match"); + vector out_vec(shape_size(out_shape)); + shared_ptr powop = as_type_ptr(binary); + runtime::reference::power(a->get_data_ptr(), + b->get_data_ptr(), + out_vec.data(), + a->get_shape(), + b->get_shape(), + power_v0_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } - else if (auto power_node = as_type_ptr(binary)) + else if (auto power_v1_node = as_type_ptr(binary)) { NGRAPH_CHECK(element::from() == element::from(), "Input/output types do not match"); vector out_vec(shape_size(out_shape)); - shared_ptr powop = as_type_ptr(binary); + shared_ptr powop = as_type_ptr(binary); runtime::reference::power(a->get_data_ptr(), b->get_data_ptr(), out_vec.data(), a->get_shape(), b->get_shape(), - power_node->get_autob()); + power_v1_node->get_autob()); return make_shared(binary->get_element_type(), out_shape, out_vec); } else if (auto subtract_node = as_type_ptr(binary)) @@ -375,12 +545,19 @@ shared_ptr fold_constant_binary_helper(shared_ptr a, bool is_supported_binary_op(std::shared_ptr n) { - return (is_type(n) || is_type(n) || is_type(n) || - is_type(n) || is_type(n) || is_type(n) || - is_type(n) || is_type(n) || is_type(n) || - is_type(n) || is_type(n) || is_type(n) || - is_type(n) || is_type(n) || is_type(n) || - is_type(n)); + return ( + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || + is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || is_type(n) || + is_type(n) || is_type(n) || + is_type(n) || is_type(n)); } void pass::ConstantFolding::construct_constant_binary() @@ -443,6 +620,9 @@ void pass::ConstantFolding::construct_constant_binary() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_binary_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_binary_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_binary_helper(a_match, b_match, binary_match, func); diff --git a/src/ngraph/pass/constant_folding_broadcast.cpp b/src/ngraph/pass/constant_folding_broadcast.cpp index 125bd8012bb..791209e6327 100644 --- a/src/ngraph/pass/constant_folding_broadcast.cpp +++ b/src/ngraph/pass/constant_folding_broadcast.cpp @@ -117,6 +117,9 @@ void pass::ConstantFolding::construct_constant_broadcast() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_broadcast_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_broadcast_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_broadcast(constant_match, broadcast_match, func); break; diff --git a/src/ngraph/pass/constant_folding_concat.cpp b/src/ngraph/pass/constant_folding_concat.cpp index 5543d9a1522..de89befcdd1 100644 --- a/src/ngraph/pass/constant_folding_concat.cpp +++ b/src/ngraph/pass/constant_folding_concat.cpp @@ -79,6 +79,9 @@ void pass::ConstantFolding::construct_constant_concat() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_concat"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_concat"); + break; case element::Type_t::boolean: replacement = fold_constant_concat_helper(concat_node); break; diff --git a/src/ngraph/pass/constant_folding_convert.cpp b/src/ngraph/pass/constant_folding_convert.cpp index 652fa22d6c8..9adb64b5456 100644 --- a/src/ngraph/pass/constant_folding_convert.cpp +++ b/src/ngraph/pass/constant_folding_convert.cpp @@ -57,6 +57,9 @@ shared_ptr fold_constant_convert_helper0(shared_ptr case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_convert"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_convert"); + break; case element::Type_t::boolean: return fold_constant_convert_helper1(constant, output_element_type); case element::Type_t::bf16: @@ -114,6 +117,9 @@ static shared_ptr fold_constant_convert(shared_ptr c case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_convert"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_convert"); + break; case element::Type_t::boolean: return fold_constant_convert_helper0(constant, output_element_type); case element::Type_t::bf16: diff --git a/src/ngraph/pass/constant_folding_dyn_broadcast.cpp b/src/ngraph/pass/constant_folding_dyn_broadcast.cpp index 313a49e7ada..49518347f54 100644 --- a/src/ngraph/pass/constant_folding_dyn_broadcast.cpp +++ b/src/ngraph/pass/constant_folding_dyn_broadcast.cpp @@ -81,6 +81,9 @@ void pass::ConstantFolding::construct_constant_dyn_broadcast() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_dyn_broadcast_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_dyn_broadcast_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_dyn_broadcast( constant_arg_match, constant_shape_match, constant_axes_match); diff --git a/src/ngraph/pass/constant_folding_dyn_reshape.cpp b/src/ngraph/pass/constant_folding_dyn_reshape.cpp index b98c08d45a2..1dbb08d7449 100644 --- a/src/ngraph/pass/constant_folding_dyn_reshape.cpp +++ b/src/ngraph/pass/constant_folding_dyn_reshape.cpp @@ -50,7 +50,8 @@ void pass::ConstantFolding::construct_constant_dyn_reshape() element::f32, Shape{2, 4}, pattern::has_class()); auto constant_shape_label = make_shared(element::i64, Shape{1}, pattern::has_class()); - auto dyn_reshape = make_shared(constant_data_label, constant_shape_label); + auto dyn_reshape = + make_shared(constant_data_label, constant_shape_label, false); // Note: No need to capture or consider constant_shape_label, because // shape propagation will have transferred the info to dyn_reshape's @@ -79,6 +80,9 @@ void pass::ConstantFolding::construct_constant_dyn_reshape() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_dyn_reshape_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_dyn_reshape_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_dyn_reshape(constant_data_match, dyn_reshape_match); break; diff --git a/src/ngraph/pass/constant_folding_dyn_slice.cpp b/src/ngraph/pass/constant_folding_dyn_slice.cpp index 9cb7df63457..2c3930dbf7a 100644 --- a/src/ngraph/pass/constant_folding_dyn_slice.cpp +++ b/src/ngraph/pass/constant_folding_dyn_slice.cpp @@ -114,6 +114,9 @@ void pass::ConstantFolding::construct_constant_dyn_slice() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_dyn_slice"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_dyn_slice"); + break; case element::Type_t::boolean: replacement = fold_constant_dyn_slice(data_node, lb_node, ub_node, strides_node, dyn_slice); diff --git a/src/ngraph/pass/constant_folding_gather.cpp b/src/ngraph/pass/constant_folding_gather.cpp index 33da340cf41..48fb21971c5 100644 --- a/src/ngraph/pass/constant_folding_gather.cpp +++ b/src/ngraph/pass/constant_folding_gather.cpp @@ -26,17 +26,34 @@ using namespace ngraph; template static shared_ptr fold_constant_gather_helper(const shared_ptr& data, const shared_ptr& indices, - const shared_ptr& gather) + const shared_ptr& gather) { std::vector result_vec(shape_size(gather->get_shape())); - runtime::reference::gather(data->get_data_ptr(), - indices->get_data_ptr(), - result_vec.data(), - data->get_shape(), - indices->get_shape(), - gather->get_shape(), - gather->get_axis()); + if (auto gather_v1 = as_type_ptr(gather)) + { + runtime::reference::gather(data->get_data_ptr(), + indices->get_data_ptr(), + result_vec.data(), + data->get_shape(), + indices->get_shape(), + gather_v1->get_shape(), + gather_v1->get_axis()); + } + else if (auto gather_v0 = as_type_ptr(gather)) + { + runtime::reference::gather(data->get_data_ptr(), + indices->get_data_ptr(), + result_vec.data(), + data->get_shape(), + indices->get_shape(), + gather_v0->get_shape(), + gather_v0->get_axis()); + } + else + { + throw ngraph_error("Unsupported op in gather constant folding."); + } return make_shared( gather->get_output_element_type(0), gather->get_output_shape(0), result_vec); @@ -45,7 +62,7 @@ static shared_ptr fold_constant_gather_helper(const shared_ptr static shared_ptr fold_constant_gather(const shared_ptr& data, const shared_ptr& indices, - const shared_ptr& gather) + const shared_ptr& gather) { auto indices_type = indices->get_output_element_type(0); @@ -64,6 +81,7 @@ static shared_ptr fold_constant_gather(const shared_ptr(element::i64, Shape{5}, pattern::has_class()); size_t gather_axis = 1; - auto gather_op = make_shared(data_label, indices_label, gather_axis); + auto gather_v0 = make_shared(data_label, indices_label, gather_axis); + + auto axis_label = + make_shared(element::i64, Shape{1}, pattern::has_class()); + auto gather_v1 = make_shared(data_label, indices_label, axis_label); auto constant_gather_callback = [data_label, indices_label](pattern::Matcher& m) { NGRAPH_DEBUG << "In callback for constant_gather_callback against node = " @@ -98,7 +120,7 @@ void pass::ConstantFolding::construct_constant_gather() auto data = static_pointer_cast(pattern_map[data_label]); auto indices = static_pointer_cast(pattern_map[indices_label]); - auto gather = static_pointer_cast(m.get_match_root()); + auto gather = m.get_match_root(); NGRAPH_CHECK(revalidate_and_ensure_static(gather)); @@ -113,6 +135,9 @@ void pass::ConstantFolding::construct_constant_gather() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_gather_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_gather_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_gather(data, indices, gather); break; @@ -158,7 +183,12 @@ void pass::ConstantFolding::construct_constant_gather() return true; }; - auto gather_matcher = - make_shared(gather_op, "ConstantFolding.ConstantGather"); - this->add_matcher(gather_matcher, constant_gather_callback, PassProperty::CHANGE_DYNAMIC_STATE); + auto gather_matcher_v0 = + make_shared(gather_v0, "ConstantFolding.ConstantGatherV0"); + this->add_matcher( + gather_matcher_v0, constant_gather_callback, PassProperty::CHANGE_DYNAMIC_STATE); + auto gather_matcher_v1 = + make_shared(gather_v1, "ConstantFolding.ConstantGatherV1"); + this->add_matcher( + gather_matcher_v1, constant_gather_callback, PassProperty::CHANGE_DYNAMIC_STATE); } diff --git a/src/ngraph/pass/constant_folding_logical_reduction.cpp b/src/ngraph/pass/constant_folding_logical_reduction.cpp index 49f18bfcea8..187ad841825 100644 --- a/src/ngraph/pass/constant_folding_logical_reduction.cpp +++ b/src/ngraph/pass/constant_folding_logical_reduction.cpp @@ -17,12 +17,29 @@ #include "constant_folding.hpp" #include "ngraph/op/all.hpp" #include "ngraph/op/any.hpp" +#include "ngraph/op/reduce_logical_and.hpp" +#include "ngraph/op/reduce_logical_or.hpp" #include "ngraph/runtime/reference/all.hpp" #include "ngraph/runtime/reference/any.hpp" using namespace std; using namespace ngraph; +static Shape get_shape_no_keep_dims(const AxisSet& reduction_axes, const Shape& input_shape) +{ + Shape shape_no_keep_dims; + + for (size_t i = 0; i < input_shape.size(); i++) + { + if (reduction_axes.count(i) == 0) + { + shape_no_keep_dims.push_back(input_shape[i]); + } + } + + return shape_no_keep_dims; +} + static shared_ptr fold_constant_logical_reduction(shared_ptr constant, shared_ptr reduction_node) { @@ -44,6 +61,28 @@ static shared_ptr fold_constant_logical_reduction(shared_ptrget_shape(), any->get_reduction_axes()); } + else if (auto reduce_and = as_type_ptr<::ngraph::op::v1::ReduceLogicalAnd>(reduction_node)) + { + const auto reduction_axes = reduce_and->get_reduction_axes(); + const auto input_shape = reduce_and->get_input_shape(0); + + runtime::reference::all(constant->get_vector().data(), + out_vec.data(), + constant->get_output_shape(0), + get_shape_no_keep_dims(reduction_axes, input_shape), + reduction_axes); + } + else if (auto reduce_or = as_type_ptr<::ngraph::op::v1::ReduceLogicalOr>(reduction_node)) + { + const auto reduction_axes = reduce_or->get_reduction_axes(); + const auto input_shape = reduce_or->get_input_shape(0); + + runtime::reference::any(constant->get_vector().data(), + out_vec.data(), + constant->get_output_shape(0), + get_shape_no_keep_dims(reduction_axes, input_shape), + reduction_axes); + } else { NGRAPH_CHECK(false, @@ -64,7 +103,9 @@ void pass::ConstantFolding::construct_constant_logical_reduction() make_shared(element::i64, Shape{2}, pattern::has_class()); auto is_supported_reduction = [](std::shared_ptr n) { return (pattern::has_class<::ngraph::op::All>()(n) || - pattern::has_class<::ngraph::op::Any>()(n)); + pattern::has_class<::ngraph::op::Any>()(n) || + pattern::has_class<::ngraph::op::v1::ReduceLogicalAnd>()(n) || + pattern::has_class<::ngraph::op::v1::ReduceLogicalOr>()(n)); }; auto reduction = std::make_shared(element::i32, diff --git a/src/ngraph/pass/constant_folding_pad.cpp b/src/ngraph/pass/constant_folding_pad.cpp index c09a4cd2afe..4e5fd540d2c 100644 --- a/src/ngraph/pass/constant_folding_pad.cpp +++ b/src/ngraph/pass/constant_folding_pad.cpp @@ -100,6 +100,9 @@ void pass::ConstantFolding::construct_constant_pad() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_pad_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_pad_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_pad(constant_match, pad_match, func); break; diff --git a/src/ngraph/pass/constant_folding_range.cpp b/src/ngraph/pass/constant_folding_range.cpp index b9227d8f8a7..2df20a5cc48 100644 --- a/src/ngraph/pass/constant_folding_range.cpp +++ b/src/ngraph/pass/constant_folding_range.cpp @@ -68,6 +68,9 @@ void pass::ConstantFolding::construct_constant_range() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_range_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_range_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_range(start_node, step_node, range); break; diff --git a/src/ngraph/pass/constant_folding_reshape.cpp b/src/ngraph/pass/constant_folding_reshape.cpp index 391ff627f05..a9fc60005c5 100644 --- a/src/ngraph/pass/constant_folding_reshape.cpp +++ b/src/ngraph/pass/constant_folding_reshape.cpp @@ -87,6 +87,9 @@ void pass::ConstantFolding::construct_constant_reshape() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_reshape_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_reshape_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_reshape(constant_match, reshape_match, func); break; diff --git a/src/ngraph/pass/constant_folding_reverse.cpp b/src/ngraph/pass/constant_folding_reverse.cpp index cf7375c8490..7b909f69974 100644 --- a/src/ngraph/pass/constant_folding_reverse.cpp +++ b/src/ngraph/pass/constant_folding_reverse.cpp @@ -52,6 +52,9 @@ static shared_ptr fold_constant_reverse(shared_ptr c case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_convert"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_convert"); + break; case element::Type_t::boolean: return fold_constant_reverse_helper(constant, reversed_axes); case element::Type_t::bf16: diff --git a/src/ngraph/pass/constant_folding_select.cpp b/src/ngraph/pass/constant_folding_select.cpp index 6af1f773b36..361c9257bbf 100644 --- a/src/ngraph/pass/constant_folding_select.cpp +++ b/src/ngraph/pass/constant_folding_select.cpp @@ -72,6 +72,9 @@ void pass::ConstantFolding::construct_constant_select() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_select_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_select_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_select(selection_node, t_node, f_node, select); break; diff --git a/src/ngraph/pass/constant_folding_slice.cpp b/src/ngraph/pass/constant_folding_slice.cpp index 98cb8eebcfb..979e1bf2c3b 100644 --- a/src/ngraph/pass/constant_folding_slice.cpp +++ b/src/ngraph/pass/constant_folding_slice.cpp @@ -67,6 +67,9 @@ void pass::ConstantFolding::construct_constant_slice() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_slice"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_slice"); + break; case element::Type_t::boolean: replacement = fold_constant_slice(data_node, slice); break; diff --git a/src/ngraph/pass/constant_folding_squeeze.cpp b/src/ngraph/pass/constant_folding_squeeze.cpp index 79fc28efd28..8e661b22535 100644 --- a/src/ngraph/pass/constant_folding_squeeze.cpp +++ b/src/ngraph/pass/constant_folding_squeeze.cpp @@ -61,6 +61,9 @@ void pass::ConstantFolding::construct_constant_squeeze() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_squeeze_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_squeeze_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_squeeze(constant_match, squeeze_match); break; diff --git a/src/ngraph/pass/constant_folding_strided_slice.cpp b/src/ngraph/pass/constant_folding_strided_slice.cpp new file mode 100644 index 00000000000..3ccc5f3af33 --- /dev/null +++ b/src/ngraph/pass/constant_folding_strided_slice.cpp @@ -0,0 +1,196 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "constant_folding.hpp" +#include "ngraph/op/strided_slice.hpp" +#include "ngraph/runtime/reference/reshape.hpp" +#include "ngraph/runtime/reference/reverse.hpp" +#include "ngraph/runtime/reference/slice.hpp" +#include "ngraph/slice_plan.hpp" +#include "ngraph/type/element_type.hpp" + +using namespace std; +using namespace ngraph; + +template +shared_ptr fold_constant_strided_slice(shared_ptr data, + shared_ptr begin, + shared_ptr end, + shared_ptr strides, + shared_ptr slice) +{ + auto convert_mask_to_axis_set = [](const std::vector& mask) { + AxisSet axis_set{}; + for (size_t i = 0; i < static_cast(mask.size()); ++i) + { + if (mask[i] == 1) + { + axis_set.emplace(i); + } + } + return axis_set; + }; + + SlicePlan plan = make_slice_plan(data->get_shape(), + begin->get_vector(), + end->get_vector(), + strides->get_vector(), + convert_mask_to_axis_set(slice->get_begin_mask()), + convert_mask_to_axis_set(slice->get_end_mask()), + convert_mask_to_axis_set(slice->get_new_axis_mask()), + convert_mask_to_axis_set(slice->get_shrink_axis_mask()), + convert_mask_to_axis_set(slice->get_ellipsis_mask())); + + vector slice_out_vec(shape_size(plan.reshape_in_shape)); + runtime::reference::slice(data->get_data_ptr(), + slice_out_vec.data(), + data->get_shape(), + Coordinate(plan.begins.begin(), plan.begins.end()), + Coordinate(plan.ends.begin(), plan.ends.end()), + Strides(plan.strides.begin(), plan.strides.end()), + plan.reshape_in_shape); + + vector reshape_out_vec(shape_size(plan.reshape_out_shape)); + runtime::reference::reshape(slice_out_vec.data(), + reshape_out_vec.data(), + plan.reshape_in_shape, + get_default_order(plan.reshape_in_shape.size()), + plan.reshape_out_shape); + + vector reverse_out_vec(shape_size(plan.reshape_out_shape)); + runtime::reference::reverse(reshape_out_vec.data(), + reverse_out_vec.data(), + plan.reshape_out_shape, + plan.reshape_out_shape, + plan.reverse_axes); + + return make_shared( + data->get_element_type(), plan.reshape_out_shape, reverse_out_vec); +} + +void pass::ConstantFolding::construct_constant_strided_slice() +{ + auto data_label = make_shared( + element::f32, Shape{2, 3, 4}, pattern::has_class()); + auto begin_label = + make_shared(element::i64, Shape{3}, pattern::has_class()); + auto end_label = + make_shared(element::i64, Shape{3}, pattern::has_class()); + auto strides_label = + make_shared(element::i64, Shape{3}, pattern::has_class()); + auto strided_slice_op = make_shared(data_label, + begin_label, + end_label, + strides_label, + std::vector{}, + std::vector{}, + std::vector{}, + std::vector{}, + std::vector{}); + + auto constant_strided_slice_callback = + [data_label, begin_label, end_label, strides_label](pattern::Matcher& m) { + NGRAPH_DEBUG << "In callback for constant_strided_slice_callback against node = " + << m.get_match_root()->get_name(); + + auto pattern_map = m.get_pattern_map(); + + auto data_node = static_pointer_cast(pattern_map[data_label]); + auto begin_node = static_pointer_cast(pattern_map[begin_label]); + auto end_node = static_pointer_cast(pattern_map[end_label]); + auto strides_node = static_pointer_cast(pattern_map[strides_label]); + auto strided_slice = static_pointer_cast(m.get_match_root()); + + NGRAPH_CHECK(revalidate_and_ensure_static(strided_slice)); + + std::shared_ptr replacement; + + switch (strided_slice->get_output_element_type(0)) + { + case element::Type_t::undefined: + NGRAPH_CHECK(false, + "Encountered 'undefined' element type in fold_constant_strided_slice"); + break; + case element::Type_t::dynamic: + NGRAPH_CHECK(false, + "Encountered 'dynamic' element type in fold_constant_strided_slice"); + break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_strided_slice"); + break; + case element::Type_t::boolean: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::bf16: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::f16: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::f32: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::f64: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::i8: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::i16: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::i32: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::i64: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::u8: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::u16: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::u32: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + case element::Type_t::u64: + replacement = fold_constant_strided_slice( + data_node, begin_node, end_node, strides_node, strided_slice); + break; + } + + replace_node(m.get_match_root(), replacement); + return true; + }; + + auto strided_slice_matcher = + make_shared(strided_slice_op, "ConstantFolding.ConstantStridedSlice"); + this->add_matcher( + strided_slice_matcher, constant_strided_slice_callback, PassProperty::CHANGE_DYNAMIC_STATE); +} diff --git a/src/ngraph/pass/constant_folding_transpose.cpp b/src/ngraph/pass/constant_folding_transpose.cpp index 9752a06e79b..88fbbbd3792 100644 --- a/src/ngraph/pass/constant_folding_transpose.cpp +++ b/src/ngraph/pass/constant_folding_transpose.cpp @@ -75,6 +75,9 @@ void pass::ConstantFolding::construct_constant_transpose() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_transpose_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_transpose_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_transpose( constant_data_match, constant_perm_match, transpose_match); diff --git a/src/ngraph/pass/constant_folding_unary.cpp b/src/ngraph/pass/constant_folding_unary.cpp index 4d9791d725b..0c449b8ce4c 100644 --- a/src/ngraph/pass/constant_folding_unary.cpp +++ b/src/ngraph/pass/constant_folding_unary.cpp @@ -89,12 +89,17 @@ shared_ptr fold_constant_unary(shared_ptr constant, runtime::reference::floor( constant->get_data_ptr(), out_vec.data(), shape_size(out_shape)); } + else if (is_type(unary)) + { + runtime::reference::logical_not( + constant->get_data_ptr(), out_vec.data(), shape_size(out_shape)); + } else if (is_type(unary)) { runtime::reference::negate( constant->get_data_ptr(), out_vec.data(), shape_size(out_shape)); } - else if (is_type(unary)) + else if (is_type(unary)) { runtime::reference::logical_not( constant->get_data_ptr(), out_vec.data(), shape_size(out_shape)); @@ -169,6 +174,9 @@ void pass::ConstantFolding::construct_constant_unary() case element::Type_t::dynamic: NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_unary_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_unary_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_unary(constant_match, unary_match, func); break; diff --git a/src/ngraph/pass/constant_folding_unsqueeze.cpp b/src/ngraph/pass/constant_folding_unsqueeze.cpp index aab5c4b49dc..d895eeb41eb 100644 --- a/src/ngraph/pass/constant_folding_unsqueeze.cpp +++ b/src/ngraph/pass/constant_folding_unsqueeze.cpp @@ -62,6 +62,9 @@ void pass::ConstantFolding::construct_constant_unsqueeze() NGRAPH_CHECK(false, "Encountered 'dynamic' element type in constant_unsqueeze_callback"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in constant_unsqueeze_callback"); + break; case element::Type_t::boolean: replacement = fold_constant_unsqueeze(constant_match, unsqueeze_match); break; diff --git a/src/ngraph/pass/constant_to_broadcast.hpp b/src/ngraph/pass/constant_to_broadcast.hpp index c48fd57eee6..cddd117db50 100644 --- a/src/ngraph/pass/constant_to_broadcast.hpp +++ b/src/ngraph/pass/constant_to_broadcast.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::ConstantToBroadcast : public NodePass +class NGRAPH_API ngraph::pass::ConstantToBroadcast : public NodePass { public: bool run_on_node(std::shared_ptr) override; diff --git a/src/ngraph/pass/core_fusion.hpp b/src/ngraph/pass/core_fusion.hpp index e93b635b17c..da7945defbe 100644 --- a/src/ngraph/pass/core_fusion.hpp +++ b/src/ngraph/pass/core_fusion.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::CoreFusion : public ngraph::pass::GraphRewrite +class NGRAPH_API ngraph::pass::CoreFusion : public ngraph::pass::GraphRewrite { public: CoreFusion(FusionTypeMask fusions = FusionType::REGULAR_FUSIONS) diff --git a/src/ngraph/pass/cse.hpp b/src/ngraph/pass/cse.hpp index adf687465d7..76d55134ac2 100644 --- a/src/ngraph/pass/cse.hpp +++ b/src/ngraph/pass/cse.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::CommonSubexpressionElimination : public FunctionPass +class NGRAPH_API ngraph::pass::CommonSubexpressionElimination : public FunctionPass { public: CommonSubexpressionElimination() diff --git a/src/ngraph/pass/dump_sorted.hpp b/src/ngraph/pass/dump_sorted.hpp index 9d62abd272f..015c9d6e3d1 100644 --- a/src/ngraph/pass/dump_sorted.hpp +++ b/src/ngraph/pass/dump_sorted.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::DumpSorted : public ModulePass +class NGRAPH_API ngraph::pass::DumpSorted : public ModulePass { public: DumpSorted(const std::string& output_file); diff --git a/src/ngraph/pass/dyn_elimination.cpp b/src/ngraph/pass/dyn_elimination.cpp index f7b4d61330d..bb3b0668c0f 100644 --- a/src/ngraph/pass/dyn_elimination.cpp +++ b/src/ngraph/pass/dyn_elimination.cpp @@ -428,6 +428,7 @@ void pass::DynElimination::construct_range() case element::Type_t::u64: replacement = make_range_replacement(et, shape, start_arg, step_arg); break; + case element::Type_t::u1: case element::Type_t::undefined: case element::Type_t::dynamic: case element::Type_t::boolean: diff --git a/src/ngraph/pass/dyn_elimination.hpp b/src/ngraph/pass/dyn_elimination.hpp index b66e625610a..c8b8b6d62e1 100644 --- a/src/ngraph/pass/dyn_elimination.hpp +++ b/src/ngraph/pass/dyn_elimination.hpp @@ -23,7 +23,7 @@ namespace ngraph { namespace pass { - class DynElimination : public GraphRewrite + class NGRAPH_API DynElimination : public GraphRewrite { public: DynElimination(); diff --git a/src/ngraph/pass/fused_op_decomposition.hpp b/src/ngraph/pass/fused_op_decomposition.hpp index 69ca4eeeb0b..030a2408f43 100644 --- a/src/ngraph/pass/fused_op_decomposition.hpp +++ b/src/ngraph/pass/fused_op_decomposition.hpp @@ -25,7 +25,7 @@ namespace ngraph { namespace pass { - class FusedOpDecomposition : public NodePass + class NGRAPH_API FusedOpDecomposition : public NodePass { public: /// \brief Function signature type for callback used to check whether provided node diff --git a/src/ngraph/pass/get_output_element_elimination.hpp b/src/ngraph/pass/get_output_element_elimination.hpp index be54f351c4e..2e05194de01 100644 --- a/src/ngraph/pass/get_output_element_elimination.hpp +++ b/src/ngraph/pass/get_output_element_elimination.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::GetOutputElementElimination : public NodePass +class NGRAPH_API ngraph::pass::GetOutputElementElimination : public NodePass { public: bool run_on_node(std::shared_ptr node) override; diff --git a/src/ngraph/pass/graph_rewrite.hpp b/src/ngraph/pass/graph_rewrite.hpp index 898795202e2..3a0232eee0f 100644 --- a/src/ngraph/pass/graph_rewrite.hpp +++ b/src/ngraph/pass/graph_rewrite.hpp @@ -46,7 +46,7 @@ namespace ngraph /// Patterns can be added by using \sa add_matcher /// Callbacks should use \sa replace_node to transform matched sub graphs -class ngraph::pass::GraphRewrite : public FunctionPass +class NGRAPH_API ngraph::pass::GraphRewrite : public FunctionPass { public: GraphRewrite() @@ -82,7 +82,7 @@ class ngraph::pass::GraphRewrite : public FunctionPass std::vector m_matchers; }; -class ngraph::pass::RecurrentGraphRewrite : public FunctionPass +class NGRAPH_API ngraph::pass::RecurrentGraphRewrite : public FunctionPass { public: RecurrentGraphRewrite(size_t num_iters = 10) diff --git a/src/ngraph/pass/implicit_broadcast_elimination.hpp b/src/ngraph/pass/implicit_broadcast_elimination.hpp index 10515727477..f51bbed90ad 100644 --- a/src/ngraph/pass/implicit_broadcast_elimination.hpp +++ b/src/ngraph/pass/implicit_broadcast_elimination.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::ImplicitBroadcastElimination : public ngraph::pass::NodePass +class NGRAPH_API ngraph::pass::ImplicitBroadcastElimination : public ngraph::pass::NodePass { public: bool run_on_node(std::shared_ptr node) override; diff --git a/src/ngraph/pass/like_replacement.hpp b/src/ngraph/pass/like_replacement.hpp index 021cca6c667..08598ad6486 100644 --- a/src/ngraph/pass/like_replacement.hpp +++ b/src/ngraph/pass/like_replacement.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace pass { - class LikeReplacement : public FunctionPass + class NGRAPH_API LikeReplacement : public FunctionPass { public: bool run_on_function(std::shared_ptr function) override; diff --git a/src/ngraph/pass/liveness.hpp b/src/ngraph/pass/liveness.hpp index 63e813da2cb..4cc81b14c9a 100644 --- a/src/ngraph/pass/liveness.hpp +++ b/src/ngraph/pass/liveness.hpp @@ -27,7 +27,7 @@ namespace ngraph } } -class ngraph::pass::Liveness : public FunctionPass +class NGRAPH_API ngraph::pass::Liveness : public FunctionPass { public: bool run_on_function(std::shared_ptr) override; diff --git a/src/ngraph/pass/manager.hpp b/src/ngraph/pass/manager.hpp index acfa7351ab4..bb5c7e2cb0c 100644 --- a/src/ngraph/pass/manager.hpp +++ b/src/ngraph/pass/manager.hpp @@ -35,7 +35,7 @@ namespace ngraph } } -class ngraph::pass::Manager +class NGRAPH_API ngraph::pass::Manager { public: Manager(); diff --git a/src/ngraph/pass/memory_visualize.hpp b/src/ngraph/pass/memory_visualize.hpp index 128b8f51b8f..771502ae88d 100644 --- a/src/ngraph/pass/memory_visualize.hpp +++ b/src/ngraph/pass/memory_visualize.hpp @@ -30,7 +30,7 @@ namespace ngraph } } -class ngraph::pass::MemoryVisualize : public ModulePass +class NGRAPH_API ngraph::pass::MemoryVisualize : public ModulePass { public: MemoryVisualize(const std::string& filename); diff --git a/src/ngraph/pass/nop_elimination.hpp b/src/ngraph/pass/nop_elimination.hpp index 66f6332afb3..b9c71bda297 100644 --- a/src/ngraph/pass/nop_elimination.hpp +++ b/src/ngraph/pass/nop_elimination.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace pass { - class NopElimination : public FunctionPass + class NGRAPH_API NopElimination : public FunctionPass { public: NopElimination() { set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); } diff --git a/src/ngraph/pass/opset0_downgrade.cpp b/src/ngraph/pass/opset0_downgrade.cpp index 2bcb28a7a93..da17a92de38 100644 --- a/src/ngraph/pass/opset0_downgrade.cpp +++ b/src/ngraph/pass/opset0_downgrade.cpp @@ -14,137 +14,52 @@ // limitations under the License. //***************************************************************************** +#include #include +#include +#include #include "ngraph/graph_util.hpp" #include "ngraph/node.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/experimental/dyn_reshape.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/not.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/reduce_prod.hpp" -#include "ngraph/op/reduce_sum.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/strided_slice.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/op/util/broadcasting.hpp" +#include "ngraph/ops.hpp" #include "ngraph/pass/opset0_downgrade.hpp" #include "ngraph/slice_plan.hpp" - -#include +#include "ngraph/type.hpp" using namespace std; using namespace ngraph; -#define NGRAPH_OP(a, b) a, -enum class OP_TYPEID -{ -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" -}; -#undef NGRAPH_OP - -#define NGRAPH_OP(a, b) {#a, OP_TYPEID::a}, -static unordered_map typeid_map{ -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" -}; -#undef NGRAPH_OP - -static OP_TYPEID get_typeid(shared_ptr node) +namespace { - OP_TYPEID type_id; - auto it = typeid_map.find(node->description()); - if (it != typeid_map.end()) - { - type_id = it->second; - } - else + template + void op_cast_binary_elementwise_node(const shared_ptr& node) { - throw unsupported_op("Unsupported op '" + node->description() + "'"); + const auto input_arg0 = node->input_value(0); + const auto input_arg1 = node->input_value(1); + const auto autob = node->get_autob(); + auto replacement_node = make_shared(input_arg0, input_arg1, autob); + replace_node(node, replacement_node); } - return type_id; -} -// END mapping to OP_TYPEID - -template -void downgrade_binary_elementwise_node(const shared_ptr& node) -{ - const auto tmp = as_type_ptr(node); - const auto input_arg0 = node->input(0).get_source_output(); - const auto input_arg1 = node->input(1).get_source_output(); - const auto autob = tmp->get_autob(); - auto replacement_node = make_shared(input_arg0, input_arg1, autob); - replace_node(node, replacement_node); -} -bool pass::Opset0Downgrade::run_on_node(shared_ptr node) -{ - bool modified = false; - - size_t op_version = node->get_version(); - - if (op_version == 0) + // Default is that we didn nothing + bool op_cast(shared_ptr node) { return false; } + bool op_cast(shared_ptr node) { - return modified; + op_cast_binary_elementwise_node(node); + return true; } - NGRAPH_CHECK(op_version == 1, - "Op version 1 transformation pass failed for ", - *node, - ", only op version 1 operations expected. Op version ", - op_version, - " found."); - -// Not all enumeration values explicitly handled in switch -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - switch (get_typeid(node)) + bool op_cast(shared_ptr node) { - case OP_TYPEID::Add: - { - downgrade_binary_elementwise_node(node); - modified = true; - break; - } - case OP_TYPEID::AvgPool: - { - const auto tmp = as_type_ptr(node); - - auto const input_arg = node->input(0).get_source_output(); - const auto ceil_mode = static_cast(tmp->get_rounding_type()); - const auto include_padding_in_avg_computation = !tmp->get_exclude_pad(); - const auto pad_type = tmp->get_auto_pad(); - const auto padding_below = tmp->get_pads_begin(); - const auto padding_above = tmp->get_pads_end(); - const auto window_movement_strides = tmp->get_strides(); - const auto window_shape = tmp->get_kernel(); + auto const input_arg = node->input_value(0); + const auto ceil_mode = static_cast(node->get_rounding_type()); + const auto include_padding_in_avg_computation = !node->get_exclude_pad(); + const auto pad_type = node->get_auto_pad(); + const auto padding_below = node->get_pads_begin(); + const auto padding_above = node->get_pads_end(); + const auto window_movement_strides = node->get_strides(); + const auto window_shape = node->get_kernel(); auto replacement_node = make_shared(input_arg, window_shape, @@ -155,22 +70,21 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) pad_type, ceil_mode); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::AvgPoolBackprop: + + bool op_cast(shared_ptr node) { - const auto tmp = as_type_ptr(node); NGRAPH_CHECK(node->input_value(1).get_node_shared_ptr()->is_constant()); const auto forward_arg_shape = static_pointer_cast(node->input_value(1).get_node_shared_ptr()) ->get_shape_val(); - const auto delta = node->input(0).get_source_output(); - const auto include_padding_in_avg_computation = !tmp->get_exclude_pad(); - const auto padding_below = tmp->get_pads_begin(); - const auto padding_above = tmp->get_pads_end(); - const auto window_movement_strides = tmp->get_strides(); - const auto window_shape = tmp->get_kernel(); + const auto delta = node->input_value(0); + const auto include_padding_in_avg_computation = !node->get_exclude_pad(); + const auto padding_below = node->get_pads_begin(); + const auto padding_above = node->get_pads_end(); + const auto window_movement_strides = node->get_strides(); + const auto window_shape = node->get_kernel(); auto replacement_node = make_shared(forward_arg_shape, @@ -181,30 +95,28 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) padding_above, include_padding_in_avg_computation); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Broadcast: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - const auto arg = node->input(0).get_source_output(); + auto arg = node->input_value(0); NGRAPH_CHECK(node->input_value(1).get_node_shared_ptr()->is_constant()); auto target_shape = static_pointer_cast(node->input_value(1).get_node_shared_ptr()) ->get_shape_val(); - NGRAPH_CHECK(tmp->get_broadcast_axes().first); + NGRAPH_CHECK(node->get_broadcast_axes().first); auto replacement_node = - make_shared(arg, target_shape, tmp->get_broadcast_axes().second); + make_shared(arg, target_shape, node->get_broadcast_axes().second); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Convolution: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - const auto data_arg = node->input(0).get_source_output(); - const auto filters_arg = node->input(1).get_source_output(); + const auto data_arg = node->input_value(0); + const auto filters_arg = node->input_value(1); const PartialShape& data_arg_pshape = node->get_input_partial_shape(0); NGRAPH_CHECK(data_arg_pshape.rank().is_static(), "Unable to convert Convolution:v1 to Convolution:v0 if data argument " @@ -213,53 +125,63 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) const size_t num_spatial_dims = static_cast(data_arg_pshape.rank()) - 2; auto replacement_node = make_shared(data_arg, filters_arg, - tmp->get_strides(), - tmp->get_dilations(), - tmp->get_pads_begin(), - tmp->get_pads_end(), + node->get_strides(), + node->get_dilations(), + node->get_pads_begin(), + node->get_pads_end(), Strides(num_spatial_dims, 1), - tmp->get_auto_pad()); + node->get_auto_pad()); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::ConvolutionBackpropData: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - NGRAPH_CHECK(node->input_value(2).get_node_shared_ptr()->is_constant()); - auto data_batch_shape = - static_pointer_cast(node->input_value(2).get_node_shared_ptr()) - ->get_shape_val(); - const auto filters_arg = node->input(0).get_source_output(); - const auto delta_arg = node->input(1).get_source_output(); + auto output_shape = as_type_ptr(node->input_value(2).get_node_shared_ptr()); + const auto data_arg = node->input(0).get_source_output(); + const auto filters_arg = node->input(1).get_source_output(); const PartialShape& delta_arg_pshape = node->get_input_partial_shape(1); NGRAPH_CHECK(delta_arg_pshape.rank().is_static(), "Unable to convert ConvolutionBackpropData:v1 to ConvolutionBackpropData:v0 " "if delta argument rank is dynamic. Node: ", *node); + NGRAPH_CHECK(output_shape, + "Unable to convert ConvolutionBackpropData:v1 to ConvolutionBackpropData:v0 " + "if output_shape is not constant. Node: ", + *node); const size_t num_spatial_dims = static_cast(delta_arg_pshape.rank()) - 2; + + auto output_padding = node->get_output_padding(); + + bool is_op_valid = all_of( + output_padding.begin(), output_padding.end(), [](size_t value) { return value == 0; }); + + NGRAPH_CHECK(is_op_valid, + "Unable to convert ConvolutionBackpropData:v1 to ConvolutionBackpropData:v0 " + "with output padding other than `0`. Node: ", + *node); + auto replacement_node = - make_shared(data_batch_shape, + make_shared(output_shape->get_shape_val(), filters_arg, - delta_arg, - tmp->get_strides(), - tmp->get_dilations(), - tmp->get_pads_begin(), - tmp->get_pads_end(), + data_arg, + node->get_strides(), + node->get_dilations(), + node->get_pads_begin(), + node->get_pads_end(), Strides(num_spatial_dims, 1)); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::ConvolutionBackpropFilters: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); NGRAPH_CHECK(node->input_value(2).get_node_shared_ptr()->is_constant()); auto filters_shape = static_pointer_cast(node->input_value(2).get_node_shared_ptr()) ->get_shape_val(); - const auto data_arg = node->input(0).get_source_output(); - const auto delta_arg = node->input(1).get_source_output(); + const auto data_arg = node->input_value(0); + const auto delta_arg = node->input_value(1); const PartialShape& data_arg_pshape = node->get_input_partial_shape(0); NGRAPH_CHECK(data_arg_pshape.rank().is_static(), "Unable to convert ConvolutionBackpropFilters:v1 to " @@ -270,127 +192,121 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) make_shared(data_arg, filters_shape, delta_arg, - tmp->get_strides(), - tmp->get_dilations(), - tmp->get_pads_begin(), - tmp->get_pads_end(), + node->get_strides(), + node->get_dilations(), + node->get_pads_begin(), + node->get_pads_end(), Strides(num_spatial_dims, 1)); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Divide: + + bool op_cast(shared_ptr node) { - const auto tmp = as_type_ptr(node); - const auto input_arg0 = node->input(0).get_source_output(); - const auto input_arg1 = node->input(1).get_source_output(); - const auto autob = tmp->get_autob(); - const bool pydiv = tmp->is_pythondiv(); + const auto input_arg0 = node->input_value(0); + const auto input_arg1 = node->input_value(1); + const auto autob = node->get_autob(); + const bool pydiv = node->is_pythondiv(); auto replacement_node = make_shared(input_arg0, input_arg1, pydiv, autob); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::DynReshape: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - auto replacement_node = make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - tmp->get_zero_flag()); + auto replacement_node = make_shared( + node->input_value(0), node->input_value(1), node->get_special_zero()); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Equal: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::GenerateMask: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); NGRAPH_CHECK(node->input_value(1).get_node_shared_ptr()->is_constant()); auto mask_shape = static_pointer_cast(node->input_value(1).get_node_shared_ptr()) ->get_shape_val(); - auto seed = tmp->get_seed(); - auto use_seed = tmp->get_use_seed(); - auto probability = tmp->get_probability(); - auto et = tmp->get_element_type(); + auto seed = node->get_seed(); + auto use_seed = node->get_use_seed(); + auto probability = node->get_probability(); + auto et = node->get_element_type(); auto replacement_node = make_shared( - node->input(0).get_source_output(), mask_shape, et, seed, probability, use_seed); + node->input_value(0), mask_shape, et, seed, probability, use_seed); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Greater: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::GreaterEq: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Less: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::LessEqual: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::LogicalAnd: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::LogicalNot: + + bool op_cast(shared_ptr node) { - replace_node(node, make_shared(node->input(0).get_source_output())); - modified = true; - break; + replace_node(node, make_shared(node->input_value(0))); + return true; } - case OP_TYPEID::LogicalOr: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::LogicalXor: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Maximum: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::MaxPool: - { - auto tmp = as_type_ptr(node); - auto const input_arg = node->input(0).get_source_output(); - auto ceil_mode = static_cast(tmp->get_rounding_type()); - auto pad_type = tmp->get_auto_pad(); - auto padding_below = tmp->get_pads_begin(); - auto padding_above = tmp->get_pads_end(); - auto window_movement_strides = tmp->get_strides(); - auto window_shape = tmp->get_kernel(); + bool op_cast(shared_ptr node) + { + auto const input_arg = node->input_value(0); + auto ceil_mode = static_cast(node->get_rounding_type()); + auto pad_type = node->get_auto_pad(); + auto padding_below = node->get_pads_begin(); + auto padding_above = node->get_pads_end(); + auto window_movement_strides = node->get_strides(); + auto window_shape = node->get_kernel(); auto replacement_node = make_shared(input_arg, window_shape, @@ -400,25 +316,23 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) pad_type, ceil_mode); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::MaxPoolBackprop: - { - const auto tmp = as_type_ptr(node); - const auto padding_below = tmp->get_pads_begin(); - const auto padding_above = tmp->get_pads_end(); - const auto window_movement_strides = tmp->get_strides(); - const auto window_shape = tmp->get_kernel(); + bool op_cast(shared_ptr node) + { + const auto padding_below = node->get_pads_begin(); + const auto padding_above = node->get_pads_end(); + const auto window_movement_strides = node->get_strides(); + const auto window_shape = node->get_kernel(); - const auto arg_forward = node->input(0).get_source_output(); - const auto delta = node->input(1).get_source_output(); + const auto arg_forward = node->input_value(0); + const auto delta = node->input_value(1); shared_ptr replacement_node; if (node->get_inputs().size() == 3) { - const auto result_forward = node->input(2).get_source_output(); + const auto result_forward = node->input_value(2); replacement_node = make_shared(arg_forward, delta, result_forward, @@ -437,53 +351,82 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) padding_above); } replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Minimum: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Multiply: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::NotEqual: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Pad: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - const auto pad_arg = node->input(0).get_source_output(); - const auto pad_value = node->input(3).get_source_output(); + const auto indices = node->input_value(0).get_node_shared_ptr(); + const auto depth = node->input_value(1).get_node_shared_ptr(); + auto on_value = node->input_value(2).get_node_shared_ptr(); + auto off_value = node->input_value(3).get_node_shared_ptr(); + const auto axis = node->get_axis(); + + NGRAPH_CHECK(depth->is_constant(), "depth input must be constant", *node); + const auto const_depth = as_type_ptr(depth); + std::int64_t depth_value = const_depth->get_vector()[0]; + + const auto indices_shape = node->get_input_partial_shape(0); + NGRAPH_CHECK(indices_shape.is_static(), "indices shape must be static", *node); + auto output_shape = indices_shape.to_shape(); + output_shape.insert(output_shape.begin() + axis, depth_value); + + auto one_hot = std::make_shared( + std::make_shared(indices, output_shape, axis), + on_value->get_element_type()); + + auto broadcasted_values = op::numpy_style_broadcast({one_hot, on_value, off_value}); + on_value = broadcasted_values[1]; + off_value = broadcasted_values[2]; + + auto replacement_node = one_hot * (on_value - off_value) + off_value; + + replace_node(node, replacement_node); + return true; + } + + bool op_cast(shared_ptr node) + { + const auto pad_arg = node->input_value(0); + const auto pad_value = node->input_value(3); auto replacement_node = make_shared( - pad_arg, pad_value, tmp->get_pads_begin(), tmp->get_pads_end(), tmp->get_pad_mode()); + pad_arg, pad_value, node->get_pads_begin(), node->get_pads_end(), node->get_pad_mode()); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Power: + + bool op_cast(shared_ptr node) { - downgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Product: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - auto replacement_node = make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output()); - if (tmp->get_keep_dims()) + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1)); + if (node->get_keep_dims()) { - NGRAPH_CHECK(tmp->reduction_axes_constant(), + NGRAPH_CHECK(node->reduction_axes_constant(), "Unable to convert ReduceProd:v1 to Product:v0 " "if reduction axes are not constant (for keep_dims=true). Node: ", *node); @@ -494,7 +437,7 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) *node); const auto output_shape = output_pshape.to_shape(); auto reshaped_output_shape = output_shape; - for (const auto& axis : tmp->get_reduction_axes()) + for (const auto& axis : node->get_reduction_axes()) { reshaped_output_shape.insert(reshaped_output_shape.begin() + axis, 1); } @@ -507,20 +450,19 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) { replace_node(node, replacement_node); } - modified = true; - break; + return true; } - case OP_TYPEID::Reverse: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - auto axes_node = tmp->input_value(1).get_node_shared_ptr(); + auto axes_node = node->input_value(1).get_node_shared_ptr(); NGRAPH_CHECK(axes_node->is_constant(), "Unable to convert Reverse:v1 to Reverse:v0 " "if reduction axes are not constant. Node: ", *node); const auto axes_node_const = as_type_ptr(axes_node); AxisSet axes{}; - if (tmp->get_mode() == op::v1::Reverse::Mode::INDEX) + if (node->get_mode() == op::v1::Reverse::Mode::INDEX) { axes = axes_node_const->get_axis_vector_val(); } @@ -535,14 +477,13 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) } } } - auto replacement_node = - make_shared(node->input(0).get_source_output(), axes); + auto replacement_node = make_shared(node->input_value(0), axes); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Slice: + + bool op_cast(shared_ptr node) { auto convert_mask_to_axes = [](const std::vector& mask) { AxisSet axes{}; @@ -575,17 +516,15 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) "if begin, end or strides are not constant. Node: ", *node); - const auto tmp = as_type_ptr(node); - SlicePlan p = make_slice_plan(input_data_pshape.to_shape(), begin_const->get_vector(), end_const->get_vector(), strides->get_vector(), - convert_mask_to_axes(tmp->get_begin_mask()), - convert_mask_to_axes(tmp->get_end_mask()), - convert_mask_to_axes(tmp->get_new_axis_mask()), - convert_mask_to_axes(tmp->get_shrink_axis_mask()), - convert_mask_to_axes(tmp->get_ellipsis_mask())); + convert_mask_to_axes(node->get_begin_mask()), + convert_mask_to_axes(node->get_end_mask()), + convert_mask_to_axes(node->get_new_axis_mask()), + convert_mask_to_axes(node->get_shrink_axis_mask()), + convert_mask_to_axes(node->get_ellipsis_mask())); shared_ptr replacement_node = make_shared(input_data, @@ -607,16 +546,34 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) } replace_node(node, replacement_node); - break; + return true; + } + + bool op_cast(shared_ptr node) + { + auto axis = node->get_axis(); + auto data = node->input(0); + auto data_shape = data.get_shape(); + std::vector axes(data_shape.size() - axis); + std::iota(std::begin(axes), std::end(axes), axis); + auto replacement_node = make_shared(node->input_value(0), axes); + replace_node(node, replacement_node); + return true; + } + + bool op_cast(shared_ptr node) + { + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Sum: + + bool op_cast(shared_ptr node) { - auto tmp = as_type_ptr(node); - auto replacement_node = make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output()); - if (tmp->get_keep_dims()) + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1)); + if (node->get_keep_dims()) { - NGRAPH_CHECK(tmp->reduction_axes_constant(), + NGRAPH_CHECK(node->reduction_axes_constant(), "Unable to convert ReduceSum:v1 to Sum:v0 " "if reduction axes are not constant (for keep_dims=true). Node: ", *node); @@ -627,7 +584,7 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) *node); const auto output_shape = output_pshape.to_shape(); auto reshaped_output_shape = output_shape; - for (const auto& axis : tmp->get_reduction_axes()) + for (const auto& axis : node->get_reduction_axes()) { reshaped_output_shape.insert(reshaped_output_shape.begin() + axis, 1); } @@ -640,21 +597,20 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) { replace_node(node, replacement_node); } - modified = true; - break; + return true; } - case OP_TYPEID::TopK: + + bool op_cast(shared_ptr node) { - const auto tmp = as_type_ptr(node); - const auto axis = tmp->get_axis(); - const auto sort_type = tmp->get_sort_type(); - const auto index_elem_type = tmp->get_index_element_type(); + const auto axis = node->get_axis(); + const auto sort_type = node->get_sort_type(); + const auto index_elem_type = node->get_index_element_type(); - bool comnpute_max; - switch (tmp->get_mode()) + bool compute_max; + switch (node->get_mode()) { - case op::v1::TopK::Mode::MAX: comnpute_max = true; break; - case op::v1::TopK::Mode::MIN: comnpute_max = false; break; + case op::v1::TopK::Mode::MAX: compute_max = true; break; + case op::v1::TopK::Mode::MIN: compute_max = false; break; default: break; } @@ -662,18 +618,43 @@ bool pass::Opset0Downgrade::run_on_node(shared_ptr node) const auto k_node = node->input_value(1); auto replacement_node = make_shared( - arg_node, k_node, axis, index_elem_type, comnpute_max, sort_type); + arg_node, k_node, axis, index_elem_type, compute_max, sort_type); // values output will be 0, indices 1 vector output_order{1, 0}; replace_node(node, replacement_node, output_order); - modified = true; - break; + return true; } - default: break; + + using DispatchMap = map node)>>; + + template + bool op_cast_thunk(shared_ptr node) + { + return op_cast(as_type_ptr(node)); + } + + DispatchMap& get_dispatch_map() + { + static DispatchMap dispatch_map{ +#define NGRAPH_OP(NAME, NAMESPACE) {NAMESPACE::NAME::type_info, op_cast_thunk}, +#include "ngraph/opsets/opset1_tbl.hpp" + NGRAPH_OP(AvgPoolBackprop, op::v1) NGRAPH_OP(ConvolutionBackpropFilters, op::v1) + NGRAPH_OP(GenerateMask, op::v1) NGRAPH_OP(MaxPoolBackprop, op::v1) +#undef NGRAPH_OP + }; + return dispatch_map; + } +} + +bool pass::Opset0Downgrade::run_on_node(shared_ptr node) +{ + bool modified = false; + auto& dispatch_map = get_dispatch_map(); + auto it = dispatch_map.find(node->get_type_info()); + if (it != dispatch_map.end()) + { + modified = it->second(node); } -#if defined(__clang__) -#pragma clang diagnostic pop -#endif return modified; } diff --git a/src/ngraph/pass/opset0_downgrade.hpp b/src/ngraph/pass/opset0_downgrade.hpp index 271989b3f63..c9d8e7a50d7 100644 --- a/src/ngraph/pass/opset0_downgrade.hpp +++ b/src/ngraph/pass/opset0_downgrade.hpp @@ -22,15 +22,15 @@ namespace ngraph { namespace pass { - class Opset0Downgrade : public NodePass + class NGRAPH_API Opset0Downgrade : public NodePass { public: /// - /// \brief Constructor for the Opset 1 downgrade transformation pass. + /// \brief Constructor for the Opv1 downgrade transformation pass. /// /// \details This transformation pass iterates over all nodes in a graph - /// and updates opset version 1 ops to their opset version 0 equivalents. - /// All ops in the final graph have opset version 0. + /// and updates version 1 ops to their version 0 equivalents. + /// All ops in the final graph have op version 0. Opset0Downgrade() = default; bool run_on_node(std::shared_ptr node) override; }; diff --git a/src/ngraph/pass/opset1_upgrade.cpp b/src/ngraph/pass/opset1_upgrade.cpp index 52dd59a7b2e..e76d8330cec 100644 --- a/src/ngraph/pass/opset1_upgrade.cpp +++ b/src/ngraph/pass/opset1_upgrade.cpp @@ -13,181 +13,102 @@ // See the License for the specific language governing permissions and // limitations under the License. //***************************************************************************** -#include "ngraph/pass/opset1_upgrade.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/experimental/dyn_reshape.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/not.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/reduce_prod.hpp" -#include "ngraph/op/reduce_sum.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/strided_slice.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/xor.hpp" +#include #include #include +#include "ngraph/graph_util.hpp" +#include "ngraph/ops.hpp" +#include "ngraph/pass/opset1_upgrade.hpp" + using namespace std; using namespace ngraph; -#define NGRAPH_OP(a, b) a, -enum class OP_TYPEID -{ -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" -}; -#undef NGRAPH_OP - -#define NGRAPH_OP(a, b) {#a, OP_TYPEID::a}, -static unordered_map typeid_map{ -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" -}; -#undef NGRAPH_OP - -static OP_TYPEID get_typeid(shared_ptr node) +namespace { - OP_TYPEID type_id; - auto it = typeid_map.find(node->description()); - if (it != typeid_map.end()) - { - type_id = it->second; - } - else + template + void op_cast_binary_elementwise_node(const shared_ptr& node) { - throw unsupported_op("Unsupported op '" + node->description() + "'"); + const auto autob = node->get_autob(); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), autob); + replace_node(node, replacement_node); } - return type_id; -} -// END mapping to OP_TYPEID -template -void upgrade_binary_elementwise_node(const shared_ptr& node) -{ - const auto tmp = dynamic_cast(node.get()); - const auto autob = tmp->get_autob(); - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), autob); - replace_node(node, replacement_node); -} - -bool pass::Opset1Upgrade::run_on_node(shared_ptr node) -{ - bool modified = false; - - size_t op_version = node->get_version(); - - if (op_version == 1) + // Default is that we didn nothing + bool op_cast(shared_ptr node) { return false; } + bool op_cast(shared_ptr node) { - return modified; + op_cast_binary_elementwise_node(node); + return true; } - NGRAPH_CHECK(op_version == 0, - "Op version 1 transformation pass failed for ", - *node, - ", only op version 0 operations expected. Op version ", - op_version, - " found."); - -// Not all enumeration values explicitly handled in switch -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wswitch-enum" -#endif - switch (get_typeid(node)) - { - case OP_TYPEID::Add: - { - upgrade_binary_elementwise_node(node); - modified = true; - break; - } - case OP_TYPEID::And: + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::AvgPool: - { - auto tmp = dynamic_cast(node.get()); - auto rounding_type = static_cast(tmp->get_ceil_mode()); - auto exclude_pad = !tmp->get_include_padding_in_avg_computation(); - auto auto_pad = tmp->get_pad_type(); - auto pads_begin = tmp->get_padding_below(); - auto pads_end = tmp->get_padding_above(); - auto strides = tmp->get_window_movement_strides(); - auto kernel = tmp->get_window_shape(); + bool op_cast(shared_ptr node) + { + auto rounding_mode = + node->get_ceil_mode() ? op::RoundingType::CEIL : op::RoundingType::FLOOR; + auto exclude_pad = !node->get_include_padding_in_avg_computation(); + auto auto_pad = node->get_pad_type(); + auto pads_begin = node->get_padding_below(); + auto pads_end = node->get_padding_above(); + auto strides = node->get_window_movement_strides(); + auto kernel = node->get_window_shape(); - auto replacement_node = make_shared(node->input(0).get_source_output(), + auto replacement_node = make_shared(node->input_value(0), strides, pads_begin, pads_end, kernel, exclude_pad, - rounding_type, + rounding_mode, auto_pad); +#if defined(__clang__) && __clang_major__ == 3 + // There are some really by clang 3.9 bugs + if (node->get_ceil_mode()) + { + replacement_node->set_rounding_type(op::RoundingType::CEIL); + } + else + { + replacement_node->set_rounding_type(op::RoundingType::FLOOR); + } +#endif replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::AvgPoolBackprop: - { - auto tmp = dynamic_cast(node.get()); - auto exclude_pad = !tmp->get_include_padding_in_avg_computation(); - auto pads_begin = tmp->get_padding_below(); - auto pads_end = tmp->get_padding_above(); - auto strides = tmp->get_window_movement_strides(); - auto kernel = tmp->get_window_shape(); + bool op_cast(shared_ptr node) + { + auto exclude_pad = !node->get_include_padding_in_avg_computation(); + auto pads_begin = node->get_padding_below(); + auto pads_end = node->get_padding_above(); + auto strides = node->get_window_movement_strides(); + auto kernel = node->get_window_shape(); - auto replacement_node = - make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - strides, - pads_begin, - pads_end, - kernel, - exclude_pad); + auto replacement_node = make_shared(node->input_value(0), + node->input_value(1), + strides, + pads_begin, + pads_end, + kernel, + exclude_pad); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Broadcast: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - auto result_shape = tmp->get_broadcast_shape(); + auto result_shape = node->get_broadcast_shape(); auto result_shape_node = op::Constant::create(element::i64, Shape{result_shape.size()}, result_shape); - auto broadcast_axes = tmp->get_broadcast_axes(); + auto broadcast_axes = node->get_broadcast_axes(); // Flip broadcast_axes to get axes_mapping std::vector axes_mapping(result_shape.size()); @@ -199,22 +120,21 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) auto axes_mapping_node = op::Constant::create(element::i64, Shape{axes_mapping.size()}, axes_mapping); - auto replacement_node = make_shared(node->input(0).get_source_output(), - result_shape_node->output(0), - axes_mapping_node->output(0)); + auto replacement_node = make_shared( + node->input_value(0), result_shape_node->output(0), axes_mapping_node->output(0)); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Convolution: + + bool op_cast(shared_ptr node) { return false; } + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - auto strides = tmp->get_window_movement_strides(); - auto dilations = tmp->get_window_dilation_strides(); - auto pads_begin = tmp->get_padding_below(); - auto pads_end = tmp->get_padding_above(); - auto data_dilation_strides = tmp->get_data_dilation_strides(); - auto auto_pad = tmp->get_pad_type(); + auto strides = node->get_window_movement_strides(); + auto dilations = node->get_window_dilation_strides(); + auto pads_begin = node->get_padding_below(); + auto pads_end = node->get_padding_above(); + auto data_dilation_strides = node->get_data_dilation_strides(); + auto auto_pad = node->get_pad_type(); bool is_dds_valid = true; for (auto value : data_dilation_strides) @@ -227,26 +147,25 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) "other than `1`. Node: ", *node); - auto replacement_node = make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), + auto replacement_node = make_shared(node->input_value(0), + node->input_value(1), strides, pads_begin, pads_end, dilations, auto_pad); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::ConvolutionBackpropData: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - auto data_batch_shape = tmp->get_data_batch_shape(); - auto strides = tmp->get_window_movement_strides_forward(); - auto dilations = tmp->get_window_dilation_strides_forward(); - auto pads_begin = tmp->get_padding_below_forward(); - auto pads_end = tmp->get_padding_above_forward(); - auto data_dilation_strides = tmp->get_data_dilation_strides_forward(); + auto data_batch_shape = node->get_data_batch_shape(); + auto strides = node->get_window_movement_strides_forward(); + auto dilations = node->get_window_dilation_strides_forward(); + auto pads_begin = node->get_padding_below_forward(); + auto pads_end = node->get_padding_above_forward(); + auto data_dilation_strides = node->get_data_dilation_strides_forward(); bool is_dds_valid = true; for (auto value : data_dilation_strides) @@ -260,33 +179,30 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) "other than `1`. Node: ", *node); - auto replacement_node = - make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - node->input(2).get_source_output(), - strides, - dilations, - pads_begin, - pads_end); + auto replacement_node = make_shared( + node->input_value(1), // data + node->input_value(0), // filters + op::Constant::create(element::i64, Shape{data_batch_shape.size()}, data_batch_shape), + strides, + pads_begin, + pads_end, + dilations); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::ConvolutionBackpropFilters: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - auto filters_shape = tmp->get_filters_shape(); - auto strides = tmp->get_window_movement_strides_forward(); - auto dilations = tmp->get_window_dilation_strides_forward(); - auto pads_begin = tmp->get_padding_below_forward(); - auto pads_end = tmp->get_padding_above_forward(); - auto data_dilation_strides = tmp->get_data_dilation_strides_forward(); + auto filters_shape = node->get_filters_shape(); + auto strides = node->get_window_movement_strides_forward(); + auto dilations = node->get_window_dilation_strides_forward(); + auto pads_begin = node->get_padding_below_forward(); + auto pads_end = node->get_padding_above_forward(); + auto data_dilation_strides = node->get_data_dilation_strides_forward(); - bool is_dds_valid = true; - for (auto value : data_dilation_strides) - { - is_dds_valid = is_dds_valid && (value == 1); - } + bool is_dds_valid = all_of(data_dilation_strides.begin(), + data_dilation_strides.end(), + [](size_t value) { return value == 1; }); NGRAPH_CHECK( is_dds_valid, @@ -296,234 +212,244 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) *node); auto replacement_node = - make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - node->input(2).get_source_output(), + make_shared(node->input_value(0), + node->input_value(1), + node->input_value(2), strides, dilations, pads_begin, pads_end); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Divide: + + bool op_cast(shared_ptr node) { - const auto tmp = dynamic_cast(node.get()); - const auto autob = tmp->get_autob(); - const bool pydiv = tmp->is_pythondiv(); - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), pydiv, autob); + const auto autob = node->get_autob(); + const bool pydiv = node->is_pythondiv(); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), pydiv, autob); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::DynReshape: + + bool op_cast(shared_ptr node) { auto zero_flag = false; - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), zero_flag); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), zero_flag); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Equal: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Gather: + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - int64_t axis = tmp->get_axis(); + int64_t axis = node->get_axis(); auto axis_node = make_shared(element::i64, Shape{}, vector{axis}); - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), axis_node); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), axis_node); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Greater: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::GreaterEq: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Less: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::LessEq: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Maximum: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::MaxPool: - { - auto tmp = dynamic_cast(node.get()); - auto rounding_type = static_cast(tmp->get_ceil_mode()); - auto auto_pad = tmp->get_pad_type(); - auto pads_begin = tmp->get_padding_below(); - auto pads_end = tmp->get_padding_above(); - auto strides = tmp->get_window_movement_strides(); - auto kernel = tmp->get_window_shape(); + bool op_cast(shared_ptr node) + { + auto rounding_type = + node->get_ceil_mode() ? op::RoundingType::CEIL : op::RoundingType::FLOOR; + auto auto_pad = node->get_pad_type(); + auto pads_begin = node->get_padding_below(); + auto pads_end = node->get_padding_above(); + auto strides = node->get_window_movement_strides(); + auto kernel = node->get_window_shape(); - auto replacement_node = make_shared(node->input(0).get_source_output(), - strides, - pads_begin, - pads_end, - kernel, - rounding_type, - auto_pad); + auto replacement_node = make_shared( + node->input_value(0), strides, pads_begin, pads_end, kernel, rounding_type, auto_pad); +#if defined(__clang__) && __clang_major__ == 3 + // There are some really by clang 3.9 bugs + if (node->get_ceil_mode()) + { + replacement_node->set_rounding_type(op::RoundingType::CEIL); + } + else + { + replacement_node->set_rounding_type(op::RoundingType::FLOOR); + } +#endif replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::MaxPoolBackprop: - { - auto tmp = dynamic_cast(node.get()); - auto pads_begin = tmp->get_padding_below(); - auto pads_end = tmp->get_padding_above(); - auto strides = tmp->get_window_movement_strides(); - auto kernel = tmp->get_window_shape(); + bool op_cast(shared_ptr node) + { + auto pads_begin = node->get_padding_below(); + auto pads_end = node->get_padding_above(); + auto strides = node->get_window_movement_strides(); + auto kernel = node->get_window_shape(); shared_ptr replacement_node; if (node->get_inputs().size() == 3) { - replacement_node = - make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - node->input(2).get_source_output(), - strides, - pads_begin, - pads_end, - kernel); + replacement_node = make_shared(node->input_value(0), + node->input_value(1), + node->input_value(2), + strides, + pads_begin, + pads_end, + kernel); } else { - replacement_node = - make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - strides, - pads_begin, - pads_end, - kernel); + replacement_node = make_shared( + node->input_value(0), node->input_value(1), strides, pads_begin, pads_end, kernel); } replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Minimum: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Multiply: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Not: + + bool op_cast(shared_ptr node) { - replace_node(node, make_shared(node->input(0).get_source_output())); - modified = true; - break; + replace_node(node, make_shared(node->input_value(0))); + return true; } - case OP_TYPEID::NotEqual: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Or: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + const auto indices = node->input_value(0).get_node_shared_ptr(); + const auto one_hot_axis = node->get_one_hot_axis(); + + const auto output_pshape = node->get_output_partial_shape(0); + NGRAPH_CHECK(output_pshape[one_hot_axis].is_static(), + "OneHot:v0 one hot axis dimension must be static ", + *node); + const auto depth = static_cast(output_pshape[one_hot_axis]); + const auto depth_node = op::Constant::create(element::i64, Shape{}, {depth}); + + const auto on_value = op::Constant::create(element::i64, Shape{}, {1}); + const auto off_value = op::Constant::create(element::i64, Shape{}, {0}); + + auto replacement_node = + make_shared(indices, depth_node, on_value, off_value, one_hot_axis); + replace_node(node, replacement_node); + return true; } - case OP_TYPEID::Pad: + + bool op_cast(shared_ptr node) + { + op_cast_binary_elementwise_node(node); + return true; + } + + bool op_cast(shared_ptr node) { - auto tmp = dynamic_cast(node.get()); - auto padding_below = tmp->get_padding_below(); + auto padding_below = node->get_padding_below(); auto pads_begin_node = make_shared(element::i64, Shape{padding_below.size()}, padding_below); - auto padding_above = tmp->get_padding_above(); + auto padding_above = node->get_padding_above(); auto pads_end_node = make_shared(element::i64, Shape{padding_above.size()}, padding_above); - auto replacement_node = make_shared(node->input(0).get_source_output(), + auto replacement_node = make_shared(node->input_value(0), pads_begin_node, pads_end_node, - node->input(1).get_source_output(), - tmp->get_pad_mode()); + node->input_value(1), + node->get_pad_mode()); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Power: + + bool op_cast(shared_ptr node) { - upgrade_binary_elementwise_node(node); - modified = true; - break; + op_cast_binary_elementwise_node(node); + return true; } - case OP_TYPEID::Product: + + bool op_cast(shared_ptr node) { bool keep_dims = false; - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), keep_dims); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), keep_dims); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Reverse: + + bool op_cast(shared_ptr node) { // creates a Constant node from the v0::Reverse reversed_axes attribute // and uses it as the second input of v1::Reverse - const auto reverse_v0 = dynamic_cast(node.get()); - const auto reversed_axes = reverse_v0->get_reversed_axes(); + const auto reversed_axes = node->get_reversed_axes(); const auto reversed_axes_constant = op::Constant::create( element::i64, Shape{reversed_axes.size()}, reversed_axes.to_vector()); - const auto reverse_v1 = make_shared(node->input(0).get_source_output(), - reversed_axes_constant, - op::v1::Reverse::Mode::INDEX); + const auto reverse_v1 = make_shared( + node->input_value(0), reversed_axes_constant, op::v1::Reverse::Mode::INDEX); replace_node(node, reverse_v1); - modified = true; - - break; + return true; } - case OP_TYPEID::Softmax: - { - auto tmp = dynamic_cast(node.get()); + bool op_cast(shared_ptr node) + { NGRAPH_CHECK(node->input_value(1).get_node_shared_ptr()->is_constant(), "axes parameter is expected to be a static constant"); - AxisSet axes = tmp->get_axes(); + AxisSet axes = node->get_axes(); NGRAPH_CHECK( axes.size() == 1, @@ -531,23 +457,21 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) *node); auto replacement_node = - make_shared(node->input(0).get_source_output(), axes.to_vector()[0]); + make_shared(node->input_value(0), axes.to_vector()[0]); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Slice: - { - const auto tmp = as_type_ptr(node); - const auto data = node->input(0).get_source_output(); + bool op_cast(shared_ptr node) + { + const auto data = node->input_value(0); const auto begin = op::Constant::create( - element::i64, Shape{tmp->get_lower_bounds().size()}, tmp->get_lower_bounds()); + element::i64, Shape{node->get_lower_bounds().size()}, node->get_lower_bounds()); const auto end = op::Constant::create( - element::i64, Shape{tmp->get_upper_bounds().size()}, tmp->get_upper_bounds()); + element::i64, Shape{node->get_upper_bounds().size()}, node->get_upper_bounds()); const auto strides = op::Constant::create( - element::i64, Shape{tmp->get_strides().size()}, tmp->get_strides()); - int64_t input_size = tmp->get_lower_bounds().size(); + element::i64, Shape{node->get_strides().size()}, node->get_strides()); + int64_t input_size = node->get_lower_bounds().size(); auto replacement_node = make_shared(data, begin, @@ -557,32 +481,36 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) vector(input_size, 0)); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::Sum: + + bool op_cast(shared_ptr node) + { + op_cast_binary_elementwise_node(node); + return true; + } + + bool op_cast(shared_ptr node) { bool keep_dims = false; - auto replacement_node = make_shared( - node->input(0).get_source_output(), node->input(1).get_source_output(), keep_dims); + auto replacement_node = + make_shared(node->input_value(0), node->input_value(1), keep_dims); replace_node(node, replacement_node); - modified = true; - break; + return true; } - case OP_TYPEID::TopK: - { - const auto topk_v0 = dynamic_cast(node.get()); + bool op_cast(shared_ptr node) + { NGRAPH_CHECK(node->input_value(1).get_node_shared_ptr()->is_constant(), "parameter k is expected to be a static constant"); NGRAPH_CHECK(node->input_value(2).get_node_shared_ptr()->is_constant(), "parameter top_k_axis is expected to be a static constant"); - const auto k = topk_v0->get_k(); - const auto axis = topk_v0->get_top_k_axis(); + const auto k = node->get_k(); + const auto axis = node->get_top_k_axis(); std::string sort; - switch (topk_v0->get_sort()) + switch (node->get_sort()) { case op::TopK::SortType::SORT_INDICES: sort = "index"; break; case op::TopK::SortType::SORT_VALUES: sort = "value"; break; @@ -590,7 +518,7 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) } std::string mode; - if (topk_v0->get_compute_max()) + if (node->get_compute_max()) { mode = "max"; } @@ -606,25 +534,44 @@ bool pass::Opset1Upgrade::run_on_node(shared_ptr node) // indices output will be 0, values 1 vector output_order{1, 0}; replace_node(node, replacement_node, output_order); - modified = true; - break; + return true; } - case OP_TYPEID::Xor: + + bool op_cast(shared_ptr node) { - const auto xor_v0 = dynamic_cast(node.get()); - auto replacement_node = make_shared(node->input(0).get_source_output(), - node->input(1).get_source_output(), - xor_v0->get_autob()); + auto replacement_node = make_shared( + node->input_value(0), node->input_value(1), node->get_autob()); replace_node(node, replacement_node); - modified = true; - break; + return true; } - default: break; + + using DispatchMap = map node)>>; + + template + bool op_cast_thunk(shared_ptr node) + { + return op_cast(as_type_ptr(node)); } -#if defined(__clang__) -#pragma clang diagnostic pop -#endif + DispatchMap& get_dispatch_map() + { + static DispatchMap dispatch_map{ +#define NGRAPH_OP(NAME, NAMESPACE) {NAMESPACE::NAME::type_info, op_cast_thunk}, +#include "ngraph/opsets/opset0_tbl.hpp" +#undef NGRAPH_OP + }; + return dispatch_map; + } +} +bool pass::Opset1Upgrade::run_on_node(shared_ptr node) +{ + bool modified = false; + auto& dispatch_map = get_dispatch_map(); + auto it = dispatch_map.find(node->get_type_info()); + if (it != dispatch_map.end()) + { + modified = it->second(node); + } return modified; } diff --git a/src/ngraph/pass/opset1_upgrade.hpp b/src/ngraph/pass/opset1_upgrade.hpp index 47701ca2729..c8156a18563 100644 --- a/src/ngraph/pass/opset1_upgrade.hpp +++ b/src/ngraph/pass/opset1_upgrade.hpp @@ -22,15 +22,15 @@ namespace ngraph { namespace pass { - class Opset1Upgrade : public NodePass + class NGRAPH_API Opset1Upgrade : public NodePass { public: /// - /// \brief Constructor for the Opset 1 transformation pass. + /// \brief Constructor for the Opset1Upgrade transformation pass. /// /// \details This transformation pass iterates over all nodes in a graph - /// and updates opset version 0 ops to their opset version 1 equivalents. - /// All ops in the final graph have opset version 1. + /// and updates version 0 ops to their version 1 equivalents. + /// All ops in the final graph have op version 1. Opset1Upgrade() = default; bool run_on_node(std::shared_ptr node) override; }; diff --git a/src/ngraph/pass/pass.cpp b/src/ngraph/pass/pass.cpp index 02e222f74c0..d619c75af84 100644 --- a/src/ngraph/pass/pass.cpp +++ b/src/ngraph/pass/pass.cpp @@ -51,3 +51,21 @@ void pass::PassBase::set_property(const PassPropertyMask& prop, bool value) m_property.clear(prop); } } + +// The symbols are requiered to be in cpp file to workaround RTTI issue on Android LLVM + +pass::ModulePass::~ModulePass() +{ +} + +pass::FunctionPass::~FunctionPass() +{ +} + +pass::NodePass::~NodePass() +{ +} + +pass::CallGraphPass::~CallGraphPass() +{ +} diff --git a/src/ngraph/pass/pass.hpp b/src/ngraph/pass/pass.hpp index 3f853f87f3e..7932495c689 100644 --- a/src/ngraph/pass/pass.hpp +++ b/src/ngraph/pass/pass.hpp @@ -55,12 +55,21 @@ namespace ngraph // Pass transformation will change the function's dynamic state CHANGE_DYNAMIC_STATE = 1 << 1 }; + } +} + +template class NGRAPH_API ngraph::EnumMask; + +namespace ngraph +{ + namespace pass + { typedef EnumMask PassPropertyMask; - constexpr PassPropertyMask all_pass_property_off; + const PassPropertyMask all_pass_property_off; } } -class ngraph::pass::PassBase +class NGRAPH_API ngraph::pass::PassBase { friend class Manager; @@ -80,30 +89,30 @@ class ngraph::pass::PassBase ManagerState* m_state{nullptr}; }; -class ngraph::pass::ModulePass : public PassBase +class NGRAPH_API ngraph::pass::ModulePass : public PassBase { public: - virtual ~ModulePass() {} + virtual ~ModulePass(); virtual bool run_on_module(std::vector>&) = 0; }; -class ngraph::pass::FunctionPass : public PassBase +class NGRAPH_API ngraph::pass::FunctionPass : public PassBase { public: - virtual ~FunctionPass() {} + virtual ~FunctionPass(); virtual bool run_on_function(std::shared_ptr) = 0; }; -class ngraph::pass::NodePass : public PassBase +class NGRAPH_API ngraph::pass::NodePass : public PassBase { public: - virtual ~NodePass() {} + virtual ~NodePass(); virtual bool run_on_node(std::shared_ptr) = 0; }; -class ngraph::pass::CallGraphPass : public PassBase +class NGRAPH_API ngraph::pass::CallGraphPass : public PassBase { public: - virtual ~CallGraphPass() {} + virtual ~CallGraphPass(); virtual bool run_on_call_graph(const std::list>&) = 0; }; diff --git a/src/ngraph/pass/propagate_cacheability.hpp b/src/ngraph/pass/propagate_cacheability.hpp index afe3aa32ed9..cd77cbb7907 100644 --- a/src/ngraph/pass/propagate_cacheability.hpp +++ b/src/ngraph/pass/propagate_cacheability.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::PropagateCacheability : public FunctionPass +class NGRAPH_API ngraph::pass::PropagateCacheability : public FunctionPass { public: PropagateCacheability() diff --git a/src/ngraph/pass/reshape_elimination.hpp b/src/ngraph/pass/reshape_elimination.hpp index 248762b37ae..a771ee40cc8 100644 --- a/src/ngraph/pass/reshape_elimination.hpp +++ b/src/ngraph/pass/reshape_elimination.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::ReshapeElimination : public ngraph::pass::GraphRewrite +class NGRAPH_API ngraph::pass::ReshapeElimination : public ngraph::pass::GraphRewrite { public: ReshapeElimination() @@ -45,7 +45,8 @@ class ngraph::pass::ReshapeElimination : public ngraph::pass::GraphRewrite void construct_reshapex2_pattern(); }; -class ngraph::pass::RecurrentReshapeElimination : public ngraph::pass::RecurrentGraphRewrite +class NGRAPH_API ngraph::pass::RecurrentReshapeElimination + : public ngraph::pass::RecurrentGraphRewrite { public: RecurrentReshapeElimination() diff --git a/src/ngraph/pass/reshape_sinking.hpp b/src/ngraph/pass/reshape_sinking.hpp index d8041a36e8e..5bb0fd2a71d 100644 --- a/src/ngraph/pass/reshape_sinking.hpp +++ b/src/ngraph/pass/reshape_sinking.hpp @@ -23,7 +23,7 @@ namespace ngraph { namespace pass { - class ReshapeSinking : public ngraph::pass::FunctionPass + class NGRAPH_API ReshapeSinking : public ngraph::pass::FunctionPass { public: ReshapeSinking() { set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); } diff --git a/src/ngraph/pass/serialize.hpp b/src/ngraph/pass/serialize.hpp index d5292ca5dd3..5b7dbc74b52 100644 --- a/src/ngraph/pass/serialize.hpp +++ b/src/ngraph/pass/serialize.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::Serialization : public ModulePass +class NGRAPH_API ngraph::pass::Serialization : public ModulePass { public: Serialization(const std::string& name); diff --git a/src/ngraph/pass/shape_relevance.hpp b/src/ngraph/pass/shape_relevance.hpp index b897dc51f30..6f12603d205 100644 --- a/src/ngraph/pass/shape_relevance.hpp +++ b/src/ngraph/pass/shape_relevance.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace pass { - class ShapeRelevance : public FunctionPass + class NGRAPH_API ShapeRelevance : public FunctionPass { public: ShapeRelevance() diff --git a/src/ngraph/pass/validate.hpp b/src/ngraph/pass/validate.hpp index 6343d45cb28..95c37d8fdd2 100644 --- a/src/ngraph/pass/validate.hpp +++ b/src/ngraph/pass/validate.hpp @@ -22,7 +22,7 @@ namespace ngraph { namespace pass { - class Validate : public FunctionPass + class NGRAPH_API Validate : public FunctionPass { public: Validate() diff --git a/src/ngraph/pass/validate_graph.hpp b/src/ngraph/pass/validate_graph.hpp index 7003400034b..0caeaff9dc1 100644 --- a/src/ngraph/pass/validate_graph.hpp +++ b/src/ngraph/pass/validate_graph.hpp @@ -28,7 +28,7 @@ namespace ngraph } } -class ngraph::pass::ValidateGraph : public ModulePass +class NGRAPH_API ngraph::pass::ValidateGraph : public ModulePass { public: bool run_on_module(std::vector>&) override; diff --git a/src/ngraph/pass/visualize_tree.hpp b/src/ngraph/pass/visualize_tree.hpp index 39c559004d9..618c389088e 100644 --- a/src/ngraph/pass/visualize_tree.hpp +++ b/src/ngraph/pass/visualize_tree.hpp @@ -38,7 +38,7 @@ namespace ngraph class HeightMap; -class ngraph::pass::VisualizeTree : public ModulePass +class NGRAPH_API ngraph::pass::VisualizeTree : public ModulePass { public: using node_modifiers_t = @@ -49,13 +49,13 @@ class ngraph::pass::VisualizeTree : public ModulePass bool run_on_module(std::vector>&) override; void set_ops_to_details(const visualize_tree_ops_map_t& ops_map) { m_ops_to_details = ops_map; } -private: +protected: void add_node_arguments(std::shared_ptr node, std::unordered_map& height_maps, size_t& fake_node_ctr); std::string add_attributes(std::shared_ptr node); - std::string get_attributes(std::shared_ptr node); - std::string get_node_name(std::shared_ptr node); + virtual std::string get_attributes(std::shared_ptr node); + virtual std::string get_node_name(std::shared_ptr node); void render() const; std::stringstream m_ss; diff --git a/src/ngraph/pass/zero_dim_tensor_elimination.hpp b/src/ngraph/pass/zero_dim_tensor_elimination.hpp index 3146eacb8c3..ddab2e4c56e 100644 --- a/src/ngraph/pass/zero_dim_tensor_elimination.hpp +++ b/src/ngraph/pass/zero_dim_tensor_elimination.hpp @@ -26,7 +26,7 @@ namespace ngraph } } -class ngraph::pass::ZeroDimTensorElimination : public FunctionPass +class NGRAPH_API ngraph::pass::ZeroDimTensorElimination : public FunctionPass { public: ZeroDimTensorElimination() diff --git a/src/ngraph/pattern/matcher.cpp b/src/ngraph/pattern/matcher.cpp index d522312584b..efb1ffa98b3 100644 --- a/src/ngraph/pattern/matcher.cpp +++ b/src/ngraph/pattern/matcher.cpp @@ -28,6 +28,16 @@ namespace ngraph { namespace pattern { + namespace op + { + // The symbols are requiered to be in cpp file to workaround RTTI issue on Android LLVM + const NodeTypeInfo& Any::get_type_info() const { return type_info; } + const NodeTypeInfo& AnyOf::get_type_info() const { return type_info; } + const NodeTypeInfo& Label::get_type_info() const { return type_info; } + const NodeTypeInfo& Skip::get_type_info() const { return type_info; } + Predicate Pattern::get_predicate() const { return m_predicate; } + } + constexpr NodeTypeInfo op::AnyOf::type_info; constexpr NodeTypeInfo op::Any::type_info; constexpr NodeTypeInfo op::Label::type_info; diff --git a/src/ngraph/pattern/matcher.hpp b/src/ngraph/pattern/matcher.hpp index aab92fed1f5..0805214e8c8 100644 --- a/src/ngraph/pattern/matcher.hpp +++ b/src/ngraph/pattern/matcher.hpp @@ -52,7 +52,7 @@ namespace ngraph /// \brief Matcher matches (compares) two graphs /// - class Matcher + class NGRAPH_API Matcher { public: using PatternMap = std::map, std::shared_ptr>; diff --git a/src/ngraph/pattern/op/any.hpp b/src/ngraph/pattern/op/any.hpp index 3e84c332e5b..fc05f7f5a7d 100644 --- a/src/ngraph/pattern/op/any.hpp +++ b/src/ngraph/pattern/op/any.hpp @@ -26,12 +26,11 @@ namespace ngraph namespace op { /// \brief Anys are used in patterns to express arbitrary queries on a node - class Any : public Pattern + class NGRAPH_API Any : public Pattern { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"patternAny", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + const NodeTypeInfo& get_type_info() const override; /// \brief creates a Any node containing a sub-pattern described by \sa type and \sa /// shape. Any(const element::Type& type, diff --git a/src/ngraph/pattern/op/any_of.hpp b/src/ngraph/pattern/op/any_of.hpp index dbeaaaa106f..aee4dce47a4 100644 --- a/src/ngraph/pattern/op/any_of.hpp +++ b/src/ngraph/pattern/op/any_of.hpp @@ -32,12 +32,11 @@ namespace ngraph /// This is useful for nodes with variable number of arguments such as Concat /// AnyOf enables on to specify one single branch/chain. The remaining arguments /// can be discovered (in a callback) by simply inspecting matched node's argument. - class AnyOf : public Pattern + class NGRAPH_API AnyOf : public Pattern { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"patternAnyOf", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + const NodeTypeInfo& get_type_info() const override; /// \brief creates a AnyOf node containing a sub-pattern described by \sa type and /// \sa shape. AnyOf(const element::Type& type, diff --git a/src/ngraph/pattern/op/label.hpp b/src/ngraph/pattern/op/label.hpp index d803ccc0174..4883511284e 100644 --- a/src/ngraph/pattern/op/label.hpp +++ b/src/ngraph/pattern/op/label.hpp @@ -28,12 +28,11 @@ namespace ngraph /// \brief Labels are used in patterns to express repeating nodes in an input graph /// and bind them to specific nodes from the graph /// - class Label : public Pattern + class NGRAPH_API Label : public Pattern { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"patternLabel", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + const NodeTypeInfo& get_type_info() const override; /// \brief creates a Label node containing a sub-pattern described by \sa type and /// \sa shape. /// diff --git a/src/ngraph/pattern/op/pattern.hpp b/src/ngraph/pattern/op/pattern.hpp index 12f7fcfbac3..51ad7136397 100644 --- a/src/ngraph/pattern/op/pattern.hpp +++ b/src/ngraph/pattern/op/pattern.hpp @@ -28,7 +28,7 @@ namespace ngraph { using Predicate = std::function)>; - class Pattern : public Node + class NGRAPH_API Pattern : public Node { public: /// \brief \p a base class for \sa Skip and \sa Label @@ -45,7 +45,8 @@ namespace ngraph throw ngraph_error("Uncopyable"); } - Predicate get_predicate() const { return m_predicate; } + Predicate get_predicate() const; + protected: std::function)> m_predicate; }; diff --git a/src/ngraph/pattern/op/skip.hpp b/src/ngraph/pattern/op/skip.hpp index e22a83618d9..542b61695ff 100644 --- a/src/ngraph/pattern/op/skip.hpp +++ b/src/ngraph/pattern/op/skip.hpp @@ -28,12 +28,11 @@ namespace ngraph /// \brief \p Skip allows users to specify unexpected nodes in a pattern /// and skip them if a predicate condition is satisfied. /// - class Skip : public Pattern + class NGRAPH_API Skip : public Pattern { public: - NGRAPH_API static constexpr NodeTypeInfo type_info{"patternSkip", 0}; - const NodeTypeInfo& get_type_info() const override { return type_info; } + const NodeTypeInfo& get_type_info() const override; Skip(const std::shared_ptr& arg, Predicate predicate = nullptr) : Pattern(NodeVector{arg}, predicate) { diff --git a/src/ngraph/runtime/aligned_buffer.hpp b/src/ngraph/runtime/aligned_buffer.hpp index 3d42ea4738a..66f942f35f4 100644 --- a/src/ngraph/runtime/aligned_buffer.hpp +++ b/src/ngraph/runtime/aligned_buffer.hpp @@ -31,7 +31,7 @@ namespace ngraph /// \brief Allocates a block of memory on the specified alignment. The actual size of the /// allocated memory is larger than the requested size by the alignment, so allocating 1 byte /// on 64 byte alignment will allocate 65 bytes. -class ngraph::runtime::AlignedBuffer +class NGRAPH_API ngraph::runtime::AlignedBuffer { public: // Allocator objects and the allocation interfaces are owned by the diff --git a/src/ngraph/runtime/backend.hpp b/src/ngraph/runtime/backend.hpp index 6d584976716..9bd21b0d9d3 100644 --- a/src/ngraph/runtime/backend.hpp +++ b/src/ngraph/runtime/backend.hpp @@ -40,7 +40,7 @@ namespace ngraph /// \brief Interface to a generic backend. /// /// Backends are responsible for function execution and value allocation. -class ngraph::runtime::Backend +class NGRAPH_API ngraph::runtime::Backend { public: virtual ~Backend(); diff --git a/src/ngraph/runtime/cpu/CMakeLists.txt b/src/ngraph/runtime/cpu/CMakeLists.txt index cd3627343f0..7a1c26167b7 100644 --- a/src/ngraph/runtime/cpu/CMakeLists.txt +++ b/src/ngraph/runtime/cpu/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC builder/convert.cpp builder/convert_layout.cpp builder/convolution.cpp + builder/cum_sum.cpp builder/dot.cpp builder/dropout.cpp builder/embedding_lookup.cpp @@ -100,7 +101,6 @@ set(SRC mkldnn_emitter.cpp mkldnn_invoke.cpp mkldnn_utils.cpp - op/batch_mat_mul_transpose.cpp op/batch_norm_relu.cpp op/bounded_relu.cpp op/conv_add.cpp @@ -237,7 +237,7 @@ if (NGRAPH_CPU_ENABLE) message(WARNING "The build toolset doesn't support OpenMP. This will impact performance and lead to slowdowns.") endif() - if (MSVS) + if (MSVC) target_compile_definitions(cpu_backend PRIVATE EIGEN_HAS_CONSTEXPR) # under debug mode, more files besides builder/dot.cpp rises the error target_compile_options(cpu_backend PRIVATE "/bigobj" ) @@ -261,7 +261,7 @@ if (NGRAPH_CPU_ENABLE) endif() target_include_directories(cpu_backend SYSTEM PUBLIC libmkldnn) - if (NOT APPLE AND NOT MSVS) + if (NOT APPLE AND NOT MSVC) # CPU backend uses third-party libraries like Eigen that might be linked in and # exported by other DSOs as well. In the absence of versioning, this could lead to the # CPU backend picking up the wrong version or even multiple versions of the diff --git a/src/ngraph/runtime/cpu/builder/cum_sum.cpp b/src/ngraph/runtime/cpu/builder/cum_sum.cpp new file mode 100644 index 00000000000..4faea62ed68 --- /dev/null +++ b/src/ngraph/runtime/cpu/builder/cum_sum.cpp @@ -0,0 +1,158 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "ngraph/runtime/cpu/kernel/cum_sum.hpp" +#include "ngraph/op/cum_sum.hpp" +#include "ngraph/runtime/cpu/cpu_builder.hpp" + +using namespace std; +using namespace ngraph; + +namespace ngraph +{ + namespace runtime + { + namespace cpu + { + template <> + void Builder::BUILDER_DECL(ngraph::op::CumSum) + { +#define FUNCTOR_CUMSUM(T, M) \ + do \ + { \ + auto functor = [&, \ + kernel, \ + arg0_buffer_index, \ + arg1_buffer_index, \ + out0_buffer_index, \ + tensor_shape, \ + cumsum_op](CPURuntimeContext* ctx, CPUExecutionContext* /* ectx */) { \ + runtime::cpu::kernel::reference_cumsum(ctx->buffer_data[arg0_buffer_index], \ + ctx->buffer_data[arg1_buffer_index], \ + ctx->buffer_data[out0_buffer_index], \ + tensor_shape, \ + cumsum_op->is_exclusive(), \ + cumsum_op->is_reverse()); \ + }; \ + functors.emplace_back(functor); \ + } while (0) + (void)node; + + auto cumsum_op = static_cast(node); + auto tensor_shape = args[0].get_shape(); + auto arg0_buffer_index = external_function->get_buffer_index(args[0].get_name()); + auto arg1_buffer_index = external_function->get_buffer_index(args[1].get_name()); + auto out0_buffer_index = external_function->get_buffer_index(out[0].get_name()); + auto& functors = external_function->get_functors(); + + if (args[0].get_element_type() == element::f32 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(float, int32_t); + } + else if (args[0].get_element_type() == element::f32 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(float, int64_t); + } + else if (args[0].get_element_type() == element::f64 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(double, int32_t); + } + else if (args[0].get_element_type() == element::f64 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(double, int64_t); + } + else if (args[0].get_element_type() == element::i32 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(int32_t, int32_t); + } + else if (args[0].get_element_type() == element::i32 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(int32_t, int64_t); + } + else if (args[0].get_element_type() == element::i64 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(int64_t, int32_t); + } + else if (args[0].get_element_type() == element::i64 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(int64_t, int64_t); + } + else if (args[0].get_element_type() == element::u32 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(uint32_t, int32_t); + } + else if (args[0].get_element_type() == element::u32 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(uint32_t, int64_t); + } + else if (args[0].get_element_type() == element::u64 && + args[1].get_element_type() == element::i32) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(uint64_t, int32_t); + } + else if (args[0].get_element_type() == element::u64 && + args[1].get_element_type() == element::i64) + { + std::function)> + kernel; + FUNCTOR_CUMSUM(uint64_t, int64_t); + } + } + + void register_builders_cumsum_cpp() { REGISTER_OP_BUILDER(CumSum); } + } + } +} diff --git a/src/ngraph/runtime/cpu/builder/matmul_bias.cpp b/src/ngraph/runtime/cpu/builder/matmul_bias.cpp index f1354f4b9eb..834b3ca12db 100644 --- a/src/ngraph/runtime/cpu/builder/matmul_bias.cpp +++ b/src/ngraph/runtime/cpu/builder/matmul_bias.cpp @@ -15,10 +15,11 @@ //***************************************************************************** #include "ngraph/runtime/cpu/op/matmul_bias.hpp" + #include "ngraph/op/experimental/batch_mat_mul.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/runtime/cpu/cpu_builder.hpp" #include "ngraph/runtime/cpu/cpu_kernels.hpp" -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" using namespace std; using namespace ngraph; diff --git a/src/ngraph/runtime/cpu/builder/random_uniform.cpp b/src/ngraph/runtime/cpu/builder/random_uniform.cpp index 81014ea9bd5..077671729ba 100644 --- a/src/ngraph/runtime/cpu/builder/random_uniform.cpp +++ b/src/ngraph/runtime/cpu/builder/random_uniform.cpp @@ -112,6 +112,9 @@ namespace ngraph NGRAPH_CHECK(false, "Encountered 'dynamic' element type in fold_constant_convert"); break; + case element::Type_t::u1: + NGRAPH_CHECK(false, "Encountered 'u1' element type in fold_constant_convert"); + break; case element::Type_t::boolean: functor = prepare_functor(node, args, out, external_function); break; diff --git a/src/ngraph/runtime/cpu/cpu_backend.cpp b/src/ngraph/runtime/cpu/cpu_backend.cpp index a215423a7e1..8ceb6ee28ce 100644 --- a/src/ngraph/runtime/cpu/cpu_backend.cpp +++ b/src/ngraph/runtime/cpu/cpu_backend.cpp @@ -210,6 +210,76 @@ vector runtime::cpu::CPU_Executable::get_performanc return rc; } +shared_ptr runtime::cpu::CPU_Executable::get_parameter(size_t index) const +{ + const ParameterVector& parameters = get_parameters(); + NGRAPH_CHECK(index < parameters.size(), "create_tensor for input out of bounds"); + return parameters[index]; +} + +shared_ptr runtime::cpu::CPU_Executable::get_result(size_t index) const +{ + const ResultVector& results = get_results(); + NGRAPH_CHECK(index < results.size(), "create_tensor for input out of bounds"); + return results[index]; +} + +shared_ptr runtime::cpu::CPU_Executable::create_input_tensor(size_t input_index) +{ + shared_ptr parameter = get_parameter(input_index); + return make_shared(parameter->get_element_type(), + parameter->get_shape()); +} + +shared_ptr runtime::cpu::CPU_Executable::create_output_tensor(size_t output_index) +{ + shared_ptr result = get_result(output_index); + return make_shared(result->get_element_type(), + result->get_shape()); +} + +vector> + runtime::cpu::CPU_Executable::create_input_tensor(size_t input_index, size_t pipeline_depth) +{ + vector> tensors; + shared_ptr parameter = get_parameter(input_index); + for (size_t i = 0; i < pipeline_depth; i++) + { + shared_ptr tensor; + auto t = make_shared(parameter->get_element_type(), + parameter->get_shape()); + tensor = static_pointer_cast(t); + tensors.push_back(tensor); + } + vector> result_tensors; + for (const shared_ptr& tensor : tensors) + { + result_tensors.push_back(tensor); + } + return result_tensors; +} + +vector> + runtime::cpu::CPU_Executable::create_output_tensor(size_t output_index, size_t pipeline_depth) +{ + vector> tensors; + shared_ptr result = get_result(output_index); + for (size_t i = 0; i < pipeline_depth; i++) + { + shared_ptr tensor; + auto t = make_shared(result->get_element_type(), + result->get_shape()); + tensor = static_pointer_cast(t); + tensors.push_back(tensor); + } + vector> result_tensors; + for (const shared_ptr& tensor : tensors) + { + result_tensors.push_back(tensor); + } + return result_tensors; +} + bool runtime::cpu::CPU_Backend::is_supported(const Node& /* op */) const { return true; diff --git a/src/ngraph/runtime/cpu/cpu_backend.hpp b/src/ngraph/runtime/cpu/cpu_backend.hpp index affaf408540..c858826c6a8 100644 --- a/src/ngraph/runtime/cpu/cpu_backend.hpp +++ b/src/ngraph/runtime/cpu/cpu_backend.hpp @@ -94,7 +94,19 @@ namespace ngraph std::vector get_performance_data() const override; + std::shared_ptr create_input_tensor(size_t input_index) override; + + std::shared_ptr create_output_tensor(size_t output_index) override; + + std::vector> + create_input_tensor(size_t input_index, size_t pipeline_depth) override; + + std::vector> + create_output_tensor(size_t output_index, size_t pipeline_depth) override; + private: + std::shared_ptr get_parameter(size_t index) const; + std::shared_ptr get_result(size_t index) const; class FunctionInstance { public: diff --git a/src/ngraph/runtime/cpu/cpu_builder_registry.cpp b/src/ngraph/runtime/cpu/cpu_builder_registry.cpp index 389083c2cb1..854c7c64276 100644 --- a/src/ngraph/runtime/cpu/cpu_builder_registry.cpp +++ b/src/ngraph/runtime/cpu/cpu_builder_registry.cpp @@ -36,6 +36,7 @@ namespace ngraph register_builders_convert_cpp(); register_builders_convert_layout_cpp(); register_builders_convolution_cpp(); + register_builders_cumsum_cpp(); register_builders_dot_cpp(); register_builders_dropout_cpp(); register_builders_embedding_lookup_cpp(); diff --git a/src/ngraph/runtime/cpu/cpu_builder_registry.hpp b/src/ngraph/runtime/cpu/cpu_builder_registry.hpp index 784f1e58a55..4cd1718bc54 100644 --- a/src/ngraph/runtime/cpu/cpu_builder_registry.hpp +++ b/src/ngraph/runtime/cpu/cpu_builder_registry.hpp @@ -35,6 +35,7 @@ namespace ngraph void register_builders_convert_cpp(); void register_builders_convert_layout_cpp(); void register_builders_convolution_cpp(); + void register_builders_cumsum_cpp(); void register_builders_dot_cpp(); void register_builders_dropout_cpp(); void register_builders_embedding_lookup_cpp(); diff --git a/src/ngraph/runtime/cpu/cpu_emitter.cpp b/src/ngraph/runtime/cpu/cpu_emitter.cpp index bd8badcecb1..1f20f3da674 100644 --- a/src/ngraph/runtime/cpu/cpu_emitter.cpp +++ b/src/ngraph/runtime/cpu/cpu_emitter.cpp @@ -45,6 +45,7 @@ #include "ngraph/op/convolution.hpp" #include "ngraph/op/cos.hpp" #include "ngraph/op/cosh.hpp" +#include "ngraph/op/cum_sum.hpp" #include "ngraph/op/dequantize.hpp" #include "ngraph/op/divide.hpp" #include "ngraph/op/dot.hpp" @@ -61,6 +62,7 @@ #include "ngraph/op/experimental/random_uniform.hpp" #include "ngraph/op/experimental/tile.hpp" #include "ngraph/op/floor.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/op/fused/conv_fused.hpp" #include "ngraph/op/fused/gelu.hpp" #include "ngraph/op/fused/group_conv.hpp" @@ -112,7 +114,6 @@ #include "ngraph/runtime/cpu/cpu_kernel_emitters.hpp" #include "ngraph/runtime/cpu/cpu_op_annotations.hpp" #include "ngraph/runtime/cpu/mkldnn_utils.hpp" -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" #include "ngraph/runtime/cpu/op/batch_norm_relu.hpp" #include "ngraph/runtime/cpu/op/bounded_relu.hpp" #include "ngraph/runtime/cpu/op/conv_add.hpp" @@ -4604,6 +4605,22 @@ namespace ngraph } } + template <> + void CPU_Emitter::EMITTER_DECL(ngraph::op::CumSum) + { + const ngraph::op::CumSum* cumsum = static_cast(node); + writer.block_begin(); + writer << "reference::cumsum<" << args[0].get_element_type().c_type_string(); + writer << ", " << args[1].get_element_type().c_type_string() << ">("; + writer << " " << args[0].get_name() << ",\n"; + writer << " " << args[1].get_name() << ",\n"; + writer << " " << out[0].get_name() << ",\n"; + writer << " {" << join(args[0].get_shape()) << "},\n"; + writer << " " << cumsum->is_exclusive() << ",\n"; + writer << " " << cumsum->is_reverse() << ");\n"; + writer.block_end(); + } + #undef TI } // namespace cpu } // namespace runtime diff --git a/src/ngraph/runtime/cpu/cpu_emitter.hpp b/src/ngraph/runtime/cpu/cpu_emitter.hpp index 51dec4b242a..21896823933 100644 --- a/src/ngraph/runtime/cpu/cpu_emitter.hpp +++ b/src/ngraph/runtime/cpu/cpu_emitter.hpp @@ -21,39 +21,21 @@ #include "ngraph/code_writer.hpp" #include "ngraph/node.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/min.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/not.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/ops.hpp" #include "ngraph/runtime/cpu/cpu_external_function.hpp" #include "ngraph/runtime/cpu/cpu_tensor_view_wrapper.hpp" +#include "ngraph/runtime/cpu/op/bounded_relu.hpp" +#include "ngraph/runtime/cpu/op/convert_layout.hpp" +#include "ngraph/runtime/cpu/op/dropout.hpp" #include "ngraph/runtime/cpu/op/gelu_backprop.hpp" +#include "ngraph/runtime/cpu/op/lstm.hpp" +#include "ngraph/runtime/cpu/op/matmul_bias.hpp" +#include "ngraph/runtime/cpu/op/max_pool_with_indices.hpp" +#include "ngraph/runtime/cpu/op/quantized_matmul.hpp" +#include "ngraph/runtime/cpu/op/quantized_matmul.hpp" +#include "ngraph/runtime/cpu/op/rnn.hpp" +#include "ngraph/runtime/cpu/op/sigmoid_mul.hpp" +#include "ngraph/runtime/cpu/op/update_slice.hpp" #define EMITTER_DECL(op_name) \ emit(CPU_ExternalFunction * external_function, \ @@ -64,106 +46,10 @@ namespace ngraph { - namespace op - { - class AllReduce; - class BroadcastDistributed; - class MatmulBias; - class BatchMatMul; - class BatchMatMulTranspose; - class Lstm; - class Rnn; - class BatchNormTraining; - class BatchNormInference; - class BatchNormTrainingRelu; - class BatchNormInferenceRelu; - class BatchNormTrainingBackprop; - class Dot; - class GetOutputElement; - class Abs; - class Concat; - class Any; - class All; - class LRN; - class Log; - class Negative; - class Select; - class Subtract; - class Convert; - class Constant; - class Reshape; - class Sign; - class Exp; - class EmbeddingLookup; - class Sin; - class Sinh; - class Cos; - class Cosh; - class Tan; - class Tanh; - class Asin; - class Atan; - class ArgMin; - class ArgMax; - class GatherND; - class ScatterAdd; - class ScatterNDAdd; - class UpdateSlice; - class ReplaceSlice; - class OneHot; - class Ceiling; - class Floor; - class Sqrt; - class ConvolutionRelu; - class QuantizedConvolutionRelu; - class QuantizedConvolution; - class GroupConvolution; - class GroupConvolutionBias; - class DeconvolutionBias; - class QuantizedConvolutionBias; - class QuantizedConvolutionBiasAdd; - class QuantizedConvolutionBiasSignedAdd; - class QuantizedDotBias; - class QuantizedDot; - class QuantizedMatmul; - class ConvolutionBias; - class ConvolutionBiasAdd; - class ConvolutionAdd; - class ConvolutionBiasBackpropFiltersBias; - class QuantizedMaxPool; - class QuantizedAvgPool; - class MaxPoolWithIndices; - class ReverseSequence; - class MaxPoolWithIndicesBackprop; - class Erf; - class ReluBackprop; - class Relu; - class CPULeakyRelu; - class BoundedRelu; - class Sigmoid; - class SigmoidBackprop; - class SigmoidMultiply; - class SigmoidMultiplyBackprop; - class Result; - class CompiledKernel; - class Dropout; - class Dequantize; - class Quantize; - class QuantizedConcat; - class Tile; - class Gelu; - class RandomUniform; - class GeluBackprop; - } namespace runtime { namespace cpu { - namespace op - { - class ConvertLayout; - } - class CPU_Emitter { public: @@ -218,8 +104,6 @@ namespace ngraph template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::BatchMatMul); template <> - void CPU_Emitter::EMITTER_DECL(ngraph::op::BatchMatMulTranspose); - template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Lstm); template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Rnn); @@ -234,6 +118,8 @@ namespace ngraph template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::BatchNormTrainingBackprop); template <> + void CPU_Emitter::EMITTER_DECL(ngraph::op::CumSum); + template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Dot); template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Multiply); @@ -378,10 +264,6 @@ namespace ngraph template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Not); template <> - void CPU_Emitter::EMITTER_DECL(ngraph::op::QuantizedMaxPool); - template <> - void CPU_Emitter::EMITTER_DECL(ngraph::op::QuantizedAvgPool); - template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::MaxPoolWithIndices); template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Reverse); @@ -444,8 +326,6 @@ namespace ngraph template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Quantize); template <> - void CPU_Emitter::EMITTER_DECL(ngraph::op::QuantizedConcat); - template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Tile); template <> void CPU_Emitter::EMITTER_DECL(ngraph::op::Gelu); diff --git a/src/ngraph/runtime/cpu/cpu_external_function.cpp b/src/ngraph/runtime/cpu/cpu_external_function.cpp index 3910b24cf4b..35eebefdfa8 100644 --- a/src/ngraph/runtime/cpu/cpu_external_function.cpp +++ b/src/ngraph/runtime/cpu/cpu_external_function.cpp @@ -68,6 +68,7 @@ #include "ngraph/op/convolution.hpp" #include "ngraph/op/cos.hpp" #include "ngraph/op/cosh.hpp" +#include "ngraph/op/cum_sum.hpp" #include "ngraph/op/dequantize.hpp" #include "ngraph/op/divide.hpp" #include "ngraph/op/dot.hpp" @@ -174,7 +175,6 @@ #include "ngraph/runtime/cpu/cpu_visualize_tree.hpp" #include "ngraph/runtime/cpu/mkldnn_emitter.hpp" #include "ngraph/runtime/cpu/mkldnn_utils.hpp" -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" #include "ngraph/runtime/cpu/op/batch_norm_relu.hpp" #include "ngraph/runtime/cpu/op/bounded_relu.hpp" #include "ngraph/runtime/cpu/op/conv_add.hpp" @@ -325,8 +325,6 @@ static const runtime::cpu::OpMap dispatcher{ {TI(ngraph::op::Any), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::All), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::BatchMatMul), &runtime::cpu::CPU_Emitter::emit}, - {TI(ngraph::op::BatchMatMulTranspose), - &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Concat), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Divide), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Equal), &runtime::cpu::CPU_Emitter::emit}, @@ -361,6 +359,7 @@ static const runtime::cpu::OpMap dispatcher{ {TI(ngraph::op::Sinh), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Cos), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Cosh), &runtime::cpu::CPU_Emitter::emit}, + {TI(ngraph::op::CumSum), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Tan), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::Tanh), &runtime::cpu::CPU_Emitter::emit}, {TI(ngraph::op::TopK), &runtime::cpu::CPU_Emitter::emit}, @@ -553,6 +552,7 @@ void runtime::cpu::CPU_ExternalFunction::compile(ngraph::pass::PassConfig& pass_ #include "ngraph/runtime/reference/broadcast.hpp" #include "ngraph/runtime/reference/concat.hpp" #include "ngraph/runtime/reference/convolution.hpp" +#include "ngraph/runtime/reference/cum_sum.hpp" #include "ngraph/runtime/reference/dequantize.hpp" #include "ngraph/runtime/reference/dot.hpp" #include "ngraph/runtime/reference/embedding_lookup.hpp" @@ -1264,7 +1264,6 @@ void runtime::cpu::CPU_ExternalFunction::register_common_passes( REGISTER_KNOBBED_PASS(BiDirectionalRnn, true, runtime::cpu::pass) REGISTER_KNOBBED_PASS(CPURnnMatFusion, true, runtime::cpu::pass) REGISTER_KNOBBED_PASS(BatchFusion, true, ngraph::pass) - REGISTER_KNOBBED_PASS(CPUBatchFusion, true, runtime::cpu::pass) REGISTER_KNOBBED_PASS(ReshapeSinking, false, ngraph::pass) REGISTER_KNOBBED_PASS(ReshapeElimination, true, ngraph::pass) REGISTER_KNOBBED_PASS(RecurrentReshapeElimination, false, ngraph::pass) @@ -1376,6 +1375,7 @@ static void dump_one_kernel_with_type(runtime::cpu::CPU_DebugTracer& debug_trace case element::Type_t::f64: case element::Type_t::i16: case element::Type_t::i64: + case element::Type_t::u1: case element::Type_t::u16: case element::Type_t::u32: case element::Type_t::u64: diff --git a/src/ngraph/runtime/cpu/cpu_kernels.hpp b/src/ngraph/runtime/cpu/cpu_kernels.hpp index ef8ab8c68e6..001c009495c 100644 --- a/src/ngraph/runtime/cpu/cpu_kernels.hpp +++ b/src/ngraph/runtime/cpu/cpu_kernels.hpp @@ -275,6 +275,14 @@ namespace ngraph const double value, const std::vector& vmsr, const bool use_seed); + + template + void reference_cumsum(void* input_tensor, + void* axis_tensor, + void* out, + const Shape& tensor_shape, + const bool exclusive, + const bool reverse); } } } diff --git a/src/ngraph/runtime/cpu/kernel/convolution.hpp b/src/ngraph/runtime/cpu/kernel/convolution.hpp index b1b3cf03364..a1b4bb4e77c 100644 --- a/src/ngraph/runtime/cpu/kernel/convolution.hpp +++ b/src/ngraph/runtime/cpu/kernel/convolution.hpp @@ -43,12 +43,12 @@ namespace ngraph const CoordinateDiff& padding_below, const CoordinateDiff& padding_above, const Strides& data_dilation_strides, - void* input_scale = nullptr, - void* input_zero_point = nullptr, - void* filter_scale = nullptr, - void* filter_zero_point = nullptr, - void* output_scale = nullptr, - void* output_zero_point = nullptr) + void* input_scale, + void* input_zero_point, + void* filter_scale, + void* filter_zero_point, + void* output_scale, + void* output_zero_point) { reference::convolution( static_cast(input0), diff --git a/src/ngraph/runtime/cpu/kernel/cum_sum.hpp b/src/ngraph/runtime/cpu/kernel/cum_sum.hpp new file mode 100644 index 00000000000..f2d6c960a97 --- /dev/null +++ b/src/ngraph/runtime/cpu/kernel/cum_sum.hpp @@ -0,0 +1,49 @@ +//***************************************************************************** +// Copyright 2017-2019 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/runtime/cpu/cpu_executor.hpp" +#include "ngraph/runtime/reference/cum_sum.hpp" + +namespace ngraph +{ + namespace runtime + { + namespace cpu + { + namespace kernel + { + template + void reference_cumsum(void* input_tensor, + void* axis_tensor, + void* out, + const Shape& tensor_shape, + const bool exclusive, + const bool reverse) + { + reference::cumsum( + static_cast(input_tensor), + static_cast(axis_tensor), + static_cast(out), + tensor_shape, + exclusive, + reverse); + } + } + } + } +} diff --git a/src/ngraph/runtime/cpu/kernel/dot.hpp b/src/ngraph/runtime/cpu/kernel/dot.hpp index 5f86f98011e..5e620ed8ceb 100644 --- a/src/ngraph/runtime/cpu/kernel/dot.hpp +++ b/src/ngraph/runtime/cpu/kernel/dot.hpp @@ -180,12 +180,12 @@ namespace ngraph const Shape& arg1_shape, const Shape& out_shape, size_t reduction_axes_count, - void* input0_scale = nullptr, - void* input0_zero_point = nullptr, - void* input1_scale = nullptr, - void* input1_zero_point = nullptr, - void* output_scale = nullptr, - void* output_zero_point = nullptr) + void* input0_scale, + void* input0_zero_point, + void* input1_scale, + void* input1_zero_point, + void* output_scale, + void* output_zero_point) { reference::dot( static_cast(arg0), diff --git a/src/ngraph/runtime/cpu/op/gelu_backprop.cpp b/src/ngraph/runtime/cpu/op/gelu_backprop.cpp index 2a9f76181b9..68ebca66757 100644 --- a/src/ngraph/runtime/cpu/op/gelu_backprop.cpp +++ b/src/ngraph/runtime/cpu/op/gelu_backprop.cpp @@ -22,7 +22,7 @@ using namespace ngraph; constexpr NodeTypeInfo op::GeluBackprop::type_info; op::GeluBackprop::GeluBackprop(const Output& arg, const Output& delta) - : BinaryElementwiseArithmetic(arg, delta) + : BinaryElementwiseArithmetic(arg, delta, AutoBroadcastSpec::NONE) { constructor_validate_and_infer_types(); set_output_size(1); diff --git a/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.cpp b/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.cpp index 9b76f73a4f7..75e3a7455c8 100644 --- a/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.cpp +++ b/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.cpp @@ -28,12 +28,12 @@ #include "ngraph/op/broadcast.hpp" #include "ngraph/op/concat.hpp" #include "ngraph/op/dot.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/op/fused/group_conv.hpp" #include "ngraph/op/reshape.hpp" #include "ngraph/op/slice.hpp" #include "ngraph/pattern/matcher.hpp" #include "ngraph/pattern/op/label.hpp" -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" #include "ngraph/util.hpp" using namespace ngraph; @@ -384,109 +384,5 @@ bool runtime::cpu::pass::CPURnnMatFusion::run_on_function(std::shared_ptr fuse_batch_mat_mul_transpose(const std::shared_ptr& n) -{ - const int num_op_branches = 2; - std::shared_ptr input[num_op_branches]; - std::shared_ptr reshape[num_op_branches]; - for (int i = 0; i < num_op_branches; ++i) - { - input[i] = std::make_shared(element::f32, Shape{3, 2, 2}); - auto slice = - std::make_shared(input[i], Coordinate{0, 0, 0}, Coordinate{1, 2, 2}); - auto skip = std::make_shared(slice, pattern::has_class()); - reshape[i] = std::make_shared(skip, AxisVector{0, 1, 2}, Shape{2, 2}); - } - auto dot = std::make_shared(reshape[0], reshape[1]); - auto final_reshape = std::make_shared(dot, AxisVector{0, 1}, Shape{1, 2, 2}); - - auto matcher = std::make_shared(final_reshape); - std::shared_ptr fuse_input[num_op_branches]; - bool transpose[num_op_branches] = {false, false}; - const int num_expected_reshape_with_trans = 3; - - // check each input arg matches the pattern - for (auto arg : n->get_arguments()) - { - if (matcher->match(arg)) - { - auto pattern_map = matcher->get_pattern_map(); - int reshape_count[num_op_branches] = {0, 0}; - // we found a match, determine whether we have to transpose for each input by - // counting the number of reshapes in each branch, if transpose is applied, there - // should be 3 reshapes. - for (int i = 0; i < num_op_branches; ++i) - { - auto iter = matcher->get_match_root(); - auto& input_node = pattern_map[input[i]]; - do - { - if (is_type(iter)) - { - ++reshape_count[i]; - if (reshape_count[i] == num_expected_reshape_with_trans) - { - transpose[i] = true; - break; - } - } - // branch to either input 0 or 1 depending on which one we are traversing - iter = - iter->get_input_size() > 1 ? iter->get_argument(i) : iter->get_argument(0); - } while (iter != input_node); - } - // keep track of the input data, make sure they all match - for (int i = 0; i < num_op_branches; ++i) - { - auto& input_node = pattern_map[input[i]]; - if (fuse_input[i] == nullptr) - { - fuse_input[i] = input_node; - } - // found different input nodes between different args, can't fuse. - else if (fuse_input[i] != input_node) - { - return {nullptr}; - } - } - } - } - if (fuse_input[0] && fuse_input[1]) - { - return std::make_shared( - fuse_input[0], fuse_input[1], transpose[0], transpose[1]); - } - return {nullptr}; -} - -bool runtime::cpu::pass::CPUBatchFusion::run_on_function(std::shared_ptr func) -{ - bool modified = false; - - for (auto n : func->get_ordered_ops()) - { - const Node& node = *n; - if (TI(node) == TI(op::Concat)) - { - if (m_fusion_type.is_set(FusionType::DIFFERENTIABLE_FUSIONS)) - { - if (auto fused_node = fuse_batch_mat_mul_transpose(n)) - { - func->replace_node(n, fused_node); - modified = true; - } - } - if (m_fusion_type.is_set(FusionType::REGULAR_FUSIONS)) - { - // if (auto fused_conv = fuse_group_convolution(n)) - // { - // func->replace_node(n, fused_conv); - // modified = true; - // } - } - } - } - return modified; -} +// Moved set_or_check_if_same and fuse_group_convolution, fuse_batch_mat_mul_transpose +// to core pass batch_fusion diff --git a/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.hpp b/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.hpp index 1ee57712016..cdfb9aaf1ab 100644 --- a/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.hpp +++ b/src/ngraph/runtime/cpu/pass/cpu_mat_fusion.hpp @@ -33,22 +33,6 @@ namespace ngraph virtual bool run_on_function(std::shared_ptr function) override; }; - class CPU_BACKEND_API CPUBatchFusion : public ngraph::pass::FunctionPass - { - public: - typedef ngraph::pass::FusionType FusionType; - typedef ngraph::pass::FusionTypeMask FusionTypeMask; - CPUBatchFusion(FusionTypeMask fusions = FusionType::ALL_FUSIONS) - : FunctionPass() - , m_fusion_type(fusions) - { - } - virtual bool - run_on_function(std::shared_ptr function) override; - - private: - FusionTypeMask m_fusion_type; - }; } } } diff --git a/src/ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.cpp b/src/ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.cpp index c9923e3321f..6722e6d8ad2 100644 --- a/src/ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.cpp +++ b/src/ngraph/runtime/cpu/pass/cpu_post_layout_optimizations.cpp @@ -439,6 +439,10 @@ bool ngraph::runtime::cpu::pass::CPUConvertLayoutConstantFolding::run_on_functio false, "Encountered 'dynamic' element type in construct_constant_convertlayout"); break; + case element::Type_t::u1: + NGRAPH_CHECK( + false, "Encountered 'u1' element type in construct_constant_convertlayout"); + break; case element::Type_t::boolean: replacement = fold_constant_convertlayout_helper( m_input, m_convertlayout, input_md, output_md); diff --git a/src/ngraph/runtime/cpu/unit_test.manifest b/src/ngraph/runtime/cpu/unit_test.manifest index d2510055390..21494b0a355 100644 --- a/src/ngraph/runtime/cpu/unit_test.manifest +++ b/src/ngraph/runtime/cpu/unit_test.manifest @@ -21,6 +21,8 @@ lrn_across_all_dims lrn_across_nw lrn_across_empty lrn_6D_across_2_axes +lrn_2d_across_empty +lrn_2d_across_outermost_axis # ONNX TopK with dynamic K top_k_opset_10 diff --git a/src/ngraph/runtime/executable.hpp b/src/ngraph/runtime/executable.hpp index bf4f7978d8d..22f3822d84c 100644 --- a/src/ngraph/runtime/executable.hpp +++ b/src/ngraph/runtime/executable.hpp @@ -32,7 +32,7 @@ namespace ngraph } } -class ngraph::runtime::Executable +class NGRAPH_API ngraph::runtime::Executable { public: Executable(); diff --git a/src/ngraph/runtime/generic_cpu/CMakeLists.txt b/src/ngraph/runtime/generic_cpu/CMakeLists.txt index 6024c57f8e3..ac53c06140b 100644 --- a/src/ngraph/runtime/generic_cpu/CMakeLists.txt +++ b/src/ngraph/runtime/generic_cpu/CMakeLists.txt @@ -19,7 +19,7 @@ if (NGRAPH_GENERIC_CPU_ENABLE) # if (OPENMP_FOUND) # add_compile_options(${OpenMP_CXX_FLAGS}) # endif() - add_library(gcpu_backend SHARED gcpu_backend.cpp gcpu_executable.cpp node_wrapper.cpp) + add_library(gcpu_backend SHARED gcpu_backend.cpp gcpu_executable.cpp) if(NGRAPH_LIB_VERSIONING_ENABLE) set_target_properties(gcpu_backend PROPERTIES VERSION ${NGRAPH_VERSION} diff --git a/src/ngraph/runtime/generic_cpu/gcpu_executable.cpp b/src/ngraph/runtime/generic_cpu/gcpu_executable.cpp index f7cd248951c..cfd3c428ebb 100644 --- a/src/ngraph/runtime/generic_cpu/gcpu_executable.cpp +++ b/src/ngraph/runtime/generic_cpu/gcpu_executable.cpp @@ -18,9 +18,7 @@ #include "ngraph/cpio.hpp" #include "ngraph/descriptor/layout/dense_tensor_layout.hpp" #include "ngraph/except.hpp" -#include "ngraph/op/convert.hpp" -#include "ngraph/op/select.hpp" -#include "ngraph/op/util/binary_elementwise_comparison.hpp" +#include "ngraph/ops.hpp" #include "ngraph/pass/assign_layout.hpp" #include "ngraph/pass/core_fusion.hpp" #include "ngraph/pass/fused_op_decomposition.hpp" @@ -39,6 +37,27 @@ using namespace ngraph; using descriptor::layout::DenseTensorLayout; +runtime::gcpu::OP_TYPEID runtime::gcpu::GCPUExecutable::get_typeid(const NodeTypeInfo& type_info) +{ + // This expands the op list in op_tbl.hpp into a list of enumerations that look like this: + // {Abs::type_info, OP_TYPEID::Abs}, + // {Acos::type_info, OP_TYPEID::Acos}, + // ... + static const map type_info_map{ +#define NGRAPH_OP(NAME, NAMESPACE) {NAMESPACE::NAME::type_info, OP_TYPEID::NAME}, +#include "ngraph/opsets/opset0_tbl.hpp" +#undef NGRAPH_OP + }; + OP_TYPEID rc = OP_TYPEID::UnknownOp; + + auto it = type_info_map.find(type_info); + if (it != type_info_map.end()) + { + rc = it->second; + } + return rc; +} + runtime::gcpu::GCPUExecutable::GCPUExecutable(const shared_ptr& function, bool enable_performance_collection) : m_is_compiled{true} @@ -54,9 +73,9 @@ runtime::gcpu::GCPUExecutable::GCPUExecutable(const shared_ptr& functi pass_manager.register_pass(); pass_manager.run_passes(m_function); - for (const shared_ptr& node : m_function->get_ordered_ops()) + for (auto node : m_function->get_ordered_ops()) { - m_wrapped_nodes.emplace_back(node); + m_nodes.push_back(node); } set_parameters_and_results(*m_function); } @@ -66,9 +85,9 @@ runtime::gcpu::GCPUExecutable::GCPUExecutable(const std::string& model_string) , m_performance_counters_enabled{false} { m_function = deserialize(model_string); - for (const shared_ptr& node : m_function->get_ordered_ops()) + for (auto& node : m_function->get_ordered_ops()) { - m_wrapped_nodes.emplace_back(node); + m_nodes.push_back(node); } set_parameters_and_results(*m_function); } @@ -121,10 +140,9 @@ bool runtime::gcpu::GCPUExecutable::call(const vectorget_type_info()); if (type_id == OP_TYPEID::Parameter) { continue; @@ -195,7 +213,7 @@ bool runtime::gcpu::GCPUExecutable::call(const vector>& out, const vector>& in) { @@ -230,9 +248,10 @@ void runtime::gcpu::GCPUExecutable::generate_calls(const element::Type& type, case element::Type_t::u64: op_engine(op, out, in); break; case element::Type_t::undefined: case element::Type_t::dynamic: + case element::Type_t::u1: case element::Type_t::bf16: case element::Type_t::f16: - ss << "unsupported element type " << type << " op " << op.get_node()->get_name(); + ss << "unsupported element type " << type << " op " << op.get_name(); throw ngraph_error(ss.str()); } } diff --git a/src/ngraph/runtime/generic_cpu/gcpu_executable.hpp b/src/ngraph/runtime/generic_cpu/gcpu_executable.hpp index 77924222e55..89b97b2fd95 100644 --- a/src/ngraph/runtime/generic_cpu/gcpu_executable.hpp +++ b/src/ngraph/runtime/generic_cpu/gcpu_executable.hpp @@ -23,58 +23,12 @@ #include #include -#include "ngraph/op/all.hpp" -#include "ngraph/op/allreduce.hpp" -#include "ngraph/op/any.hpp" -#include "ngraph/op/argmax.hpp" -#include "ngraph/op/argmin.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/broadcast_distributed.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/dequantize.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/embedding_lookup.hpp" -#include "ngraph/op/experimental/batch_mat_mul.hpp" -#include "ngraph/op/experimental/dyn_broadcast.hpp" -#include "ngraph/op/experimental/dyn_pad.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/experimental/shape_of.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/lrn.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/min.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/passthrough.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/quantize.hpp" -#include "ngraph/op/quantized_convolution.hpp" -#include "ngraph/op/recv.hpp" -#include "ngraph/op/replace_slice.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/result.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/reverse_sequence.hpp" -#include "ngraph/op/send.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/ops.hpp" #include "ngraph/runtime/aligned_buffer.hpp" #include "ngraph/runtime/backend.hpp" #include "ngraph/runtime/generic_cpu/kernel/broadcast.hpp" #include "ngraph/runtime/generic_cpu/kernel/dot.hpp" #include "ngraph/runtime/generic_cpu/kernel/reshape.hpp" -#include "ngraph/runtime/generic_cpu/node_wrapper.hpp" #include "ngraph/runtime/host_tensor.hpp" #include "ngraph/runtime/reference/abs.hpp" #include "ngraph/runtime/reference/acos.hpp" @@ -169,6 +123,22 @@ namespace ngraph { class GCPUBackend; class GCPUExecutable; + + namespace + { + // This expands the op list in op_tbl.hpp into a list of enumerations that look like + // this: + // Abs, + // Acos, + // ... + enum class OP_TYPEID + { +#define NGRAPH_OP(NAME, NAMESPACE) a, +#include "ngraph/opsets/opset0_tbl.hpp" +#undef NGRAPH_OP + UnknownOp + }; + } } // namespace gcpu } // namespace runtime } // namespace ngraph @@ -199,25 +169,25 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable bool m_performance_counters_enabled = false; std::shared_ptr m_function; std::unordered_map, stopwatch> m_timer_map; - std::vector m_wrapped_nodes; + std::vector> m_nodes; std::unordered_map> m_states; std::set m_unsupported_op_name_list; + static OP_TYPEID get_typeid(const NodeTypeInfo& type_info); + static void perform_nan_check(const std::vector>&, const Node* op = nullptr); void generate_calls(const element::Type& type, - const NodeWrapper& op, + const Node& op, const std::vector>& outputs, const std::vector>& inputs); template - void op_engine(const NodeWrapper& node_wrapper, + void op_engine(const Node& node, const std::vector>& out, const std::vector>& args) { - const Node& node = *node_wrapper.get_node(); - // We want to check that every OP_TYPEID enumeration is included in the list. // These GCC flags enable compile-time checking so that if an enumeration // is not in the list an error is generated. @@ -227,7 +197,7 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable #pragma GCC diagnostic error "-Wswitch-enum" // #pragma GCC diagnostic error "-Wcovered-switch-default" #endif - switch (node_wrapper.get_typeid()) + switch (get_typeid(node.get_type_info())) { case OP_TYPEID::Abs: { @@ -626,6 +596,7 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable break; case element::Type_t::undefined: case element::Type_t::dynamic: + case element::Type_t::u1: case element::Type_t::bf16: case element::Type_t::f16: ss << "unsupported element type " << type << " op Convert"; @@ -970,6 +941,7 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable { const op::LRN* lrn = static_cast(&node); reference::lrn(args[0]->get_data_ptr(), + lrn->get_reduction_axes(), out[0]->get_data_ptr(), node.get_input_shape(0), lrn->get_alpha(), @@ -1597,7 +1569,8 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable node.get_output_shape(0), topk->get_top_k_axis(), topk->get_k(), - topk->get_compute_max()); + topk->get_compute_max(), + topk->get_sort()); } else if (node.get_output_element_type(0) == element::i32) { @@ -1608,7 +1581,8 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable node.get_output_shape(0), topk->get_top_k_axis(), topk->get_k(), - topk->get_compute_max()); + topk->get_compute_max(), + topk->get_sort()); } else { @@ -1616,7 +1590,6 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable } break; } - case OP_TYPEID::LogicalXor: case OP_TYPEID::Xor: { size_t element_count = shape_size(node.get_output_shape(0)); @@ -1626,11 +1599,58 @@ class ngraph::runtime::gcpu::GCPUExecutable : public Executable element_count); break; } + case OP_TYPEID::BatchMatMulTranspose: + case OP_TYPEID::Clamp: + case OP_TYPEID::ConvolutionBias: + case OP_TYPEID::ConvolutionBiasAdd: + case OP_TYPEID::ConvolutionBiasBackpropFiltersBias: + case OP_TYPEID::CropAndResize: + case OP_TYPEID::CrossEntropy: + case OP_TYPEID::CrossEntropyBackprop: + case OP_TYPEID::DepthToSpace: case OP_TYPEID::DynBroadcast: - case OP_TYPEID::Transpose: case OP_TYPEID::DynPad: - case OP_TYPEID::Tile: case OP_TYPEID::DynReplaceSlice: + case OP_TYPEID::Elu: + case OP_TYPEID::FakeQuantize: + case OP_TYPEID::GroupConvolution: + case OP_TYPEID::GRN: + case OP_TYPEID::GRUCell: + case OP_TYPEID::Gelu: + case OP_TYPEID::GeluBackpropFactor: + case OP_TYPEID::Gemm: + case OP_TYPEID::GroupConvolutionTranspose: + case OP_TYPEID::HardSigmoid: + case OP_TYPEID::Interpolate: + case OP_TYPEID::LayerNorm: + case OP_TYPEID::LayerNormBackprop: + case OP_TYPEID::LogSoftmax: + case OP_TYPEID::LSTMCell: + case OP_TYPEID::LSTMSequence: + case OP_TYPEID::MatMul: + case OP_TYPEID::MVN: + case OP_TYPEID::NormalizeL2: + case OP_TYPEID::PRelu: + case OP_TYPEID::PartialSlice: + case OP_TYPEID::PartialSliceBackprop: + case OP_TYPEID::RandomUniform: + case OP_TYPEID::Reciprocal: + case OP_TYPEID::RNNCell: + case OP_TYPEID::ScaleShift: + case OP_TYPEID::Selu: + case OP_TYPEID::ShuffleChannels: + case OP_TYPEID::SoftmaxCrossEntropy: + case OP_TYPEID::SoftmaxCrossEntropyBackprop: + case OP_TYPEID::SpaceToDepth: + case OP_TYPEID::Split: + case OP_TYPEID::SquaredDifference: + case OP_TYPEID::Squeeze: + // Tensor Iterator not yet supported + case OP_TYPEID::TensorIterator: + case OP_TYPEID::Tile: + case OP_TYPEID::Transpose: + case OP_TYPEID::Unsqueeze: + case OP_TYPEID::UnknownOp: throw unsupported_op("Unsupported op '" + node.description() + "'"); #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8) #pragma GCC diagnostic pop diff --git a/src/ngraph/runtime/generic_cpu/kernel/broadcast.hpp b/src/ngraph/runtime/generic_cpu/kernel/broadcast.hpp index f3d4b8e047f..34e4e433ca7 100644 --- a/src/ngraph/runtime/generic_cpu/kernel/broadcast.hpp +++ b/src/ngraph/runtime/generic_cpu/kernel/broadcast.hpp @@ -18,9 +18,12 @@ #include #include -#include #include +#ifdef PARALLEL +#include +#endif + #include "ngraph/runtime/reference/broadcast.hpp" #include "ngraph/shape_util.hpp" #include "ngraph/util.hpp" diff --git a/src/ngraph/runtime/generic_cpu/kernel/dot.hpp b/src/ngraph/runtime/generic_cpu/kernel/dot.hpp index 5317fdba2e6..e2b34eef947 100644 --- a/src/ngraph/runtime/generic_cpu/kernel/dot.hpp +++ b/src/ngraph/runtime/generic_cpu/kernel/dot.hpp @@ -18,9 +18,12 @@ #include #include -#include #include +#ifdef PARALLEL +#include +#endif + #include "ngraph/coordinate_transform.hpp" #include "ngraph/shape_util.hpp" diff --git a/src/ngraph/runtime/generic_cpu/node_wrapper.hpp b/src/ngraph/runtime/generic_cpu/node_wrapper.hpp deleted file mode 100644 index f6c347a408b..00000000000 --- a/src/ngraph/runtime/generic_cpu/node_wrapper.hpp +++ /dev/null @@ -1,59 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2019 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 - -#include "ngraph/node.hpp" - -namespace ngraph -{ - namespace runtime - { - namespace gcpu - { - enum class OP_TYPEID; - class NodeWrapper; - } - } -} - -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// Abs, -// Acos, -// ... -#define NGRAPH_OP(a, b) a, -enum class ngraph::runtime::gcpu::OP_TYPEID -{ -#include "ngraph/op/op_tbl.hpp" -}; -#undef NGRAPH_OP - -/// \brief This class allows adding an enum typeid to each Node. This makes dealing with -/// collections of Nodes a little easier and faster as we can use switch() instead of -/// if/else statements -class ngraph::runtime::gcpu::NodeWrapper -{ -public: - NodeWrapper(const std::shared_ptr& node); - - std::shared_ptr get_node() const { return m_node; } - ngraph::runtime::gcpu::OP_TYPEID get_typeid() const { return m_typeid; } -private: - std::shared_ptr m_node; - OP_TYPEID m_typeid; -}; diff --git a/src/ngraph/runtime/generic_cpu/unit_test.manifest b/src/ngraph/runtime/generic_cpu/unit_test.manifest index 8b137891791..529c6ca6c7c 100644 --- a/src/ngraph/runtime/generic_cpu/unit_test.manifest +++ b/src/ngraph/runtime/generic_cpu/unit_test.manifest @@ -1 +1,2 @@ - +topk_resnet50 +topk_max_sort_none diff --git a/src/ngraph/runtime/host_tensor.hpp b/src/ngraph/runtime/host_tensor.hpp index e86dcd883e6..63d70b70006 100644 --- a/src/ngraph/runtime/host_tensor.hpp +++ b/src/ngraph/runtime/host_tensor.hpp @@ -30,7 +30,7 @@ namespace ngraph } } -class ngraph::runtime::HostTensor : public ngraph::runtime::Tensor +class NGRAPH_API ngraph::runtime::HostTensor : public ngraph::runtime::Tensor { public: HostTensor(const ngraph::element::Type& element_type, diff --git a/src/ngraph/runtime/interpreter/CMakeLists.txt b/src/ngraph/runtime/interpreter/CMakeLists.txt index 0ab34cb0270..f699d4ac086 100644 --- a/src/ngraph/runtime/interpreter/CMakeLists.txt +++ b/src/ngraph/runtime/interpreter/CMakeLists.txt @@ -21,7 +21,7 @@ else() endif() if (NGRAPH_INTERPRETER_ENABLE) - add_library(interpreter_backend ${LIBRARY_TYPE} int_backend.cpp node_wrapper.cpp int_executable.cpp) + add_library(interpreter_backend ${LIBRARY_TYPE} int_backend.cpp int_executable.cpp) target_compile_definitions(interpreter_backend PRIVATE INTERPRETER_BACKEND_EXPORTS) if(NGRAPH_LIB_VERSIONING_ENABLE) set_target_properties(interpreter_backend PROPERTIES diff --git a/src/ngraph/runtime/interpreter/int_executable.cpp b/src/ngraph/runtime/interpreter/int_executable.cpp index 5d388baaf45..5b54b034563 100644 --- a/src/ngraph/runtime/interpreter/int_executable.cpp +++ b/src/ngraph/runtime/interpreter/int_executable.cpp @@ -18,9 +18,7 @@ #include "ngraph/cpio.hpp" #include "ngraph/descriptor/layout/dense_tensor_layout.hpp" #include "ngraph/except.hpp" -#include "ngraph/op/convert.hpp" -#include "ngraph/op/select.hpp" -#include "ngraph/op/util/binary_elementwise_comparison.hpp" +#include "ngraph/ops.hpp" #include "ngraph/pass/assign_layout.hpp" #include "ngraph/pass/core_fusion.hpp" #include "ngraph/pass/fused_op_decomposition.hpp" @@ -39,6 +37,28 @@ using namespace ngraph; using descriptor::layout::DenseTensorLayout; +runtime::interpreter::OP_TYPEID + runtime::interpreter::INTExecutable::get_typeid(const NodeTypeInfo& type_info) +{ + // This expands the op list in op_tbl.hpp into a list of enumerations that look like this: + // {Abs::type_info, OP_TYPEID::Abs}, + // {Acos::type_info, OP_TYPEID::Acos}, + // ... + static const map type_info_map{ +#define NGRAPH_OP(NAME, NAMESPACE) {NAMESPACE::NAME::type_info, OP_TYPEID::ID_SUFFIX(NAME)}, +#include "ngraph/runtime/interpreter/opset_int_tbl.hpp" +#undef NGRAPH_OP + }; + OP_TYPEID rc = OP_TYPEID::UnknownOp; + + auto it = type_info_map.find(type_info); + if (it != type_info_map.end()) + { + rc = it->second; + } + return rc; +} + runtime::interpreter::INTExecutable::INTExecutable(const shared_ptr& function, bool enable_performance_collection) : m_is_compiled{true} @@ -52,10 +72,9 @@ runtime::interpreter::INTExecutable::INTExecutable(const shared_ptr& f pass_manager.register_pass>(); pass_manager.register_pass(); pass_manager.run_passes(m_function); - - for (const shared_ptr& node : m_function->get_ordered_ops()) + for (auto node : m_function->get_ordered_ops()) { - m_wrapped_nodes.emplace_back(node); + m_nodes.push_back(node); } set_parameters_and_results(*m_function); } @@ -65,9 +84,9 @@ runtime::interpreter::INTExecutable::INTExecutable(const std::string& model_stri , m_performance_counters_enabled{false} { m_function = deserialize(model_string); - for (const shared_ptr& node : m_function->get_ordered_ops()) + for (auto node : m_function->get_ordered_ops()) { - m_wrapped_nodes.emplace_back(node); + m_nodes.push_back(node); } set_parameters_and_results(*m_function); } @@ -122,12 +141,10 @@ bool runtime::interpreter::INTExecutable::call(const vectordescription(), "Interpreter"); - auto type_id = wrapped.get_typeid(); - if (type_id == OP_TYPEID::Parameter) + if (op->is_parameter()) { continue; } @@ -164,40 +181,33 @@ bool runtime::interpreter::INTExecutable::call(const vector(op) || is_type(op) || is_type(op) || + is_type(op) || is_type(op)) + { + type = op->get_input_element_type(0); + } + else if (is_type(op) || is_type(op) || is_type(op) || + is_type(op) || is_type(op) || is_type(op)) { - case OP_TYPEID::Convert: - case OP_TYPEID::Quantize: - case OP_TYPEID::Dequantize: - case OP_TYPEID::ArgMin: - case OP_TYPEID::ArgMax: type = op->get_input_element_type(0); break; - case OP_TYPEID::Equal: - case OP_TYPEID::Greater: - case OP_TYPEID::GreaterEq: - case OP_TYPEID::Less: - case OP_TYPEID::LessEq: - case OP_TYPEID::NotEqual: // Get the type of the second input, not the first // All BinaryElementwiseComparision ops have the same type for inputs // Select has bool for first input and the type we are interested in for the second type = op->get_input_element_type(1); - break; - case OP_TYPEID::TopK: type = op->get_output_element_type(1); break; - default: type = op->get_output_element_type(0); break; } -#if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8) -#pragma GCC diagnostic pop -#endif + else if (is_type(op)) + { + type = op->get_output_element_type(1); + } + else + { + type = op->get_output_element_type(0); + } if (m_performance_counters_enabled) { m_timer_map[op].start(); } - generate_calls(type, wrapped, op_outputs, op_inputs); + generate_calls(type, *op.get(), op_outputs, op_inputs); if (m_performance_counters_enabled) { m_timer_map[op].stop(); @@ -212,7 +222,7 @@ bool runtime::interpreter::INTExecutable::call(const vector>& out, const vector>& in) { @@ -232,9 +242,10 @@ void runtime::interpreter::INTExecutable::generate_calls(const element::Type& ty case element::Type_t::u64: op_engine(op, out, in); break; case element::Type_t::undefined: case element::Type_t::dynamic: + case element::Type_t::u1: case element::Type_t::bf16: case element::Type_t::f16: - ss << "unsupported element type " << type << " op " << op.get_node()->get_name(); + ss << "unsupported element type " << type << " op " << op.get_name(); throw ngraph_error(ss.str()); } } diff --git a/src/ngraph/runtime/interpreter/int_executable.hpp b/src/ngraph/runtime/interpreter/int_executable.hpp index aa656fb1f9d..aa8deb2fbdd 100644 --- a/src/ngraph/runtime/interpreter/int_executable.hpp +++ b/src/ngraph/runtime/interpreter/int_executable.hpp @@ -23,75 +23,13 @@ #include #include -#include "ngraph/op/add.hpp" -#include "ngraph/op/all.hpp" -#include "ngraph/op/allreduce.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/any.hpp" -#include "ngraph/op/argmax.hpp" -#include "ngraph/op/argmin.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/binary_convolution.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/broadcast_distributed.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/dequantize.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/embedding_lookup.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/experimental/batch_mat_mul.hpp" -#include "ngraph/op/experimental/dyn_broadcast.hpp" -#include "ngraph/op/experimental/dyn_pad.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/experimental/random_uniform.hpp" -#include "ngraph/op/experimental/shape_of.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/lrn.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/min.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/passthrough.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/quantize.hpp" -#include "ngraph/op/quantized_convolution.hpp" -#include "ngraph/op/quantized_dot.hpp" -#include "ngraph/op/recv.hpp" -#include "ngraph/op/replace_slice.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/result.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/reverse_sequence.hpp" -#include "ngraph/op/send.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/ops.hpp" #include "ngraph/runtime/aligned_buffer.hpp" #include "ngraph/runtime/backend.hpp" #include "ngraph/runtime/host_tensor.hpp" #ifdef INTERPRETER_USE_HYBRID #include "ngraph/runtime/hybrid/op/function_call.hpp" #endif -#include "ngraph/runtime/interpreter/node_wrapper.hpp" #include "ngraph/runtime/reference/abs.hpp" #include "ngraph/runtime/reference/acos.hpp" #include "ngraph/runtime/reference/add.hpp" @@ -117,6 +55,7 @@ #include "ngraph/runtime/reference/copy.hpp" #include "ngraph/runtime/reference/cos.hpp" #include "ngraph/runtime/reference/cosh.hpp" +#include "ngraph/runtime/reference/cum_sum.hpp" #include "ngraph/runtime/reference/dequantize.hpp" #include "ngraph/runtime/reference/divide.hpp" #include "ngraph/runtime/reference/dot.hpp" @@ -187,6 +126,23 @@ namespace ngraph { class INTBackend; class INTExecutable; + + namespace + { + // This expands the op list in op_tbl.hpp into a list of enumerations that look like + // this: + // Abs, + // Acos, + // ... + enum class OP_TYPEID + { +#define NGRAPH_OP(NAME, NAMESPACE) ID_SUFFIX(NAME), +#include "ngraph/runtime/interpreter/opset_int_tbl.hpp" +#undef NGRAPH_OP + UnknownOp + }; + } + } // namespace interpreter } // namespace runtime } // namespace ngraph @@ -229,35 +185,25 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable bool m_performance_counters_enabled = false; std::shared_ptr m_function; std::unordered_map, stopwatch> m_timer_map; - std::vector m_wrapped_nodes; + std::vector> m_nodes; std::unordered_map> m_states; std::set m_unsupported_op_name_list; + static OP_TYPEID get_typeid(const NodeTypeInfo& type_info); + static void perform_nan_check(const std::vector>&, const Node* op = nullptr); void generate_calls(const element::Type& type, - const NodeWrapper& op, + const Node& op, const std::vector>& outputs, const std::vector>& inputs); template - void op_engine(const NodeWrapper& node_wrapper, + void op_engine(const Node& node, const std::vector>& out, const std::vector>& args) { - const Node& node = *node_wrapper.get_node(); - - size_t op_version = node.get_version(); - bool is_op_version_supported = op_version == 0; - NGRAPH_CHECK(is_op_version_supported, - "Unsupported operator version ", - op_version, - " in ", - node, - ".\n", - "INTERPRETER backend currently only supports op in version 0."); - // We want to check that every OP_TYPEID enumeration is included in the list. // These GCC flags enable compile-time checking so that if an enumeration // is not in the list an error is generated. @@ -267,7 +213,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable #pragma GCC diagnostic error "-Wswitch-enum" // #pragma GCC diagnostic error "-Wcovered-switch-default" #endif - switch (node_wrapper.get_typeid()) + switch (get_typeid(node.get_type_info())) { case OP_TYPEID::Abs: { @@ -426,11 +372,6 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable avg_pool->get_include_padding_in_avg_computation()); break; } - case OP_TYPEID::BinaryConvolution: - { - throw unsupported_op("Unsupported op '" + node.description() + "'"); - break; - } case OP_TYPEID::GenerateMask: { bool use_seed = static_cast(args[2]->get_data_ptr()[0]); @@ -672,6 +613,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable break; case element::Type_t::undefined: case element::Type_t::dynamic: + case element::Type_t::u1: case element::Type_t::bf16: case element::Type_t::f16: ss << "unsupported element type " << type << " op Convert"; @@ -746,6 +688,35 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable args[0]->get_data_ptr(), out[0]->get_data_ptr(), element_count); break; } + case OP_TYPEID::CumSum: + { + const op::CumSum* cumsum = static_cast(&node); + auto axis_et = node.get_input_element_type(1); + if (axis_et == element::i32) + { + reference::cumsum(args[0]->get_data_ptr(), + args[1]->get_data_ptr(), + out[0]->get_data_ptr(), + node.get_input_shape(0), + cumsum->is_exclusive(), + cumsum->is_reverse()); + } + else if (axis_et == element::i64) + { + reference::cumsum(args[0]->get_data_ptr(), + args[1]->get_data_ptr(), + out[0]->get_data_ptr(), + node.get_input_shape(0), + cumsum->is_exclusive(), + cumsum->is_reverse()); + } + break; + } + case OP_TYPEID::CropAndResize: + { + throw unsupported_op("Unsupported op '" + node.description() + "'"); + break; + } case OP_TYPEID::Dequantize: { const op::Dequantize* dequantize = static_cast(&node); @@ -1016,7 +987,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable less_eq->get_autob()); break; } - case OP_TYPEID::LessEqual: + case OP_TYPEID::LessEqual_v1: { auto less_eq = static_cast(&node); reference::less_eq(args[0]->get_data_ptr(), @@ -1034,7 +1005,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable args[0]->get_data_ptr(), out[0]->get_data_ptr(), element_count); break; } - case OP_TYPEID::LogicalAnd: + case OP_TYPEID::LogicalAnd_v1: { auto logical_and = static_cast(&node); reference::logical_and(args[0]->get_data_ptr(), @@ -1045,7 +1016,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable logical_and->get_autob()); break; } - case OP_TYPEID::LogicalOr: + case OP_TYPEID::LogicalOr_v1: { auto logical_or = static_cast(&node); reference::logical_or(args[0]->get_data_ptr(), @@ -1056,7 +1027,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable logical_or->get_autob()); break; } - case OP_TYPEID::LogicalXor: + case OP_TYPEID::LogicalXor_v1: { auto logical_xor = static_cast(&node); reference::logical_xor(args[0]->get_data_ptr(), @@ -1170,7 +1141,7 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable args[0]->get_data_ptr(), out[0]->get_data_ptr(), element_count); break; } - case OP_TYPEID::LogicalNot: + case OP_TYPEID::LogicalNot_v1: case OP_TYPEID::Not: { size_t element_count = shape_size(node.get_output_shape(0)); @@ -1550,6 +1521,11 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable throw unsupported_op("Unsupported op '" + node.description() + "'"); break; } + case OP_TYPEID::Reciprocal: + { + throw unsupported_op("Unsupported op '" + node.description() + "'"); + break; + } case OP_TYPEID::Relu: { size_t element_count = shape_size(node.get_output_shape(0)); @@ -1862,11 +1838,59 @@ class ngraph::runtime::interpreter::INTExecutable : public Executable logical_xor->get_autob()); break; } + + // Fused Ops are not supported in interpreter. They need to be decomposed before execution + case OP_TYPEID::Clamp: + case OP_TYPEID::MatMul: + case OP_TYPEID::Split: case OP_TYPEID::DynBroadcast: case OP_TYPEID::Transpose: case OP_TYPEID::DynPad: case OP_TYPEID::Tile: case OP_TYPEID::DynReplaceSlice: + case OP_TYPEID::BatchMatMulTranspose: + case OP_TYPEID::ConvolutionBias: + case OP_TYPEID::ConvolutionBiasAdd: + case OP_TYPEID::ConvolutionBiasBackpropFiltersBias: + case OP_TYPEID::CrossEntropy: + case OP_TYPEID::CrossEntropyBackprop: + case OP_TYPEID::DepthToSpace: + case OP_TYPEID::Elu: + case OP_TYPEID::FakeQuantize: + case OP_TYPEID::GroupConvolution: + case OP_TYPEID::GroupConvolutionBackpropData: + case OP_TYPEID::GroupConvolutionBackpropFilters: + case OP_TYPEID::GRN: + case OP_TYPEID::GRUCell: + case OP_TYPEID::Gelu: + case OP_TYPEID::GeluBackpropFactor: + case OP_TYPEID::Gemm: + case OP_TYPEID::GroupConvolutionTranspose: + case OP_TYPEID::HardSigmoid: + case OP_TYPEID::Interpolate: + case OP_TYPEID::LayerNorm: + case OP_TYPEID::LayerNormBackprop: + case OP_TYPEID::LogSoftmax: + case OP_TYPEID::LSTMCell: + case OP_TYPEID::LSTMSequence: + case OP_TYPEID::MVN: + case OP_TYPEID::NormalizeL2: + case OP_TYPEID::PRelu: + case OP_TYPEID::PartialSlice: + case OP_TYPEID::PartialSliceBackprop: + case OP_TYPEID::RNNCell: + case OP_TYPEID::ScaleShift: + case OP_TYPEID::Selu: + case OP_TYPEID::ShuffleChannels: + case OP_TYPEID::SoftmaxCrossEntropy: + case OP_TYPEID::SoftmaxCrossEntropyBackprop: + case OP_TYPEID::SpaceToDepth: + case OP_TYPEID::SquaredDifference: + case OP_TYPEID::Squeeze: + case OP_TYPEID::Unsqueeze: + // Tensor Iterator not yet supported + case OP_TYPEID::TensorIterator: + case OP_TYPEID::UnknownOp: throw unsupported_op("Unsupported op '" + node.description() + "'"); #if defined(__GNUC__) && !(__GNUC__ == 4 && __GNUC_MINOR__ == 8) #pragma GCC diagnostic pop diff --git a/src/ngraph/runtime/interpreter/node_wrapper.cpp b/src/ngraph/runtime/interpreter/node_wrapper.cpp deleted file mode 100644 index cdcaf8a46d4..00000000000 --- a/src/ngraph/runtime/interpreter/node_wrapper.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2019 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 "ngraph/runtime/interpreter/node_wrapper.hpp" - -using namespace ngraph; -using namespace std; - -runtime::interpreter::NodeWrapper::NodeWrapper(const shared_ptr& node) - : m_node{node} -{ -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// {"Abs", runtime::interpreter::OP_TYPEID::Abs}, -// {"Acos", runtime::interpreter::OP_TYPEID::Acos}, -// ... -#define NGRAPH_OP(a, b) {#a, runtime::interpreter::OP_TYPEID::a}, - static unordered_map typeid_map{ -#include "ngraph/op/op_tbl.hpp" -#ifdef INTERPRETER_USE_HYBRID -#include "ngraph/runtime/hybrid/op/op_tbl.hpp" -#endif - }; -#undef NGRAPH_OP - - auto it = typeid_map.find(m_node->description()); - if (it != typeid_map.end()) - { - m_typeid = it->second; - } - else - { - throw unsupported_op("Unsupported op '" + m_node->description() + "'"); - } -} diff --git a/src/ngraph/runtime/interpreter/node_wrapper.hpp b/src/ngraph/runtime/interpreter/node_wrapper.hpp deleted file mode 100644 index a0e49c9554e..00000000000 --- a/src/ngraph/runtime/interpreter/node_wrapper.hpp +++ /dev/null @@ -1,62 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2019 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 - -#include "ngraph/node.hpp" - -namespace ngraph -{ - namespace runtime - { - namespace interpreter - { - enum class OP_TYPEID; - class NodeWrapper; - } - } -} - -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// Abs, -// Acos, -// ... -#define NGRAPH_OP(a, b) a, -enum class ngraph::runtime::interpreter::OP_TYPEID -{ -#include "ngraph/op/op_tbl.hpp" -#ifdef INTERPRETER_USE_HYBRID -#include "ngraph/runtime/hybrid/op/op_tbl.hpp" -#endif -}; -#undef NGRAPH_OP - -/// \brief This class allows adding an enum typeid to each Node. This makes dealing with -/// collections of Nodes a little easier and faster as we can use switch() instead of -/// if/else statements -class ngraph::runtime::interpreter::NodeWrapper -{ -public: - NodeWrapper(const std::shared_ptr& node); - - std::shared_ptr get_node() const { return m_node; } - ngraph::runtime::interpreter::OP_TYPEID get_typeid() const { return m_typeid; } -private: - std::shared_ptr m_node; - OP_TYPEID m_typeid; -}; diff --git a/src/ngraph/runtime/interpreter/opset_int_tbl.hpp b/src/ngraph/runtime/interpreter/opset_int_tbl.hpp new file mode 100644 index 00000000000..4cbdd6d8111 --- /dev/null +++ b/src/ngraph/runtime/interpreter/opset_int_tbl.hpp @@ -0,0 +1,27 @@ +//***************************************************************************** +// Copyright 2017-2019 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. +//***************************************************************************** + +#define ID_SUFFIX(NAME) NAME +#include "ngraph/opsets/opset0_tbl.hpp" +#undef ID_SUFFIX + +#define ID_SUFFIX(NAME) NAME##_v1 +NGRAPH_OP(LessEqual, op::v1) +NGRAPH_OP(LogicalAnd, op::v1) +NGRAPH_OP(LogicalOr, op::v1) +NGRAPH_OP(LogicalXor, op::v1) +NGRAPH_OP(LogicalNot, op::v1) +#undef ID_SUFFIX diff --git a/src/ngraph/runtime/performance_counter.hpp b/src/ngraph/runtime/performance_counter.hpp index 98a098a15ee..809fd525427 100644 --- a/src/ngraph/runtime/performance_counter.hpp +++ b/src/ngraph/runtime/performance_counter.hpp @@ -25,7 +25,7 @@ namespace ngraph { namespace runtime { - class PerformanceCounter + class NGRAPH_API PerformanceCounter { public: PerformanceCounter(const std::shared_ptr& n, size_t us, size_t calls) diff --git a/src/ngraph/runtime/plaidml/plaidml_compiler.cpp b/src/ngraph/runtime/plaidml/plaidml_compiler.cpp index 2847e0d4dac..f0d24f49eec 100644 --- a/src/ngraph/runtime/plaidml/plaidml_compiler.cpp +++ b/src/ngraph/runtime/plaidml/plaidml_compiler.cpp @@ -91,15 +91,8 @@ std::shared_ptr // We apply the same general-purposes passes as the CPU backend. pass_manager.register_pass([](const Node& node) -> bool { - if (node.description() == ngraph::op::GroupConvolution().description()) - { - return true; - } - else if (node.description() == ngraph::op::LayerNorm().description()) - { - return true; - } - return false; + return ngraph::is_type(&node) || + ngraph::is_type(&node); }); pass_manager.register_pass(); pass_manager.register_pass(); diff --git a/src/ngraph/runtime/plaidml/unit_test.manifest b/src/ngraph/runtime/plaidml/unit_test.manifest index f6f0e23b16e..a38ddd619a4 100644 --- a/src/ngraph/runtime/plaidml/unit_test.manifest +++ b/src/ngraph/runtime/plaidml/unit_test.manifest @@ -15,6 +15,7 @@ min_3d_eliminate_zero_dim # Out-of-range for PlaidML reverse_sequence_n2c3h4w2 # No plans to implement ReverseSequence reverse_sequence_n4c3h2w2 # No plans to implement ReverseSequence reverse_sequence_n4d2c3h2w2 # No plans to implement ReverseSequence +reverse_sequence_negative_axes # No plans to implement ReverseSequence topk_1d_max_all # No plans to implement TopK topk_1d_max_partial # No plans to implement TopK topk_1d_max_one # No plans to implement TopK @@ -147,6 +148,7 @@ pad_reflect_1d_multi_reflect pad_reflect_2d pad_reflect_2d_with_neg pad_symmetric +cross_entropy_with_one_hot # No double precision FP support in PlaidML sum_trivial_in_double @@ -240,6 +242,16 @@ gather_no_axis_bool batch_mat_mul_forward backwards_batchmatmul_tensor2_tensor2 +# unsupported op: `CumSum` +cum_sum_default +cum_sum_2dim +cum_sum_3d +cum_sum_2dim_allmodes +model_cum_sum_1d +model_cum_sum_2d_axis_input +model_cum_sum_2d_dynamic_axis_input +model_cum_sum_3d_exclusive_reverse + # onnx tests model_quant_conv_linear_2d model_quant_conv_linear_3d @@ -289,6 +301,8 @@ lrn_across_all_dims lrn_across_nw lrn_across_empty lrn_6D_across_2_axes +lrn_2d_across_empty +lrn_2d_across_outermost_axis # RandomUniform not supported in PlaidML backend random_uniform_all_static_seed_unused @@ -319,3 +333,6 @@ tile_3d_few_repeats # dyn shape dyn_generate_mask + +# Test fails on intel gpu mac +model_mod diff --git a/src/ngraph/runtime/reference/broadcast.hpp b/src/ngraph/runtime/reference/broadcast.hpp index ea092159d94..566c5e07a1f 100644 --- a/src/ngraph/runtime/reference/broadcast.hpp +++ b/src/ngraph/runtime/reference/broadcast.hpp @@ -34,13 +34,31 @@ namespace ngraph const Shape& out_shape, const AxisSet& broadcast_axes) { - CoordinateTransform input_transform(in_shape); + // Remove all broadcast axes from in_shape + Shape adjusted_in_shape; + for (auto length : in_shape) + { + if (length != 1) + { + adjusted_in_shape.push_back(length); + } + } + // Remove 1s from out_shape + AxisSet adjusted_axes(broadcast_axes); + for (uint64_t axis = 0; axis < out_shape.size(); ++axis) + { + auto length = out_shape.at(axis); + if (length == 1) + { + adjusted_axes.insert(axis); + } + } + CoordinateTransform input_transform(adjusted_in_shape); CoordinateTransform output_transform(out_shape); for (const Coordinate& output_coord : output_transform) { - Coordinate input_coord = reduce(output_coord, broadcast_axes); - + Coordinate input_coord = reduce(output_coord, adjusted_axes); out[output_transform.index(output_coord)] = arg[input_transform.index(input_coord)]; } diff --git a/src/ngraph/runtime/reference/cum_sum.hpp b/src/ngraph/runtime/reference/cum_sum.hpp new file mode 100644 index 00000000000..42eea8e80ff --- /dev/null +++ b/src/ngraph/runtime/reference/cum_sum.hpp @@ -0,0 +1,142 @@ +//***************************************************************************** +// Copyright 2017-2019 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 + +#include "ngraph/coordinate_transform.hpp" +#include "ngraph/type/bfloat16.hpp" +#include "ngraph/type/float16.hpp" + +namespace ngraph +{ + namespace runtime + { + namespace reference + { + template + void cumsum(const T* arg, + const P* axis_tensor, + T* out, + const Shape& tensor_shape, + const bool exclusive, + const bool reverse) + { + CoordinateTransform temp_transform(tensor_shape); + for (const Coordinate& output_coord : temp_transform) + { + out[temp_transform.index(output_coord)] = 0; + } + + P axis = axis_tensor[0]; + P rank = tensor_shape.size(); + + if (axis < -rank || axis > rank) + { + throw ngraph_error("axis must be in the range [-rank, rank]"); + } + axis = axis < 0 ? rank + axis : axis; + + auto get_key = [&, axis](const Coordinate& coord) -> Coordinate { + Coordinate result(coord.size(), 0); + result[axis] = coord[axis]; + + for (size_t i = 0; i < coord.size(); i++) + { + result[i] = coord[i] - result[i]; + } + return result; + }; + + auto update_output_buffer = + [&](size_t input_index, + size_t output_index, + T& prev, + std::vector>& tensor_vec) -> void { + + tensor_vec[input_index].second = prev + tensor_vec[input_index].second; + out[tensor_vec[output_index].first] = tensor_vec[input_index].second; + + // update prev to hold the last result value to compute ruuning sum for + // subsequent iter + prev = out[tensor_vec[output_index].first]; + }; + + auto cum_sum = + [&, exclusive, reverse](std::vector>& tensor_vec) { + if (!reverse) + { + T prev = 0; + for (size_t i = 0; i < tensor_vec.size(); i++) + { + if (exclusive && i == 0) + { + out[tensor_vec[i].first] = prev; + continue; + } + // we will compute running sum of j-1 elements if exlusive=1 or else + // for j elements if exclusive = 0 + size_t arg_index = exclusive == 1 ? i - 1 : i; + update_output_buffer(arg_index, i, prev, tensor_vec); + } + } + else // reverse == true + { + T prev = 0; + for (size_t i = tensor_vec.size(); i-- > 0;) + { + if (exclusive && i == tensor_vec.size() - 1) + { + out[tensor_vec[i].first] = prev; + continue; + } + // we will compute running sum of j-1 elements if exlusive=1 or else + // for j elements if exclusive = 0 + size_t arg_index = exclusive == 1 ? i + 1 : i; + update_output_buffer(arg_index, i, prev, tensor_vec); + } + } + }; + + // Map to collect tensor elements belonging to the same axis + std::map>> map_cooord_to_val; + CoordinateTransform input_transform(tensor_shape); + for (const Coordinate& input_coord : input_transform) + { + // points to the current element in the input tensor + T current = arg[input_transform.index(input_coord)]; + auto key = get_key(input_coord); + auto index = input_transform.index(input_coord); + if (map_cooord_to_val.find(key) != map_cooord_to_val.end()) + { + map_cooord_to_val[key].push_back(std::make_pair(index, current)); + } + else + { + map_cooord_to_val.insert({key, std::vector>()}); + map_cooord_to_val[key].push_back(std::make_pair(index, current)); + } + } + // iterate the map and perform cumulative sum over the give axis + for (auto& it : map_cooord_to_val) + { + cum_sum(it.second); + } + } + } + } +} diff --git a/src/ngraph/runtime/tensor.hpp b/src/ngraph/runtime/tensor.hpp index 47ddb646086..22732a97a1a 100644 --- a/src/ngraph/runtime/tensor.hpp +++ b/src/ngraph/runtime/tensor.hpp @@ -35,7 +35,7 @@ namespace ngraph namespace runtime { - class Tensor + class NGRAPH_API Tensor { protected: Tensor(const std::shared_ptr& descriptor) @@ -105,7 +105,9 @@ namespace ngraph /// \brief copy bytes directly from source to this tensor /// \param source The source tensor - virtual void copy_from(const ngraph::runtime::Tensor& source); + virtual void copy_from(const ngraph::runtime::Tensor& source) NGRAPH_DEPRECATED( + "Allocate buf_ptr with size=get_size_in_bytes(), then use source.read(buf_ptr, " + "size) followed by this->write(buf_ptr, size)"); protected: std::shared_ptr m_descriptor; diff --git a/src/ngraph/serializer.cpp b/src/ngraph/serializer.cpp index 20c7ffa64d4..51c9f6311e7 100644 --- a/src/ngraph/serializer.cpp +++ b/src/ngraph/serializer.cpp @@ -22,142 +22,7 @@ #include "ngraph/cpio.hpp" #include "ngraph/file_util.hpp" #include "ngraph/graph_util.hpp" -#include "ngraph/op/abs.hpp" -#include "ngraph/op/acos.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/all.hpp" -#include "ngraph/op/allreduce.hpp" -#include "ngraph/op/and.hpp" -#include "ngraph/op/any.hpp" -#include "ngraph/op/argmax.hpp" -#include "ngraph/op/argmin.hpp" -#include "ngraph/op/asin.hpp" -#include "ngraph/op/atan.hpp" -#include "ngraph/op/atan2.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/binary_convolution.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/broadcast_distributed.hpp" -#include "ngraph/op/ceiling.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convert.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/cos.hpp" -#include "ngraph/op/cosh.hpp" -#include "ngraph/op/dequantize.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/embedding_lookup.hpp" -#include "ngraph/op/equal.hpp" -#include "ngraph/op/erf.hpp" -#include "ngraph/op/exp.hpp" -#include "ngraph/op/experimental/batch_mat_mul.hpp" -#include "ngraph/op/experimental/compiled_kernel.hpp" -#include "ngraph/op/experimental/dyn_broadcast.hpp" -#include "ngraph/op/experimental/dyn_pad.hpp" -#include "ngraph/op/experimental/dyn_replace_slice.hpp" -#include "ngraph/op/experimental/dyn_reshape.hpp" -#include "ngraph/op/experimental/dyn_slice.hpp" -#include "ngraph/op/experimental/generate_mask.hpp" -#include "ngraph/op/experimental/quantized_conv_bias.hpp" -#include "ngraph/op/experimental/quantized_conv_relu.hpp" -#include "ngraph/op/experimental/quantized_dot_bias.hpp" -#include "ngraph/op/experimental/random_uniform.hpp" -#include "ngraph/op/experimental/range.hpp" -#include "ngraph/op/experimental/shape_of.hpp" -#include "ngraph/op/experimental/tile.hpp" -#include "ngraph/op/experimental/transpose.hpp" -#include "ngraph/op/floor.hpp" -#include "ngraph/op/fused/clamp.hpp" -#include "ngraph/op/fused/conv_fused.hpp" -#include "ngraph/op/fused/depth_to_space.hpp" -#include "ngraph/op/fused/elu.hpp" -#include "ngraph/op/fused/fake_quantize.hpp" -#include "ngraph/op/fused/gelu.hpp" -#include "ngraph/op/fused/gemm.hpp" -#include "ngraph/op/fused/grn.hpp" -#include "ngraph/op/fused/group_conv.hpp" -#include "ngraph/op/fused/group_conv_transpose.hpp" -#include "ngraph/op/fused/gru_cell.hpp" -#include "ngraph/op/fused/hard_sigmoid.hpp" -#include "ngraph/op/fused/layer_norm.hpp" -#include "ngraph/op/fused/lstm_cell.hpp" -#include "ngraph/op/fused/lstm_sequence.hpp" -#include "ngraph/op/fused/matmul.hpp" -#include "ngraph/op/fused/mvn.hpp" -#include "ngraph/op/fused/normalize_l2.hpp" -#include "ngraph/op/fused/partial_slice.hpp" -#include "ngraph/op/fused/prelu.hpp" -#include "ngraph/op/fused/rnn_cell.hpp" -#include "ngraph/op/fused/scale_shift.hpp" -#include "ngraph/op/fused/selu.hpp" -#include "ngraph/op/fused/shuffle_channels.hpp" -#include "ngraph/op/fused/softmax_crossentropy.hpp" -#include "ngraph/op/fused/space_to_depth.hpp" -#include "ngraph/op/fused/split.hpp" -#include "ngraph/op/fused/squared_difference.hpp" -#include "ngraph/op/fused/squeeze.hpp" -#include "ngraph/op/fused/unsqueeze.hpp" -#include "ngraph/op/gather.hpp" -#include "ngraph/op/gather_nd.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/greater.hpp" -#include "ngraph/op/greater_eq.hpp" -#include "ngraph/op/less.hpp" -#include "ngraph/op/less_eq.hpp" -#include "ngraph/op/log.hpp" -#include "ngraph/op/lrn.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/min.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/negative.hpp" -#include "ngraph/op/not.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/or.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/passthrough.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/quantize.hpp" -#include "ngraph/op/quantized_convolution.hpp" -#include "ngraph/op/quantized_dot.hpp" -#include "ngraph/op/recv.hpp" -#include "ngraph/op/reduce_prod.hpp" -#include "ngraph/op/reduce_sum.hpp" -#include "ngraph/op/relu.hpp" -#include "ngraph/op/replace_slice.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/result.hpp" -#include "ngraph/op/reverse.hpp" -#include "ngraph/op/reverse_sequence.hpp" -#include "ngraph/op/scatter_add.hpp" -#include "ngraph/op/scatter_nd_add.hpp" -#include "ngraph/op/select.hpp" -#include "ngraph/op/send.hpp" -#include "ngraph/op/sigmoid.hpp" -#include "ngraph/op/sign.hpp" -#include "ngraph/op/sin.hpp" -#include "ngraph/op/sinh.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/stop_gradient.hpp" -#include "ngraph/op/strided_slice.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/tan.hpp" -#include "ngraph/op/tanh.hpp" -#include "ngraph/op/tensor_iterator.hpp" -#include "ngraph/op/topk.hpp" -#include "ngraph/op/util/attr_types.hpp" -#include "ngraph/op/xor.hpp" +#include "ngraph/ops.hpp" #include "ngraph/provenance.hpp" #include "ngraph/serializer.hpp" #include "ngraph/util.hpp" @@ -181,34 +46,39 @@ bool ngraph::get_serialize_output_shapes() return s_serialize_output_shapes_enabled; } -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// Abs, -// Acos, -// ... -#define NGRAPH_OP(a, b) a, -enum class OP_TYPEID +namespace { -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" - UnknownOp -}; + // This expands the op list in op_tbl.hpp into a list of enumerations that look like this: + // Abs, + // Acos, + // ... + enum class OP_TYPEID + { +#define VSUF0(NAME) NAME +#define VSUF1(NAME) NAME##_v1 +#define NGRAPH_OP(NAME, NAMESPACE, VERSION) VSUF##VERSION(NAME), +#include "ngraph/op/op_version_tbl.hpp" #undef NGRAPH_OP + UnknownOp + }; +} -static OP_TYPEID get_typeid(const string& s) +static OP_TYPEID get_typeid(const NodeTypeInfo& type_info) { -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// {"Abs", OP_TYPEID::Abs}, -// {"Acos", OP_TYPEID::Acos}, -// ... -#define NGRAPH_OP(a, b) {#a, OP_TYPEID::a}, - static const unordered_map typeid_map{ -#include "ngraph/op/fused_op_tbl.hpp" -#include "ngraph/op/op_tbl.hpp" - }; + // This expands the op list in op_tbl.hpp into a list of enumerations that look like this: + // {Abs::type_info, OP_TYPEID::Abs}, + // {Acos::type_info, OP_TYPEID::Acos}, + // ... + static const map type_info_map{ +#define NGRAPH_OP(NAME, NAMESPACE, VERSION) \ + {NAMESPACE::NAME::type_info, OP_TYPEID::VSUF##VERSION(NAME)}, +#include "ngraph/op/op_version_tbl.hpp" #undef NGRAPH_OP + }; OP_TYPEID rc = OP_TYPEID::UnknownOp; - auto it = typeid_map.find(s); - if (it != typeid_map.end()) + + auto it = type_info_map.find(type_info); + if (it != type_info_map.end()) { rc = it->second; } @@ -896,10 +766,19 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) shared_ptr node; try { - string node_name = node_js.at("name").get(); string node_op = node_js.at("op").get(); - string friendly_name = get_value(node_js, "friendly_name"); size_t op_version = get_value(node_js, "op_version"); + NodeTypeInfo type_info{node_op.c_str(), op_version}; + string type_info_name; + if (has_key(node_js, "type_info")) + { + json jtype_info = node_js["type_info"]; + type_info_name = jtype_info.at("name").get(); + type_info.name = type_info_name.c_str(); + type_info.version = jtype_info.at("version").get(); + } + string node_name = node_js.at("name").get(); + string friendly_name = get_value(node_js, "friendly_name"); vector control_deps_inputs = get_value>(node_js, "control_deps"); vector node_outputs = get_value>(node_js, "outputs"); OutputVectorHelper args(deserialize_output_vector(node_js["inputs"])); @@ -911,7 +790,7 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) // #pragma GCC diagnostic error "-Wimplicit-fallthrough" #endif - switch (get_typeid(node_op)) + switch (get_typeid(type_info)) { case OP_TYPEID::Abs: { @@ -925,20 +804,17 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Add: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - break; - } - if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - break; - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Add_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); + break; } case OP_TYPEID::All: { @@ -995,76 +871,75 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) case OP_TYPEID::AvgPool: { - if (op_version == 0) - { - auto window_shape = node_js.at("window_shape").get>(); - auto window_movement_strides = - node_js.at("window_movement_strides").get>(); - auto padding_below = node_js.at("padding_below").get>(); - auto padding_above = node_js.at("padding_above").get>(); - auto include_padding_in_avg_computation = - node_js.at("include_padding_in_avg_computation").get(); - op::PadType pad_type = read_pad_type(node_js); - bool ceil_mode = get_or_default(node_js, "ceil_mode", false); - node = make_shared(args[0], - window_shape, - window_movement_strides, - padding_below, - padding_above, - include_padding_in_avg_computation, - pad_type, - ceil_mode); - } - if (op_version == 1) - { - auto kernel = node_js.at("kernel").get>(); - auto strides = node_js.at("strides").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - auto exclude_pad = node_js.at("exclude_pad").get(); - op::PadType pad_type = read_pad_type(node_js); - op::RoundingType rounding_type = read_rounding_type(node_js); - node = make_shared(args[0], - strides, - pads_begin, - pads_end, - kernel, - exclude_pad, - rounding_type, - pad_type); - } + auto window_shape = node_js.at("window_shape").get>(); + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + auto include_padding_in_avg_computation = + node_js.at("include_padding_in_avg_computation").get(); + op::PadType pad_type = read_pad_type(node_js); + bool ceil_mode = get_or_default(node_js, "ceil_mode", false); + node = make_shared(args[0], + window_shape, + window_movement_strides, + padding_below, + padding_above, + include_padding_in_avg_computation, + pad_type, + ceil_mode); + break; + } + case OP_TYPEID::AvgPool_v1: + { + auto kernel = node_js.at("kernel").get>(); + auto strides = node_js.at("strides").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + auto exclude_pad = node_js.at("exclude_pad").get(); + op::PadType pad_type = read_pad_type(node_js); + op::RoundingType rounding_type = read_rounding_type(node_js); + node = make_shared(args[0], + strides, + pads_begin, + pads_end, + kernel, + exclude_pad, + rounding_type, + pad_type); + break; } case OP_TYPEID::AvgPoolBackprop: { - if (op_version == 0) - { - auto forward_arg_shape = node_js.at("forward_arg_shape").get>(); - auto window_shape = node_js.at("window_shape").get>(); - auto window_movement_strides = - node_js.at("window_movement_strides").get>(); - auto padding_below = node_js.at("padding_below").get>(); - auto padding_above = node_js.at("padding_above").get>(); - auto include_padding_in_avg_computation = - get_or_default(node_js, "include_padding_in_avg_computation", false); - node = make_shared(forward_arg_shape, - args[0], - window_shape, - window_movement_strides, - padding_below, - padding_above, - include_padding_in_avg_computation); - } - if (op_version == 1) - { - auto kernel = node_js.at("kernel").get>(); - auto strides = node_js.at("strides").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - auto exclude_pad = get_or_default(node_js, "exclude_pad", true); - node = make_shared( - args[0], args[1], strides, pads_begin, pads_end, kernel, exclude_pad); - } + auto forward_arg_shape = node_js.at("forward_arg_shape").get>(); + auto window_shape = node_js.at("window_shape").get>(); + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + auto include_padding_in_avg_computation = + get_or_default(node_js, "include_padding_in_avg_computation", false); + node = make_shared(forward_arg_shape, + args[0], + window_shape, + window_movement_strides, + padding_below, + padding_above, + include_padding_in_avg_computation); + break; + } + + case OP_TYPEID::AvgPoolBackprop_v1: + { + auto kernel = node_js.at("kernel").get>(); + auto strides = node_js.at("strides").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + auto exclude_pad = get_or_default(node_js, "exclude_pad", true); + node = make_shared( + args[0], args[1], strides, pads_begin, pads_end, kernel, exclude_pad); + break; } case OP_TYPEID::BatchMatMul: @@ -1072,7 +947,14 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], args[1]); break; } - + case OP_TYPEID::BatchMatMulTranspose: + { + auto transpose_0 = node_js.at("transpose_0").get(); + auto transpose_1 = node_js.at("transpose_1").get(); + node = + make_shared(args[0], args[1], transpose_0, transpose_1); + break; + } case OP_TYPEID::BatchNormTraining: { auto epsilon = node_js.at("eps").get(); @@ -1096,7 +978,7 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) args[2], args[0], args[1], args[3], args[4], args[5], epsilon); break; } - case OP_TYPEID::BinaryConvolution: + case OP_TYPEID::BinaryConvolution_v1: { auto strides = node_js.at("strides").get>(); auto dilations = node_js.at("dilations").get>(); @@ -1119,17 +1001,15 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Broadcast: { - if (op_version == 0) - { - auto shape = node_js.at("shape").get>(); - auto axes = deserialize_axis_set(node_js.at("axes")); - node = make_shared(args[0], shape, axes); - } - if (op_version == 1) - { - node = make_shared( - args[0], args[1], args[2], read_auto_broadcast(node_js, "auto_broadcast")); - } + auto shape = node_js.at("shape").get>(); + auto axes = deserialize_axis_set(node_js.at("axes")); + node = make_shared(args[0], shape, axes); + break; + } + case OP_TYPEID::Broadcast_v1: + { + node = make_shared( + args[0], args[1], args[2], read_auto_broadcast(node_js, "auto_broadcast")); break; } case OP_TYPEID::BroadcastDistributed: @@ -1177,137 +1057,160 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], target_type); break; } + case OP_TYPEID::ConvertLike_v1: + { + node = make_shared(args[0], args[1]); + break; + } case OP_TYPEID::Convolution: { - if (op_version == 0) + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto window_dilation_strides = + node_js.at("window_dilation_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + + // For backwards compatibility, we accept "image_dilation_strides" in place of + // "data_dilation_strides", and we also allow it to be omitted altogether. + json data_dilation_strides; + if (has_key(node_js, "data_dilation_strides")) { - auto window_movement_strides = - node_js.at("window_movement_strides").get>(); - auto window_dilation_strides = - node_js.at("window_dilation_strides").get>(); - auto padding_below = node_js.at("padding_below").get>(); - auto padding_above = node_js.at("padding_above").get>(); - - // For backwards compatibility, we accept "image_dilation_strides" in place of - // "data_dilation_strides", and we also allow it to be omitted altogether. - json data_dilation_strides; - if (has_key(node_js, "data_dilation_strides")) - { - data_dilation_strides = node_js["data_dilation_strides"]; - } - else if (has_key(node_js, "image_dilation_strides")) - { - data_dilation_strides = node_js["image_dilation_strides"]; - } + data_dilation_strides = node_js["data_dilation_strides"]; + } + else if (has_key(node_js, "image_dilation_strides")) + { + data_dilation_strides = node_js["image_dilation_strides"]; + } - op::PadType pad_type = read_pad_type(node_js); + op::PadType pad_type = read_pad_type(node_js); - if (data_dilation_strides.empty()) - { - node = make_shared(args[0], - args[1], - window_movement_strides, - window_dilation_strides, - padding_below, - padding_above); - } - else - { - node = make_shared( - args[0], - args[1], - window_movement_strides, - window_dilation_strides, - padding_below, - padding_above, - data_dilation_strides.get>(), - pad_type); - } + if (data_dilation_strides.empty()) + { + node = make_shared(args[0], + args[1], + window_movement_strides, + window_dilation_strides, + padding_below, + padding_above); } - if (op_version == 1) + else { - auto strides = node_js.at("strides").get>(); - auto dilations = node_js.at("dilations").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); + node = make_shared( + args[0], + args[1], + window_movement_strides, + window_dilation_strides, + padding_below, + padding_above, + data_dilation_strides.get>(), + pad_type); + } + break; + } + + case OP_TYPEID::Convolution_v1: + { + auto strides = node_js.at("strides").get>(); + auto dilations = node_js.at("dilations").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); - op::PadType auto_pad = read_pad_type(node_js); + op::PadType auto_pad = read_pad_type(node_js); + + node = make_shared( + args[0], args[1], strides, pads_begin, pads_end, dilations, auto_pad); - node = make_shared( - args[0], args[1], strides, pads_begin, pads_end, dilations, auto_pad); - } break; } case OP_TYPEID::ConvolutionBackpropData: { - if (op_version == 0) + auto data_batch_shape = node_js.at("data_batch_shape").get>(); + auto window_movement_strides_forward = + node_js.at("window_movement_strides_forward").get>(); + auto window_dilation_strides_forward = + node_js.at("window_dilation_strides_forward").get>(); + auto padding_below_forward = + node_js.at("padding_below_forward").get>(); + auto padding_above_forward = + node_js.at("padding_above_forward").get>(); + auto data_dilation_strides_forward = + node_js.at("data_dilation_strides_forward").get>(); + node = make_shared(data_batch_shape, + args[0], + args[1], + window_movement_strides_forward, + window_dilation_strides_forward, + padding_below_forward, + padding_above_forward, + data_dilation_strides_forward); + break; + } + case OP_TYPEID::ConvolutionBackpropData_v1: + { + auto strides = node_js.at("strides").get>(); + auto dilations = node_js.at("dilations").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + auto output_padding = node_js.at("output_padding").get>(); + if (args.size() == 3) { - auto data_batch_shape = node_js.at("data_batch_shape").get>(); - auto window_movement_strides_forward = - node_js.at("window_movement_strides_forward").get>(); - auto window_dilation_strides_forward = - node_js.at("window_dilation_strides_forward").get>(); - auto padding_below_forward = - node_js.at("padding_below_forward").get>(); - auto padding_above_forward = - node_js.at("padding_above_forward").get>(); - auto data_dilation_strides_forward = - node_js.at("data_dilation_strides_forward").get>(); - node = make_shared(data_batch_shape, - args[0], + node = make_shared(args[0], args[1], - window_movement_strides_forward, - window_dilation_strides_forward, - padding_below_forward, - padding_above_forward, - data_dilation_strides_forward); + args[2], + strides, + pads_begin, + pads_end, + dilations, + read_pad_type(node_js), + output_padding); } - if (op_version == 1) + else { - auto strides = node_js.at("strides").get>(); - auto dilations = node_js.at("dilations").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - node = make_shared( - args[0], args[1], args[2], strides, dilations, pads_begin, pads_end); + node = make_shared(args[0], + args[1], + strides, + pads_begin, + pads_end, + dilations, + read_pad_type(node_js), + output_padding); } break; } case OP_TYPEID::ConvolutionBackpropFilters: { - if (op_version == 0) - { - auto filters_shape = node_js.at("filters_shape").get>(); - auto window_movement_strides_forward = - node_js.at("window_movement_strides_forward").get>(); - auto window_dilation_strides_forward = - node_js.at("window_dilation_strides_forward").get>(); - auto padding_below_forward = - node_js.at("padding_below_forward").get>(); - auto padding_above_forward = - node_js.at("padding_above_forward").get>(); - auto data_dilation_strides_forward = - node_js.at("data_dilation_strides_forward").get>(); - node = - make_shared(args[0], - filters_shape, - args[1], - window_movement_strides_forward, - window_dilation_strides_forward, - padding_below_forward, - padding_above_forward, - data_dilation_strides_forward); - } - if (op_version == 1) - { - auto filters_shape = node_js.at("filters_shape").get>(); - auto strides = node_js.at("strides").get>(); - auto dilations = node_js.at("dilations").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - node = make_shared( - args[0], args[1], args[2], strides, dilations, pads_begin, pads_end); - } + auto filters_shape = node_js.at("filters_shape").get>(); + auto window_movement_strides_forward = + node_js.at("window_movement_strides_forward").get>(); + auto window_dilation_strides_forward = + node_js.at("window_dilation_strides_forward").get>(); + auto padding_below_forward = + node_js.at("padding_below_forward").get>(); + auto padding_above_forward = + node_js.at("padding_above_forward").get>(); + auto data_dilation_strides_forward = + node_js.at("data_dilation_strides_forward").get>(); + node = make_shared(args[0], + filters_shape, + args[1], + window_movement_strides_forward, + window_dilation_strides_forward, + padding_below_forward, + padding_above_forward, + data_dilation_strides_forward); + break; + } + case OP_TYPEID::ConvolutionBackpropFilters_v1: + { + auto filters_shape = node_js.at("filters_shape").get>(); + auto strides = node_js.at("strides").get>(); + auto dilations = node_js.at("dilations").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + node = make_shared( + args[0], args[1], args[2], strides, dilations, pads_begin, pads_end); + break; } case OP_TYPEID::ConvolutionBias: @@ -1387,13 +1290,74 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0]); break; } - case OP_TYPEID::DepthToSpace: + case OP_TYPEID::CumSum: + { + auto exclusive = node_js.at("exclusive"); + auto reverse = node_js.at("reverse"); + node = make_shared(args[0], args[1], exclusive, reverse); + break; + } + case OP_TYPEID::CrossEntropy: + { + auto soft_label = node_js.at("soft_label"); + auto ignore_index = node_js.at("ignore_index"); + node = make_shared(args[0], args[1], soft_label, ignore_index); + break; + } + case OP_TYPEID::CrossEntropyBackprop: + { + auto soft_label = node_js.at("soft_label"); + auto ignore_index = node_js.at("ignore_index"); + node = make_shared( + args[0], args[1], args[2], soft_label, ignore_index); + break; + } + case OP_TYPEID::CropAndResize: + { + auto resize_method = + as_type(node_js.at("resize_method").get()); + auto extrapolation_value = node_js.at("extrapolation_value").get(); + node = make_shared( + args[0], args[1], args[2], args[3], resize_method, extrapolation_value); + break; + } + case OP_TYPEID::CompiledKernel: { break; + } + case OP_TYPEID::CTCGreedyDecoder: { break; + } + case OP_TYPEID::DeformablePSROIPooling_v1: + { + const auto output_dim = node_js.at("output_dim").get(); + const auto spatial_scale = node_js.at("spatial_scale").get(); + const auto group_size = node_js.at("group_size").get(); + const auto mode = node_js.at("mode").get(); + const auto spatial_bins_x = node_js.at("spatial_bins_x").get(); + const auto spatial_bins_y = node_js.at("spatial_bins_y").get(); + const auto trans_std = node_js.at("trans_std").get(); + const auto part_size = node_js.at("part_size").get(); + + node = make_shared(args[0], + args[1], + args[2], + output_dim, + spatial_scale, + group_size, + mode, + spatial_bins_x, + spatial_bins_y, + trans_std, + part_size); + break; + } + case OP_TYPEID::DepthToSpace_v1: { auto mode = node_js.at("mode").get(); auto block_size = node_js.at("block_size").get(); node = make_shared(args[0], mode, block_size); break; } + case OP_TYPEID::DetectionOutput: { break; + } case OP_TYPEID::Dequantize: { auto type = read_element_type(node_js.at("type")); @@ -1404,19 +1368,18 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) case OP_TYPEID::Divide: { bool pythondiv = get_or_default(node_js, "pythondiv", true); - if (op_version == 0) - { - node = make_shared( - args[0], args[1], pythondiv, read_auto_broadcast(node_js, "auto_broadcast")); - } - if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - pythondiv, - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], pythondiv, read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Divide_v1: + { + bool pythondiv = get_or_default(node_js, "pythondiv", true); + node = make_shared( + args[0], + args[1], + pythondiv, + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::Dot: @@ -1465,14 +1428,13 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) case OP_TYPEID::DynReshape: { const auto zero_flag = node_js.at("zero_flag").get(); - if (op_version == 0) - { - node = make_shared(args[0], args[1], zero_flag); - } - if (op_version == 1) - { - node = make_shared(args[0], args[1], zero_flag); - } + node = make_shared(args[0], args[1], zero_flag); + break; + } + case OP_TYPEID::Reshape_v1: + { + const auto zero_flag = node_js.at("zero_flag").get(); + node = make_shared(args[0], args[1], zero_flag); break; } case OP_TYPEID::DynSlice: @@ -1506,23 +1468,21 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Equal: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } - case OP_TYPEID::Erf: + case OP_TYPEID::Equal_v1: { - node = make_shared(args[0]); + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); + break; + } + case OP_TYPEID::Erf: + { + node = make_shared(args[0]); break; } case OP_TYPEID::Exp: @@ -1542,17 +1502,21 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0]); break; } + case OP_TYPEID::FloorMod_v1: + { + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } case OP_TYPEID::Gather: { - if (op_version == 0) - { - auto axis = node_js.at("axis").get(); - node = make_shared(args[0], args[1], axis); - } - if (op_version == 1) - { - node = make_shared(args[0], args[1], args[2]); - } + auto axis = node_js.at("axis").get(); + node = make_shared(args[0], args[1], axis); + break; + } + case OP_TYPEID::Gather_v1: + { + node = make_shared(args[0], args[1], args[2]); break; } case OP_TYPEID::GatherND: @@ -1560,6 +1524,11 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], args[1]); break; } + case OP_TYPEID::GatherTree_v1: + { + node = make_shared(args[0], args[1], args[2], args[3]); + break; + } case OP_TYPEID::Gelu: { node = make_shared(args[0]); @@ -1586,18 +1555,22 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) auto probability = node_js.at("probability").get(); bool use_seed = get_or_default(node_js, "use_seed", false); - if (op_version == 0) - { - auto output_shape = node_js.at("output_shape").get>(); + auto output_shape = node_js.at("output_shape").get>(); - node = make_shared( - args[0], output_shape, type, seed, probability, use_seed); - } - if (op_version == 1) - { - node = make_shared( - args[0], args[1], type, seed, probability, use_seed); - } + node = make_shared( + args[0], output_shape, type, seed, probability, use_seed); + + break; + } + case OP_TYPEID::GenerateMask_v1: + { + auto type = read_element_type(node_js.at("type")); + auto seed = node_js.at("seed").get(); + auto probability = node_js.at("probability").get(); + bool use_seed = get_or_default(node_js, "use_seed", false); + + node = make_shared( + args[0], args[1], type, seed, probability, use_seed); break; } @@ -1610,34 +1583,30 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Greater: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Greater_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::GreaterEq: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::GreaterEqual_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::GRN: @@ -1669,6 +1638,46 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) pad_type); break; } + case OP_TYPEID::GroupConvolutionBackpropData: + { + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto window_dilation_strides = + node_js.at("window_dilation_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + auto groups = node_js.at("groups").get(); + + node = make_shared(args[0], + args[1], + args[2], + window_movement_strides, + window_dilation_strides, + padding_below, + padding_above, + groups); + break; + } + case OP_TYPEID::GroupConvolutionBackpropFilters: + { + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto window_dilation_strides = + node_js.at("window_dilation_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + auto groups = node_js.at("groups").get(); + + node = make_shared(args[0], + args[1], + args[2], + window_movement_strides, + window_dilation_strides, + padding_below, + padding_above, + groups); + break; + } case OP_TYPEID::GroupConvolutionTranspose: { auto strides = node_js.at("strides").get>(); @@ -1715,11 +1724,11 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::HardSigmoid: { - auto alpha = node_js.at("alpha").get(); - auto beta = node_js.at("beta").get(); - node = make_shared(args[0], alpha, beta); + node = make_shared(args[0], args[1], args[2]); break; } + case OP_TYPEID::Interpolate: { break; + } case OP_TYPEID::LayerNorm: { auto keep_stats = node_js.at("keep_stats").get(); @@ -1767,18 +1776,16 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Less: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - else if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Less_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::LessEq: @@ -1787,7 +1794,7 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } - case OP_TYPEID::LessEqual: + case OP_TYPEID::LessEqual_v1: { node = make_shared( args[0], @@ -1800,29 +1807,35 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0]); break; } - case OP_TYPEID::LogicalAnd: + case OP_TYPEID::LogicalAnd_v1: { node = make_shared( args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } - case OP_TYPEID::LogicalNot: + case OP_TYPEID::LogicalNot_v1: { node = make_shared(args[0]); break; } - case OP_TYPEID::LogicalOr: + case OP_TYPEID::LogicalOr_v1: { node = make_shared( args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } - case OP_TYPEID::LogicalXor: + case OP_TYPEID::LogicalXor_v1: { node = make_shared( args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } + case OP_TYPEID::LogSoftmax: + { + auto axis = node_js.at("axis").get(); + node = make_shared(args[0], axis); + break; + } case OP_TYPEID::LRN: { auto alpha = node_js.at("alpha").get(); @@ -1953,120 +1966,122 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], reduction_axes); break; } + case OP_TYPEID::ReduceMax_v1: + { + node = make_shared(args[0], args[1]); + break; + } case OP_TYPEID::MaxPool: { - if (op_version == 0) + auto window_shape = node_js.at("window_shape").get>(); + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + // For backwards compatibility, both (but not just one) of the padding_ fields may + // be omitted. + auto padding_below_maybe = get_or_default(node_js, "padding_below", json{}); + auto padding_above_maybe = get_or_default(node_js, "padding_above", json{}); + op::PadType pad_type = read_pad_type(node_js); + if (padding_below_maybe.empty() && !padding_above_maybe.empty()) { - auto window_shape = node_js.at("window_shape").get>(); - auto window_movement_strides = - node_js.at("window_movement_strides").get>(); - // For backwards compatibility, both (but not just one) of the padding_ fields may - // be omitted. - auto padding_below_maybe = get_or_default(node_js, "padding_below", json{}); - auto padding_above_maybe = get_or_default(node_js, "padding_above", json{}); - op::PadType pad_type = read_pad_type(node_js); - if (padding_below_maybe.empty() && !padding_above_maybe.empty()) - { - throw runtime_error( - "MaxPool: padding_below is absent but padding_above is present"); - } - else if (!padding_below_maybe.empty() && padding_above_maybe.empty()) - { - throw runtime_error( - "MaxPool: padding_below is present but padding_above is absent"); - } - else if (!padding_below_maybe.empty() && !padding_above_maybe.empty()) - { - auto padding_below = padding_below_maybe.get>(); - auto padding_above = padding_above_maybe.get>(); - node = make_shared(args[0], - window_shape, - window_movement_strides, - padding_below, - padding_above, - pad_type); - } - else - { - node = make_shared( - args[0], window_shape, window_movement_strides); - } + throw runtime_error( + "MaxPool: padding_below is absent but padding_above is present"); } - if (op_version == 1) + else if (!padding_below_maybe.empty() && padding_above_maybe.empty()) + { + throw runtime_error( + "MaxPool: padding_below is present but padding_above is absent"); + } + else if (!padding_below_maybe.empty() && !padding_above_maybe.empty()) + { + auto padding_below = padding_below_maybe.get>(); + auto padding_above = padding_above_maybe.get>(); + node = make_shared(args[0], + window_shape, + window_movement_strides, + padding_below, + padding_above, + pad_type); + } + else { - auto kernel = node_js.at("kernel").get>(); - auto strides = node_js.at("strides").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - auto rounding_type = read_rounding_type(node_js); - op::PadType pad_type = read_pad_type(node_js); - node = make_shared( - args[0], strides, pads_begin, pads_end, kernel, rounding_type, pad_type); + node = make_shared(args[0], window_shape, window_movement_strides); } + + break; + } + + case OP_TYPEID::MaxPool_v1: + { + auto kernel = node_js.at("kernel").get>(); + auto strides = node_js.at("strides").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + auto rounding_type = read_rounding_type(node_js); + op::PadType pad_type = read_pad_type(node_js); + node = make_shared( + args[0], strides, pads_begin, pads_end, kernel, rounding_type, pad_type); break; } case OP_TYPEID::MaxPoolBackprop: { - if (op_version == 0) + auto window_shape = node_js.at("window_shape").get>(); + auto window_movement_strides = + node_js.at("window_movement_strides").get>(); + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + if (args.size() == 3) { - auto window_shape = node_js.at("window_shape").get>(); - auto window_movement_strides = - node_js.at("window_movement_strides").get>(); - auto padding_below = node_js.at("padding_below").get>(); - auto padding_above = node_js.at("padding_above").get>(); - if (args.size() == 3) - { - node = make_shared(args[0], - args[1], - args[2], - window_shape, - window_movement_strides, - padding_below, - padding_above); - } - else - { - node = make_shared(args[0], - args[1], - window_shape, - window_movement_strides, - padding_below, - padding_above); - } + node = make_shared(args[0], + args[1], + args[2], + window_shape, + window_movement_strides, + padding_below, + padding_above); } - if (op_version == 1) + else { - auto kernel = node_js.at("kernel").get>(); - auto strides = node_js.at("strides").get>(); - auto pads_begin = node_js.at("pads_begin").get>(); - auto pads_end = node_js.at("pads_end").get>(); - if (args.size() == 3) - { - node = make_shared( - args[0], args[1], args[2], kernel, strides, pads_begin, pads_end); - } - else - { - node = make_shared( - args[0], args[1], kernel, strides, pads_begin, pads_end); - } + node = make_shared(args[0], + args[1], + window_shape, + window_movement_strides, + padding_below, + padding_above); } break; } - case OP_TYPEID::Maximum: + + case OP_TYPEID::MaxPoolBackprop_v1: { - if (op_version == 0) + auto kernel = node_js.at("kernel").get>(); + auto strides = node_js.at("strides").get>(); + auto pads_begin = node_js.at("pads_begin").get>(); + auto pads_end = node_js.at("pads_end").get>(); + if (args.size() == 3) { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + node = make_shared( + args[0], args[1], args[2], kernel, strides, pads_begin, pads_end); } - else if (op_version == 1) + else { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); + node = make_shared( + args[0], args[1], kernel, strides, pads_begin, pads_end); } + + break; + } + case OP_TYPEID::Maximum: + { + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Maximum_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::Min: @@ -2075,36 +2090,43 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], reduction_axes); break; } + case OP_TYPEID::ReduceMin_v1: + { + node = make_shared(args[0], args[1]); + break; + } case OP_TYPEID::Minimum: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - else if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + + case OP_TYPEID::Minimum_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } + case OP_TYPEID::Mod_v1: + { + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + } case OP_TYPEID::Multiply: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - else if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Multiply_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::MVN: @@ -2129,18 +2151,16 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::NotEqual: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - else if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::NotEqual_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::Not: @@ -2150,9 +2170,18 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::OneHot: { - auto shape = node_js.at("shape").get>(); - auto one_hot_axis = node_js.at("one_hot_axis").get(); - node = make_shared(args[0], read_partial_shape(shape), one_hot_axis); + if (op_version == 0) + { + auto shape = node_js.at("shape").get>(); + auto one_hot_axis = node_js.at("one_hot_axis").get(); + node = + make_shared(args[0], read_partial_shape(shape), one_hot_axis); + } + if (op_version == 1) + { + auto axis = node_js.at("axis").get(); + node = make_shared(args[0], args[1], args[2], args[3], axis); + } break; } case OP_TYPEID::Or: @@ -2163,36 +2192,36 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Pad: { - if (op_version == 0) + auto padding_below = node_js.at("padding_below").get>(); + auto padding_above = node_js.at("padding_above").get>(); + + // This is a legacy field whose functionality is no longer supported. The new + // behavior is equivalent to interior padding of 0, so we will accept it under + // those conditions. + auto padding_interior = get_value>(node_js, "padding_interior"); + NGRAPH_CHECK(std::all_of(padding_interior.begin(), + padding_interior.end(), + [](size_t s) { return s == 0; }), + "Legacy padding_interior field must be zero everywhere."); + + auto pad_mode = read_pad_mode(node_js); + + node = + make_shared(args[0], args[1], padding_below, padding_above, pad_mode); + + break; + } + + case OP_TYPEID::Pad_v1: + { + auto pad_mode = read_pad_mode(node_js); + if (args.size() == 4) { - auto padding_below = node_js.at("padding_below").get>(); - auto padding_above = node_js.at("padding_above").get>(); - - // This is a legacy field whose functionality is no longer supported. The new - // behavior is equivalent to interior padding of 0, so we will accept it under - // those conditions. - auto padding_interior = get_value>(node_js, "padding_interior"); - NGRAPH_CHECK(std::all_of(padding_interior.begin(), - padding_interior.end(), - [](size_t s) { return s == 0; }), - "Legacy padding_interior field must be zero everywhere."); - - auto pad_mode = read_pad_mode(node_js); - - node = make_shared( - args[0], args[1], padding_below, padding_above, pad_mode); + node = make_shared(args[0], args[1], args[2], args[3], pad_mode); } - if (op_version == 1) + else { - auto pad_mode = read_pad_mode(node_js); - if (args.size() == 4) - { - node = make_shared(args[0], args[1], args[2], args[3], pad_mode); - } - else - { - node = make_shared(args[0], args[1], args[2], pad_mode); - } + node = make_shared(args[0], args[1], args[2], pad_mode); } break; } @@ -2243,18 +2272,16 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Power: { - if (op_version == 0) - { - node = make_shared( - args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); - } - else if (op_version == 1) - { - node = make_shared( - args[0], - args[1], - read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); - } + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); + break; + } + case OP_TYPEID::Power_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); break; } case OP_TYPEID::PRelu: @@ -2264,21 +2291,28 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Product: { - if (op_version == 0) - { - auto reduction_axes = deserialize_axis_set(node_js.at("reduction_axes")); - if (reduction_axes.empty()) - node = make_shared(args[0], args[1]); - else - node = make_shared(args[0], reduction_axes); - } - if (op_version == 1) - { - auto keep_dims = node_js.at("keep_dims").get(); - node = make_shared(args[0], args[1], keep_dims); - } + auto reduction_axes = deserialize_axis_set(node_js.at("reduction_axes")); + if (reduction_axes.empty()) + node = make_shared(args[0], args[1]); + else + node = make_shared(args[0], reduction_axes); + break; + } + case OP_TYPEID::ReduceProd_v1: + { + auto keep_dims = node_js.at("keep_dims").get(); + node = make_shared(args[0], args[1], keep_dims); break; } + case OP_TYPEID::PSROIPooling: { break; + } + case OP_TYPEID::PriorBox: { break; + } + case OP_TYPEID::PriorBoxClustered: { break; + } + case OP_TYPEID::Proposal: { break; + } + case OP_TYPEID::Quantize: { auto type = read_element_type(node_js.at("type")); @@ -2372,6 +2406,30 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], args[1], args[2]); break; } + case OP_TYPEID::Reciprocal: + { + node = make_shared(args[0]); + break; + } + case OP_TYPEID::ReduceMean_v1: + { + auto keep_dims = node_js.at("keep_dims").get(); + node = make_shared(args[0], args[1], keep_dims); + + break; + } + case OP_TYPEID::ReduceLogicalAnd_v1: + { + const auto keep_dims = node_js.at("keep_dims").get(); + node = make_shared(args[0], args[1], keep_dims); + break; + } + case OP_TYPEID::ReduceLogicalOr_v1: + { + const auto keep_dims = node_js.at("keep_dims").get(); + node = make_shared(args[0], args[1], keep_dims); + break; + } case OP_TYPEID::Relu: { node = make_shared(args[0]); @@ -2407,24 +2465,20 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Reverse: { - if (op_version == 0) - { - const auto reversed_axes = deserialize_axis_set(node_js.at("reversed_axes")); - node = make_shared(args[0], reversed_axes); - break; - } - else if (op_version == 1) - { - const auto mode = node_js.at("mode").get(); - node = make_shared(args[0], args[1], mode); - break; - } + const auto reversed_axes = deserialize_axis_set(node_js.at("reversed_axes")); + node = make_shared(args[0], reversed_axes); + break; + } + case OP_TYPEID::Reverse_v1: + { + const auto mode = node_js.at("mode").get(); + node = make_shared(args[0], args[1], mode); break; } case OP_TYPEID::ReverseSequence: { - auto batch_axis = node_js.at("batch_axis").get(); - auto sequence_axis = node_js.at("sequence_axis").get(); + auto batch_axis = node_js.at("batch_axis").get(); + auto sequence_axis = node_js.at("sequence_axis").get(); node = make_shared(args[0], args[1], batch_axis, sequence_axis); break; } @@ -2447,7 +2501,14 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) clip); break; } - case OP_TYPEID::ScalarConstantLike: + case OP_TYPEID::ROIPooling: { break; + } + case OP_TYPEID::RegionYolo: { break; + } + case OP_TYPEID::ReorgYolo: { break; + } + + case OP_TYPEID::ScalarConstantLikeBase: { double value = node_js.at("value").get(); node = make_shared(args[0], value); @@ -2523,51 +2584,51 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::Slice: { - if (op_version == 0) - { - auto lower_bounds = node_js.at("lower_bounds").get>(); - auto upper_bounds = node_js.at("upper_bounds").get>(); - auto strides = node_js.at("strides").get>(); - node = make_shared(args[0], lower_bounds, upper_bounds, strides); - } - if (op_version == 1) - { - auto begin_mask = node_js.at("begin_mask").get>(); - auto end_mask = node_js.at("end_mask").get>(); - auto new_axis_mask = node_js.at("new_axis_mask").get>(); - auto shrink_axis_mask = node_js.at("shrink_axis_mask").get>(); - auto ellipsis_mask = node_js.at("ellipsis_mask").get>(); - node = make_shared(args[0], - args[1], - args[2], - args[3], - begin_mask, - end_mask, - new_axis_mask, - shrink_axis_mask, - ellipsis_mask); - } + auto lower_bounds = node_js.at("lower_bounds").get>(); + auto upper_bounds = node_js.at("upper_bounds").get>(); + auto strides = node_js.at("strides").get>(); + node = make_shared(args[0], lower_bounds, upper_bounds, strides); + break; + } + + case OP_TYPEID::StridedSlice_v1: + { + auto begin_mask = node_js.at("begin_mask").get>(); + auto end_mask = node_js.at("end_mask").get>(); + auto new_axis_mask = node_js.at("new_axis_mask").get>(); + auto shrink_axis_mask = node_js.at("shrink_axis_mask").get>(); + auto ellipsis_mask = node_js.at("ellipsis_mask").get>(); + node = make_shared(args[0], + args[1], + args[2], + args[3], + begin_mask, + end_mask, + new_axis_mask, + shrink_axis_mask, + ellipsis_mask); + break; } case OP_TYPEID::Softmax: { - if (op_version == 0) + if (has_key(node_js, "softmax_axes")) { - if (has_key(node_js, "softmax_axes")) - { - auto softmax_axes = deserialize_axis_set(node_js.at("softmax_axes")); - node = make_shared(args[0], softmax_axes); - } - else - { - node = make_shared(args[0], args[1]); - } + auto softmax_axes = deserialize_axis_set(node_js.at("softmax_axes")); + node = make_shared(args[0], softmax_axes); } - if (op_version == 1) + else { - size_t softmax_axis = node_js.at("softmax_axis"); - node = make_shared(args[0], softmax_axis); + node = make_shared(args[0], args[1]); } + + break; + } + + case OP_TYPEID::Softmax_v1: + { + size_t softmax_axis = node_js.at("softmax_axis"); + node = make_shared(args[0], softmax_axis); break; } case OP_TYPEID::SoftmaxCrossEntropy: @@ -2588,14 +2649,14 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) case OP_TYPEID::SpaceToDepth: { auto block_size = node_js.at("block_size").get(); - node = make_shared(args[0], block_size); + auto mode = node_js.at("mode").get(); + node = make_shared(args[0], mode, block_size); break; } case OP_TYPEID::Split: { - const auto axis = node_js.at("axis").get(); const auto splits = node_js.at("splits").get>(); - node = make_shared(args[0], axis, splits); + node = make_shared(args[0], args[1], splits); break; } case OP_TYPEID::Sqrt: @@ -2605,7 +2666,8 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::SquaredDifference: { - node = make_shared(args[0], args[1]); + node = make_shared( + args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } case OP_TYPEID::Squeeze: @@ -2619,21 +2681,27 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) args[0], args[1], read_auto_broadcast(node_js, "auto_broadcast")); break; } + case OP_TYPEID::Subtract_v1: + { + node = make_shared( + args[0], + args[1], + read_auto_broadcast(node_js, "auto_broadcast", op::AutoBroadcastType::NUMPY)); + break; + } + case OP_TYPEID::ReduceSum_v1: + { + auto keep_dims = node_js.at("keep_dims").get(); + node = make_shared(args[0], args[1], keep_dims); + break; + } case OP_TYPEID::Sum: { - if (op_version == 0) - { - auto reduction_axes = deserialize_axis_set(node_js.at("reduction_axes")); - if (reduction_axes.empty()) - node = make_shared(args[0], args[1]); - else - node = make_shared(args[0], reduction_axes); - } - if (op_version == 1) - { - auto keep_dims = node_js.at("keep_dims").get(); - node = make_shared(args[0], args[1], keep_dims); - } + auto reduction_axes = deserialize_axis_set(node_js.at("reduction_axes")); + if (reduction_axes.empty()) + node = make_shared(args[0], args[1]); + else + node = make_shared(args[0], reduction_axes); break; } case OP_TYPEID::Tan: @@ -2697,43 +2765,40 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) } case OP_TYPEID::TopK: { - if (op_version == 0) + auto compute_max = node_js.at("compute_max").get(); + auto target_type = read_element_type(node_js.at("index_element_type")); + if (has_key(node_js, "top_k_axis")) { - auto compute_max = node_js.at("compute_max").get(); - auto target_type = read_element_type(node_js.at("index_element_type")); - if (has_key(node_js, "top_k_axis")) + auto top_k_axis = node_js.at("top_k_axis").get(); + if (has_key(node_js, "k")) { - auto top_k_axis = node_js.at("top_k_axis").get(); - if (has_key(node_js, "k")) - { - auto k = node_js.at("k").get(); - node = - make_shared(args[0], top_k_axis, target_type, k, compute_max); - } - else - { - node = make_shared( - args[0], args[1], top_k_axis, target_type, compute_max); - } + auto k = node_js.at("k").get(); + node = make_shared(args[0], top_k_axis, target_type, k, compute_max); } else { - node = - make_shared(args[0], args[1], args[2], target_type, compute_max); + node = make_shared( + args[0], args[1], top_k_axis, target_type, compute_max); } } - else if (op_version == 1) + else { - const auto axis = node_js.at("axis").get(); - const auto mode = node_js.at("mode").get(); - const auto sort_type = node_js.at("sort_type").get(); - const auto index_element_type = read_element_type(node_js.at("index_element_type")); - auto topk = make_shared(args[0], args[1], axis, mode, sort_type); - topk->set_index_element_type(index_element_type); - node = move(topk); + node = make_shared(args[0], args[1], args[2], target_type, compute_max); } break; } + + case OP_TYPEID::TopK_v1: + { + const auto axis = node_js.at("axis").get(); + const auto mode = node_js.at("mode").get(); + const auto sort_type = node_js.at("sort_type").get(); + const auto index_element_type = read_element_type(node_js.at("index_element_type")); + auto topk = make_shared(args[0], args[1], axis, mode, sort_type); + topk->set_index_element_type(index_element_type); + node = move(topk); + break; + } case OP_TYPEID::Transpose: { node = make_shared(args[0], args[1]); @@ -2749,6 +2814,11 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) node = make_shared(args[0], args[1]); break; } + case OP_TYPEID::VariadicSplit_v1: + { + node = make_shared(args[0], args[1], args[2]); + break; + } case OP_TYPEID::Xor: { node = make_shared( @@ -2758,7 +2828,7 @@ shared_ptr JSONDeserializer::deserialize_node(json node_js) case OP_TYPEID::UnknownOp: { stringstream ss; - ss << "unsupported op " << node_op; + ss << "unsupported op " << type_info.name << ":" << type_info.version; throw runtime_error(ss.str()); } } @@ -2861,7 +2931,12 @@ json JSONSerializer::serialize_output_vector(const OutputVector& output_vector) json JSONSerializer::serialize_node(const Node& n) { m_nodes_serialized.insert(&n); + const NodeTypeInfo& type_info = n.get_type_info(); + json jtype_info; + jtype_info["name"] = type_info.name; + jtype_info["version"] = type_info.version; json node; + node["type_info"] = jtype_info; node["name"] = n.get_name(); auto op_version = n.get_version(); node["op_version"] = op_version; @@ -2870,7 +2945,7 @@ json JSONSerializer::serialize_node(const Node& n) { node["friendly_name"] = n.get_friendly_name(); } - node["op"] = n.description(); + node["op"] = n.type_info.name; // TODO Multiple outputs json inputs = json::array(); json control_deps = json::array(); @@ -2921,14 +2996,13 @@ json JSONSerializer::serialize_node(const Node& n) node["provenance_tags"] = provenance_tags; } - string node_op = n.description(); #if !(defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 8)) #pragma GCC diagnostic push #pragma GCC diagnostic error "-Wswitch" #pragma GCC diagnostic error "-Wswitch-enum" // #pragma GCC diagnostic error "-Wimplicit-fallthrough" #endif - switch (get_typeid(node_op)) + switch (get_typeid(type_info)) { case OP_TYPEID::Abs: { break; } @@ -2937,14 +3011,17 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::Add: { const op::util::BinaryElementwiseArithmetic* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Add_v1: + { + const op::util::BinaryElementwiseArithmetic* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3003,61 +3080,62 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::AvgPool: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["window_shape"] = tmp->get_window_shape(); - node["window_movement_strides"] = tmp->get_window_movement_strides(); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - node["include_padding_in_avg_computation"] = - tmp->get_include_padding_in_avg_computation(); - node["pad_type"] = tmp->get_pad_type(); - if (tmp->get_ceil_mode()) - { - node["ceil_mode"] = tmp->get_ceil_mode(); - } - } - if (op_version == 1) + auto tmp = static_cast(&n); + node["window_shape"] = tmp->get_window_shape(); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["include_padding_in_avg_computation"] = tmp->get_include_padding_in_avg_computation(); + node["pad_type"] = tmp->get_pad_type(); + if (tmp->get_ceil_mode()) { - auto tmp = static_cast(&n); - node["kernel"] = tmp->get_kernel(); - node["strides"] = tmp->get_strides(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - node["exclude_pad"] = tmp->get_exclude_pad(); - node["auto_pad"] = tmp->get_auto_pad(); - node["rounding_type"] = tmp->get_rounding_type(); + node["ceil_mode"] = tmp->get_ceil_mode(); } break; } + case OP_TYPEID::AvgPool_v1: + { + auto tmp = static_cast(&n); + node["kernel"] = tmp->get_kernel(); + node["strides"] = tmp->get_strides(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); + node["exclude_pad"] = tmp->get_exclude_pad(); + node["auto_pad"] = tmp->get_auto_pad(); + node["rounding_type"] = tmp->get_rounding_type(); + break; + } case OP_TYPEID::AvgPoolBackprop: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["forward_arg_shape"] = tmp->get_forward_arg_shape(); - node["window_shape"] = tmp->get_window_shape(); - node["window_movement_strides"] = tmp->get_window_movement_strides(); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - node["include_padding_in_avg_computation"] = - tmp->get_include_padding_in_avg_computation(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["forward_arg_shape"] = tmp->get_forward_arg_shape(); - node["kernel"] = tmp->get_kernel(); - node["strides"] = tmp->get_strides(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - node["exclude_pad"] = tmp->get_exclude_pad(); - } + auto tmp = static_cast(&n); + node["forward_arg_shape"] = tmp->get_forward_arg_shape(); + node["window_shape"] = tmp->get_window_shape(); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["include_padding_in_avg_computation"] = tmp->get_include_padding_in_avg_computation(); + break; + } + case OP_TYPEID::AvgPoolBackprop_v1: + { + auto tmp = static_cast(&n); + node["forward_arg_shape"] = tmp->get_forward_arg_shape(); + node["kernel"] = tmp->get_kernel(); + node["strides"] = tmp->get_strides(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); + node["exclude_pad"] = tmp->get_exclude_pad(); break; } case OP_TYPEID::BatchMatMul: { break; } + case OP_TYPEID::BatchMatMulTranspose: + { + auto tmp = static_cast(&n); + node["transpose_0"] = tmp->get_transpose_arg0(); + node["transpose_1"] = tmp->get_transpose_arg1(); + break; + } case OP_TYPEID::BatchNormTraining: { auto tmp = static_cast(&n); @@ -3076,7 +3154,7 @@ json JSONSerializer::serialize_node(const Node& n) node["eps"] = tmp->get_eps_value(); break; } - case OP_TYPEID::BinaryConvolution: + case OP_TYPEID::BinaryConvolution_v1: { auto tmp = static_cast(&n); node["strides"] = tmp->get_strides(); @@ -3090,19 +3168,17 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Broadcast: { - if (op_version == 0) - { - auto tmp = dynamic_cast(&n); - node["axes"] = serialize_axis_set(tmp->get_broadcast_axes()); - node["shape"] = tmp->get_broadcast_shape(); - } - if (op_version == 1) + auto tmp = dynamic_cast(&n); + node["axes"] = serialize_axis_set(tmp->get_broadcast_axes()); + node["shape"] = tmp->get_broadcast_shape(); + break; + } + case OP_TYPEID::Broadcast_v1: + { + auto tmp = dynamic_cast(&n); + if (tmp->get_broadcast_spec().m_type != op::AutoBroadcastType::NONE) { - auto tmp = dynamic_cast(&n); - if (tmp->get_broadcast_spec().m_type != op::AutoBroadcastType::NONE) - { - node["auto_broadcast"] = write_auto_broadcast(tmp->get_broadcast_spec()); - } + node["auto_broadcast"] = write_auto_broadcast(tmp->get_broadcast_spec()); } break; } @@ -3152,73 +3228,70 @@ json JSONSerializer::serialize_node(const Node& n) node["target_type"] = write_element_type(tmp->get_convert_element_type()); break; } + case OP_TYPEID::ConvertLike_v1: { break; + } case OP_TYPEID::Convolution: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["window_movement_strides"] = tmp->get_window_movement_strides(); - node["window_dilation_strides"] = tmp->get_window_dilation_strides(); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - node["data_dilation_strides"] = tmp->get_data_dilation_strides(); - node["pad_type"] = tmp->get_pad_type(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["strides"] = tmp->get_strides(); - node["dilations"] = tmp->get_dilations(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - node["auto_pad"] = tmp->get_auto_pad(); - } + auto tmp = static_cast(&n); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["window_dilation_strides"] = tmp->get_window_dilation_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["data_dilation_strides"] = tmp->get_data_dilation_strides(); + node["pad_type"] = tmp->get_pad_type(); + break; + } + case OP_TYPEID::Convolution_v1: + { + auto tmp = static_cast(&n); + node["strides"] = tmp->get_strides(); + node["dilations"] = tmp->get_dilations(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); + node["auto_pad"] = tmp->get_auto_pad(); break; } case OP_TYPEID::ConvolutionBackpropData: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["data_batch_shape"] = tmp->get_data_batch_shape(); - node["window_movement_strides_forward"] = tmp->get_window_movement_strides_forward(); - node["window_dilation_strides_forward"] = tmp->get_window_dilation_strides_forward(); - node["padding_below_forward"] = tmp->get_padding_below_forward(); - node["padding_above_forward"] = tmp->get_padding_above_forward(); - node["data_dilation_strides_forward"] = tmp->get_data_dilation_strides_forward(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["data_batch_shape"] = tmp->get_data_batch_shape(); - node["strides"] = tmp->get_strides(); - node["dilations"] = tmp->get_dilations(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - } + auto tmp = static_cast(&n); + node["data_batch_shape"] = tmp->get_data_batch_shape(); + node["window_movement_strides_forward"] = tmp->get_window_movement_strides_forward(); + node["window_dilation_strides_forward"] = tmp->get_window_dilation_strides_forward(); + node["padding_below_forward"] = tmp->get_padding_below_forward(); + node["padding_above_forward"] = tmp->get_padding_above_forward(); + node["data_dilation_strides_forward"] = tmp->get_data_dilation_strides_forward(); + break; + } + case OP_TYPEID::ConvolutionBackpropData_v1: + { + auto tmp = static_cast(&n); + node["strides"] = tmp->get_strides(); + node["dilations"] = tmp->get_dilations(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); + node["auto_pad"] = tmp->get_auto_pad(); + node["output_padding"] = tmp->get_output_padding(); break; } case OP_TYPEID::ConvolutionBackpropFilters: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["filters_shape"] = tmp->get_filters_shape(); - node["window_movement_strides_forward"] = tmp->get_window_movement_strides_forward(); - node["window_dilation_strides_forward"] = tmp->get_window_dilation_strides_forward(); - node["padding_below_forward"] = tmp->get_padding_below_forward(); - node["padding_above_forward"] = tmp->get_padding_above_forward(); - node["data_dilation_strides_forward"] = tmp->get_data_dilation_strides_forward(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["filters_shape"] = tmp->get_filters_shape(); - node["strides"] = tmp->get_strides(); - node["dilations"] = tmp->get_dilations(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - } + auto tmp = static_cast(&n); + node["filters_shape"] = tmp->get_filters_shape(); + node["window_movement_strides_forward"] = tmp->get_window_movement_strides_forward(); + node["window_dilation_strides_forward"] = tmp->get_window_dilation_strides_forward(); + node["padding_below_forward"] = tmp->get_padding_below_forward(); + node["padding_above_forward"] = tmp->get_padding_above_forward(); + node["data_dilation_strides_forward"] = tmp->get_data_dilation_strides_forward(); + break; + } + case OP_TYPEID::ConvolutionBackpropFilters_v1: + { + auto tmp = static_cast(&n); + node["filters_shape"] = tmp->get_filters_shape(); + node["strides"] = tmp->get_strides(); + node["dilations"] = tmp->get_dilations(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); break; } case OP_TYPEID::ConvolutionBias: @@ -3257,6 +3330,68 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Cosh: { break; } + case OP_TYPEID::CumSum: + { + auto tmp = static_cast(&n); + node["exclusive"] = tmp->is_exclusive(); + node["reverse"] = tmp->is_reverse(); + break; + } + case OP_TYPEID::CrossEntropy: + { + auto tmp = static_cast(&n); + node["soft_label"] = tmp->get_soft_label(); + node["ignore_index"] = tmp->get_ignore_index(); + break; + } + case OP_TYPEID::CrossEntropyBackprop: + { + auto tmp = static_cast(&n); + node["soft_label"] = tmp->get_soft_label(); + node["ignore_index"] = tmp->get_ignore_index(); + break; + } + case OP_TYPEID::CropAndResize: + { + auto tmp = static_cast(&n); + node["resize_method"] = as_string(tmp->get_resize_method()); + node["extrapolation_value"] = tmp->get_extrapolation_value(); + break; + } + case OP_TYPEID::CTCGreedyDecoder: { break; + } + case OP_TYPEID::CompiledKernel: { break; + } + case OP_TYPEID::DetectionOutput: { break; + } + case OP_TYPEID::PSROIPooling: { break; + } + case OP_TYPEID::PriorBox: { break; + } + case OP_TYPEID::PriorBoxClustered: { break; + } + case OP_TYPEID::Proposal: { break; + } + case OP_TYPEID::ROIPooling: { break; + } + case OP_TYPEID::RegionYolo: { break; + } + case OP_TYPEID::ReorgYolo: { break; + } + + case OP_TYPEID::DeformablePSROIPooling_v1: + { + auto tmp = static_cast(&n); + node["output_dim"] = tmp->get_output_dim(); + node["group_size"] = tmp->get_group_size(); + node["spatial_scale"] = tmp->get_spatial_scale(); + node["mode"] = tmp->get_mode(); + node["spatial_bins_x"] = tmp->get_spatial_bins_x(); + node["spatial_bins_y"] = tmp->get_spatial_bins_y(); + node["trans_std"] = tmp->get_trans_std(); + node["part_size"] = tmp->get_part_size(); + break; + } case OP_TYPEID::Dequantize: { auto tmp = static_cast(&n); @@ -3264,7 +3399,7 @@ json JSONSerializer::serialize_node(const Node& n) node["axes"] = serialize_axis_set(tmp->get_axes()); break; } - case OP_TYPEID::DepthToSpace: + case OP_TYPEID::DepthToSpace_v1: { auto tmp = static_cast(&n); node["type"] = write_element_type(tmp->get_element_type()); @@ -3275,18 +3410,21 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::Divide: { const op::util::BinaryElementwiseArithmetic* bea_node = nullptr; - if (op_version == 0) - { - auto tmp = static_cast(&n); - bea_node = tmp; - node["pythondiv"] = tmp->is_pythondiv(); - } - else if (op_version == 1) + auto tmp = static_cast(&n); + bea_node = tmp; + node["pythondiv"] = tmp->is_pythondiv(); + if (bea_node != nullptr && bea_node->get_autob().m_type != op::AutoBroadcastType::NONE) { - auto tmp = static_cast(&n); - bea_node = tmp; - node["pythondiv"] = tmp->is_pythondiv(); + node["auto_broadcast"] = write_auto_broadcast(bea_node->get_autob()); } + break; + } + case OP_TYPEID::Divide_v1: + { + const op::util::BinaryElementwiseArithmetic* bea_node = nullptr; + auto tmp = static_cast(&n); + bea_node = tmp; + node["pythondiv"] = tmp->is_pythondiv(); if (bea_node != nullptr && bea_node->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(bea_node->get_autob()); @@ -3315,16 +3453,14 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::DynReshape: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["zero_flag"] = tmp->get_zero_flag(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["zero_flag"] = tmp->get_zero_flag(); - } + auto tmp = static_cast(&n); + node["zero_flag"] = tmp->get_zero_flag(); + break; + } + case OP_TYPEID::Reshape_v1: + { + auto tmp = static_cast(&n); + node["special_zero"] = tmp->get_special_zero(); break; } case OP_TYPEID::DynSlice: @@ -3348,14 +3484,17 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::Equal: { const op::util::BinaryElementwiseComparison* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Equal_v1: + { + const op::util::BinaryElementwiseComparison* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3374,17 +3513,27 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Floor: { break; } - case OP_TYPEID::Gather: + case OP_TYPEID::FloorMod_v1: { - if (op_version == 0) + auto tmp = static_cast(&n); + if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - auto tmp = static_cast(&n); - node["axis"] = tmp->get_axis(); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } break; } + case OP_TYPEID::Gather: + { + auto tmp = static_cast(&n); + node["axis"] = tmp->get_axis(); + break; + } + case OP_TYPEID::Gather_v1: { break; + } case OP_TYPEID::GatherND: { break; } + case OP_TYPEID::GatherTree_v1: { break; + } case OP_TYPEID::GetOutputElement: { auto tmp = static_cast(&n); @@ -3411,24 +3560,32 @@ json JSONSerializer::serialize_node(const Node& n) node["use_seed"] = tmp->get_use_seed(); node["seed"] = tmp->get_seed(); node["probability"] = tmp->get_probability(); - if (op_version == 0) - { - node["output_shape"] = tmp->get_mask_shape(); - } - + node["output_shape"] = tmp->get_mask_shape(); + break; + } + case OP_TYPEID::GenerateMask_v1: + { + auto tmp = static_cast(&n); + node["type"] = write_element_type(tmp->get_element_type()); + node["use_seed"] = tmp->get_use_seed(); + node["seed"] = tmp->get_seed(); + node["probability"] = tmp->get_probability(); break; } case OP_TYPEID::Greater: { const op::util::BinaryElementwiseComparison* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Greater_v1: + { + const op::util::BinaryElementwiseComparison* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3438,14 +3595,17 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::GreaterEq: { const op::util::BinaryElementwiseComparison* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::GreaterEqual_v1: + { + const op::util::BinaryElementwiseComparison* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3481,6 +3641,26 @@ json JSONSerializer::serialize_node(const Node& n) node["pad_type"] = tmp->get_pad_type(); break; } + case OP_TYPEID::GroupConvolutionBackpropData: + { + auto tmp = static_cast(&n); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["window_dilation_strides"] = tmp->get_window_dilation_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["groups"] = tmp->get_groups(); + break; + } + case OP_TYPEID::GroupConvolutionBackpropFilters: + { + auto tmp = static_cast(&n); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["window_dilation_strides"] = tmp->get_window_dilation_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["groups"] = tmp->get_groups(); + break; + } case OP_TYPEID::GroupConvolutionTranspose: { auto tmp = static_cast(&n); @@ -3494,12 +3674,9 @@ json JSONSerializer::serialize_node(const Node& n) node["output_shape"] = tmp->get_output_shape(); break; } - case OP_TYPEID::HardSigmoid: - { - auto tmp = static_cast(&n); - node["alpha"] = tmp->get_alpha(); - node["beta"] = tmp->get_beta(); - break; + case OP_TYPEID::HardSigmoid: { break; + } + case OP_TYPEID::Interpolate: { break; } case OP_TYPEID::LayerNorm: { @@ -3522,14 +3699,17 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::Less: { const op::util::BinaryElementwiseComparison* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Less_v1: + { + const op::util::BinaryElementwiseComparison* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3545,7 +3725,7 @@ json JSONSerializer::serialize_node(const Node& n) } break; } - case OP_TYPEID::LessEqual: + case OP_TYPEID::LessEqual_v1: { auto tmp = static_cast(&n); if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) @@ -3556,7 +3736,7 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Log: { break; } - case OP_TYPEID::LogicalAnd: + case OP_TYPEID::LogicalAnd_v1: { auto tmp = static_cast(&n); if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) @@ -3565,9 +3745,9 @@ json JSONSerializer::serialize_node(const Node& n) } break; } - case OP_TYPEID::LogicalNot: { break; + case OP_TYPEID::LogicalNot_v1: { break; } - case OP_TYPEID::LogicalOr: + case OP_TYPEID::LogicalOr_v1: { auto tmp = static_cast(&n); if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) @@ -3576,7 +3756,7 @@ json JSONSerializer::serialize_node(const Node& n) } break; } - case OP_TYPEID::LogicalXor: + case OP_TYPEID::LogicalXor_v1: { auto tmp = static_cast(&n); if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) @@ -3585,6 +3765,12 @@ json JSONSerializer::serialize_node(const Node& n) } break; } + case OP_TYPEID::LogSoftmax: + { + auto tmp = static_cast(&n); + node["axis"] = tmp->get_axis(); + break; + } case OP_TYPEID::LRN: { auto tmp = static_cast(&n); @@ -3634,58 +3820,57 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::MaxPool: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["window_shape"] = tmp->get_window_shape(); - node["window_movement_strides"] = tmp->get_window_movement_strides(); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - node["pad_type"] = tmp->get_pad_type(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["kernel"] = tmp->get_kernel(); - node["strides"] = tmp->get_strides(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - node["auto_pad"] = tmp->get_auto_pad(); - node["rounding_type"] = tmp->get_rounding_type(); - } + auto tmp = static_cast(&n); + node["window_shape"] = tmp->get_window_shape(); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["pad_type"] = tmp->get_pad_type(); + break; + } + case OP_TYPEID::MaxPool_v1: + { + auto tmp = static_cast(&n); + node["kernel"] = tmp->get_kernel(); + node["strides"] = tmp->get_strides(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); + node["auto_pad"] = tmp->get_auto_pad(); + node["rounding_type"] = tmp->get_rounding_type(); break; } case OP_TYPEID::MaxPoolBackprop: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["window_shape"] = tmp->get_window_shape(); - node["window_movement_strides"] = tmp->get_window_movement_strides(); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["kernel"] = tmp->get_kernel(); - node["strides"] = tmp->get_strides(); - node["pads_begin"] = tmp->get_pads_begin(); - node["pads_end"] = tmp->get_pads_end(); - } + auto tmp = static_cast(&n); + node["window_shape"] = tmp->get_window_shape(); + node["window_movement_strides"] = tmp->get_window_movement_strides(); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + break; + } + case OP_TYPEID::MaxPoolBackprop_v1: + { + auto tmp = static_cast(&n); + node["kernel"] = tmp->get_kernel(); + node["strides"] = tmp->get_strides(); + node["pads_begin"] = tmp->get_pads_begin(); + node["pads_end"] = tmp->get_pads_end(); break; } case OP_TYPEID::Maximum: { const op::util::BinaryElementwiseArithmetic* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Maximum_v1: + { + const op::util::BinaryElementwiseArithmetic* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3698,34 +3883,49 @@ json JSONSerializer::serialize_node(const Node& n) node["reduction_axes"] = serialize_axis_set(tmp->get_reduction_axes()); break; } + case OP_TYPEID::ReduceMin_v1: + case OP_TYPEID::ReduceMax_v1: { break; + } case OP_TYPEID::Minimum: { const op::util::BinaryElementwiseArithmetic* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Minimum_v1: + { + const op::util::BinaryElementwiseArithmetic* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } break; } + case OP_TYPEID::Mod_v1: + { + auto tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_auto_broadcast()); + break; + } case OP_TYPEID::Multiply: { const op::util::BinaryElementwiseArithmetic* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Multiply_v1: + { + const op::util::BinaryElementwiseArithmetic* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3752,14 +3952,17 @@ json JSONSerializer::serialize_node(const Node& n) case OP_TYPEID::NotEqual: { const op::util::BinaryElementwiseComparison* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::NotEqual_v1: + { + const op::util::BinaryElementwiseComparison* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3770,9 +3973,17 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::OneHot: { - auto tmp = static_cast(&n); - node["shape"] = write_partial_shape(tmp->get_output_partial_shape(0)); - node["one_hot_axis"] = tmp->get_one_hot_axis(); + if (op_version == 0) + { + auto tmp = static_cast(&n); + node["shape"] = write_partial_shape(tmp->get_output_partial_shape(0)); + node["one_hot_axis"] = tmp->get_one_hot_axis(); + } + if (op_version == 1) + { + auto tmp = static_cast(&n); + node["axis"] = tmp->get_axis(); + } break; } case OP_TYPEID::Or: @@ -3786,18 +3997,16 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Pad: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["padding_below"] = tmp->get_padding_below(); - node["padding_above"] = tmp->get_padding_above(); - node["pad_mode"] = tmp->get_pad_mode(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["pad_mode"] = tmp->get_pad_mode(); - } + auto tmp = static_cast(&n); + node["padding_below"] = tmp->get_padding_below(); + node["padding_above"] = tmp->get_padding_above(); + node["pad_mode"] = tmp->get_pad_mode(); + break; + } + case OP_TYPEID::Pad_v1: + { + auto tmp = static_cast(&n); + node["pad_mode"] = tmp->get_pad_mode(); break; } case OP_TYPEID::Parameter: @@ -3844,30 +4053,28 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::PRelu: { break; } - case OP_TYPEID::Product: + case OP_TYPEID::Product: { break; + } + case OP_TYPEID::ReduceProd_v1: { - if (op_version == 0) - { - break; - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["keep_dims"] = tmp->get_keep_dims(); - } + auto tmp = static_cast(&n); + node["keep_dims"] = tmp->get_keep_dims(); break; } case OP_TYPEID::Power: { const op::util::BinaryElementwiseArithmetic* tmp = nullptr; - if (op_version == 0) - { - tmp = static_cast(&n); - } - else if (op_version == 1) + tmp = static_cast(&n); + if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - tmp = static_cast(&n); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } + break; + } + case OP_TYPEID::Power_v1: + { + const op::util::BinaryElementwiseArithmetic* tmp = nullptr; + tmp = static_cast(&n); if (tmp != nullptr && tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); @@ -3916,19 +4123,39 @@ json JSONSerializer::serialize_node(const Node& n) node["output_axes"] = tmp->get_output_axes(); break; } + case OP_TYPEID::RandomUniform: + { + auto tmp = static_cast(&n); + node["fixed_seed"] = tmp->get_fixed_seed(); + break; + } + case OP_TYPEID::Range: { break; + } + case OP_TYPEID::Reciprocal: { break; + } case OP_TYPEID::Recv: { auto tmp = static_cast(&n); node["source_id"] = tmp->get_src_id(); break; } - case OP_TYPEID::RandomUniform: + case OP_TYPEID::ReduceLogicalAnd_v1: { - auto tmp = static_cast(&n); - node["fixed_seed"] = tmp->get_fixed_seed(); + const auto tmp = static_cast(&n); + node["keep_dims"] = tmp->get_keep_dims(); break; } - case OP_TYPEID::Range: { break; + case OP_TYPEID::ReduceLogicalOr_v1: + { + const auto tmp = static_cast(&n); + node["keep_dims"] = tmp->get_keep_dims(); + break; + } + case OP_TYPEID::ReduceMean_v1: + { + auto tmp = static_cast(&n); + node["keep_dims"] = tmp->get_keep_dims(); + break; } case OP_TYPEID::Relu: { break; } @@ -3957,25 +4184,21 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Reverse: { - if (op_version == 0) - { - const auto tmp = static_cast(&n); - node["reversed_axes"] = serialize_axis_set(tmp->get_reversed_axes()); - break; - } - else if (op_version == 1) - { - const auto tmp = static_cast(&n); - node["mode"] = tmp->get_mode(); - break; - } + const auto tmp = static_cast(&n); + node["reversed_axes"] = serialize_axis_set(tmp->get_reversed_axes()); + break; + } + case OP_TYPEID::Reverse_v1: + { + const auto tmp = static_cast(&n); + node["mode"] = tmp->get_mode(); break; } case OP_TYPEID::ReverseSequence: { auto tmp = static_cast(&n); - node["batch_axis"] = tmp->get_batch_axis(); - node["sequence_axis"] = tmp->get_sequence_axis(); + node["batch_axis"] = tmp->get_origin_batch_axis(); + node["sequence_axis"] = tmp->get_origin_sequence_axis(); break; } case OP_TYPEID::RNNCell: @@ -3988,7 +4211,7 @@ json JSONSerializer::serialize_node(const Node& n) node["activations_beta"] = tmp->get_activations_beta(); break; } - case OP_TYPEID::ScalarConstantLike: + case OP_TYPEID::ScalarConstantLikeBase: { auto tmp = static_cast(&n); auto constant = tmp->as_constant(); @@ -4033,41 +4256,46 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::Slice: { - if (op_version == 0) - { - auto tmp = static_cast(&n); - node["lower_bounds"] = tmp->get_lower_bounds(); - node["upper_bounds"] = tmp->get_upper_bounds(); - node["strides"] = tmp->get_strides(); - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["begin_mask"] = tmp->get_begin_mask(); - node["end_mask"] = tmp->get_end_mask(); - node["new_axis_mask"] = tmp->get_new_axis_mask(); - node["shrink_axis_mask"] = tmp->get_shrink_axis_mask(); - node["ellipsis_mask"] = tmp->get_ellipsis_mask(); - } + auto tmp = static_cast(&n); + node["lower_bounds"] = tmp->get_lower_bounds(); + node["upper_bounds"] = tmp->get_upper_bounds(); + node["strides"] = tmp->get_strides(); + break; + } + case OP_TYPEID::StridedSlice_v1: + { + auto tmp = static_cast(&n); + node["begin_mask"] = tmp->get_begin_mask(); + node["end_mask"] = tmp->get_end_mask(); + node["new_axis_mask"] = tmp->get_new_axis_mask(); + node["shrink_axis_mask"] = tmp->get_shrink_axis_mask(); + node["ellipsis_mask"] = tmp->get_ellipsis_mask(); break; } case OP_TYPEID::SpaceToDepth: { auto tmp = static_cast(&n); node["type"] = write_element_type(tmp->get_element_type()); + node["mode"] = tmp->get_mode(); node["block_size"] = tmp->get_block_size(); break; } case OP_TYPEID::Split: { auto tmp = static_cast(&n); - node["axis"] = tmp->get_axis(); node["splits"] = tmp->get_splits(); break; } case OP_TYPEID::Sqrt: { break; } - case OP_TYPEID::SquaredDifference: { break; + case OP_TYPEID::SquaredDifference: + { + auto tmp = static_cast(&n); + if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) + { + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); + } + break; } case OP_TYPEID::Squeeze: { break; } @@ -4082,30 +4310,30 @@ json JSONSerializer::serialize_node(const Node& n) } break; } - case OP_TYPEID::Sum: + case OP_TYPEID::Subtract_v1: { - if (op_version == 0) - { - break; - } - if (op_version == 1) + auto tmp = static_cast(&n); + if (tmp->get_autob().m_type != op::AutoBroadcastType::NONE) { - auto tmp = static_cast(&n); - node["keep_dims"] = tmp->get_keep_dims(); + node["auto_broadcast"] = write_auto_broadcast(tmp->get_autob()); } break; } - case OP_TYPEID::Softmax: + case OP_TYPEID::Sum: { break; + } + case OP_TYPEID::ReduceSum_v1: { - if (op_version == 0) - { - break; - } - if (op_version == 1) - { - auto tmp = static_cast(&n); - node["softmax_axis"] = tmp->get_axis(); - } + auto tmp = static_cast(&n); + node["keep_dims"] = tmp->get_keep_dims(); + break; + } + case OP_TYPEID::Softmax: { break; + } + + case OP_TYPEID::Softmax_v1: + { + auto tmp = static_cast(&n); + node["softmax_axis"] = tmp->get_axis(); break; } case OP_TYPEID::SoftmaxCrossEntropy: @@ -4172,20 +4400,19 @@ json JSONSerializer::serialize_node(const Node& n) } case OP_TYPEID::TopK: { - if (op_version == 0) - { - const auto tmp = static_cast(&n); - node["index_element_type"] = write_element_type(tmp->get_index_element_type()); - node["compute_max"] = tmp->get_compute_max(); - } - else if (op_version == 1) - { - const auto tmp = static_cast(&n); - node["axis"] = tmp->get_axis(); - node["mode"] = tmp->get_mode(); - node["sort_type"] = tmp->get_sort_type(); - node["index_element_type"] = write_element_type(tmp->get_index_element_type()); - } + const auto tmp = static_cast(&n); + node["index_element_type"] = write_element_type(tmp->get_index_element_type()); + node["compute_max"] = tmp->get_compute_max(); + break; + } + + case OP_TYPEID::TopK_v1: + { + const auto tmp = static_cast(&n); + node["axis"] = tmp->get_axis(); + node["mode"] = tmp->get_mode(); + node["sort_type"] = tmp->get_sort_type(); + node["index_element_type"] = write_element_type(tmp->get_index_element_type()); break; } case OP_TYPEID::Transpose: { break; @@ -4201,6 +4428,8 @@ json JSONSerializer::serialize_node(const Node& n) } break; } + case OP_TYPEID::VariadicSplit_v1: { break; + } case OP_TYPEID::UnknownOp: { break; } } diff --git a/src/ngraph/shape.cpp b/src/ngraph/shape.cpp index bd78a3bc2c6..916f9dbd88e 100644 --- a/src/ngraph/shape.cpp +++ b/src/ngraph/shape.cpp @@ -17,6 +17,9 @@ #include "ngraph/shape.hpp" #include "ngraph/util.hpp" +using namespace std; +using namespace ngraph; + std::ostream& ngraph::operator<<(std::ostream& s, const Shape& shape) { s << "Shape{"; @@ -24,3 +27,62 @@ std::ostream& ngraph::operator<<(std::ostream& s, const Shape& shape) s << "}"; return s; } + +ngraph::Shape::Shape() + : std::vector() +{ +} + +ngraph::Shape::Shape(const std::initializer_list& axis_lengths) + : std::vector(axis_lengths) +{ +} + +ngraph::Shape::Shape(const std::vector& axis_lengths) + : std::vector(axis_lengths) +{ +} + +ngraph::Shape::Shape(const Shape& axis_lengths) + : std::vector(axis_lengths) +{ +} + +ngraph::Shape::Shape(size_t n, size_t initial_value) + : std::vector(n, initial_value) +{ +} + +ngraph::Shape::~Shape() +{ +} + +ngraph::Shape& ngraph::Shape::operator=(const Shape& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::Shape& ngraph::Shape::operator=(Shape&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} + +const vector& AttributeAdapter::get() +{ + if (!m_buffer_valid) + { + m_buffer = copy_from>(m_value); + m_buffer_valid = true; + } + return m_buffer; +} + +void AttributeAdapter::set(const vector& value) +{ + m_value = copy_from(value); + m_buffer_valid = false; +} + +constexpr DiscreteTypeInfo AttributeAdapter::type_info; diff --git a/src/ngraph/shape.hpp b/src/ngraph/shape.hpp index 7150064e87d..4ff8efd9e9f 100644 --- a/src/ngraph/shape.hpp +++ b/src/ngraph/shape.hpp @@ -19,7 +19,9 @@ #include #include +#include "ngraph/attribute_adapter.hpp" #include "ngraph/axis_set.hpp" +#include "ngraph/ngraph_visibility.hpp" #include "ngraph/strides.hpp" namespace ngraph @@ -28,25 +30,17 @@ namespace ngraph class Shape : public std::vector { public: - Shape(const std::initializer_list& axis_lengths) - : std::vector(axis_lengths) - { - } + NGRAPH_API Shape(); - Shape(const std::vector& axis_lengths) - : std::vector(axis_lengths) - { - } + NGRAPH_API Shape(const std::initializer_list& axis_lengths); - Shape(const Shape& axis_lengths) - : std::vector(axis_lengths) - { - } + NGRAPH_API Shape(const std::vector& axis_lengths); - explicit Shape(size_t n, size_t initial_value = 0) - : std::vector(n, initial_value) - { - } + NGRAPH_API Shape(const Shape& axis_lengths); + + NGRAPH_API explicit Shape(size_t n, size_t initial_value = 0); + + NGRAPH_API ~Shape(); template Shape(InputIterator first, InputIterator last) @@ -54,17 +48,23 @@ namespace ngraph { } - Shape() {} - Shape& operator=(const Shape& v) - { - static_cast*>(this)->operator=(v); - return *this; - } - Shape& operator=(Shape&& v) + NGRAPH_API Shape& operator=(const Shape& v); + NGRAPH_API Shape& operator=(Shape&& v) noexcept; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor> + { + public: + AttributeAdapter(Shape& value) + : ValueReference(value) { - static_cast*>(this)->operator=(v); - return *this; } + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; }; /// Number of elements in spanned by a shape @@ -106,5 +106,6 @@ namespace ngraph return 1 == shape.size(); } + NGRAPH_API std::ostream& operator<<(std::ostream& s, const Shape& shape); } diff --git a/src/ngraph/specialize_function.cpp b/src/ngraph/specialize_function.cpp index 9451838b6a8..9e9ad379a8a 100644 --- a/src/ngraph/specialize_function.cpp +++ b/src/ngraph/specialize_function.cpp @@ -60,6 +60,7 @@ std::shared_ptr m[f->get_parameters()[i].get()] = std::make_shared(parameter_element_types[i], parameter_shapes[i]); } + m[f->get_parameters()[i].get()]->get_rt_info() = f->get_parameters()[i]->get_rt_info(); } for (auto old_node : f->get_ordered_ops()) @@ -83,6 +84,7 @@ std::shared_ptr else { m[old_node.get()] = old_node->copy_with_new_inputs(new_args); + m[old_node.get()]->get_rt_info() = old_node->get_rt_info(); } m[old_node.get()]->set_friendly_name(old_node->get_friendly_name()); diff --git a/src/ngraph/strides.cpp b/src/ngraph/strides.cpp index b0342269f9f..0c4657ffeb8 100644 --- a/src/ngraph/strides.cpp +++ b/src/ngraph/strides.cpp @@ -17,6 +17,9 @@ #include "ngraph/strides.hpp" #include "ngraph/util.hpp" +using namespace std; +using namespace ngraph; + std::ostream& ngraph::operator<<(std::ostream& s, const Strides& strides) { s << "Strides{"; @@ -24,3 +27,58 @@ std::ostream& ngraph::operator<<(std::ostream& s, const Strides& strides) s << "}"; return s; } + +ngraph::Strides::Strides() + : std::vector() +{ +} + +ngraph::Strides::Strides(const std::initializer_list& axis_strides) + : std::vector(axis_strides) +{ +} + +ngraph::Strides::Strides(const std::vector& axis_strides) + : std::vector(axis_strides) +{ +} + +ngraph::Strides::Strides(const Strides& axis_strides) + : std::vector(axis_strides) +{ +} + +ngraph::Strides::Strides(size_t n, size_t initial_value) + : std::vector(n, initial_value) +{ +} + +ngraph::Strides& ngraph::Strides::operator=(const Strides& v) +{ + static_cast*>(this)->operator=(v); + return *this; +} + +ngraph::Strides& ngraph::Strides::operator=(Strides&& v) noexcept +{ + static_cast*>(this)->operator=(v); + return *this; +} + +const vector& AttributeAdapter::get() +{ + if (!m_buffer_valid) + { + m_buffer = copy_from>(m_value); + m_buffer_valid = true; + } + return m_buffer; +} + +void AttributeAdapter::set(const vector& value) +{ + m_value = copy_from(value); + m_buffer_valid = false; +} + +constexpr DiscreteTypeInfo AttributeAdapter::type_info; diff --git a/src/ngraph/strides.hpp b/src/ngraph/strides.hpp index c647a1b1f39..77d34a14cb6 100644 --- a/src/ngraph/strides.hpp +++ b/src/ngraph/strides.hpp @@ -20,31 +20,24 @@ #include #include +#include "ngraph/attribute_adapter.hpp" +#include "ngraph/ngraph_visibility.hpp" + namespace ngraph { /// \brief Strides for a tensor. class Strides : public std::vector { public: - Strides(const std::initializer_list& axis_strides) - : std::vector(axis_strides) - { - } + NGRAPH_API Strides(); - Strides(const std::vector& axis_strides) - : std::vector(axis_strides) - { - } + NGRAPH_API Strides(const std::initializer_list& axis_strides); - Strides(const Strides& axis_strides) - : std::vector(axis_strides) - { - } + NGRAPH_API Strides(const std::vector& axis_strides); - explicit Strides(size_t n, size_t initial_value = 0) - : std::vector(n, initial_value) - { - } + NGRAPH_API Strides(const Strides& axis_strides); + + NGRAPH_API explicit Strides(size_t n, size_t initial_value = 0); template Strides(InputIterator first, InputIterator last) @@ -52,17 +45,24 @@ namespace ngraph { } - Strides() {} - Strides& operator=(const Strides& v) - { - static_cast*>(this)->operator=(v); - return *this; - } - Strides& operator=(Strides&& v) + NGRAPH_API Strides& operator=(const Strides& v); + + NGRAPH_API Strides& operator=(Strides&& v) noexcept; + }; + + template <> + class NGRAPH_API AttributeAdapter : public ValueReference, + public ValueAccessor> + { + public: + AttributeAdapter(Strides& value) + : ValueReference(value) { - static_cast*>(this)->operator=(v); - return *this; } + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + const std::vector& get() override; + void set(const std::vector& value) override; }; std::ostream& operator<<(std::ostream& s, const Strides& strides); diff --git a/src/ngraph/type.hpp b/src/ngraph/type.hpp index 8fae4cab63a..1a347662305 100644 --- a/src/ngraph/type.hpp +++ b/src/ngraph/type.hpp @@ -16,6 +16,8 @@ #pragma once +#include +#include #include #include #include @@ -31,18 +33,36 @@ namespace ngraph /// Type information for a type system without inheritance; instances have exactly one type not /// related to any other type. - NGRAPH_API - struct DiscreteTypeInfo + struct NGRAPH_API DiscreteTypeInfo { const char* name; uint64_t version; - bool is_castable(const DiscreteTypeInfo& target_type) const { return this == &target_type; } + bool is_castable(const DiscreteTypeInfo& target_type) const { return *this == target_type; } // For use as a key bool operator<(const DiscreteTypeInfo& b) const { - return version < b.version || - (version == b.version && std::string(name) < std::string(b.name)); + return version < b.version || (version == b.version && strcmp(name, b.name) < 0); + } + bool operator<=(const DiscreteTypeInfo& b) const + { + return version < b.version || (version == b.version && strcmp(name, b.name) <= 0); + } + bool operator>(const DiscreteTypeInfo& b) const + { + return version < b.version || (version == b.version && strcmp(name, b.name) > 0); + } + bool operator>=(const DiscreteTypeInfo& b) const + { + return version < b.version || (version == b.version && strcmp(name, b.name) >= 0); + } + bool operator==(const DiscreteTypeInfo& b) const + { + return version == b.version && strcmp(name, b.name) == 0; + } + bool operator!=(const DiscreteTypeInfo& b) const + { + return version != b.version || strcmp(name, b.name) != 0; } }; diff --git a/src/ngraph/type/bfloat16.hpp b/src/ngraph/type/bfloat16.hpp index 5fb50dc0be6..f811f19caea 100644 --- a/src/ngraph/type/bfloat16.hpp +++ b/src/ngraph/type/bfloat16.hpp @@ -23,11 +23,13 @@ #include #include +#include "ngraph/ngraph_visibility.hpp" + #define ROUND_MODE_TO_NEAREST_EVEN namespace ngraph { - class bfloat16 + class NGRAPH_API bfloat16 { public: constexpr bfloat16() diff --git a/src/ngraph/type/element_type.cpp b/src/ngraph/type/element_type.cpp index ba6f0a85984..99fa7dcc9e2 100644 --- a/src/ngraph/type/element_type.cpp +++ b/src/ngraph/type/element_type.cpp @@ -24,20 +24,23 @@ using namespace ngraph; using namespace std; -NGRAPH_API const element::Type element::dynamic(element::Type_t::dynamic); -NGRAPH_API const element::Type element::boolean(element::Type_t::boolean); -NGRAPH_API const element::Type element::bf16(element::Type_t::bf16); -NGRAPH_API const element::Type element::f16(element::Type_t::f16); -NGRAPH_API const element::Type element::f32(element::Type_t::f32); -NGRAPH_API const element::Type element::f64(element::Type_t::f64); -NGRAPH_API const element::Type element::i8(element::Type_t::i8); -NGRAPH_API const element::Type element::i16(element::Type_t::i16); -NGRAPH_API const element::Type element::i32(element::Type_t::i32); -NGRAPH_API const element::Type element::i64(element::Type_t::i64); -NGRAPH_API const element::Type element::u8(element::Type_t::u8); -NGRAPH_API const element::Type element::u16(element::Type_t::u16); -NGRAPH_API const element::Type element::u32(element::Type_t::u32); -NGRAPH_API const element::Type element::u64(element::Type_t::u64); +const element::Type element::dynamic(element::Type_t::dynamic); +const element::Type element::boolean(element::Type_t::boolean); +const element::Type element::bf16(element::Type_t::bf16); +const element::Type element::f16(element::Type_t::f16); +const element::Type element::f32(element::Type_t::f32); +const element::Type element::f64(element::Type_t::f64); +const element::Type element::i8(element::Type_t::i8); +const element::Type element::i16(element::Type_t::i16); +const element::Type element::i32(element::Type_t::i32); +const element::Type element::i64(element::Type_t::i64); +const element::Type element::u1(element::Type_t::u1); +const element::Type element::u8(element::Type_t::u8); +const element::Type element::u16(element::Type_t::u16); +const element::Type element::u32(element::Type_t::u32); +const element::Type element::u64(element::Type_t::u64); + +NGRAPH_API constexpr DiscreteTypeInfo AttributeAdapter::type_info; class TypeInfo { @@ -80,6 +83,7 @@ static const map& get_type_info_map() {element::Type_t::i16, TypeInfo(16, false, true, false, "int16_t", "i16")}, {element::Type_t::i32, TypeInfo(32, false, true, true, "int32_t", "i32")}, {element::Type_t::i64, TypeInfo(64, false, true, false, "int64_t", "i64")}, + {element::Type_t::u1, TypeInfo(1, false, false, false, "uint8_t", "u1")}, {element::Type_t::u8, TypeInfo(8, false, false, true, "uint8_t", "u8")}, {element::Type_t::u16, TypeInfo(16, false, false, false, "uint16_t", "u16")}, {element::Type_t::u32, TypeInfo(32, false, false, false, "uint32_t", "u32")}, @@ -100,6 +104,7 @@ std::vector element::Type::get_known_types() &element::i16, &element::i32, &element::i64, + &element::u1, &element::u8, &element::u16, &element::u32, diff --git a/src/ngraph/type/element_type.hpp b/src/ngraph/type/element_type.hpp index 7b2a2dc442e..6fdc80c9a5c 100644 --- a/src/ngraph/type/element_type.hpp +++ b/src/ngraph/type/element_type.hpp @@ -26,6 +26,7 @@ #include #include +#include "ngraph/attribute_adapter.hpp" #include "ngraph/deprecated.hpp" #include "ngraph/except.hpp" #include "ngraph/ngraph_visibility.hpp" @@ -49,13 +50,14 @@ namespace ngraph i16, i32, i64, + u1, u8, u16, u32, u64 }; - class Type + class NGRAPH_API Type { public: Type() @@ -95,7 +97,7 @@ namespace ngraph bool operator==(const Type& other) const; bool operator!=(const Type& other) const { return !(*this == other); } bool operator<(const Type& other) const; - friend std::ostream& operator<<(std::ostream&, const Type&); + friend NGRAPH_API std::ostream& operator<<(std::ostream&, const Type&); static std::vector get_known_types(); /// \brief Checks whether this element type is merge-compatible with `t`. @@ -139,6 +141,7 @@ namespace ngraph extern NGRAPH_API const Type i16; extern NGRAPH_API const Type i32; extern NGRAPH_API const Type i64; + extern NGRAPH_API const Type u1; extern NGRAPH_API const Type u8; extern NGRAPH_API const Type u16; extern NGRAPH_API const Type u32; @@ -150,34 +153,48 @@ namespace ngraph throw std::invalid_argument("Unknown type"); } template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); template <> - Type from(); + NGRAPH_API Type from(); + NGRAPH_API std::ostream& operator<<(std::ostream& out, const ngraph::element::Type& obj); } + template <> + class AttributeAdapter : public ValueReference, + public ValueAccessor + { + public: + AttributeAdapter(element::Type& value) + : ValueReference(value) + { + } + NGRAPH_API + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; } diff --git a/src/ngraph/type/float16.cpp b/src/ngraph/type/float16.cpp index ee33168c5f0..887d07c8474 100644 --- a/src/ngraph/type/float16.cpp +++ b/src/ngraph/type/float16.cpp @@ -71,10 +71,11 @@ float16::float16(float value) // denorm biased_exp = 0; raw_frac |= hidden_one; - uint32_t shift = (-15 - exp) + (23 - frac_size) + 1; - raw_frac = (raw_frac + (hidden_one >> (shift + 1))) >> shift; + uint32_t exp_shift = (-15 - exp) + 1; + uint32_t shift = exp_shift + (23 - frac_size); + raw_frac = (raw_frac + (hidden_one >> (frac_size - exp_shift + 1))) >> shift; } - else if (exp > 15) + else if (exp > 15 || (exp == 15 && raw_frac > 0x7fef00 /* numpy overflow value */)) { biased_exp = 0x1F; raw_frac = 0; diff --git a/src/ngraph/type/float16.hpp b/src/ngraph/type/float16.hpp index d1f5ce95a53..fd397e08c3e 100644 --- a/src/ngraph/type/float16.hpp +++ b/src/ngraph/type/float16.hpp @@ -23,11 +23,13 @@ #include #include +#include "ngraph/ngraph_visibility.hpp" + #define ROUND_MODE_TO_NEAREST_EVEN namespace ngraph { - class float16 + class NGRAPH_API float16 { public: constexpr float16() diff --git a/src/ngraph/util.hpp b/src/ngraph/util.hpp index e2dcadbe0f5..d436f13f850 100644 --- a/src/ngraph/util.hpp +++ b/src/ngraph/util.hpp @@ -199,6 +199,7 @@ namespace ngraph T apply_permutation(T input, ngraph::AxisVector order); AxisVector get_default_order(size_t rank); + NGRAPH_API AxisVector get_default_order(const Shape& shape); AxisVector get_permutation_to_default_order(const AxisVector& axis_order); diff --git a/src/ngraph/validation_util.cpp b/src/ngraph/validation_util.cpp index ec8628fcfc4..6beac457132 100644 --- a/src/ngraph/validation_util.cpp +++ b/src/ngraph/validation_util.cpp @@ -794,3 +794,43 @@ PartialShape ngraph::infer_slice_shape(const Node* node, return dim; } + +int64_t ngraph::normalize_axis(const Node* node, std::int64_t axis, std::int64_t tensor_rank) +{ + return normalize_axis(node, axis, tensor_rank, -tensor_rank, tensor_rank - 1); +} + +int64_t ngraph::normalize_axis(const Node* node, + std::int64_t axis, + std::int64_t tensor_rank, + std::int64_t axis_range_min, + std::int64_t axis_range_max) +{ + return ngraph::normalize_axis( + node->description(), axis, tensor_rank, axis_range_min, axis_range_max); +} + +int64_t ngraph::normalize_axis(const std::string& node_description, + std::int64_t axis, + std::int64_t tensor_rank, + std::int64_t axis_range_min, + std::int64_t axis_range_max) +{ + // Accepted range of value for axis is [axis_range_min, axis_range_max]. + NGRAPH_CHECK(((axis >= axis_range_min) && (axis <= axis_range_max)), + node_description, + "Parameter axis ", + axis, + " out of the tensor rank [-", + axis_range_min, + ", ", + axis_range_max, + "]."); + + if (axis < 0) + { + axis = axis + tensor_rank; + } + + return static_cast(axis); +} diff --git a/src/ngraph/validation_util.hpp b/src/ngraph/validation_util.hpp index 6a5682531f8..01d3f9230be 100644 --- a/src/ngraph/validation_util.hpp +++ b/src/ngraph/validation_util.hpp @@ -102,4 +102,49 @@ namespace ngraph const AxisSet& new_axis_mask, const AxisSet& shrink_axis_mask, const AxisSet& ellipsis_mask); + + /// \brief Handle out of range axis. + /// + /// \param[in] node The node with requested axis. + /// \param[in] axis The requested axis value. + /// \param[in] tensor_rank The corresponding tensor rank. + /// + /// \return Checking if axis is in range [-tensor_rank, tensor_rank-1], otherwise + /// returns error. If negative axis, it counts from the last to the first axis, + /// by adding tensor_rank to axis. + int64_t normalize_axis(const Node* node, std::int64_t axis, std::int64_t tensor_rank); + + /// \brief Handle out of range axis. + /// + /// \param[in] node The node with requested axis. + /// \param[in] axis The requested axis value. + /// \param[in] tensor_rank The corresponding tensor rank. + /// \param[in] axis_range_min The min value of accepted range for axis. + /// \param[in] axis_range_max The max value of accepted range for axis. + /// + /// \return Checking if axis is in range [axis_range_min, axis_range_max], otherwise + /// returns error. If negative axis, it counts from the last to the first axis, + /// by adding tensor_rank to axis. + int64_t normalize_axis(const Node* node, + std::int64_t axis, + std::int64_t tensor_rank, + std::int64_t axis_range_min, + std::int64_t axis_range_max); + + /// \brief Handle out of range axis. + /// + /// \param[in] node The name of node with requested axis. + /// \param[in] axis The requested axis value. + /// \param[in] tensor_rank The corresponding tensor rank. + /// \param[in] axis_range_min The min value of accepted range for axis. + /// \param[in] axis_range_max The max value of accepted range for axis. + /// + /// \return Checking if axis is in range [axis_range_min, axis_range_max], otherwise + /// returns error. If negative axis, it counts from the last to the first axis, + /// by adding tensor_rank to axis. + int64_t normalize_axis(const std::string& node_description, + std::int64_t axis, + std::int64_t tensor_rank, + std::int64_t axis_range_min, + std::int64_t axis_range_max); } diff --git a/src/ngraph/visibility.hpp b/src/ngraph/visibility.hpp index 03bfc98bafe..6b1df581954 100644 --- a/src/ngraph/visibility.hpp +++ b/src/ngraph/visibility.hpp @@ -20,7 +20,7 @@ #define NGRAPH_HELPER_DLL_IMPORT __declspec(dllimport) #define NGRAPH_HELPER_DLL_EXPORT __declspec(dllexport) #define NGRAPH_HELPER_DLL_LOCAL -#elif defined NGRAPH_LINUX_VISIBILITY_ENABLE && __GNUC__ >= 4 +#elif defined(__GNUC__) && __GNUC__ >= 4 #define NGRAPH_HELPER_DLL_IMPORT __attribute__((visibility("default"))) #define NGRAPH_HELPER_DLL_EXPORT __attribute__((visibility("default"))) #define NGRAPH_HELPER_DLL_LOCAL __attribute__((visibility("hidden"))) diff --git a/src/tools/nbench/benchmark_utils.cpp b/src/tools/nbench/benchmark_utils.cpp index 89e79002b0d..afcc2b67c14 100644 --- a/src/tools/nbench/benchmark_utils.cpp +++ b/src/tools/nbench/benchmark_utils.cpp @@ -100,6 +100,7 @@ void random_init(shared_ptr tensor) case element::Type_t::u64: init_int_tensor(tensor, 0, 1); break; case element::Type_t::undefined: case element::Type_t::dynamic: + case element::Type_t::u1: case element::Type_t::bf16: case element::Type_t::f16: default: throw runtime_error("unsupported type"); diff --git a/src/tools/nbench/nbench.cpp b/src/tools/nbench/nbench.cpp index 00945dc9a2f..da34eddf341 100644 --- a/src/tools/nbench/nbench.cpp +++ b/src/tools/nbench/nbench.cpp @@ -34,6 +34,7 @@ #include "ngraph/except.hpp" #include "ngraph/file_util.hpp" #include "ngraph/graph_util.hpp" +#include "ngraph/ops.hpp" #include "ngraph/pass/liveness.hpp" #include "ngraph/pass/manager.hpp" #include "ngraph/pass/memory_layout.hpp" @@ -161,29 +162,6 @@ void print_results(vector perf_data, bool timing_detail) } } -element::Type get_op_element_type(const Node& op) -{ - element::Type type; - if (op.description() == "Convert") - { - type = op.input(0).get_element_type(); - } - else if (op.description() == "Equal" || op.description() == "Greater" || - op.description() == "GreaterEq" || op.description() == "Less" || - op.description() == "LessEq" || op.description() == "NotEqual") - { - // Get the type of the second input, not the first - // All BinaryElementwiseComparision ops have the same type for inputs - // Select has bool for first input and the type we are interested in for the second - type = op.input(1).get_element_type(); - } - else - { - type = op.output(0).get_element_type(); - } - return type; -} - int main(int argc, char** argv) { string model_arg; @@ -373,6 +351,10 @@ OPTIONS set type_list; for (shared_ptr node : f->get_ordered_ops()) { + for (auto value : node->outputs()) + { + type_list.insert(value.get_element_type().c_type_string()); + } for (descriptor::Tensor* tensor : node->liveness_new_list) { total_temporary_bytes += tensor->size(); @@ -381,11 +363,8 @@ OPTIONS string op_name = node->description(); string shape_name = "{" + join(node->output(0).get_shape()) + "}"; op_list[op_name + shape_name]++; - auto et = get_op_element_type(*node); - string type_string = et.c_type_string(); - type_list.insert(type_string); - if (op_name == "Constant") + if (node->is_constant()) { total_constant_count++; const Shape& shape = node->output(0).get_shape(); @@ -400,14 +379,14 @@ OPTIONS (const_size * shape_size(node->output(0).get_shape())); } } - else if (op_name == "Parameter") + else if (node->is_parameter()) { total_parameter_count++; const Shape& shape = node->output(0).get_shape(); size_t size = node->output(0).get_element_type().size() * shape_size(shape); total_parameter_bytes += size; } - else if (op_name == "Result") + else if (is_type(node)) { total_result_count++; const Shape& shape = node->input(0).get_shape(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6573536db75..db9112755ef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC aligned_buffer.cpp all_close_f.cpp assertion.cpp + attributes.cpp bfloat16.cpp build_graph.cpp builder_autobroadcast.cpp @@ -53,6 +54,7 @@ set(SRC constant_folding.cpp concat_fusion.cpp control_dependencies.cpp + convert_u1_to_string.cpp coordinate.cpp copy.cpp cpio.cpp @@ -69,6 +71,7 @@ set(SRC node_input_output.cpp nop_elimination.cpp op.cpp + opset1.cpp opset_pass/binary_elementwise_opset_pass.cpp opset_pass/broadcast_opset_pass.cpp opset_pass/convolution_opset_pass.cpp @@ -77,6 +80,7 @@ set(SRC opset_pass/logical_not_opset_pass.cpp opset_pass/logical_or_opset_pass.cpp opset_pass/logical_xor_opset_pass.cpp + opset_pass/one_hot_opset_pass.cpp opset_pass/gather_opset_pass.cpp opset_pass/generate_mask_opset_pass.cpp opset_pass/pad_opset_pass.cpp @@ -105,6 +109,7 @@ set(SRC type_prop/any.cpp type_prop/avg_pool.cpp type_prop/batch_mat_mul.cpp + type_prop/batch_mat_mul_transpose.cpp type_prop/batch_norm.cpp type_prop/binary_elementwise.cpp type_prop/broadcast.cpp @@ -114,6 +119,8 @@ set(SRC type_prop/convert.cpp type_prop/convolution.cpp type_prop/convolution_bias.cpp + type_prop/crop_and_resize.cpp + type_prop/deformable_psroi_pooling.cpp type_prop/depth_to_space.cpp type_prop/dequantize.cpp type_prop/dot.cpp @@ -128,6 +135,7 @@ set(SRC type_prop/fake_quantize.cpp type_prop/gather.cpp type_prop/gather_nd.cpp + type_prop/gather_tree.cpp type_prop/gemm.cpp type_prop/get_output_element.cpp type_prop/grn.cpp @@ -137,6 +145,7 @@ set(SRC type_prop/hard_sigmoid.cpp type_prop/index_reduction.cpp type_prop/layer_norm.cpp + type_prop/log_softmax.cpp type_prop/lrn.cpp type_prop/lstm_cell.cpp type_prop/lstm_sequence.cpp @@ -283,6 +292,7 @@ set(MULTI_TEST_SRC backend/convolution.in.cpp backend/cos.in.cpp backend/cosh.in.cpp + backend/cum_sum.in.cpp backend/divide.in.cpp backend/dot.in.cpp backend/dyn_broadcast.in.cpp @@ -300,6 +310,7 @@ set(MULTI_TEST_SRC backend/gather.in.cpp backend/gelu.in.cpp backend/generate_mask.in.cpp + backend/group_convolution.in.cpp backend/layer_norm.in.cpp backend/log.in.cpp backend/logical_and.in.cpp @@ -348,7 +359,6 @@ set(MULTI_TEST_SRC backend/sum.in.cpp backend/tan.in.cpp backend/tanh.in.cpp - backend/tensorview_custom_mem.in.cpp backend/tile.in.cpp backend/topk.in.cpp backend/transpose.in.cpp @@ -430,7 +440,6 @@ if (NGRAPH_UNIT_TEST_OPENVINO_ENABLE) backend/subtract.in.cpp backend/tan.in.cpp backend/tanh.in.cpp - backend/tensorview_custom_mem.in.cpp backend/transpose.in.cpp backend/validate_call.in.cpp backend/zero_sized.in.cpp @@ -543,9 +552,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(Apple)?Clang$") target_compile_options(unit-test PRIVATE -Wno-undef -Wno-reserved-id-macro) endif() -# So many type_prop tests these days that we need to set /bigobj flag for MSVS. +# So many type_prop tests these days that we need to set /bigobj flag for MSVC. # We should probably split up type_prop.cpp. -if (MSVS) +if (MSVC) target_compile_options(unit-test PRIVATE "/bigobj") endif() @@ -601,7 +610,7 @@ endif() if (NOT NGRAPH_UNIT_TEST_OPENVINO_ENABLE) # If all the runtime libraries are installed into one location, that will make life easier. - if (MSVS) + if (MSVC) add_custom_target(unit-test-check COMMAND set "PATH=${EXTERNAL_PROJECTS_ROOT}/src/ngraph/Release;${EXTERNAL_PROJECTS_ROOT}/mkldnn/lib/;${EXTERNAL_PROJECTS_ROOT}/mkl/src/ext_mkl/lib/;${EXTERNAL_PROJECTS_ROOT}/ext_tbb-prefix/src/ext_tbb/tbb2019_20181203oss/bin/intel64/vc14;%PATH%" COMMAND ${PROJECT_BINARY_DIR}/test/unit-test \${ARGS} diff --git a/test/attributes.cpp b/test/attributes.cpp new file mode 100644 index 00000000000..61dd311b233 --- /dev/null +++ b/test/attributes.cpp @@ -0,0 +1,258 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" + +#include "ngraph/ngraph.hpp" + +using namespace std; +using namespace ngraph; + +enum class TuringModel +{ + XL400, + XL1200 +}; + +namespace ngraph +{ + template <> + EnumNames& EnumNames::get() + { + static auto enum_names = EnumNames( + "TuringModel", {{"XL400", TuringModel::XL400}, {"XL1200", TuringModel::XL1200}}); + return enum_names; + } + + template <> + class AttributeAdapter : public EnumAttributeAdapterBase + { + public: + AttributeAdapter(TuringModel& value) + : EnumAttributeAdapterBase(value) + { + } + + static constexpr DiscreteTypeInfo type_info{"AttributeAdapter", 0}; + const DiscreteTypeInfo& get_type_info() const override { return type_info; } + }; + + constexpr DiscreteTypeInfo AttributeAdapter::type_info; +} + +// Given a Turing machine program and data, return scalar 1 if the program would +// complete, 1 if it would not. +class Oracle : public op::Op +{ +public: + Oracle(const Output& program, + const Output& data, + TuringModel turing_model, + uint64_t model_version, + uint8_t rev, + const string& serial_number, + bool enable_turbo, + const std::vector& hyper_parameters, + const std::vector& ultra_parameters) + : Op({program, data}) + , m_turing_model(turing_model) + , m_model_version(model_version) + , m_rev(rev) + , m_serial_number(serial_number) + , m_enable_turbo(enable_turbo) + , m_hyper_parameters(hyper_parameters) + , m_ultra_parameters(ultra_parameters) + { + } + + static constexpr NodeTypeInfo type_info{"Oracle", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } + Oracle() = default; + + TuringModel get_turing_model() const { return m_turing_model; } + uint64_t get_model_version() const { return m_model_version; } + const string& get_serial_number() const { return m_serial_number; } + bool get_enable_turbo() const { return m_enable_turbo; } + const vector& get_hyper_parameters() const { return m_hyper_parameters; } + const vector& get_ultra_parameters() const { return m_ultra_parameters; } + shared_ptr copy_with_new_args(const NodeVector& args) const override + { + return make_shared(args[0], + args[1], + m_turing_model, + m_model_version, + m_rev, + m_serial_number, + m_enable_turbo, + m_hyper_parameters, + m_ultra_parameters); + } + + void validate_and_infer_types() override { set_output_type(0, element::i64, {}); } + bool visit_attributes(AttributeVisitor& visitor) override + { + visitor.on_attribute("turing_model", m_turing_model); + visitor.on_attribute("model_version", m_model_version); + visitor.on_attribute("rev", m_rev); + visitor.on_attribute("serial_number", m_serial_number); + visitor.on_attribute("enable_turbo", m_enable_turbo); + visitor.on_attribute("hyper_parameters", m_hyper_parameters); + visitor.on_attribute("ultra_parameters", m_ultra_parameters); + return true; + } + +protected: + TuringModel m_turing_model; + uint64_t m_model_version; + int8_t m_rev; + string m_serial_number; + bool m_enable_turbo; + vector m_hyper_parameters; + vector m_ultra_parameters; +}; + +constexpr NodeTypeInfo Oracle::type_info; + +class NodeSaver : public AttributeVisitor +{ +public: + NodeSaver(shared_ptr node) + : m_node_type_info(node->get_type_info()) + { + node->visit_attributes(*this); + } + const NodeTypeInfo& get_node_type_info() { return m_node_type_info; } + string& get_string(const string& name) { return m_strings.at(name); } + bool get_bool(const string& name) { return m_bools.at(name); } + double get_double(const string& name) { return m_doubles.at(name); } + int64_t get_signed(const string& name) { return m_signeds.at(name); } + uint64_t get_unsigned(const string& name) { return m_unsigneds.at(name); } + vector& get_signed_vector(const string& name) { return m_signed_vectors.at(name); } + void set_string(const string& name, const string& value) { m_strings[name] = value; } + void set_bool(const string& name, bool value) { m_bools[name] = value; } + void set_double(const string& name, double value) { m_doubles[name] = value; } + void set_signed(const string& name, int64_t value) { m_signeds[name] = value; } + void set_unsigned(const string& name, uint64_t value) { m_unsigneds[name] = value; } + void set_signed_vector(const string& name, const vector& value) + { + m_signed_vectors[name] = value; + } + + void on_attribute(const string& name, string& value) override { set_string(name, value); }; + void on_attribute(const string& name, bool& value) override { set_bool(name, value); } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + NGRAPH_CHECK(false, "name cannot be marshalled"); + } + // The remaining adapter methods fall back on the void adapter if not implemented + void on_adapter(const string& name, ValueAccessor& adapter) override + { + set_string(name, adapter.get()); + }; + void on_adapter(const string& name, ValueAccessor>& adapter) override + { + set_signed_vector(name, adapter.get()); + } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + set_signed(name, adapter.get()); + } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + set_double(name, adapter.get()); + } + +protected: + NodeTypeInfo m_node_type_info; + map m_strings; + map m_bools; + map m_doubles; + map m_signeds; + map m_unsigneds; + map> m_signed_vectors; +}; + +class NodeBuilder : public AttributeVisitor +{ +public: + NodeBuilder(const shared_ptr& node) + : m_values(node) + { + } + + shared_ptr create() + { + shared_ptr node(FactoryRegistry::get().create(m_values.get_node_type_info())); + node->visit_attributes(*this); + node->validate_and_infer_types(); + return node; + } + + void on_attribute(const string& name, string& value) override + { + value = m_values.get_string(name); + }; + void on_attribute(const string& name, bool& value) override { value = m_values.get_bool(name); } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + NGRAPH_CHECK(false, "name cannot be marshalled"); + } + // The remaining adapter methods fall back on the void adapter if not implemented + void on_adapter(const string& name, ValueAccessor& adapter) override + { + adapter.set(m_values.get_string(name)); + }; + void on_adapter(const string& name, ValueAccessor>& adapter) override + { + adapter.set(m_values.get_signed_vector(name)); + } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + adapter.set(m_values.get_signed(name)); + } + void on_adapter(const string& name, ValueAccessor& adapter) override + { + adapter.set(m_values.get_double(name)); + } + +protected: + NodeSaver m_values; +}; + +TEST(attributes, user_op) +{ + FactoryRegistry::get().register_factory(); + auto program = make_shared(element::i32, Shape{200}); + auto data = make_shared(element::i32, Shape{200}); + auto oracle = make_shared(program, + data, + TuringModel::XL1200, + 2, + 4, + "12AU7", + true, + vector{1, 2, 4, 8}, + vector{-1, -2, -4, -8}); + NodeBuilder builder(oracle); + auto g_oracle = as_type_ptr(builder.create()); + + EXPECT_EQ(g_oracle->get_turing_model(), oracle->get_turing_model()); + EXPECT_EQ(g_oracle->get_model_version(), oracle->get_model_version()); + EXPECT_EQ(g_oracle->get_serial_number(), oracle->get_serial_number()); + EXPECT_EQ(g_oracle->get_enable_turbo(), oracle->get_enable_turbo()); + EXPECT_EQ(g_oracle->get_hyper_parameters(), oracle->get_hyper_parameters()); + EXPECT_EQ(g_oracle->get_ultra_parameters(), oracle->get_ultra_parameters()); +} diff --git a/test/backend/api.in.cpp b/test/backend/api.in.cpp index d4a4b3072e9..0842fd22890 100644 --- a/test/backend/api.in.cpp +++ b/test/backend/api.in.cpp @@ -53,58 +53,6 @@ NGRAPH_TEST(${BACKEND_NAME}, create_tensor_1) EXPECT_TRUE(test::all_close_f(read_vector(result), expected, MIN_FLOAT_TOLERANCE_BITS)); } -// This tests a backend's implementation of the three parameter version of create_tensor -// Testing using this tensor as a Function input -NGRAPH_TEST(${BACKEND_NAME}, create_tensor_2_input) -{ - Shape shape{2, 2}; - auto A = make_shared(element::f32, shape); - auto B = make_shared(element::f32, shape); - auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); - - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - // Create some tensors for input/output - vector av = {1, 2, 3, 4}; - vector bv = {5, 6, 7, 8}; - shared_ptr a = backend->create_tensor(element::f32, shape, av.data()); - shared_ptr b = backend->create_tensor(element::f32, shape, bv.data()); - shared_ptr result = backend->create_tensor(element::f32, shape); - - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a, b}); - vector expected = {6, 8, 10, 12}; - EXPECT_TRUE(test::all_close_f(read_vector(result), expected, MIN_FLOAT_TOLERANCE_BITS)); -} - -// This tests a backend's implementation of the three parameter version of create_tensor -// Testing using this tensor as a Function output -NGRAPH_TEST(${BACKEND_NAME}, create_tensor_2_output) -{ - Shape shape{2, 2}; - auto A = make_shared(element::f32, shape); - auto B = make_shared(element::f32, shape); - auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); - - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - // Create some tensors for input/output - vector av = {1, 2, 3, 4}; - vector bv = {5, 6, 7, 8}; - shared_ptr a = backend->create_tensor(element::f32, shape); - shared_ptr b = backend->create_tensor(element::f32, shape); - copy_data(a, av); - copy_data(b, bv); - - vector actual(4); - shared_ptr result = backend->create_tensor(element::f32, shape, actual.data()); - - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a, b}); - vector expected = {6, 8, 10, 12}; - EXPECT_TRUE(test::all_close_f(actual, expected, MIN_FLOAT_TOLERANCE_BITS)); -} - // This tests a backend's implementation of the copy_from for tensor NGRAPH_TEST(${BACKEND_NAME}, tensor_copy_from) { diff --git a/test/backend/auto_broadcast.in.cpp b/test/backend/auto_broadcast.in.cpp index ff71288edfa..3d1125cce88 100644 --- a/test/backend/auto_broadcast.in.cpp +++ b/test/backend/auto_broadcast.in.cpp @@ -21,6 +21,8 @@ #include #include +#include "util/type_prop.hpp" + // clang-format off #ifdef ${BACKEND_NAME}_FLOAT_TOLERANCE_BITS #define DEFAULT_FLOAT_TOLERANCE_BITS ${BACKEND_NAME}_FLOAT_TOLERANCE_BITS @@ -29,6 +31,15 @@ #ifdef ${BACKEND_NAME}_DOUBLE_TOLERANCE_BITS #define DEFAULT_DOUBLE_TOLERANCE_BITS ${BACKEND_NAME}_DOUBLE_TOLERANCE_BITS #endif + +#ifndef RTOL +#define RTOL 1e-4 +#endif + +#ifndef ATOL +#define ATOL 1e-4 +#endif + // clang-format on #include "gtest/gtest.h" @@ -48,7 +59,8 @@ template void check_auto_bcast( const std::vector>& inputs, const std::vector output, - const op::AutoBroadcastSpec& autob = op::AutoBroadcastSpec(op::AutoBroadcastType::NUMPY)) + const op::AutoBroadcastSpec& autob = op::AutoBroadcastSpec(op::AutoBroadcastType::NUMPY), + bool set_tolerance = false) { auto iet = element::from(); auto oet = element::from(); @@ -77,7 +89,17 @@ void check_auto_bcast( auto handle = backend->compile(f); handle->call_with_validate({result}, {a, b}); - EXPECT_TRUE(test::all_close(read_vector(result), output)); + if (set_tolerance) + { + EXPECT_TRUE(test::all_close(read_vector(result), + output, + static_cast(RTOL), + static_cast(ATOL))); + } + else + { + EXPECT_TRUE(test::all_close(read_vector(result), output)); + } } NGRAPH_TEST(${BACKEND_NAME}, auto_bcast_binary_elementwise) @@ -94,7 +116,9 @@ NGRAPH_TEST(${BACKEND_NAME}, auto_bcast_binary_elementwise) check_auto_bcast({{1, 2, 3, 4, 5, 6}, {1, 5, 8}}, {1, 2, 3, 1, 5, 6}); check_auto_bcast({{1, 2, 3, 4, 5, 6}, {1, 2, 3}}, - {1, 4, 27, 4, 25, 216}); + {1, 4, 27, 4, 25, 216}, + op::AutoBroadcastSpec(op::AutoBroadcastType::NUMPY), + true); check_auto_bcast({{1, 0, 1, 0, 0, 1}, {1, 0, 1}}, {1, 0, 1, 0, 0, 1}); check_auto_bcast({{1, 0, 1, 0, 1, 1}, {1, 0, 0}}, {1, 0, 1, 1, 1, 1}); @@ -126,7 +150,7 @@ NGRAPH_TEST(${BACKEND_NAME}, auto_bcast_binary_elementwise_pdpd) check_auto_bcast( {{1, 2, 3, 4, 5, 6}, {1, 5, 8}}, {1, 2, 3, 1, 5, 6}, autob); check_auto_bcast( - {{1, 2, 3, 4, 5, 6}, {1, 2, 3}}, {1, 4, 27, 4, 25, 216}, autob); + {{1, 2, 3, 4, 5, 6}, {1, 2, 3}}, {1, 4, 27, 4, 25, 216}, autob, true); check_auto_bcast( {{1, 0, 1, 0, 0, 1}, {1, 0, 1}}, {1, 0, 1, 0, 0, 1}, autob); check_auto_bcast( @@ -191,3 +215,35 @@ NGRAPH_TEST(${BACKEND_NAME}, auto_bcast_binary_elementwise_pdpd_dynamic) ex->call_with_validate({t_r}, {t_a, t_b}); ASSERT_EQ(t_r->get_shape(), (Shape{2, 3, 4, 5})); } + +NGRAPH_TEST(${BACKEND_NAME}, auto_bcast_string_cast) +{ + auto a = make_shared(element::f32, Shape{1}); + auto b = make_shared(element::f32, Shape{1}); + + auto add = make_shared(a, b, "NUMPY"); + ASSERT_EQ(add->get_autob(), op::AutoBroadcastType::NUMPY); + + add = make_shared(a, b, "NONE"); + ASSERT_EQ(add->get_autob(), op::AutoBroadcastType::NONE); + + add = make_shared(a, b, "PDPD"); + ASSERT_EQ(add->get_autob(), op::AutoBroadcastType::PDPD); + + add = make_shared(a, b, "EXPLICIT"); + ASSERT_EQ(add->get_autob(), op::AutoBroadcastType::EXPLICIT); + + try + { + add = make_shared(a, b, "UNKNOWN"); + FAIL() << "Unknown AutoBroadcastType not detected."; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("Invalid 'type' value passed in.")); + } + catch (...) + { + FAIL() << "AutoBroadcastType checking failed for unexpected reason"; + } +} diff --git a/test/backend/autodiff.in.cpp b/test/backend/autodiff.in.cpp index 66fc2690158..2e2f572659a 100644 --- a/test/backend/autodiff.in.cpp +++ b/test/backend/autodiff.in.cpp @@ -27,10 +27,6 @@ #include "ngraph/ngraph.hpp" #include "ngraph/pass/manager.hpp" -#if defined(AUTODIFF_BACKEND_CPU) -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" -#include "ngraph/runtime/cpu/pass/cpu_mat_fusion.hpp" -#endif #include "ngraph/runtime/reference/avg_pool.hpp" #include "util/autodiff/backprop_function.hpp" #include "util/autodiff/numeric_compare.hpp" diff --git a/test/backend/batch_mat_mul.in.cpp b/test/backend/batch_mat_mul.in.cpp index ec117fbc03c..3ea81ed266f 100644 --- a/test/backend/batch_mat_mul.in.cpp +++ b/test/backend/batch_mat_mul.in.cpp @@ -16,8 +16,11 @@ #include "gtest/gtest.h" #include "ngraph/ngraph.hpp" +#include "ngraph/pass/batch_fusion.hpp" +#include "ngraph/pass/manager.hpp" #include "util/all_close.hpp" #include "util/all_close_f.hpp" +#include "util/autodiff/numeric_compare.hpp" #include "util/known_element_types.hpp" #include "util/ndarray.hpp" #include "util/random.hpp" @@ -93,4 +96,56 @@ NGRAPH_TEST(${BACKEND_NAME}, batch_mat_mul_forward) ref_results.at(i), backend_results.at(i), DEFAULT_FLOAT_TOLERANCE_BITS + 3)); } } + +#ifndef NGRAPH_JSON_DISABLE +NGRAPH_TEST(${BACKEND_NAME}, fuse_batch_mat_mul_transpose_forward) +{ + pass::Manager pass_manager; + pass_manager.register_pass(); + + const std::string file_name("mxnet/batch_dot_3.json"); + auto backend_f = make_function_from_file(file_name); + auto int_f = make_function_from_file(file_name); + pass_manager.run_passes(backend_f); + test::Uniform rng(0.0f, 1.0f); + vector> args; + + for (shared_ptr param : int_f->get_parameters()) + { + vector tensor_val(shape_size(param->get_shape())); + rng.initialize(tensor_val); + args.push_back(tensor_val); + } + auto int_results = execute(int_f, args, "INTERPRETER"); + auto backend_results = execute(backend_f, args, "${BACKEND_NAME}"); + for (size_t i = 0; i < int_results.size(); i++) + { + EXPECT_TRUE(test::all_close(backend_results.at(i), int_results.at(i), 1.0e-4f, 1.0e-4f)); + } +} + +//#if defined(AUTODIFF_BACKEND_${BACKEND_NAME}) +NGRAPH_TEST(${BACKEND_NAME}, backwards_batchmatmultranspose_tensor2_tensor2) +{ + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + const std::string file_name("mxnet/batch_dot_3.json"); + auto f = make_function_from_file(file_name); + + test::Uniform rng(-1.0f, 1.0f); + std::vector> args; + for (shared_ptr param : f->get_parameters()) + { + args.push_back(rng.initialize(backend->create_tensor(param->get_shape()))); + } + + auto g = make_function_from_file(file_name); + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(g); + EXPECT_TRUE(autodiff_numeric_compare(backend.get(), f, g, args, .01f, .01f)); +} +//#endif +#endif + #endif diff --git a/test/backend/convolution.in.cpp b/test/backend/convolution.in.cpp index b94eeb26112..2ae3954b22a 100644 --- a/test/backend/convolution.in.cpp +++ b/test/backend/convolution.in.cpp @@ -154,9 +154,9 @@ NGRAPH_TEST(${BACKEND_NAME}, dyn_convolution_backprop_data) auto padding_end = CoordinateDiff{0, 0}; auto conv1 = make_shared( - filters, deltas, data_batch_shape, strides, dilations, padding_begin, padding_end); + deltas, filters, data_batch_shape, strides, padding_begin, padding_end, dilations); - auto f = make_shared(conv1, ParameterVector{filters, deltas, data_batch_shape}); + auto f = make_shared(conv1, ParameterVector{deltas, filters, data_batch_shape}); auto backend = runtime::Backend::create("${BACKEND_NAME}", true); @@ -178,10 +178,10 @@ NGRAPH_TEST(${BACKEND_NAME}, dyn_convolution_backprop_data) vector shapes = {2, 3, 5, 5}; // Create some tensors for input/output - auto a = backend->create_tensor(element::f32, shape_filter); - copy_data(a, filter); - auto b = backend->create_tensor(element::f32, shape_delta); - copy_data(b, delta); + auto a = backend->create_tensor(element::f32, shape_delta); + copy_data(a, delta); + auto b = backend->create_tensor(element::f32, shape_filter); + copy_data(b, filter); auto c = backend->create_tensor(element::i64, Shape{shapes.size()}); // dynamic data batch shape copy_data(c, shapes); handle->call_with_validate({result}, {a, b, c}); diff --git a/test/backend/cum_sum.in.cpp b/test/backend/cum_sum.in.cpp new file mode 100644 index 00000000000..e9de542d497 --- /dev/null +++ b/test/backend/cum_sum.in.cpp @@ -0,0 +1,189 @@ +//***************************************************************************** +// Copyright 2017-2019 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 +#include +#include +#include + +#include "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/ndarray.hpp" +#include "util/random.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +static std::mt19937_64 random_generator; + +using namespace std; +using namespace ngraph; + +static string s_manifest = "${MANIFEST}"; + +NGRAPH_TEST(${BACKEND_NAME}, cum_sum_default) +{ + Shape shape{1, 4}; + auto A = make_shared(element::f32, shape); + auto axis = make_shared(element::i32, Shape{1}); + auto f = make_shared(make_shared(A, axis), ParameterVector{A, axis}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, vector{1, 2, 3, 4}); + auto axis_tensor = backend->create_tensor(axis->get_element_type(), axis->get_shape()); + copy_data(axis_tensor, vector{1}); + auto result = backend->create_tensor(element::f32, shape); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, axis_tensor}); + EXPECT_TRUE(test::all_close_f((vector{1, 3, 6, 10}), read_vector(result))); +} + +NGRAPH_TEST(${BACKEND_NAME}, cum_sum_2dim) +{ + Shape shape{2, 4}; + auto A = make_shared(element::f32, shape); + auto axis = make_shared(element::i64, Shape{1}); + auto f = make_shared(make_shared(A, axis), ParameterVector{A, axis}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, vector{0, 1, 2, 3, 4, 5, 6, 7}); + auto axis_tensor = backend->create_tensor(axis->get_element_type(), axis->get_shape()); + copy_data(axis_tensor, vector{0}); + auto result = backend->create_tensor(element::f32, shape); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, axis_tensor}); + EXPECT_TRUE( + test::all_close_f((vector{0, 1, 2, 3, 4, 6, 8, 10}), read_vector(result))); +} + +NGRAPH_TEST(${BACKEND_NAME}, cum_sum_3d) +{ + auto test_cumsum_3d = [](const int32_t axis_val) -> void { + Shape shape{3, 2, 4}; + auto A = make_shared(element::f32, shape); + auto axis = make_shared(element::i32, Shape{1}); + auto f = make_shared(make_shared(A, axis), ParameterVector{A, axis}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}); + auto axis_tensor = backend->create_tensor(axis->get_element_type(), axis->get_shape()); + copy_data(axis_tensor, vector{axis_val}); + auto result = backend->create_tensor(element::f32, shape); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, axis_tensor}); + + if (axis_val == 0) + { + EXPECT_TRUE( + test::all_close_f((vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 42, 45}), + read_vector(result))); + } + else if (axis_val == 1) + { + EXPECT_TRUE( + test::all_close_f((vector{0, 1, 2, 3, 4, 6, 8, 10, 8, 9, 10, 11, + 20, 22, 24, 26, 16, 17, 18, 19, 36, 38, 40, 42}), + read_vector(result))); + } + else if (axis_val == 2) + { + EXPECT_TRUE( + test::all_close_f((vector{0, 1, 3, 6, 4, 9, 15, 22, 8, 17, 27, 38, + 12, 25, 39, 54, 16, 33, 51, 70, 20, 41, 63, 86}), + read_vector(result))); + } + }; + test_cumsum_3d(0); + test_cumsum_3d(1); + test_cumsum_3d(2); +} + +NGRAPH_TEST(${BACKEND_NAME}, cum_sum_2dim_allmodes) +{ + auto test_cum_sum_allmodes = [](const int64_t axis_val, int exclusive, int reverse) { + Shape shape{2, 4}; + auto A = make_shared(element::f32, shape); + auto axis = make_shared(element::i64, Shape{1}); + auto f = make_shared(make_shared(A, axis, exclusive, reverse), + ParameterVector{A, axis}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, vector{0, 1, 2, 3, 4, 5, 6, 7}); + auto axis_tensor = backend->create_tensor(axis->get_element_type(), axis->get_shape()); + copy_data(axis_tensor, vector{axis_val}); + auto result = backend->create_tensor(element::f32, shape); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, axis_tensor}); + if (axis_val == 1 && exclusive == 1 && reverse == 0) + { + EXPECT_TRUE(test::all_close_f((vector{0, 0, 1, 3, 0, 4, 9, 15}), + read_vector(result))); + } + else if (axis_val == 1 && exclusive == 0 && reverse == 1) + { + EXPECT_TRUE(test::all_close_f((vector{6, 6, 5, 3, 22, 18, 13, 7}), + read_vector(result))); + } + else if (axis_val == 1 && exclusive == 1 && reverse == 1) + { + EXPECT_TRUE(test::all_close_f((vector{6, 5, 3, 0, 18, 13, 7, 0}), + read_vector(result))); + } + else if (axis_val == 0 && exclusive == 0 && reverse == 0) + { + EXPECT_TRUE(test::all_close_f((vector{0, 1, 2, 3, 4, 6, 8, 10}), + read_vector(result))); + } + else if (axis_val == 0 && exclusive == 1 && reverse == 1) + { + EXPECT_TRUE(test::all_close_f((vector{4, 5, 6, 7, 0, 0, 0, 0}), + read_vector(result))); + } + else if (axis_val == 0 && exclusive == 0 && reverse == 1) + { + EXPECT_TRUE(test::all_close_f((vector{4, 6, 8, 10, 4, 5, 6, 7}), + read_vector(result))); + } + }; + + test_cum_sum_allmodes(1, 1, 0); + test_cum_sum_allmodes(-1, 0, 1); + test_cum_sum_allmodes(-1, 1, 1); + test_cum_sum_allmodes(0, 0, 0); + test_cum_sum_allmodes(0, 1, 1); + test_cum_sum_allmodes(0, 0, 1); +} diff --git a/test/backend/dyn_reshape.in.cpp b/test/backend/dyn_reshape.in.cpp index 1cf8f109fe9..ffbdc649776 100644 --- a/test/backend/dyn_reshape.in.cpp +++ b/test/backend/dyn_reshape.in.cpp @@ -120,7 +120,7 @@ NGRAPH_TEST(${BACKEND_NAME}, reshape_v1) { auto arg = std::make_shared(element::i64, PartialShape::dynamic()); auto pattern = make_shared(element::i64, PartialShape::dynamic(1)); - auto reshape_v1 = std::make_shared(arg, pattern); + auto reshape_v1 = std::make_shared(arg, pattern, false); auto f = std::make_shared(NodeVector{reshape_v1}, ParameterVector{arg, pattern}); diff --git a/test/backend/fused_op.in.cpp b/test/backend/fused_op.in.cpp index bf1180fc449..03e7f096777 100644 --- a/test/backend/fused_op.in.cpp +++ b/test/backend/fused_op.in.cpp @@ -95,13 +95,31 @@ NGRAPH_TEST(${BACKEND_NAME}, prelu) EXPECT_EQ(expected, read_vector(result0)); } +NGRAPH_TEST(${BACKEND_NAME}, reciprocal) +{ + Shape shape{3, 2}; + auto A = make_shared(element::f32, shape); + auto reciprocal = make_shared(A); + auto f0 = make_shared(NodeVector{reciprocal}, ParameterVector{A}); + + auto test_case = test::NgraphTestCase(f0, "${BACKEND_NAME}"); + test_case.add_input(vector{1, 2, 3, 4, 5, 6}); + test_case.add_expected_output( + Shape{3, 2}, vector{1.0f, 1 / 2.0f, 1 / 3.0f, 1 / 4.0f, 1 / 5.0f, 1 / 6.0f}); + test_case.run(); +} + NGRAPH_TEST(${BACKEND_NAME}, hardsigmoid) { - Shape shape{2, 7}; - float alpha = 0.125f; - float beta = 0.642f; + const Shape shape{2, 7}; + const float alpha_f = 0.125f; + const float beta_f = 0.642f; + + const auto A = make_shared(element::f32, shape); + + const auto alpha = op::Constant::create(A->get_element_type(), Shape{}, {alpha_f}); + const auto beta = op::Constant::create(A->get_element_type(), Shape{}, {beta_f}); - auto A = make_shared(element::f32, shape); auto hardsigmoid = make_shared(A, alpha, beta); auto f0 = make_shared(NodeVector{hardsigmoid}, ParameterVector{A}); @@ -123,7 +141,7 @@ NGRAPH_TEST(${BACKEND_NAME}, hardsigmoid) numeric_limits::min() / 16.f, -numeric_limits::min() / 16.f}; - auto impl = [alpha, beta](float val) { return min(max(alpha * val + beta, 0.f), 1.f); }; + auto impl = [alpha_f, beta_f](float val) { return min(max(alpha_f * val + beta_f, 0.f), 1.f); }; vector expected_output; transform(begin(input_data), end(input_data), back_inserter(expected_output), impl); @@ -347,6 +365,57 @@ NGRAPH_TEST(${BACKEND_NAME}, group_conv) EXPECT_EQ(expected, read_vector(result0)); } +NGRAPH_TEST(${BACKEND_NAME}, batch_mat_mul_transpose) +{ + Shape shape0 = Shape{2, 2, 3}; + Shape shape1 = Shape{2, 3, 4}; + auto arg0 = make_shared(element::f32, shape0); + auto arg1 = make_shared(element::f32, shape1); + auto bmmt = make_shared(arg0, arg1, false, false); + auto f0 = make_shared(NodeVector{bmmt}, ParameterVector{arg0, arg1}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape0); + copy_data(a, vector{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}); + auto b = backend->create_tensor(element::f32, shape1); + copy_data( + b, vector{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3}); + auto result0 = backend->create_tensor(element::f32, Shape{2, 2, 4}); + + auto handle = backend->compile(f0); + handle->call_with_validate({result0}, {a, b}); + vector expected{6, 6, 6, 6, 12, 12, 12, 12, 18, 18, 18, 18, 24, 24, 24, 24}; + EXPECT_EQ(expected, read_vector(result0)); +} + +NGRAPH_TEST(${BACKEND_NAME}, batch_mat_mul_transpose_with_transpose) +{ + Shape shape0 = Shape{2, 3, 2}; + Shape shape1 = Shape{2, 3, 4}; + auto arg0 = make_shared(element::f32, shape0); + auto arg1 = make_shared(element::f32, shape1); + auto bmmt = make_shared(arg0, arg1, true, false); + auto f0 = make_shared(NodeVector{bmmt}, ParameterVector{arg0, arg1}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, shape0); + copy_data(a, vector{1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}); + auto b = backend->create_tensor(element::f32, shape1); + copy_data( + b, vector{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3}); + auto result0 = backend->create_tensor(element::f32, Shape{2, 2, 4}); + + auto handle = backend->compile(f0); + handle->call_with_validate({result0}, {a, b}); + vector expected{9, 9, 9, 9, 11, 11, 11, 11, 21, 21, 21, 21, 23, 23, 23, 23}; + EXPECT_EQ(expected, read_vector(result0)); + auto res = read_vector(result0); +} + NGRAPH_TEST(${BACKEND_NAME}, group_conv_striding) { auto data = make_shared(element::f32, Shape{1, 4, 2, 2}); @@ -573,10 +642,11 @@ NGRAPH_TEST(${BACKEND_NAME}, group_conv_groups_included_in_shape) EXPECT_EQ(expected, read_vector(result0)); } -NGRAPH_TEST(${BACKEND_NAME}, space_to_depth) +NGRAPH_TEST(${BACKEND_NAME}, space_to_depth_block_first) { auto A = make_shared(element::f32, Shape{1, 2, 4, 4}); - auto space_to_depth = make_shared(A, 2); + const auto mode = ngraph::op::SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST; + auto space_to_depth = make_shared(A, mode, 2); auto function = make_shared(NodeVector{space_to_depth}, ParameterVector{A}); auto test_case = test::NgraphTestCase(function, "${BACKEND_NAME}"); @@ -593,6 +663,24 @@ NGRAPH_TEST(${BACKEND_NAME}, space_to_depth) test_case.run(); } +NGRAPH_TEST(${BACKEND_NAME}, space_to_depth_depth_first) +{ + auto A = make_shared(element::f32, Shape{1, 2, 4, 4}); + const auto mode = ngraph::op::SpaceToDepth::SpaceToDepthMode::DEPTH_FIRST; + auto space_to_depth = make_shared(A, mode, 2); + auto function = make_shared(NodeVector{space_to_depth}, ParameterVector{A}); + + auto test_case = test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input({0.f, 16.f, 2.f, 18.f, 1.f, 17.f, 3.f, 19.f, 8.f, 24.f, 10.f, + 26.f, 9.f, 25.f, 11.f, 27.f, 4.f, 20.f, 6.f, 22.f, 5.f, 21.f, + 7.f, 23.f, 12.f, 28.f, 14.f, 30.f, 13.f, 29.f, 15.f, 31.f}); + test_case.add_expected_output( + Shape{1, 8, 2, 2}, {0.f, 2.f, 8.f, 10.f, 16.f, 18.f, 24.f, 26.f, 1.f, 3.f, 9.f, + 11.f, 17.f, 19.f, 25.f, 27.f, 4.f, 6.f, 12.f, 14.f, 20.f, 22.f, + 28.f, 30.f, 5.f, 7.f, 13.f, 15.f, 21.f, 23.f, 29.f, 31.f}); + test_case.run(); +} + NGRAPH_TEST(${BACKEND_NAME}, depth_to_space_block_first) { auto A = make_shared(element::f32, Shape{1, 8, 2, 2}); @@ -1271,8 +1359,9 @@ NGRAPH_TEST(${BACKEND_NAME}, squared_difference_broadcast) NGRAPH_TEST(${BACKEND_NAME}, split_3_equal_parts) { const auto data = make_shared(element::i32, Shape{6}); + const auto axis = op::Constant::create(element::i64, Shape{}, {0}); - const auto tested_op = make_shared(data, 0, 3); + const auto tested_op = make_shared(data, axis, 3); const auto function = make_shared(tested_op->decompose_op(), ParameterVector{data}); auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); @@ -1290,7 +1379,8 @@ NGRAPH_TEST(${BACKEND_NAME}, split_var_len_parts) const auto data = make_shared(element::i32, Shape{2, 6}); const std::vector splits = {2, 4}; - const auto tested_op = make_shared(data, 1, splits); + const auto axis = op::Constant::create(element::i64, Shape{}, {1}); + const auto tested_op = make_shared(data, axis, splits); const auto function = make_shared(tested_op->decompose_op(), ParameterVector{data}); auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); @@ -2515,3 +2605,47 @@ NGRAPH_TEST(${BACKEND_NAME}, gru_cell_activation_function) test_case.run(); } + +NGRAPH_TEST(${BACKEND_NAME}, cross_entropy_with_soft_labels) +{ + Shape tensor_shape{2, 4}; + auto input = make_shared(element::f32, tensor_shape); + auto labels = make_shared(element::i32, Shape{2, 4}); + auto cross_entropy = make_shared(input, labels, true); + auto f0 = make_shared(NodeVector{cross_entropy}, ParameterVector{input, labels}); + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, tensor_shape); + copy_data(a, vector{0.25f, 0.25f, 0.25f, 0.25f, 0.01f, 0.01f, 0.01f, 0.96f}); + auto b = backend->create_tensor(element::i32, Shape{2, 4}); + copy_data(b, vector{0, 0, 0, 1, 0, 0, 0, 1}); + auto result0 = backend->create_tensor(element::f32, Shape{2, 1}); + auto handle = backend->compile(f0); + handle->call_with_validate({result0}, {a, b}); + vector expected{1.38629f, 0.040822f}; + auto result = read_vector(result0); + EXPECT_TRUE(test::all_close_f(result, expected, 23)); +} + +NGRAPH_TEST(${BACKEND_NAME}, cross_entropy_with_one_hot) +{ + Shape tensor_shape{2, 4}; + auto input = make_shared(element::f32, tensor_shape); + auto labels = make_shared(element::i32, Shape{2, 1}); + auto cross_entropy = make_shared(input, labels, false); + auto f0 = make_shared(NodeVector{cross_entropy}, ParameterVector{input, labels}); + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::f32, tensor_shape); + copy_data(a, vector{0.25f, 0.25f, 0.25f, 0.25f, 0.01f, 0.01f, 0.01f, 0.96f}); + auto b = backend->create_tensor(element::i32, Shape{2, 1}); + copy_data(b, vector{1, 1}); + auto result0 = backend->create_tensor(element::f32, Shape{2, 1}); + auto handle = backend->compile(f0); + handle->call_with_validate({result0}, {a, b}); + vector expected{1.38629f, 4.60517f}; + auto result = read_vector(result0); + EXPECT_TRUE(test::all_close_f(result, expected, 23)); +} diff --git a/test/backend/group_convolution.in.cpp b/test/backend/group_convolution.in.cpp new file mode 100644 index 00000000000..39f26af911c --- /dev/null +++ b/test/backend/group_convolution.in.cpp @@ -0,0 +1,128 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/all_close.hpp" +#include "util/all_close_f.hpp" +#include "util/known_element_types.hpp" +#include "util/ndarray.hpp" +#include "util/test_control.hpp" +#include "util/test_tools.hpp" + +using namespace std; +using namespace ngraph; + +static string s_manifest = "${MANIFEST}"; + +NGRAPH_TEST(${BACKEND_NAME}, dyn_group_convolution_backprop_data) +{ + Shape shape_filter{6, 1, 3, 3}; + auto filters = make_shared(element::f32, PartialShape::dynamic()); + Shape shape_delta{2, 6, 3, 3}; + auto deltas = make_shared(element::f32, PartialShape::dynamic()); + Shape shape_data_batch{2, 3, 5, 5}; + auto data_batch = make_shared(element::f32, PartialShape::dynamic()); + auto strides = Strides{1, 1}; + auto dilations = Strides{1, 1}; + auto padding_begin = CoordinateDiff{0, 0}; + auto padding_end = CoordinateDiff{0, 0}; + size_t groups = 3; + + auto conv_bprop_data = make_shared( + data_batch, filters, deltas, strides, dilations, padding_begin, padding_end, groups); + + auto f = make_shared(conv_bprop_data, ParameterVector{data_batch, filters, deltas}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}", true); + + auto handle = backend->compile(f); + + auto result = backend->create_dynamic_tensor(element::f32, PartialShape::dynamic()); + + vector filter, delta, data, expected_result; + + for (int i = 0; i < 6 * 1 * 3 * 3; i++) + filter.emplace_back(i); + + for (int i = 0; i < 2 * 6 * 3 * 3; i++) + delta.emplace_back(i); + + for (int i = 0; i < 2 * 3 * 5 * 5; i++) + data.emplace_back(i); + + for (int i = 0; i < 2 * 3 * 5 * 5; i++) + expected_result.emplace_back(i); + + auto a = backend->create_tensor(element::f32, shape_data_batch); + copy_data(a, data); + auto b = backend->create_tensor(element::f32, shape_filter); + copy_data(b, filter); + auto c = backend->create_tensor(element::f32, shape_delta); + copy_data(c, delta); + handle->call_with_validate({result}, {a, b, c}); + EXPECT_FALSE(test::all_close_f(vector{expected_result}, read_vector(result))); +} + +NGRAPH_TEST(${BACKEND_NAME}, dyn_group_convolution_backprop_filters) +{ + Shape shape_filter{6, 1, 3, 3}; + auto filters = make_shared(element::f32, PartialShape::dynamic()); + Shape shape_delta{2, 6, 3, 3}; + auto deltas = make_shared(element::f32, PartialShape::dynamic()); + Shape shape_data_batch{2, 3, 5, 5}; + auto data_batch = make_shared(element::f32, PartialShape::dynamic()); + auto strides = Strides{1, 1}; + auto dilations = Strides{1, 1}; + auto padding_begin = CoordinateDiff{0, 0}; + auto padding_end = CoordinateDiff{0, 0}; + size_t groups = 3; + + auto conv_bprop_filters = make_shared( + data_batch, filters, deltas, strides, dilations, padding_begin, padding_end, groups); + + auto f = + make_shared(conv_bprop_filters, ParameterVector{data_batch, filters, deltas}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}", true); + + auto handle = backend->compile(f); + + auto result = backend->create_dynamic_tensor(element::f32, PartialShape::dynamic()); + + vector filter, delta, data, expected_result; + + for (int i = 0; i < 6 * 1 * 3 * 3; i++) + filter.emplace_back(i); + + for (int i = 0; i < 2 * 6 * 3 * 3; i++) + delta.emplace_back(i); + + for (int i = 0; i < 2 * 3 * 5 * 5; i++) + data.emplace_back(i); + + for (int i = 0; i < 6 * 1 * 3 * 3; i++) + expected_result.emplace_back(i); + + auto a = backend->create_tensor(element::f32, shape_data_batch); + copy_data(a, data); + auto b = backend->create_tensor(element::f32, shape_filter); + copy_data(b, filter); + auto c = backend->create_tensor(element::f32, shape_delta); + copy_data(c, delta); + handle->call_with_validate({result}, {a, b, c}); + EXPECT_FALSE(test::all_close_f(vector{expected_result}, read_vector(result))); +} diff --git a/test/backend/lrn.in.cpp b/test/backend/lrn.in.cpp index 62cd6baeccd..7da408f4001 100644 --- a/test/backend/lrn.in.cpp +++ b/test/backend/lrn.in.cpp @@ -293,3 +293,90 @@ NGRAPH_TEST(${BACKEND_NAME}, lrn_6D_across_2_axes) 0.5130308f, 0.5415326f, 0.4643635f, 0.4875816f, 0.5107998f, 0.534018f}; EXPECT_TRUE(test::all_close_f(expected, read_vector(result))); } + +NGRAPH_TEST(${BACKEND_NAME}, lrn_2d_across_empty) +{ + Shape shape{12}; + auto A = make_shared(element::f32, shape); + auto axes = make_shared(element::i64, Shape{0}, vector{}); + double alpha = 3; + double beta = 0.5; + double bias = 1; + size_t size = 3; + auto lrn = make_shared(A, axes, alpha, beta, bias, size); + auto f = make_shared(lrn, ParameterVector{A}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + vector args{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f}; + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, args); + + auto result = backend->create_tensor(element::f32, shape); + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a}); + + vector expected{ + 0.0f, + 0.7071068f, + 0.8944272f, + 0.9486833f, + 0.9701425f, + 0.9805807f, + 0.9863939f, + 0.9899495f, + 0.9922779f, + 0.9938837f, + 0.9950372f, + 0.9958932f, + }; + EXPECT_TRUE(test::all_close_f(expected, read_vector(result))); +} + +NGRAPH_TEST(${BACKEND_NAME}, lrn_2d_across_outermost_axis) +{ + Shape shape{6, 2}; + auto A = make_shared(element::f32, shape); + auto axes = make_shared(element::i64, Shape{1}, vector{0}); + double alpha = 0.0002; + double beta = 0.5; + double bias = 2.0; + size_t size = 3; + auto lrn = make_shared(A, axes, alpha, beta, bias, size); + auto f = make_shared(lrn, ParameterVector{A}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + vector args{0.64915806f, + 0.21213771f, + -1.48256505f, + -1.41040838f, + 0.58189541f, + 0.11432108f, + -0.22993855f, + -0.13325502f, + -0.03083259f, + -0.48450908f, + 0.50342429f, + -0.99551708f}; + auto a = backend->create_tensor(element::f32, shape); + copy_data(a, args); + + auto result = backend->create_tensor(element::f32, shape); + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a}); + + vector expected{0.45900404f, + 0.14999892f, + -1.04828012f, + -0.99727529f, + 0.41144446f, + 0.08083449f, + -0.16259004f, + -0.09422511f, + -0.02180192f, + -0.34259823f, + 0.35597473f, + -0.70393407f}; + EXPECT_TRUE(test::all_close_f(expected, read_vector(result), 23)); +} diff --git a/test/backend/one_hot.in.cpp b/test/backend/one_hot.in.cpp index f04a72a2dc5..2c6e236f54b 100644 --- a/test/backend/one_hot.in.cpp +++ b/test/backend/one_hot.in.cpp @@ -94,27 +94,6 @@ NGRAPH_TEST(${BACKEND_NAME}, one_hot_scalar_0_in_3) EXPECT_EQ((vector{1, 0, 0}), read_vector(result)); } -NGRAPH_TEST(${BACKEND_NAME}, one_hot_scalar_oob_in_3) -{ - Shape shape_a{}; - auto A = make_shared(element::i32, shape_a); - Shape shape_r{3}; - auto r = make_shared(A, Shape{3}, 0); - auto f = make_shared(r, ParameterVector{A}); - - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - // Create some tensors for input/output - auto a = backend->create_tensor(element::i32, shape_a); - copy_data(a, vector{3}); - vector r_data(4); - auto result = backend->create_tensor(element::i32, shape_r, r_data.data()); - - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a}); - EXPECT_EQ(r_data[3], 0); -} - NGRAPH_TEST(${BACKEND_NAME}, one_hot_vector_0) { Shape shape_a{8}; diff --git a/test/backend/reverse_sequence.in.cpp b/test/backend/reverse_sequence.in.cpp index ab82496cbaa..8df67be1b15 100644 --- a/test/backend/reverse_sequence.in.cpp +++ b/test/backend/reverse_sequence.in.cpp @@ -154,3 +154,44 @@ NGRAPH_TEST(${BACKEND_NAME}, reverse_sequence_n4d2c3h2w2) handle->call_with_validate({result}, {a, b}); EXPECT_EQ(read_vector(result), expected); } + +NGRAPH_TEST(${BACKEND_NAME}, reverse_sequence_negative_axes) +{ + Shape shape{2, 3, 4, 2}; + Shape seq_len_shape{4}; + auto A = make_shared(element::i32, shape); + auto B = make_shared(element::i32, seq_len_shape); + + int64_t batch_axis = -2; + int64_t sequence_axis = -3; + auto rs = std::make_shared(A, B, batch_axis, sequence_axis); + + auto f = make_shared(rs, ParameterVector{A, B}); + + auto backend = runtime::Backend::create("${BACKEND_NAME}"); + + // Create some tensors for input/output + shared_ptr a = backend->create_tensor(element::i32, shape); + shared_ptr b = backend->create_tensor(element::i32, seq_len_shape); + + shared_ptr result = backend->create_tensor(element::i32, shape); + + std::vector input{ + 0, 0, 3, 0, 6, 0, 9, 0, 1, 0, 4, 0, 7, 0, 10, 0, 2, 0, 5, 0, 8, 0, 11, 0, + 12, 0, 15, 0, 18, 0, 21, 0, 13, 0, 16, 0, 19, 0, 22, 0, 14, 0, 17, 0, 20, 0, 23, 0, + }; + + std::vector seq_lenghts{1, 2, 1, 2}; + copy_data(b, seq_lenghts); + + std::vector expected{ + 0, 0, 4, 0, 6, 0, 10, 0, 1, 0, 3, 0, 7, 0, 9, 0, 2, 0, 5, 0, 8, 0, 11, 0, + + 12, 0, 16, 0, 18, 0, 22, 0, 13, 0, 15, 0, 19, 0, 21, 0, 14, 0, 17, 0, 20, 0, 23, 0}; + + copy_data(a, input); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, b}); + EXPECT_EQ(read_vector(result), expected); +} diff --git a/test/backend/tensorview_custom_mem.in.cpp b/test/backend/tensorview_custom_mem.in.cpp deleted file mode 100644 index dafa6a23170..00000000000 --- a/test/backend/tensorview_custom_mem.in.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2019 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 "gtest/gtest.h" -#include "ngraph/ngraph.hpp" -#include "util/all_close.hpp" -#include "util/all_close_f.hpp" -#include "util/known_element_types.hpp" -#include "util/ndarray.hpp" -#include "util/test_control.hpp" -#include "util/test_tools.hpp" - -using namespace std; -using namespace ngraph; - -static string s_manifest = "${MANIFEST}"; - -NGRAPH_TEST(${BACKEND_NAME}, tensorview_custom_mem) -{ - auto backend = runtime::Backend::create("${BACKEND_NAME}"); - - Shape shape{2, 2}; - - auto make_external = [&]() { - auto A = make_shared(element::f32, shape); - auto B = make_shared(element::f32, shape); - auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); - - return f; - }; - - auto f = make_external(); - - vector av{2, 4, 8, 16}; - vector bv{1, 2, 4, 8}; - // use custom mem with tensorview, no need to copy data - auto a = backend->create_tensor(element::f32, shape, av.data()); - auto b = backend->create_tensor(element::f32, shape, bv.data()); - - // use custom mem with result tensorview - vector rv{0, 0, 0, 0}; - auto result = backend->create_tensor(element::f32, shape, rv.data()); - - // result should be in memory without needing explict read - auto handle = backend->compile(f); - handle->call_with_validate({result}, {a, b}); - EXPECT_TRUE(test::all_close_f((vector{2, 2, 2, 2}), rv, MIN_FLOAT_TOLERANCE_BITS)); -} diff --git a/test/backend_api.cpp b/test/backend_api.cpp index 58b931f8267..a6d8f097c3f 100644 --- a/test/backend_api.cpp +++ b/test/backend_api.cpp @@ -98,6 +98,6 @@ TEST(backend_api, executable_can_create_tensor) auto cpu = runtime::Backend::create("CPU"); EXPECT_TRUE(interpreter->executable_can_create_tensors()); - EXPECT_FALSE(cpu->executable_can_create_tensors()); + EXPECT_TRUE(cpu->executable_can_create_tensors()); } #endif diff --git a/test/build_graph.cpp b/test/build_graph.cpp index 065a115ed2f..82ca489105f 100644 --- a/test/build_graph.cpp +++ b/test/build_graph.cpp @@ -155,7 +155,8 @@ TEST(build_graph, multi_output_split) { const auto data = make_shared(element::f32, Shape{64, 8, 100, 150}); auto filters = make_shared(element::f32, Shape{128, 2, 10, 20}); - const auto split = make_shared(data, 1, 2); + const auto axis = op::Constant::create(element::i64, Shape{}, {1}); + const auto split = make_shared(data, axis, 2); auto conv = make_shared(split->output(1), filters, Strides{1, 1}, @@ -170,7 +171,8 @@ TEST(build_graph, multi_output_split) TEST(build_graph, multi_output_split_dynamic) { const auto data = make_shared(element::f32, PartialShape::dynamic()); - const auto split = make_shared(data, 1, 2); + const auto axis = op::Constant::create(element::i64, Shape{}, {1}); + const auto split = make_shared(data, axis, 2); auto abs = make_shared(split->output(1)); EXPECT_TRUE(abs->get_output_partial_shape(0).same_scheme(PartialShape::dynamic())); diff --git a/test/constant_folding.cpp b/test/constant_folding.cpp index c8d566b21c8..b75293c921e 100644 --- a/test/constant_folding.cpp +++ b/test/constant_folding.cpp @@ -206,6 +206,30 @@ TEST(constant_folding, constant_broadcast_v1) ASSERT_EQ(values_expected, values_out); } +TEST(constant_folding, constant_broadcast_v1_with_target_shape) +{ + vector values_in{1}; + auto constant_in = make_shared(element::i32, Shape{1, 1, 1, 1}, values_in); + vector shape_in{1, 3, 1, 1}; + auto target_shape = make_shared(element::i64, Shape{4}, shape_in); + auto broadcast_v1 = make_shared(constant_in, target_shape); + auto f = make_shared(broadcast_v1, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + auto values_out = new_const->get_vector(); + + vector values_expected{1, 1, 1}; + ASSERT_EQ(values_expected, values_out); +} + TEST(constant_folding, constant_broadcast_v1_numpy) { vector values_in{0, 1}; @@ -1023,6 +1047,98 @@ TEST(constant_folding, const_all) ASSERT_EQ(values_expected, values_out); } +TEST(constant_folding, const_reduce_logical_and__no_keepdims) +{ + const Shape input_shape{3, 3}; + + const vector values_in{0, 1, 1, 0, 1, 0, 1, 1, 1}; + const auto data = op::Constant::create(element::boolean, input_shape, values_in); + const auto axes = op::Constant::create(element::i64, {1}, {1}); + const auto convert = make_shared(data, axes, false); + auto f = make_shared(convert, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + const auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + + const Shape expected_out_shape{3}; + ASSERT_EQ(new_const->get_shape(), expected_out_shape); + + const auto values_out = new_const->get_vector(); + + const vector values_expected{0, 0, 1}; + + ASSERT_EQ(values_expected, values_out); +} + +TEST(constant_folding, const_reduce_logical_and__keepdims) +{ + const Shape input_shape{3, 3}; + + const vector values_in{0, 1, 1, 0, 1, 0, 1, 1, 1}; + const auto data = op::Constant::create(element::boolean, input_shape, values_in); + const auto axes = op::Constant::create(element::i64, {1}, {1}); + const auto convert = make_shared(data, axes, true); + auto f = make_shared(convert, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + const auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + + // the output shape is expected to have 'ones' at the positions specified in the reduction axes + // in case the keep_dims attribute of ReduceLogicalAnd is set to true + const Shape expected_out_shape{3, 1}; + ASSERT_EQ(new_const->get_shape(), expected_out_shape); + + const auto values_out = new_const->get_vector(); + + const vector values_expected{0, 0, 1}; + + ASSERT_EQ(values_expected, values_out); +} + +TEST(constant_folding, const_reduce_logical_and__keepdims_3d) +{ + const Shape input_shape{2, 2, 2}; + + const vector values_in{1, 1, 0, 0, 1, 0, 0, 1}; + const auto data = op::Constant::create(element::boolean, input_shape, values_in); + const auto axes = op::Constant::create(element::i64, {2}, {0, 2}); + const auto convert = make_shared(data, axes, true); + auto f = make_shared(convert, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + const auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + + const Shape expected_out_shape{1, 2, 1}; + ASSERT_EQ(new_const->get_shape(), expected_out_shape); + + const auto values_out = new_const->get_vector(); + + const vector values_expected{0, 0}; + + ASSERT_EQ(values_expected, values_out); +} + TEST(constant_folding, const_any) { Shape input_shape{3, 3}; @@ -1048,6 +1164,36 @@ TEST(constant_folding, const_any) ASSERT_EQ(values_expected, values_out); } +TEST(constant_folding, const_reduce_logical_or__no_keepdims) +{ + const Shape input_shape{3, 3}; + + const vector values_in{1, 0, 0, 1, 0, 1, 0, 0, 0}; + const auto data = op::Constant::create(element::boolean, input_shape, values_in); + const auto axes = op::Constant::create(element::i64, {1}, {1}); + const auto convert = make_shared(data, axes, false); + auto f = make_shared(convert, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + const auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + + const Shape expected_out_shape{3}; + ASSERT_EQ(new_const->get_shape(), expected_out_shape); + + const auto values_out = new_const->get_vector(); + + const vector values_expected{1, 1, 0}; + + ASSERT_EQ(values_expected, values_out); +} + TEST(constant_folding, const_concat) { auto constant0 = @@ -1375,14 +1521,70 @@ TEST(constant_folding, const_gather) auto constant_indices = op::Constant::create(element::i64, Shape{4}, vector{0, 3, 2, 2}); size_t gather_axis = 1; - auto gather = make_shared(constant_data, constant_indices, gather_axis); + auto gather = make_shared(constant_data, constant_indices, gather_axis); + auto f = make_shared(gather, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + auto values_out = new_const->get_vector(); + + vector values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f}; + + ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS)); +} + +TEST(constant_folding, const_gather_v1) +{ + auto constant_data = op::Constant::create( + element::f32, + Shape{2, 5}, + vector{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}); + auto constant_indices = + op::Constant::create(element::i64, Shape{4}, vector{0, 3, 2, 2}); + auto constant_axis = op::Constant::create(element::i64, Shape{1}, vector{1}); + auto gather = make_shared(constant_data, constant_indices, constant_axis); + auto f = make_shared(gather, ParameterVector{}); + + pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 1); + + auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); + ASSERT_TRUE(new_const); + auto values_out = new_const->get_vector(); + + vector values_expected{1.0f, 4.0f, 3.0f, 3.0f, 6.0f, 9.0f, 8.0f, 8.0f}; + + ASSERT_TRUE(test::all_close_f(values_out, values_expected, MIN_FLOAT_TOLERANCE_BITS)); +} + +TEST(constant_folding, const_gather_v1_scalar) +{ + auto constant_data = op::Constant::create( + element::f32, + Shape{2, 5}, + vector{1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}); + auto constant_indices = + op::Constant::create(element::i64, Shape{4}, vector{0, 3, 2, 2}); + auto constant_axis = op::Constant::create(element::i64, Shape{}, vector{1}); + auto gather = make_shared(constant_data, constant_indices, constant_axis); auto f = make_shared(gather, ParameterVector{}); pass::Manager pass_manager; pass_manager.register_pass(); pass_manager.run_passes(f); - ASSERT_EQ(count_ops_of_type(f), 0); + ASSERT_EQ(count_ops_of_type(f), 0); ASSERT_EQ(count_ops_of_type(f), 1); auto new_const = as_type_ptr(f->get_results().at(0)->get_argument(0)); @@ -1468,7 +1670,7 @@ TEST(constant_folding, constant_dyn_reshape) auto constant_in = make_shared(element::f32, shape_in, values_in); auto constant_shape = make_shared(element::i64, shape_shape, values_shape); - auto dyn_reshape = make_shared(constant_in, constant_shape); + auto dyn_reshape = make_shared(constant_in, constant_shape, false); auto f = make_shared(dyn_reshape, ParameterVector{}); pass::Manager pass_manager; @@ -1502,7 +1704,7 @@ TEST(constant_folding, constant_dyn_reshape_shape_not_originally_constant) auto constant_shape_a = make_shared(element::i64, shape_shape, values_shape_a); auto constant_shape_b = make_shared(element::i64, shape_shape, values_shape_b); auto dyn_reshape = - make_shared(constant_in, constant_shape_a + constant_shape_b); + make_shared(constant_in, constant_shape_a + constant_shape_b, false); auto f = make_shared(dyn_reshape, ParameterVector{}); ASSERT_TRUE(dyn_reshape->output(0).get_partial_shape().is_dynamic()); diff --git a/test/control_dependencies.cpp b/test/control_dependencies.cpp index 23397cb4423..cbb1db2f2b4 100644 --- a/test/control_dependencies.cpp +++ b/test/control_dependencies.cpp @@ -47,6 +47,8 @@ using namespace std; class ControlDependencyOp : public ngraph::op::Op { public: + static constexpr NodeTypeInfo type_info{"ControlDependencyOp", 0}; + const NodeTypeInfo& get_type_info() const override { return type_info; } virtual std::shared_ptr copy_with_new_args(const NodeVector& new_args) const override { auto clone = make_shared(new_args, std::set>{}); @@ -77,6 +79,7 @@ class ControlDependencyOp : public ngraph::op::Op } } }; +constexpr NodeTypeInfo ControlDependencyOp::type_info; TEST(control_dependencies, cdep_ops) { diff --git a/test/convert_u1_to_string.cpp b/test/convert_u1_to_string.cpp new file mode 100644 index 00000000000..d671bf85bdc --- /dev/null +++ b/test/convert_u1_to_string.cpp @@ -0,0 +1,35 @@ +//***************************************************************************** +// Copyright 2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/all_close_f.hpp" +#include "util/test_tools.hpp" + +using namespace ngraph; +using namespace std; + +TEST(convert_u1_to_string, convert_u1_to_string) +{ + vector values{171, 16}; + auto constant = make_shared(element::u1, Shape{12}, &values[0]); + + vector ref{"1", "0", "1", "0", "1", "0", "1", "1", "0", "0", "0", "1"}; + for (size_t i = 0; i < 12; ++i) + { + ASSERT_EQ(constant->convert_value_to_string(i), ref[i]); + } +} \ No newline at end of file diff --git a/test/core_fusion.cpp b/test/core_fusion.cpp index 40afa9eaa5a..091550130b7 100644 --- a/test/core_fusion.cpp +++ b/test/core_fusion.cpp @@ -26,6 +26,7 @@ #include "ngraph/graph_util.hpp" #include "ngraph/log.hpp" #include "ngraph/ngraph.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/op/fused/group_conv.hpp" #include "ngraph/op/relu.hpp" #include "ngraph/op/reshape.hpp" @@ -648,6 +649,21 @@ TEST(core_fusion, DISABLED_conv_bias_bprop) } } +#ifndef NGRAPH_JSON_DISABLE +TEST(batch_fusion, fuse_batch_mat_mul_transpose) +{ + pass::Manager pass_manager; + pass_manager.register_pass(); + const string json_path = file_util::path_join(SERIALIZED_ZOO, "mxnet/batch_dot_3.json"); + const string json_string = file_util::read_file_to_string(json_path); + stringstream ss(json_string); + shared_ptr func = ngraph::deserialize(ss); + pass_manager.run_passes(func); + size_t ccg = count_ops_of_type(func); + ASSERT_EQ(ccg, 1); +} +#endif + TEST(batch_fusion, group_convolution_fusion) { Shape shape_a{1, 32, 2, 2}; @@ -853,3 +869,42 @@ TEST(core_fusion, softmax_crossentropy) test_softmax_crossentropy(Shape{41, 37}, Shape{41, 37}, true, -1); test_softmax_crossentropy(Shape{41, 37}, Shape{41, 1}, false, 5); } + +void test_crossentropy(Shape input_shape, Shape label_shape, bool soft_label, int64_t ignore_index) +{ + auto input = std::make_shared(element::f64, input_shape); + auto labels = std::make_shared(element::i64, label_shape); + auto sm_ce = std::make_shared(input, labels, soft_label, ignore_index); + auto cpu_f = make_shared(sm_ce, ParameterVector{input, labels}); + + test::Uniform rng(-1.0, 1.0); + vector> args; + for (shared_ptr param : cpu_f->get_parameters()) + { + vector tensor_val(shape_size(param->get_shape())); + rng.initialize(tensor_val); + args.push_back(tensor_val); + } + + auto cpu_results = execute(cpu_f, args, "CPU"); + // if softlabels = flase, we will have one one hot encoding for labels + if (!soft_label) + { + size_t onehot = count_ops_of_type(cpu_f); + ASSERT_EQ(onehot, 1); + } + if (ignore_index >= 0 && !soft_label) + // check for the mask + { + size_t not_equal = count_ops_of_type(cpu_f); + ASSERT_EQ(not_equal, 1); + } +} + +TEST(core_fusion, crossentropy) +{ + test_crossentropy(Shape{41, 37}, Shape{41, 37}, true, -1); + test_crossentropy(Shape{41, 37}, Shape{41, 1}, false, 5); + test_crossentropy(Shape{10, 2, 4, 10}, Shape{10, 2, 4, 1}, false, 5); + test_crossentropy(Shape{4, 3, 2, 4}, Shape{4, 3, 2, 4}, true, -1); +} diff --git a/test/cpu_fusion.cpp b/test/cpu_fusion.cpp index 44c93d24954..970caf7bbe5 100644 --- a/test/cpu_fusion.cpp +++ b/test/cpu_fusion.cpp @@ -32,6 +32,7 @@ #include "ngraph/op/dequantize.hpp" #include "ngraph/op/experimental/generate_mask.hpp" #include "ngraph/op/experimental/quantized_conv_bias.hpp" +#include "ngraph/op/fused/batch_mat_mul_transpose.hpp" #include "ngraph/op/fused/conv_fused.hpp" #include "ngraph/op/fused/gelu.hpp" #include "ngraph/op/fused/group_conv.hpp" @@ -59,7 +60,6 @@ #include "ngraph/pattern/op/skip.hpp" #include "ngraph/runtime/cpu/cpu_layout_descriptor.hpp" #include "ngraph/runtime/cpu/cpu_tensor_view.hpp" -#include "ngraph/runtime/cpu/op/batch_mat_mul_transpose.hpp" #include "ngraph/runtime/cpu/op/batch_norm_relu.hpp" #include "ngraph/runtime/cpu/op/bounded_relu.hpp" #include "ngraph/runtime/cpu/op/conv_add.hpp" @@ -1092,7 +1092,7 @@ static double gelu_backprop_factor(double x) TEST(cpu_fusion, fuse_gelu_backprop_f32) { - Shape shape_a{2, 1, 60, 60}; + Shape shape_a{2, 1, 600, 600}; auto make_function = [shape_a]() { auto A = std::make_shared(element::f32, shape_a); @@ -3685,53 +3685,14 @@ TEST(cpu_fusion, sigmoid_multiply_fusion) ASSERT_EQ(ccg, 18); } -TEST(cpu_fusion, fuse_batch_mat_mul_transpose) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - const string json_path = file_util::path_join(SERIALIZED_ZOO, "mxnet/batch_dot_3.json"); - const string json_string = file_util::read_file_to_string(json_path); - stringstream ss(json_string); - shared_ptr func = ngraph::deserialize(ss); - pass_manager.run_passes(func); - size_t ccg = count_ops_of_type(func); - ASSERT_EQ(ccg, 1); -} - -TEST(cpu_fusion, fuse_batch_mat_mul_transpose_forward) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - - const std::string file_name("mxnet/batch_dot_3.json"); - auto cpu_f = make_function_from_file(file_name); - auto int_f = make_function_from_file(file_name); - pass_manager.run_passes(cpu_f); - test::Uniform rng(0.0f, 1.0f); - vector> args; - - for (shared_ptr param : int_f->get_parameters()) - { - vector tensor_val(shape_size(param->get_shape())); - rng.initialize(tensor_val); - args.push_back(tensor_val); - } - auto int_results = execute(int_f, args, "INTERPRETER"); - auto cpu_results = execute(cpu_f, args, "CPU"); - for (size_t i = 0; i < int_results.size(); i++) - { - EXPECT_TRUE(test::all_close(cpu_results.at(i), int_results.at(i), 1.0e-4f, 1.0e-4f)); - } -} - -TEST(cpu_fusion, fuse_batch_dot_backward) +TEST(batch_fusion, fuse_batch_dot_backward) { const std::string file_name("mxnet/batch_dot_3.json"); auto cpu_f = make_function_from_file(file_name); auto int_f = make_function_from_file(file_name); pass::Manager pass_manager; - pass_manager.register_pass(); + pass_manager.register_pass(); pass_manager.run_passes(cpu_f); auto int_df = autodiff::backprop_function(int_f); @@ -4044,28 +4005,4 @@ TEST(cpu_fusion, validate_fuse_gru_inputs) EXPECT_TRUE(test::all_close(cpu_results.at(i), int_results.at(i), 1.0e-4f, 1.0e-4f)); } } - -#if defined(AUTODIFF_BACKEND_CPU) && !defined(NGRAPH_JSON_DISABLE) -NGRAPH_TEST(cpu_fusion, backwards_batchmatmultranspose_tensor2_tensor2) -{ - auto backend = runtime::Backend::create("CPU"); - - const std::string file_name("mxnet/batch_dot_3.json"); - auto f = make_function_from_file(file_name); - - test::Uniform rng(-1.0f, 1.0f); - std::vector> args; - for (shared_ptr param : f->get_parameters()) - { - args.push_back(rng.initialize(backend->create_tensor(param->get_shape()))); - } - - auto g = make_function_from_file(file_name); - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.run_passes(g); - EXPECT_TRUE(autodiff_numeric_compare(backend.get(), f, g, args, .01f, .01f)); -} -#endif - #endif diff --git a/test/cpu_test.cpp b/test/cpu_test.cpp index a62dc5e7c4d..10f05ab39ff 100644 --- a/test/cpu_test.cpp +++ b/test/cpu_test.cpp @@ -2222,3 +2222,108 @@ TEST(cpu_test, convolution_simple_bf16) read_vector(result)); } #endif + +// This tests a backend's implementation of the three parameter version of create_tensor +// Testing using this tensor as a Function input +TEST(cpu_test, create_tensor_2_input) +{ + Shape shape{2, 2}; + auto A = make_shared(element::f32, shape); + auto B = make_shared(element::f32, shape); + auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); + + auto backend = runtime::Backend::create("CPU"); + + // Create some tensors for input/output + vector av = {1, 2, 3, 4}; + vector bv = {5, 6, 7, 8}; + shared_ptr a = backend->create_tensor(element::f32, shape, av.data()); + shared_ptr b = backend->create_tensor(element::f32, shape, bv.data()); + shared_ptr result = backend->create_tensor(element::f32, shape); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, b}); + vector expected = {6, 8, 10, 12}; + EXPECT_TRUE(test::all_close_f(read_vector(result), expected, MIN_FLOAT_TOLERANCE_BITS)); +} + +// This tests a backend's implementation of the three parameter version of create_tensor +// Testing using this tensor as a Function output +TEST(cpu_test, create_tensor_2_output) +{ + Shape shape{2, 2}; + auto A = make_shared(element::f32, shape); + auto B = make_shared(element::f32, shape); + auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); + + auto backend = runtime::Backend::create("CPU"); + + // Create some tensors for input/output + vector av = {1, 2, 3, 4}; + vector bv = {5, 6, 7, 8}; + shared_ptr a = backend->create_tensor(element::f32, shape); + shared_ptr b = backend->create_tensor(element::f32, shape); + copy_data(a, av); + copy_data(b, bv); + + vector actual(4); + shared_ptr result = backend->create_tensor(element::f32, shape, actual.data()); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, b}); + vector expected = {6, 8, 10, 12}; + EXPECT_TRUE(test::all_close_f(actual, expected, MIN_FLOAT_TOLERANCE_BITS)); +} + +TEST(cpu_test, tensorview_custom_mem) +{ + auto backend = runtime::Backend::create("CPU"); + + Shape shape{2, 2}; + + auto make_external = [&]() { + auto A = make_shared(element::f32, shape); + auto B = make_shared(element::f32, shape); + auto f = make_shared(make_shared(A, B), ParameterVector{A, B}); + + return f; + }; + + auto f = make_external(); + + vector av{2, 4, 8, 16}; + vector bv{1, 2, 4, 8}; + // use custom mem with tensorview, no need to copy data + auto a = backend->create_tensor(element::f32, shape, av.data()); + auto b = backend->create_tensor(element::f32, shape, bv.data()); + + // use custom mem with result tensorview + vector rv{0, 0, 0, 0}; + auto result = backend->create_tensor(element::f32, shape, rv.data()); + + // result should be in memory without needing explict read + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a, b}); + EXPECT_TRUE(test::all_close_f((vector{2, 2, 2, 2}), rv, MIN_FLOAT_TOLERANCE_BITS)); +} + +TEST(cpu_test, one_hot_scalar_oob_in_3) +{ + Shape shape_a{}; + auto A = make_shared(element::i32, shape_a); + Shape shape_r{3}; + auto r = make_shared(A, Shape{3}, 0); + auto f = make_shared(r, ParameterVector{A}); + + auto backend = runtime::Backend::create("CPU"); + + // Create some tensors for input/output + auto a = backend->create_tensor(element::i32, shape_a); + copy_data(a, vector{3}); + vector r_data(4); + auto result = backend->create_tensor(element::i32, shape_r, r_data.data()); + + auto handle = backend->compile(f); + handle->call_with_validate({result}, {a}); + EXPECT_EQ(r_data[3], 0); +} diff --git a/test/float16.cpp b/test/float16.cpp index c9deaab1eca..c4a2f7e4d90 100644 --- a/test/float16.cpp +++ b/test/float16.cpp @@ -90,8 +90,20 @@ TEST(float16, assigns) TEST(float16, values) { - std::vector f32vec{2.73786e-05, 3.87722e-05, -0.0223043}; - std::vector intvals = {459, 650, 42422}; + std::vector f32vec{2.73786e-05, + 3.87722e-05, + -0.0223043, + 5.10779e-05, + -5.10779e-05, + -2.553895e-05, + -0.0001021558, + 5.960464477539063e-08, + 8.940696716308594e-08, + 65536.0, + 65519.0, + 65520.0}; + std::vector intvals = { + 459, 650, 42422, 857, 0x8359, 0x81ac, 0x86b2, 0x01, 0x02, 0x7c00, 0x7bff, 0x7c00}; for (size_t i = 0; i < f32vec.size(); ++i) { float16 fp16val = f32vec.at(i); diff --git a/test/mlir/affine_conversion/core_ops.mlir b/test/mlir/affine_conversion/core_ops.mlir index 6b18b818e39..a60e1c9ad94 100644 --- a/test/mlir/affine_conversion/core_ops.mlir +++ b/test/mlir/affine_conversion/core_ops.mlir @@ -36,3 +36,22 @@ func @simple_dot(%arg0: !ng.tensor<16x8xf32>, %arg1: !ng.tensor<8x32xf32>) -> !n %0 = "ng.dot"(%arg0, %arg1) : (!ng.tensor<16x8xf32>, !ng.tensor<8x32xf32>) -> !ng.tensor<16x32xf32> "ng.return"(%0) : (!ng.tensor<16x32xf32>) -> () } + +// ----- + +// std.view + +// CHECK-DAG: #[[MAP0:[a-zA-Z0-9]+]] = (d0, d1) -> (d0 * 2 + d1) +// CHECK: %[[T1:[0-9]+]] = alloc() : memref<24xi8> +// CHECK-NEXT: %[[T2:[0-9]+]] = std.view %[[T1]][][] : memref<24xi8> to memref<3x2xf32, #[[MAP0]]> +// CHECK: affine.store %{{[0-9]+}}, %[[T2]][%{{.*}}, %{{.*}}] : memref<3x2xf32, #[[MAP0]]> +// +// CHECK: %[[T4:[0-9]+]] = std.view %[[T1]][][] : memref<24xi8> to memref<3x2xf32, #[[MAP0]]> +// CHECK: affine.store %{{[0-9]+}}, %[[T4]][%{{.*}}, %{{.*}}] : memref<3x2xf32, #[[MAP0]]> + +func @add(%arg0: !ng.tensor<3x2xf32>, %arg1: !ng.tensor<3x2xf32>) -> !ng.tensor<3x2xf32> { + %0 = "ng.add"(%arg0, %arg1) {ng.buffer_id = 0 : i64} : (!ng.tensor<3x2xf32>, !ng.tensor<3x2xf32>) -> !ng.tensor<3x2xf32> + %2 = "ng.add"(%0, %0) {ng.buffer_id = 0 : i64}: (!ng.tensor<3x2xf32>, !ng.tensor<3x2xf32>) -> !ng.tensor<3x2xf32> + %3 = "ng.add"(%2, %2) : (!ng.tensor<3x2xf32>, !ng.tensor<3x2xf32>) -> !ng.tensor<3x2xf32> + "ng.return"(%3) : (!ng.tensor<3x2xf32>) -> () +} diff --git a/test/mlir/ngraph_dialect/fused_ops.mlir b/test/mlir/ngraph_dialect/fused_ops.mlir new file mode 100644 index 00000000000..611dcf2636e --- /dev/null +++ b/test/mlir/ngraph_dialect/fused_ops.mlir @@ -0,0 +1,322 @@ +// RUN: ngraph-opt %s | FileCheck %s +// Verify the printed output can be parsed. +// RUN: ngraph-opt %s | ngraph-opt | FileCheck %s + +// These tests verify the parser, builder and printer of element-wise binary ops. + +// CHECK-LABEL: func @squeeze +func @squeeze(%arg0: !ng.tensor<2x1x2x1xf32>, %arg1: !ng.tensor<2xi64>) -> !ng.tensor<2x2xf32> { + // CHECK: %{{[0-9]+}} = "ng.squeeze"(%{{.*}}, %{{.*}}) : (!ng.tensor<2x1x2x1xf32>, !ng.tensor<2xi64>) -> !ng.tensor<2x2xf32> + %0 = "ng.squeeze"(%arg0, %arg1) : (!ng.tensor<2x1x2x1xf32>, !ng.tensor<2xi64>) -> !ng.tensor<2x2xf32> + "ng.return"(%0) : (!ng.tensor<2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @unsqueeze +func @unsqueeze(%arg0: !ng.tensor<2x2xf32>, %arg1: !ng.tensor<2xi64>) -> !ng.tensor<2x1x2x1xf32> { + // CHECK: %{{[0-9]+}} = "ng.unsqueeze"(%{{.*}}, %{{.*}}) : (!ng.tensor<2x2xf32>, !ng.tensor<2xi64>) -> !ng.tensor<2x1x2x1xf32> + %0 = "ng.unsqueeze"(%arg0, %arg1) : (!ng.tensor<2x2xf32>, !ng.tensor<2xi64>) -> !ng.tensor<2x1x2x1xf32> + "ng.return"(%0) : (!ng.tensor<2x1x2x1xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @sqrddiff +func @sqrddiff(%arg0: !ng.tensor<2x2xf32>, %arg1: !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> { + // CHECK: %{{[0-9]+}} = "ng.sqrdDiff"(%{{.*}}, %{{.*}}) : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> + %0 = "ng.sqrdDiff"(%arg0, %arg1) : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> + "ng.return"(%0) : (!ng.tensor<2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @split +func @split(%arg0: !ng.tensor<2x2x16xf32>) -> !ng.tensor<2x2x4xf32> { + // CHECK: %{{[0-9]+}}:4 = "ng.split"(%{{.*}}) {axis = 2 : i64, numSplits = [4, 4, 4, 4]} : (!ng.tensor<2x2x16xf32>) -> (!ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>) + %0:4= "ng.split"(%arg0) {axis = 2, numSplits = [4, 4, 4, 4]} + : (!ng.tensor<2x2x16xf32>) -> (!ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>, !ng.tensor<2x2x4xf32>) + "ng.return"(%0#0) : (!ng.tensor<2x2x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @spaceToDepth +func @spaceToDepth(%arg0: !ng.tensor<1x4x16x16xf32>) -> !ng.tensor<1x64x4x4xf32> { + // CHECK: %{{[0-9]+}} = "ng.spaceToDepth"(%{{.*}}) {blockSize = 4 : i64, mode = 0 : i32} : (!ng.tensor<1x4x16x16xf32>) -> !ng.tensor<1x64x4x4xf32> + %0 = "ng.spaceToDepth"(%arg0) {blockSize = 4, mode = 0 : i32} : (!ng.tensor<1x4x16x16xf32>) -> (!ng.tensor<1x64x4x4xf32>) + "ng.return"(%0) : (!ng.tensor<1x64x4x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @shuffleChannels +func @shuffleChannels(%arg0: !ng.tensor<1x16x16x16xf32>) -> !ng.tensor<1x16x16x16xf32> { + // CHECK: %{{[0-9]+}} = "ng.shuffleChannels"(%{{.*}}) {axis = 1 : i64, groups = 4 : i64} : (!ng.tensor<1x16x16x16xf32>) -> !ng.tensor<1x16x16x16xf32> + %0 = "ng.shuffleChannels"(%arg0) {axis = 1 : i64, groups = 4 : i64} : (!ng.tensor<1x16x16x16xf32>) -> !ng.tensor<1x16x16x16xf32> + "ng.return"(%0) : (!ng.tensor<1x16x16x16xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @scaleShift +func @scaleShift(%arg0: !ng.tensor<2x2xf32>, %arg1: !ng.tensor<2x2xf32>, %arg2: !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> { + // CHECK: %{{[0-9]+}} = "ng.scaleShift"(%{{.*}}, %{{.*}}, %{{.*}}) : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> + + %0 = "ng.scaleShift"(%arg0, %arg1, %arg2) : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> + + "ng.return"(%0) : (!ng.tensor<2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @prelu +func @prelu(%arg0: !ng.tensor<2x2xf32>, %arg1: !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> { + // CHECK: %{{[0-9]+}} = "ng.prelu"(%{{.*}}, %{{.*}}) : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> !ng.tensor<2x2xf32> + %0 = "ng.prelu"(%arg0, %arg1) {} : (!ng.tensor<2x2xf32>, !ng.tensor<2x2xf32>) -> (!ng.tensor<2x2xf32>) + "ng.return"(%0) : (!ng.tensor<2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @normalizeL2 +func @normalizeL2(%arg0: !ng.tensor<1x2x3x4xf32>, %arg1: !ng.tensor<3x!ng.i64>) -> !ng.tensor<1x2x3x4xf32> { + // CHECK: %{{[0-9]+}} = "ng.normalizeL2"(%{{.*}}, %{{.*}}) {eps = {{0.[0-9]+}} : f32, epsMode = 0 : i32} : (!ng.tensor<1x2x3x4xf32>, !ng.tensor<3x!ng.i64>) -> !ng.tensor<1x2x3x4xf32> + %0 = "ng.normalizeL2"(%arg0, %arg1) {eps = 0.01 : f32, epsMode = 0 : i32} : (!ng.tensor<1x2x3x4xf32> , !ng.tensor<3x!ng.i64>) -> !ng.tensor<1x2x3x4xf32> + "ng.return"(%0) : (!ng.tensor<1x2x3x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @mvn +func @mvn(%arg0: !ng.tensor<1x2x5xf32>) -> !ng.tensor<1x2x5xf32> { + // CHECK: %{{[0-9]+}} = "ng.mvn"(%{{.*}}) {normalizeVariance = false} : (!ng.tensor<1x2x5xf32>) -> !ng.tensor<1x2x5xf32> + %0 = "ng.mvn"(%arg0) {normalizeVariance = false} : (!ng.tensor<1x2x5xf32>) -> !ng.tensor<1x2x5xf32> + "ng.return"(%0) : (!ng.tensor<1x2x5xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @matmul +func @matmul(%arg0: !ng.tensor<2x5xf32>, %arg1: !ng.tensor<2x5xf32>) -> !ng.tensor<2x5xf32> { + // CHECK: %{{[0-9]+}} = "ng.matmul"(%{{.*}}, %{{.*}}) : (!ng.tensor<2x5xf32>, !ng.tensor<2x5xf32>) -> !ng.tensor<2x5xf32> + %0 = "ng.matmul"(%arg0, %arg1) : (!ng.tensor<2x5xf32>, !ng.tensor<2x5xf32>) -> !ng.tensor<2x5xf32> + + "ng.return"(%0) : (!ng.tensor<2x5xf32>) -> () +} + +// ------ + +// CHECK-LABEL: func @layernorm +func @layernorm(%arg0: !ng.tensor<2x4xf32>, %arg1: !ng.tensor<4xf32>, %arg2: !ng.tensor<4xf32>) -> !ng.tensor<2x4xf32> { + // CHECK %{{[0-9]+}}:3 = "ng.layernorm"(%{{.*}}, %{{.*}}, %{{.*}}) : (!ng.tensor<2x4xf32>, !ng.tensor<4xf32>, !ng.tensor<4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + %0:3 = "ng.layernorm"(%arg0, %arg1, %arg2) + : (!ng.tensor<2x4xf32>, !ng.tensor<4xf32>, !ng.tensor<4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + // CHECK %{{[0-9]+}}:3 = "ng.layernorm"(%{{.*}}) : (!ng.tensor<2x4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + %1:3 = "ng.layernorm"(%arg0) + : (!ng.tensor<2x4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + "ng.return"(%0#0) : (!ng.tensor<2x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @layernormBackprop +func @layernormBackprop(%arg0: !ng.tensor<2x4xf32>, %arg1: !ng.tensor<2x4xf32>, %arg2: !ng.tensor<2xf32>, %arg3: !ng.tensor<2xf32>, %arg4: !ng.tensor<4xf32>) -> !ng.tensor<2x4xf32> { + // CHECK: %{{[0-9]+}}:3 = "ng.layernormBackprop"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!ng.tensor<2x4xf32>, !ng.tensor<2x4xf32>, !ng.tensor<4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + %0:3 = "ng.layernormBackprop"(%arg0, %arg1, %arg4, %arg2, %arg3) + : (!ng.tensor<2x4xf32>, !ng.tensor<2x4xf32>, !ng.tensor<4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + + // CHECK: %{{[0-9]+}}:3 = "ng.layernormBackprop"(%{{.*}}, %{{.*}}, %{{.*}}) : (!ng.tensor<2x4xf32>, !ng.tensor<2x4xf32>, !ng.tensor<4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + %1:3 = "ng.layernormBackprop"(%arg0, %arg1, %arg4) + : (!ng.tensor<2x4xf32>, !ng.tensor<2x4xf32>, !ng.tensor<4xf32>) -> (!ng.tensor<2x4xf32>, !ng.tensor<2xf32>, !ng.tensor<2xf32>) + "ng.return"(%0#0) : (!ng.tensor<2x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @hardSigmoid +func @hardSigmoid(%arg0: !ng.tensor<2x7xf32>) -> !ng.tensor<2x7xf32> +{ + %0 = "ng.hardSigmoid"(%arg0) {alpha = 0.125 : f32, beta = 0.642 : f32} : (!ng.tensor<2x7xf32>) -> !ng.tensor<2x7xf32> + "ng.return"(%0) : (!ng.tensor<2x7xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @gemm +func @gemm(%arg0: !ng.tensor<3x6xf32>, %arg1: !ng.tensor<6x4xf32>, %arg2: !ng.tensor<3x4xf32>) -> !ng.tensor<3x4xf32> { + // CHECK: %{{[0-9]+}} = "ng.gemm"(%{{.*}}, %{{.*}}, %{{.*}}) : (!ng.tensor<3x6xf32>, !ng.tensor<6x4xf32>, !ng.tensor<3x4xf32>) -> !ng.tensor<3x4xf32> + %0 = "ng.gemm"(%arg0, %arg1, %arg2) : (!ng.tensor<3x6xf32>, !ng.tensor<6x4xf32>, !ng.tensor<3x4xf32>) -> !ng.tensor<3x4xf32> + + "ng.return"(%0) : (!ng.tensor<3x4xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @groupConv +func @groupConv(%arg0: !ng.tensor<1x4x2x2xf32>, %arg1: !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.groupConv"(%{{.*}}, %{{.*}}) {groups = 2 : i64, padAbove = [0, 0], padBelow = [0, 0], strides = [1, 1]} : (!ng.tensor<1x4x2x2xf32>, !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> + %0 = "ng.groupConv"(%arg0, %arg1) {groups=2 : i64, padAbove=[0,0], padBelow=[0,0], strides=[1, 1]} + : (!ng.tensor<1x4x2x2xf32>, !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> + "ng.return"(%0) : (!ng.tensor<1x2x2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @groupConvTranspose +func @groupConvTranspose(%arg0: !ng.tensor<1x4x2x2xf32>, %arg1: !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.groupConvTranspose"(%{{.*}}, %{{.*}}) {groups = 2 : i64, outputPad = [1, 1], outputShape = [], padAbove = [0, 0], padBelow = [0, 0], strides = [1, 1]} : (!ng.tensor<1x4x2x2xf32>, !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> + %0 = "ng.groupConvTranspose"(%arg0, %arg1) {groups=2 : i64, padAbove=[0,0], padBelow=[0,0], outputPad=[1,1], outputShape=[], strides=[1, 1]} + : (!ng.tensor<1x4x2x2xf32>, !ng.tensor<2x2x1x1xf32>) -> !ng.tensor<1x2x2x2xf32> + "ng.return"(%0) : (!ng.tensor<1x2x2x2xf32>) -> () +} + +// ----- + +// CHECK-LABEL: func @grn +func @grn(%arg0: !ng.tensor<1x2x3x4xf32>) -> !ng.tensor<1x2x3x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.grn"(%{{.*}}) {bias = {{.*}} : f32} : (!ng.tensor<1x2x3x4xf32>) -> !ng.tensor<1x2x3x4xf32> + %0 = "ng.grn"(%arg0) {bias = 0.1 : f32 } : (!ng.tensor<1x2x3x4xf32>) -> !ng.tensor<1x2x3x4xf32> + "ng.return"(%0) : (!ng.tensor<1x2x3x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @clamp +func @clamp(%arg0: !ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.clamp"(%{{.*}}) {max = {{.*}} : f64, min = {{.*}} : f64} : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + %0 = "ng.clamp"(%arg0) {max = 20.0 : f64, min = 10.0 : f64} : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + "ng.return"(%0) : (!ng.tensor<4x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @gelu +func @gelu(%arg0: !ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.gelu"({{.*}}) : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + %0 = "ng.gelu"(%arg0) : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + "ng.return"(%0) : (!ng.tensor<4x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @geluBackpropFactor +func @geluBackpropFactor(%arg0: !ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.geluBackpropFactor"({{.*}}) : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + %0 = "ng.geluBackpropFactor"(%arg0) : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + "ng.return"(%0) : (!ng.tensor<4x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @elu +func @elu(%arg0: !ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.elu"({{.*}}) {alpha = {{.*}} : f64} : (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + %0 = "ng.elu"(%arg0) {alpha = 0.001 : f64}: (!ng.tensor<4x4xf32>) -> !ng.tensor<4x4xf32> + "ng.return"(%0) : (!ng.tensor<4x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @fakeQuant +func @fakeQuant(%arg0: !ng.tensor<1x2x3x4xf32>, %arg1: !ng.tensor<1xf32>, + %arg2: !ng.tensor<1xf32>, %arg3: !ng.tensor<1xf32>, %arg4: !ng.tensor<1xf32>) -> !ng.tensor<1x2x3x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.fakeQuant"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {levels = 4 : i64} : (!ng.tensor<1x2x3x4xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>) -> !ng.tensor<1x2x3x4xf32> + %0 = "ng.fakeQuant"(%arg0, %arg1, %arg2, %arg3, %arg4) {levels = 4 : i64} + : (!ng.tensor<1x2x3x4xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>, !ng.tensor<1xf32>) -> !ng.tensor<1x2x3x4xf32> + "ng.return"(%0) : (!ng.tensor<1x2x3x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @depthToSpace +func @depthToSpace(%arg0: !ng.tensor<1x8x2x2xf32>) -> !ng.tensor<1x2x4x4xf32> +{ + //CHECK: %{{[0-9]+}} = "ng.depthToSpace"(%{{.*}}) {blockSize = 2 : i64, mode = 0 : i32} : (!ng.tensor<1x8x2x2xf32>) -> !ng.tensor<1x2x4x4xf32> + %0 = "ng.depthToSpace"(%arg0) {blockSize = 2 : i64, mode = 0 : i32} : (!ng.tensor<1x8x2x2xf32>) -> !ng.tensor<1x2x4x4xf32> + "ng.return"(%0) : (!ng.tensor<1x2x4x4xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @convBias +func @convBias(%arg0: !ng.tensor<1x3x2xf32>, %arg1: !ng.tensor<2x3x1xf32>, %arg2: !ng.tensor<2xf32>) -> (!ng.tensor<1x2x2xf32>) +{ + //CHECK: %{{[0-9]+}} = "ng.convBias"(%{{.*}}, %{{.*}}, %{{.*}}) {padAbove = [0], padBelow = [0], strides = [1]} : (!ng.tensor<1x3x2xf32>, !ng.tensor<2x3x1xf32>, !ng.tensor<2xf32>) -> !ng.tensor<1x2x2xf32> + %0 = "ng.convBias"(%arg0, %arg1, %arg2) {padAbove=[0], padBelow=[0], strides=[1]} + : (!ng.tensor<1x3x2xf32>, !ng.tensor<2x3x1xf32>, !ng.tensor<2xf32>) -> !ng.tensor<1x2x2xf32> + "ng.return"(%0) : (!ng.tensor<1x2x2xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @convBiasBackprop +func @convBiasBackprop(%arg0: !ng.tensor<1x3x2x2xf32>, %arg1: !ng.tensor<1x2x2x2xf32>) -> (!ng.tensor<12x3x1x1xf32>) +{ + //CHECK: %{{[0-9]+}}:2 = "ng.convBiasBackpropFiltersBias"(%{{.*}}, %{{.*}}) {biasShape = [2], filtersShape = [2, 3, 1, 1], padAbove = [0], padBelow = [0], strides = [1]} : (!ng.tensor<1x3x2x2xf32>, !ng.tensor<1x2x2x2xf32>) -> (!ng.tensor<2x3x1x1xf32>, !ng.tensor<2xf32>) + %0:2 = "ng.convBiasBackpropFiltersBias"(%arg0, %arg1) {biasShape=[2], filtersShape=[2, 3, 1, 1], padAbove=[0], padBelow=[0], strides=[1]} + : (!ng.tensor<1x3x2x2xf32>, !ng.tensor<1x2x2x2xf32>) -> (!ng.tensor<2x3x1x1xf32>, !ng.tensor<2xf32>) + "ng.return"(%0#0) : (!ng.tensor<2x3x1x1xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @convBiasAdd +func @convBiasAdd(%arg0: !ng.tensor<1x3x2x2xf32>, %arg1: !ng.tensor<2x3x1x1xf32>, %arg2: !ng.tensor<2xf32>, %arg3: !ng.tensor<1x2x2x2xf32>) -> !ng.tensor<1x2x2x2xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.convBiasAdd"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {padAbove = [0, 0], padBelow = [0, 0], strides = [1, 1]} : (!ng.tensor<1x3x2x2xf32>, !ng.tensor<2x3x1x1xf32>, !ng.tensor<2xf32>, !ng.tensor<1x2x2x2xf32>) -> !ng.tensor<1x2x2x2xf32> + %0 = "ng.convBiasAdd" (%arg0, %arg1, %arg2, %arg3) {padAbove=[0, 0], padBelow=[0, 0], strides=[1, 1]} + : (!ng.tensor<1x3x2x2xf32>, !ng.tensor<2x3x1x1xf32>, !ng.tensor<2xf32>, !ng.tensor<1x2x2x2xf32>) -> !ng.tensor<1x2x2x2xf32> + "ng.return"(%0) : (!ng.tensor<1x2x2x2xf32>) -> () +} + +// ----- + +//CHECK-LABEL: func @rnnCell +func @rnnCell(%arg0: !ng.tensor<2x3xf32>, %arg1: !ng.tensor<2x3xf32>, %arg2: !ng.tensor<2x3xf32>, %arg3: !ng.tensor<3x3xf32>, %arg4: !ng.tensor<3xf32>) -> !ng.tensor<2x3xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.rnnCell"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {hiddenSize = 3 : i64} : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<3x3xf32>) -> !ng.tensor<2x3xf32> + %0 = "ng.rnnCell" (%arg0, %arg1, %arg2, %arg3) {hiddenSize = 3 : i64} + : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<3x3xf32>) -> !ng.tensor<2x3xf32> + + // CHECK: %{{[0-9]+}} = "ng.rnnCell"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {hiddenSize = 3 : i64} : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<3x3xf32>, !ng.tensor<3xf32>) -> !ng.tensor<2x3xf32> + %1 = "ng.rnnCell" (%arg0, %arg1, %arg2, %arg3, %arg4) {hiddenSize = 3 : i64} + : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<3x3xf32>, !ng.tensor<3xf32>) -> !ng.tensor<2x3xf32> + + "ng.return" (%0) : (!ng.tensor<2x3xf32>)->() + +} + +// ----- + +//CHECK-LABEL: func @lstmCell +func @lstmCell(%arg0: !ng.tensor<2x3xf32>, %arg1: !ng.tensor<2x3xf32>, %arg2: !ng.tensor<2x3xf32>, %arg3: !ng.tensor<12x3xf32>, %arg4: !ng.tensor<12x3xf32>) -> !ng.tensor<2x3xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.lstmCell"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {hiddenSize = 3 : i64} : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<12x3xf32>, !ng.tensor<12x3xf32>) -> !ng.tensor<2x3xf32> + %0 = "ng.lstmCell" (%arg0, %arg1, %arg2, %arg3, %arg4) {hiddenSize = 3 : i64} + : (!ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<12x3xf32>, !ng.tensor<12x3xf32>) -> !ng.tensor<2x3xf32> + "ng.return" (%0) : (!ng.tensor<2x3xf32>)->() +} + +// ----- + +//CHECK-LABEL: func @gruCell +func @gruCell(%arg0: !ng.tensor<2x3xf32>, %arg1: !ng.tensor<9x3xf32>, %arg2: !ng.tensor<9x3xf32>, %arg3: !ng.tensor<2x3xf32>, %arg4: !ng.tensor<18xf32>) -> !ng.tensor<2x3xf32> +{ + // CHECK: %{{[0-9]+}} = "ng.gruCell"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {activations = ["sigmoid", "tanh"], activationsAlpha = [], clip = {{.*}} : f32, hiddenSize = 3 : i64} : (!ng.tensor<2x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<18xf32>) -> !ng.tensor<2x3xf32> + %0 = "ng.gruCell" (%arg0, %arg1, %arg2, %arg3, %arg4) {activations=["sigmoid", "tanh"], activationsAlpha = [], clip = 2.88 : f32, hiddenSize = 3 : i64} + : (!ng.tensor<2x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<2x3xf32>, !ng.tensor<18xf32>) -> !ng.tensor<2x3xf32> + + // CHECK: %{{[0-9]+}} = "ng.gruCell"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {activations = ["sigmoid", "tanh"], activationsAlpha = [], clip = {{.*}} : f32, hiddenSize = 3 : i64} : (!ng.tensor<2x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<2x3xf32>) -> !ng.tensor<2x3xf32> + %1 = "ng.gruCell" (%arg0, %arg1, %arg2, %arg3) {activations=["sigmoid", "tanh"], activationsAlpha = [], clip = 2.88 : f32, hiddenSize = 3 : i64} + : (!ng.tensor<2x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<9x3xf32>, !ng.tensor<2x3xf32>) -> !ng.tensor<2x3xf32> + "ng.return" (%0) : (!ng.tensor<2x3xf32>) -> () +} diff --git a/test/mlir/ngraph_dialect/types.mlir b/test/mlir/ngraph_dialect/types.mlir index 21d7b210716..654fae05193 100644 --- a/test/mlir/ngraph_dialect/types.mlir +++ b/test/mlir/ngraph_dialect/types.mlir @@ -55,7 +55,7 @@ func @i64(%arg0: !ng.i64) { // ----- // CHECK-LABEL: func @u8 -// CHECK-SAME: (%{{.*}}: !ng.i8) +// CHECK-SAME: (%{{.*}}: !ng.u8) func @u8(%arg0: !ng.u8) { "ng.return"() : () -> () } @@ -63,7 +63,7 @@ func @u8(%arg0: !ng.u8) { // ----- // CHECK-LABEL: func @u16 -// CHECK-SAME: (%{{.*}}: !ng.i16) +// CHECK-SAME: (%{{.*}}: !ng.u16) func @u16(%arg0: !ng.u16) { "ng.return"() : () -> () } @@ -71,7 +71,7 @@ func @u16(%arg0: !ng.u16) { // ----- // CHECK-LABEL: func @u32 -// CHECK-SAME: (%{{.*}}: !ng.i32) +// CHECK-SAME: (%{{.*}}: !ng.u32) func @u32(%arg0: !ng.u32) { "ng.return"() : () -> () } @@ -83,3 +83,83 @@ func @u32(%arg0: !ng.u32) { func @u64(%arg0: !ng.u64) { "ng.return"() : () -> () } + +// ----- + +// CHECK: func @tensor_i8 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.i8>) +func @tensor_i8(%arg0: !ng.tensor<2x2x!ng.i8>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_i16 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.i16>) +func @tensor_i16(%arg0: !ng.tensor<2x2x!ng.i16>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_i32 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.i32>) +func @tensor_i32(%arg0: !ng.tensor<2x2x!ng.i32>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_i64 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.i64>) +func @tensor_i64(%arg0: !ng.tensor<2x2x!ng.i64>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_u8 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.u8>) +func @tensor_u8(%arg0: !ng.tensor<2x2x!ng.u8>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_u16 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.u16>) +func @tensor_u16(%arg0: !ng.tensor<2x2x!ng.u16>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_u32 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.u32>) +func @tensor_u32(%arg0: !ng.tensor<2x2x!ng.u32>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_u64 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2x!ng.u64>) +func @tensor_u64(%arg0: !ng.tensor<2x2x!ng.u64>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_f32 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2xf32>) +func @tensor_f32(%arg0: !ng.tensor<2x2xf32>) { + "ng.return"() : () -> () +} + +// ----- + +// CHECK: func @tensor_f64 +// CHECK-SAME: (%{{.*}}: !ng.tensor<2x2xf64>) +func @tensor_f64(%arg0: !ng.tensor<2x2xf64>) { + "ng.return"() : () -> () +} diff --git a/test/models/onnx/cum_sum_1d.prototxt b/test/models/onnx/cum_sum_1d.prototxt new file mode 100644 index 00000000000..6a09cfa51b3 --- /dev/null +++ b/test/models/onnx/cum_sum_1d.prototxt @@ -0,0 +1,49 @@ +ir_version: 5 +producer_name: "nGraph ONNX Importer" +graph { + node { + input: "x" + output: "y" + op_type: "CumSum" + attribute { + name: "exclusive" + i: 0 + type: INT + } + attribute { + name: "reverse" + i: 0 + type: INT + } + } + name: "test_cum_sum" + input { + name: "x" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 3 + } + } + } + } + } + output { + name: "y" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 3 + } + } + } + } + } +} +opset_import { + version: 11 +} diff --git a/test/models/onnx/cum_sum_2d_axis_input.prototxt b/test/models/onnx/cum_sum_2d_axis_input.prototxt new file mode 100644 index 00000000000..1585c29c668 --- /dev/null +++ b/test/models/onnx/cum_sum_2d_axis_input.prototxt @@ -0,0 +1,69 @@ +ir_version: 5 +producer_name: "nGraph ONNX Importer" +graph { + node { + input: "x" + input: "axis" + output: "y" + op_type: "CumSum" + attribute { + name: "exclusive" + i: 0 + type: INT + } + attribute { + name: "reverse" + i: 0 + type: INT + } + } + name: "test_cum_sum" + input { + name: "x" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + } + } + } + } + initializer { + data_type: 7 + name: "axis" + int64_data: 1 + } + input { + name: "axis" + type { + tensor_type { + elem_type: 7 + } + } + } + output { + name: "y" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + } + } + } + } +} +opset_import { + version: 11 +} diff --git a/test/models/onnx/cum_sum_2d_dynamic_axis_input.prototxt b/test/models/onnx/cum_sum_2d_dynamic_axis_input.prototxt new file mode 100644 index 00000000000..a25c0a33b99 --- /dev/null +++ b/test/models/onnx/cum_sum_2d_dynamic_axis_input.prototxt @@ -0,0 +1,64 @@ +ir_version: 5 +producer_name: "nGraph ONNX Importer" +graph { + node { + input: "x" + input: "axis" + output: "y" + op_type: "CumSum" + attribute { + name: "exclusive" + i: 0 + type: INT + } + attribute { + name: "reverse" + i: 0 + type: INT + } + } + name: "test_cum_sum" + input { + name: "x" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + } + } + } + } + input { + name: "axis" + type { + tensor_type { + elem_type: 6 + } + } + } + output { + name: "y" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + } + } + } + } +} +opset_import { + version: 11 +} diff --git a/test/models/onnx/cum_sum_3d_exclusive_reverse.prototxt b/test/models/onnx/cum_sum_3d_exclusive_reverse.prototxt new file mode 100644 index 00000000000..921201bb947 --- /dev/null +++ b/test/models/onnx/cum_sum_3d_exclusive_reverse.prototxt @@ -0,0 +1,61 @@ +ir_version: 5 +producer_name: "nGraph ONNX Importer" +graph { + node { + input: "x" + output: "y" + op_type: "CumSum" + attribute { + name: "exclusive" + i: 1 + type: INT + } + attribute { + name: "reverse" + i: 1 + type: INT + } + } + name: "test_cum_sum" + input { + name: "x" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + dim { + dim_value: 4 + } + } + } + } + } + output { + name: "y" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + dim { + dim_value: 3 + } + dim { + dim_value: 4 + } + } + } + } + } +} +opset_import { + version: 11 +} diff --git a/test/models/onnx/matmul_float.prototxt b/test/models/onnx/matmul_float.prototxt new file mode 100644 index 00000000000..c40d5cfa5e3 --- /dev/null +++ b/test/models/onnx/matmul_float.prototxt @@ -0,0 +1,69 @@ +ir_version: 6 +graph { + node { + input: "A" + input: "B" + output: "Y" + name: "node1" + op_type: "MatMul" + doc_string: "MatMul" + } + name: "fused_function_subgraph" + doc_string: "" + input { + name: "A" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 3 + } + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } + input { + name: "B" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 2 + } + } + } + } + } + output { + name: "Y" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 3 + } + dim { + dim_value: 1 + } + } + } + } + } +} +opset_import { + domain: "" + version: 7 +} +opset_import { + domain: "ai.onnx.ml" + version: 2 +} diff --git a/test/models/onnx/mod_sign.prototxt b/test/models/onnx/mod_sign.prototxt new file mode 100644 index 00000000000..3922213e957 --- /dev/null +++ b/test/models/onnx/mod_sign.prototxt @@ -0,0 +1,58 @@ +ir_version: 5 +producer_name: "nGraph ONNX Importer" +graph { + node { + input: "A" + input: "B" + output: "Y" + op_type: "Mod" + attribute { + name: "fmod" + i: 1 + type: INT + } + } + name: "test_mod" + input { + name: "A" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 6 + } + } + } + } + } + input { + name: "B" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 6 + } + } + } + } + } + output { + name: "Y" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 6 + } + } + } + } + } +} +opset_import { + version: 10 +} diff --git a/test/onnx/onnx_import.in.cpp b/test/onnx/onnx_import.in.cpp index 27969f47b92..a0ad77dbbec 100644 --- a/test/onnx/onnx_import.in.cpp +++ b/test/onnx/onnx_import.in.cpp @@ -436,6 +436,55 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_sum_one_input) EXPECT_TRUE(test::all_close_f(expected_outputs.front(), outputs.front())); } +NGRAPH_TEST(onnx_${BACKEND_NAME}, model_cum_sum_1d) +{ + auto function = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/cum_sum_1d.prototxt")); + + auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input({1.f, 2.f, 3.f}); + test_case.add_expected_output(Shape{3}, {1.f, 3.f, 6.f}); + test_case.run(); +} + +NGRAPH_TEST(onnx_${BACKEND_NAME}, model_cum_sum_2d_axis_input) +{ + auto function = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/cum_sum_2d_axis_input.prototxt")); + + auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input({1.f, 2.f, 3.f, 4.f, 5.f, 6.f}); + test_case.add_expected_output(Shape{2, 3}, {1.f, 3.f, 6.f, 4.f, 9.f, 15.f}); + test_case.run(); +} + +NGRAPH_TEST(onnx_${BACKEND_NAME}, model_cum_sum_2d_dynamic_axis_input) +{ + auto function = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/cum_sum_2d_dynamic_axis_input.prototxt")); + + auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input({1.f, 2.f, 3.f, 4.f, 5.f, 6.f}); + test_case.add_input({1}); + test_case.add_expected_output(Shape{2, 3}, {1.f, 3.f, 6.f, 4.f, 9.f, 15.f}); + test_case.run(); +} + +NGRAPH_TEST(onnx_${BACKEND_NAME}, model_cum_sum_3d_exclusive_reverse) +{ + auto function = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/cum_sum_3d_exclusive_reverse.prototxt")); + + auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input({1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, + 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f, + 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f, 24.f}); + test_case.add_expected_output( + Shape{2, 3, 4}, {13.f, 14.f, 15.f, 16.f, 17.f, 18.f, 19.f, 20.f, 21.f, 22.f, 23.f, 24.f, + 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}); + test_case.run(); +} + NGRAPH_TEST(onnx_${BACKEND_NAME}, model_min_two_inputs) { auto function = onnx_import::import_onnx_model( @@ -1703,3 +1752,27 @@ NGRAPH_TEST(onnx_${BACKEND_NAME}, model_reverse_sequence_time_and_batch_axis_equ ngraph_error) << "ReverseSequence 'time_axis' and 'batch_axis' can't be equal."; } + +NGRAPH_TEST(onnx_${BACKEND_NAME}, matmul_float_type) +{ + auto function = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/matmul_float.prototxt")); + auto test_case = ngraph::test::NgraphTestCase(function, "${BACKEND_NAME}"); + test_case.add_input(std::vector{0, 1, 2, 3, 4, 5}); + test_case.add_input(std::vector{0, 1}); + test_case.add_expected_output(Shape{3, 1}, std::vector{1, 3, 5}); + test_case.run(); +} + +NGRAPH_TEST(onnx_${BACKEND_NAME}, model_mod) +{ + const auto mod_fn = onnx_import::import_onnx_model( + file_util::path_join(SERIALIZED_ZOO, "onnx/mod_sign.prototxt")); + auto test_case = ngraph::test::NgraphTestCase(mod_fn, "${BACKEND_NAME}"); + + test_case.add_input({-8, 3, 4, 9, -17, 1}); + test_case.add_input({22, -13, 8, -3, 7, 2}); + test_case.add_expected_output(Shape{6}, {-8, 3, 4, 0, -3, 1}); + + test_case.run(); +} diff --git a/test/opset1.cpp b/test/opset1.cpp new file mode 100644 index 00000000000..50296dd6389 --- /dev/null +++ b/test/opset1.cpp @@ -0,0 +1,144 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" + +#include "ngraph/ngraph.hpp" +#include "ngraph/opsets/opset1.hpp" + +#include +#include + +using namespace std; +using namespace ngraph; + +#define CHECK_OPSET(op1, op2) \ + EXPECT_TRUE(is_type(make_shared())); \ + EXPECT_TRUE((std::is_same::value)); + +TEST(opset, check_opset1) +{ + CHECK_OPSET(op::v0::Abs, opset1::Abs) + CHECK_OPSET(op::v0::Acos, opset1::Acos) + // TODO: CHECK_OPSET(op::v0::Acosh, opset1::Acosh) + CHECK_OPSET(op::v1::Add, opset1::Add) + CHECK_OPSET(op::v0::Asin, opset1::Asin) + // TODO: CHECK_OPSET(op::v0::Asinh, opset1::Asinh) + CHECK_OPSET(op::v1::LogicalAnd, opset1::LogicalAnd) + CHECK_OPSET(op::v0::Atan, opset1::Atan) + // TODO: CHECK_OPSET(op::v0::Atanh, opset1::Atanh) + CHECK_OPSET(op::v1::AvgPool, opset1::AvgPool) + CHECK_OPSET(op::v0::BatchNormInference, opset1::BatchNormInference) + CHECK_OPSET(op::v1::Broadcast, opset1::Broadcast) + CHECK_OPSET(op::v0::Ceiling, opset1::Ceiling) + CHECK_OPSET(op::v0::Concat, opset1::Concat) + // TODO: CHECK_OPSET(op::v0::Constant, opset1::Constant) + CHECK_OPSET(op::v0::Convert, opset1::Convert) + // TODO: CHECK_OPSET(op::v0::ConvertLike, opset1::ConvertLike) + CHECK_OPSET(op::v1::Convolution, opset1::Convolution) + CHECK_OPSET(op::v1::ConvolutionBackpropData, opset1::ConvolutionBackpropData) + CHECK_OPSET(op::v0::Cos, opset1::Cos) + CHECK_OPSET(op::v0::Cosh, opset1::Cosh) + CHECK_OPSET(op::v0::CTCGreedyDecoder, opset1::CTCGreedyDecoder) + // TODO: using op::v0::DeformableConvolution + CHECK_OPSET(op::v1::DeformablePSROIPooling, opset1::DeformablePSROIPooling) + CHECK_OPSET(op::v0::DepthToSpace, opset1::DepthToSpace) + CHECK_OPSET(op::v0::DetectionOutput, opset1::DetectionOutput) + CHECK_OPSET(op::v1::Divide, opset1::Divide) + CHECK_OPSET(op::v0::Elu, opset1::Elu) + CHECK_OPSET(op::v1::Equal, opset1::Equal) + CHECK_OPSET(op::v0::Erf, opset1::Erf) + CHECK_OPSET(op::v0::Exp, opset1::Exp) + CHECK_OPSET(op::v0::FakeQuantize, opset1::FakeQuantize) + CHECK_OPSET(op::v0::Floor, opset1::Floor) + // TODO: CHECK_OPSET(op::v0::FloorMod, opset1::FloorMod) + CHECK_OPSET(op::v1::Gather, opset1::Gather) + // TODO: CHECK_OPSET(op::v0::GatherTree, opset1::GatherTree) + CHECK_OPSET(op::v1::Greater, opset1::Greater) + CHECK_OPSET(op::v1::GreaterEqual, opset1::GreaterEqual) + CHECK_OPSET(op::v0::GRN, opset1::GRN) + CHECK_OPSET(op::v0::GroupConvolution, opset1::GroupConvolution) + // CHECK_OPSET(op::v0::GRUCell, opset1::GRUCell) + // TODO CHECK_OPSET(op::v0::GRUSequence, opset1::GRUSequence) + CHECK_OPSET(op::v0::HardSigmoid, opset1::HardSigmoid) + CHECK_OPSET(op::v0::Interpolate, opset1::Interpolate) + CHECK_OPSET(op::v1::Less, opset1::Less) + CHECK_OPSET(op::v1::LessEqual, opset1::LessEqual) + CHECK_OPSET(op::v0::Log, opset1::Log) + CHECK_OPSET(op::v1::LogicalAnd, opset1::LogicalAnd) + CHECK_OPSET(op::v1::LogicalNot, opset1::LogicalNot) + CHECK_OPSET(op::v1::LogicalOr, opset1::LogicalOr) + CHECK_OPSET(op::v1::LogicalXor, opset1::LogicalXor) + CHECK_OPSET(op::v0::LRN, opset1::LRN) + CHECK_OPSET(op::v0::MatMul, opset1::MatMul) + CHECK_OPSET(op::v1::Maximum, opset1::Maximum) + CHECK_OPSET(op::v1::MaxPool, opset1::MaxPool) + CHECK_OPSET(op::v1::Minimum, opset1::Minimum) + // TODO CHECK_OPSET(op::v0::Mod, opset1::Mod) + CHECK_OPSET(op::v1::Multiply, opset1::Multiply) + CHECK_OPSET(op::v0::Negative, opset1::Negative) + // TODO using op::v0::NonMaxSuppression + CHECK_OPSET(op::v0::NormalizeL2, opset1::NormalizeL2) + CHECK_OPSET(op::v1::NotEqual, opset1::NotEqual) + // TODO CHECK_OPSET(op::v1::OneHot, opset1::OneHot) + CHECK_OPSET(op::v1::Pad, opset1::Pad) + // TODO: CHECK_OPSET(op::v0::Parameter, opset1::Parameter) + CHECK_OPSET(op::v1::Power, opset1::Power) + CHECK_OPSET(op::v0::PRelu, opset1::PRelu) + CHECK_OPSET(op::v0::PriorBox, opset1::PriorBox) + CHECK_OPSET(op::v0::PriorBoxClustered, opset1::PriorBoxClustered) + CHECK_OPSET(op::v0::Proposal, opset1::Proposal) + CHECK_OPSET(op::v0::PSROIPooling, opset1::PSROIPooling) + CHECK_OPSET(op::v1::ReduceLogicalAnd, opset1::ReduceLogicalAnd) + CHECK_OPSET(op::v1::ReduceLogicalOr, opset1::ReduceLogicalOr) + CHECK_OPSET(op::v1::ReduceMax, opset1::ReduceMax) + CHECK_OPSET(op::v1::ReduceMean, opset1::ReduceMean) + CHECK_OPSET(op::v1::ReduceMin, opset1::ReduceMin) + CHECK_OPSET(op::v1::ReduceProd, opset1::ReduceProd) + CHECK_OPSET(op::v1::ReduceSum, opset1::ReduceSum) + CHECK_OPSET(op::v0::RegionYolo, opset1::RegionYolo) + CHECK_OPSET(op::v0::Relu, opset1::Relu) + CHECK_OPSET(op::v1::Reshape, opset1::Reshape) + // TODO: CHECK_OPSET(op::v0::Result, opset1::Result) + CHECK_OPSET(op::v1::Reverse, opset1::Reverse) + CHECK_OPSET(op::v0::ReverseSequence, opset1::ReverseSequence) + // CHECK_OPSET(op::v0::RNNCell, opset1::RNNCell) + CHECK_OPSET(op::v0::Select, opset1::Select) + CHECK_OPSET(op::v0::Selu, opset1::Selu) + CHECK_OPSET(op::v0::ShapeOf, opset1::ShapeOf) + CHECK_OPSET(op::v0::ShuffleChannels, opset1::ShuffleChannels) + CHECK_OPSET(op::v0::Sigmoid, opset1::Sigmoid) + CHECK_OPSET(op::v0::Sign, opset1::Sign) + CHECK_OPSET(op::v0::Sin, opset1::Sin) + CHECK_OPSET(op::v0::Sinh, opset1::Sinh) + CHECK_OPSET(op::v1::Softmax, opset1::Softmax) + CHECK_OPSET(op::v0::SpaceToDepth, opset1::SpaceToDepth) + CHECK_OPSET(op::v0::Split, opset1::Split) + CHECK_OPSET(op::v0::Sqrt, opset1::Sqrt) + CHECK_OPSET(op::v0::SquaredDifference, opset1::SquaredDifference) + CHECK_OPSET(op::v0::Squeeze, opset1::Squeeze) + CHECK_OPSET(op::v1::StridedSlice, opset1::StridedSlice) + CHECK_OPSET(op::v1::Subtract, opset1::Subtract) + CHECK_OPSET(op::v0::Tan, opset1::Tan) + CHECK_OPSET(op::v0::Tanh, opset1::Tanh) + CHECK_OPSET(op::v0::TensorIterator, opset1::TensorIterator) + CHECK_OPSET(op::v0::Tile, opset1::Tile) + CHECK_OPSET(op::v1::TopK, opset1::TopK) + CHECK_OPSET(op::v0::Transpose, opset1::Transpose) + CHECK_OPSET(op::v0::Unsqueeze, opset1::Unsqueeze) + // TODO using op::v0::VariadicSplit + CHECK_OPSET(op::v0::Xor, opset1::Xor) +} diff --git a/test/opset_pass/binary_elementwise_opset_pass.cpp b/test/opset_pass/binary_elementwise_opset_pass.cpp index 677b247de63..c7547fe5c07 100644 --- a/test/opset_pass/binary_elementwise_opset_pass.cpp +++ b/test/opset_pass/binary_elementwise_opset_pass.cpp @@ -35,11 +35,10 @@ void test_type_prop_opset0_downgrade_pass(const element::Type& output_type, pass_manager.run_passes(f); auto v0_result = f->get_results().at(0); - auto node = v0_result->input(0).get_source_output().get_node_shared_ptr(); - auto v0_node = static_pointer_cast(node); + auto node = v0_result->input_value(0).get_node_shared_ptr(); + auto v0_node = as_type_ptr(node); - EXPECT_EQ(v0_node->description(), (node_name.empty() ? v1_node->description() : node_name)); - EXPECT_EQ(v0_node->get_version(), 0); + ASSERT_TRUE(v0_node); EXPECT_EQ(v0_node->get_autob(), np_auto_b); EXPECT_EQ(v0_node->output(0).get_element_type(), output_type); EXPECT_EQ(v0_node->output(0).get_shape(), (Shape{1, 3, 2})); @@ -76,10 +75,8 @@ void test_type_prop_opset1_upgrade_pass(const element::Type& output_type, auto v1_result = f->get_results().at(0); auto node = v1_result->input(0).get_source_output().get_node_shared_ptr(); - auto v1_node = static_pointer_cast(node); - - EXPECT_EQ(v1_node->description(), (node_name.empty() ? v0_node->description() : node_name)); - EXPECT_EQ(v1_node->get_version(), 1); + auto v1_node = as_type_ptr(node); + ASSERT_TRUE(v1_node); EXPECT_EQ(v1_node->get_autob(), none_auto_b); EXPECT_EQ(v1_node->output(0).get_element_type(), output_type); EXPECT_EQ(v1_node->output(0).get_shape(), (Shape{1, 3, 2})); @@ -131,10 +128,8 @@ TEST(opset_transform, opset0_divide_downgrade_pass) auto divide_v0_result = f->get_results().at(0); auto node = divide_v0_result->input(0).get_source_output().get_node_shared_ptr(); - auto divide_v0_node = static_pointer_cast(node); - - EXPECT_EQ(divide_v0_node->description(), "Divide"); - EXPECT_EQ(divide_v0_node->get_version(), 0); + auto divide_v0_node = as_type_ptr(node); + ASSERT_TRUE(divide_v0_node); EXPECT_EQ(divide_v0_node->is_pythondiv(), pydiv); EXPECT_EQ(divide_v0_node->get_autob(), np_auto_b); EXPECT_EQ(divide_v0_node->output(0).get_element_type(), element::f32); @@ -158,10 +153,8 @@ TEST(opset_transform, opset1_divide_upgrade_pass) auto divide_v1_result = f->get_results().at(0); auto node = divide_v1_result->input(0).get_source_output().get_node_shared_ptr(); - auto divide_v1_node = static_pointer_cast(node); - - EXPECT_EQ(divide_v1_node->description(), "Divide"); - EXPECT_EQ(divide_v1_node->get_version(), 1); + auto divide_v1_node = as_type_ptr(node); + ASSERT_TRUE(divide_v1_node); EXPECT_EQ(divide_v1_node->is_pythondiv(), pydiv); EXPECT_EQ(divide_v1_node->get_autob(), none_auto_b); EXPECT_EQ(divide_v1_node->output(0).get_element_type(), element::f32); @@ -190,12 +183,12 @@ TEST(opset_transform, opset1_greater_upgrade_pass) TEST(opset_transform, opset0_greater_eq_downgrade_pass) { - test_opset0_comparison_downgrade_pass(); + test_opset0_comparison_downgrade_pass(); } TEST(opset_transform, opset1_greater_eq_upgrade_pass) { - test_opset1_comparison_upgrade_pass(); + test_opset1_comparison_upgrade_pass(); } TEST(opset_transform, opset0_less_downgrade_pass) @@ -269,3 +262,13 @@ TEST(opset_transform, opset1_power_upgrade_pass) { test_opset1_arithmetic_upgrade_pass(); } + +TEST(opset_transform, opset0_subtract_downgrade_pass) +{ + test_opset0_arithmetic_downgrade_pass(); +} + +TEST(opset_transform, opset1_subtract_upgrade_pass) +{ + test_opset1_arithmetic_upgrade_pass(); +} diff --git a/test/opset_pass/broadcast_opset_pass.cpp b/test/opset_pass/broadcast_opset_pass.cpp index af278372d4c..267d47ac652 100644 --- a/test/opset_pass/broadcast_opset_pass.cpp +++ b/test/opset_pass/broadcast_opset_pass.cpp @@ -22,20 +22,18 @@ TEST(opset_transform, opset1_broadcast_upgrade_pass) pass_manager.register_pass(); pass_manager.run_passes(f); - auto bcast_v1 = static_pointer_cast( + auto bcast_v1 = as_type_ptr( f->get_results().at(0)->input_value(0).get_node_shared_ptr()); - EXPECT_EQ(bcast_v1->description(), "Broadcast"); - EXPECT_EQ(bcast_v1->get_version(), 1); + ASSERT_TRUE(bcast_v1); EXPECT_EQ(bcast_v1->get_broadcast_spec(), op::AutoBroadcastSpec()); EXPECT_EQ(bcast_v1->get_broadcast_axes(), (std::make_pair(true, AxisSet{0, 2}))); - - EXPECT_EQ(bcast_v1->input_value(1).get_node()->description(), "Constant"); - EXPECT_EQ(bcast_v1->input_value(2).get_node()->description(), "Constant"); - EXPECT_EQ(static_pointer_cast(bcast_v1->input_value(1).get_node_shared_ptr()) - ->get_shape_val(), - (Shape{3, 5, 4, 6})); - EXPECT_EQ(static_pointer_cast(bcast_v1->input_value(2).get_node_shared_ptr()) + ASSERT_TRUE(bcast_v1->input_value(1).get_node()->is_constant()); + ASSERT_TRUE(bcast_v1->input_value(2).get_node()->is_constant()); + EXPECT_EQ( + as_type_ptr(bcast_v1->input_value(1).get_node_shared_ptr())->get_shape_val(), + (Shape{3, 5, 4, 6})); + EXPECT_EQ(as_type_ptr(bcast_v1->input_value(2).get_node_shared_ptr()) ->get_axis_set_val(), (AxisSet{1, 3})); } @@ -53,11 +51,10 @@ TEST(opset_transform, opset1_broadcast_downgrade_pass) pass_manager.register_pass(); pass_manager.run_passes(f); - auto bcast_v0 = static_pointer_cast( + auto bcast_v0 = as_type_ptr( f->get_results().at(0)->input_value(0).get_node_shared_ptr()); - EXPECT_EQ(bcast_v0->description(), "Broadcast"); - EXPECT_EQ(bcast_v0->get_version(), 0); + ASSERT_TRUE(bcast_v0); EXPECT_EQ(bcast_v0->get_broadcast_shape(), (Shape{3, 1, 4, 2, 3})); EXPECT_EQ(bcast_v0->get_broadcast_axes(), (AxisSet{0, 2})); } diff --git a/test/opset_pass/convolution_opset_pass.cpp b/test/opset_pass/convolution_opset_pass.cpp index bf6f120a187..acd2998e0a8 100644 --- a/test/opset_pass/convolution_opset_pass.cpp +++ b/test/opset_pass/convolution_opset_pass.cpp @@ -33,10 +33,9 @@ TEST(opset_transform, opset1_convolution_upgrade_pass) auto convolution_s1_result = f->get_results().at(0); auto node = convolution_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto convolution_v1_node = static_pointer_cast(node); + auto convolution_v1_node = as_type_ptr(node); - EXPECT_EQ(convolution_v1_node->description(), "Convolution"); - EXPECT_EQ(convolution_v1_node->get_version(), 1); + ASSERT_TRUE(convolution_v1_node); EXPECT_EQ(convolution_v1_node->get_pads_begin(), pads_begin); EXPECT_EQ(convolution_v1_node->get_pads_end(), pads_end); @@ -66,10 +65,9 @@ TEST(opset_transform, opset1_convolution_downgrade_pass) auto conv_s0_result = f->get_results().at(0); auto node = conv_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto conv_v0_node = static_pointer_cast(node); + auto conv_v0_node = as_type_ptr(node); - EXPECT_EQ(conv_v0_node->description(), "Convolution"); - EXPECT_EQ(conv_v0_node->get_version(), 0); + ASSERT_TRUE(conv_v0_node); EXPECT_EQ(conv_v0_node->get_window_movement_strides(), strides); EXPECT_EQ(conv_v0_node->get_window_dilation_strides(), dilations); EXPECT_EQ(conv_v0_node->get_padding_below(), pads_begin); @@ -89,7 +87,7 @@ TEST(opset_transform, opset1_convolution_backprop_data_downgrade_pass) auto padding_end = CoordinateDiff{3}; auto conv = make_shared( - filters, delta, data_batch_shape, strides, dilations, padding_begin, padding_end); + delta, filters, data_batch_shape, strides, padding_begin, padding_end, dilations); auto result = make_shared(conv); auto f = make_shared(ResultVector{result}, ParameterVector{filters, delta}); @@ -99,10 +97,9 @@ TEST(opset_transform, opset1_convolution_backprop_data_downgrade_pass) auto conv_s0_result = f->get_results().at(0); auto node = conv_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto conv_v0_node = static_pointer_cast(node); + auto conv_v0_node = as_type_ptr(node); - EXPECT_EQ(conv_v0_node->description(), "ConvolutionBackpropData"); - EXPECT_EQ(conv_v0_node->get_version(), 0); + ASSERT_TRUE(conv_v0_node); EXPECT_EQ(conv_v0_node->get_data_batch_shape(), (Shape{64, 3, 100})); EXPECT_EQ(conv_v0_node->get_window_movement_strides_forward(), strides); EXPECT_EQ(conv_v0_node->get_window_dilation_strides_forward(), dilations); @@ -131,10 +128,9 @@ TEST(opset_transform, opset1_convolution_backprop_filters_downgrade_pass) auto conv_s0_result = f->get_results().at(0); auto node = conv_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto conv_v0_node = static_pointer_cast(node); + auto conv_v0_node = as_type_ptr(node); - EXPECT_EQ(conv_v0_node->description(), "ConvolutionBackpropFilters"); - EXPECT_EQ(conv_v0_node->get_version(), 0); + ASSERT_TRUE(conv_v0_node); EXPECT_EQ(conv_v0_node->get_filters_shape(), (Shape{128, 3, 10})); EXPECT_EQ(conv_v0_node->get_window_movement_strides_forward(), strides); EXPECT_EQ(conv_v0_node->get_window_dilation_strides_forward(), dilations); diff --git a/test/opset_pass/dyn_reshape_opset_pass.cpp b/test/opset_pass/dyn_reshape_opset_pass.cpp index f3f2babc6b2..6cb399297a9 100644 --- a/test/opset_pass/dyn_reshape_opset_pass.cpp +++ b/test/opset_pass/dyn_reshape_opset_pass.cpp @@ -39,12 +39,8 @@ TEST(opset_transform, opset1_dyn_reshape_upgrade_pass) pass_manager.register_pass(); pass_manager.run_passes(f); - const auto pass_replacement_node = - f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reshape_v1 = as_type_ptr(pass_replacement_node); - - EXPECT_EQ(reshape_v1->description(), "DynReshape"); - EXPECT_EQ(reshape_v1->get_version(), 1); + const auto pass_replacement_node = f->get_result()->input_value(0).get_node_shared_ptr(); + EXPECT_TRUE(is_type(pass_replacement_node)); } TEST(opset_transform, opset1_reshape_downgrade_pass) @@ -60,11 +56,8 @@ TEST(opset_transform, opset1_reshape_downgrade_pass) pass_manager.register_pass(); pass_manager.run_passes(f); - const auto pass_replacement_node = - f->get_result()->input(0).get_source_output().get_node_shared_ptr(); + const auto pass_replacement_node = f->get_result()->input_value(0).get_node_shared_ptr(); const auto reshape_v1 = as_type_ptr(pass_replacement_node); - - EXPECT_EQ(reshape_v1->description(), "DynReshape"); - EXPECT_EQ(reshape_v1->get_version(), 0); + ASSERT_TRUE(reshape_v1); EXPECT_EQ(reshape_v1->get_zero_flag(), true); } diff --git a/test/opset_pass/gather_opset_pass.cpp b/test/opset_pass/gather_opset_pass.cpp index f133086f7dd..158c1e6054c 100644 --- a/test/opset_pass/gather_opset_pass.cpp +++ b/test/opset_pass/gather_opset_pass.cpp @@ -40,10 +40,8 @@ TEST(opset_transform, opset1_gather_upgrade_pass) pass_manager.run_passes(f); auto gather_s1_result = f->get_results().at(0); - auto node = gather_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto gather_v1_node = static_pointer_cast(node); - - EXPECT_EQ(gather_v1_node->description(), "Gather"); - EXPECT_EQ(gather_v1_node->get_version(), 1); + auto gather_v1_node = as_type_ptr( + gather_s1_result->input(0).get_source_output().get_node_shared_ptr()); + ASSERT_TRUE(gather_v1_node); EXPECT_EQ(gather_v1_node->get_axis(), axis); } diff --git a/test/opset_pass/generate_mask_opset_pass.cpp b/test/opset_pass/generate_mask_opset_pass.cpp index 1b9cbd28bb3..dd98b1100cb 100644 --- a/test/opset_pass/generate_mask_opset_pass.cpp +++ b/test/opset_pass/generate_mask_opset_pass.cpp @@ -26,10 +26,8 @@ TEST(opset_transform, opset1_generate_mask_downgrade_pass) pass_manager.register_pass(); pass_manager.run_passes(f); - auto generate_mask_v0 = static_pointer_cast( + auto generate_mask_v0 = as_type_ptr( f->get_results().at(0)->input_value(0).get_node_shared_ptr()); - - EXPECT_EQ(generate_mask_v0->description(), "GenerateMask"); - EXPECT_EQ(generate_mask_v0->get_version(), 0); + ASSERT_TRUE(generate_mask_v0); EXPECT_EQ(generate_mask_v0->get_mask_shape(), (Shape{1, 128})); } diff --git a/test/opset_pass/logical_and_opset_pass.cpp b/test/opset_pass/logical_and_opset_pass.cpp index 8ad5df6cd8f..936cde683f3 100644 --- a/test/opset_pass/logical_and_opset_pass.cpp +++ b/test/opset_pass/logical_and_opset_pass.cpp @@ -40,10 +40,8 @@ TEST(opset_transform, opset1_logical_and_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto and_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(and_v1->description(), "LogicalAnd"); - EXPECT_EQ(and_v1->get_version(), 1); + const auto and_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(and_v1); const auto values_out_element_type = and_v1->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); @@ -63,10 +61,8 @@ TEST(opset_transform, opset1_logical_and_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto and_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(and_v0->description(), "And"); - EXPECT_EQ(and_v0->get_version(), 0); + const auto and_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(and_v0); const auto values_out_element_type = and_v0->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); diff --git a/test/opset_pass/logical_not_opset_pass.cpp b/test/opset_pass/logical_not_opset_pass.cpp index 478de1d9e48..646182ae6ac 100644 --- a/test/opset_pass/logical_not_opset_pass.cpp +++ b/test/opset_pass/logical_not_opset_pass.cpp @@ -39,10 +39,8 @@ TEST(opset_transform, opset1_logical_not_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto not_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(not_v1->description(), "LogicalNot"); - EXPECT_EQ(not_v1->get_version(), 1); + const auto not_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(not_v1); const auto values_out_element_type = not_v1->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); @@ -61,10 +59,8 @@ TEST(opset_transform, opset1_logical_not_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto not_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(not_v0->description(), "Not"); - EXPECT_EQ(not_v0->get_version(), 0); + const auto not_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(not_v0); const auto values_out_element_type = not_v0->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); diff --git a/test/opset_pass/logical_or_opset_pass.cpp b/test/opset_pass/logical_or_opset_pass.cpp index dcf1e82d442..85a1cc368fe 100644 --- a/test/opset_pass/logical_or_opset_pass.cpp +++ b/test/opset_pass/logical_or_opset_pass.cpp @@ -40,10 +40,8 @@ TEST(opset_transform, opset1_logical_or_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto or_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(or_v1->description(), "LogicalOr"); - EXPECT_EQ(or_v1->get_version(), 1); + const auto or_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(or_v1); const auto values_out_element_type = or_v1->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); @@ -63,10 +61,8 @@ TEST(opset_transform, opset1_logical_or_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto or_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(or_v0->description(), "Or"); - EXPECT_EQ(or_v0->get_version(), 0); + const auto or_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(or_v0); const auto values_out_element_type = or_v0->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); diff --git a/test/opset_pass/logical_xor_opset_pass.cpp b/test/opset_pass/logical_xor_opset_pass.cpp index f388989fa59..56a53837fa9 100644 --- a/test/opset_pass/logical_xor_opset_pass.cpp +++ b/test/opset_pass/logical_xor_opset_pass.cpp @@ -40,10 +40,8 @@ TEST(opset_transform, opset1_logical_xor_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto xor_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(xor_v1->description(), "LogicalXor"); - EXPECT_EQ(xor_v1->get_version(), 1); + const auto xor_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(xor_v1); const auto values_out_element_type = xor_v1->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); @@ -63,10 +61,8 @@ TEST(opset_transform, opset1_logical_xor_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto xor_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(xor_v0->description(), "Xor"); - EXPECT_EQ(xor_v0->get_version(), 0); + const auto xor_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(xor_v0); const auto values_out_element_type = xor_v0->output(0).get_element_type(); EXPECT_EQ(values_out_element_type, element::boolean); diff --git a/test/opset_pass/one_hot_opset_pass.cpp b/test/opset_pass/one_hot_opset_pass.cpp new file mode 100644 index 00000000000..1f9cef5fff0 --- /dev/null +++ b/test/opset_pass/one_hot_opset_pass.cpp @@ -0,0 +1,129 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "ngraph/ngraph.hpp" +#include "ngraph/pass/manager.hpp" +#include "ngraph/pass/opset0_downgrade.hpp" +#include "ngraph/pass/opset1_upgrade.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(opset_transform, opset1_one_hot_upgrade_pass) +{ + auto indices = make_shared(element::i64, Shape{1, 3, 2, 3}); + const auto depth = 4; + PartialShape shape{1, 3, 2, depth, 3}; + size_t one_hot_axis = 3; + auto ont_hot_v0 = make_shared(indices, shape, one_hot_axis); + + auto result = make_shared(ont_hot_v0); + auto f = make_shared(ResultVector{result}, ParameterVector{indices}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + const auto pass_replacement_node = + f->get_result()->input(0).get_source_output().get_node_shared_ptr(); + const auto one_hot_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(one_hot_v1); + EXPECT_EQ(one_hot_v1->get_axis(), one_hot_axis); + + auto one_hot_v1_depth = + as_type_ptr(one_hot_v1->input_value(1).get_node_shared_ptr()); + EXPECT_EQ(one_hot_v1_depth->get_vector()[0], depth); + + auto one_hot_v1_on_value = + as_type_ptr(one_hot_v1->input_value(2).get_node_shared_ptr()); + EXPECT_EQ(one_hot_v1_on_value->get_vector()[0], 1); + + auto one_hot_v1_off_value = + as_type_ptr(one_hot_v1->input_value(3).get_node_shared_ptr()); + EXPECT_EQ(one_hot_v1_off_value->get_vector()[0], 0); +} + +TEST(opset_transform, opset1_one_hot_downgrade_pass) +{ + auto indices = make_shared(element::i64, Shape{1, 3, 2, 3}); + auto depth = op::Constant::create(element::i64, Shape{}, {4}); + auto on_value = op::Constant::create(element::u32, Shape{}, {5}); + auto off_value = op::Constant::create(element::u32, Shape{}, {10}); + int64_t axis = 3; + auto ont_hot_v1 = make_shared(indices, depth, on_value, off_value, axis); + + auto result = make_shared(ont_hot_v1); + auto f = make_shared(ResultVector{result}, ParameterVector{indices}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + const auto pass_replacement_node = f->get_result()->input_value(0).get_node_shared_ptr(); + ASSERT_FALSE(is_type(pass_replacement_node)); + + EXPECT_EQ(pass_replacement_node->get_shape(), (Shape{1, 3, 2, 4, 3})); +} + +TEST(opset_transform, opset1_one_hot_downgrade_pass_depth_not_constant) +{ + auto indices = make_shared(element::i64, Shape{1, 3, 2, 3}); + auto depth = make_shared(element::i64, Shape{}); + auto on_value = op::Constant::create(element::u32, Shape{}, {5}); + auto off_value = op::Constant::create(element::u32, Shape{}, {10}); + int64_t axis = 3; + auto ont_hot_v1 = make_shared(indices, depth, on_value, off_value, axis); + + auto result = make_shared(ont_hot_v1); + auto f = make_shared(ResultVector{result}, ParameterVector{indices, depth}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + + try + { + pass_manager.run_passes(f); + // Should have thrown, so fail if it didn't + FAIL() << "Not constant depth not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("depth input must be constant")); + } + catch (...) + { + FAIL() << "OneHot downgrade failed for unexpected reason"; + } +} + +TEST(opset_transform, opset1_one_hot_downgrade_pass_indices_shape_not_static) +{ + auto indices = make_shared(element::i64, PartialShape::dynamic()); + auto depth = op::Constant::create(element::i64, Shape{}, {4}); + auto on_value = op::Constant::create(element::u32, Shape{}, {5}); + auto off_value = op::Constant::create(element::u32, Shape{}, {10}); + int64_t axis = 3; + auto ont_hot_v1 = make_shared(indices, depth, on_value, off_value, axis); + + auto result = make_shared(ont_hot_v1); + auto f = make_shared(ResultVector{result}, ParameterVector{indices}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + + try + { + pass_manager.run_passes(f); + // Should have thrown, so fail if it didn't + FAIL() << "Not static indices shape not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("indices shape must be static")); + } + catch (...) + { + FAIL() << "OneHot downgrade failed for unexpected reason"; + } +} diff --git a/test/opset_pass/pad_opset_pass.cpp b/test/opset_pass/pad_opset_pass.cpp index b38a023556f..9d36e3ba895 100644 --- a/test/opset_pass/pad_opset_pass.cpp +++ b/test/opset_pass/pad_opset_pass.cpp @@ -29,10 +29,8 @@ TEST(opset_transform, opset1_pad_upgrade_pass) auto pad_s1_result = f->get_results().at(0); auto node = pad_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto pad_v1_node = static_pointer_cast(node); - - EXPECT_EQ(pad_v1_node->description(), "Pad"); - EXPECT_EQ(pad_v1_node->get_version(), 1); + auto pad_v1_node = as_type_ptr(node); + ASSERT_TRUE(pad_v1_node); EXPECT_EQ(pad_v1_node->get_pad_mode(), pad_mode); EXPECT_EQ(pad_v1_node->get_pads_begin(), padding_below); @@ -58,10 +56,8 @@ TEST(opset_transform, opset1_pad_downgrade_pass) auto pad_s0_result = f->get_results().at(0); auto node = pad_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto pad_v0_node = static_pointer_cast(node); - - EXPECT_EQ(pad_v0_node->description(), "Pad"); - EXPECT_EQ(pad_v0_node->get_version(), 0); + auto pad_v0_node = as_type_ptr(node); + ASSERT_TRUE(pad_v0_node); EXPECT_EQ(pad_v0_node->get_pad_mode(), pad_mode); EXPECT_EQ(pad_v0_node->get_padding_below(), CoordinateDiff({1, 2})); diff --git a/test/opset_pass/poolings_opset_pass.cpp b/test/opset_pass/poolings_opset_pass.cpp index a47894f0d3f..cab4edc2377 100644 --- a/test/opset_pass/poolings_opset_pass.cpp +++ b/test/opset_pass/poolings_opset_pass.cpp @@ -11,7 +11,7 @@ using namespace std; using namespace ngraph; -TEST(opset_transform, opset1_avgpool_upgrade_pass) +TEST(opset_transform, opset1_avgpool_upgrade_pass_floor) { auto arg = make_shared(element::f32, Shape{1, 3, 6, 9}); Shape pads_begin{0, 0}; @@ -33,10 +33,8 @@ TEST(opset_transform, opset1_avgpool_upgrade_pass) auto avgpool_s1_result = f->get_results().at(0); auto node = avgpool_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto avg_pool_v1_node = static_pointer_cast(node); - - EXPECT_EQ(avg_pool_v1_node->description(), "AvgPool"); - EXPECT_EQ(avg_pool_v1_node->get_version(), 1); + auto avg_pool_v1_node = as_type_ptr(node); + ASSERT_TRUE(avg_pool_v1_node); EXPECT_EQ(avg_pool_v1_node->get_pads_begin(), pads_begin); EXPECT_EQ(avg_pool_v1_node->get_pads_end(), pads_end); @@ -47,7 +45,41 @@ TEST(opset_transform, opset1_avgpool_upgrade_pass) EXPECT_EQ(avg_pool_v1_node->get_auto_pad(), pad_mode); } -TEST(opset_transform, opset1_maxpool_upgrade_pass) +TEST(opset_transform, opset1_avgpool_upgrade_pass_ceil) +{ + auto arg = make_shared(element::f32, Shape{1, 3, 6, 9}); + Shape pads_begin{0, 0}; + Shape pads_end{0, 0}; + Strides strides{1, 1}; + Shape kernel_shape{3, 3}; + bool include_pad = true; + bool ceil_mode = true; + op::PadType pad_mode = op::PadType::EXPLICIT; + + auto avgpool_v0 = make_shared( + arg, kernel_shape, strides, pads_begin, pads_end, include_pad, pad_mode, ceil_mode); + auto result = make_shared(avgpool_v0); + auto f = make_shared(ResultVector{result}, ParameterVector{arg}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + auto avgpool_s1_result = f->get_results().at(0); + auto node = avgpool_s1_result->input(0).get_source_output().get_node_shared_ptr(); + auto avg_pool_v1_node = as_type_ptr(node); + ASSERT_TRUE(avg_pool_v1_node); + + EXPECT_EQ(avg_pool_v1_node->get_pads_begin(), pads_begin); + EXPECT_EQ(avg_pool_v1_node->get_pads_end(), pads_end); + EXPECT_EQ(avg_pool_v1_node->get_strides(), strides); + EXPECT_EQ(avg_pool_v1_node->get_kernel(), kernel_shape); + EXPECT_EQ(avg_pool_v1_node->get_rounding_type(), op::RoundingType::CEIL); + EXPECT_EQ(avg_pool_v1_node->get_exclude_pad(), !include_pad); + EXPECT_EQ(avg_pool_v1_node->get_auto_pad(), pad_mode); +} + +TEST(opset_transform, opset1_maxpool_upgrade_pass_fllor) { auto arg = make_shared(element::f32, Shape{1, 3, 6, 9}); Shape pads_begin{0, 0}; @@ -68,10 +100,8 @@ TEST(opset_transform, opset1_maxpool_upgrade_pass) auto maxpool_s1_result = f->get_results().at(0); auto node = maxpool_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto max_pool_v1_node = static_pointer_cast(node); - - EXPECT_EQ(max_pool_v1_node->description(), "MaxPool"); - EXPECT_EQ(max_pool_v1_node->get_version(), 1); + auto max_pool_v1_node = as_type_ptr(node); + ASSERT_TRUE(max_pool_v1_node); EXPECT_EQ(max_pool_v1_node->get_pads_begin(), pads_begin); EXPECT_EQ(max_pool_v1_node->get_pads_end(), pads_end); @@ -81,6 +111,38 @@ TEST(opset_transform, opset1_maxpool_upgrade_pass) EXPECT_EQ(max_pool_v1_node->get_auto_pad(), pad_mode); } +TEST(opset_transform, opset1_maxpool_upgrade_pass_ceil) +{ + auto arg = make_shared(element::f32, Shape{1, 3, 6, 9}); + Shape pads_begin{0, 0}; + Shape pads_end{0, 0}; + Strides strides{1, 1}; + Shape kernel_shape{3, 3}; + bool ceil_mode = true; + op::PadType pad_mode = op::PadType::EXPLICIT; + + auto maxpool_v0 = make_shared( + arg, kernel_shape, strides, pads_begin, pads_end, pad_mode, ceil_mode); + auto result = make_shared(maxpool_v0); + auto f = make_shared(ResultVector{result}, ParameterVector{arg}); + + ngraph::pass::Manager pass_manager; + pass_manager.register_pass(); + pass_manager.run_passes(f); + + auto maxpool_s1_result = f->get_results().at(0); + auto node = maxpool_s1_result->input(0).get_source_output().get_node_shared_ptr(); + auto max_pool_v1_node = as_type_ptr(node); + ASSERT_TRUE(max_pool_v1_node); + + EXPECT_EQ(max_pool_v1_node->get_pads_begin(), pads_begin); + EXPECT_EQ(max_pool_v1_node->get_pads_end(), pads_end); + EXPECT_EQ(max_pool_v1_node->get_strides(), strides); + EXPECT_EQ(max_pool_v1_node->get_kernel(), kernel_shape); + EXPECT_EQ(max_pool_v1_node->get_rounding_type(), op::RoundingType::CEIL); + EXPECT_EQ(max_pool_v1_node->get_auto_pad(), pad_mode); +} + TEST(opset_transform, opset1_avgpool_downgrade_pass) { auto arg = make_shared(element::f32, Shape{1, 3, 6, 9}); @@ -109,10 +171,8 @@ TEST(opset_transform, opset1_avgpool_downgrade_pass) auto avgpool_s0_result = f->get_results().at(0); auto node = avgpool_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto avg_pool_v0_node = static_pointer_cast(node); - - EXPECT_EQ(avg_pool_v0_node->description(), "AvgPool"); - EXPECT_EQ(avg_pool_v0_node->get_version(), 0); + auto avg_pool_v0_node = as_type_ptr(node); + ASSERT_TRUE(avg_pool_v0_node); EXPECT_EQ(avg_pool_v0_node->get_padding_below(), padding_below); EXPECT_EQ(avg_pool_v0_node->get_padding_above(), padding_above); @@ -149,10 +209,8 @@ TEST(opset_transform, opset1_maxpool_downgrade_pass) auto maxpool_s0_result = f->get_results().at(0); auto node = maxpool_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto max_pool_v0_node = static_pointer_cast(node); - - EXPECT_EQ(max_pool_v0_node->description(), "MaxPool"); - EXPECT_EQ(max_pool_v0_node->get_version(), 0); + auto max_pool_v0_node = as_type_ptr(node); + ASSERT_TRUE(max_pool_v0_node); EXPECT_EQ(max_pool_v0_node->get_padding_below(), padding_below); EXPECT_EQ(max_pool_v0_node->get_padding_above(), padding_above); @@ -189,10 +247,8 @@ TEST(opset_transform, opset1_avgpool_backprop_downgrade_pass) auto avgpool_backprop_s0_result = f->get_results().at(0); auto node = avgpool_backprop_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto avg_pool_backprop_v0_node = static_pointer_cast(node); - - EXPECT_EQ(avg_pool_backprop_v0_node->description(), "AvgPoolBackprop"); - EXPECT_EQ(avg_pool_backprop_v0_node->get_version(), 0); + auto avg_pool_backprop_v0_node = as_type_ptr(node); + ASSERT_TRUE(avg_pool_backprop_v0_node); EXPECT_EQ(avg_pool_backprop_v0_node->get_padding_below(), padding_below); EXPECT_EQ(avg_pool_backprop_v0_node->get_padding_above(), padding_above); @@ -229,10 +285,8 @@ TEST(opset_transform, opset1_maxpool_backprop_downgrade_pass) auto max_pool_backprop_s0_result = f->get_results().at(0); auto node = max_pool_backprop_s0_result->input(0).get_source_output().get_node_shared_ptr(); - auto max_pool_backprop_v0_node = static_pointer_cast(node); - - EXPECT_EQ(max_pool_backprop_v0_node->description(), "MaxPoolBackprop"); - EXPECT_EQ(max_pool_backprop_v0_node->get_version(), 0); + auto max_pool_backprop_v0_node = as_type_ptr(node); + ASSERT_TRUE(max_pool_backprop_v0_node); EXPECT_EQ(max_pool_backprop_v0_node->get_padding_below(), padding_below); EXPECT_EQ(max_pool_backprop_v0_node->get_padding_above(), padding_above); EXPECT_EQ(max_pool_backprop_v0_node->get_window_movement_strides(), window_movement_strides); diff --git a/test/opset_pass/product_opset_pass.cpp b/test/opset_pass/product_opset_pass.cpp index 1ee354d00ea..e3746e76946 100644 --- a/test/opset_pass/product_opset_pass.cpp +++ b/test/opset_pass/product_opset_pass.cpp @@ -41,10 +41,8 @@ TEST(opset_transform, opset1_product_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reduce_prod_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(reduce_prod_v1->description(), "Product"); - EXPECT_EQ(reduce_prod_v1->get_version(), 1); + const auto reduce_prod_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(reduce_prod_v1); EXPECT_EQ(reduce_prod_v1->get_keep_dims(), false); } @@ -63,15 +61,12 @@ TEST(opset_transform, opset0_reduce_prod_downgrade_pass) const auto reshape_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reshape = static_pointer_cast(reshape_replacement_node); + const auto reshape = as_type_ptr(reshape_replacement_node); + ASSERT_TRUE(reshape); const auto product_replace_node = reshape_replacement_node->input(0).get_source_output().get_node_shared_ptr(); - const auto product_v0 = static_pointer_cast(product_replace_node); - - EXPECT_EQ(reshape->description(), "Reshape"); - EXPECT_EQ(reshape->get_version(), 0); - EXPECT_EQ(product_v0->description(), "Product"); - EXPECT_EQ(product_v0->get_version(), 0); + const auto product_v0 = as_type_ptr(product_replace_node); + ASSERT_TRUE(product_v0); } TEST(opset_transform, opset0_reduce_prod_downgrade_pass_axes_not_constant) diff --git a/test/opset_pass/reverse_opset_pass.cpp b/test/opset_pass/reverse_opset_pass.cpp index 73ba423b5d5..27ba843a58c 100644 --- a/test/opset_pass/reverse_opset_pass.cpp +++ b/test/opset_pass/reverse_opset_pass.cpp @@ -41,11 +41,9 @@ TEST(opset_transform, opset1_reverse_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reverse_v1 = static_pointer_cast(pass_replacement_node); - + const auto reverse_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(reverse_v1); EXPECT_EQ(reverse_v1->get_mode(), op::v1::Reverse::Mode::INDEX); - EXPECT_EQ(reverse_v1->description(), "Reverse"); - EXPECT_EQ(reverse_v1->get_version(), 1); const auto& rev_axes_input_shape = reverse_v1->get_input_shape(1); // should match the number of elements of v0::Reverse reverse_axes attribute @@ -69,10 +67,8 @@ TEST(opset_transform, opset0_reverse_downgrade_pass_index_mode) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reverse_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(reverse_v0->description(), "Reverse"); - EXPECT_EQ(reverse_v0->get_version(), 0); + const auto reverse_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(reverse_v0); EXPECT_EQ(reverse_v0->get_reversed_axes(), AxisSet({1, 2})); } @@ -93,10 +89,8 @@ TEST(opset_transform, opset0_reverse_downgrade_pass_mask_mode) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reverse_v0 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(reverse_v0->description(), "Reverse"); - EXPECT_EQ(reverse_v0->get_version(), 0); + const auto reverse_v0 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(reverse_v0); EXPECT_EQ(reverse_v0->get_reversed_axes(), AxisSet({0, 2})); } diff --git a/test/opset_pass/slice_opset_pass.cpp b/test/opset_pass/slice_opset_pass.cpp index 1ffb586c2a6..36b9e38ebce 100644 --- a/test/opset_pass/slice_opset_pass.cpp +++ b/test/opset_pass/slice_opset_pass.cpp @@ -45,16 +45,17 @@ TEST(opset_transform, opset1_dyn_slice_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); const auto strided_slice_v1 = as_type_ptr(pass_replacement_node); - + ASSERT_TRUE(strided_slice_v1); auto begin_const = as_type_ptr(strided_slice_v1->input_value(1).get_node_shared_ptr()); + ASSERT_TRUE(begin_const); auto end_const = as_type_ptr(strided_slice_v1->input_value(2).get_node_shared_ptr()); + ASSERT_TRUE(end_const); auto strides_const = as_type_ptr(strided_slice_v1->input_value(3).get_node_shared_ptr()); + ASSERT_TRUE(strides_const); - EXPECT_EQ(strided_slice_v1->description(), "Slice"); - EXPECT_EQ(strided_slice_v1->get_version(), 1); EXPECT_EQ(strided_slice_v1->get_begin_mask(), vector(4, 0)); EXPECT_EQ(strided_slice_v1->get_end_mask(), vector(4, 0)); EXPECT_EQ(begin_const->get_vector(), @@ -84,9 +85,7 @@ TEST(opset_transform, opset1_strided_slice_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); const auto slice_v0 = as_type_ptr(pass_replacement_node); - - EXPECT_EQ(slice_v0->description(), "Slice"); - EXPECT_EQ(slice_v0->get_version(), 0); + ASSERT_TRUE(slice_v0); EXPECT_EQ(slice_v0->get_lower_bounds(), Coordinate({1, 2, 0, 2})); EXPECT_EQ(slice_v0->get_upper_bounds(), Coordinate({5, 4, 5, 6})); EXPECT_EQ(slice_v0->get_strides(), Strides({1, 1, 1, 1})); diff --git a/test/opset_pass/softmax_opset_pass.cpp b/test/opset_pass/softmax_opset_pass.cpp index 991e28df8cd..24c67beb050 100644 --- a/test/opset_pass/softmax_opset_pass.cpp +++ b/test/opset_pass/softmax_opset_pass.cpp @@ -40,11 +40,9 @@ TEST(opset_transform, opset1_softmax_upgrade_pass_axis) auto softmax_s1_result = f->get_results().at(0); auto node = softmax_s1_result->input(0).get_source_output().get_node_shared_ptr(); - auto softmax_s1_node = static_pointer_cast(node); - + auto softmax_s1_node = as_type_ptr(node); + ASSERT_TRUE(softmax_s1_node); EXPECT_EQ(softmax_s1_node->get_axis(), axis); - EXPECT_EQ(softmax_s1_node->description(), "Softmax"); - EXPECT_EQ(softmax_s1_node->get_version(), 1); } TEST(opset_transform, opset1_softmax_upgrade_pass_axis_exception) @@ -75,43 +73,3 @@ TEST(opset_transform, opset1_softmax_upgrade_pass_axis_exception) FAIL() << "Softmax pass failed for unexpected reason"; } } - -namespace fake_v2 -{ - class FakeSoftmax : public op::v0::Softmax - { - public: - FakeSoftmax(const Output& arg, const AxisSet& axes) - : Softmax{arg, axes} - { - } - size_t get_version() const override { return 2; } - }; -} - -TEST(opset_transform, opset1_softmax_upgrade_pass_incorrect_op_version) -{ - const AxisSet axes{2}; - auto arg = make_shared(element::f32, Shape{2, 3, 4}); - auto softmax_s2 = make_shared(arg, axes); - auto result = make_shared(softmax_s2); - auto f = make_shared(ResultVector{result}, ParameterVector{arg}); - - ngraph::pass::Manager pass_manager; - pass_manager.register_pass(); - - try - { - pass_manager.run_passes(f); - FAIL() << "Opset 1 transformation pass failed for"; - } - catch (const ngraph_error& error) - { - EXPECT_HAS_SUBSTRING(error.what(), - std::string("Op version 1 transformation pass failed for")); - } - catch (...) - { - FAIL() << "Softmax pass failed for unexpected reason"; - } -} diff --git a/test/opset_pass/sum_opset_pass.cpp b/test/opset_pass/sum_opset_pass.cpp index 1d236ef30e6..1440042a2a0 100644 --- a/test/opset_pass/sum_opset_pass.cpp +++ b/test/opset_pass/sum_opset_pass.cpp @@ -41,10 +41,8 @@ TEST(opset_transform, opset1_reduce_sum_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reduce_sum_v1 = static_pointer_cast(pass_replacement_node); - - EXPECT_EQ(reduce_sum_v1->description(), "Sum"); - EXPECT_EQ(reduce_sum_v1->get_version(), 1); + const auto reduce_sum_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(reduce_sum_v1); EXPECT_EQ(reduce_sum_v1->get_keep_dims(), false); } @@ -63,15 +61,12 @@ TEST(opset_transform, opset0_reduce_sum_downgrade_pass) const auto reshape_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto reshape = static_pointer_cast(reshape_replacement_node); + const auto reshape = as_type_ptr(reshape_replacement_node); + ASSERT_TRUE(reshape); const auto sum_replace_node = reshape_replacement_node->input(0).get_source_output().get_node_shared_ptr(); - const auto sum_v0 = static_pointer_cast(sum_replace_node); - - EXPECT_EQ(reshape->description(), "Reshape"); - EXPECT_EQ(reshape->get_version(), 0); - EXPECT_EQ(sum_v0->description(), "Sum"); - EXPECT_EQ(sum_v0->get_version(), 0); + const auto sum_v0 = as_type_ptr(sum_replace_node); + ASSERT_TRUE(sum_v0); } TEST(opset_transform, opset0_reduce_sum_downgrade_pass_not_constant_axes) diff --git a/test/opset_pass/topk_opset_pass.cpp b/test/opset_pass/topk_opset_pass.cpp index e527be4ab3b..f7f424a4f67 100644 --- a/test/opset_pass/topk_opset_pass.cpp +++ b/test/opset_pass/topk_opset_pass.cpp @@ -41,11 +41,9 @@ TEST(opset_transform, opset1_topk_upgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); - const auto topk_v1 = static_pointer_cast(pass_replacement_node); - + const auto topk_v1 = as_type_ptr(pass_replacement_node); + ASSERT_TRUE(topk_v1); EXPECT_EQ(topk_v1->get_axis(), axis); - EXPECT_EQ(topk_v1->description(), "TopK"); - EXPECT_EQ(topk_v1->get_version(), 1); EXPECT_EQ(topk_v1->get_mode(), op::v1::TopK::Mode::MAX); EXPECT_EQ(topk_v1->get_sort_type(), op::v1::TopK::SortType::SORT_VALUES); @@ -74,9 +72,7 @@ TEST(opset_transform, opset1_topk_downgrade_pass) const auto pass_replacement_node = f->get_result()->input(0).get_source_output().get_node_shared_ptr(); const auto topk_v0 = as_type_ptr(pass_replacement_node); - - EXPECT_EQ(topk_v0->description(), "TopK"); - EXPECT_EQ(topk_v0->get_version(), 0); + ASSERT_TRUE(topk_v0); EXPECT_EQ(topk_v0->get_k(), k); EXPECT_EQ(topk_v0->get_top_k_axis(), axis); EXPECT_EQ(topk_v0->get_compute_max(), true); diff --git a/test/pattern.cpp b/test/pattern.cpp index f43ecaf432b..9915c5b9391 100644 --- a/test/pattern.cpp +++ b/test/pattern.cpp @@ -144,8 +144,8 @@ class TestGraphRewrite : public ngraph::pass::GraphRewrite size_t const_node_index = m.get_match_root()->get_arguments().at(0) == pattern_map[pattern]; - auto const_node = static_pointer_cast( - m.get_match_root()->get_arguments().at(const_node_index)); + auto const_node = + as_type_ptr(m.get_match_root()->get_arguments().at(const_node_index)); auto second_node = m.get_match_root()->get_arguments().at(const_node_index); NGRAPH_DEBUG << "second_node = " << second_node->get_name() << " , pattern = " << pattern_map[pattern]->get_name(); diff --git a/test/serialize.cpp b/test/serialize.cpp index 62b0d4649e6..8a274d9e47d 100644 --- a/test/serialize.cpp +++ b/test/serialize.cpp @@ -288,25 +288,25 @@ TEST(serialize, constant_infinity_nan) { if (node->get_friendly_name() == "A") { - a = static_pointer_cast(node); + a = as_type_ptr(node); } else if (node->get_friendly_name() == "B") { - b = static_pointer_cast(node); + b = as_type_ptr(node); } else if (node->get_friendly_name() == "C") { - c = static_pointer_cast(node); + c = as_type_ptr(node); } else if (node->get_friendly_name() == "D") { - d = static_pointer_cast(node); + d = as_type_ptr(node); } } - ASSERT_NE(a, nullptr); - ASSERT_NE(b, nullptr); - ASSERT_NE(c, nullptr); - ASSERT_NE(d, nullptr); + ASSERT_TRUE(a); + ASSERT_TRUE(b); + ASSERT_TRUE(c); + ASSERT_TRUE(d); EXPECT_TRUE(test::all_close_f(a->get_vector(), a_data)); EXPECT_TRUE(test::all_close_f(b->get_vector(), b_data)); EXPECT_TRUE(test::all_close_f(c->get_vector(), c_data)); @@ -335,10 +335,10 @@ TEST(serialize, non_zero_node_output) string s = serialize(f); shared_ptr g = deserialize(s); auto g_result = g->get_results().at(0); - auto g_abs = g_result->input(0).get_source_output().get_node_shared_ptr(); - auto topk_out = g_abs->input(0).get_source_output(); + auto g_abs = g_result->input_value(0).get_node_shared_ptr(); + auto topk_out = g_abs->input_value(0); EXPECT_EQ(topk_out.get_index(), 1); - EXPECT_EQ(topk_out.get_node()->description(), "TopK"); + ASSERT_TRUE(is_type(topk_out.get_node())); } TEST(serialize, opset1_softmax) @@ -352,9 +352,7 @@ TEST(serialize, opset1_softmax) shared_ptr g = deserialize(s); const auto g_result = g->get_results().at(0); const auto g_softmax = g_result->input(0).get_source_output().get_node_shared_ptr(); - - EXPECT_EQ(g_softmax->description(), "Softmax"); - EXPECT_EQ(g_softmax->get_version(), 1); + EXPECT_TRUE(is_type(g_softmax)); } TEST(serialize, opset1_gather) @@ -371,9 +369,7 @@ TEST(serialize, opset1_gather) shared_ptr g = deserialize(s); auto g_result = g->get_results().at(0); auto g_gather = g_result->input(0).get_source_output().get_node_shared_ptr(); - - EXPECT_EQ(g_gather->description(), "Gather"); - EXPECT_EQ(g_gather->get_version(), 1); + EXPECT_TRUE(is_type(g_gather)); } TEST(serialize, opset1_product) @@ -389,12 +385,10 @@ TEST(serialize, opset1_product) shared_ptr g = deserialize(s); auto g_result = g->get_results().at(0); auto g_red_prod = g_result->input(0).get_source_output().get_node_shared_ptr(); - - EXPECT_EQ(g_red_prod->description(), "Product"); - EXPECT_EQ(g_red_prod->get_version(), 1); - EXPECT_EQ(dynamic_cast(g_red_prod.get())->get_keep_dims(), 1); - EXPECT_EQ(dynamic_cast(g_red_prod.get())->get_reduction_axes(), - AxisSet({1, 2})); + auto node = as_type_ptr(g_red_prod); + EXPECT_TRUE(node); + EXPECT_EQ(node->get_keep_dims(), 1); + EXPECT_EQ(node->get_reduction_axes(), AxisSet({1, 2})); } TEST(serialize, opset1_sum) @@ -410,12 +404,10 @@ TEST(serialize, opset1_sum) shared_ptr g = deserialize(s); auto g_result = g->get_results().at(0); auto g_red_sum = g_result->input(0).get_source_output().get_node_shared_ptr(); - - EXPECT_EQ(g_red_sum->description(), "Sum"); - EXPECT_EQ(g_red_sum->get_version(), 1); - EXPECT_EQ(dynamic_cast(g_red_sum.get())->get_keep_dims(), 1); - EXPECT_EQ(dynamic_cast(g_red_sum.get())->get_reduction_axes(), - AxisSet({1, 2})); + auto node = as_type_ptr(g_red_sum); + EXPECT_TRUE(node); + EXPECT_EQ(node->get_keep_dims(), 1); + EXPECT_EQ(node->get_reduction_axes(), AxisSet({1, 2})); } TEST(serialize, opset1_pad) @@ -434,11 +426,9 @@ TEST(serialize, opset1_pad) shared_ptr g = deserialize(s); auto g_result = g->get_results().at(0); - auto g_pad = g_result->input(0).get_source_output().get_node_shared_ptr(); - - EXPECT_EQ(g_pad->description(), "Pad"); - EXPECT_EQ(g_pad->get_version(), 1); - EXPECT_EQ(dynamic_cast(g_pad.get())->get_pad_mode(), pad_mode); + auto g_pad = as_type_ptr(g_result->input_value(0).get_node_shared_ptr()); + ASSERT_TRUE(g_pad); + EXPECT_EQ(g_pad->get_pad_mode(), pad_mode); } TEST(serialize, tensor_iterator_raw) @@ -486,8 +476,8 @@ TEST(serialize, tensor_iterator_raw) auto tensor_iterator = make_shared(); tensor_iterator->set_body(body); // The Xi are the elements of Xseq - // start=0, stride=1, part_size=1, end=40, axis=1 - tensor_iterator->set_sliced_input(Xi, X, 0, 1, 1, 40, 1); + // start=0, stride=1, part_size=1, end=39, axis=1 + tensor_iterator->set_sliced_input(Xi, X, 0, 1, 1, 39, 1); // Hi is Hinit on the first iteration, Ho after that tensor_iterator->set_merged_input(Hi, Hinit, Ho); tensor_iterator->set_invariant_input(WH_body, WH); @@ -499,8 +489,8 @@ TEST(serialize, tensor_iterator_raw) // Output 0 is last Yo auto out0 = tensor_iterator->get_iter_value(Yo, -1); // Output 1 is concat of hidden states - // start=0, stride=1, part_size=1, end=40, axis=1 - auto out1 = tensor_iterator->get_concatenated_slices(Ho, 0, 1, 1, 40, 1); + // start=0, stride=1, part_size=1, end=39, axis=1 + auto out1 = tensor_iterator->get_concatenated_slices(Ho, 0, 1, 1, 39, 1); auto results = ResultVector{make_shared(out0), make_shared(out1)}; auto f = make_shared(results, ParameterVector{X, Hinit, WH, WX, bH, WY, bY}); @@ -543,7 +533,7 @@ TEST(serialize, tensor_iterator_lstm) auto tensor_iterator = make_shared(); tensor_iterator->set_body(body); - // start=0, stride=1, part_size=1, end=40, axis=1 + // start=0, stride=1, part_size=1, end=39, axis=1 tensor_iterator->set_sliced_input(X, SENT, 0, 1, 1, -1, 1); // H_t is Hinit on the first iteration, Ho after that tensor_iterator->set_merged_input(H_t, H_init, H_o); @@ -583,8 +573,8 @@ TEST(serialize, tensor_iterator_2_slice_inputs_part_size_2) auto tensor_iterator = make_shared(); tensor_iterator->set_body(body); // The Xi are the elements of Xseq - // start=0, stride=2, part_size=2, end=20, axis=1 - tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 20, 1); + // start=0, stride=2, part_size=2, end=39, axis=1 + tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 39, 1); // The Yi are the elements of Yseq // start=0, stride=2, part_size=2, end=-1, axis=1 tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -1, 1); @@ -593,8 +583,8 @@ TEST(serialize, tensor_iterator_2_slice_inputs_part_size_2) // Output 0 is last Zo auto out0 = tensor_iterator->get_iter_value(Zo, -1); // Output 1 is concat of Zos - // start=0, stride=2, part_size=2, end=20, axis=1 - auto out1 = tensor_iterator->get_concatenated_slices(Zo, 0, 2, 2, 20, 1); + // start=0, stride=2, part_size=2, end=39, axis=1 + auto out1 = tensor_iterator->get_concatenated_slices(Zo, 0, 2, 2, 39, 1); auto result0 = make_shared(out0); auto result1 = make_shared(out1); @@ -631,23 +621,62 @@ TEST(serialize, tensor_iterator_2_slice_inputs_part_size_2_dynamic) auto tensor_iterator = make_shared(); tensor_iterator->set_body(body); // The Xi are the elements of Xseq - // start=0, stride=2, part_size=2, end=20, axis=1 - tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 20, 1); + // start=0, stride=2, part_size=2, end=38, axis=1 + tensor_iterator->set_sliced_input(Xi, X, 0, 2, 2, 38, 1); // The Yi are the elements of Yseq - // start=0, stride=2, part_size=2, end=-1, axis=1 - tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -1, 1); + // start=0, stride=2, part_size=2, end=-2, axis=1 + tensor_iterator->set_sliced_input(Yi, Y, 0, 2, 2, -2, 1); tensor_iterator->set_invariant_input(M_body, M); + // check input descriptors + for (auto& desc : tensor_iterator->get_input_descriptions()) + { + auto type_info = desc->get_type_info(); + if (std::strcmp(type_info.name, "InvariantInputDescription") == 0) + { + auto input_desc = + as_type_ptr(desc); + EXPECT_NE(input_desc, nullptr); + } + else if (std::strcmp(type_info.name, "SliceInputDescription") == 0) + { + auto input_desc = as_type_ptr(desc); + EXPECT_NE(input_desc, nullptr); + } + else if (std::strcmp(type_info.name, "MergedInputDescription") == 0) + { + auto input_desc = as_type_ptr(desc); + EXPECT_NE(input_desc, nullptr); + } + } + // Output 0 is last Zo auto out0 = tensor_iterator->get_iter_value(Zo, -1); // Output 1 is concat of Zos - // start=0, stride=2, part_size=2, end=20, axis=1 - auto out1 = tensor_iterator->get_concatenated_slices(Zo, 0, 2, 2, 20, 1); + // start=0, stride=2, part_size=2, end=38, axis=1 + auto out1 = tensor_iterator->get_concatenated_slices(Zo, 0, 2, 2, 38, 1); + + // check output descriptors + for (auto& desc : tensor_iterator->get_output_descriptions()) + { + auto type_info = desc->get_type_info(); + if (std::strcmp(type_info.name, "ConcatOutputDescription") == 0) + { + auto output_desc = + as_type_ptr(desc); + EXPECT_NE(output_desc, nullptr); + } + else if (std::strcmp(type_info.name, "BodyOutputDescription") == 0) + { + auto output_desc = as_type_ptr(desc); + EXPECT_NE(output_desc, nullptr); + } + } auto result0 = make_shared(out0); auto result1 = make_shared(out1); Shape out0_shape{32, 2, 10}; - Shape out1_shape{32, 40, 10}; + Shape out1_shape{32, 38, 10}; auto results = ResultVector{result0, result1}; auto f = make_shared(results, ParameterVector{X, Y, M}); @@ -693,8 +722,7 @@ TEST(serialize, opset1_strided_slice) auto g_strided_slice_v1 = g_result->input(0).get_source_output().get_node_shared_ptr(); auto strided_slice_out = as_type_ptr(g_strided_slice_v1); - EXPECT_EQ(strided_slice_out->description(), "Slice"); - EXPECT_EQ(strided_slice_out->get_version(), 1); + ASSERT_TRUE(strided_slice_out); EXPECT_EQ(strided_slice_out->get_begin_mask(), begin_mask); EXPECT_EQ(strided_slice_out->get_end_mask(), end_mask); EXPECT_EQ(strided_slice_out->get_new_axis_mask(), new_axis_mask); @@ -725,9 +753,7 @@ TEST(serialize, opset1_binary_convolution) auto g_result = g->get_results().at(0); auto g_binary_conv = g_result->input(0).get_source_output().get_node_shared_ptr(); auto binary_conv_out = as_type_ptr(g_binary_conv); - - EXPECT_EQ(binary_conv_out->description(), "BinaryConvolution"); - EXPECT_EQ(binary_conv_out->get_version(), 1); + ASSERT_TRUE(binary_conv_out); EXPECT_EQ(binary_conv_out->get_strides(), strides); EXPECT_EQ(binary_conv_out->get_pads_begin(), pads_begin); @@ -754,9 +780,75 @@ TEST(serialize, depth_to_space) auto g_result = g->get_results().at(0); auto g_depth_to_space = g_result->input(0).get_source_output().get_node_shared_ptr(); auto depth_to_space_out = as_type_ptr(g_depth_to_space); + ASSERT_TRUE(depth_to_space_out); + EXPECT_EQ(depth_to_space_out->get_block_size(), block_size); + EXPECT_EQ(depth_to_space_out->get_mode(), mode); +} - EXPECT_EQ(depth_to_space_out->description(), "DepthToSpace"); - EXPECT_EQ(depth_to_space_out->get_version(), 0); +TEST(serialize, space_to_depth) +{ + auto arg = make_shared(element::f32, Shape{4, 6, 8}); + auto mode = op::SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST; + size_t block_size = 2; + auto space_to_depth_in = make_shared(arg, mode, block_size); + + auto result = make_shared(space_to_depth_in); + auto f = make_shared(ResultVector{result}, ParameterVector{arg}); + string s = serialize(f); + + shared_ptr g = deserialize(s); + auto g_result = g->get_results().at(0); + auto g_space_to_depth = g_result->input(0).get_source_output().get_node_shared_ptr(); + auto depth_to_space_out = as_type_ptr(g_space_to_depth); + ASSERT_TRUE(depth_to_space_out); EXPECT_EQ(depth_to_space_out->get_block_size(), block_size); EXPECT_EQ(depth_to_space_out->get_mode(), mode); } + +TEST(serialize, deformable_psroi_pooling) +{ + auto input = make_shared(element::f32, Shape{1, 2, 3, 4}); + auto coords = make_shared(element::f32, Shape{1, 1}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4}); + const int64_t output_dim = 1; + const int64_t group_size = 2; + const float spatial_scale = 3; + std::string mode = "bilinear_deformable"; + int64_t spatial_bins_x = 4; + int64_t spatial_bins_y = 5; + float trans_std = 6.1f; + int64_t part_size = 7; + + auto def_psroi_pool_in = make_shared(input, + coords, + offsets, + output_dim, + spatial_scale, + group_size, + mode, + spatial_bins_x, + spatial_bins_y, + trans_std, + part_size); + + auto result = make_shared(def_psroi_pool_in); + auto f = make_shared(ResultVector{result}, ParameterVector{input, coords, offsets}); + string s = serialize(f); + + shared_ptr g = deserialize(s); + auto g_result = g->get_results().at(0); + auto g_def_psroi_pool = g_result->input(0).get_source_output().get_node_shared_ptr(); + auto def_psroi_pool_out = as_type_ptr(g_def_psroi_pool); + + EXPECT_EQ(def_psroi_pool_out->description(), "DeformablePSROIPooling"); + EXPECT_EQ(def_psroi_pool_out->get_version(), 1); + + EXPECT_EQ(def_psroi_pool_out->get_output_dim(), output_dim); + EXPECT_EQ(def_psroi_pool_out->get_group_size(), group_size); + EXPECT_EQ(def_psroi_pool_out->get_spatial_scale(), spatial_scale); + EXPECT_EQ(def_psroi_pool_out->get_mode(), mode); + EXPECT_EQ(def_psroi_pool_out->get_spatial_bins_x(), spatial_bins_x); + EXPECT_EQ(def_psroi_pool_out->get_spatial_bins_y(), spatial_bins_y); + EXPECT_EQ(def_psroi_pool_out->get_trans_std(), trans_std); + EXPECT_EQ(def_psroi_pool_out->get_part_size(), part_size); +} diff --git a/test/type_prop/batch_mat_mul_transpose.cpp b/test/type_prop/batch_mat_mul_transpose.cpp new file mode 100644 index 00000000000..2e8300a3385 --- /dev/null +++ b/test/type_prop/batch_mat_mul_transpose.cpp @@ -0,0 +1,212 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, batchmatmultranspose_deduce_3d) +{ + // Deduce type for matrix/matrix arguments + auto param1 = make_shared(element::f32, Shape{5, 4, 2}); + auto param2 = make_shared(element::f32, Shape{5, 2, 3}); + auto bc = make_shared(param1, param2); + ASSERT_EQ(bc->get_element_type(), element::f32); + ASSERT_EQ(bc->get_shape(), (Shape{5, 4, 3})); +} + +TEST(type_prop, batchmatmultranspose_deduce_3d_transpose0) +{ + // Deduce type for matrix/matrix arguments + auto param1 = make_shared(element::f32, Shape{5, 2, 4}); + auto param2 = make_shared(element::f32, Shape{5, 2, 3}); + auto bc = make_shared(param1, param2, true, false); + ASSERT_EQ(bc->get_element_type(), element::f32); + ASSERT_EQ(bc->get_shape(), (Shape{5, 4, 3})); +} + +TEST(type_prop, batchmatmultranspose_deduce_3d_transpose1) +{ + // Deduce type for matrix/matrix arguments + auto param1 = make_shared(element::f32, Shape{5, 4, 2}); + auto param2 = make_shared(element::f32, Shape{5, 3, 2}); + auto bc = make_shared(param1, param2, false, true); + ASSERT_EQ(bc->get_element_type(), element::f32); + ASSERT_EQ(bc->get_shape(), (Shape{5, 4, 3})); +} + +TEST(type_prop, batchmatmultranspose_deduce_3d_transpose_both) +{ + // Deduce type for matrix/matrix arguments + auto param1 = make_shared(element::f32, Shape{5, 2, 4}); + auto param2 = make_shared(element::f32, Shape{5, 3, 2}); + auto bc = make_shared(param1, param2, true, true); + ASSERT_EQ(bc->get_element_type(), element::f32); + ASSERT_EQ(bc->get_shape(), (Shape{5, 4, 3})); +} + +TEST(type_prop, batchmatmultranspose_deduce_left_rank_wrong) +{ + // Type deduction fails due to element type mismatch + auto param1 = make_shared(element::f32, Shape{2, 5, 4, 2}); + auto param2 = make_shared(element::f32, Shape{5, 2, 5}); + try + { + auto bc = make_shared(param1, param2); + // Should have thrown, so fail if it didn't + FAIL() << "Element type mismatch not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("shape must have rank 3")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, batchmatmultranspose_deduce_right_rank_wrong) +{ + // Type deduction fails due to element type mismatch + auto param1 = make_shared(element::f32, Shape{5, 4, 2}); + auto param2 = make_shared(element::f32, Shape{2, 5, 2, 5}); + try + { + auto bc = make_shared(param1, param2); + // Should have thrown, so fail if it didn't + FAIL() << "Element type mismatch not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("shape must have rank 3")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, batchmatmultranspose_deduce_element_type_mismatch) +{ + // Type deduction fails due to element type mismatch + auto param1 = make_shared(element::f32, Shape{5, 4, 2}); + auto param2 = make_shared(element::i32, Shape{5, 2, 5}); + try + { + auto bc = make_shared(param1, param2); + // Should have thrown, so fail if it didn't + FAIL() << "Element type mismatch not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("compatible element type")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, batchmatmultranspose_deduce_reduction_axes_size_mismatch) +{ + // Type deduction fails due to reduction axes size mismatch + auto param1 = make_shared(element::f32, Shape{6, 4, 2}); + auto param2 = make_shared(element::f32, Shape{6, 3, 5}); + try + { + auto bc = make_shared(param1, param2); + // Should have thrown, so fail if it didn't + FAIL() << "BatchMatMulTranspose reduction axes size mismatch not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("Product dimensions are not equal")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, batchmatmultranspose_partial_both_rank_dynamic_implicit) +{ + auto param0 = make_shared(element::f32, PartialShape::dynamic()); + auto param1 = make_shared(element::f32, PartialShape::dynamic()); + auto d = make_shared(param0, param1); + + ASSERT_TRUE(d->get_output_partial_shape(0).rank().same_scheme(3)); +} + +TEST(type_prop, batchmatmultranspose_partial_left_rank_dynamic_right_rank_static_dynamic) +{ + auto param0 = make_shared(element::f32, PartialShape::dynamic()); + auto param1 = + make_shared(element::f32, PartialShape{Dimension::dynamic(), 2, 3}); + auto d = make_shared(param0, param1); + + ASSERT_TRUE(d->get_output_partial_shape(0).rank().same_scheme(3)); +} + +TEST(type_prop, batchmatmultranspose_partial_left_rank_static_dynamic_right_rank_dynamic) +{ + auto param0 = + make_shared(element::f32, PartialShape{Dimension::dynamic(), 2, 3}); + auto param1 = make_shared(element::f32, PartialShape::dynamic()); + auto d = make_shared(param0, param1); + + ASSERT_TRUE(d->get_output_partial_shape(0).rank().same_scheme(3)); +} + +TEST(type_prop, batchmatmultranspose_partial_left_rank_static_dynamic_right_rank_static) +{ + auto param0 = + make_shared(element::f32, PartialShape{Dimension::dynamic(), 2, 4}); + auto param1 = make_shared(element::f32, PartialShape{3, 4, 5}); + auto d = make_shared(param0, param1); + + ASSERT_TRUE(d->get_output_partial_shape(0).same_scheme(PartialShape{3, 2, 5})); +} + +TEST(type_prop, batchmatmultranspose_partial_left_et_dynamic) +{ + auto param0 = make_shared(element::dynamic, PartialShape::dynamic()); + auto param1 = make_shared(element::f32, PartialShape::dynamic()); + auto d = make_shared(param0, param1); + + ASSERT_EQ(d->get_output_element_type(0), element::f32); +} + +TEST(type_prop, batchmatmultranspose_partial_right_et_dynamic) +{ + auto param0 = make_shared(element::i32, PartialShape::dynamic()); + auto param1 = make_shared(element::dynamic, PartialShape::dynamic()); + auto d = make_shared(param0, param1); + + ASSERT_EQ(d->get_output_element_type(0), element::i32); +} + +TEST(type_prop, batchmatmultranspose_partial_both_et_dynamic) +{ + auto param0 = make_shared(element::dynamic, PartialShape::dynamic()); + auto param1 = make_shared(element::dynamic, PartialShape::dynamic()); + auto d = make_shared(param0, param1); + + ASSERT_EQ(d->get_output_element_type(0), element::dynamic); +} diff --git a/test/type_prop/convolution.cpp b/test/type_prop/convolution.cpp index 54dc9ce32b0..f38e6efa808 100644 --- a/test/type_prop/convolution.cpp +++ b/test/type_prop/convolution.cpp @@ -2836,7 +2836,29 @@ TEST(type_prop, conv_bprop_data_v1_output_partial_shape_dynamic) auto padding_end = CoordinateDiff{0, 0}; auto conv1 = make_shared( - filters, deltas, data_batch_shape, strides, dilations, padding_begin, padding_end); + deltas, filters, data_batch_shape, strides, padding_begin, padding_end, dilations); ASSERT_TRUE(conv1->get_output_partial_shape(0).is_dynamic()); } + +TEST(type_prop, conv_v1_partial_rank) +{ + PartialShape data_batch_shape{PartialShape::dynamic()}; + PartialShape filters_shape{PartialShape::dynamic()}; + Strides window_movement_strides{1, 1}; + Strides window_dilation_strides{1, 1}; + CoordinateDiff padding_below{0, 0}; + CoordinateDiff padding_above{0, 0}; + + auto param0 = make_shared(element::f32, data_batch_shape); + auto param1 = make_shared(element::f32, filters_shape); + + auto conv = make_shared(param0, + param1, + window_movement_strides, + padding_below, + padding_above, + window_dilation_strides); + + ASSERT_TRUE(conv->get_output_partial_shape(0).is_dynamic()); +} diff --git a/test/type_prop/crop_and_resize.cpp b/test/type_prop/crop_and_resize.cpp new file mode 100644 index 00000000000..1a7875917e2 --- /dev/null +++ b/test/type_prop/crop_and_resize.cpp @@ -0,0 +1,81 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, crop_and_resize_valid) +{ + Dimension N = 4; + Dimension W_image = 400; + Dimension H_image = 300; + Dimension C_image = 3; + Dimension num_boxes = 20; + int32_t W_crop = 30; + int32_t H_crop = 40; + + PartialShape result_shape{num_boxes, H_crop, W_crop, C_image}; + + auto image = + make_shared(element::f32, PartialShape{N, H_image, W_image, C_image}); + auto boxes = make_shared(element::f32, PartialShape{num_boxes, 4}); + auto box_indices = make_shared(element::i32, PartialShape{num_boxes}); + auto crop_shape = op::Constant::create(element::i32, Shape{2}, {H_crop, W_crop}); + + auto crop_and_resize = make_shared( + image, boxes, box_indices, crop_shape, op::CropAndResize::ResizeMethod::bilinear, 0); + auto result = crop_and_resize->output(0); + ASSERT_EQ(result.get_shape(), result_shape.to_shape()); + ASSERT_EQ(result.get_element_type(), image->output(0).get_element_type()); +} + +TEST(type_prop, crop_and_resize_not_constant) +{ + Dimension N = 4; + Dimension W_image = 400; + Dimension H_image = 300; + Dimension C_image = 3; + Dimension num_boxes = 20; + int32_t W_crop = 30; + int32_t H_crop = 40; + + PartialShape result_shape{num_boxes, H_crop, W_crop, C_image}; + + auto image = + make_shared(element::f32, PartialShape{N, H_image, W_image, C_image}); + auto boxes = make_shared(element::f32, PartialShape{num_boxes, 4}); + auto box_indices = make_shared(element::i32, PartialShape{num_boxes}); + auto crop_shape = make_shared(element::i32, PartialShape{2}); + + try + { + auto crop_and_resize = make_shared( + image, boxes, box_indices, crop_shape, op::CropAndResize::ResizeMethod::bilinear, 0); + FAIL() << "CropAndReshape without constant crop shape should fail"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("crop_size must be a constant")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} diff --git a/test/type_prop/deformable_psroi_pooling.cpp b/test/type_prop/deformable_psroi_pooling.cpp new file mode 100644 index 00000000000..2d595f384c5 --- /dev/null +++ b/test/type_prop/deformable_psroi_pooling.cpp @@ -0,0 +1,131 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, deformable_psroi_pooling_output_shape) +{ + auto input = make_shared(element::f32, Shape{1, 1024, 63, 38}); + auto coords = make_shared(element::f32, Shape{300, 5}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4}); + const int64_t output_dim = 882; + const float spatial_scale = 0.0625; + const int64_t group_size = 3; + + auto def_psroi_pool = make_shared( + input, coords, offsets, output_dim, spatial_scale, group_size); + + ASSERT_EQ(def_psroi_pool->get_output_shape(0), (Shape{300, 882, 3, 3})); +} + +TEST(type_prop, deformable_psroi_pooling_output_shape_2) +{ + auto input = make_shared(element::f32, Shape{1, 7938, 38, 38}); + auto coords = make_shared(element::f32, Shape{300, 5}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4}); + const int64_t output_dim = 162; + const float spatial_scale = 0.0625; + const int64_t group_size = 7; + + auto def_psroi_pool = make_shared( + input, coords, offsets, output_dim, spatial_scale, group_size); + + ASSERT_EQ(def_psroi_pool->get_output_shape(0), (Shape{300, 162, 7, 7})); +} + +TEST(type_prop, deformable_psroi_pooling_invalid_input_rank) +{ + auto input = make_shared(element::f32, Shape{1, 2, 3}); + auto coords = make_shared(element::f32, Shape{1, 2}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4}); + const int64_t output_dim = 4; + const float spatial_scale = 0.9; + const int64_t group_size = 7; + try + { + auto def_psroi_pool = make_shared( + input, coords, offsets, output_dim, spatial_scale, group_size); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid feature map input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), + std::string("Feature map input rank must equal to 4 (input rank: 3)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, deformable_psroi_pooling_invalid_box_coordinates_rank) +{ + auto input = make_shared(element::f32, Shape{1, 2, 3, 4}); + auto coords = make_shared(element::f32, Shape{1, 2, 3}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4}); + const int64_t output_dim = 4; + const float spatial_scale = 0.9; + const int64_t group_size = 7; + try + { + auto def_psroi_pool = make_shared( + input, coords, offsets, output_dim, spatial_scale, group_size); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid box coordinates input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING( + error.what(), + std::string("Box coordinates input rank must equal to 2 (input rank: 3)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, deformable_psroi_pooling_invalid_offstes_rank) +{ + auto input = make_shared(element::f32, Shape{1, 2, 3, 4}); + auto coords = make_shared(element::f32, Shape{1, 2}); + auto offsets = make_shared(element::f32, Shape{1, 2, 3, 4, 5}); + const int64_t output_dim = 4; + const float spatial_scale = 0.9; + const int64_t group_size = 7; + try + { + auto def_psroi_pool = make_shared( + input, coords, offsets, output_dim, spatial_scale, group_size); + // Should have thrown, so fail if it didn't + FAIL() << "Offsets input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), + std::string("Offsets input rank must equal to 4 (input rank: 5)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} diff --git a/test/type_prop/gather_tree.cpp b/test/type_prop/gather_tree.cpp new file mode 100644 index 00000000000..23f137ed1c1 --- /dev/null +++ b/test/type_prop/gather_tree.cpp @@ -0,0 +1,134 @@ +//***************************************************************************** +// Copyright 2017-2019 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, gather_tree_output_shape) +{ + auto step_ids = make_shared(element::i64, Shape{1, 2, 3}); + auto parent_idx = make_shared(element::i64, Shape{1, 2, 3}); + auto max_seq_len = make_shared(element::i64, Shape{1}); + auto end_token = make_shared(element::i64, Shape{1, 2, 3}); + + auto gather_tree = + make_shared(step_ids, parent_idx, max_seq_len, end_token); + + ASSERT_EQ(gather_tree->get_output_shape(0), (Shape{1, 2, 3})); + ASSERT_EQ(gather_tree->get_output_element_type(0), element::i64); +} + +TEST(type_prop, gather_tree_pooling_step_ids_invalid_rank) +{ + auto step_ids = make_shared(element::i64, Shape{1, 2, 3, 4}); + auto parent_idx = make_shared(element::i64, Shape{1, 2, 3}); + auto max_seq_len = make_shared(element::i64, Shape{1}); + auto end_token = make_shared(element::i64, Shape{1, 2, 3}); + try + { + auto gather_tree = + make_shared(step_ids, parent_idx, max_seq_len, end_token); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid step_ids input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), + std::string("step_ids input rank must equal to 3 (step_ids rank: 4)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, gather_tree_parent_idx_invalid_rank) +{ + auto step_ids = make_shared(element::i64, Shape{1, 2, 3}); + auto parent_idx = make_shared(element::i64, Shape{1, 2, 3, 4}); + auto max_seq_len = make_shared(element::i64, Shape{1}); + auto end_token = make_shared(element::i64, Shape{1, 2, 3}); + try + { + auto gather_tree = + make_shared(step_ids, parent_idx, max_seq_len, end_token); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid parent_idx input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING( + error.what(), + std::string("parent_idx input rank must equal to 3 (parent_idx rank: 4)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, gather_tree_max_seq_len_invalid_rank) +{ + auto step_ids = make_shared(element::i64, Shape{1, 2, 3}); + auto parent_idx = make_shared(element::i64, Shape{1, 2, 3}); + auto max_seq_len = make_shared(element::i64, Shape{1, 2}); + auto end_token = make_shared(element::i64, Shape{1, 2, 3}); + try + { + auto gather_tree = + make_shared(step_ids, parent_idx, max_seq_len, end_token); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid parent_idx input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING( + error.what(), + std::string("max_seq_len input rank must equal to 1 (max_seq_len rank: 2)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, gather_tree_end_token_invalid_rank) +{ + auto step_ids = make_shared(element::i64, Shape{1, 2, 3}); + auto parent_idx = make_shared(element::i64, Shape{1, 2, 3}); + auto max_seq_len = make_shared(element::i64, Shape{1}); + auto end_token = make_shared(element::i64, Shape{1, 2, 3, 4}); + try + { + auto gather_tree = + make_shared(step_ids, parent_idx, max_seq_len, end_token); + // Should have thrown, so fail if it didn't + FAIL() << "Ivalid end_token input rank not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING( + error.what(), std::string("end_token input rank must equal to 3 (end_token rank: 4)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} diff --git a/test/type_prop/hard_sigmoid.cpp b/test/type_prop/hard_sigmoid.cpp index ef30f90e01e..1a3d3bfda06 100644 --- a/test/type_prop/hard_sigmoid.cpp +++ b/test/type_prop/hard_sigmoid.cpp @@ -23,11 +23,12 @@ using namespace ngraph; TEST(type_prop, hardsigmoid) { - Shape data_shape{3, 5}; - float alpha = 0.1; - float beta = 1.2; - auto P = make_shared(element::f32, data_shape); - auto H = make_shared(P, alpha, beta); + const Shape data_shape{3, 5}; + + const auto P = make_shared(element::f32, data_shape); + const auto alpha = op::Constant::create(P->get_element_type(), Shape{}, {0.1f}); + const auto beta = op::Constant::create(P->get_element_type(), Shape{}, {1.2f}); + const auto H = make_shared(P, alpha, beta); ASSERT_EQ(H->get_element_type(), element::f32); ASSERT_EQ(H->get_shape(), data_shape); } diff --git a/src/ngraph/runtime/generic_cpu/node_wrapper.cpp b/test/type_prop/log_softmax.cpp similarity index 53% rename from src/ngraph/runtime/generic_cpu/node_wrapper.cpp rename to test/type_prop/log_softmax.cpp index 2bdef4b5aa3..3ae4129dcd7 100644 --- a/src/ngraph/runtime/generic_cpu/node_wrapper.cpp +++ b/test/type_prop/log_softmax.cpp @@ -14,31 +14,29 @@ // limitations under the License. //***************************************************************************** -#include "ngraph/runtime/generic_cpu/node_wrapper.hpp" +#include "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" -using namespace ngraph; using namespace std; +using namespace ngraph; -runtime::gcpu::NodeWrapper::NodeWrapper(const shared_ptr& node) - : m_node{node} +TEST(type_prop, log_softmax) { -// This expands the op list in op_tbl.hpp into a list of enumerations that look like this: -// {"Abs", runtime::gcpu::OP_TYPEID::Abs}, -// {"Acos", runtime::gcpu::OP_TYPEID::Acos}, -// ... -#define NGRAPH_OP(a, b) {#a, runtime::gcpu::OP_TYPEID::a}, - static unordered_map typeid_map{ -#include "ngraph/op/op_tbl.hpp" - }; -#undef NGRAPH_OP - - auto it = typeid_map.find(m_node->description()); - if (it != typeid_map.end()) + const auto data = make_shared(element::f64, Shape{2, 2}); + const auto axis = 2; + try + { + const auto log_softmax = make_shared(data, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Invalid axis value not detected"; + } + catch (const ngraph_error& error) { - m_typeid = it->second; + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis ")); } - else + catch (...) { - throw unsupported_op("Unsupported op '" + m_node->description() + "'"); + FAIL() << "Log softmax failed for unexpected reason"; } } diff --git a/test/type_prop/lrn.cpp b/test/type_prop/lrn.cpp index 3b1c9dc1dba..e8cc25401aa 100644 --- a/test/type_prop/lrn.cpp +++ b/test/type_prop/lrn.cpp @@ -21,23 +21,6 @@ using namespace std; using namespace ngraph; -TEST(type_prop, lrn_invalid_arg_rank) -{ - auto data = make_shared(element::f32, Shape{1, 2}); - double alpha = 0.1, beta = 0.2, bias = 0.3; - size_t size = 3; - try - { - auto lrn = make_shared(data, alpha, beta, bias, size); - // Should have thrown, so fail if it didn't - FAIL() << "Invalid input tensor rank not detected"; - } - catch (const NodeValidationFailure& error) - { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument must have rank >= 3")); - } -} - TEST(type_prop, lrn_invalid_axes_rank) { auto data = make_shared(element::f32, Shape{1, 2, 3, 4}); diff --git a/test/type_prop/one_hot.cpp b/test/type_prop/one_hot.cpp index 726679c229a..fb84236332a 100644 --- a/test/type_prop/one_hot.cpp +++ b/test/type_prop/one_hot.cpp @@ -372,3 +372,167 @@ TEST(type_prop, one_hot_partial_rank_static_dynamic_rank_static_dynamic_one_hot_ FAIL() << "Deduced type check failed for unexpected reason"; } } + +TEST(type_prop, one_hot_v1_output_shape) +{ + auto indices = make_shared(element::i64, Shape{3}); + auto depth = op::Constant::create(element::i64, Shape{}, {2}); + auto on_value = op::Constant::create(element::u32, Shape{}, {5}); + auto off_value = op::Constant::create(element::u32, Shape{}, {10}); + int64_t axis = -1; + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + ASSERT_EQ(ont_hot->get_element_type(), element::u32); + ASSERT_EQ(ont_hot->get_shape(), (Shape{3, 2})); +} + +TEST(type_prop, one_hot_v1_output_shape_2) +{ + auto indices = make_shared(element::i64, Shape{1, 3, 2, 3}); + auto depth = op::Constant::create(element::i64, Shape{}, {4}); + auto on_value = op::Constant::create(element::f32, Shape{}, {1.0f}); + auto off_value = op::Constant::create(element::f32, Shape{}, {0.0f}); + int64_t axis = 3; + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + ASSERT_EQ(ont_hot->get_element_type(), element::f32); + ASSERT_EQ(ont_hot->get_shape(), (Shape{1, 3, 2, 4, 3})); +} + +TEST(type_prop, one_hot_v1_indices_elem_not_integral) +{ + auto indices = make_shared(element::f16, Shape{2, 2}); + auto depth = make_shared(element::i64, Shape{}); + auto on_value = make_shared(element::u32, Shape{}); + auto off_value = make_shared(element::u32, Shape{}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Incorrect indices element type not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("Indices must be integral element type.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, one_hot_v1_depth_elem_not_integral) +{ + auto indices = make_shared(element::i64, Shape{2, 2}); + auto depth = make_shared(element::f16, Shape{}); + auto on_value = make_shared(element::u32, Shape{}); + auto off_value = make_shared(element::u32, Shape{}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Incorrect depth element type not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("Depth must be integral element type.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, one_hot_v1_on_off_values_not_compatible) +{ + auto indices = make_shared(element::i64, Shape{2, 2}); + auto depth = make_shared(element::i64, Shape{}); + auto on_value = make_shared(element::bf16, Shape{}); + auto off_value = make_shared(element::f16, Shape{}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Incompatible on/off element types not detected"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING( + error.what(), + std::string("on_value element type must be compatible with off_value element type.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, one_hot_v1_depth_not_scalar) +{ + auto indices = make_shared(element::i64, Shape{2, 2}); + auto depth = make_shared(element::i64, Shape{1}); + auto on_value = make_shared(element::bf16, Shape{}); + auto off_value = make_shared(element::bf16, Shape{}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Not scalar depth input not detected."; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("depth input must be scalar.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, one_hot_v1_on_value_not_scalar) +{ + auto indices = make_shared(element::i64, Shape{2, 2}); + auto depth = make_shared(element::i64, Shape{}); + auto on_value = make_shared(element::bf16, Shape{2}); + auto off_value = make_shared(element::bf16, Shape{}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Not scalar on_value input not detected."; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("on_value input must be scalar.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, one_hot_v1_off_value_not_scalar) +{ + auto indices = make_shared(element::i64, Shape{2, 2}); + auto depth = make_shared(element::i64, Shape{}); + auto on_value = make_shared(element::bf16, Shape{}); + auto off_value = make_shared(element::bf16, Shape{3}); + int64_t axis = -1; + try + { + auto ont_hot = make_shared(indices, depth, on_value, off_value, axis); + // Should have thrown, so fail if it didn't + FAIL() << "Not scalar off_value input not detected."; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("off_value input must be scalar.")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} diff --git a/test/type_prop/reverse_sequence.cpp b/test/type_prop/reverse_sequence.cpp index db79c45cb0c..d203cbbbea1 100644 --- a/test/type_prop/reverse_sequence.cpp +++ b/test/type_prop/reverse_sequence.cpp @@ -54,9 +54,9 @@ TEST(type_prop, reverse_sequence_batch_index_oob) auto bc = make_shared(data, seq_lenghts, batch_axis, seq_axis); FAIL() << "ReverseSequence c-tor should throw for out-of-bounds batch axis index"; } - catch (const NodeValidationFailure& error) + catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Batch axis index (3) is out of bounds")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 3 out of the tensor rank")); } catch (...) { @@ -75,9 +75,9 @@ TEST(type_prop, reverse_sequence_sequence_index_oob) auto bc = make_shared(data, seq_lengths, batch_axis, seq_axis); FAIL() << "ReverseSequence c-tor should throw for out-of-bounds sequence axis index"; } - catch (const NodeValidationFailure& error) + catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Sequence axis index (3) is out of bounds")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 3 out of the tensor rank")); } catch (...) { @@ -179,9 +179,9 @@ TEST(type_prop, reverse_sequence_partial_both_rank_static_dynamic_batch_axis_oob auto rs = make_shared(data, seq_lengths, batch_axis, seq_axis); FAIL() << "Batch axis out of bounds not detected (rank-static dynamic shape)"; } - catch (const NodeValidationFailure& error) + catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Batch axis index (4) is out of bounds")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 4 out of the tensor rank")); } catch (...) { @@ -204,9 +204,9 @@ TEST(type_prop, reverse_sequence_partial_both_rank_static_dynamic_sequence_axis_ auto rs = make_shared(data, seq_lengths, batch_axis, seq_axis); FAIL() << "Sequence axis out of bounds not detected (rank-static dynamic shape)"; } - catch (const NodeValidationFailure& error) + catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("Sequence axis index (4) is out of bounds")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis 4 out of the tensor rank")); } catch (...) { @@ -289,3 +289,39 @@ TEST( FAIL() << "Deduced type check failed for unexpected reason"; } } + +TEST(type_prop, reverse_sequence_negative_axis_dynamic_input_rank) +{ + auto data = make_shared(element::f32, PartialShape::dynamic()); + auto seq_lengths = make_shared(element::f32, PartialShape{1}); + int64_t batch_axis = 1; + int64_t seq_axis = -2; + try + { + auto rs = make_shared(data, seq_lengths, batch_axis, seq_axis); + FAIL() << "Dynamic input rank for negative axis not detected"; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), + std::string("In order to handle negative axes input_rank must be " + "static (batch_axis=1, seq_axis=-2)")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason"; + } +} + +TEST(type_prop, reverse_sequence_negative_axes_support) +{ + auto data = make_shared(element::f32, PartialShape{1, 2, 3, 4, 5}); + auto seq_lengths = make_shared(element::f32, PartialShape{3}); + int64_t batch_axis = -3; + int64_t seq_axis = -2; + + auto rs = make_shared(data, seq_lengths, batch_axis, seq_axis); + + EXPECT_EQ(rs->get_batch_axis(), 2); + EXPECT_EQ(rs->get_sequence_axis(), 3); +} diff --git a/test/type_prop/space_to_depth.cpp b/test/type_prop/space_to_depth.cpp index c4702411e67..7138eb1d5d7 100644 --- a/test/type_prop/space_to_depth.cpp +++ b/test/type_prop/space_to_depth.cpp @@ -24,8 +24,28 @@ using namespace ngraph; TEST(type_prop, space_to_depth) { auto A = make_shared(element::f32, Shape{1, 2, 64, 64}); - auto space_to_depth = make_shared(A, 8); + const auto mode = ngraph::op::SpaceToDepth::SpaceToDepthMode::BLOCKS_FIRST; + auto space_to_depth = make_shared(A, mode, 8); ASSERT_EQ(space_to_depth->get_element_type(), element::f32); ASSERT_EQ(space_to_depth->get_shape(), (Shape{1, 128, 8, 8})); } + +TEST(type_prop, space_to_depth_input_rank_not_supported) +{ + auto A = make_shared(element::f32, Shape{1, 8, 8, 8, 4}); + try + { + auto space_to_depth = + make_shared(A, op::DepthToSpace::DepthToSpaceMode::DEPTH_FIRST, 2); + FAIL() << "Not supported input shape for SpaceToDepth exception not thrown"; + } + catch (const ngraph_error& error) + { + EXPECT_HAS_SUBSTRING(error.what(), "The provided tensor shape: "); + } + catch (...) + { + FAIL() << "SpaceToDepth decomposition failed for unexpected reason"; + } +} diff --git a/test/type_prop/split.cpp b/test/type_prop/split.cpp index d9a3279192d..4759ea00f77 100644 --- a/test/type_prop/split.cpp +++ b/test/type_prop/split.cpp @@ -28,7 +28,8 @@ TEST(type_prop, split) try { const std::vector splits = {1, 6}; // should sum up to 6 - const auto split = make_shared(data, 1, splits); + const auto axis = op::Constant::create(element::i64, Shape{}, {1}); + const auto split = make_shared(data, axis, splits); FAIL() << "Split node was created with incorrect data."; } catch (const NodeValidationFailure& error) @@ -40,20 +41,62 @@ TEST(type_prop, split) try { const std::vector splits = {4, 2}; - const auto split = make_shared(data, -5, splits); // invalid axis + const auto axis = op::Constant::create(element::i64, Shape{}, {-5}); + const auto split = make_shared(data, axis, splits); // invalid axis FAIL() << "Split node was created with incorrect data."; } - catch (const NodeValidationFailure& error) + catch (const ngraph_error& error) { - EXPECT_HAS_SUBSTRING(error.what(), - std::string("The 'axis' parameter for Split has to point to one of " - "the input tensor's shape dimensions.")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Parameter axis -5 out of the tensor rank")); } - const auto split = make_shared(data, 1, 2); + const auto axis = op::Constant::create(element::i64, Shape{}, {1}); + const auto split = make_shared(data, axis, 2); EXPECT_EQ(split->outputs().size(), 2); EXPECT_EQ(split->output(0).get_shape(), (Shape{2, 3})); EXPECT_EQ(split->output(1).get_shape(), (Shape{2, 3})); EXPECT_EQ(split->output(0).get_element_type(), element::i32); EXPECT_EQ(split->output(1).get_element_type(), element::i32); } + +TEST(type_prop, split_axis_must_be_scalar) +{ + const auto data = make_shared(element::i32, Shape{2, 6}); + const std::vector splits = {1, 6}; + const auto axis = op::Constant::create(element::i64, Shape{2}, {0, 1}); + + try + { + const auto split = make_shared(data, axis, splits); + FAIL() << "Incorrect axis of Split not detected."; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("The 'axis' input node must be scalar")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason."; + } +} + +TEST(type_prop, split_axis_must_be_constant) +{ + const auto data = make_shared(element::i32, Shape{2, 6}); + const std::vector splits = {1, 6}; + const auto axis = make_shared(element::i32, Shape{}); + + try + { + const auto split = make_shared(data, axis, splits); + FAIL() << "Not constant axis of Split not detected."; + } + catch (const NodeValidationFailure& error) + { + EXPECT_HAS_SUBSTRING(error.what(), std::string("The 'axis' input node must be constant")); + } + catch (...) + { + FAIL() << "Deduced type check failed for unexpected reason."; + } +} diff --git a/test/type_prop/squared_difference.cpp b/test/type_prop/squared_difference.cpp index aabbfd0aa04..f8be1310e2c 100644 --- a/test/type_prop/squared_difference.cpp +++ b/test/type_prop/squared_difference.cpp @@ -34,7 +34,7 @@ TEST(type_prop, squared_difference) } catch (const NodeValidationFailure& error) { - EXPECT_HAS_SUBSTRING(error.what(), std::string("axes are incompatible")); + EXPECT_HAS_SUBSTRING(error.what(), std::string("Argument shapes are inconsistent")); } const auto clamp = make_shared(x1, x3); diff --git a/test/type_prop/unary_elementwise.cpp b/test/type_prop/unary_elementwise.cpp index 473cb33d4ba..0fd8574555c 100644 --- a/test/type_prop/unary_elementwise.cpp +++ b/test/type_prop/unary_elementwise.cpp @@ -40,3 +40,11 @@ TEST(type_prop, unary_arithmetic_bad_argument_element_types) FAIL() << "Deduced type check failed for unexpected reason"; } } + +TEST(type_prop, reciprocal) +{ + auto param = make_shared(element::f32, Shape{2, 3, 4}); + auto pad = make_shared(param); + EXPECT_EQ(pad->get_element_type(), element::f32); + EXPECT_EQ(pad->get_shape(), (Shape{2, 3, 4})); +} diff --git a/test/util/CMakeLists.txt b/test/util/CMakeLists.txt index bff252a25ac..6db4896204b 100644 --- a/test/util/CMakeLists.txt +++ b/test/util/CMakeLists.txt @@ -31,6 +31,7 @@ if(NGRAPH_LIB_VERSIONING_ENABLE) endif() target_include_directories(ngraph_test_util PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) target_link_libraries(ngraph_test_util PRIVATE ngraph libgtest) +add_dependencies(ngraph_test_util ext_gtest) if (NGRAPH_UNIT_TEST_OPENVINO_ENABLE) add_definitions(-DNGRAPH_UNIT_TEST_OPENVINO_ENABLE) diff --git a/test/util/matcher.hpp b/test/util/matcher.hpp index 99621425e38..b998a874dc2 100644 --- a/test/util/matcher.hpp +++ b/test/util/matcher.hpp @@ -24,8 +24,7 @@ class TestMatcher : public ngraph::pattern::Matcher { if (ngraph::as_type_ptr<::ngraph::op::Parameter>(pattern_node)) { - bool result = - pattern_node.get() == dynamic_cast<::ngraph::op::Parameter*>(graph_node.get()); + bool result = pattern_node == ngraph::as_type_ptr<::ngraph::op::Parameter>(graph_node); if (result) { m_matched_list.push_back(graph_node);