[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-12 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r303094273
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op.cc
 ##
 @@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op.cc
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+bool TensordotOpShape(const nnvm::NodeAttrs& attrs,
+  mxnet::ShapeVector *in_attrs,
+  mxnet::ShapeVector *out_attrs) {
+  CHECK_EQ(in_attrs->size(), 2U);
+  CHECK_EQ(out_attrs->size(), 1U);
+
+  const mxnet::TShape& a_shape = in_attrs->at(0);
+  const mxnet::TShape& b_shape = in_attrs->at(1);
+
+  if (!ndim_is_known(a_shape) || !ndim_is_known(b_shape)) {
+return false;
+  }
+
+  if ((a_shape.ndim() < 1) || (b_shape.ndim() < 1)) {
+return false;
+  }
+
+  const TensordotParam& param = nnvm::get(attrs.parsed);
+  const Tuple& a_axes_summed = param.a_axes_summed;
+  const Tuple& b_axes_summed = param.b_axes_summed;
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+   _axes, a_shape, b_shape);
+
+  CHECK_EQ(a_axes_summed.ndim(), b_axes_summed.ndim());
+
+  mxnet::TShape out_shape(a_axes_remained.ndim() + b_axes_remained.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+out_shape[i] = a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+out_shape[a_axes_remained.ndim() + i] = b_shape[b_axes_remained[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*out_attrs, 0, out_shape);
+
+  mxnet::TShape tem_shape1(a_axes.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+tem_shape1[a_axes_remained[i]] = out_shape[i];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+tem_shape1[a_axes_summed[i]] = b_shape[b_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 0, tem_shape1);
+
+  mxnet::TShape tem_shape2(b_axes.ndim(), -1);
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+tem_shape2[b_axes_remained[i]] = out_shape[a_axes_remained.ndim() + i];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+tem_shape2[b_axes_summed[i]] = a_shape[a_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 1, tem_shape2);
+
+  return shape_is_known(*in_attrs) && shape_is_known(*out_attrs);
+}
+
+DMLC_REGISTER_PARAMETER(TensordotParam);
+
+NNVM_REGISTER_OP(_npi_tensordot)
+.set_attr_parser(mxnet::op::ParamParser)
+.set_num_inputs(2)
+.set_num_outputs(1)
+.set_attr("FListInputNames",
+  [](const NodeAttrs& attrs) {
+return std::vector{"a", "b"};
+  })
+.set_attr("FInferShape", TensordotOpShape)
+.set_attr("FInferType", mxnet::op::ElemwiseType<2, 1>)
+.set_attr("FResourceRequest",
+  [](const NodeAttrs& attrs) {
+return std::vector{ResourceRequest::kTempSpace};
+  })
+.set_attr("FCompute", TensordotOpForward)
+.set_attr("FGradient", 
mxnet::op::ElemwiseGradUseIn{"_backward_npi_tensordot"})
+.add_argument("a", "NDArray-or-Symbol", "First input")
+.add_argument("b", "NDArray-or-Symbol", "Second input")
+.add_arguments(TensordotParam::__FIELDS__());
+
+NNVM_REGISTER_OP(_backward_npi_tensordot)
+.set_attr_parser(mxnet::op::ParamParser)
+.set_num_inputs(3)
+.set_num_outputs(2)
+.set_attr("TIsBackward", true)
+.set_attr("FResourceRequest",
+  [](const NodeAttrs& attrs) {
+return std::vector{ResourceRequest::kTempSpace};
+  })
+.set_attr("FCompute", TensordotOpBackward);
+
+bool TensordotIntAxesOpShape(const nnvm::NodeAttrs& attrs,
+ mxnet::ShapeVector *in_attrs,
+ mxnet::ShapeVector *out_attrs) {
+  CHECK_EQ(in_attrs->size(), 2U);
+  CHECK_EQ(out_attrs->size(), 1U);
+
+  const mxnet::TShape& a_shape = in_attrs->at(0);
+  const mxnet::TShape& b_shape = in_attrs->at(1);
+
+  if (!ndim_is_known(a_shape) || !ndim_is_known(b_shape)) {
+return false;
+  }
+
+  if ((a_shape.ndim() < 1) || (b_shape.ndim() < 1)) {
+return false;
+  }
+
+  const 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-12 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r303094358
 
 

 ##
 File path: tests/python/unittest/test_numpy_op.py
 ##
 @@ -26,6 +26,151 @@
 from mxnet.test_utils import check_numeric_gradient
 from common import assertRaises, with_seed
 import random
+import collections
+
 
 Review comment:
   one more blank line.


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302813785
 
 

 ##
 File path: tests/python/unittest/test_numpy_op.py
 ##
 @@ -26,6 +26,151 @@
 from mxnet.test_utils import check_numeric_gradient
 from common import assertRaises, with_seed
 import random
+import collections
+
+@with_seed()
+@npx.use_np_shape
+def test_np_tensordot():
+class TestTensordot(HybridBlock):
+def __init__(self, axes):
+super(TestTensordot, self).__init__()
+self._axes = axes
+
+def hybrid_forward(self, F, a, b):
+return F.np.tensordot(a, b, self._axes)
+
+def tensordot_backward(a, b, axes = 2):
+if (a.ndim < 1) or (b.ndim < 1):
+raise ValueError('An input is zero-dim')
+
+if isinstance(axes, collections.abc.Sequence):
+if len(axes) != 2:
+raise ValueError('Axes must consist of two arrays.')
+a_axes_summed, b_axes_summed = axes
+if _np.isscalar(a_axes_summed):
+a_axes_summed = a_axes_summed,
+if _np.isscalar(b_axes_summed):
+b_axes_summed = b_axes_summed,
+else:
+a_axes_summed = [i + a.ndim - axes for i in range(axes)]
+b_axes_summed = [i for i in range(axes)]
+
+if len(a_axes_summed) != len(b_axes_summed):
+raise ValueError('Axes length mismatch') 
+
+a_axes_remained = []
+for i in range(a.ndim):
+if not (i in a_axes_summed):
+a_axes_remained.append(i)
+a_axes = a_axes_remained[:] + a_axes_summed[:]
+
+b_axes_remained = []
+for i in range(b.ndim):
+if not (i in b_axes_summed):
+b_axes_remained.append(i)
+b_axes = b_axes_summed[:] + b_axes_remained[:]
+
+ad1 = _np.prod([a.shape[i] for i in a_axes_remained]) if 
len(a_axes_remained) > 0 else 1
+ad2 = _np.prod([a.shape[i] for i in a_axes_summed]) if 
len(a_axes_summed) > 0 else 1
+bd1 = _np.prod([b.shape[i] for i in b_axes_summed]) if 
len(b_axes_summed) > 0 else 1
+bd2 = _np.prod([b.shape[i] for i in b_axes_remained]) if 
len(b_axes_remained) > 0 else 1
+
+out_grad = _np.ones((ad1, bd2))
+
+new_a = _np.transpose(a, a_axes)
+new_a_shape = new_a.shape[:]
+new_a = new_a.reshape((ad1, ad2)) 
+new_b = _np.transpose(b, b_axes) 
+new_b_shape = new_b.shape[:]
+new_b = new_b.reshape((bd1, bd2))
+
+reverse_a_axes = [0 for i in a_axes]
+for i in range(len(a_axes)):
+reverse_a_axes[a_axes[i]] = i
+
+reverse_b_axes = [0 for i in b_axes]
+for i in range(len(b_axes)):
+reverse_b_axes[b_axes[i]] = i
+
+grad_b = _np.dot(new_a.T, out_grad).reshape(new_b_shape)
+grad_b = _np.transpose(grad_b, reverse_b_axes)
+grad_a = _np.dot(out_grad, new_b.T).reshape(new_a_shape)
+grad_a = _np.transpose(grad_a, reverse_a_axes)
+
+return [grad_a, grad_b]
+
+# test non zero size input
+tensor_shapes = [ 
+((3, 5), (5, 4), 1),  # (a_shape, b_shape, axes)
+((3,), (3,), 1),   
+((3, 4, 5, 6, 7), (5, 6, 7, 1, 2), 3),
+((3, 5, 4, 6, 7), (7, 6, 5, 1, 2), [[1, 3, 4], [2, 1, 0]]),
+((2, 2), (2, 2), 2),
+((3, 5, 4), (5, ), [[1], [0]]),  
+((2,), (2, 3), 1),
+((3,), (3,), 0),
+((2,), (2, 3), 0),
+((3, 5, 4), (5, ), 0)
+]
+
+for hybridize in [True, False]:
+for a_shape, b_shape, axes in tensor_shapes:
+for dtype in [_np.float32, _np.float64]:
 
 Review comment:
   what about fp16?


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302812085
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op.cc
 ##
 @@ -0,0 +1,344 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op.cc
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+bool TensordotOpShape(
+const nnvm::NodeAttrs& attrs,
+mxnet::ShapeVector *in_attrs,
+mxnet::ShapeVector *out_attrs) {
+  CHECK_EQ(in_attrs->size(), 2U);
+  CHECK_EQ(out_attrs->size(), 1U);
+
+  const mxnet::TShape& a_shape = in_attrs->at(0);
+  const mxnet::TShape& b_shape = in_attrs->at(1);
+
+  if (!ndim_is_known(a_shape) || !ndim_is_known(b_shape)) {
+return false;
+  }
+
+  if ((a_shape.ndim() < 1) || (b_shape.ndim() < 1)) {
+return false;
+  }
+
+  const TensordotParam& param = nnvm::get(attrs.parsed);
+  const Tuple& a_axes_summed = param.a_axes_summed;
+  const Tuple& b_axes_summed = param.b_axes_summed;
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+   _axes, a_shape, b_shape);
+
+  CHECK_EQ(a_axes_summed.ndim(), b_axes_summed.ndim());
+
+  mxnet::TShape out_shape(a_axes_remained.ndim() + b_axes_remained.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+out_shape[i] = a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+out_shape[a_axes_remained.ndim() + i] = b_shape[b_axes_remained[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*out_attrs, 0, out_shape);
+
+  mxnet::TShape tem_shape1(a_axes.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+tem_shape1[a_axes_remained[i]] = out_shape[i];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+tem_shape1[a_axes_summed[i]] = b_shape[b_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 0, tem_shape1);
+
+  mxnet::TShape tem_shape2(b_axes.ndim(), -1);
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+tem_shape2[b_axes_remained[i]] = out_shape[a_axes_remained.ndim() + i];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+tem_shape2[b_axes_summed[i]] = a_shape[a_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 1, tem_shape2);
+
+  return shape_is_known(*in_attrs) && shape_is_known(*out_attrs);
+}
+
+DMLC_REGISTER_PARAMETER(TensordotParam);
+
+NNVM_REGISTER_OP(_npi_tensordot)
+.describe(R"code(tensordot(a, b, axes=2)
+
+Compute tensor dot product along specified axes for arrays >= 1-D.
+
+Given two tensors (arrays of dimension greater than or equal to one),
+`a` and `b`, and an array_like object containing two array_like
+objects, ``(a_axes, b_axes)``, sum the products of `a`'s and `b`'s
+elements (components) over the axes specified by ``a_axes`` and
+``b_axes``. The third argument can be a single non-negative
+integer_like scalar, ``N``; if it is such, then the last ``N``
+dimensions of `a` and the first ``N`` dimensions of `b` are summed
+over.
+
+Parameters
+--
+a, b : ndarray, len(shape) >= 1
+Tensors to "dot".
+
 
 Review comment:
   Please get rid of this description since:
   1. this piece of doc does not describe how this internal operator behaves.
   2. this will not be seen by users.
   3. you already have a wrapper which contains the same doc.
   Same comment for your `int_axes` operator


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302804904
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
+const mxnet::Tuple& a_axes_remained,
+const mxnet::Tuple& a_axes_summed,
+const mxnet::Tuple& b_axes_remained,
+const mxnet::Tuple& b_axes_summed,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  *ad1 = 1;
+  *ad2 = 1;
+  *bd1 = 1;
+  *bd2 = 1;
+
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+*ad1 *= a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+*ad2 *= a_shape[a_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+*bd1 *= b_shape[b_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+*bd2 *= b_shape[b_axes_remained[i]];
+  }
+}
+
+/**
+ * gets new axes of a and b after transpose and reshape.
+ */
+inline void GetReorderedAxes(
+const mxnet::Tuple& a_axes_summed,
+mxnet::Tuple* a_axes_remained,
+mxnet::Tuple* a_axes,
+const mxnet::Tuple& b_axes_summed,
+mxnet::Tuple* b_axes_remained,
+mxnet::Tuple* b_axes,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  std::vector a_axes_remained_vector;
+  for (int i = 0; i < a_shape.ndim(); i++) {
+a_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : a_axes_summed) {
+a_axes_remained_vector.erase(std::find(a_axes_remained_vector.begin(),
+  a_axes_remained_vector.end(), i));
+  }
+  *a_axes_remained = mxnet::Tuple(a_axes_remained_vector);
+
+  std::vector a_axes_vector(a_axes_remained_vector);
+  for (auto& i : a_axes_summed) {
+a_axes_vector.push_back(i);
+  }
+  *a_axes = mxnet::Tuple(a_axes_vector);
+
+  std::vector b_axes_remained_vector;
+  for (int i = 0; i < b_shape.ndim(); i++) {
+b_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : b_axes_summed) {
+b_axes_remained_vector.erase(std::find(b_axes_remained_vector.begin(),
+  b_axes_remained_vector.end(), i));
+  }
+  *b_axes_remained = mxnet::Tuple(b_axes_remained_vector);
+
+  std::vector b_axes_vector;
+  for (auto& i : b_axes_summed) {
+b_axes_vector.push_back(i);
+  }
+  for (auto& i : b_axes_remained_vector) {
+b_axes_vector.push_back(i);
+  }
+  *b_axes = mxnet::Tuple(b_axes_vector);
+}
+
+/**
+ * gets shapes of a and b after transpose and reshape.
+ */
+inline mxnet::TShape GetReorderedShape(const mxnet::TShape& shape, const 
mxnet::Tuple& axes) {
+  mxnet::TShape new_shape(shape);
+  for (int i = 0; i < axes.ndim(); i++) {
+new_shape[i] = shape[axes[i]];
+  }
+  return new_shape;
+}
+
+/**
+ * gets matrix dot. Reshapes tensor a as ad1-by-ad2 matrix, tensor b as 
bd1-by-bd2 matrix, then 
+ * calculates matrix dot a * b and stores in tensor out.
+ */
+template
+void MatrixDot(
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const OpReqType req,
+const int ad1,
+const int ad2,
+const int bd1,
+const int bd2,
+const bool aT = false,
+const bool bT = false) {
+  using namespace mshadow;
+  using namespace mshadow_op;
+
+  Stream *s = ctx.get_stream();
+
+  MSHADOW_REAL_TYPE_SWITCH(out.type_flag_, DType, {
+Tensor a_tensor = a.get_with_shape(Shape2(ad1, ad2), s);
+Tensor b_tensor 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302804904
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
+const mxnet::Tuple& a_axes_remained,
+const mxnet::Tuple& a_axes_summed,
+const mxnet::Tuple& b_axes_remained,
+const mxnet::Tuple& b_axes_summed,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  *ad1 = 1;
+  *ad2 = 1;
+  *bd1 = 1;
+  *bd2 = 1;
+
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+*ad1 *= a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+*ad2 *= a_shape[a_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+*bd1 *= b_shape[b_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+*bd2 *= b_shape[b_axes_remained[i]];
+  }
+}
+
+/**
+ * gets new axes of a and b after transpose and reshape.
+ */
+inline void GetReorderedAxes(
+const mxnet::Tuple& a_axes_summed,
+mxnet::Tuple* a_axes_remained,
+mxnet::Tuple* a_axes,
+const mxnet::Tuple& b_axes_summed,
+mxnet::Tuple* b_axes_remained,
+mxnet::Tuple* b_axes,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  std::vector a_axes_remained_vector;
+  for (int i = 0; i < a_shape.ndim(); i++) {
+a_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : a_axes_summed) {
+a_axes_remained_vector.erase(std::find(a_axes_remained_vector.begin(),
+  a_axes_remained_vector.end(), i));
+  }
+  *a_axes_remained = mxnet::Tuple(a_axes_remained_vector);
+
+  std::vector a_axes_vector(a_axes_remained_vector);
+  for (auto& i : a_axes_summed) {
+a_axes_vector.push_back(i);
+  }
+  *a_axes = mxnet::Tuple(a_axes_vector);
+
+  std::vector b_axes_remained_vector;
+  for (int i = 0; i < b_shape.ndim(); i++) {
+b_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : b_axes_summed) {
+b_axes_remained_vector.erase(std::find(b_axes_remained_vector.begin(),
+  b_axes_remained_vector.end(), i));
+  }
+  *b_axes_remained = mxnet::Tuple(b_axes_remained_vector);
+
+  std::vector b_axes_vector;
+  for (auto& i : b_axes_summed) {
+b_axes_vector.push_back(i);
+  }
+  for (auto& i : b_axes_remained_vector) {
+b_axes_vector.push_back(i);
+  }
+  *b_axes = mxnet::Tuple(b_axes_vector);
+}
+
+/**
+ * gets shapes of a and b after transpose and reshape.
+ */
+inline mxnet::TShape GetReorderedShape(const mxnet::TShape& shape, const 
mxnet::Tuple& axes) {
+  mxnet::TShape new_shape(shape);
+  for (int i = 0; i < axes.ndim(); i++) {
+new_shape[i] = shape[axes[i]];
+  }
+  return new_shape;
+}
+
+/**
+ * gets matrix dot. Reshapes tensor a as ad1-by-ad2 matrix, tensor b as 
bd1-by-bd2 matrix, then 
+ * calculates matrix dot a * b and stores in tensor out.
+ */
+template
+void MatrixDot(
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const OpReqType req,
+const int ad1,
+const int ad2,
+const int bd1,
+const int bd2,
+const bool aT = false,
+const bool bT = false) {
+  using namespace mshadow;
+  using namespace mshadow_op;
+
+  Stream *s = ctx.get_stream();
+
+  MSHADOW_REAL_TYPE_SWITCH(out.type_flag_, DType, {
+Tensor a_tensor = a.get_with_shape(Shape2(ad1, ad2), s);
+Tensor b_tensor 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302804045
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
+const mxnet::Tuple& a_axes_remained,
+const mxnet::Tuple& a_axes_summed,
+const mxnet::Tuple& b_axes_remained,
+const mxnet::Tuple& b_axes_summed,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  *ad1 = 1;
+  *ad2 = 1;
+  *bd1 = 1;
+  *bd2 = 1;
+
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+*ad1 *= a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+*ad2 *= a_shape[a_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+*bd1 *= b_shape[b_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+*bd2 *= b_shape[b_axes_remained[i]];
+  }
+}
+
+/**
+ * gets new axes of a and b after transpose and reshape.
+ */
+inline void GetReorderedAxes(
+const mxnet::Tuple& a_axes_summed,
+mxnet::Tuple* a_axes_remained,
+mxnet::Tuple* a_axes,
+const mxnet::Tuple& b_axes_summed,
+mxnet::Tuple* b_axes_remained,
+mxnet::Tuple* b_axes,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  std::vector a_axes_remained_vector;
+  for (int i = 0; i < a_shape.ndim(); i++) {
+a_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : a_axes_summed) {
+a_axes_remained_vector.erase(std::find(a_axes_remained_vector.begin(),
+  a_axes_remained_vector.end(), i));
+  }
+  *a_axes_remained = mxnet::Tuple(a_axes_remained_vector);
+
+  std::vector a_axes_vector(a_axes_remained_vector);
+  for (auto& i : a_axes_summed) {
+a_axes_vector.push_back(i);
+  }
+  *a_axes = mxnet::Tuple(a_axes_vector);
+
+  std::vector b_axes_remained_vector;
+  for (int i = 0; i < b_shape.ndim(); i++) {
+b_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : b_axes_summed) {
+b_axes_remained_vector.erase(std::find(b_axes_remained_vector.begin(),
+  b_axes_remained_vector.end(), i));
+  }
+  *b_axes_remained = mxnet::Tuple(b_axes_remained_vector);
+
+  std::vector b_axes_vector;
+  for (auto& i : b_axes_summed) {
+b_axes_vector.push_back(i);
+  }
+  for (auto& i : b_axes_remained_vector) {
+b_axes_vector.push_back(i);
+  }
+  *b_axes = mxnet::Tuple(b_axes_vector);
+}
+
+/**
+ * gets shapes of a and b after transpose and reshape.
+ */
+inline mxnet::TShape GetReorderedShape(const mxnet::TShape& shape, const 
mxnet::Tuple& axes) {
+  mxnet::TShape new_shape(shape);
+  for (int i = 0; i < axes.ndim(); i++) {
+new_shape[i] = shape[axes[i]];
+  }
+  return new_shape;
+}
+
+/**
+ * gets matrix dot. Reshapes tensor a as ad1-by-ad2 matrix, tensor b as 
bd1-by-bd2 matrix, then 
+ * calculates matrix dot a * b and stores in tensor out.
+ */
+template
+void MatrixDot(
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const OpReqType req,
+const int ad1,
+const int ad2,
+const int bd1,
+const int bd2,
+const bool aT = false,
+const bool bT = false) {
+  using namespace mshadow;
+  using namespace mshadow_op;
+
+  Stream *s = ctx.get_stream();
+
+  MSHADOW_REAL_TYPE_SWITCH(out.type_flag_, DType, {
+Tensor a_tensor = a.get_with_shape(Shape2(ad1, ad2), s);
+Tensor b_tensor 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302804104
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
+const mxnet::Tuple& a_axes_remained,
+const mxnet::Tuple& a_axes_summed,
+const mxnet::Tuple& b_axes_remained,
+const mxnet::Tuple& b_axes_summed,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  *ad1 = 1;
+  *ad2 = 1;
+  *bd1 = 1;
+  *bd2 = 1;
+
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+*ad1 *= a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+*ad2 *= a_shape[a_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+*bd1 *= b_shape[b_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+*bd2 *= b_shape[b_axes_remained[i]];
+  }
+}
+
+/**
+ * gets new axes of a and b after transpose and reshape.
+ */
+inline void GetReorderedAxes(
+const mxnet::Tuple& a_axes_summed,
+mxnet::Tuple* a_axes_remained,
+mxnet::Tuple* a_axes,
+const mxnet::Tuple& b_axes_summed,
+mxnet::Tuple* b_axes_remained,
+mxnet::Tuple* b_axes,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  std::vector a_axes_remained_vector;
+  for (int i = 0; i < a_shape.ndim(); i++) {
+a_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : a_axes_summed) {
+a_axes_remained_vector.erase(std::find(a_axes_remained_vector.begin(),
+  a_axes_remained_vector.end(), i));
+  }
+  *a_axes_remained = mxnet::Tuple(a_axes_remained_vector);
+
+  std::vector a_axes_vector(a_axes_remained_vector);
+  for (auto& i : a_axes_summed) {
+a_axes_vector.push_back(i);
+  }
+  *a_axes = mxnet::Tuple(a_axes_vector);
+
+  std::vector b_axes_remained_vector;
+  for (int i = 0; i < b_shape.ndim(); i++) {
+b_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : b_axes_summed) {
+b_axes_remained_vector.erase(std::find(b_axes_remained_vector.begin(),
+  b_axes_remained_vector.end(), i));
+  }
+  *b_axes_remained = mxnet::Tuple(b_axes_remained_vector);
+
+  std::vector b_axes_vector;
+  for (auto& i : b_axes_summed) {
+b_axes_vector.push_back(i);
+  }
+  for (auto& i : b_axes_remained_vector) {
+b_axes_vector.push_back(i);
+  }
+  *b_axes = mxnet::Tuple(b_axes_vector);
+}
+
+/**
+ * gets shapes of a and b after transpose and reshape.
+ */
+inline mxnet::TShape GetReorderedShape(const mxnet::TShape& shape, const 
mxnet::Tuple& axes) {
+  mxnet::TShape new_shape(shape);
+  for (int i = 0; i < axes.ndim(); i++) {
+new_shape[i] = shape[axes[i]];
+  }
+  return new_shape;
+}
+
+/**
+ * gets matrix dot. Reshapes tensor a as ad1-by-ad2 matrix, tensor b as 
bd1-by-bd2 matrix, then 
+ * calculates matrix dot a * b and stores in tensor out.
+ */
+template
+void MatrixDot(
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const OpReqType req,
+const int ad1,
+const int ad2,
+const int bd1,
+const int bd2,
+const bool aT = false,
+const bool bT = false) {
+  using namespace mshadow;
+  using namespace mshadow_op;
+
+  Stream *s = ctx.get_stream();
+
+  MSHADOW_REAL_TYPE_SWITCH(out.type_flag_, DType, {
+Tensor a_tensor = a.get_with_shape(Shape2(ad1, ad2), s);
+Tensor b_tensor 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-11 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302803909
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,575 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
+const mxnet::Tuple& a_axes_remained,
+const mxnet::Tuple& a_axes_summed,
+const mxnet::Tuple& b_axes_remained,
+const mxnet::Tuple& b_axes_summed,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  *ad1 = 1;
+  *ad2 = 1;
+  *bd1 = 1;
+  *bd2 = 1;
+
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+*ad1 *= a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+*ad2 *= a_shape[a_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+*bd1 *= b_shape[b_axes_summed[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+*bd2 *= b_shape[b_axes_remained[i]];
+  }
+}
+
+/**
+ * gets new axes of a and b after transpose and reshape.
+ */
+inline void GetReorderedAxes(
+const mxnet::Tuple& a_axes_summed,
+mxnet::Tuple* a_axes_remained,
+mxnet::Tuple* a_axes,
+const mxnet::Tuple& b_axes_summed,
+mxnet::Tuple* b_axes_remained,
+mxnet::Tuple* b_axes,
+const mxnet::TShape& a_shape,
+const mxnet::TShape& b_shape) {
+  std::vector a_axes_remained_vector;
+  for (int i = 0; i < a_shape.ndim(); i++) {
+a_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : a_axes_summed) {
+a_axes_remained_vector.erase(std::find(a_axes_remained_vector.begin(),
+  a_axes_remained_vector.end(), i));
+  }
+  *a_axes_remained = mxnet::Tuple(a_axes_remained_vector);
+
+  std::vector a_axes_vector(a_axes_remained_vector);
+  for (auto& i : a_axes_summed) {
+a_axes_vector.push_back(i);
+  }
+  *a_axes = mxnet::Tuple(a_axes_vector);
+
+  std::vector b_axes_remained_vector;
+  for (int i = 0; i < b_shape.ndim(); i++) {
+b_axes_remained_vector.push_back(i);
+  }
+  for (auto& i : b_axes_summed) {
+b_axes_remained_vector.erase(std::find(b_axes_remained_vector.begin(),
+  b_axes_remained_vector.end(), i));
+  }
+  *b_axes_remained = mxnet::Tuple(b_axes_remained_vector);
+
+  std::vector b_axes_vector;
+  for (auto& i : b_axes_summed) {
+b_axes_vector.push_back(i);
+  }
+  for (auto& i : b_axes_remained_vector) {
+b_axes_vector.push_back(i);
+  }
+  *b_axes = mxnet::Tuple(b_axes_vector);
+}
+
+/**
+ * gets shapes of a and b after transpose and reshape.
+ */
+inline mxnet::TShape GetReorderedShape(const mxnet::TShape& shape, const 
mxnet::Tuple& axes) {
+  mxnet::TShape new_shape(shape);
+  for (int i = 0; i < axes.ndim(); i++) {
+new_shape[i] = shape[axes[i]];
+  }
+  return new_shape;
+}
+
+/**
+ * gets matrix dot. Reshapes tensor a as ad1-by-ad2 matrix, tensor b as 
bd1-by-bd2 matrix, then 
+ * calculates matrix dot a * b and stores in tensor out.
+ */
+template
+void MatrixDot(
 
 Review comment:
   ```c++
   void MatrixDot(const OpContext& ctx,
  const TBlob& a,
  const TBlob& b,
  const TBlob& out,
  const OpReqType req,
  const int ad1,
  const int ad2,
  const int bd1,
  const int bd2,
  const bool aT = false,
  const bool bT = false) {
   ```


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302268332
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op.cc
 ##
 @@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op.cc
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+bool TensordotOpShape(const nnvm::NodeAttrs& attrs,
+ mxnet::ShapeVector *in_attrs,
 
 Review comment:
   Align the arguments.


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302267636
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op-inl.h
 ##
 @@ -0,0 +1,399 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op-inl.h
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_OP_INL_H_
+
+#include 
+#include "np_matrix_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotParam : public dmlc::Parameter {
+  mxnet::Tuple a_axes_summed, b_axes_summed;
+  DMLC_DECLARE_PARAMETER(TensordotParam) {
+DMLC_DECLARE_FIELD(a_axes_summed);
+DMLC_DECLARE_FIELD(b_axes_summed);
+  }
+};
+
+/**
+ * Gets matrix dimensions of a and b after transpose and reshape.
+ */
+inline void GetMatrixDimensions(
+int* ad1,
+int* ad2,
+int* bd1,
+int* bd2,
 
 Review comment:
   Why do you need to pass pointers to those values? Could they not be 
references?


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302266877
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op.cc
 ##
 @@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the 
+ * icense at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op.cc
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+
+#include 
+
+#include "np_tensordot_int_axes_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+bool TensordotIntAxesOpShape(
+const nnvm::NodeAttrs& attrs,
+mxnet::ShapeVector *in_attrs,
+mxnet::ShapeVector *out_attrs) {
+  CHECK_EQ(in_attrs->size(), 2U);
+  CHECK_EQ(out_attrs->size(), 1U);
+
+  const mxnet::TShape& a_shape = in_attrs->at(0);
+  const mxnet::TShape& b_shape = in_attrs->at(1);
+
+  if (!ndim_is_known(a_shape) || !ndim_is_known(b_shape)) {
+return false;
+  }
+
+  if ((a_shape.ndim() < 1) || (b_shape.ndim() < 1)) {
+return false;
+  }
+
+  const TensordotIntAxesParam& param = 
nnvm::get(attrs.parsed);
+  const int& axes = param.axes;
+
+  Tuple a_axes_summed;
+  Tuple b_axes_summed;
+  GetSummedAxes(_axes_summed, _axes_summed, axes, a_shape);
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+_axes, a_shape, b_shape);
+
+  CHECK_EQ(a_axes_summed.ndim(), b_axes_summed.ndim());
+
+  mxnet::TShape out_shape(a_axes_remained.ndim() + b_axes_remained.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+out_shape[i] = a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+out_shape[a_axes_remained.ndim() + i] = b_shape[b_axes_remained[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*out_attrs, 0, out_shape);
+
+  mxnet::TShape tem_shape1(a_axes.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+tem_shape1[a_axes_remained[i]] = out_shape[i];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+tem_shape1[a_axes_summed[i]] = b_shape[b_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 0, tem_shape1);
+
+  mxnet::TShape tem_shape2(b_axes.ndim(), -1);
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+tem_shape2[b_axes_remained[i]] = out_shape[a_axes_remained.ndim() + i];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+tem_shape2[b_axes_summed[i]] = a_shape[a_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 1, tem_shape2);
+
+  return shape_is_known(*in_attrs) && shape_is_known(*out_attrs);
+}
+
+DMLC_REGISTER_PARAMETER(TensordotIntAxesParam);
+
+NNVM_REGISTER_OP(tensordot_int_axes)
+.add_alias("_npi_tensordot_int_axes")
+.describe(R"code(tensordot(a, b, axes=2)
+
+Compute tensor dot product along specified axes for arrays >= 1-D.
+
+Given two tensors (arrays of dimension greater than or equal to one),
+`a` and `b`, and an array_like object containing two array_like
+objects, ``(a_axes, b_axes)``, sum the products of `a`'s and `b`'s
+elements (components) over the axes specified by ``a_axes`` and
+``b_axes``. The third argument can be a single non-negative
+integer_like scalar, ``N``; if it is such, then the last ``N``
+dimensions of `a` and the first ``N`` dimensions of `b` are summed
+over.
+
+Parameters
+--
+a, b : ndarray, len(shape) >= 1
+Tensors to "dot".
+
+axes : int or (2,) ndarray
+* integer_like
+If an int N, sum over the last N axes of `a` and the first N axes
+of `b` in order. The sizes of the corresponding axes must match.
+* (2,) ndarray
+Or, a list of axes to be summed over, first sequence applying to `a`,
+second to `b`. Both elements ndarray must be of the same length.
+
+See Also
+
+dot, einsum
+
+Notes
+-
+Three common use cases are:
+* ``axes = 0`` : tensor product :math:`a\otimes b`
+* ``axes = 1`` : tensor dot product :math:`a\cdot b`
+* ``axes = 2`` : (default) tensor double contraction :math:`a:b`
+
+When `axes` is integer_like, the sequence for evaluation will 

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302266577
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op-inl.h
+ * \brief Implementation of numpy-compatible tensordot_int_axes
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotIntAxesParam : public dmlc::Parameter {
+  int axes;
+  DMLC_DECLARE_PARAMETER(TensordotIntAxesParam) {
+DMLC_DECLARE_FIELD(axes);
+  }
+};
+
+/**
+ * gets summed axes of a and b from parameter axes.
+ */
+inline void GetSummedAxes(
+mxnet::Tuple* a_axes_summed_ptr,
+mxnet::Tuple* b_axes_summed_ptr,
+const int axes,
+const mxnet::TShape& a_shape) {
+  std::vector a_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+a_axes_summed_vector.push_back(a_shape.ndim() - axes + i);
+  }
+  *a_axes_summed_ptr = mxnet::Tuple(a_axes_summed_vector);
+
+  std::vector b_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+b_axes_summed_vector.push_back(i);
+  }
+  *b_axes_summed_ptr = mxnet::Tuple(b_axes_summed_vector);
+}
+
+/**
+ * Calculates tensordot.
+ */
+template
+void TensordotIntAxesImpl(
 
 Review comment:
   Similar comments for `TensordotIntAxesBackwardImpl` below.


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302265978
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op-inl.h
+ * \brief Implementation of numpy-compatible tensordot_int_axes
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotIntAxesParam : public dmlc::Parameter {
+  int axes;
+  DMLC_DECLARE_PARAMETER(TensordotIntAxesParam) {
+DMLC_DECLARE_FIELD(axes);
+  }
+};
+
+/**
+ * gets summed axes of a and b from parameter axes.
+ */
+inline void GetSummedAxes(
+mxnet::Tuple* a_axes_summed_ptr,
+mxnet::Tuple* b_axes_summed_ptr,
+const int axes,
+const mxnet::TShape& a_shape) {
+  std::vector a_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+a_axes_summed_vector.push_back(a_shape.ndim() - axes + i);
+  }
+  *a_axes_summed_ptr = mxnet::Tuple(a_axes_summed_vector);
+
+  std::vector b_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+b_axes_summed_vector.push_back(i);
+  }
+  *b_axes_summed_ptr = mxnet::Tuple(b_axes_summed_vector);
+}
+
+/**
+ * Calculates tensordot.
+ */
+template
+void TensordotIntAxesImpl(
+const int axes,
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const std::vector& req) {
+
+  if (req[0] == kNullOp) {
+return;
+  }
+
+  if (out.shape_.Size() == 0U) {
+return;  // zero-size output, no need to launch kernel
+  }
+
+  const mxnet::TShape& a_shape = a.shape_;
+  const mxnet::TShape& b_shape = b.shape_;
+
+  mshadow::Stream *s = ctx.get_stream();
+  CHECK_EQ(out.type_flag_, a.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK_EQ(out.type_flag_, b.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK(out.type_flag_ == kFloat32 || out.type_flag_ == kFloat64 ||
+  (out.type_flag_ == kFloat16 && ctx.run_ctx.ctx.dev_mask() == 
mshadow::gpu::kDevMask))
+  << "Tensordot only supports float32/float64 for CPU, and 
float16/float32/float64 for GPU";
+
+  Tuple a_axes_summed;
+  Tuple b_axes_summed;
+  GetSummedAxes(_axes_summed, _axes_summed, axes, a_shape);
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+_axes, a_shape, b_shape);
 
 Review comment:
   Align:
   ```c++
 GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
  _axes, a_shape, b_shape);
   ```


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302266096
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op-inl.h
+ * \brief Implementation of numpy-compatible tensordot_int_axes
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotIntAxesParam : public dmlc::Parameter {
+  int axes;
+  DMLC_DECLARE_PARAMETER(TensordotIntAxesParam) {
+DMLC_DECLARE_FIELD(axes);
+  }
+};
+
+/**
+ * gets summed axes of a and b from parameter axes.
+ */
+inline void GetSummedAxes(
+mxnet::Tuple* a_axes_summed_ptr,
+mxnet::Tuple* b_axes_summed_ptr,
+const int axes,
+const mxnet::TShape& a_shape) {
+  std::vector a_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+a_axes_summed_vector.push_back(a_shape.ndim() - axes + i);
+  }
+  *a_axes_summed_ptr = mxnet::Tuple(a_axes_summed_vector);
+
+  std::vector b_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+b_axes_summed_vector.push_back(i);
+  }
+  *b_axes_summed_ptr = mxnet::Tuple(b_axes_summed_vector);
+}
+
+/**
+ * Calculates tensordot.
+ */
+template
+void TensordotIntAxesImpl(
+const int axes,
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const std::vector& req) {
+
+  if (req[0] == kNullOp) {
+return;
+  }
+
+  if (out.shape_.Size() == 0U) {
+return;  // zero-size output, no need to launch kernel
+  }
+
+  const mxnet::TShape& a_shape = a.shape_;
+  const mxnet::TShape& b_shape = b.shape_;
+
+  mshadow::Stream *s = ctx.get_stream();
+  CHECK_EQ(out.type_flag_, a.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK_EQ(out.type_flag_, b.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK(out.type_flag_ == kFloat32 || out.type_flag_ == kFloat64 ||
+  (out.type_flag_ == kFloat16 && ctx.run_ctx.ctx.dev_mask() == 
mshadow::gpu::kDevMask))
+  << "Tensordot only supports float32/float64 for CPU, and 
float16/float32/float64 for GPU";
+
+  Tuple a_axes_summed;
+  Tuple b_axes_summed;
+  GetSummedAxes(_axes_summed, _axes_summed, axes, a_shape);
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+_axes, a_shape, b_shape);
 
 Review comment:
   Same for all other applicable places.


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302265718
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op-inl.h
+ * \brief Implementation of numpy-compatible tensordot_int_axes
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotIntAxesParam : public dmlc::Parameter {
+  int axes;
+  DMLC_DECLARE_PARAMETER(TensordotIntAxesParam) {
+DMLC_DECLARE_FIELD(axes);
+  }
+};
+
+/**
+ * gets summed axes of a and b from parameter axes.
+ */
+inline void GetSummedAxes(
+mxnet::Tuple* a_axes_summed_ptr,
+mxnet::Tuple* b_axes_summed_ptr,
+const int axes,
+const mxnet::TShape& a_shape) {
+  std::vector a_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+a_axes_summed_vector.push_back(a_shape.ndim() - axes + i);
+  }
+  *a_axes_summed_ptr = mxnet::Tuple(a_axes_summed_vector);
+
+  std::vector b_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+b_axes_summed_vector.push_back(i);
+  }
+  *b_axes_summed_ptr = mxnet::Tuple(b_axes_summed_vector);
+}
+
+/**
+ * Calculates tensordot.
+ */
+template
+void TensordotIntAxesImpl(
+const int axes,
+const OpContext& ctx,
+const TBlob& a,
+const TBlob& b,
+const TBlob& out,
+const std::vector& req) {
+
+  if (req[0] == kNullOp) {
+return;
+  }
+
+  if (out.shape_.Size() == 0U) {
+return;  // zero-size output, no need to launch kernel
+  }
+
+  const mxnet::TShape& a_shape = a.shape_;
+  const mxnet::TShape& b_shape = b.shape_;
+
+  mshadow::Stream *s = ctx.get_stream();
+  CHECK_EQ(out.type_flag_, a.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK_EQ(out.type_flag_, b.type_flag_)
+  << "Binary function only support input/output with the same type";
+  CHECK(out.type_flag_ == kFloat32 || out.type_flag_ == kFloat64 ||
 
 Review comment:
   align the lines:
   ```c++
 CHECK(out.type_flag_ == kFloat32 || out.type_flag_ == kFloat64 ||
   (out.type_flag_ == kFloat16 && ctx.run_ctx.ctx.dev_mask() == 
mshadow::gpu::kDevMask))
 << "Tensordot only supports float32/float64 for CPU, and 
float16/float32/float64 for GPU";
   ```


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302265188
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_int_axes_op-inl.h
+ * \brief Implementation of numpy-compatible tensordot_int_axes
+ */
+#ifndef MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+#define MXNET_OPERATOR_NUMPY_NP_TENSORDOT_INT_AXES_OP_INL_H_
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+using namespace mxnet;
+using namespace mshadow;
+
+struct TensordotIntAxesParam : public dmlc::Parameter {
+  int axes;
+  DMLC_DECLARE_PARAMETER(TensordotIntAxesParam) {
+DMLC_DECLARE_FIELD(axes);
+  }
+};
+
+/**
+ * gets summed axes of a and b from parameter axes.
+ */
+inline void GetSummedAxes(
+mxnet::Tuple* a_axes_summed_ptr,
+mxnet::Tuple* b_axes_summed_ptr,
+const int axes,
+const mxnet::TShape& a_shape) {
+  std::vector a_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+a_axes_summed_vector.push_back(a_shape.ndim() - axes + i);
+  }
+  *a_axes_summed_ptr = mxnet::Tuple(a_axes_summed_vector);
+
+  std::vector b_axes_summed_vector;
+  for (int i = 0; i < axes; i++) {
+b_axes_summed_vector.push_back(i);
+  }
+  *b_axes_summed_ptr = mxnet::Tuple(b_axes_summed_vector);
+}
+
+/**
+ * Calculates tensordot.
+ */
+template
+void TensordotIntAxesImpl(
 
 Review comment:
   I don't think you need line breaks for this signature:
   ```c++
   void TensordotIntAxesImpl(const int axes,
 const OpContext& ctx,
 const TBlob& a,
 const TBlob& b,
 const TBlob& out,
 const std::vector& req) {
   ```
   BTW `req` here only contains 1 element, so maybe you want to change the 
signature to:
   ```c++
   void TensordotIntAxesImpl(const int axes,
 const OpContext& ctx,
 const TBlob& a,
 const TBlob& b,
 const TBlob& out,
 const OpReqType& req) {
   ```


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302263201
 
 

 ##
 File path: tests/python/unittest/test_numpy_op.py
 ##
 @@ -26,7 +26,151 @@
 from mxnet.test_utils import check_numeric_gradient
 from common import assertRaises, with_seed
 import random
+import collections
 
+@with_seed()
+@npx.use_np_shape
+def test_np_tensordot():
+class TestTensordot(HybridBlock):
+def __init__(self, axes):
+super(TestTensordot, self).__init__()
+self._axes = axes
+
+def hybrid_forward(self, F, a, b):
+return F.np.tensordot(a, b, self._axes)
+
+def tensordot_backward(a, b, axes = 2):
+if (a.ndim < 1) or (b.ndim < 1):
+raise ValueError('An input is zero-dim')
+
+if isinstance(axes, collections.abc.Sequence):
+if len(axes) != 2:
+raise ValueError('Axes must consist of two arrays.')
+a_axes_summed, b_axes_summed = axes
+if _np.isscalar(a_axes_summed):
+a_axes_summed = a_axes_summed,
+if _np.isscalar(b_axes_summed):
+b_axes_summed = b_axes_summed,
+else:
+a_axes_summed = [i + a.ndim - axes for i in range(axes)]
+b_axes_summed = [i for i in range(axes)]
+
+if len(a_axes_summed) != len(b_axes_summed):
+raise ValueError('Axes length mismatch') 
+
+a_axes_remained = []
+for i in range(a.ndim):
+if not (i in a_axes_summed):
+a_axes_remained.append(i)
+a_axes = a_axes_remained[:] + a_axes_summed[:]
+
+b_axes_remained = []
+for i in range(b.ndim):
+if not (i in b_axes_summed):
+b_axes_remained.append(i)
+b_axes = b_axes_summed[:] + b_axes_remained[:]
+
+ad1 = _np.prod([a.shape[i] for i in a_axes_remained]) if 
len(a_axes_remained) > 0 else 1
+ad2 = _np.prod([a.shape[i] for i in a_axes_summed]) if 
len(a_axes_summed) > 0 else 1
+bd1 = _np.prod([b.shape[i] for i in b_axes_summed]) if 
len(b_axes_summed) > 0 else 1
+bd2 = _np.prod([b.shape[i] for i in b_axes_remained]) if 
len(b_axes_remained) > 0 else 1
+
+out_grad = _np.ones((ad1, bd2))
+
+new_a = _np.transpose(a, a_axes)
+new_a_shape = new_a.shape[:]
+new_a = new_a.reshape((ad1, ad2)) 
+new_b = _np.transpose(b, b_axes) 
+new_b_shape = new_b.shape[:]
+new_b = new_b.reshape((bd1, bd2))
+
+reverse_a_axes = [0 for i in a_axes]
+for i in range(len(a_axes)):
+reverse_a_axes[a_axes[i]] = i
+
+reverse_b_axes = [0 for i in b_axes]
+for i in range(len(b_axes)):
+reverse_b_axes[b_axes[i]] = i
+
+grad_b = _np.dot(new_a.T, out_grad).reshape(new_b_shape)
+grad_b = _np.transpose(grad_b, reverse_b_axes)
+grad_a = _np.dot(out_grad, new_b.T).reshape(new_a_shape)
+grad_a = _np.transpose(grad_a, reverse_a_axes)
+
+return [grad_a, grad_b]
+
+# test non zero size input
+tensor_shapes = [ 
+((3, 5), (5, 4), 1),  # (a_shape, b_shape, axes)
+((3,), (3,), 1),   
+((3, 4, 5, 6, 7), (5, 6, 7, 1, 2), 3),
+((3, 5, 4, 6, 7), (7, 6, 5, 1, 2), [[1, 3, 4], [2, 1, 0]]),
+((2, 2), (2, 2), 2),
+((3, 5, 4), (5, ), [[1], [0]]),  
+((2,), (2, 3), 1),
+((3,), (3,), 0),
+((2,), (2, 3), 0),
+((3, 5, 4), (5, ), 0)
+]
+
+for hybridize in [True, False]:
+for a_shape, b_shape, axes in tensor_shapes:
+for dtype in [_np.float32, _np.float64]:
+test_tensordot = TestTensordot(axes)
+if hybridize:
+test_tensordot.hybridize()
+a = rand_ndarray(shape = a_shape, dtype = 
dtype).as_np_ndarray() 
+b = rand_ndarray(shape = b_shape, dtype = 
dtype).as_np_ndarray() 
+a.attach_grad()
+b.attach_grad()
+
+np_out = _np.tensordot(a.asnumpy(), b.asnumpy(), axes)
+with mx.autograd.record():
+mx_out = test_tensordot(a, b)   
+assert mx_out.shape == np_out.shape
+assert_almost_equal(mx_out.asnumpy(), np_out, rtol = 1e-3, 
atol = 1e-5)
+mx_out.backward()
+np_backward = tensordot_backward(a.asnumpy(), b.asnumpy(), 
axes)
+assert_almost_equal(a.grad.asnumpy(), np_backward[0], rtol = 
1e-3, atol=1e-5)
+assert_almost_equal(b.grad.asnumpy(), np_backward[1], rtol = 
1e-3, atol=1e-5)
+
+# Test imperative once again
+mx_out = np.tensordot(a, b, axes)
+np_out = _np.tensordot(a.asnumpy(), b.asnumpy(), axes)
+

[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302262995
 
 

 ##
 File path: src/operator/numpy/np_tensordot_op.cc
 ##
 @@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file np_tensordot_op.cc
+ * \brief CPU Implementation of numpy-compatible tensordot
+ */
+
+#include 
+#include "np_tensordot_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+bool TensordotOpShape(const nnvm::NodeAttrs& attrs,
+ mxnet::ShapeVector *in_attrs,
+ mxnet::ShapeVector *out_attrs) {
+  CHECK_EQ(in_attrs->size(), 2U);
+  CHECK_EQ(out_attrs->size(), 1U);
+
+  const mxnet::TShape& a_shape = in_attrs->at(0);
+  const mxnet::TShape& b_shape = in_attrs->at(1);
+
+  if (!ndim_is_known(a_shape) || !ndim_is_known(b_shape)) {
+return false;
+  }
+
+  if ((a_shape.ndim() < 1) || (b_shape.ndim() < 1)) {
+return false;
+  }
+
+  const TensordotParam& param = nnvm::get(attrs.parsed);
+  const Tuple& a_axes_summed = param.a_axes_summed;
+  const Tuple& b_axes_summed = param.b_axes_summed;
+
+  Tuple a_axes_remained;
+  Tuple b_axes_remained;
+  Tuple a_axes;
+  Tuple b_axes;
+  GetReorderedAxes(a_axes_summed, _axes_remained, _axes, b_axes_summed, 
_axes_remained,
+_axes, a_shape, b_shape);
+
+  CHECK_EQ(a_axes_summed.ndim(), b_axes_summed.ndim());
+
+  mxnet::TShape out_shape(a_axes_remained.ndim() + b_axes_remained.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+out_shape[i] = a_shape[a_axes_remained[i]];
+  }
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+out_shape[a_axes_remained.ndim() + i] = b_shape[b_axes_remained[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*out_attrs, 0, out_shape);
+
+  mxnet::TShape tem_shape1(a_axes.ndim(), -1);
+  for (int i = 0; i < a_axes_remained.ndim(); i++) {
+tem_shape1[a_axes_remained[i]] = out_shape[i];
+  }
+  for (int i = 0; i < a_axes_summed.ndim(); i++) {
+tem_shape1[a_axes_summed[i]] = b_shape[b_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 0, tem_shape1);
+
+  mxnet::TShape tem_shape2(b_axes.ndim(), -1);
+  for (int i = 0; i < b_axes_remained.ndim(); i++) {
+tem_shape2[b_axes_remained[i]] = out_shape[a_axes_remained.ndim() + i];
+  }
+  for (int i = 0; i < b_axes_summed.ndim(); i++) {
+tem_shape2[b_axes_summed[i]] = a_shape[a_axes_summed[i]];
+  }
+  SHAPE_ASSIGN_CHECK(*in_attrs, 1, tem_shape2);
+
+  return shape_is_known(*in_attrs) && shape_is_known(*out_attrs);
+}
+
+DMLC_REGISTER_PARAMETER(TensordotParam);
+
+NNVM_REGISTER_OP(tensordot)
 
 Review comment:
   Are you sure you want to expose this operator as `mxnet.ndarray.tensordot` 
and `mxnet.symbol.tensordot` to the users?


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302262454
 
 

 ##
 File path: src/operator/numpy/np_tensordot_int_axes_op-inl.h
 ##
 @@ -0,0 +1,213 @@
+/*
 
 Review comment:
   Why do you need a separate file for this op? If this is part of tensordot's 
implementation it should just fall in your `np_tensordot_op` files.


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302260577
 
 

 ##
 File path: python/mxnet/symbol/numpy/_symbol.py
 ##
 @@ -33,12 +33,77 @@
'clip', 'add', 'subtract', 'multiply', 'divide', 'mod', 'power', 
'split', 'swapaxes',
'expand_dims', 'tile', 'linspace', 'sin', 'cos', 'sinh', 'cosh', 
'log10', 'sqrt',
'abs', 'exp', 'arctan', 'sign', 'log', 'degrees', 'log2', 'rint', 
'radians', 'mean',
-   'reciprocal', 'square', 'arcsin', 'argsort']
+   'reciprocal', 'square', 'arcsin', 'argsort', 'tensordot']
 
 
 def _num_outputs(sym):
 return len(sym.as_nd_ndarray())
 
+@set_module('mxnet.symbol.numpy')
 
 Review comment:
   same here, one more blank line


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302260610
 
 

 ##
 File path: python/mxnet/numpy/multiarray.py
 ##
 @@ -45,10 +45,90 @@
 
 __all__ = ['ndarray', 'empty', 'array', 'zeros', 'ones', 'maximum', 'minimum', 
'stack', 'arange',
'argmax', 'add', 'subtract', 'multiply', 'divide', 'mod', 'power', 
'concatenate',
-   'clip', 'split', 'swapaxes', 'expand_dims', 'tile', 'linspace', 
'sin', 'cos',
'sin', 'cos', 'sinh', 'cosh', 'log10', 'sqrt', 'abs', 'exp', 
'arctan', 'sign', 'log',
'degrees', 'log2', 'rint', 'radians', 'mean', 'reciprocal', 
'square', 'arcsin',
-   'argsort']
+   'argsort', 'tensordot']
+
 
 Review comment:
   same here, one more blank line


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services


[GitHub] [incubator-mxnet] haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator

2019-07-10 Thread GitBox
haojin2 commented on a change in pull request #15349: Numpy Tensordot Operator 
URL: https://github.com/apache/incubator-mxnet/pull/15349#discussion_r302218985
 
 

 ##
 File path: python/mxnet/ndarray/numpy/_op.py
 ##
 @@ -33,7 +33,88 @@
'clip', 'split', 'swapaxes', 'expand_dims', 'tile', 'linspace',
'sin', 'cos', 'sinh', 'cosh', 'log10', 'sqrt', 'abs', 'exp', 
'arctan', 'sign', 'log',
'degrees', 'log2', 'rint', 'radians', 'mean', 'reciprocal', 
'square', 'arcsin',
-   'argsort']
+   'argsort', 'tensordot']
+
 
 Review comment:
   one more blank line?


This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services