Unverified Commit 54132cc9 authored by Mateusz Bencer's avatar Mateusz Bencer Committed by GitHub

[ONNX] norm builders should produce v1 ops (#4354)

parent d28fac61
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "ngraph/op/reduce_sum.hpp" #include "ngraph/op/reduce_sum.hpp"
#include "ngraph/op/sqrt.hpp" #include "ngraph/op/sqrt.hpp"
#include "ngraph/op/sum.hpp" #include "ngraph/op/sum.hpp"
#include "ngraph/opsets/opset1.hpp"
#include "ngraph/shape.hpp" #include "ngraph/shape.hpp"
using namespace std; using namespace std;
...@@ -36,125 +37,134 @@ namespace ngraph ...@@ -36,125 +37,134 @@ namespace ngraph
{ {
namespace detail namespace detail
{ {
shared_ptr<Node> lp_norm(const Output<Node>& value, namespace opset1
size_t p_norm,
const AxisSet& reduction_axes,
float bias)
{ {
// In general "entrywise" lp-norm for matrix `A` is defined as following double sum: shared_ptr<Node> lp_norm(const Output<Node>& value,
// ||A||_p = ||vec(A)||_p = [sum_{i=1}^m sum_{j=1}^n abs(a_{i,j})^p]^{1/p} size_t p_norm,
shared_ptr<Node> abs_values{make_shared<op::Abs>(value)}; const AxisSet& reduction_axes,
shared_ptr<Node> p_node = op::Constant::create( float bias)
value.get_element_type(), {
value.get_shape(), // In general "entrywise" lp-norm for matrix `A` is defined as following double
vector<float>(shape_size(value.get_shape()), static_cast<float>(p_norm))); // sum:
// ||A||_p = ||vec(A)||_p = [sum_{i=1}^m sum_{j=1}^n abs(a_{i,j})^p]^{1/p}
// Get inner part of equation: abs_values^p_node, then sum over reduction_axes. shared_ptr<Node> abs_values{make_shared<ngraph::opset1::Abs>(value)};
shared_ptr<Node> values{make_shared<op::Power>(abs_values, p_node)}; shared_ptr<Node> p_node = ngraph::opset1::Constant::create(
values = make_shared<op::Sum>(values, reduction_axes); value.get_element_type(), Shape{}, {p_norm});
shared_ptr<Node> bias_node{ // Get inner part of equation: abs_values^p_node, then sum over reduction_axes.
op::Constant::create(values->get_element_type(), shared_ptr<Node> values{make_shared<ngraph::opset1::Power>(abs_values, p_node)};
values->get_shape(), values = make_shared<ngraph::opset1::ReduceSum>(
vector<float>(shape_size(values->get_shape()), bias))}; values,
ngraph::opset1::Constant::create(
values = values + bias_node; element::i64, Shape{reduction_axes.size()}, reduction_axes.to_vector()),
false);
// Get outer part of equation: raise values to 1/p_norm exponent.
shared_ptr<Node> inv_p_node = op::Constant::create( shared_ptr<Node> bias_node{ngraph::opset1::Constant::create(
values->get_element_type(), values->get_element_type(), Shape{}, {bias})};
values->get_shape(),
vector<float>(shape_size(values->get_shape()), 1.f / p_norm)); values = make_shared<ngraph::opset1::Add>(values, bias_node);
return {make_shared<op::Power>(values, inv_p_node) // Get outer part of equation: raise values to 1/p_norm exponent.
->add_provenance_group_members_above({value})}; shared_ptr<Node> inv_p_node = ngraph::opset1::Constant::create(
values->get_element_type(), Shape{}, {1.f / p_norm});
return {make_shared<ngraph::opset1::Power>(values, inv_p_node)
->add_provenance_group_members_above({value})};
}
} }
} }
shared_ptr<Node> l0_norm(const Output<Node>& value, const AxisSet& reduction_axes) shared_ptr<Node> builder::opset1::l0_norm(const Output<Node>& value,
const AxisSet& reduction_axes)
{ {
// L0 norm returns number of elements different from zero. // L0 norm returns number of elements different from zero.
shared_ptr<Node> zero_node{ const shared_ptr<Node> zero_node{
op::Constant::create(value.get_element_type(), ngraph::opset1::Constant::create(value.get_element_type(), Shape{}, {0.f})};
value.get_shape(),
vector<float>(shape_size(value.get_shape()), 0.f))};
// Convert bool values to input node data type. // Convert bool values to input node data type.
shared_ptr<Node> non_zero_values = make_shared<op::Convert>( const shared_ptr<Node> non_zero_values = make_shared<ngraph::opset1::Convert>(
make_shared<op::NotEqual>(value, zero_node), value.get_element_type()); make_shared<ngraph::opset1::NotEqual>(value, zero_node), value.get_element_type());
return make_shared<op::Sum>(non_zero_values, reduction_axes) return make_shared<ngraph::opset1::ReduceSum>(
non_zero_values,
ngraph::opset1::Constant::create(
element::i64, Shape{reduction_axes.size()}, reduction_axes.to_vector()),
false)
->add_provenance_group_members_above({value}); ->add_provenance_group_members_above({value});
} }
shared_ptr<Node> shared_ptr<Node> builder::opset1::l1_norm(const Output<Node>& value,
l1_norm(const Output<Node>& value, const AxisSet& reduction_axes, float bias) const AxisSet& reduction_axes,
float bias)
{ {
shared_ptr<Node> values{ const shared_ptr<Node> values{make_shared<ngraph::opset1::ReduceSum>(
make_shared<op::Sum>(make_shared<op::Abs>(value), reduction_axes)}; make_shared<ngraph::opset1::Abs>(value),
ngraph::opset1::Constant::create(
element::i64, Shape{reduction_axes.size()}, reduction_axes.to_vector()),
false)};
shared_ptr<Node> bias_node{ const shared_ptr<Node> bias_node{
op::Constant::create(values->get_element_type(), ngraph::opset1::Constant::create(values->get_element_type(), Shape{}, {bias})};
values->get_shape(),
vector<float>(shape_size(values->get_shape()), bias))};
return (values + bias_node)->add_provenance_group_members_above({value}); return make_shared<ngraph::opset1::Add>(values, bias_node)
->add_provenance_group_members_above({value});
} }
shared_ptr<Node> l2_norm(const Output<Node>& value, shared_ptr<Node> builder::opset1::l2_norm(const Output<Node>& value,
const AxisSet& reduction_axes, const AxisSet& reduction_axes,
float bias, float bias,
BiasMode bias_mode, BiasMode bias_mode,
bool keep_dims) bool keep_dims)
{ {
shared_ptr<Node> values{make_shared<op::v1::ReduceSum>( shared_ptr<Node> values{make_shared<ngraph::opset1::ReduceSum>(
value * value, make_shared<ngraph::opset1::Multiply>(value, value),
make_shared<op::Constant>( ngraph::opset1::Constant::create(
element::i64, Shape{reduction_axes.size()}, reduction_axes.to_vector()), element::i64, Shape{reduction_axes.size()}, reduction_axes.to_vector()),
keep_dims)}; keep_dims)};
shared_ptr<Node> bias_node{ shared_ptr<Node> bias_node{
op::Constant::create(values->get_element_type(), ngraph::opset1::Constant::create(values->get_element_type(), Shape{}, {bias})};
values->get_shape(),
vector<float>(shape_size(values->get_shape()), bias))};
shared_ptr<Node> result; shared_ptr<Node> result;
switch (bias_mode) switch (bias_mode)
{ {
case BiasMode::MAX: case BiasMode::MAX:
{ {
result = make_shared<op::Sqrt>(make_shared<op::Maximum>(values, bias_node)); result = make_shared<ngraph::opset1::Sqrt>(
make_shared<ngraph::opset1::Maximum>(values, bias_node));
break; break;
} }
case BiasMode::ADD: case BiasMode::ADD:
default: result = make_shared<op::Sqrt>(values + bias_node); default:
result = make_shared<ngraph::opset1::Sqrt>(
make_shared<ngraph::opset1::Add>(values, bias_node));
} }
return result->add_provenance_group_members_above({value}); return result->add_provenance_group_members_above({value});
} }
shared_ptr<Node> lp_norm(const Output<Node>& value, shared_ptr<Node> builder::opset1::lp_norm(const Output<Node>& value,
const AxisSet& reduction_axes, const AxisSet& reduction_axes,
size_t p_norm, size_t p_norm,
float bias) float bias)
{ {
// The number of non-zero elements // The number of non-zero elements
if (p_norm == 0) if (p_norm == 0)
{ {
return l0_norm(value, reduction_axes); return opset1::l0_norm(value, reduction_axes);
} }
// sum of absolute values. // sum of absolute values.
else if (p_norm == 1) else if (p_norm == 1)
{ {
return l1_norm(value, reduction_axes, bias); return opset1::l1_norm(value, reduction_axes, bias);
} }
// sqrt of sum of squares - Euclidean norm // sqrt of sum of squares - Euclidean norm
else if (p_norm == 2) else if (p_norm == 2)
{ {
return l2_norm(value, reduction_axes, bias); return opset1::l2_norm(value, reduction_axes, bias);
} }
// generic case // generic case
else else
{ {
return detail::lp_norm(value, p_norm, reduction_axes, bias); return detail::opset1::lp_norm(value, p_norm, reduction_axes, bias);
} }
} }
......
...@@ -34,62 +34,65 @@ namespace ngraph ...@@ -34,62 +34,65 @@ namespace ngraph
MAX MAX
}; };
/// \brief Calculates L-0 norm of input tensor. namespace opset1
/// {
/// \note The L-0 norm represents the cardinality of elements different /// \brief Calculates L-0 norm of input tensor.
/// from zero. This actually is not a "true" norm. ///
/// /// \note The L-0 norm represents the cardinality of elements different
/// \param[in] value The input tensor. /// from zero. This actually is not a "true" norm.
/// \param[in] reduction_axes The axes along which we calculate norm. ///
/// /// \param[in] value The input tensor.
/// \return L-0 norm of value. /// \param[in] reduction_axes The axes along which we calculate norm.
/// ///
std::shared_ptr<Node> l0_norm(const Output<Node>& value, const AxisSet& reduction_axes); /// \return L-0 norm of value. The output sub-graph is composed of v1 ops.
///
std::shared_ptr<Node> l0_norm(const Output<Node>& value, const AxisSet& reduction_axes);
/// \brief Calculates L-1 norm of a value. /// \brief Calculates L-1 norm of a value.
/// ///
/// \note The L-1 norm represents the sum of absolute values. /// \note The L-1 norm represents the sum of absolute values.
/// ///
/// \param[in] value The input tensor. /// \param[in] value The input tensor.
/// \param[in] reduction_axes The axes along which we calculate norm. /// \param[in] reduction_axes The axes along which we calculate norm.
/// \param[in] bias The bias added to the calculated sum. /// \param[in] bias The bias added to the calculated sum.
/// ///
/// \return L-1 norm of value. /// \return L-1 norm of value. The output sub-graph is composed of v1 ops.
/// ///
std::shared_ptr<Node> std::shared_ptr<Node>
l1_norm(const Output<Node>& value, const AxisSet& reduction_axes, float bias = 0.f); l1_norm(const Output<Node>& value, const AxisSet& reduction_axes, float bias = 0.f);
/// \brief Calculates L-2 norm of input tensor. /// \brief Calculates L-2 norm of input tensor.
/// ///
/// \note The L-2 norm represents the square root of sum of squares of each /// \note The L-2 norm represents the square root of sum of squares of each
/// individual element. /// individual element.
/// ///
/// \param[in] value The input tensor. /// \param[in] value The input tensor.
/// \param[in] reduction_axes The axes along which we calculate norm. /// \param[in] reduction_axes The axes along which we calculate norm.
/// \param[in] bias The bias combined with calculated sum. /// \param[in] bias The bias combined with calculated sum.
/// \param[in] bias_mode The method of bias application. /// \param[in] bias_mode The method of bias application.
/// \param[in] keep_dims The flag indicates if axes will be removed or kept. /// \param[in] keep_dims The flag indicates if axes will be removed or kept.
/// ///
/// \return L-2 norm of value. /// \return L-2 norm of value. The output sub-graph is composed of v1 ops.
/// ///
std::shared_ptr<Node> l2_norm(const Output<Node>& value, std::shared_ptr<Node> l2_norm(const Output<Node>& value,
const AxisSet& reduction_axes, const AxisSet& reduction_axes,
float bias = 0.f, float bias = 0.f,
BiasMode bias_mode = BiasMode::ADD, BiasMode bias_mode = BiasMode::ADD,
bool keep_dims = false); bool keep_dims = false);
/// \brief Creates node which calculates L-p norm on input tensor. /// \brief Creates node which calculates L-p norm on input tensor.
/// ///
/// \param[in] value The input tensor. /// \param[in] value The input tensor.
/// \param[in] reduction_axes The axes along which we calculate norm. /// \param[in] reduction_axes The axes along which we calculate norm.
/// \param[in] p_norm The p norm to calculate. /// \param[in] p_norm The p norm to calculate.
/// \param[in] bias The bias added to the calculated sum. /// \param[in] bias The bias added to the calculated sum.
/// ///
/// \return L-p norm of value. /// \return L-p norm of value. The output sub-graph is composed of v1 ops.
/// ///
std::shared_ptr<Node> lp_norm(const Output<Node>& value, std::shared_ptr<Node> lp_norm(const Output<Node>& value,
const AxisSet& reduction_axes, const AxisSet& reduction_axes,
std::size_t p_norm = 2, std::size_t p_norm = 2,
float bias = 0.f); float bias = 0.f);
}
} // namespace builder } // namespace builder
} // namespace ngraph } // namespace ngraph
...@@ -55,7 +55,7 @@ namespace ngraph ...@@ -55,7 +55,7 @@ namespace ngraph
<< "Invalid `p` attribute value: " << p_norm << "Invalid `p` attribute value: " << p_norm
<< "Only normalization of 1st or 2nd order is supported."; << "Only normalization of 1st or 2nd order is supported.";
std::shared_ptr<ngraph::Node> norm = ngraph::builder::lp_norm( std::shared_ptr<ngraph::Node> norm = ngraph::builder::opset1::lp_norm(
data, AxisSet{normalize_axis}, static_cast<std::size_t>(p_norm)); data, AxisSet{normalize_axis}, static_cast<std::size_t>(p_norm));
const auto target_shape = default_opset::Constant::create( const auto target_shape = default_opset::Constant::create(
......
...@@ -55,7 +55,7 @@ namespace ngraph ...@@ -55,7 +55,7 @@ namespace ngraph
AxisSet reduction_axes{ AxisSet reduction_axes{
common::get_monotonic_range<std::size_t>(orig_shape.size(), 2)}; common::get_monotonic_range<std::size_t>(orig_shape.size(), 2)};
slice = ngraph::builder::lp_norm( slice = ngraph::builder::opset1::lp_norm(
slice, reduction_axes, static_cast<std::size_t>(p_norm)); slice, reduction_axes, static_cast<std::size_t>(p_norm));
// output shape is all ones except N channel // output shape is all ones except N channel
......
...@@ -97,7 +97,7 @@ namespace ngraph ...@@ -97,7 +97,7 @@ namespace ngraph
/// ///
inline NodeVector reduce_l1(const Node& node) inline NodeVector reduce_l1(const Node& node)
{ {
auto l1_norm_reduction = std::bind(ngraph::builder::l1_norm, auto l1_norm_reduction = std::bind(ngraph::builder::opset1::l1_norm,
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_2,
0.f); 0.f);
...@@ -119,7 +119,7 @@ namespace ngraph ...@@ -119,7 +119,7 @@ namespace ngraph
/// ///
inline NodeVector reduce_l2(const Node& node) inline NodeVector reduce_l2(const Node& node)
{ {
auto l2_norm_reduction = std::bind(ngraph::builder::l2_norm, auto l2_norm_reduction = std::bind(ngraph::builder::opset1::l2_norm,
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_2,
0.f, 0.f,
......
...@@ -68,7 +68,7 @@ NodeVector op::GRN::decompose_op() const ...@@ -68,7 +68,7 @@ NodeVector op::GRN::decompose_op() const
} }
// Calculate l2 norm across channels. // Calculate l2 norm across channels.
shared_ptr<Node> norm = builder::l2_norm(data, AxisSet{1}, m_bias); shared_ptr<Node> norm = builder::opset1::l2_norm(data, AxisSet{1}, m_bias);
// Get back reduced axis. // Get back reduced axis.
norm = std::make_shared<Broadcast>(norm, data.get_shape(), AxisSet{1}); norm = std::make_shared<Broadcast>(norm, data.get_shape(), AxisSet{1});
data = data / norm; data = data / norm;
......
...@@ -96,7 +96,8 @@ NodeVector op::NormalizeL2::decompose_op() const ...@@ -96,7 +96,8 @@ NodeVector op::NormalizeL2::decompose_op() const
// Calculate l2 norm across axes determined by axes input // Calculate l2 norm across axes determined by axes input
auto builder_bias_mode = auto builder_bias_mode =
(m_eps_mode == EpsMode::MAX) ? builder::BiasMode::MAX : builder::BiasMode::ADD; (m_eps_mode == EpsMode::MAX) ? builder::BiasMode::MAX : builder::BiasMode::ADD;
Output<Node> norm = builder::l2_norm(data, reduction_axes, m_eps, builder_bias_mode, true); Output<Node> norm =
builder::opset1::l2_norm(data, reduction_axes, m_eps, builder_bias_mode, true);
data = make_shared<op::Divide>(data, norm, AutoBroadcastSpec(AutoBroadcastType::NUMPY)); data = make_shared<op::Divide>(data, norm, AutoBroadcastSpec(AutoBroadcastType::NUMPY));
......
...@@ -389,7 +389,7 @@ TEST(provenance, builder) ...@@ -389,7 +389,7 @@ TEST(provenance, builder)
{ {
auto p1 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4}); auto p1 = make_shared<op::Parameter>(element::i32, PartialShape{2, 3, 4});
p1->add_provenance_tag("P1"); p1->add_provenance_tag("P1");
auto norm = builder::lp_norm(p1, {0}, 1, 0); auto norm = builder::opset1::lp_norm(p1, {0}, 1, 0);
norm->add_provenance_tag("norm"); norm->add_provenance_tag("norm");
for (auto node : topological_sort(NodeVector{norm})) for (auto node : topological_sort(NodeVector{norm}))
{ {
......
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