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

Initial implementation of implicit broadcasting for eltwise ops #2936

Merged
merged 17 commits into from May 30, 2019

Conversation

jbobba
Copy link
Contributor

@jbobba jbobba commented May 15, 2019

TODO

  • Figure out the autodiff story for implicit broadcast modes
    Will be supported through reductions along broadcast axes in a future PR
  • Expand to other eltwise ops
  • Add more eltwise execution unit tests
  • Serializer support

@jbobba jbobba added the WIP Work In Progress and will not be merged label May 15, 2019
@jbobba jbobba requested review from aprocter and diyessi May 15, 2019 00:02
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.

Just comments since this is [WIP] but it looks great so far

src/ngraph/dimension.cpp Outdated Show resolved Hide resolved
src/ngraph/node.cpp Show resolved Hide resolved
src/ngraph/op/util/binary_elementwise_arithmetic.cpp Outdated Show resolved Hide resolved
src/ngraph/partial_shape.cpp Outdated Show resolved Hide resolved
src/ngraph/op/util/binary_elementwise_arithmetic.cpp Outdated Show resolved Hide resolved
src/ngraph/pass/auto_broadcast.hpp Outdated Show resolved Hide resolved
test/type_prop.cpp Outdated Show resolved Hide resolved
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.

Also agree on bcast -> broadcast

src/ngraph/dimension.cpp Outdated Show resolved Hide resolved
src/ngraph/node.cpp Show resolved Hide resolved
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.

Good stuff! In the comments are a couple of cosmetic gripes. A few additional things I think we should do (ideally before merging, but I could be persuaded to take a raincheck):

  1. Expand support to all binops.
  2. Add a few execution tests for binops with implicit broadcast. (Okay to disable in non-CPU/INTERPRETER BEs for now.)

src/ngraph/op/util/attr_types.hpp Outdated Show resolved Hide resolved
src/ngraph/op/util/attr_types.hpp Outdated Show resolved Hide resolved
@jbobba
Copy link
Contributor Author

jbobba commented May 16, 2019

Good stuff! In the comments are a couple of cosmetic gripes. A few additional things I think we should do (ideally before merging, but I could be persuaded to take a raincheck):

  1. Expand support to all binops.
  2. Add a few execution tests for binops with implicit broadcast. (Okay to disable in non-CPU/INTERPRETER BEs for now.)
  3. (Likely consequence of 2) Update other backends to invoke.

Will remove WIP once i expand to all binops. We can run execution tests on other backends as well since they will invoke the ImplicitBroadcastElimination pass

@aprocter
Copy link
Contributor

Will remove WIP once i expand to all binops. We can run execution tests on other backends as well since they will invoke the ImplicitBroadcastElimination pass

SGTM. I'd actually meant to backspace the comment about updating other BEs, since it occurred to me as I was typing it that the manifest exists. But it might be worth doing in this PR as well.

@jbobba jbobba changed the title [WIP] Initial implementation of implicit broadcasting for eltwise ops Initial implementation of implicit broadcasting for eltwise ops May 21, 2019
@jbobba jbobba removed the WIP Work In Progress and will not be merged label May 21, 2019
{
// One static. Set dst to static size if >1
auto ds = d1.is_dynamic() ? size_t(d2) : size_t(d1);
dst = (ds > 1) ? ds : Dimension::dynamic();
Copy link
Contributor

Choose a reason for hiding this comment

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

I dunno why, but I genuinely love corner cases like this.

@@ -471,7 +471,8 @@ const NodeVector& ngraph::check_single_output_args(const NodeVector& args)
return args;
}

std::tuple<element::Type, PartialShape> Node::validate_and_infer_elementwise_args()
std::tuple<element::Type, PartialShape>
Node::validate_and_infer_elementwise_args(const op::AutoBroadcastSpec autob)
Copy link
Contributor

Choose a reason for hiding this comment

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

Pass by reference instead of by value

NUMPY
};

struct AutoBroadcastSpec
Copy link
Contributor

