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

Commit 80c6bfc

Browse files
committed
add operator : append ; fix op concatenate when axis = None
1 parent b5d07e3 commit 80c6bfc

File tree

9 files changed

+455
-50
lines changed

9 files changed

+455
-50
lines changed

python/mxnet/ndarray/numpy/_op.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2',
3434
'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
3535
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'tensordot', 'histogram', 'eye',
36-
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate',
36+
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate', 'append',
3737
'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum', 'swapaxes', 'clip', 'argmax',
3838
'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming', 'blackman', 'flip',
3939
'around', 'hypot', 'rad2deg', 'deg2rad', 'unique', 'lcm', 'tril', 'identity', 'take',
@@ -2919,8 +2919,64 @@ def concatenate(seq, axis=0, out=None):
29192919
-------
29202920
res : ndarray
29212921
The concatenated array.
2922+
2923+
Examples
2924+
--------
2925+
>>> a = np.array([[1, 2], [3, 4]])
2926+
>>> b = np.array([[5, 6]])
2927+
>>> np.concatenate((a, b), axis=0)
2928+
array([[1., 2.],
2929+
[3., 4.],
2930+
[5., 6.]])
2931+
2932+
>>> np.concatenate((a, b), axis=None)
2933+
array([1., 2., 3., 4., 5., 6.])
2934+
2935+
>>> np.concatenate((a, b.T), axis=1)
2936+
array([[1., 2., 5.],
2937+
[3., 4., 6.]])
2938+
"""
2939+
return _npi.concatenate(*seq, axis=axis, out=out)
2940+
2941+
2942+
@set_module('mxnet.ndarray.numpy')
2943+
def append(arr, values, axis=None):
2944+
"""
2945+
Append values to the end of an array.
2946+
2947+
Parameters
2948+
----------
2949+
arr : ndarray
2950+
Values are appended to a copy of this array.
2951+
values : ndarray
2952+
These values are appended to a copy of `arr`. It must be of the
2953+
correct shape (the same shape as `arr`, excluding `axis`). If
2954+
`axis` is not specified, `values` can be any shape and will be
2955+
flattened before use.
2956+
axis : int, optional
2957+
The axis along which `values` are appended. If `axis` is not
2958+
given, both `arr` and `values` are flattened before use.
2959+
2960+
Returns
2961+
-------
2962+
append : ndarray
2963+
A copy of `arr` with `values` appended to `axis`. Note that
2964+
`append` does not occur in-place: a new array is allocated and
2965+
filled. If `axis` is None, `out` is a flattened array.
2966+
2967+
Examples
2968+
--------
2969+
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
2970+
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
2971+
2972+
When `axis` is specified, `values` must have the correct shape.
2973+
2974+
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
2975+
array([[1., 2., 3.],
2976+
[4., 5., 6.],
2977+
[7., 8., 9.]])
29222978
"""
2923-
return _npi.concatenate(*seq, dim=axis, out=out)
2979+
return _npi.concatenate(arr, values, axis=axis, out=None)
29242980

29252981

29262982
@set_module('mxnet.ndarray.numpy')

python/mxnet/numpy/multiarray.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
'mod', 'remainder', 'power', 'arctan2', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'log10',
5050
'sqrt', 'cbrt', 'abs', 'absolute', 'exp', 'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log',
5151
'degrees', 'log2', 'log1p', 'rint', 'radians', 'reciprocal', 'square', 'negative',
52-
'fix', 'ceil', 'floor', 'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh',
52+
'fix', 'ceil', 'floor', 'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'append',
5353
'tensordot', 'histogram', 'eye', 'linspace', 'logspace', 'expand_dims', 'tile', 'arange',
5454
'split', 'vsplit', 'concatenate', 'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum',
5555
'swapaxes', 'clip', 'argmax', 'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming',
@@ -4803,10 +4803,53 @@ def concatenate(seq, axis=0, out=None):
48034803
>>> np.concatenate((a, b.T), axis=1)
48044804
array([[1., 2., 5.],
48054805
[3., 4., 6.]])
4806+
4807+
>>> np.concatenate((a, b), axis=None)
4808+
array([1., 2., 3., 4., 5., 6.])
48064809
"""
48074810
return _mx_nd_np.concatenate(seq, axis=axis, out=out)
48084811

48094812

