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

Commit

Permalink
[numpy] add numpy operator : append (#16564)
Browse files Browse the repository at this point in the history
* add operator : append ; fix op concatenate when axis = None

* pylint disable

remove mistake

disable pylint
  • Loading branch information
JiangZhaoh authored and haojin2 committed Nov 1, 2019
1 parent 9f6e819 commit 6c42992
Show file tree
Hide file tree
Showing 9 changed files with 458 additions and 53 deletions.
62 changes: 59 additions & 3 deletions python/mxnet/ndarray/numpy/_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2',
'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'tensordot', 'histogram', 'eye',
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate',
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate', 'append',
'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum', 'swapaxes', 'clip', 'argmax',
'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming', 'blackman', 'flip',
'around', 'hypot', 'rad2deg', 'deg2rad', 'unique', 'lcm', 'tril', 'identity', 'take',
Expand Down Expand Up @@ -2919,8 +2919,64 @@ def concatenate(seq, axis=0, out=None):
-------
res : ndarray
The concatenated array.
Examples
--------
>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])
>>> np.concatenate((a, b), axis=0)
array([[1., 2.],
[3., 4.],
[5., 6.]])
>>> np.concatenate((a, b), axis=None)
array([1., 2., 3., 4., 5., 6.])
>>> np.concatenate((a, b.T), axis=1)
array([[1., 2., 5.],
[3., 4., 6.]])
"""
return _npi.concatenate(*seq, axis=axis, out=out)


@set_module('mxnet.ndarray.numpy')
def append(arr, values, axis=None): # pylint: disable=redefined-outer-name
"""
Append values to the end of an array.
Parameters
----------
arr : ndarray
Values are appended to a copy of this array.
values : ndarray
These values are appended to a copy of `arr`. It must be of the
correct shape (the same shape as `arr`, excluding `axis`). If
`axis` is not specified, `values` can be any shape and will be
flattened before use.
axis : int, optional
The axis along which `values` are appended. If `axis` is not
given, both `arr` and `values` are flattened before use.
Returns
-------
append : ndarray
A copy of `arr` with `values` appended to `axis`. Note that
`append` does not occur in-place: a new array is allocated and
filled. If `axis` is None, `out` is a flattened array.
Examples
--------
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
When `axis` is specified, `values` must have the correct shape.
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
"""
return _npi.concatenate(*seq, dim=axis, out=out)
return _npi.concatenate(arr, values, axis=axis, out=None)


@set_module('mxnet.ndarray.numpy')
Expand Down Expand Up @@ -5014,7 +5070,7 @@ def may_share_memory(a, b, max_work=None):
return _npi.share_memory(a, b).item()


def diff(a, n=1, axis=-1, prepend=None, append=None):
def diff(a, n=1, axis=-1, prepend=None, append=None): # pylint: disable=redefined-outer-name
r"""
numpy.diff(a, n=1, axis=-1, prepend=<no value>, append=<no value>)
Expand Down
47 changes: 45 additions & 2 deletions python/mxnet/numpy/multiarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
'mod', 'remainder', 'power', 'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10',
'sqrt', 'cbrt', 'abs', 'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log',
'degrees', 'log2', 'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative',
'fix', 'ceil', 'floor', 'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh',
'fix', 'ceil', 'floor', 'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'append',
'tensordot', 'histogram', 'eye', 'linspace', 'logspace', 'expand_dims', 'tile', 'arange',
'split', 'vsplit', 'concatenate', 'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum',
'swapaxes', 'clip', 'argmax', 'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming',
Expand Down Expand Up @@ -4803,10 +4803,53 @@ def concatenate(seq, axis=0, out=None):
>>> np.concatenate((a, b.T), axis=1)
array([[1., 2., 5.],
[3., 4., 6.]])
>>> np.concatenate((a, b), axis=None)
array([1., 2., 3., 4., 5., 6.])
"""
return _mx_nd_np.concatenate(seq, axis=axis, out=out)


@set_module('mxnet.numpy')
def append(arr, values, axis=None): # pylint: disable=redefined-outer-name
"""
Append values to the end of an array.
Parameters
----------
arr : ndarray
Values are appended to a copy of this array.
values : ndarray
These values are appended to a copy of `arr`. It must be of the
correct shape (the same shape as `arr`, excluding `axis`). If
`axis` is not specified, `values` can be any shape and will be
flattened before use.
axis : int, optional
The axis along which `values` are appended. If `axis` is not
given, both `arr` and `values` are flattened before use.
Returns
-------
append : ndarray
A copy of `arr` with `values` appended to `axis`. Note that
`append` does not occur in-place: a new array is allocated and
filled. If `axis` is None, `out` is a flattened array.
Examples
--------
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
When `axis` is specified, `values` must have the correct shape.
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
"""
return _mx_nd_np.append(arr, values, axis=axis)


@set_module('mxnet.numpy')
def stack(arrays, axis=0, out=None):
"""Join a sequence of arrays along a new axis.
Expand Down Expand Up @@ -7018,7 +7061,7 @@ def may_share_memory(a, b, max_work=None):
return _mx_nd_np.may_share_memory(a, b, max_work)


