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