4813+
@set_module('mxnet.numpy')
4814+
def append(arr, values, axis=None):
4815+
"""
4816+
Append values to the end of an array.
4817+
4818+
Parameters
4819+
----------
4820+
arr : ndarray
4821+
Values are appended to a copy of this array.
4822+
values : ndarray
4823+
These values are appended to a copy of `arr`. It must be of the
4824+
correct shape (the same shape as `arr`, excluding `axis`). If
4825+
`axis` is not specified, `values` can be any shape and will be
4826+
flattened before use.
4827+
axis : int, optional
4828+
The axis along which `values` are appended. If `axis` is not
4829+
given, both `arr` and `values` are flattened before use.
4830+
4831+
Returns
4832+
-------
4833+
append : ndarray
4834+
A copy of `arr` with `values` appended to `axis`. Note that
4835+
`append` does not occur in-place: a new array is allocated and
4836+
filled. If `axis` is None, `out` is a flattened array.
4837+
4838+
Examples
4839+
--------
4840+
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
4841+
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
4842+
4843+
When `axis` is specified, `values` must have the correct shape.
4844+
4845+
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
4846+
array([[1., 2., 3.],
4847+
[4., 5., 6.],
4848+
[7., 8., 9.]])
4849+
"""
4850+
return _mx_nd_np.append(arr, values, axis=axis)
4851+
4852+
48104853
@set_module('mxnet.numpy')
48114854
def stack(arrays, axis=0, out=None):
48124855
"""Join a sequence of arrays along a new axis.

python/mxnet/numpy_dispatch_protocol.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def _run_with_array_ufunc_proto(*args, **kwargs):
8686
'argmin',
8787
'argmax',
8888
'around',
89+
'append',
8990
'broadcast_arrays',
9091
'broadcast_to',
9192
'clip',

python/mxnet/symbol/numpy/_symbol.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
'expm1', 'arcsin', 'arccos', 'arctan', 'sign', 'log', 'degrees', 'log2', 'log1p',
3636
'rint', 'radians', 'reciprocal', 'square', 'negative', 'fix', 'ceil', 'floor',
3737
'trunc', 'logical_not', 'arcsinh', 'arccosh', 'arctanh', 'tensordot', 'histogram', 'eye',
38-
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate',
38+
'linspace', 'logspace', 'expand_dims', 'tile', 'arange', 'split', 'vsplit', 'concatenate', 'append',
3939
'stack', 'vstack', 'column_stack', 'dstack', 'mean', 'maximum', 'minimum', 'swapaxes', 'clip', 'argmax',
4040
'argmin', 'std', 'var', 'indices', 'copysign', 'ravel', 'hanning', 'hamming', 'blackman', 'flip',
4141
'around', 'hypot', 'rad2deg', 'deg2rad', 'unique', 'lcm', 'tril', 'identity', 'take',
@@ -2992,6 +2992,7 @@ def vsplit(ary, indices_or_sections):
29922992
@set_module('mxnet.symbol.numpy')
29932993
def concatenate(seq, axis=0, out=None):
29942994
"""Join a sequence of arrays along an existing axis.
2995+
29952996
Parameters
29962997
----------
29972998
a1, a2, ... : sequence of array_like
@@ -3004,12 +3005,69 @@ def concatenate(seq, axis=0, out=None):
30043005
If provided, the destination to place the result. The shape must be
30053006
correct, matching that of what concatenate would have returned if no
30063007
out argument were specified.
3008+
30073009
Returns
30083010
-------
30093011
res : ndarray
30103012
The concatenated array.
3013+
3014+
Examples
3015+
--------
3016+
>>> a = np.array([[1, 2], [3, 4]])
3017+
>>> b = np.array([[5, 6]])
3018+
>>> np.concatenate((a, b), axis=0)
3019+
array([[1., 2.],
3020+
[3., 4.],
3021+
[5., 6.]])
3022+
3023+
>>> np.concatenate((a, b), axis=None)
3024+
array([1., 2., 3., 4., 5., 6.])
3025+
3026+
>>> np.concatenate((a, b.T), axis=1)
3027+
array([[1., 2., 5.],
3028+
[3., 4., 6.]])
3029+
"""
3030+
return _npi.concatenate(*seq, axis=axis, out=out)
3031+
3032+
3033+
@set_module('mxnet.symbol.numpy')
3034+
def append(arr, values, axis=None):
3035+
"""
3036+
Append values to the end of an array.
3037+
3038+
Parameters
3039+
----------
3040+
arr : ndarray
3041+
Values are appended to a copy of this array.
3042+
values : ndarray
3043+
These values are appended to a copy of `arr`. It must be of the
3044+
correct shape (the same shape as `arr`, excluding `axis`). If
3045+
`axis` is not specified, `values` can be any shape and will be
3046+
flattened before use.
3047+
axis : int, optional
3048+
The axis along which `values` are appended. If `axis` is not
3049+
given, both `arr` and `values` are flattened before use.
3050+
3051+
Returns
3052+
-------
3053+
append : ndarray
3054+
A copy of `arr` with `values` appended to `axis`. Note that
3055+
`append` does not occur in-place: a new array is allocated and
3056+
filled. If `axis` is None, `out` is a flattened array.
3057+
3058+
Examples
3059+
--------
3060+
>>> np.append(np.array([1, 2, 3]), np.array([[4, 5, 6],[7, 8, 9]]))
3061+
array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
3062+
3063+
When `axis` is specified, `values` must have the correct shape.
3064+
3065+
>>> np.append(np.array([[1, 2, 3], [4, 5, 6]]), np.array([[7, 8, 9]]), axis=0)
3066+
array([[1., 2., 3.],
3067+
[4., 5., 6.],
3068+
[7., 8., 9.]])
30113069
"""
3012-
return _npi.concatenate(*seq, dim=axis, out=out)
3070+
return _npi.concatenate(arr, values, axis=axis, out=None)
30133071

30143072

30153073
@set_module('mxnet.symbol.numpy')

src/operator/numpy/np_matrix_op-inl.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,87 @@ inline void HSplitOpBackward(const nnvm::NodeAttrs &attrs,
864864
}
865865
SplitOpBackwardImpl<xpu>(attrs, ctx, inputs, req, outputs, real_axis);
866866
}
867+
868+
struct NumpyConcatenateParam : public dmlc::Parameter<NumpyConcatenateParam> {
869+
int num_args;
870+
dmlc::optional<int> axis;
871+
DMLC_DECLARE_PARAMETER(NumpyConcatenateParam) {
872+
DMLC_DECLARE_FIELD(num_args)
873+
.set_lower_bound(1)
874+
.describe("Number of inputs to be concated.");
875+
DMLC_DECLARE_FIELD(axis)
876+
.set_default(dmlc::optional<int>(0))
877+
.describe("The axis along which `values` are appended. If `axis` is not"
878+
"given, both `arr` and `values` are flattened before use.");
879+
}
880+
};
881+
882+
template<typename xpu>
883+
void NumpyConcatenateForward(const nnvm::NodeAttrs& attrs,
884+
const OpContext& ctx,
885+
const std::vector<TBlob>& inputs,
886+
const std::vector<OpReqType>& req,
887+
const std::vector<TBlob>& outputs) {
888+
using namespace mshadow;
889+
using namespace mshadow_op;
890+
891+
const NumpyConcatenateParam& param = nnvm::get<NumpyConcatenateParam>(attrs.parsed);
892+
CHECK_EQ(inputs.size(), param.num_args);
893+
CHECK_EQ(outputs.size(), 1U);
894+
CHECK_EQ(req.size(), 1U);
895+
896+
std::vector<TBlob> data(param.num_args);
897+
for (int i = 0; i < param.num_args; i++) {
898+
if (!param.axis.has_value()) {
899+
data[i] = inputs[i].reshape(Shape1(inputs[i].shape_.Size()));
900+
} else {
901+
data[i] = inputs[i];
902+
}
903+
}
904+
905+
ConcatParam cparam;
906+
cparam.num_args = param.num_args;
907+
cparam.dim = param.axis.has_value() ? param.axis.value() : 0;
908+
MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, DType, {
909+
ConcatOp<xpu, DType> op;
910+
op.Init(cparam);
911+
op.Forward(ctx, data, req, outputs);
912+
});
913+
}
914+
915+
template<typename xpu>
916+
void NumpyConcatenateBackward(const nnvm::NodeAttrs& attrs,
917+
const OpContext& ctx,
918+
const std::vector<TBlob>& inputs,
919+
const std::vector<OpReqType>& req,
920+
const std::vector<TBlob>& outputs) {
921+
using namespace mshadow;
922+
using namespace mshadow_op;
923+
924+
const NumpyConcatenateParam& param = nnvm::get<NumpyConcatenateParam>(attrs.parsed);
925+
CHECK_EQ(inputs.size(), 1U);
926+
CHECK_EQ(outputs.size(), param.num_args);
927+
CHECK_EQ(req.size(), param.num_args);
928+
929+
std::vector<TBlob> data(param.num_args);
930+
for (int i = 0; i < param.num_args; i++) {
931+
if (!param.axis.has_value()) {
932+
data[i] = outputs[i].reshape(Shape1(outputs[i].shape_.Size()));
933+
} else {
934+
data[i] = outputs[i];
935+
}
936+
}
937+
938+
ConcatParam cparam;
939+
cparam.num_args = param.num_args;
940+
cparam.dim = param.axis.has_value() ? param.axis.value() : 0;
941+
MSHADOW_TYPE_SWITCH(inputs[0].type_flag_, DType, {
942+
ConcatOp<xpu, DType> op;
943+
op.Init(cparam);
944+
op.Backward(ctx, inputs[0], req, data);
945+
});
946+
}
947+
867948
} // namespace op
868949
} // namespace mxnet
869950

0 commit comments

Comments
 (0)