def diff(a, n=1, axis=-1, prepend=None, append=None):
def diff(a, n=1, axis=-1, prepend=None, append=None): # pylint: disable=redefined-outer-name
r"""
numpy.diff(a, n=1, axis=-1, prepend=<no value>, append=<no value>)
Expand Down
1 change: 1 addition & 0 deletions python/mxnet/numpy_dispatch_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def _run_with_array_ufunc_proto(*args, **kwargs):
'argmin',
'argmax',
'around',
'append',
'broadcast_arrays',
'broadcast_to',
'clip',
Expand Down
64 changes: 61 additions & 3 deletions python/mxnet/symbol/numpy/_symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p',
'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'tensordot', 'histogram', 'eye',
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate',
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate', 'append',
'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum', 'swapaxes', 'clip', 'argmax',
'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming', 'blackman', 'flip',
'around', 'hypot', 'rad2deg', 'deg2rad', 'unique', 'lcm', 'tril', 'identity', 'take',
Expand Down Expand Up @@ -2992,6 +2992,7 @@ def vsplit(ary, indices_or_sections):
@set_module('mxnet.symbol.numpy')
def concatenate(seq, axis=0, out=None):
"""Join a sequence of arrays along an existing axis.
Parameters
----------
a1, a2, ... : sequence of array_like
Expand All @@ -3004,12 +3005,69 @@ def concatenate(seq, axis=0, out=None):
If provided, the destination to place the result. The shape must be
correct, matching that of what concatenate would have returned if no
out argument were specified.
Returns
-------
res : ndarray
The concatenated array.
Examples
--------
>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])
>>> np.concatenate((a, b), axis=0)
array([[1., 2.],
[3., 4.],
[5., 6.]])
>>> np.concatenate((a, b), axis=None)
array([1., 2., 3., 4., 5., 6.])
>>> np.concatenate((a, b.T), axis=1)
array([[1., 2., 5.],
[3., 4., 6.]])
"""
return _npi.concatenate(*seq, axis=axis, out=out)


@set_module('mxnet.symbol.numpy')
def append(arr, values, axis=None): # pylint: disable=redefined-outer-name
"""
Append values to the end of an array.
Parameters
----------
arr : ndarray
Values are appended to a copy of this array.
values : ndarray
These values are appended to a copy of `arr`. It must be of the
correct shape (the same shape as `arr`, excluding `axis`). If
`axis` is not specified, `values` can be any shape and will be
flattened before use.
axis : int, optional
The axis along which `values` are appended. If `axis` is not
given, both `arr` and `values` are flattened before use.
Returns
-------
append : ndarray
A copy of `arr` with `values` appended to `axis`. Note that
`append` does not occur in-place: a new array is allocated and
filled. If `axis` is None, `out` is a flattened array.
Examples
--------
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
When `axis` is specified, `values` must have the correct shape.
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
"""
return _npi.concatenate(*seq, dim=axis, out=out)
return _npi.concatenate(arr, values, axis=axis, out=None)


@set_module('mxnet.symbol.numpy')
Expand Down Expand Up @@ -4665,7 +4723,7 @@ def may_share_memory(a, b, max_work=None):
return _npi.share_memory(a, b)


def diff(a, n=1, axis=-1, prepend=None, append=None):
def diff(a, n=1, axis=-1, prepend=None, append=None): # pylint: disable=redefined-outer-name
r"""
numpy.diff(a, n=1, axis=-1, prepend=<no value>, append=<no value>)
Expand Down
81 changes: 81 additions & 0 deletions src/operator/numpy/np_matrix_op-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,87 @@ inline void HSplitOpBackward(const nnvm::NodeAttrs &attrs,
}
SplitOpBackwardImpl<xpu>(attrs, ctx, inputs, req, outputs, real_axis);
}

