-
Notifications
You must be signed in to change notification settings - Fork 221
Conversation
53af5cd
to
43885b5
Compare
There was a problem hiding this 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.
src/ngraph/autodiff/adjoints.cpp
Outdated
@@ -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}); |
There was a problem hiding this comment.
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 .
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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>()) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
src/ngraph/ops/constant.hpp
Outdated
/// \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) |
There was a problem hiding this comment.
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 <> |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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}); |
There was a problem hiding this comment.
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>()); |
There was a problem hiding this comment.
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.
There was a problem hiding this 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).
src/ngraph/autodiff/adjoints.cpp
Outdated
@@ -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}); |
There was a problem hiding this comment.
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>()) |
There was a problem hiding this comment.
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.
src/ngraph/ops/constant.hpp
Outdated
/// | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
/// | `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. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer strings, right?
src/ngraph/ops/constant.hpp
Outdated
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. |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sooooo much red ;)
There was a problem hiding this 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 :-(
src/ngraph/ops/constant.hpp
Outdated
/// | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
/// | `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. | |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
src/ngraph/autodiff/adjoints.cpp
Outdated
@@ -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}); |
There was a problem hiding this comment.
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>()) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 | ||
{ |
There was a problem hiding this comment.
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.
src/ngraph/ops/constant.hpp
Outdated
} | ||
|
||
void* get_data_ptr() { return m_data; } | ||
virtual bool is_constant() const override { return true; } | ||
protected: |
There was a problem hiding this comment.
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>(); |
There was a problem hiding this comment.
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)
15b0054
to
ba6bc12
Compare
…t instead. Constant is not a templated class.
ba6bc12
to
60fb9de
Compare
There was a problem hiding this 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
@rkimballn1 . Just to be clear. Constant ops are only created through the factory function |
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.