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

[MXNET-382] Shape and Size Operator #10889

Merged
merged 31 commits into from
Jun 30, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4635957
Shape Operator
May 10, 2018
38c15d9
cuda
May 10, 2018
6540678
size op
May 11, 2018
01d1b95
lint issues
May 11, 2018
b513dbe
docs example
May 11, 2018
125c3cd
add docs, change op name to avoid conflict, add convenience confluent
May 11, 2018
ac96ef1
change name to _nd
May 11, 2018
93ffddc
fix test cases, add new kernel
May 15, 2018
3d578d3
test name fix.
May 15, 2018
ef43d2f
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
May 15, 2018
1b7ba47
solve gpu memory problem for size and shape
Jun 11, 2018
f8cc278
Merge pull request #3 from haojin2/shape_op
anirudhacharya Jun 11, 2018
eb74750
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Jun 12, 2018
08346da
get rid of FIgnoreInputs attr of shape_nd
Jun 12, 2018
d2f7999
Merge pull request #4 from haojin2/shape_op
anirudhacharya Jun 12, 2018
93fc294
Merge branch 'shape' of https://github.com/anirudhacharya/incubator-m…
Jun 13, 2018
3f84b1a
op name change
Jun 13, 2018
3d8f560
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Jun 13, 2018
2074b46
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Jun 18, 2018
4b1164e
fix
Jun 22, 2018
ee97196
Merge branch 'master' of https://github.com/apache/incubator-mxnet into
Jun 25, 2018
10cb562
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Jun 26, 2018
cbec1e5
retrigger CI
Jun 26, 2018
039e6d4
retrigger CI
Jun 26, 2018
ee110fd
retrigger CI
Jun 26, 2018
460c315
Merge branch 'master' of https://github.com/apache/incubator-mxnet in…
Jun 26, 2018
67cbbfe
trigger CI
Jun 26, 2018
804dfb4
fix comments
Jun 28, 2018
f17f9c8
cpplint
Jun 28, 2018
c188404
nit
Jun 29, 2018
de64b97
trigger CI
Jun 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/api/python/ndarray/ndarray.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ The `ndarray` package provides several classes:
:nosignatures:

NDArray.T
NDArray.shape_nd
NDArray.size_nd
NDArray.reshape
NDArray.reshape_like
NDArray.flatten
Expand Down Expand Up @@ -375,6 +377,8 @@ The `ndarray` package provides several classes:
:nosignatures:

cast
shape_nd
size_nd
reshape
reshape_like
flatten
Expand Down
4 changes: 4 additions & 0 deletions docs/api/python/symbol/symbol.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ Composite multiple symbols into a new one by an operator.
:nosignatures:

Symbol.astype
Symbol.shape_nd
Symbol.size_nd
Symbol.reshape
Symbol.reshape_like
Symbol.flatten
Expand Down Expand Up @@ -371,6 +373,8 @@ Composite multiple symbols into a new one by an operator.
:nosignatures:

cast
shape_nd
size_nd
reshape
reshape_like
flatten
Expand Down
16 changes: 16 additions & 0 deletions python/mxnet/ndarray/ndarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1254,6 +1254,22 @@ def flatten(self, *args, **kwargs):
"""
return op.flatten(self, *args, **kwargs)

def shape_nd(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`shape_op`.

The arguments are the same as for :py:func:`shape_op`, with
this array as data.
"""
return op.shape_nd(self, *args, **kwargs)