Choose a reason for hiding this comment

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

This could use some doc strings, also on ctors

{
}

AutoBroadcastType type;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm sure I am the only one who thinks this, but these should be m_type and there should be accessor functions.

enum class AutoBroadcastType
{
NONE = 0,
NUMPY
Copy link
Contributor

Choose a reason for hiding this comment

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

It is a shortcut to just say that this works like numpy broadcast, but it would be nice to actually know the rules without having to go find numpy's documentation to find out how our code works.


bool PartialShape::broadcast_merge_into(PartialShape& dst,
const PartialShape& src,
const op::AutoBroadcastSpec autob)
Copy link
Contributor

Choose a reason for hiding this comment

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

pass by reference

{
if (node->get_autob().type == op::AutoBroadcastType::NONE)
{
return node->get_arguments();
Copy link
Contributor

Choose a reason for hiding this comment

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

by having multiple returns you do not allow the compiler to use Return Value Optimization, forcing it to make a copy when returning NodeVector.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is only used on nodes with two arguments. As such copying might not be too bad. Do you have an alternative in mind?

Copy link
Contributor

Choose a reason for hiding this comment

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

at the top define NodeVector rc;
instead of returns set rc = <whatever>;
then at the bottom return rc;
One return so RVO works. It is a good general rule to follow to only have one return per function if you are returning something non trivial

case OP_TYPEID::Add:
{
auto tmp = dynamic_cast<const op::Add*>(&n);
node["autob"] = write_auto_broadcast(tmp->get_autob());
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be better if you only wrote out autob if it is not the default value.

op::And::And(const shared_ptr<Node>& arg0,
const shared_ptr<Node>& arg1,
const AutoBroadcastSpec& autob)
: BinaryElementwiseLogical("And", arg0, arg1, autob)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to pass this to every constructor ? I assume autob mode should be fixed for all nodes during at least on ngraph invocation. Can't we instead implicitly read it from some configuration class/global ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Provide a way to change the default constructor of AutoBroadcastSpec?

Copy link
Contributor

Choose a reason for hiding this comment

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

It might make sense to have a global that influences the constructors' behavior for the sake of convenience, but I still think we'll need to store autob and respect that stored value, for things like deserialization.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or set the attribute after construction and before validation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Basically, is it possible that nodes may have different auto-broadcast modes ? If not, then makes more sense to keep it as a global.

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, "possible" is up to us, right? ;)

Consider, for example, a builder (either one that's part of Core and meant to be reused across bridges, or one that's used internally by the bridge) that wants to use autobroadcast internally. How would that interact with the global?

}

AutoBroadcastType type;
size_t axis;
Copy link
Contributor

Choose a reason for hiding this comment

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

What is axis ? Couldn't find a use anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used to indicate the start of alignment, I added a comment.

@postrational postrational added this to the 0.21 milestone May 28, 2019
{
if (node->get_autob().type == op::AutoBroadcastType::NONE)
{
return node->get_arguments();
Copy link
Contributor

Choose a reason for hiding this comment

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

at the top define NodeVector rc;
instead of returns set rc = <whatever>;
then at the bottom return rc;
One return so RVO works. It is a good general rule to follow to only have one return per function if you are returning something non trivial

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.

I don't like passing that ab all over the place, but this will do until we can work something better out like a graph context or something.

op::And::And(const shared_ptr<Node>& arg0,
const shared_ptr<Node>& arg1,
const AutoBroadcastSpec& autob)
: BinaryElementwiseLogical("And", arg0, arg1, autob)
Copy link
Contributor

Choose a reason for hiding this comment

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

Or set the attribute after construction and before validation.

@rkimballn1 rkimballn1 added the Fully Reviewed PR is approved by all reviewers. label May 30, 2019
@rkimballn1 rkimballn1 merged commit 0caefe7 into master May 30, 2019
@rkimballn1 rkimballn1 deleted the jbobba/eltwise-autob branch May 30, 2019 22:11
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Fully Reviewed PR is approved by all reviewers.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants