Commit 61df6725 authored by Rob Earhart's avatar Rob Earhart Committed by Robert Kimball

[PlaidML] Specialize within namespaces (for Linux) (#1948)

parent 5698fa75
...@@ -17,87 +17,101 @@ ...@@ -17,87 +17,101 @@
#include "ngraph/op/concat.hpp" #include "ngraph/op/concat.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Concat views a tensor as a new type. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Concat>::operator()()
{ {
check_outputs(1); namespace runtime
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))) namespace plaidml
{
continue;
}
if (saw_non_zero_tensor)
{ {
concat_dsize << "+"; // Concat views a tensor as a new type.
} template <>
saw_non_zero_tensor = true; void Impl<op::Concat>::operator()()
concat_dsize << "I" << iidx << "_D" << op().get_concatenation_axis(); {
} check_outputs(1);
saw_non_zero_tensor = false; auto f = start_tile_function();
for (std::size_t iidx = 0; iidx < op().get_inputs().size(); ++iidx) f.add(builder::Output{"O"});
{ std::size_t dim_count = op().get_shape().size();
if (!shape_size(op().get_input_shape(iidx))) std::ostringstream offset;
{ std::ostringstream oexpr;
continue; std::ostringstream concat_dsize;
} bool saw_non_zero_tensor = false;
std::string sidx{std::to_string(iidx)}; for (std::size_t iidx = 0; iidx < op().get_inputs().size(); ++iidx)
f.add(builder::Input{op_input(iidx), "I" + sidx}.add_dims("I" + sidx + "_D", 0, dim_count)); {
f.add(builder::UnaryContraction{"="} if (!shape_size(op().get_input_shape(iidx)))
.set(builder::ContractionOutput{"E" + sidx} {
.add_dims([&](std::back_insert_iterator<std::list<std::string>> out) { continue;
for (std::size_t idx = 0; idx < dim_count; ++idx) }
{ if (saw_non_zero_tensor)
std::ostringstream s; {
if (idx == op().get_concatenation_axis()) concat_dsize << "+";
{ }
out = concat_dsize.str(); saw_non_zero_tensor = true;
} concat_dsize << "I" << iidx << "_D" << op().get_concatenation_axis();
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()); 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()});
namespace set_output(f.finalize());
{ }
ngraph::runtime::plaidml::Impl<ngraph::op::Concat>::Registration register_concat;
namespace
{
Impl<op::Concat>::Registration register_concat;
}
}
}
} }
...@@ -18,21 +18,31 @@ ...@@ -18,21 +18,31 @@
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp" #include "ngraph/runtime/plaidml/plaidml_translate.hpp"
// Convert views a tensor as a new type. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Convert>::operator()()
{ {
check_inputs(1); namespace runtime
check_outputs(1); {
set_output(start_tile_function() namespace plaidml
.add(builder::Input{op_input(), "I"}) {
.add(builder::Output{"O"}) // Convert views a tensor as a new type.
.add(builder::Elementwise{ template <>
"O", tile_converter("I", to_plaidml(op().get_convert_element_type()))}) void Impl<op::Convert>::operator()()
.finalize()); {
} 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 namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::Convert>::Registration register_convert; Impl<op::Convert>::Registration register_convert;
}
}
}
} }
...@@ -20,50 +20,60 @@ ...@@ -20,50 +20,60 @@
#include "ngraph/op/dot.hpp" #include "ngraph/op/dot.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Dot is a generalized dot product operation -- scalar-tensor, namespace ngraph
// matrix-vector, and matrix multiplication.
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Dot>::operator()()
{ {
check_inputs(2); namespace runtime
check_outputs(1); {
namespace plaidml
{
// Dot is a generalized dot product operation -- scalar-tensor,
// matrix-vector, and matrix multiplication.
template <>
void Impl<op::Dot>::operator()()
{
check_inputs(2);
check_outputs(1);
auto l_dim_limit = op().get_inputs()[0].get_shape().size(); auto l_dim_limit = op().get_inputs()[0].get_shape().size();
auto r_dim_limit = op().get_inputs()[1].get_shape().size(); auto r_dim_limit = op().get_inputs()[1].get_shape().size();
auto reduce_limit = op().get_reduction_axes_count(); auto reduce_limit = op().get_reduction_axes_count();
auto l_dim_mac = l_dim_limit - reduce_limit; auto l_dim_mac = l_dim_limit - reduce_limit;
auto r_dim_mic = reduce_limit; auto r_dim_mic = reduce_limit;
NGRAPH_DEBUG << "l_dim_limit=" << l_dim_limit; NGRAPH_DEBUG << "l_dim_limit=" << l_dim_limit;
NGRAPH_DEBUG << "r_dim_limit=" << r_dim_limit; NGRAPH_DEBUG << "r_dim_limit=" << r_dim_limit;
NGRAPH_DEBUG << "reduce_limit=" << reduce_limit; NGRAPH_DEBUG << "reduce_limit=" << reduce_limit;
NGRAPH_DEBUG << "l_dim_mac=" << l_dim_mac; NGRAPH_DEBUG << "l_dim_mac=" << l_dim_mac;
NGRAPH_DEBUG << "r_dim_mic=" << r_dim_mic; NGRAPH_DEBUG << "r_dim_mic=" << r_dim_mic;
set_output(start_tile_function() set_output(
.add(builder::Input{op_input(0), "L"} start_tile_function()
.add_dims("DL", 1, l_dim_mac + 1) .add(builder::Input{op_input(0), "L"}
.add_dims("DC", 1, reduce_limit + 1)) .add_dims("DL", 1, l_dim_mac + 1)
.add(builder::Input{op_input(1), "R"} .add_dims("DC", 1, reduce_limit + 1))
.add_dims("DC", 1, reduce_limit + 1) .add(builder::Input{op_input(1), "R"}
.add_dims("DR", r_dim_mic + 1, r_dim_limit + 1)) .add_dims("DC", 1, reduce_limit + 1)
.add(builder::Output{"O"}) .add_dims("DR", r_dim_mic + 1, r_dim_limit + 1))
.add(builder::BinaryContraction{"+", "*"} .add(builder::Output{"O"})
.set(builder::ContractionOutput{"O"} .add(builder::BinaryContraction{"+", "*"}
.add_indices("dl", 1, l_dim_mac + 1) .set(builder::ContractionOutput{"O"}
.add_indices("dr", r_dim_mic + 1, r_dim_limit + 1) .add_indices("dl", 1, l_dim_mac + 1)
.add_dims("DL", 1, l_dim_mac + 1) .add_indices("dr", r_dim_mic + 1, r_dim_limit + 1)
.add_dims("DR", r_dim_mic + 1, r_dim_limit + 1)) .add_dims("DL", 1, l_dim_mac + 1)
.set_lhs(builder::ContractionInput{"L"} .add_dims("DR", r_dim_mic + 1, r_dim_limit + 1))
.add_indices("dl", 1, l_dim_mac + 1) .set_lhs(builder::ContractionInput{"L"}
.add_indices("dc", 1, reduce_limit + 1)) .add_indices("dl", 1, l_dim_mac + 1)
.set_rhs(builder::ContractionInput{"R"} .add_indices("dc", 1, reduce_limit + 1))
.add_indices("dc", 1, reduce_limit + 1) .set_rhs(builder::ContractionInput{"R"}
.add_indices("dr", r_dim_mic + 1, r_dim_limit + 1))) .add_indices("dc", 1, reduce_limit + 1)
.finalize()); .add_indices("dr", r_dim_mic + 1, r_dim_limit + 1)))
} .finalize());
}
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::Dot>::Registration register_dot; Impl<op::Dot>::Registration register_dot;
}
}
}
} }
...@@ -19,29 +19,39 @@ ...@@ -19,29 +19,39 @@
#include "ngraph/runtime/plaidml/plaidml_compiler.hpp" #include "ngraph/runtime/plaidml/plaidml_compiler.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// FunctionCall invokes a sub-function. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::FunctionCall>::operator()()
{ {
Build b; namespace runtime
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(); namespace plaidml
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); // FunctionCall invokes a sub-function.
} template <>
vertexai::plaidml::application app{f.apply(inputs)}; void Impl<op::FunctionCall>::operator()()
for (std::size_t idx = 0; idx < op().get_output_size(); ++idx) {
{ Build b;
auto* iotv = b.func->get_results()[idx]->get_output_tensor_ptr().get(); build()->compiler->build(op().get_functions()[0], &b);
set_output(idx, app.get_output(b.output_names[iotv])); 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 namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::FunctionCall>::Registration register_function_call; Impl<op::FunctionCall>::Registration register_function_call;
}
}
}
} }
...@@ -20,35 +20,44 @@ ...@@ -20,35 +20,44 @@
namespace vp = vertexai::plaidml; namespace vp = vertexai::plaidml;
// Parameter binds a descriptor::Tensor to a PlaidML Placeholder. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Parameter>::operator()()
{ {
check_inputs(0); namespace runtime
check_outputs(1); {
vp::placeholder ph{build()->io_dim_override ? build()->io_dim_override_count namespace plaidml
: op().get_output_shape(0).size()}; {
std::string name = std::string{"I"} + std::to_string(build()->input_names.size()); // Parameter binds a descriptor::Tensor to a PlaidML Placeholder.
descriptor::Tensor* tv = op().get_output_tensor_ptr().get(); template <>
build()->bindings.emplace(tv, TensorInfo{ph, TensorContents::DATA}); void Impl<op::Parameter>::operator()()
build()->composer.input(name, ph); {
build()->input_names.emplace(tv, std::move(name)); 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. // Result binds a PlaidML variable to a composed function output.
template <> template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Result>::operator()() void Impl<op::Result>::operator()()
{ {
check_inputs(1); check_inputs(1);
check_outputs(1); check_outputs(1);
std::string name = std::string{"O"} + std::to_string(build()->output_names.size()); std::string name = std::string{"O"} + std::to_string(build()->output_names.size());
descriptor::Tensor* tv = op().get_output_tensor_ptr().get(); descriptor::Tensor* tv = op().get_output_tensor_ptr().get();
build()->composer.output(name, op_input()); build()->composer.output(name, op_input());
build()->output_names.emplace(tv, std::move(name)); build()->output_names.emplace(tv, std::move(name));
} }
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::Parameter>::Registration register_parameter; Impl<op::Parameter>::Registration register_parameter;
ngraph::runtime::plaidml::Impl<ngraph::op::Result>::Registration register_result; Impl<op::Result>::Registration register_result;
}
}
}
} }
...@@ -17,40 +17,52 @@ ...@@ -17,40 +17,52 @@
#include "ngraph/op/lrn.hpp" #include "ngraph/op/lrn.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// LRN implements Local Response Normalization namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::LRN>::operator()()
{ {
check_inputs(1); namespace runtime
check_outputs(1); {
auto dim_limit = op().get_inputs()[0].get_shape().size(); namespace plaidml
auto rank = dim_limit - 2; {
auto distance = op().get_nsize() / 2; // LRN implements Local Response Normalization
std::ostringstream div_expr; template <>
div_expr << "I / pow(" << op().get_bias() << ".0 + ((" << op().get_alpha() << ".0 / " void Impl<op::LRN>::operator()()
<< op().get_nsize() << ".0) * S), " << op().get_beta() << ".0)"; {
set_output( check_inputs(1);
start_tile_function() check_outputs(1);
.add(builder::Input{op_input(), "I"}.add_dims({"N", "C"}).add_dims("D", 0, rank)) auto dim_limit = op().get_inputs()[0].get_shape().size();
.add(builder::Output{"O"}) auto rank = dim_limit - 2;
.add(builder::Elementwise{"ISQ", "I * I"}) auto distance = op().get_nsize() / 2;
.add(builder::UnaryContraction{"+"} std::ostringstream div_expr;
.set(builder::ContractionOutput{"S"} div_expr << "I / pow(" << op().get_bias() << ".0 + ((" << op().get_alpha()
.add_indices({"n", "c"}) << ".0 / " << op().get_nsize() << ".0) * S), " << op().get_beta() << ".0)";
.add_indices("d", 0, rank) set_output(
.add_dims({"N", "C"}) start_tile_function()
.add_dims("D", 0, rank)) .add(builder::Input{op_input(), "I"}
.set(builder::ContractionInput{"ISQ"} .add_dims({"N", "C"})
.add_indices({"n", "c + z - " + std::to_string(distance)}) .add_dims("D", 0, rank))
.add_indices("d", 0, rank)) .add(builder::Output{"O"})
.add_constraints([&](std::back_insert_iterator<std::list<std::string>> out) { .add(builder::Elementwise{"ISQ", "I * I"})
out = "z < " + std::to_string(op().get_nsize()); .add(builder::UnaryContraction{"+"}
})) .set(builder::ContractionOutput{"S"}
.add(builder::Elementwise{"O", div_expr.str()}) .add_indices({"n", "c"})
.finalize()); .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 namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::LRN>::Registration register_local_response_norm; Impl<op::LRN>::Registration register_local_response_norm;
}
}
}
} }
...@@ -19,53 +19,62 @@ ...@@ -19,53 +19,62 @@
#include "ngraph/op/or.hpp" #include "ngraph/op/or.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// And performs a simple elementwise logical and. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::And>::operator()()
{ {
check_inputs(2); namespace runtime
check_outputs(1); {
set_output(start_tile_function() namespace plaidml
.add(builder::Input{op_input(0, TensorContents::LOGICAL), "A"}) {
.add(builder::Input{op_input(1, TensorContents::LOGICAL), "B"}) // And performs a simple elementwise logical and.
.add(builder::Output{"C"}) template <>
.add(builder::Elementwise{"C", "A ? B : A"}) void Impl<op::And>::operator()()
.finalize(), {
TensorContents::LOGICAL); 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 : A"})
.finalize(),
TensorContents::LOGICAL);
}
// Not performs a simple elementwise logical not. // Not performs a simple elementwise logical not.
template <> template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Not>::operator()() void Impl<op::Not>::operator()()
{ {
check_inputs(1); check_inputs(1);
check_outputs(1); check_outputs(1);
set_output(start_tile_function() set_output(start_tile_function()
.add(builder::Input{op_input(0, TensorContents::LOGICAL), "I"}) .add(builder::Input{op_input(0, TensorContents::LOGICAL), "I"})
.add(builder::Output{"O"}) .add(builder::Output{"O"})
.add(builder::Elementwise{"O", "cmp_eq(I, 0)"}) .add(builder::Elementwise{"O", "cmp_eq(I, 0)"})
.finalize(), .finalize(),
TensorContents::LOGICAL); TensorContents::LOGICAL);
} }
// Or performs a simple elementwise logical or. // Or performs a simple elementwise logical or.
template <> template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Or>::operator()() void Impl<op::Or>::operator()()
{ {
check_inputs(2); check_inputs(2);
check_outputs(1); check_outputs(1);
set_output(start_tile_function() set_output(start_tile_function()
.add(builder::Input{op_input(0, TensorContents::LOGICAL), "A"}) .add(builder::Input{op_input(0, TensorContents::LOGICAL), "A"})
.add(builder::Input{op_input(1, TensorContents::LOGICAL), "B"}) .add(builder::Input{op_input(1, TensorContents::LOGICAL), "B"})
.add(builder::Output{"C"}) .add(builder::Output{"C"})
.add(builder::Elementwise{"C", "A ? A : B"}) .add(builder::Elementwise{"C", "A ? A : B"})
.finalize(), .finalize(),
TensorContents::LOGICAL); TensorContents::LOGICAL);
} }
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::And>::Registration register_and; Impl<op::And>::Registration register_and;
ngraph::runtime::plaidml::Impl<ngraph::op::Not>::Registration register_not; Impl<op::Not>::Registration register_not;
ngraph::runtime::plaidml::Impl<ngraph::op::Or>::Registration register_or; Impl<op::Or>::Registration register_or;
}
}
}
} }
...@@ -20,80 +20,93 @@ ...@@ -20,80 +20,93 @@
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
#include "ngraph/runtime/plaidml/plaidml_translate.hpp" #include "ngraph/runtime/plaidml/plaidml_translate.hpp"
// OneHot performs one-hot encoding along the requested axis. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::OneHot>::operator()()
{ {
check_inputs(1); namespace runtime
check_outputs(1); {
namespace plaidml
{
// OneHot performs one-hot encoding along the requested axis.
template <>
void Impl<op::OneHot>::operator()()
{
check_inputs(1);
check_outputs(1);
// Here's what's going on to implement OneHot: // Here's what's going on to implement OneHot:
// //
// * We reshape the input tensor to add a size=1 dimension where we want the one-hot axis to be, // * We reshape the input tensor to add a size=1 dimension where we want the one-hot axis to be,
// //
// * We create an index tensor that's size=1 on every dimension except the one-hot dimension, // * We create an index tensor that's size=1 on every dimension except the one-hot dimension,
// //
// * We perform an elementwise conditional across them to assign the one-hot values. // * We perform an elementwise conditional across them to assign the one-hot values.
// //
// The broadcast rules will expand the index tensor on all non-one-hot dimensions to match the // The broadcast rules will expand the index tensor on all non-one-hot dimensions to match the
// input, and will expand the input tensor on the one-hot dimension to match the index. // input, and will expand the input tensor on the one-hot dimension to match the index.
// //
// In theory, it'd be pretty easy to implement all this with purely elementwise operations. The // In theory, it'd be pretty easy to implement all this with purely elementwise operations. The
// current definition of index() requires an input tensor of the index() output shape, and it's // current definition of index() requires an input tensor of the index() output shape, and it's
// a little tricky to fix that, so we generate a zero tensor of the correct shape using a // a little tricky to fix that, so we generate a zero tensor of the correct shape using a
// contraction. TODO: Optimize out the zero tensor contraction. // contraction. TODO: Optimize out the zero tensor contraction.
const auto& in_shape = op().get_inputs()[0].get_shape(); const auto& in_shape = op().get_inputs()[0].get_shape();
const auto& out_shape = op().get_shape(); const auto& out_shape = op().get_shape();
std::ostringstream in_reshape; std::ostringstream in_reshape;
for (std::size_t idx = 0; idx < out_shape.size(); ++idx) for (std::size_t idx = 0; idx < out_shape.size(); ++idx)
{ {
if (idx) if (idx)
{ {
in_reshape << ", "; in_reshape << ", ";
} }
if (idx == op().get_one_hot_axis()) if (idx == op().get_one_hot_axis())
{ {
in_reshape << 1; in_reshape << 1;
} }
else else
{ {
in_reshape << out_shape[idx]; in_reshape << out_shape[idx];
} }
} }
set_output( set_output(
start_tile_function() start_tile_function()
.add(builder::Input{op_input(), "I"}.add_dims("D", 0, in_shape.size())) .add(builder::Input{op_input(), "I"}.add_dims("D", 0, in_shape.size()))
.add(builder::Input{static_cast<std::int64_t>(0), "Zero"}) .add(builder::Input{static_cast<std::int64_t>(0), "Zero"})
.add(builder::Output{"O"}) .add(builder::Output{"O"})
.add(builder::UnaryContraction{"="} .add(
.set(builder::ContractionOutput{"ZS"} builder::UnaryContraction{"="}
.add_dims([&](std::back_insert_iterator<std::list<std::string>> out) { .set(
for (std::size_t idx = 0; idx < out_shape.size(); ++idx) builder::ContractionOutput{"ZS"}
{ .add_dims([&](
if (idx == op().get_one_hot_axis()) std::back_insert_iterator<std::list<std::string>> out) {
{ for (std::size_t idx = 0; idx < out_shape.size(); ++idx)
out = std::to_string(out_shape[idx]); {
} if (idx == op().get_one_hot_axis())
else {
{ out = std::to_string(out_shape[idx]);
out = "1"; }
} else
} {
}) out = "1";
.add_indices("d", 0, out_shape.size())) }
.set(builder::ContractionInput{"Zero"})) }
.add(builder::Elementwise{"Idx", })
"index(ZS, " + std::to_string(op().get_one_hot_axis()) + ")"}) .add_indices("d", 0, out_shape.size()))
.add(builder::Elementwise{"IS", "reshape(I, " + in_reshape.str() + ")"}) .set(builder::ContractionInput{"Zero"}))
.add(builder::Elementwise{"OV", "IS == Idx ? 1 : 0"}) .add(builder::Elementwise{
.add(builder::Elementwise{"O", tile_converter("OV", op().get_element_type())}) "Idx", "index(ZS, " + std::to_string(op().get_one_hot_axis()) + ")"})
.finalize()); .add(builder::Elementwise{"IS", "reshape(I, " + in_reshape.str() + ")"})
} .add(builder::Elementwise{"OV", "IS == Idx ? 1 : 0"})
.add(builder::Elementwise{"O",
tile_converter("OV", op().get_element_type())})
.finalize());
}
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::OneHot>::Registration register_one_hot; Impl<op::OneHot>::Registration register_one_hot;
}
}
}
} }
...@@ -19,74 +19,87 @@ ...@@ -19,74 +19,87 @@
#include "ngraph/op/replace_slice.hpp" #include "ngraph/op/replace_slice.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// ReplaceSlice replaces part of a tensor with another tensor. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::ReplaceSlice>::operator()()
{ {
check_inputs(2); namespace runtime
check_outputs(1); {
namespace plaidml
{
// ReplaceSlice replaces part of a tensor with another tensor.
template <>
void Impl<op::ReplaceSlice>::operator()()
{
check_inputs(2);
check_outputs(1);
// For ReplaceSlice: // For ReplaceSlice:
// //
// * Pad the second tensor to match the first (same-size dimensions and offset according to the // * Pad the second tensor to match the first (same-size dimensions and offset according to the
// * lower bounds of the replacement, with the desired stridings) // * lower bounds of the replacement, with the desired stridings)
// //
// * Generate a boolean tensor of the same shape as the first, where true == "Do the // * Generate a boolean tensor of the same shape as the first, where true == "Do the
// * replacement". // * replacement".
// //
// * Use a trinary to do the replacement. // * Use a trinary to do the replacement.
const auto& shape = op().get_shape(); const auto& shape = op().get_shape();
set_output( set_output(
start_tile_function() start_tile_function()
.add(builder::Input{op_input(0), "L"}.add_dims("D", 0, shape.size())) .add(builder::Input{op_input(0), "L"}.add_dims("D", 0, shape.size()))
.add(builder::Input{op_input(1), "S"}.add_dims("SD", 0, shape.size())) .add(builder::Input{op_input(1), "S"}.add_dims("SD", 0, shape.size()))
.add(builder::Output{"O"}) .add(builder::Output{"O"})
.add(builder::UnaryContraction{"="} .add(
.set(builder::ContractionOutput{"O"} builder::UnaryContraction{"="}
.add_dims("D", 0, shape.size()) .set(
.add_indices( builder::ContractionOutput{"O"}
[&](std::back_insert_iterator<std::list<std::string>> out) { .add_dims("D", 0, shape.size())
for (std::size_t idx = 0; idx < shape.size(); ++idx) .add_indices([&](
{ std::back_insert_iterator<std::list<std::string>> out) {
auto stride = op().get_strides()[idx]; for (std::size_t idx = 0; idx < shape.size(); ++idx)
auto lower_bound = op().get_lower_bounds()[idx]; {
std::ostringstream didx; auto stride = op().get_strides()[idx];
if ((stride != 1) && lower_bound) auto lower_bound = op().get_lower_bounds()[idx];
{ std::ostringstream didx;
didx << "("; if ((stride != 1) && lower_bound)
} {
didx << "d" << idx; didx << "(";
if (stride != 1) }
{ didx << "d" << idx;
didx << "*" << stride; if (stride != 1)
} {
if ((stride != 1) && lower_bound) didx << "*" << stride;
{ }
didx << ")"; if ((stride != 1) && lower_bound)
} {
if (lower_bound) didx << ")";
{ }
didx << "+" << lower_bound; if (lower_bound)
} {
out = didx.str(); didx << "+" << lower_bound;
} }
})) out = didx.str();
.set(builder::ContractionInput{"S"}.add_indices("d", 0, shape.size())) }
.add_constraints([&](std::back_insert_iterator<std::list<std::string>> out) { }))
for (std::size_t idx = 0; idx < shape.size(); ++idx) .set(builder::ContractionInput{"S"}.add_indices(
{ "d", 0, shape.size()))
out = "d" + std::to_string(idx) + " < " + .add_constraints(
std::to_string(op().get_upper_bounds()[idx] - [&](std::back_insert_iterator<std::list<std::string>> out) {
op().get_lower_bounds()[idx]); for (std::size_t idx = 0; idx < shape.size(); ++idx)
} {
}) out = "d" + std::to_string(idx) + " < " +
.set_default("L")) std::to_string(op().get_upper_bounds()[idx] -
.finalize()); op().get_lower_bounds()[idx]);
} }
})
.set_default("L"))
.finalize());
}
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::ReplaceSlice>::Registration register_replace_slice; Impl<op::ReplaceSlice>::Registration register_replace_slice;
}
}
}
} }
...@@ -19,41 +19,50 @@ ...@@ -19,41 +19,50 @@
#include "ngraph/op/reverse.hpp" #include "ngraph/op/reverse.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Reverse reverses the selected axes within a tensor. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Reverse>::operator()()
{ {
check_inputs(1); namespace runtime
check_outputs(1); {
namespace plaidml
{
// Reverse reverses the selected axes within a tensor.
template <>
void Impl<op::Reverse>::operator()()
{
check_inputs(1);
check_outputs(1);
const auto& shape = op().get_shape(); const auto& shape = op().get_shape();
set_output(start_tile_function() set_output(start_tile_function()
.add(builder::Input{op_input(), "I"}.add_dims("D", 0, shape.size())) .add(builder::Input{op_input(), "I"}.add_dims("D", 0, shape.size()))
.add(builder::Output{"O"}) .add(builder::Output{"O"})
.add(builder::UnaryContraction{"="} .add(builder::UnaryContraction{"="}
.set(builder::ContractionOutput{"O"} .set(builder::ContractionOutput{"O"}
.add_indices("d", 0, shape.size()) .add_indices("d", 0, shape.size())
.add_dims("D", 0, shape.size())) .add_dims("D", 0, shape.size()))
.set(builder::ContractionInput{"I"}.add_indices( .set(builder::ContractionInput{"I"}.add_indices([&](
[&](std::back_insert_iterator<std::list<std::string>> out) { std::back_insert_iterator<std::list<std::string>> out) {
for (std::size_t idx = 0; idx < shape.size(); ++idx) for (std::size_t idx = 0; idx < shape.size(); ++idx)
{ {
auto sidx = std::to_string(idx); auto sidx = std::to_string(idx);
if (op().get_reversed_axes().count(idx)) if (op().get_reversed_axes().count(idx))
{ {
out = "D" + sidx + "-d" + sidx + "-1"; out = "D" + sidx + "-d" + sidx + "-1";
} }
else else
{ {
out = "d" + sidx; out = "d" + sidx;
} }
} }
}))) })))
.finalize()); .finalize());
} }
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::Reverse>::Registration register_reverse; Impl<op::Reverse>::Registration register_reverse;
}
}
}
} }
...@@ -18,87 +18,100 @@ ...@@ -18,87 +18,100 @@
#include "ngraph/op/slice.hpp" #include "ngraph/op/slice.hpp"
#include "ngraph/runtime/plaidml/plaidml_impl.hpp" #include "ngraph/runtime/plaidml/plaidml_impl.hpp"
// Slice takes a sub-slice of a tensor. namespace ngraph
template <>
void ngraph::runtime::plaidml::Impl<ngraph::op::Slice>::operator()()
{ {
check_inputs(1); namespace runtime
check_outputs(1); {
NGRAPH_DEBUG << "Slice: low: " << op().get_lower_bounds(); namespace plaidml
NGRAPH_DEBUG << "Slice high: " << op().get_upper_bounds(); {
NGRAPH_DEBUG << "Slice stride: " << op().get_strides(); // Slice takes a sub-slice of a tensor.
const auto& shape = op().get_inputs()[0].get_shape(); template <>
auto dim_limit = shape.size(); void Impl<op::Slice>::operator()()
set_output( {
start_tile_function() check_inputs(1);
.add(builder::Input{op_input(), "I"}.add_dims("ID", 0, dim_limit)) check_outputs(1);
.add(builder::Output{"O"}) NGRAPH_DEBUG << "Slice: low: " << op().get_lower_bounds();
.add(builder::UnaryContraction{"="} NGRAPH_DEBUG << "Slice high: " << op().get_upper_bounds();
.set(builder::ContractionOutput{"O"} NGRAPH_DEBUG << "Slice stride: " << op().get_strides();
.add_indices("od", 0, dim_limit) const auto& shape = op().get_inputs()[0].get_shape();
.add_dims([&](std::back_insert_iterator<std::list<std::string>> out) { auto dim_limit = shape.size();
for (std::size_t idx = 0; idx < dim_limit; ++idx) set_output(
{ start_tile_function()
std::ostringstream s; .add(builder::Input{op_input(), "I"}.add_dims("ID", 0, dim_limit))
std::size_t stride = op().get_strides()[idx]; .add(builder::Output{"O"})
std::ptrdiff_t trim_count = .add(
op().get_lower_bounds()[idx] + builder::UnaryContraction{"="}
(shape[idx] - op().get_upper_bounds()[idx]) + 1 - stride; .set(
if ((stride != 1) && trim_count) builder::ContractionOutput{"O"}
{ .add_indices("od", 0, dim_limit)
s << "("; .add_dims([&](
} std::back_insert_iterator<std::list<std::string>> out) {
s << "ID" << idx; for (std::size_t idx = 0; idx < dim_limit; ++idx)
if (0 < trim_count) {
{ std::ostringstream s;
s << " - " << trim_count; std::size_t stride = op().get_strides()[idx];
} std::ptrdiff_t trim_count =
if (trim_count < 0) op().get_lower_bounds()[idx] +
{ (shape[idx] - op().get_upper_bounds()[idx]) +
s << " + " << -trim_count; 1 - stride;
} if ((stride != 1) && trim_count)
if ((stride != 1) && trim_count) {
{ s << "(";
s << ")"; }
} s << "ID" << idx;
if (stride != 1) if (0 < trim_count)
{ {
s << " / " << stride; s << " - " << trim_count;
} }
out = s.str(); if (trim_count < 0)
} {
})) s << " + " << -trim_count;
.set(builder::ContractionInput{"I"}.add_indices( }
[&](std::back_insert_iterator<std::list<std::string>> out) { if ((stride != 1) && trim_count)
for (std::size_t idx = 0; idx < dim_limit; ++idx) {
{ s << ")";
std::ostringstream s; }
std::size_t stride = op().get_strides()[idx]; if (stride != 1)
std::size_t offset = op().get_lower_bounds()[idx]; {
if ((stride != 1) && offset) s << " / " << stride;
{ }
s << "("; out = s.str();
} }
s << "od" << idx; }))
if (stride != 1) .set(builder::ContractionInput{"I"}.add_indices(
{ [&](std::back_insert_iterator<std::list<std::string>> out) {
s << " * " << stride; for (std::size_t idx = 0; idx < dim_limit; ++idx)
} {
if ((stride != 1) && offset) std::ostringstream s;
{ std::size_t stride = op().get_strides()[idx];
s << ")"; std::size_t offset = op().get_lower_bounds()[idx];
} if ((stride != 1) && offset)
if (offset) {
{ s << "(";
s << " + " << offset; }
} s << "od" << idx;
out = s.str(); if (stride != 1)
} {
}))) s << " * " << stride;
.finalize()); }
} if ((stride != 1) && offset)
{
s << ")";
}
if (offset)
{
s << " + " << offset;
}
out = s.str();
}
})))
.finalize());
}
namespace namespace
{ {
ngraph::runtime::plaidml::Impl<ngraph::op::Slice>::Registration register_slice; Impl<op::Slice>::Registration register_slice;
}
}
}
} }
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