Commit f0acb7da authored by Rob Earhart's avatar Rob Earhart Committed by Robert Kimball

Add PlaidML backend (#1888)

* Add PlaidML backend

* CR comments

Used m_ prefix for members; removed trailing underscores
Updated license headers
Moved associated header inclusions to project blocks
Wrapped comments to 100 chars
Added missing newlines between functions
Removed nested namespaces in operation implementations

* Add earhart to CODEOWNERS

* Rebase updates

* style
parent d901446d
......@@ -104,6 +104,8 @@ if (NGRAPH_ONNX_IMPORT_ENABLE)
option(NGRAPH_ONNXIFI_ENABLE "Enable ONNX Interface for Framework Integration" TRUE)
endif()
option(NGRAPH_PLAIDML_ENABLE "Enable the PlaidML backend" FALSE)
#-----------------------------------------------------------------------------------------------
# Installation logic...
#-----------------------------------------------------------------------------------------------
......@@ -206,6 +208,10 @@ if (NGRAPH_CPU_ENABLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNGRAPH_CPU_ENABLE")
endif()
if (NGRAPH_PLAIDML_ENABLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNGRAPH_PlaidML_ENABLE")
endif()
if (NOT DEFINED NGRAPH_TBB_ENABLE)
set(NGRAPH_TBB_ENABLE ${NGRAPH_CPU_ENABLE})
endif()
......
......@@ -43,6 +43,7 @@
/src/ngraph/runtime/hybrid/ @sasadep
/src/ngraph/runtime/intelgpu/ @shssf
/src/ngraph/runtime/interpreter/ @rkimballn1
/src/ngraph/runtime/plaidml/ @earhart
/src/ngraph/runtime/reference/ @aprocter
/src/ngraph/type/ @diyessi
/src/ngraph/serializer.*pp @rkimballn1
......
......@@ -18,7 +18,7 @@ import pytest
def pytest_addoption(parser):
parser.addoption('--backend', default='INTERPRETER',
choices=['INTERPRETER', 'CPU', 'GPU', 'NNP'],
choices=['INTERPRETER', 'CPU', 'GPU', 'NNP', 'PlaidML'],
help='Select from available backends')
......@@ -31,3 +31,4 @@ def pytest_configure(config):
config.cpu_skip = pytest.mark.skipif(config.getvalue('backend') == 'CPU')
config.nnp_skip = pytest.mark.skipif(config.getvalue('backend') == 'NNP')
config.interpreter_skip = pytest.mark.skipif(config.getvalue('backend') == 'INTERPRETER')
config.plaidml_skip = pytest.mark.skipif(config.getvalue('backend') == 'PlaidML')
......@@ -35,6 +35,7 @@ std::string ngraph::placement_to_string(Placement placement)
case Placement::CPU: return "CPU";
case Placement::GPU: return "GPU";
case Placement::NNP: return "NNP";
case Placement::PLAIDML: return "PlaidML";
}
throw runtime_error("unhandled placement type");
}
......
......@@ -42,6 +42,7 @@ namespace ngraph
CPU,
GPU,
NNP,
PLAIDML,
};
std::string placement_to_string(Placement placement);
......
......@@ -32,3 +32,5 @@ endif()
if (NGRAPH_GPU_ENABLE)
add_subdirectory(gpu)
endif()
add_subdirectory(plaidml)
# ******************************************************************************
# Copyright 2018 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.
# ******************************************************************************
set(SRC
plaidml_backend.cpp
plaidml_builder.cpp
plaidml_compilation_cache.cpp
plaidml_compiled_function.cpp
plaidml_compiler.cpp
plaidml_config.cpp
plaidml_convpool_formatter.cpp
plaidml_impl.cpp
plaidml_logger.cpp
plaidml_ops_arithmetic.cpp
plaidml_ops_batch_norm.cpp
plaidml_ops_comparison.cpp
plaidml_ops_concat.cpp
plaidml_ops_convert.cpp
plaidml_ops_convolution.cpp
plaidml_ops_dot.cpp
plaidml_ops_function.cpp
plaidml_ops_general.cpp
plaidml_ops_index_reduction.cpp
plaidml_ops_io.cpp
plaidml_ops_local_response_norm.cpp
plaidml_ops_logical.cpp
plaidml_ops_one_hot.cpp
plaidml_ops_pool.cpp
plaidml_ops_reduce.cpp
plaidml_ops_replace_slice.cpp
plaidml_ops_reverse.cpp
plaidml_ops_slice.cpp
plaidml_ops_softmax.cpp
plaidml_ops_transcendental.cpp
plaidml_tensor.cpp
plaidml_translate.cpp
)
if (NGRAPH_PLAIDML_ENABLE)
find_package(PlaidML CONFIG REQUIRED)
message(STATUS "PlaidML enabled")
add_library(libplaidml INTERFACE)
target_link_libraries(libplaidml INTERFACE ${PLAIDML_LIBRARIES})
install(FILES ${PLAIDML_LIBRARIES} DESTINATION ${NGRAPH_INSTALL_LIB})
add_library(plaidml_backend SHARED ${SRC})
set_target_properties(plaidml_backend PROPERTIES VERSION ${NGRAPH_VERSION} SOVERSION ${NGRAPH_API_VERSION})
target_include_directories(plaidml_backend SYSTEM PUBLIC ${PLAIDML_INCLUDE_DIRS})
target_link_libraries(plaidml_backend PUBLIC ngraph libplaidml)
set_target_properties(plaidml_backend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${NGRAPH_BUILD_DIR}")
install(TARGETS plaidml_backend LIBRARY DESTINATION ${NGRAPH_INSTALL_LIB})
else()
message(STATUS "PlaidML not enabled")
endif()
//*****************************************************************************
// Copyright 2017-2018 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/plaidml/plaidml_backend.hpp"
#include "ngraph/node.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiled_function.hpp"
#include "ngraph/runtime/plaidml/plaidml_tensor.hpp"
#include "ngraph/util.hpp"
namespace vp = vertexai::plaidml;
ngraph::runtime::plaidml::PlaidML_Backend::PlaidML_Backend(const char* configuration_string)
: m_config{parse_config_string(configuration_string)}
, m_compiler{&m_config}
{
}
std::shared_ptr<ngraph::runtime::Tensor> ngraph::runtime::plaidml::PlaidML_Backend::create_tensor(
const ngraph::element::Type& element_type, const ngraph::Shape& shape)
{
return std::make_shared<PlaidML_Tensor>(&m_config, element_type, shape, "direct_data", nullptr);
}
std::shared_ptr<ngraph::runtime::Tensor> ngraph::runtime::plaidml::PlaidML_Backend::create_tensor(
const ngraph::element::Type& element_type, const Shape& shape, void* memory_pointer)
{
return std::make_shared<PlaidML_Tensor>(
&m_config, element_type, shape, "direct_data", memory_pointer);
}
bool ngraph::runtime::plaidml::PlaidML_Backend::compile(std::shared_ptr<Function> func)
{
m_cache.compile(func, &m_compiler);
return true;
}
bool ngraph::runtime::plaidml::PlaidML_Backend::call(
std::shared_ptr<Function> func,
const std::vector<std::shared_ptr<runtime::Tensor>>& outputs,
const std::vector<std::shared_ptr<runtime::Tensor>>& inputs)
{
auto cfunc = m_cache.try_lookup(func);
if (!cfunc)
{
cfunc = m_compiler.compile(func);
}
cfunc->schedule_invocation(inputs, outputs);
return true;
}
void ngraph::runtime::plaidml::PlaidML_Backend::remove_compiled_function(
std::shared_ptr<Function> func)
{
m_cache.forget(func);
}
void ngraph::runtime::plaidml::PlaidML_Backend::save(std::shared_ptr<Function> func,
const std::string& filename,
plaidml_file_format format)
{
auto cfunc = m_cache.try_lookup(func);
if (!cfunc)
{
cfunc = m_compiler.compile(func);
}
cfunc->save(filename, format);
}
extern "C" const char* get_ngraph_version_string()
{
return NGRAPH_VERSION;
}
extern "C" ngraph::runtime::Backend* new_backend(const char* configuration_string)
{
return new ngraph::runtime::plaidml::PlaidML_Backend{configuration_string};
}
extern "C" void delete_backend(ngraph::runtime::Backend* backend)
{
delete backend;
}
//*****************************************************************************
// Copyright 2017-2018 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 <plaidml/plaidml++.h>
#include "ngraph/runtime/backend.hpp"
#include "ngraph/runtime/plaidml/plaidml_compilation_cache.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiler.hpp"
#include "ngraph/runtime/plaidml/plaidml_config.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
class PlaidML_Backend;
}
}
}
// Implements the runtime::Backend interface for the PlaidML nGraph backend.
class ngraph::runtime::plaidml::PlaidML_Backend final : public runtime::Backend
{
public:
PlaidML_Backend(const char* configuration_string);
~PlaidML_Backend() final {}
std::shared_ptr<ngraph::runtime::Tensor>
create_tensor(const ngraph::element::Type& element_type, const Shape& shape) final;
std::shared_ptr<ngraph::runtime::Tensor> create_tensor(
const ngraph::element::Type& element_type, const Shape& shape, void* memory_pointer) final;
bool compile(std::shared_ptr<Function> func) final;
bool call(std::shared_ptr<Function> func,
const std::vector<std::shared_ptr<runtime::Tensor>>& outputs,
const std::vector<std::shared_ptr<runtime::Tensor>>& inputs) final;
void remove_compiled_function(std::shared_ptr<Function> func) final;
void save(std::shared_ptr<Function> func,
const std::string& filename,
plaidml_file_format format);
private:
Config m_config;
Compiler m_compiler;
CompilationCache m_cache;
};
//*****************************************************************************
// Copyright 2017-2018 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 <plaidml/plaidml++.h>
#include <string>
#include <unordered_map>
#include "ngraph/function.hpp"
#include "ngraph/runtime/plaidml/plaidml_config.hpp"
#include "ngraph/runtime/tensor.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
struct Build;
class Compiler;
struct TensorInfo;
enum class TensorContents
{
DATA = 0,
LOGICAL = 1
};
}
}
}
// Holds information about a particular tensor.
struct ngraph::runtime::plaidml::TensorInfo final
{
TensorInfo(vertexai::plaidml::variable _var, TensorContents _contents)
: var{std::move(_var)}
, contents{_contents}
{
}
vertexai::plaidml::variable var;
TensorContents contents;
};
// Holds the intermediate state of a function compilation.
struct ngraph::runtime::plaidml::Build final
{
Config* config = nullptr;
Compiler* compiler = nullptr;
std::shared_ptr<Function> func;
std::unordered_map<descriptor::Tensor*, std::string> input_names;
std::unordered_map<descriptor::Tensor*, std::string> output_names;
vertexai::plaidml::compose composer;
std::unordered_map<descriptor::Tensor*, TensorInfo> bindings;
bool io_dim_override = false;
std::size_t io_dim_override_count = 0;
};
This diff is collapsed.
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2018 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/plaidml/plaidml_compilation_cache.hpp"
std::shared_ptr<ngraph::runtime::plaidml::CompiledFunction>
ngraph::runtime::plaidml::CompilationCache::try_lookup(std::shared_ptr<Function> func)
{
std::lock_guard<std::mutex> lock{m_mu};
auto it = m_cache.find(func);
if (it != m_cache.end())
{
return it->second;
}
return std::shared_ptr<CompiledFunction>{};
}
std::shared_ptr<ngraph::runtime::plaidml::CompiledFunction>
ngraph::runtime::plaidml::CompilationCache::compile(std::shared_ptr<Function> func,
Compiler* compiler)
{
std::lock_guard<std::mutex> lock{m_mu};
auto it_inserted = m_cache.insert(std::make_pair(func, std::shared_ptr<CompiledFunction>{}));
if (it_inserted.second)
{
try
{
it_inserted.first->second = compiler->compile(func);
}
catch (...)
{
m_cache.erase(it_inserted.first);
throw;
}
}
return it_inserted.first->second;
}
void ngraph::runtime::plaidml::CompilationCache::forget(std::shared_ptr<Function> func)
{
std::lock_guard<std::mutex> lock{m_mu};
m_cache.erase(func);
}
//*****************************************************************************
// Copyright 2017-2018 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 <memory>
#include <mutex>
#include <unordered_map>
#include "ngraph/function.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiled_function.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiler.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
class CompilationCache;
}
}
}
// A compilation cacher.
class ngraph::runtime::plaidml::CompilationCache final
{
public:
// Looks up the supplied function in the compilation cache. If the function is not in the
// cache, returns an empty pointer.
std::shared_ptr<CompiledFunction> try_lookup(std::shared_ptr<Function> func);
// Looks up the supplied function in the compilation cache. If the function is not in the
// cache, compiles it using the specified compiler (which must not be nullptr), adds the
// compiled function to the cache, and returns the compiled function.
std::shared_ptr<CompiledFunction> compile(std::shared_ptr<Function> func, Compiler* compiler);
// Drops the supplied function's compiled function from the compilation cache.
void forget(std::shared_ptr<Function> func);
private:
std::mutex m_mu;
std::unordered_map<std::shared_ptr<Function>, std::shared_ptr<CompiledFunction>> m_cache;
};
//*****************************************************************************
// Copyright 2017-2018 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 <utility>
#include "ngraph/log.hpp"
#include "ngraph/runtime/plaidml/plaidml_build.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiled_function.hpp"
#include "ngraph/runtime/plaidml/plaidml_tensor.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp"
namespace vp = vertexai::plaidml;
ngraph::runtime::plaidml::CompiledFunction::CompiledFunction(Build build)
: m_config{build.config}
, m_func{std::move(build.func)}
, m_input_names{std::move(build.input_names)}
, m_output_names{std::move(build.output_names)}
, m_invoker{build.config->ctx, std::move(build.composer)}
{
NGRAPH_DEBUG << "Compiled PlaidML function " << this;
}
bool ngraph::runtime::plaidml::CompiledFunction::schedule_invocation(
const std::vector<std::shared_ptr<runtime::Tensor>>& inputs,
const std::vector<std::shared_ptr<runtime::Tensor>>& outputs) const
{
std::lock_guard<std::mutex> lock{m_mu};
NGRAPH_DEBUG << "Binding PlaidML function " << this;
std::size_t input_count = 0;
for (const auto& param : m_func->get_parameters())
{
for (std::size_t idx = 0; idx < param->get_output_size(); ++idx)
{
descriptor::Tensor* tv = param->get_output_tensor_ptr(idx).get();
auto rtv = dynamic_cast<PlaidML_Tensor*>(inputs[input_count++].get());
if (!rtv)
{
throw std::runtime_error{
"The PlaidML backend only operations on PlaidML tensor views"};
}
rtv->sync_input();
NGRAPH_DEBUG << "Binding input " << m_input_names.at(tv) << " to tensor " << rtv;
m_invoker.set_input(m_input_names.at(tv), rtv->tensor());
}
}
std::size_t output_count = 0;
for (const auto& result : m_func->get_results())
{
for (std::size_t idx = 0; idx < result->get_output_size(); ++idx)
{
descriptor::Tensor* tv = result->get_output_tensor_ptr(idx).get();
auto rtv = dynamic_cast<PlaidML_Tensor*>(outputs[output_count++].get());
if (!rtv)
{
throw std::runtime_error{
"The PlaidML backend only operations on PlaidML tensor views"};
}
NGRAPH_DEBUG << "Binding output " << m_output_names.at(tv) << " to tensor " << rtv;
m_invoker.set_output(m_output_names.at(tv), rtv->tensor());
}
}
NGRAPH_DEBUG << "Invoking PlaidML function " << this;
m_invoker.invoke();
m_bound = true;
output_count = 0;
for (const auto& result : m_func->get_results())
{
for (std::size_t idx = 0; idx < result->get_output_size(); ++idx)
{
auto rtv = dynamic_cast<PlaidML_Tensor*>(outputs[output_count++].get());
if (!rtv)
{
throw std::runtime_error{
"The PlaidML backend only operations on PlaidML tensor views"};
}
rtv->sync_output();
}
}
return true;
}
void ngraph::runtime::plaidml::CompiledFunction::save(const std::string& filename,
plaidml_file_format format) const
{
std::lock_guard<std::mutex> lock{m_mu};
if (!m_bound)
{
for (const auto& param : m_func->get_parameters())
{
for (std::size_t idx = 0; idx < param->get_output_size(); ++idx)
{
descriptor::Tensor* tv = param->get_output_tensor_ptr(idx).get();
auto tensor = m_config->dev->allocate(
to_plaidml(m_config->ctx, tv->get_element_type(), tv->get_shape()));
m_invoker.set_input(m_input_names.at(tv), tensor);
}
}
for (const auto& result : m_func->get_results())
{
for (std::size_t idx = 0; idx < result->get_output_size(); ++idx)
{
descriptor::Tensor* tv = result->get_output_tensor_ptr(idx).get();
auto tensor = m_config->dev->allocate(
to_plaidml(m_config->ctx, tv->get_element_type(), tv->get_shape()));
m_invoker.set_output(m_output_names.at(tv), tensor);
}
}
m_bound = true;
}
m_invoker.save(filename, format);
}
//*****************************************************************************
// Copyright 2017-2018 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 <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <plaidml/plaidml++.h>
#include "ngraph/function.hpp"
#include "ngraph/runtime/plaidml/plaidml_config.hpp"
#include "ngraph/runtime/tensor.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
struct Build;
class CompiledFunction;
}
}
}
// A PlaidML compiled function object produced by compiling an nGraph function.
class ngraph::runtime::plaidml::CompiledFunction final
{
public:
CompiledFunction(Build build);
bool schedule_invocation(const std::vector<std::shared_ptr<runtime::Tensor>>& inputs,
const std::vector<std::shared_ptr<runtime::Tensor>>& outputs) const;
void save(const std::string& filename, plaidml_file_format format) const;
private:
mutable std::mutex m_mu; // Locks the invoker while scheduling invocations.
mutable bool m_bound = false;
Config* m_config;
std::shared_ptr<Function> m_func;
std::unordered_map<descriptor::Tensor*, std::string> m_input_names;
std::unordered_map<descriptor::Tensor*, std::string> m_output_names;
mutable vertexai::plaidml::invoker m_invoker;
};
//*****************************************************************************
// Copyright 2017-2018 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/plaidml/plaidml_compiler.hpp"
#include "ngraph/log.hpp"
#include "ngraph/pass/algebraic_simplification.hpp"
#include "ngraph/pass/core_fusion.hpp"
#include "ngraph/pass/cse.hpp"
#include "ngraph/pass/get_output_element_elimination.hpp"
#include "ngraph/pass/like_replacement.hpp"
#include "ngraph/pass/liveness.hpp"
#include "ngraph/pass/nop_elimination.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
#include "ngraph/runtime/plaidml/plaidml_logger.hpp"
namespace
{
void write_debug(const ngraph::Node& op)
{
PLAIDML_DEBUG << "Node: name=\"" << op.get_name() << "\" desc=\"" << op.description()
<< "\"";
for (const auto& op_input : op.get_inputs())
{
ngraph::descriptor::Tensor* tensor = op_input.get_output().get_tensor_ptr().get();
PLAIDML_DEBUG << "Input: descriptor::Tensor " << tensor << " "
<< op.get_input_shape(op_input.get_index());
}
for (std::size_t out_idx = 0; out_idx < op.get_output_size(); ++out_idx)
{
ngraph::descriptor::Tensor* tensor = op.get_output_tensor_ptr(out_idx).get();
PLAIDML_DEBUG << "Output: descriptor::Tensor " << tensor << " "
<< op.get_output_shape(out_idx);
}
for (auto* t : op.liveness_new_list)
{
PLAIDML_DEBUG << "New tensor: " << t;
}
for (auto* t : op.liveness_free_list)
{
PLAIDML_DEBUG << "Retire tensor: " << t;
}
}
}
ngraph::runtime::plaidml::Compiler::Compiler(Config* config)
: m_config{config}
{
// We apply the same general-purposes passes as the CPU backend.
m_pass_manager.register_pass<ngraph::pass::LikeReplacement>();
m_pass_manager.register_pass<ngraph::pass::NopElimination>();
m_pass_manager.register_pass<ngraph::pass::AlgebraicSimplification>();
m_pass_manager.register_pass<ngraph::pass::CommonSubexpressionElimination>();
m_pass_manager.register_pass<ngraph::pass::CoreFusion>();
// N.B. We'd like to register ngraph::pass::GetOutputElementElimination, but it breaks BatchNorm
// backprop
m_pass_manager.register_pass<ngraph::pass::Liveness>();
}
std::shared_ptr<ngraph::runtime::plaidml::CompiledFunction>
ngraph::runtime::plaidml::Compiler::compile(std::shared_ptr<Function> func)
{
m_pass_manager.run_passes(func);
Build b;
build(std::move(func), &b);
return std::make_shared<CompiledFunction>(std::move(b));
}
void ngraph::runtime::plaidml::Compiler::build(std::shared_ptr<Function> func, Build* b)
{
b->compiler = this;
b->config = m_config;
b->func = func;
const auto* op_map = OpImplMap();
for (const auto& op_ptr : func->get_ordered_ops())
{
const ngraph::Node* op = op_ptr.get();
if (m_config->debug)
{
write_debug(*op);
}
auto it = op_map->find(std::type_index(typeid(*op)));
if (it == op_map->end())
{
throw unsupported_op{
std::string{"The PlaidML backend doesn't currently implement the '"} +
op->description() + "' operation"};
}
it->second(b, *op);
}
}
//*****************************************************************************
// Copyright 2017-2018 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 <memory>
#include <plaidml/plaidml++.h>
#include "ngraph/function.hpp"
#include "ngraph/pass/manager.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiled_function.hpp"
#include "ngraph/runtime/plaidml/plaidml_config.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
struct Build;
class Compiler;
}
}
}
// Compiles nGraph operation graphs (functions).
class ngraph::runtime::plaidml::Compiler final
{
public:
Compiler(Config* config);
std::shared_ptr<CompiledFunction> compile(std::shared_ptr<Function> func);
void build(std::shared_ptr<Function> func, Build* build);
private:
Config* m_config;
ngraph::pass::Manager m_pass_manager;
};
//*****************************************************************************
// Copyright 2017-2018 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 <cstring>
#include <sstream>
#include "ngraph/log.hpp"
#include "ngraph/runtime/plaidml/plaidml_config.hpp"
#include "ngraph/runtime/plaidml/plaidml_logger.hpp"
namespace v = vertexai;
namespace vp = vertexai::plaidml;
extern "C" void vai_internal_set_vlog(std::size_t num);
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
namespace
{
vp::device get_device(const std::shared_ptr<vertexai::ctx>& ctx,
std::size_t device_idx)
{
auto dev_configs = vp::enumerate_devices(ctx);
if (!dev_configs.size())
{
throw std::runtime_error{"Unable to find any PlaidML devices"};
}
if (dev_configs.size() <= device_idx)
{
throw std::runtime_error{"Device index out of range"};
}
return dev_configs[device_idx].open();
}
void list_devices(const std::shared_ptr<vertexai::ctx>& ctx)
{
auto dev_configs = vp::enumerate_devices(ctx);
if (!dev_configs.size())
{
NGRAPH_WARN << "No PlaidML devices found";
return;
}
NGRAPH_INFO << "PlaidML Devices:";
for (std::size_t idx = 0; idx < dev_configs.size(); ++idx)
{
const auto& config = dev_configs[idx];
NGRAPH_INFO << "\t" << idx << ": " << config.id() << ": "
<< config.description();
}
}
}
}
}
}
ngraph::runtime::plaidml::Config
ngraph::runtime::plaidml::parse_config_string(const char* configuration_string)
{
bool err = false;
bool help = false;
bool list = false;
bool debug = false;
std::size_t device_idx = 0;
std::string eventlog_config;
#ifdef NGRAPH_DEBUG_ENABLE
debug = true;
#endif
// To visualize what's going on here, here's a configuration string fragment:
//
// ,option_name=option_value,
// ^ ^^ ^
// oname_begin || |
// oname_end| |
// oval_begin |
// oval_end
//
// When there is no option value, here's where the pointers go:
//
// ,option_name,
// ^ ^
// oname_begin |
// oname_end
// oval_begin
// oval_end
const char* c = configuration_string;
while (*c && *c != ':')
{
++c;
}
// Before the options, we have an optional device index.
if (*c)
{
char* dev_end;
std::size_t explicit_idx = std::strtoul(c + 1, &dev_end, 10);
if (dev_end != c + 1)
{
device_idx = explicit_idx;
c = dev_end;
}
}
while (*c)
{
// Invariant: c points to the character introducing the current option.
const char* oname_begin = c + 1;
// Invariant: oname_begin points to the first character of the option name.
const char* oname_end = oname_begin;
while (*oname_end && *oname_end != '=' && *oname_end != ',')
{
++oname_end;
}
// Invariant: [oname_begin, oname_end) is the option name.
const char* oval_begin = oname_end;
if (*oval_begin == '=')
{
++oval_begin;
}
const char* oval_end = oval_begin;
while (*oval_end && *oval_end != ',')
{
++oval_end;
}
// Invariant: [oval_begin, oval_end) is the option value.
// Re-establish initial invariant, allowing "continue" to resume the loop.
c = oval_end;
// Readability definitions
auto is_opt = [=](const char* opt) {
auto len = strlen(opt);
return (oname_end - oname_begin == len) && !strncmp(oname_begin, opt, len);
};
auto oval_len = oval_end - oval_begin;
bool has_oval = oval_begin != oname_end;
// N.B. oval_len != 0 => has_oval, but there's no other relationship.
// So to verify that there is a non-zero-length option value, test oval_len
// To verify that there is no option value, test has_oval
// Check for verbosity
if (is_opt("v"))
{
if (!oval_len)
{
throw std::invalid_argument{"PlaidML verbosity level requires a value"};
}
char* val_end;
std::size_t vlog = std::strtoul(oval_begin, &val_end, 10);
if (oval_end != val_end)
{
throw std::invalid_argument{"Invalid PlaidML verbosity level"};
}
debug = true;
vai_internal_set_vlog(vlog);
continue;
}
// Check for help
if (is_opt("help"))
{
help = true;
continue;
}
// Check for PlaidML debugging
if (is_opt("debug"))
{
debug = true;
continue;
}
// Check for list_devices
if (is_opt("list_devices"))
{
if (has_oval)
{
throw std::invalid_argument{"PlaidML list_devices does not take a value"};
}
list = true;
continue;
}
// Check for eventlog
if (is_opt("eventlog"))
{
if (!oval_len)
{
throw std::invalid_argument{"PlaidML eventlog requires a value"};
}
std::ostringstream e;
e << "{\"@type\": "
"\"type.vertex.ai/vertexai.eventing.file.proto.EventLog\", "
"\"filename\": \"";
for (const char* oc = oval_begin; oc < oval_end; ++oc)
{
if (!isalnum(*oc))
{
e << '\\';
}
e << *oc;
}
e << "\"}";
eventlog_config = e.str();
continue;
}
// Reject unknown options
err = true;
}
constexpr char help_text[] =
"PlaidML Backend Specification: \""
"PlaidML[:[device_index][,debug][,help][,list_devices][,"
"eventlog=<filename>]]\". For example: \"PlaidML\", \""
"PlaidML:0,list_devices\"";
if (err)
{
NGRAPH_ERR << help_text;
throw std::invalid_argument{"Invalid parameter supplied to PlaidML backend"};
}
if (help)
{
NGRAPH_INFO << help_text;
}
// Ensure process-level logging callbacks are in place.
configure_plaidml_logger(debug);
// Build the PlaidML configuration.
Config result;
result.ctx = std::make_shared<vertexai::ctx>();
if (eventlog_config.length())
{
v::vai_exception::check_and_throw(
vai_set_eventlog(result.ctx->get_ctx(), eventlog_config.c_str()));
}
if (list)
{
list_devices(result.ctx);
}
result.dev = std::make_shared<vertexai::plaidml::device>(get_device(result.ctx, device_idx));
result.debug = debug;
return result;
}
//*****************************************************************************
// Copyright 2017-2018 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 <plaidml/plaidml++.h>
#include <memory>
#include <string>
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
struct Config;
Config parse_config_string(const char* configuration_string);
}
}
}
struct ngraph::runtime::plaidml::Config
{
std::shared_ptr<vertexai::ctx> ctx;
std::shared_ptr<vertexai::plaidml::device> dev;
bool debug;
};
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2018 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_diff.hpp"
#include "ngraph/runtime/plaidml/plaidml_builder.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/strides.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
class ConvPoolFormatter;
}
}
}
class ngraph::runtime::plaidml::ConvPoolFormatter
{
public:
enum class OpType
{
Conv,
MaxPool,
AvgPool
};
enum class DerivType
{
None,
Data,
Filter
};
// TODO: Data dilation?
// TODO: Types for the dimensional data?
// Convolution-style constructor
ConvPoolFormatter(std::size_t rank,
const ngraph::CoordinateDiff& pad_below,
const ngraph::CoordinateDiff& pad_above,
const ngraph::Strides& strides,
const ngraph::Strides& filter_dilation,
const ngraph::Strides& data_dilation,
ConvPoolFormatter::OpType op,
ConvPoolFormatter::DerivType deriv,
const ngraph::Shape& deriv_output_shape = Shape());
// Pool-style constructor
ConvPoolFormatter(std::size_t rank,
const ngraph::CoordinateDiff& pad_below,
const ngraph::CoordinateDiff& pad_above,
const ngraph::Strides& strides,
const ngraph::Shape& window_shape,
ConvPoolFormatter::OpType op,
ConvPoolFormatter::DerivType deriv);
// Formatted tensors
builder::Input F_in_header(vertexai::plaidml::variable var);
builder::Input I_in_header(vertexai::plaidml::variable var);
builder::Input O_in_header(vertexai::plaidml::variable var);
builder::Output F_out_header();
builder::Output I_out_header();
builder::Output O_out_header();
builder::ContractionOutput F_out_body();
builder::ContractionOutput I_out_body();
builder::ContractionOutput O_out_body();
builder::ContractionInput F_in_body();
builder::ContractionInput I_in_body();
builder::ContractionInput O_in_body();
// Special Operations
builder::UnaryContraction Broadcast_Ones();
builder::UnaryContraction Count();
builder::UnaryContraction PoolContraction();
builder::TernaryContraction PoolDerivContraction();
// Index names / formulas
std::string c();
std::string ci();
std::string co();
std::string n();
std::vector<std::string> xfs();
std::vector<std::string> xis();
std::vector<std::string> xos();
// Dimension names / formulas
std::string C();
std::string CI();
std::string CO();
std::string N();
std::vector<std::string> XFs();
std::vector<std::string> XIs();
std::vector<std::string> XOs();
// Tensor names
std::string F();
std::string I();
std::string O();
private:
std::size_t m_rank;
ngraph::CoordinateDiff m_pad_below;
ngraph::CoordinateDiff m_pad_above;
ngraph::Strides m_strides;
ngraph::Strides m_filter_dilation;
ngraph::Strides m_data_dilation;
ngraph::Shape m_window_shape;
OpType m_op = OpType::Conv;
DerivType m_deriv = DerivType::None;
ngraph::Shape m_filters_shape;
ngraph::Shape m_data_batch_shape;
std::vector<std::string> m_xfs;
std::vector<std::string> m_xis;
std::vector<std::string> m_xos;
std::vector<std::string> m_XFs;
std::vector<std::string> m_XIs;
std::vector<std::string> m_XOs;
};
//*****************************************************************************
// Copyright 2017-2018 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/plaidml/plaidml_impl.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
std::unordered_map<std::type_index, std::function<void(Build*, const ngraph::Node&)>>*
OpImplMap()
{
static std::unordered_map<std::type_index,
std::function<void(Build*, const ngraph::Node&)>>
op_impl_map;
return &op_impl_map;
}
}
}
}
//*****************************************************************************
// Copyright 2017-2018 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 <sstream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <utility>
#include "ngraph/runtime/plaidml/plaidml_build.hpp"
#include "ngraph/runtime/plaidml/plaidml_builder.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
// PlaidML Operation implementation support.
//
// To add a new operation:
// 1) Include the operation header
// 2) Write the per-operation implementation definition
// 3) Register the operation type, by instantiating Impl<op::OpClass>::Registration at
// global scope.
//
// Operation implementation definitions have access to all methods and member variables
// of the general Impl template.
// The accessor for the global operation handler map.
std::unordered_map<std::type_index, std::function<void(Build*, const ngraph::Node&)>>*
OpImplMap();
// BaseImpl provides a context for operation interpretation, and provides a few useful
// utility methods.
template <typename O>
class BaseImpl
{
public:
BaseImpl(Build* build, const O& op)
: m_build{build}
, m_op{op}
{
}
protected:
Build* build() { return m_build; }
const O& op() { return m_op; }
// Returns the indicated operation input as a PlaidML variable.
vertexai::plaidml::variable
op_input(std::size_t idx,
TensorContents as_contents = TensorContents::DATA) const
{
const auto& ti = m_build->bindings.at(
m_op.get_inputs()[idx].get_output().get_tensor_ptr().get());
if (as_contents == TensorContents::DATA &&
ti.contents == TensorContents::LOGICAL)
{
return plaidml_logical_to_data(ti.var, m_build->config->debug);
}
return ti.var;
}
// Returns the 0th operation input as a PlaidML variable.
vertexai::plaidml::variable op_input() const
{
return op_input(0, TensorContents::DATA);
}
// Validates that the number of operation inputs matches the expected operation
// input count.
void check_inputs(std::size_t expected_input_count) const
{
if (m_op.get_input_size() != expected_input_count)
{
std::ostringstream os;
os << "The PlaidML nGraph backend only supports " << m_op.description()
<< " operations with an input count == " << expected_input_count
<< " (got " << m_op.get_input_size() << " inputs)";
throw std::runtime_error{os.str()};
}
}
// Validates that the number of operation inputs is greater than or equal to the
// expected operation input count.
void check_inputs_ge(std::size_t minimum_input_count) const
{
if (m_op.get_input_size() < minimum_input_count)
{
std::ostringstream os;
os << "The PlaidML nGraph backend only supports " << m_op.description()
<< " operations with an input count >= " << minimum_input_count
<< " (got " << m_op.get_input_size() << " inputs)";
throw std::runtime_error{os.str()};
}
}
// Validates that the number of operation outputs matches the expected operation
// output count.
void check_outputs(std::size_t expected_output_count) const
{
if (m_op.get_output_size() != expected_output_count)
{
std::ostringstream os;
os << "The PlaidML nGraph backend only supports " << m_op.description()
<< " operations with an output count == " << expected_output_count
<< " (got " << m_op.get_output_size() << " outputs)";
throw std::runtime_error{os.str()};
}
}
// Binds the indicated operation output to the supplied PlaidML variable.
void set_output(std::size_t idx,
vertexai::plaidml::variable var,
TensorContents contents = TensorContents::DATA)
{
m_build->bindings.emplace(m_op.get_output_tensor_ptr(idx).get(),
TensorInfo{std::move(var), contents});
}
// Binds the 0th operation output to the supplied PlaidML variable.
void set_output(vertexai::plaidml::variable var,
TensorContents contents = TensorContents::DATA)
{
m_build->bindings.emplace(m_op.get_output_tensor_ptr().get(),
TensorInfo{std::move(var), contents});
}
// Gets a useful name for the current op.
std::string get_op_name() const { return this->m_op.description(); }
// Starts a Tile function builder.
builder::Function start_tile_function() const
{
return builder::Function{get_op_name(), m_build->config->debug};
}
private:
Build* m_build;
const O& m_op;
};
// ParentImpl sets the base implementation class for a particular operation class; the
// Impl template uses this to figure out which class to derive from when implementing a
// particular operation. This is meant to be specialized as needed.
template <typename O>
struct ParentImpl
{
using Type = BaseImpl<O>;
};
// Impl is the common operation implementation class. It declares an operator(), to be
// subsequently defined with the implementation for the particular operation.
//
// Operations that do require extensions may derive their common class from BaseImpl,
// and pass it to the Impl template. Alternatively, they may specialize the Impl
// template, replacing it with their own implementation.
template <typename O>
class Impl : public ParentImpl<O>::Type
{
public:
Impl(Build* build, const O& op)
: ParentImpl<O>::Type{build, op}
{
}
void operator()();
static void handler(Build* build, const ngraph::Node& node)
{
Impl<O>(build, dynamic_cast<const O&>(node))();
}
// Registration handles the registration of a particular operation implementation.
// To use it, instantiate a variable of type Impl<op::OpClass>::Registration at
// global scope.
class Registration
{
public:
Registration()
{
OpImplMap()->emplace(std::type_index{typeid(O)}, &Impl<O>::handler);
}
};
};
}
}
}
//*****************************************************************************
// Copyright 2017-2018 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 <plaidml/plaidml++.h>
#include "ngraph/log.hpp"
#include "ngraph/runtime/plaidml/plaidml_logger.hpp"
namespace
{
void logger(void* debug, vai_log_severity severity, const char* message)
{
switch (severity)
{
case VAI_LOG_SEVERITY_VERBOSE:
case VAI_LOG_SEVERITY_TRACE:
case VAI_LOG_SEVERITY_DEBUG:
if (debug)
{
PLAIDML_DEBUG << message;
}
return;
case VAI_LOG_SEVERITY_INFO:
// We treat PlaidML info-level logs as nGraph debug-level logs, since we expect that
// most nGraph users think of PlaidML details as debugging information.
if (debug)
{
PLAIDML_DEBUG << message;
}
return;
case VAI_LOG_SEVERITY_WARNING: NGRAPH_WARN << message; return;
case VAI_LOG_SEVERITY_ERROR:
default: NGRAPH_ERR << message; return;
}
}
}
void ngraph::runtime::plaidml::configure_plaidml_logger(bool debug)
{
vai_set_logger(&logger, reinterpret_cast<void*>(debug ? 1 : 0));
}
//*****************************************************************************
// Copyright 2017-2018 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/log.hpp"
namespace ngraph
{
namespace runtime
{
namespace plaidml
{
void configure_plaidml_logger(bool debug);
// N.B. This is an unconditional write to the debug log, used when PlaidML debugging is enabled.
#define PLAIDML_DEBUG \
ngraph::LogHelper(ngraph::LOG_TYPE::_LOG_TYPE_DEBUG, \
ngraph::get_file_name(__FILE__), \
__LINE__, \
ngraph::default_logger_handler_func) \
.stream()
}
}
}
//*****************************************************************************
// Copyright 2017-2018 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/abs.hpp"
#include "ngraph/op/add.hpp"
#include "ngraph/op/ceiling.hpp"
#include "ngraph/op/divide.hpp"
#include "ngraph/op/floor.hpp"
#include "ngraph/op/multiply.hpp"
#include "ngraph/op/negative.hpp"
#include "ngraph/op/relu.hpp"
#include "ngraph/op/sigmoid.hpp"
#include "ngraph/op/sign.hpp"
#include "ngraph/op/subtract.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp"
// Abs performs a simple elementwise absolute value.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Abs>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "abs(I)"})
.finalize());
}
// Add performs a simple elementwise addition.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Add>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A + B"})
.finalize());
}
// Ceiling performs a simple elementwise ceiling.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Ceiling>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "ceil(I)"})
.finalize());
}
// Divide performs a simple elementwise division.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Divide>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A / B"})
.finalize());
}
// Floor performs a simple elementwise floor.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Floor>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "floor(I)"})
.finalize());
}
// Multiply performs a simple elementwise multiplication.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Multiply>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A * B"})
.finalize());
}
// Negative performs a simple elementwise negation.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Negative>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "-I"})
.finalize());
}
// Relu implements a simple elementwise rectified linear unit.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Relu>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "relu(I)"})
.finalize());
}
// ReluBackprop computes the derivative of Relu.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::ReluBackprop>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Input{op_input(1), "DO"})
.add(builder::Output{"DI"})
.add(builder::Elementwise{"DI", "I > 0 ? DO : 0"})
.finalize());
}
// Sigmoid computes a standard ML sigmoid: 1/(1+exp(-X))
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Sigmoid>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"O", "1/(1+exp(-I))"})
.finalize());
}
// SigmoidBackprop computes the derivative of a standard ML
// sigmoid: dOutput * sigmoid(X) * (1-sigmoid(X))
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::SigmoidBackprop>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Input{op_input(1), "DO"})
.add(builder::Output{"DI"})
.add(builder::Elementwise{"O", "1/(1+exp(-I))"})
.add(builder::Elementwise{"DI", "DO * O * (1-O)"})
.finalize());
}
// Sign returns the sign of an element.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Sign>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{"S", "(I < 0) ? -1 : ((I > 0) ? 1 : 0)"})
.add(builder::Elementwise{"O", tile_converter("S", op().get_element_type())})
.finalize());
}
// Subtract performs a simple elementwise subtraction.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Subtract>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A - B"})
.finalize());
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Abs>::Registration register_abs;
ngraph::runtime::plaidml::Impl<ngraph::op::Add>::Registration register_add;
ngraph::runtime::plaidml::Impl<ngraph::op::Ceiling>::Registration register_ceiling;
ngraph::runtime::plaidml::Impl<ngraph::op::Divide>::Registration register_divide;
ngraph::runtime::plaidml::Impl<ngraph::op::Floor>::Registration register_floor;
ngraph::runtime::plaidml::Impl<ngraph::op::Multiply>::Registration register_multiply;
ngraph::runtime::plaidml::Impl<ngraph::op::Negative>::Registration register_negative;
ngraph::runtime::plaidml::Impl<ngraph::op::Relu>::Registration register_relu;
ngraph::runtime::plaidml::Impl<ngraph::op::ReluBackprop>::Registration register_relu_backprop;
ngraph::runtime::plaidml::Impl<ngraph::op::Sigmoid>::Registration register_sigmoid;
ngraph::runtime::plaidml::Impl<ngraph::op::SigmoidBackprop>::Registration
register_sigmoid_backprop;
ngraph::runtime::plaidml::Impl<ngraph::op::Sign>::Registration register_sign;
ngraph::runtime::plaidml::Impl<ngraph::op::Subtract>::Registration register_subtract;
}
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2018 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/equal.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/maximum.hpp"
#include "ngraph/op/minimum.hpp"
#include "ngraph/op/not_equal.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Equal performs a simple elementwise equality.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Equal>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0, TensorContents::LOGICAL), "A"})
.add(builder::Input{op_input(1, TensorContents::LOGICAL), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A == B"})
.finalize(),
TensorContents::LOGICAL);
}
// Greater performs a simple elementwise greater-than comparison.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Greater>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A > B"})
.finalize(),
TensorContents::LOGICAL);
}
// GreaterEq performs a simple elementwise greater-than-or-equal-to comparison.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::GreaterEq>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A >= B"})
.finalize(),
TensorContents::LOGICAL);
}
// Less performs a simple elementwise less-than comparison.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Less>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A < B"})
.finalize(),
TensorContents::LOGICAL);
}
// LessEq performs a simple elementwise less-than-or-equal-to comparison.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::LessEq>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A <= B"})
.finalize(),
TensorContents::LOGICAL);
}
// Maximum performs a simple elementwise maximum.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Maximum>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "max(A, B)"})
.finalize());
}
// Minimum performs a simple elementwise minimum.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Minimum>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0), "A"})
.add(builder::Input{op_input(1), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "min(A, B)"})
.finalize());
}
// NotEqual performs a simple elementwise not-equality.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::NotEqual>::operator()()
{
check_inputs(2);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(0, TensorContents::LOGICAL), "A"})
.add(builder::Input{op_input(1, TensorContents::LOGICAL), "B"})
.add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A != B"})
.finalize(),
TensorContents::LOGICAL);
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Equal>::Registration register_equal;
ngraph::runtime::plaidml::Impl<ngraph::op::Greater>::Registration register_greater;
ngraph::runtime::plaidml::Impl<ngraph::op::GreaterEq>::Registration register_greater_eq;
ngraph::runtime::plaidml::Impl<ngraph::op::Less>::Registration register_less;
ngraph::runtime::plaidml::Impl<ngraph::op::LessEq>::Registration register_less_eq;
ngraph::runtime::plaidml::Impl<ngraph::op::Maximum>::Registration register_maximum;
ngraph::runtime::plaidml::Impl<ngraph::op::Minimum>::Registration register_minimum;
ngraph::runtime::plaidml::Impl<ngraph::op::NotEqual>::Registration register_not_equal;
}
//*****************************************************************************
// Copyright 2017-2018 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/concat.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Concat views a tensor as a new type.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Concat>::operator()()
{
check_outputs(1);
auto f = start_tile_function();
f.add(builder::Output{"O"});
std::size_t dim_count = op().get_shape().size();
std::ostringstream offset;
std::ostringstream oexpr;
std::ostringstream concat_dsize;
bool saw_non_zero_tensor = false;
for (std::size_t iidx = 0; iidx < op().get_inputs().size(); ++iidx)
{
if (!shape_size(op().get_input_shape(iidx)))
{
continue;
}
if (saw_non_zero_tensor)
{
concat_dsize << "+";
}
saw_non_zero_tensor = true;
concat_dsize << "I" << iidx << "_D" << op().get_concatenation_axis();
}
saw_non_zero_tensor = false;
for (std::size_t iidx = 0; iidx < op().get_inputs().size(); ++iidx)
{
if (!shape_size(op().get_input_shape(iidx)))
{
continue;
}
std::string sidx{std::to_string(iidx)};
f.add(builder::Input{op_input(iidx), "I" + sidx}.add_dims("I" + sidx + "_D", 0, dim_count));
f.add(builder::UnaryContraction{"="}
.set(builder::ContractionOutput{"E" + sidx}
.add_dims([&](std::back_insert_iterator<std::list<std::string>> out) {
for (std::size_t idx = 0; idx < dim_count; ++idx)
{
std::ostringstream s;
if (idx == op().get_concatenation_axis())
{
out = concat_dsize.str();
}
else
{
s << "I" << iidx << "_D" << idx;
out = s.str();
}
}
})
.add_indices([&](std::back_insert_iterator<std::list<std::string>> out) {
for (std::size_t idx = 0; idx < dim_count; ++idx)
{
std::ostringstream s;
s << "d" << idx;
if (saw_non_zero_tensor && idx == op().get_concatenation_axis())
{
s << " + " << offset.str();
}
out = s.str();
}
}))
.set(builder::ContractionInput{"I" + sidx}.add_indices("d", 0, dim_count)));
if (saw_non_zero_tensor)
{
oexpr << " + ";
offset << " + ";
}
oexpr << "E" << sidx;
offset << "I" << iidx << "_D" << op().get_concatenation_axis();
saw_non_zero_tensor = true;
}
f.add(builder::Elementwise{"O", oexpr.str()});
set_output(f.finalize());
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Concat>::Registration register_concat;
}
//*****************************************************************************
// Copyright 2017-2018 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/convert.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp"
// Convert views a tensor as a new type.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Convert>::operator()()
{
check_inputs(1);
check_outputs(1);
set_output(start_tile_function()
.add(builder::Input{op_input(), "I"})
.add(builder::Output{"O"})
.add(builder::Elementwise{
"O", tile_converter("I", to_plaidml(op().get_convert_element_type()))})
.finalize());
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Convert>::Registration register_convert;
}
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2018 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 <sstream>
#include "ngraph/log.hpp"
#include "ngraph/op/dot.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Dot is a generalized dot product operation -- scalar-tensor,
// matrix-vector, and matrix multiplication.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Dot>::operator()()
{
check_inputs(2);
check_outputs(1);
auto l_dim_limit = op().get_inputs()[0].get_shape().size();
auto r_dim_limit = op().get_inputs()[1].get_shape().size();
auto reduce_limit = op().get_reduction_axes_count();
auto l_dim_mac = l_dim_limit - reduce_limit;
auto r_dim_mic = reduce_limit;
NGRAPH_DEBUG << "l_dim_limit=" << l_dim_limit;
NGRAPH_DEBUG << "r_dim_limit=" << r_dim_limit;
NGRAPH_DEBUG << "reduce_limit=" << reduce_limit;
NGRAPH_DEBUG << "l_dim_mac=" << l_dim_mac;
NGRAPH_DEBUG << "r_dim_mic=" << r_dim_mic;
set_output(start_tile_function()
.add(builder::Input{op_input(0), "L"}
.add_dims("DL", 1, l_dim_mac + 1)
.add_dims("DC", 1, reduce_limit + 1))
.add(builder::Input{op_input(1), "R"}
.add_dims("DC", 1, reduce_limit + 1)
.add_dims("DR", r_dim_mic + 1, r_dim_limit + 1))
.add(builder::Output{"O"})
.add(builder::BinaryContraction{"+", "*"}
.set(builder::ContractionOutput{"O"}
.add_indices("dl", 1, l_dim_mac + 1)
.add_indices("dr", r_dim_mic + 1, r_dim_limit + 1)
.add_dims("DL", 1, l_dim_mac + 1)
.add_dims("DR", r_dim_mic + 1, r_dim_limit + 1))
.set_lhs(builder::ContractionInput{"L"}
.add_indices("dl", 1, l_dim_mac + 1)
.add_indices("dc", 1, reduce_limit + 1))
.set_rhs(builder::ContractionInput{"R"}
.add_indices("dc", 1, reduce_limit + 1)
.add_indices("dr", r_dim_mic + 1, r_dim_limit + 1)))
.finalize());
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Dot>::Registration register_dot;
}
//*****************************************************************************
// Copyright 2017-2018 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/function_call.hpp"
#include "ngraph/runtime/plaidml/plaidml_build.hpp"
#include "ngraph/runtime/plaidml/plaidml_compiler.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// FunctionCall invokes a sub-function.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::FunctionCall>::operator()()
{
Build b;
build()->compiler->build(op().get_functions()[0], &b);
vertexai::plaidml::function f{b.composer};
vertexai::plaidml::function::parameters_t inputs;
for (std::size_t idx = 0; idx < op().get_input_size(); ++idx)
{
auto* oitv = op().get_inputs()[idx].get_output().get_tensor_ptr().get();
auto* iitv = b.func->get_parameters()[idx]->get_outputs()[0].get_tensor_ptr().get();
inputs.emplace_back(b.input_names.at(iitv), build()->bindings.at(oitv).var);
}
vertexai::plaidml::application app{f.apply(inputs)};
for (std::size_t idx = 0; idx < op().get_output_size(); ++idx)
{
auto* iotv = b.func->get_results()[idx]->get_output_tensor_ptr().get();
set_output(idx, app.get_output(b.output_names[iotv]));
}
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::FunctionCall>::Registration register_function_call;
}
This diff is collapsed.
This diff is collapsed.
//*****************************************************************************
// Copyright 2017-2018 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/parameter.hpp"
#include "ngraph/op/result.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
namespace vp = vertexai::plaidml;
// Parameter binds a descriptor::Tensor to a PlaidML Placeholder.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Parameter>::operator()()
{
check_inputs(0);
check_outputs(1);
vp::placeholder ph{build()->io_dim_override ? build()->io_dim_override_count
: op().get_output_shape(0).size()};
std::string name = std::string{"I"} + std::to_string(build()->input_names.size());
descriptor::Tensor* tv = op().get_output_tensor_ptr().get();
build()->bindings.emplace(tv, TensorInfo{ph, TensorContents::DATA});
build()->composer.input(name, ph);
build()->input_names.emplace(tv, std::move(name));
}
// Result binds a PlaidML variable to a composed function output.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Result>::operator()()
{
check_inputs(1);
check_outputs(1);
std::string name = std::string{"O"} + std::to_string(build()->output_names.size());
descriptor::Tensor* tv = op().get_output_tensor_ptr().get();
build()->composer.output(name, op_input());
build()->output_names.emplace(tv, std::move(name));
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::Parameter>::Registration register_parameter;
ngraph::runtime::plaidml::Impl<ngraph::op::Result>::Registration register_result;
}
//*****************************************************************************
// Copyright 2017-2018 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/lrn.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// LRN implements Local Response Normalization
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::LRN>::operator()()
{
check_inputs(1);
check_outputs(1);
auto dim_limit = op().get_inputs()[0].get_shape().size();
auto rank = dim_limit - 2;
auto distance = op().get_nsize() / 2;
std::ostringstream div_expr;
div_expr << "I / pow(" << op().get_bias() << ".0 + ((" << op().get_alpha() << ".0 / "
<< op().get_nsize() << ".0) * S), " << op().get_beta() << ".0)";
set_output(
start_tile_function()
.add(builder::Input{op_input(), "I"}.add_dims({"N", "C"}).add_dims("D", 0, rank))
.add(builder::Output{"O"})
.add(builder::Elementwise{"ISQ", "I * I"})
.add(builder::UnaryContraction{"+"}
.set(builder::ContractionOutput{"S"}
.add_indices({"n", "c"})
.add_indices("d", 0, rank)
.add_dims({"N", "C"})
.add_dims("D", 0, rank))
.set(builder::ContractionInput{"ISQ"}
.add_indices({"n", "c + z - " + std::to_string(distance)})
.add_indices("d", 0, rank))
.add_constraints([&](std::back_insert_iterator<std::list<std::string>> out) {
out = "z < " + std::to_string(op().get_nsize());
}))
.add(builder::Elementwise{"O", div_expr.str()})
.finalize());
}
namespace
{
ngraph::runtime::plaidml::Impl<ngraph::op::LRN>::Registration register_local_response_norm;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -15,6 +15,7 @@
# ******************************************************************************
add_subdirectory(nbench)
add_subdirectory(ngraph-to-plaidml)
add_subdirectory(reserialize)
if (NGRAPH_ONNX_IMPORT_ENABLE)
add_subdirectory(serialize_onnx)
......
......@@ -34,5 +34,8 @@ endif()
if (NGRAPH_INTERPRETER_ENABLE)
target_link_libraries(nbench interpreter_backend)
endif()
if (NGRAPH_PLAIDML_ENABLE)
target_link_libraries(nbench plaidml_backend)
endif()
install(TARGETS nbench RUNTIME DESTINATION ${NGRAPH_INSTALL_BIN})
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment