Skip to content
This repository has been archived by the owner on Jan 3, 2023. It is now read-only.

Remove ParameterizedConstant #309

Merged
merged 18 commits into from
Dec 19, 2017
Merged

Remove ParameterizedConstant #309

merged 18 commits into from
Dec 19, 2017

Conversation

rkimballn1
Copy link
Contributor

Most of the work is on op::Constant. I would like to know what you guys think. If it looks ok then we can bring in more reviewers for the PR but I want to get your opinions before I do more.

Copy link
Contributor

@diyessi diyessi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor scathes that can be resolved by change and/or successful rebuttal.

@@ -35,7 +35,7 @@ using namespace ngraph;
std::shared_ptr<Node> make_zero(const std::shared_ptr<const TensorViewType>& tensor_view_type)
{
std::shared_ptr<Node> zero =
std::make_shared<op::Constant>(tensor_view_type->get_element_type(), Shape{}, "0");
op::Constant::create(tensor_view_type->get_element_type(), Shape{}, {0.0});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lean slightly towards calling it make instead of create but that could be because I was doing make-instance before these new-fangled object creation names showed up, so I'll go along with @aprocter .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create sounds good to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda lean towards make as well but I figure @rkimballn1 got there first ;)

{
throw ngraph_error("Constant does not have tensor view type");
for (int value : get_vector<char>())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if this big if with the same essential body in each clause pattern I see multiple places could be done without all the duplication, but I don't think C++ templates can do it; you'd need a kind of lambda template for the body.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a switch/case instead of this big if?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember coming across this when adding polymorphism to NGVM. It looks like templated lambdas are available, but only in C++14.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a compiler constraint from MXNet that might prevent this; if not, we should let the compiler let us simplify our sources.

/// \param values An initializer_list of string values to use as the constant data.
template <typename T>
static std::shared_ptr<op::Constant>
create(const element::Type& type, Shape shape, std::initializer_list<T> values)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use <typename T> and const T& values and you'll be able to initialize with anything that can initialize a vector.

}
template <>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you stick spaces between these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but clang-format removes them.

@@ -3189,7 +3027,7 @@ TEST(${BACKEND_NAME}, slice_3d_strided_different_strides)
TEST(${BACKEND_NAME}, scalar_constant_float32)
{
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
auto r = make_shared<op::Constant>(element::Float32::element_type(), Shape{}, "4.8");
auto r = op::Constant::create(element::Float32::element_type(), Shape{}, {4.8});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it'd be worthwhile to have an overloading for making scalar constants, like
op::Constant::create(element::Float32::element_type(), 4.8)

@@ -3201,13 +3039,13 @@ TEST(${BACKEND_NAME}, scalar_constant_float32)
auto result = backend->make_primary_tensor_view(element::Float32::element_type(), Shape{});

cf->call({}, {result});
EXPECT_EQ(vector<float>{std::strtof("4.8", NULL)}, result->get_vector<float>());
EXPECT_EQ(vector<float>{4.8}, result->get_vector<float>());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and similarly, a get_scalar<float> although it might only be unit tests that it would matter for.

Copy link
Contributor

@aprocter aprocter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Much cleaner than the string-based stuff. Just a couple small changes requested: some docstrings related, and the "autobroadcasting" constructor (I think that behavior should be attached to a constructor that just takes T rather than vector, rather than to singleton vectors).

@@ -35,7 +35,7 @@ using namespace ngraph;
std::shared_ptr<Node> make_zero(const std::shared_ptr<const TensorViewType>& tensor_view_type)
{
std::shared_ptr<Node> zero =
std::make_shared<op::Constant>(tensor_view_type->get_element_type(), Shape{}, "0");
op::Constant::create(tensor_view_type->get_element_type(), Shape{}, {0.0});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda lean towards make as well but I figure @rkimballn1 got there first ;)

{
throw ngraph_error("Constant does not have tensor view type");
for (int value : get_vector<char>())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember coming across this when adding polymorphism to NGVM. It looks like templated lambdas are available, but only in C++14.

/// | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
/// | `type` | The ngraph::element::Type of the tensor constant. |
/// | `shape` | The ngraph::Shape of the tensor constant. |
/// | `value_strings` | A list of strings containing literals for initialization of the tensor constant. These strings are parsed with the appropriate instance of ngraph::element::TraitedType::read. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer strings, right?

Constant(const element::Type& et,
const Shape& shape,
const std::vector<std::string>& value_strings);
/// \param values A vector of string values to use as the constant data.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no longer strings

}

/// \return The initialization literals for the tensor constant.
const std::vector<std::string>& get_value_strings() const { return m_value_strings; }
std::vector<std::string> get_value_strings() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still used (maybe by the serializer)?

{
auto vt = std::make_shared<TensorViewType>(type, shape);
set_value_type_checked(vt);
if (values.size() == 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a vector length of 1 gives you the "autobroadcasting" behavior. Could we change it so that instead there is a separate constructor for this behavior that doesn't take a vector, like so?

Constant(const element::Type& type, Shape shape, T value)

@@ -480,324 +480,6 @@ void runtime::cpu::CPU_Emitter::EmitSubtract(const ngraph::Node* n,
m_out << "}\n";
}

void runtime::cpu::CPU_Emitter::EmitParameterizedConstantBool(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sooooo much red ;)

Copy link
Contributor

@avijit-nervana avijit-nervana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good and simple. I couldn't try this with TF as currently NGTF is lagging seriously behind the ngraph++ API :-(

/// | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
/// | `type` | The ngraph::element::Type of the tensor constant. |
/// | `shape` | The ngraph::Shape of the tensor constant. |
/// | `value_strings` | A list of strings containing literals for initialization of the tensor constant. These strings are parsed with the appropriate instance of ngraph::element::TraitedType::read. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we break these long lines into multiple - much easier to read (side by side)

Copy link
Contributor

@aprocter aprocter Dec 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fess up: I'm the one who wrote most of these with super-wide lines in the first place. The embarrassing reason for it is that I could not figure out how to get Doxygen's markdown parser to understand multi-line table cells without explicitly delineating the rows. (i.e. there are two table styles: one where there's one table row per ASCII line, and one where you have to put a bunch of extra dashes between rows.)

Probably switching to the explicitly-delineated rows is the best solution. I could do this in a separate PR since I'm the one who made the mess and I already know how to clean it up.

@@ -35,7 +35,7 @@ using namespace ngraph;
std::shared_ptr<Node> make_zero(const std::shared_ptr<const TensorViewType>& tensor_view_type)
{
std::shared_ptr<Node> zero =
std::make_shared<op::Constant>(tensor_view_type->get_element_type(), Shape{}, "0");
op::Constant::create(tensor_view_type->get_element_type(), Shape{}, {0.0});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create sounds good to me.

{
throw ngraph_error("Constant does not have tensor view type");
for (int value : get_vector<char>())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a switch/case instead of this big if?

{
throw std::runtime_error("Constant initializer does not match shape");
}
if (target_type == element::boolean)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to replace with a switch/case

, m_value(value)
/// \param values A vector of literals for initializing the tensor constant. The size of values must match the size of the shape.
template <typename T>
Constant(const element::Type& type, Shape shape, const std::vector<T>& values)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you have defined a create(...) method - mark the constructor private?

Copy link
Contributor

@aprocter aprocter Dec 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be a little hesitant to start marking node constructors private unless we make the change consistently. Also make_shared doesn't work with private constructors, even when used inside the class.


template <typename T>
std::vector<T> get_vector() const
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed? If the vector is large, then this will be expensive. If this method doesn't exist then users will have to use the more efficient get_data_ptr() defined below.

}

void* get_data_ptr() { return m_data; }
virtual bool is_constant() const override { return true; }
protected:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What other classes are envisioned to be derived from Constant?

@@ -258,7 +258,7 @@ class ngraph::runtime::interpreter::INT_CallFrame : public runtime::CallFrame
else if (node_op == "Constant")
{
auto c = static_cast<const op::Constant*>(&node);
std::vector<T> input = ngraph::parse_string<T>(c->get_value_strings());
std::vector<T> input = c->get_vector<T>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid the copy here i.e., use get_data_pointer()? If the lifecycle doesn't permit that, in that case can we use a emplace type operation so that the data is transferred to the kernel without the copy?
(This is a general questions about this pattern used in other ops as well)

@diyessi diyessi requested review from ransford2011 and removed request for mbrookhart December 19, 2017 18:59
Copy link
Contributor

@ransford2011 ransford2011 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is support for the constructor needed by the MXNet bridge 😄 . LGTM

@ransford2011
Copy link
Contributor

@rkimballn1 . Just to be clear. Constant ops are only created through the factory function create() right? In @mbrookhart PR, he's expecting a string as the last parameter

@ransford2011 ransford2011 reopened this Dec 19, 2017
@rkimballn1 rkimballn1 merged commit 833a8f1 into master Dec 19, 2017
@rkimballn1 rkimballn1 deleted the bob/no-ptv branch December 19, 2017 19:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants