Commit d96482a5 authored by Jayaram Bobba's avatar Jayaram Bobba Committed by Scott Cyphers

Unified interpolate layer op (#3017)

* Unified interpolate layer op

* Minor attr name changes
parent ea64f5bf
...@@ -41,7 +41,7 @@ void op::DetectionOutput::validate_and_infer_types() ...@@ -41,7 +41,7 @@ void op::DetectionOutput::validate_and_infer_types()
{ {
auto box_logits_shape = get_input_partial_shape(0).to_shape(); auto box_logits_shape = get_input_partial_shape(0).to_shape();
set_output_type( set_output_type(
0, element::f32, Shape{1, 1, m_attrs.boxes_top_k[0] * box_logits_shape[0], 7}); 0, element::f32, Shape{1, 1, m_attrs.keep_top_k[0] * box_logits_shape[0], 7});
} }
else else
{ {
......
...@@ -26,9 +26,9 @@ namespace ngraph ...@@ -26,9 +26,9 @@ namespace ngraph
{ {
int num_classes; int num_classes;
int background_label_id = 0; int background_label_id = 0;
int results_top_k = -1; int top_k = -1;
bool add_variance = false; bool variance_encoded_in_target = false;
std::vector<int> boxes_top_k = {1}; std::vector<int> keep_top_k = {1};
std::string code_type = std::string{"caffe.PriorBoxParameter.CORNER"}; std::string code_type = std::string{"caffe.PriorBoxParameter.CORNER"};
bool share_location = true; bool share_location = true;
float nms_threshold; float nms_threshold;
...@@ -39,7 +39,7 @@ namespace ngraph ...@@ -39,7 +39,7 @@ namespace ngraph
bool normalized = false; bool normalized = false;
size_t input_height = 1; size_t input_height = 1;
size_t input_width = 1; size_t input_width = 1;
float objectness_score_threshold = 0; float objectness_score = 0;
} DetectionOutputAttrs; } DetectionOutputAttrs;
/// \brief Layer which performs non-max suppression to /// \brief Layer which performs non-max suppression to
......
...@@ -21,8 +21,10 @@ ...@@ -21,8 +21,10 @@
using namespace std; using namespace std;
using namespace ngraph; using namespace ngraph;
op::Interpolate::Interpolate(const std::shared_ptr<Node>& image, const InterpolateAttrs& attrs) op::Interpolate::Interpolate(const std::shared_ptr<Node>& image,
: Op("Interpolate", check_single_output_args({image})) const std::shared_ptr<Node>& output_shape,
const InterpolateAttrs& attrs)
: Op("Interpolate", check_single_output_args({image, output_shape}))
, m_attrs(attrs) , m_attrs(attrs)
{ {
constructor_validate_and_infer_types(); constructor_validate_and_infer_types();
...@@ -30,98 +32,39 @@ op::Interpolate::Interpolate(const std::shared_ptr<Node>& image, const Interpola ...@@ -30,98 +32,39 @@ op::Interpolate::Interpolate(const std::shared_ptr<Node>& image, const Interpola
void op::Interpolate::validate_and_infer_types() void op::Interpolate::validate_and_infer_types()
{ {
if (get_input_partial_shape(0).is_static()) NODE_VALIDATION_CHECK(this,
{ get_input_element_type(1).compatible(element::Type_t::i64),
Shape input_shape = get_input_partial_shape(0).to_shape(); "output shape must have element type i64.");
Shape output_shape(4); set_input_is_relevant_to_shape(1);
// Assumes {N, C, H, W}
output_shape[0] = input_shape[0];
output_shape[1] = input_shape[1];
auto is_zero = [](float value) {
return std::fabs(value) < std::numeric_limits<float>::epsilon();
};
bool should_scale = !(is_zero(m_attrs.zoom_factor) && is_zero(m_attrs.shrink_factor) &&
is_zero(m_attrs.scale_factor));
if (should_scale) PartialShape output_shape = PartialShape(get_input_partial_shape(0));
{ if (output_shape.rank().is_static())
float scale = m_attrs.scale_factor;
if (!is_zero(m_attrs.shrink_factor) || !is_zero(m_attrs.zoom_factor))
{ {
if (!is_zero(m_attrs.zoom_factor)) for (auto axis : m_attrs.axes)
{ {
scale = m_attrs.zoom_factor; NGRAPH_CHECK(axis < static_cast<size_t>(output_shape.rank()));
} output_shape[axis] = Dimension::dynamic();
if (!is_zero(m_attrs.shrink_factor))
{
scale /= m_attrs.shrink_factor;
}
} }
output_shape[2] = input_shape[2] * scale;
output_shape[3] = input_shape[3] * scale;
} }
// Override
if (m_attrs.height > 0)
{
output_shape[2] = m_attrs.height;
}
if (m_attrs.width > 0)
{
output_shape[3] = m_attrs.width;
}
set_output_type(0, get_input_element_type(0), output_shape);
}
else
{
set_output_type(0, get_input_element_type(0), PartialShape::dynamic());
}
}
shared_ptr<Node> op::Interpolate::copy_with_new_args(const NodeVector& new_args) const
{
check_new_args_count(this, new_args);
return make_shared<Interpolate>(new_args.at(0), m_attrs);
}
op::DynInterpolate::DynInterpolate(const std::shared_ptr<Node>& image,
const std::shared_ptr<Node>& output_shape,
const InterpolateAttrs& attrs)
: Op("DynInterpolate", check_single_output_args({image, output_shape}))
, m_attrs(attrs)
{
constructor_validate_and_infer_types();
}
void op::DynInterpolate::validate_and_infer_types()
{
set_input_is_relevant_to_shape(1);
if (auto const_shape = dynamic_pointer_cast<op::Constant>(get_argument(1))) if (auto const_shape = dynamic_pointer_cast<op::Constant>(get_argument(1)))
{ {
NODE_VALIDATION_CHECK(this,
shape_size(const_shape->get_shape()) == 4,
"Layer shape must have rank 4",
const_shape->get_shape());
auto out_shape = static_cast<const int64_t*>(const_shape->get_data_ptr()); auto out_shape = static_cast<const int64_t*>(const_shape->get_data_ptr());
Shape output_shape; size_t i = 0;
for (size_t i = 0; i < 4; i++) for (auto axis : m_attrs.axes)
{ {
output_shape.push_back((out_shape[i] > 0) ? out_shape[i] : 0); output_shape[axis] = Dimension(out_shape[i++]);
} }
set_output_type(0, get_input_element_type(0), output_shape); set_output_type(0, get_input_element_type(0), output_shape);
} }
else else
{ {
set_output_type(0, get_input_element_type(0), PartialShape::dynamic()); set_output_type(0, get_input_element_type(0), output_shape);
} }
} }
shared_ptr<Node> op::DynInterpolate::copy_with_new_args(const NodeVector& new_args) const shared_ptr<Node> op::Interpolate::copy_with_new_args(const NodeVector& new_args) const
{ {
check_new_args_count(this, new_args); check_new_args_count(this, new_args);
return make_shared<DynInterpolate>(new_args.at(0), new_args.at(1), m_attrs); return make_shared<Interpolate>(new_args.at(0), new_args.at(1), m_attrs);
} }
...@@ -24,14 +24,12 @@ namespace ngraph ...@@ -24,14 +24,12 @@ namespace ngraph
{ {
typedef struct typedef struct
{ {
int height = -1; AxisSet axes;
int width = -1; std::string mode;
float zoom_factor = 0; bool align_corners = true;
float shrink_factor = 0; bool antialias = false;
float scale_factor = 1.0; std::vector<size_t> pads_begin;
bool align_coreners = true; std::vector<size_t> pads_end;
int pad_beg = 0;
int pad_end = 0;
} InterpolateAttrs; } InterpolateAttrs;
/// \brief Layer which performs bilinear interpolation /// \brief Layer which performs bilinear interpolation
...@@ -41,29 +39,9 @@ namespace ngraph ...@@ -41,29 +39,9 @@ namespace ngraph
/// \brief Constructs a Interpolate operation /// \brief Constructs a Interpolate operation
/// ///
/// \param image Input image /// \param image Input image
/// \param output_shape Output shape of spatial axes
/// \param attrs Interpolation attributes /// \param attrs Interpolation attributes
Interpolate(const std::shared_ptr<Node>& image, const InterpolateAttrs& attrs); Interpolate(const std::shared_ptr<Node>& image,
void validate_and_infer_types() override;
virtual std::shared_ptr<Node>
copy_with_new_args(const NodeVector& new_args) const override;
const InterpolateAttrs& get_attrs() const { return m_attrs; }
private:
InterpolateAttrs m_attrs;
};
/// \brief Layer which performs bilinear interpolation
class DynInterpolate : public Op
{
public:
/// \brief Constructs a DynInterpolate operation
///
/// \param image Input image
/// \param output_shape Output shape
/// \param attrs Interpolation attributes
DynInterpolate(const std::shared_ptr<Node>& image,
const std::shared_ptr<Node>& output_shape, const std::shared_ptr<Node>& output_shape,
const InterpolateAttrs& attrs); const InterpolateAttrs& attrs);
......
...@@ -66,16 +66,16 @@ void op::PriorBox::validate_and_infer_types() ...@@ -66,16 +66,16 @@ void op::PriorBox::validate_and_infer_types()
auto layer_shape = const_shape->get_shape_val(); auto layer_shape = const_shape->get_shape_val();
size_t num_priors = 0; size_t num_priors = 0;
// {Prior boxes, Variance-adjusted prior boxes} // {Prior boxes, Variance-adjusted prior boxes}
if (m_attrs.scale_all) if (m_attrs.scale_all_sizes)
{ {
num_priors = ((m_attrs.flip ? 2 : 1) * m_attrs.aspect_ratios.size() + 1) * num_priors = ((m_attrs.flip ? 2 : 1) * m_attrs.aspect_ratio.size() + 1) *
m_attrs.min_sizes.size() + m_attrs.min_size.size() +
m_attrs.max_sizes.size(); m_attrs.max_size.size();
} }
else else
{ {
num_priors = (m_attrs.flip ? 2 : 1) * m_attrs.aspect_ratios.size() + num_priors =
m_attrs.min_sizes.size() - 1; (m_attrs.flip ? 2 : 1) * m_attrs.aspect_ratio.size() + m_attrs.min_size.size() - 1;
} }
set_output_type( set_output_type(
......
...@@ -24,24 +24,24 @@ namespace ngraph ...@@ -24,24 +24,24 @@ namespace ngraph
{ {
struct PriorBoxAttrs struct PriorBoxAttrs
{ {
// min_sizes Desired min_sizes of prior boxes // min_size Desired min_size of prior boxes
// max_sizes Desired max_sizes of prior boxes // max_size Desired max_size of prior boxes
// aspect_ratios Aspect ratios of prior boxes // aspect_ratio Aspect ratios of prior boxes
// clip Clip output to [0,1] // clip Clip output to [0,1]
// flip Flip aspect ratios // flip Flip aspect ratios
// step Distance between prior box centers // step Distance between prior box centers
// offset Box offset relative to top center of image // offset Box offset relative to top center of image
// variances Values to adjust prior boxes with // variance Values to adjust prior boxes with
// scale_all Scale all sizes // scale_all_sizes Scale all sizes
std::vector<float> min_sizes; std::vector<float> min_size;
std::vector<float> max_sizes; std::vector<float> max_size;
std::vector<float> aspect_ratios; std::vector<float> aspect_ratio;
bool clip = false; bool clip = false;
bool flip = false; bool flip = false;
float step = 1.0f; float step = 1.0f;
float offset = 0.0f; float offset = 0.0f;
std::vector<float> variances; std::vector<float> variance;
bool scale_all = false; bool scale_all_sizes = false;
}; };
/// \brief Layer which generates prior boxes of specified sizes /// \brief Layer which generates prior boxes of specified sizes
......
...@@ -25,33 +25,33 @@ namespace ngraph ...@@ -25,33 +25,33 @@ namespace ngraph
// base_size Anchor sizes // base_size Anchor sizes
// pre_nms_topn Number of boxes before nms // pre_nms_topn Number of boxes before nms
// post_nms_topn Number of boxes after nms // post_nms_topn Number of boxes after nms
// nms_threshold Threshold for nms // nms_thresh Threshold for nms
// feature_stride Feature stride // feat_stride Feature stride
// min_size Minimum box size // min_size Minimum box size
// anchor_ratios Ratios for anchor generation // ratio Ratios for anchor generation
// anchor_scales Scales for anchor generation // scale Scales for anchor generation
// clip_before_nms Clip before NMs // clip_before_nms Clip before NMs
// clip_after_nms Clip after NMs // clip_after_nms Clip after NMs
// normalize Normalize boxes to [0,1] // normalize Normalize boxes to [0,1]
// box_size_scale Scale factor for scaling box size logits // box_size_scale Scale factor for scaling box size logits
// box_coord_scale Scale factor for scaling box coordiate logits // box_coordinate_scale Scale factor for scaling box coordiate logits
// algo Calculation algorithm to use // framework Calculation frameworkrithm to use
struct ProposalAttrs struct ProposalAttrs
{ {
size_t base_size; size_t base_size;
size_t pre_nms_topn; size_t pre_nms_topn;
size_t post_nms_topn; size_t post_nms_topn;
float nms_threshold = 0.0f; float nms_thresh = 0.0f;
size_t feature_stride = 1; size_t feat_stride = 1;
size_t min_size = 1; size_t min_size = 1;
std::vector<float> anchor_ratios; std::vector<float> ratio;
std::vector<float> anchor_scales; std::vector<float> scale;
bool clip_before_nms = false; bool clip_before_nms = false;
bool clip_after_nms = false; bool clip_after_nms = false;
bool normalize = false; bool normalize = false;
float box_size_scale = 1.0f; float box_size_scale = 1.0f;
float box_coord_scale = 1.0f; float box_coordinate_scale = 1.0f;
std::string algo; std::string framework;
}; };
class Proposal : public Op class Proposal : public Op
......
...@@ -48,7 +48,7 @@ TEST(type_prop_layers, detection_output) ...@@ -48,7 +48,7 @@ TEST(type_prop_layers, detection_output)
auto aux_class_preds = make_shared<op::Parameter>(element::f32, Shape{2, 1, 4, 5}); auto aux_class_preds = make_shared<op::Parameter>(element::f32, Shape{2, 1, 4, 5});
auto aux_box_preds = make_shared<op::Parameter>(element::f32, Shape{2, 1, 4, 5}); auto aux_box_preds = make_shared<op::Parameter>(element::f32, Shape{2, 1, 4, 5});
op::DetectionOutputAttrs attrs; op::DetectionOutputAttrs attrs;
attrs.boxes_top_k = {200}; attrs.keep_top_k = {200};
auto op = make_shared<op::DetectionOutput>( auto op = make_shared<op::DetectionOutput>(
box_logits, class_preds, proposals, aux_class_preds, aux_box_preds, attrs); box_logits, class_preds, proposals, aux_class_preds, aux_box_preds, attrs);
ASSERT_EQ(op->get_shape(), (Shape{1, 1, 800, 7})); ASSERT_EQ(op->get_shape(), (Shape{1, 1, 800, 7}));
...@@ -57,43 +57,24 @@ TEST(type_prop_layers, detection_output) ...@@ -57,43 +57,24 @@ TEST(type_prop_layers, detection_output)
TEST(type_prop_layers, interpolate) TEST(type_prop_layers, interpolate)
{ {
auto image = make_shared<op::Parameter>(element::f32, Shape{2, 2, 33, 65}); auto image = make_shared<op::Parameter>(element::f32, Shape{2, 2, 33, 65});
auto dyn_output_shape = make_shared<op::Parameter>(element::i64, Shape{2});
op::InterpolateAttrs attrs1; auto output_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {15, 30});
attrs1.height = 257;
attrs1.width = 513;
auto op1 = make_shared<op::Interpolate>(image, attrs1);
ASSERT_EQ(op1->get_shape(), (Shape{2, 2, 257, 513}));
op::InterpolateAttrs attrs2;
attrs2.scale_factor = 2;
attrs2.width = 513;
auto op2 = make_shared<op::Interpolate>(image, attrs2);
ASSERT_EQ(op2->get_shape(), (Shape{2, 2, 66, 513}));
op::InterpolateAttrs attrs3;
attrs3.scale_factor = 2;
attrs3.height = 257;
auto op3 = make_shared<op::Interpolate>(image, attrs3);
ASSERT_EQ(op3->get_shape(), (Shape{2, 2, 257, 130}));
}
TEST(type_prop_layers, dyn_interpolate)
{
auto image = make_shared<op::Parameter>(element::f32, Shape{2, 2, 33, 65});
auto output_shape = op::Constant::create<int64_t>(element::i64, Shape{4}, {4, 2, 15, 30});
op::InterpolateAttrs attrs; op::InterpolateAttrs attrs;
attrs.height = 257; attrs.axes = {2, 3};
attrs.width = 513; auto op = make_shared<op::Interpolate>(image, output_shape, attrs);
auto op = make_shared<op::DynInterpolate>(image, output_shape, attrs); ASSERT_EQ(op->get_shape(), (Shape{2, 2, 15, 30}));
ASSERT_EQ(op->get_shape(), (Shape{4, 2, 15, 30}));
EXPECT_TRUE(make_shared<op::Interpolate>(image, dyn_output_shape, attrs)
->get_output_partial_shape(0)
.same_scheme(PartialShape{2, 2, Dimension::dynamic(), Dimension::dynamic()}));
} }
TEST(type_prop_layers, prior_box1) TEST(type_prop_layers, prior_box1)
{ {
op::PriorBoxAttrs attrs; op::PriorBoxAttrs attrs;
attrs.min_sizes = {2.0f, 3.0f}; attrs.min_size = {2.0f, 3.0f};
attrs.aspect_ratios = {1.0f, 2.0f, 0.5f}; attrs.aspect_ratio = {1.0f, 2.0f, 0.5f};
auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {32, 32}); auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {32, 32});
auto image_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {300, 300}); auto image_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {300, 300});
...@@ -104,8 +85,8 @@ TEST(type_prop_layers, prior_box1) ...@@ -104,8 +85,8 @@ TEST(type_prop_layers, prior_box1)
TEST(type_prop_layers, prior_box2) TEST(type_prop_layers, prior_box2)
{ {
op::PriorBoxAttrs attrs; op::PriorBoxAttrs attrs;
attrs.min_sizes = {2.0f, 3.0f}; attrs.min_size = {2.0f, 3.0f};
attrs.aspect_ratios = {1.0f, 2.0f, 0.5f}; attrs.aspect_ratio = {1.0f, 2.0f, 0.5f};
attrs.flip = true; attrs.flip = true;
auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {32, 32}); auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {32, 32});
...@@ -117,11 +98,11 @@ TEST(type_prop_layers, prior_box2) ...@@ -117,11 +98,11 @@ TEST(type_prop_layers, prior_box2)
TEST(type_prop_layers, prior_box3) TEST(type_prop_layers, prior_box3)
{ {
op::PriorBoxAttrs attrs; op::PriorBoxAttrs attrs;
attrs.min_sizes = {256.0f}; attrs.min_size = {256.0f};
attrs.max_sizes = {315.0f}; attrs.max_size = {315.0f};
attrs.aspect_ratios = {2.0f}; attrs.aspect_ratio = {2.0f};
attrs.flip = true; attrs.flip = true;
attrs.scale_all = true; attrs.scale_all_sizes = true;
auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {1, 1}); auto layer_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {1, 1});
auto image_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {300, 300}); auto image_shape = op::Constant::create<int64_t>(element::i64, Shape{2}, {300, 300});
......
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