struct NumpyConcatenateParam : public dmlc::Parameter<NumpyConcatenateParam> {
int num_args;
dmlc::optional<int> axis;
DMLC_DECLARE_PARAMETER(NumpyConcatenateParam) {
DMLC_DECLARE_FIELD(num_args)
.set_lower_bound(1)
.describe("Number of inputs to be concated.");
DMLC_DECLARE_FIELD(axis)
.set_default(dmlc::optional<int>(0))
.describe("The axis along which `values` are appended. If `axis` is not"
"given, both `arr` and `values` are flattened before use.");
}
};

template<typename xpu>
void NumpyConcatenateForward(const nnvm::NodeAttrs& attrs,
const OpContext& ctx,
const std::vector<TBlob>& inputs,
const std::vector<OpReqType>& req,
const std::vector<TBlob>& outputs) {
using namespace mshadow;
using namespace mshadow_op;

const NumpyConcatenateParam& param = nnvm::get<NumpyConcatenateParam>(attrs.parsed);
CHECK_EQ(inputs.size(), param.num_args);
CHECK_EQ(outputs.size(), 1U);
CHECK_EQ(req.size(), 1U);

std::vector<TBlob> data(param.num_args);
for (int i = 0; i < param.num_args; i++) {
if (!param.axis.has_value()) {
data[i] = inputs[i].reshape(Shape1(inputs[i].shape_.Size()));
} else {
data[i] = inputs[i];
}
}

ConcatParam cparam;
cparam.num_args = param.num_args;
cparam.dim = param.axis.has_value() ? param.axis.value() : 0;
MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, DType, {
ConcatOp<xpu, DType> op;
op.Init(cparam);
op.Forward(ctx, data, req, outputs);
});
}

template<typename xpu>
void NumpyConcatenateBackward(const nnvm::NodeAttrs& attrs,
const OpContext& ctx,
const std::vector<TBlob>& inputs,
const std::vector<OpReqType>& req,
const std::vector<TBlob>& outputs) {
using namespace mshadow;
using namespace mshadow_op;

const NumpyConcatenateParam& param = nnvm::get<NumpyConcatenateParam>(attrs.parsed);
CHECK_EQ(inputs.size(), 1U);
CHECK_EQ(outputs.size(), param.num_args);
CHECK_EQ(req.size(), param.num_args);

std::vector<TBlob> data(param.num_args);
for (int i = 0; i < param.num_args; i++) {
if (!param.axis.has_value()) {
data[i] = outputs[i].reshape(Shape1(outputs[i].shape_.Size()));
} else {
data[i] = outputs[i];
}
}

ConcatParam cparam;
cparam.num_args = param.num_args;
cparam.dim = param.axis.has_value() ? param.axis.value() : 0;
MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, DType, {
ConcatOp<xpu, DType> op;
op.Init(cparam);
op.Backward(ctx, inputs[0], req, data);
});
}

} // namespace op
} // namespace mxnet

Expand Down
Loading

0 comments on commit 6c42992

Please sign in to comment.