def size_nd(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`size_op`.

The arguments are the same as for :py:func:`size_op`, with
this array as data.
"""
return op.size_nd(self, *args, **kwargs)

def expand_dims(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`expand_dims`.

Expand Down
16 changes: 16 additions & 0 deletions python/mxnet/symbol/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,22 @@ def flatten(self, *args, **kwargs):
"""
return op.flatten(self, *args, **kwargs)

def shape_nd(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`shape_op`.

The arguments are the same as for :py:func:`shape_op`, with
this array as data.
"""
return op.shape_nd(self, *args, **kwargs)

def size_nd(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`size_op`.

The arguments are the same as for :py:func:`size_op`, with
this array as data.
"""
return op.size_nd(self, *args, **kwargs)

def expand_dims(self, *args, **kwargs):
"""Convenience fluent method for :py:func:`expand_dims`.

Expand Down
33 changes: 33 additions & 0 deletions src/operator/tensor/elemwise_unary_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,39 @@ void CastCompute(const nnvm::NodeAttrs& attrs,
});
}

template<typename xpu>
void ShapeCompute(const nnvm::NodeAttrs& attrs,
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need to make templates for shape and size functions based on the type of device. CPU and GPU FCompute functions are defined respectively in .cc and .cu and don't share anything.

const OpContext& ctx,
const std::vector<TBlob>& inputs,
const std::vector<OpReqType>& req,
const std::vector<TBlob>& outputs) {
CHECK_EQ(inputs.size(), 1U);
CHECK_EQ(outputs.size(), 1U);
CHECK_EQ(req.size(), 1U);
const TBlob& in_data = inputs[0];
const TBlob& out_data = outputs[0];
mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
const TShape& in_shape = in_data.shape_;
MSHADOW_TYPE_SWITCH(out_data.type_flag_, DType, {
mxnet_op::Kernel<mshadow_op::identity_with_cast, xpu>::Launch(
s, in_data.ndim(), out_data.dptr<int64_t>(), in_shape.data());
Copy link
Contributor

Choose a reason for hiding this comment

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

in_shape.data is a pointer in cpu memory which cannot be directly accessed on gpu. You can use Shape<ndim> instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

how come this is not captured by CI?

Copy link
Member Author

Choose a reason for hiding this comment

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

it did, the CI failed for GPU tests. I need to fix it.

});
}

template<typename xpu>
void SizeCompute(const nnvm::NodeAttrs& attrs,
const OpContext& ctx,
const std::vector<TBlob>& inputs,
const std::vector<OpReqType>& req,
const std::vector<TBlob>& outputs) {
CHECK_EQ(inputs.size(), 1U);
CHECK_EQ(outputs.size(), 1U);
CHECK_EQ(req.size(), 1U);
const TBlob& in_data = inputs[0];
const TBlob& out_data = outputs[0];
out_data.dptr<int64_t>()[0] = in_data.Size();
Copy link
Member

Choose a reason for hiding this comment

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

out_data holds a pointer to gpu memory. you need to explicitly use kernel launch to set the value

Copy link
Member Author

Choose a reason for hiding this comment

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

If I use kernel launch then I will need a databuffer pointing to in_data.Size(). How would I get that? because in_data.Size() is of type index_t which does not have data or dptr attribute.

Copy link
Contributor

Choose a reason for hiding this comment

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

You know the output size is only 1, so you can just use 1 for that.

Copy link
Member Author

Choose a reason for hiding this comment

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

mxnet_op::Kernel<mshadow_op::identity_with_cast, xpu>::Launch(s, 1U, out_data.dptr<int64_t>(), < what goes here? - in_data.Size()?? >);

}

Copy link
Contributor

Choose a reason for hiding this comment

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

Please get rid of one blank line here, c++ use only 1 blank line between functions

struct HardSigmoidParam : public dmlc::Parameter<HardSigmoidParam> {
real_t alpha;
real_t beta;
Expand Down
65 changes: 65 additions & 0 deletions src/operator/tensor/elemwise_unary_op_basic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,71 @@ NNVM_REGISTER_OP(reshape_like)
.add_argument("lhs", "NDArray-or-Symbol", "First input.")
.add_argument("rhs", "NDArray-or-Symbol", "Second input.");

NNVM_REGISTER_OP(shape_nd)
.describe(R"code(Returns a 1D int64 array containing the shape of data.

Example::

shape_nd([[1,2,3,4], [5,6,7,8]]) = [2,4]
Copy link
Contributor

Choose a reason for hiding this comment

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

shape_array?


)code" ADD_FILELINE)
.set_num_inputs(1)
.set_num_outputs(1)
.set_attr<nnvm::FIgnoreInputs>("FIgnoreInputs",
[](const NodeAttrs& attrs) { return std::vector<uint32_t>(1, 1); })
.set_attr<FCompute>("FCompute<cpu>", ShapeCompute<cpu>)
.set_attr<nnvm::FInferShape>("FInferShape",
[](const nnvm::NodeAttrs& attrs,
std::vector<TShape> *in_attrs,
std::vector<TShape> *out_attrs) {
CHECK_EQ(in_attrs->size(), 1U);
CHECK_EQ(out_attrs->size(), 1U);
TShape target_shape(1);
target_shape[0] = in_attrs->at(0).ndim();
SHAPE_ASSIGN_CHECK(*out_attrs, 0, target_shape);
return !shape_is_none(out_attrs->at(0));
})
.set_attr<nnvm::FInferType>("FInferType",
Copy link
Member

Choose a reason for hiding this comment

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

not registering FGradient ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Shape operator does not have a differential. Check the conversation here - #10789 (comment)

[](const nnvm::NodeAttrs& attrs,
std::vector<int>* in_attrs,
std::vector<int>* out_attrs) {
CHECK_EQ(in_attrs->size(), 1U);
CHECK_EQ(out_attrs->size(), 1U);
TYPE_ASSIGN_CHECK(*out_attrs, 0, mshadow::kInt64);
return out_attrs->at(0) != -1;
})
.add_argument("data", "NDArray-or-Symbol", "Input Array.");

NNVM_REGISTER_OP(size_nd)
.describe(R"code(Returns a 1D int64 array containing the size of data.

Example::

size_nd([[1,2,3,4], [5,6,7,8]]) = [8]

)code" ADD_FILELINE)
.set_num_inputs(1)
.set_num_outputs(1)
.set_attr<FCompute>("FCompute<cpu>", SizeCompute<cpu>)
.set_attr<nnvm::FInferShape>("FInferShape",
[](const nnvm::NodeAttrs& attrs,
std::vector<TShape> *in_attrs,
std::vector<TShape> *out_attrs) {
CHECK_EQ(in_attrs->size(), 1U);
CHECK_EQ(out_attrs->size(), 1U);
SHAPE_ASSIGN_CHECK(*out_attrs, 0, 1U);
return !shape_is_none(out_attrs->at(0));
})
.set_attr<nnvm::FInferType>("FInferType",
[](const nnvm::NodeAttrs& attrs,
std::vector<int>* in_attrs,
std::vector<int>* out_attrs) {
CHECK_EQ(in_attrs->size(), 1U);
CHECK_EQ(out_attrs->size(), 1U);
TYPE_ASSIGN_CHECK(*out_attrs, 0, mshadow::kInt64);
return out_attrs->at(0) != -1;
})
.add_argument("data", "NDArray-or-Symbol", "Input Array.");

DMLC_REGISTER_PARAMETER(CastParam);
NNVM_REGISTER_OP(Cast)
Expand Down
6 changes: 6 additions & 0 deletions src/operator/tensor/elemwise_unary_op_basic.cu
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ NNVM_REGISTER_OP(_identity_with_attr_like_rhs)
NNVM_REGISTER_OP(reshape_like)
.set_attr<FCompute>("FCompute<gpu>", UnaryOp::IdentityCompute<gpu>);

NNVM_REGISTER_OP(shape_nd)
.set_attr<FCompute>("FCompute<gpu>", ShapeCompute<gpu>);

NNVM_REGISTER_OP(size_nd)
.set_attr<FCompute>("FCompute<gpu>", SizeCompute<gpu>);

NNVM_REGISTER_OP(Cast)
.set_attr<FCompute>("FCompute<gpu>", CastCompute<gpu>);

Expand Down
18 changes: 18 additions & 0 deletions tests/python/unittest/test_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,24 @@ def fsigmoid(a):
check_symbolic_forward(y, [xa], [ya])
check_symbolic_backward(y, [xa], [np.ones(shape)], [ya * (1 - ya)])

@with_seed()
def test_shape():
shape = [3, 4]
x = mx.symbol.Variable("x")
y = mx.sym.shape_nd(x)
xa = np.random.uniform(low=-1.0,high=1.0,size=shape)
ya = np.shape(xa)
check_symbolic_forward(y, [xa], [ya])

@with_seed()
def test_size():
shape = [3, 4]
x = mx.symbol.Variable("x")
y = mx.sym.size_nd(x)
xa = np.random.uniform(low=-1.0,high=1.0,size=shape)
ya = np.array(xa.size).astype(np.int64)
check_symbolic_forward(y, [xa], [ya])

@with_seed()
def test_hard_sigmoid():
def fhardsigmoid(a, alpha=0.2, beta=0.5):
Expand Down