You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@singa.apache.org by wa...@apache.org on 2018/07/01 13:10:31 UTC
[2/7] incubator-singa git commit: SINGA-362 Add funcitons to support
einsum function 1. fix the bug and support some test case 2. need to do some
fix and use transpose function developed by yisen
SINGA-362 Add funcitons to support einsum function
1. fix the bug and support some test case
2. need to do some fix and use transpose function developed by yisen
Project: http://git-wip-us.apache.org/repos/asf/incubator-singa/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-singa/commit/7d25ed93
Tree: http://git-wip-us.apache.org/repos/asf/incubator-singa/tree/7d25ed93
Diff: http://git-wip-us.apache.org/repos/asf/incubator-singa/diff/7d25ed93
Branch: refs/heads/master
Commit: 7d25ed93b4a05ef24ec73b8277945bd24db716d2
Parents: 16c6111
Author: sheyujian <sh...@me.com>
Authored: Tue May 22 10:04:20 2018 +0800
Committer: sheyujian <sh...@me.com>
Committed: Thu May 24 10:43:35 2018 +0800
----------------------------------------------------------------------
include/singa/core/device.h | 2 +-
include/singa/core/tensor.h | 6 +--
python/singa/tensor.py | 107 ++++++++++++++++++++++++++++++++-------
src/api/core_tensor.i | 7 +++
src/core/device/device.cc | 2 +-
src/core/tensor/tensor.cc | 55 ++++++++++++++------
test/python/test_tensor.py | 61 ++++++++++++++++++++--
test/singa/test_tensor.cc | 31 ++++++++++++
8 files changed, 228 insertions(+), 43 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/include/singa/core/device.h
----------------------------------------------------------------------
diff --git a/include/singa/core/device.h b/include/singa/core/device.h
index 24569f4..d6b8bf3 100644
--- a/include/singa/core/device.h
+++ b/include/singa/core/device.h
@@ -78,7 +78,7 @@ class Device {
virtual void RepeatDataToFrom(Block* dst, Block* src, size_t nBytes,
CopyDirection direct, bool broadcast_flag,
int axis_shape, int shape_outer, int chunk,
- vector<int> repeats, int dst_offset, int src_offset);
+ vector<size_t> repeats, int dst_offset, int src_offset);
void CopyDataFromHostPtr(Block* dst, const void* src, size_t nBytes,
size_t dst_offset = 0);
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/include/singa/core/tensor.h
----------------------------------------------------------------------
diff --git a/include/singa/core/tensor.h b/include/singa/core/tensor.h
index c7958ff..3cfafc5 100644
--- a/include/singa/core/tensor.h
+++ b/include/singa/core/tensor.h
@@ -165,7 +165,7 @@ class Tensor {
/// Meta data would not be copied!
void CopyData(const Tensor &other);
- void RepeatData(vector<int> repeats, int axis, int total_repeats, const Tensor &other);
+ void RepeatData(vector<size_t> repeats, int axis, int total_repeats, const Tensor &other);
/// Deserialize data, shape and transpose from protobuf object.
void FromProto(const singa::TensorProto &proto);
@@ -177,7 +177,7 @@ class Tensor {
/// device. If 'device' is nullptr, then clone it one the current device.
Tensor Clone(std::shared_ptr<Device> device = nullptr) const;
- Tensor Repeat(vector<int> repeats, int axis, std::shared_ptr<Device> device = nullptr) ;
+ Tensor Repeat(vector<size_t> repeats, int axis, std::shared_ptr<Device> device = nullptr) ;
// Tensor operations
@@ -291,7 +291,7 @@ Tensor Reshape(const Tensor &in, Shape &&s);
void CopyDataToFrom(Tensor *dst, const Tensor &src, const size_t num,
const size_t dst_offset = 0, const size_t src_offset = 0);
-void RepeatDataToFrom(bool broadcast_flag, vector<int> repeats, int axis,
+void RepeatDataToFrom(bool broadcast_flag, vector<size_t> repeats, int axis,
Tensor *dst, const Tensor &in, const size_t num,
const size_t dst_offset = 0, const size_t src_offset = 0);
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/python/singa/tensor.py
----------------------------------------------------------------------
diff --git a/python/singa/tensor.py b/python/singa/tensor.py
index ff7206c..d559ecb 100644
--- a/python/singa/tensor.py
+++ b/python/singa/tensor.py
@@ -136,6 +136,10 @@ class Tensor(object):
'''
return self.data.transpose()
+ # def transpose(self):
+
+ # return self.data
+
def size(self): # TODO(wangwei) compute size
'''
Returns:
@@ -255,6 +259,28 @@ class Tensor(object):
'''
return _call_singa_func(self.data.Clone)
+ def repeat_(self, repeats, axis):
+ ret = CTensor()
+ if isinstance(repeats, int):
+ if axis == 9999:
+ Repeats = [repeats,]
+ ret = self.data.Repeat(Repeats, axis)
+ else:
+ Repeats = [repeats,]
+ ret = self.data.Repeat(Repeats, axis)
+ return ret
+
+ elif isinstance(repeats, tuple) or isinstance(repeats, list):
+ if axis == 9999:
+ ret = self.data.Repeat(list(repeats), axis)
+
+ elif axis >= 0:
+ ret = self.data.Repeat(list(repeats), axis)
+ return ret
+
+
+
+
def T(self):
''' shallow copy, negate the transpose field.
@@ -1104,23 +1130,25 @@ def sum2(t, axis=None, out=None):
t_ndim = t.ndim()
if axis is None:
- one = Tensor(t.shape, t.device, t.dtype)
+ one = Tensor(t.shape, t.device)
one.set_value(1.0)
ret = tensordot(t, one, t_ndim)
if isinstance(axis,int):
if axis < 0:
- axis += 2
+ axis += t_ndim
axis_shape = t_shape[axis]
- one = Tensor(axis_shape, t.device, t.dtype)
+ axis_shape = int(axis_shape)
+ one = Tensor(shape = (axis_shape, ), device = t.device)
one.set_value(1.0)
ret = tensordot(t, one, axes=([axis],[0]))
if isinstance(axis,tuple):
l_axis = list(axis)
axis_shape = [t_shape[x] for x in axis]
- one = Tensor(axis_shape, t.device, t.dtype)
+ axisshape = tuple(axis_shape)
+ one = Tensor(axisshape, t.device)
one.set_value(1.0)
one_axis = [x for x in range(one.ndim())]
ret = tensordot(t, one, (l_axis,one_axis))
@@ -1133,31 +1161,59 @@ def sum2(t, axis=None, out=None):
else:
return ret
-def repeat(t, repeats, axis = None):
+def repeat (t, repeats, axis = None):
+ t_ndim = t.ndim()
if isinstance(repeats, int):
if repeats < 0:
raise ValueError("'repeats' should not be negative: {}".format(repeats))
+ if axis != None and axis < 0:
+ axis += t_ndim
# broadcast = True
if axis == None:
axis = 9999
- if axis < 0:
- axis += 2
- ret = singa.Repeat(t, list(repeats), axis)
+ ret = Tensor()
+ ret.shape = (product(t.shape)*repeats,)
+ # Repeats = [repeats,]
+ ret.data = t.repeat_(repeats, axis)
+ # ret.data = t.data.Repeat(Repeats, axis)
+ elif axis >= 0:
+ ret = Tensor()
+ t_shape = list(t.shape)
+ t_shape[axis] = t.shape[axis]*repeats
+ print(t_shape)
+ ret.shape = tuple(t_shape)
+ print(ret.shape)
+ # Repeats = [repeats,]
+ ret.data = t.repeat_(repeats, axis)
+ # ret.data = t.data.Repeat(Repeats, axis)
+ print(ret.shape)
+
elif isinstance(repeats, tuple) or isinstance(repeats, list):
for rep in repeats:
if rep < 0:
raise ValueError("'repeats' should be int or sequence: {}".format(repeats))
+
+ if axis != None and axis < 0:
+ axis += t_ndim
if axis == None:
axis = 9999
- if axis < 0:
- axis += 2
- ret = singa.Repeat(t, list(repeats), axis)
- t_shape = t.shape
- t_shape[axis] = sum(repeats)
- ret = ret.reshape(t_shape)
+ ret = Tensor()
+ ret.shape = (sum(repeats), )
+ t_shape = list(t.shape)
+ ret.data = t.repeat_(repeats, axis)
+ #ret = t.data.Repeat(list(repeats), axis)
+
+ elif axis >= 0:
+ ret = Tensor()
+ t_shape = list(t.shape)
+ t_shape[axis] = sum(repeats)
+ ret.shape = tuple(t_shape)
+ ret.data = t.repeat_(repeats, axis)
+ #ret = t.data.Repeat(list(repeats), axis)
else:
raise ValueError('repeats should be int or sequence')
return ret
+
def tensordot (A,B,axes=2):
@@ -1188,7 +1244,7 @@ def tensordot (A,B,axes=2):
# if A is in shape(3,2,4), B is in shape(4,2,5), it will return a matrix in shape(3,2,2,5)
#when axes is 2 and A,B are shape (3,2,4) and (2,4,5), it will return a matrix in shape(3,5)
- if type(axes) == int:
+ if type(axes) == int or type(axes) == long:
axes_A = list(range(-axes, 0))
axes_B = list(range(0, axes))
axes_B = axes_B
@@ -1257,11 +1313,24 @@ def tensordot (A,B,axes=2):
newshape_b = (N2, N1)
oldb = [b_shape[axis] for axis in notin]
# do transpose and reshape to get the 2D matrix to do multiplication
- at = A.transpose(newaxes_a).reshape(newshape_a)
- bt = B.transpose(newaxes_b).reshape(newshape_b)
- res = mult(at, bt)
+ A_ = to_numpy(A)
+ B_ = to_numpy(B)
+ at_ = np.transpose(A_,newaxes_a).reshape(newshape_a)
+ bt_ = np.transpose(B_,newaxes_b).reshape(newshape_b)
+ at = from_numpy(at_)
+ bt = from_numpy(bt_)
+ res = mult(at,bt)
+ if len(olda + oldb) == 0:
+ olda = [1]
+ oldb = [1]
+ res.reshape(tuple(olda + oldb))
+ else:
+ res.reshape(tuple(olda + oldb))
+ print(res.shape)
+ # res_ = np.dot(at_, bt_)
+ # res = from_numpy(res_.reshape(olda + oldb))
#reshape the result
- return res.reshape(olda + oldb)
+ return res
def div(lhs, rhs, ret=None):
'''Elementi-wise division.
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/src/api/core_tensor.i
----------------------------------------------------------------------
diff --git a/src/api/core_tensor.i b/src/api/core_tensor.i
index 31562c9..756fe60 100644
--- a/src/api/core_tensor.i
+++ b/src/api/core_tensor.i
@@ -119,9 +119,12 @@ namespace singa{
%template(CopyIntDataFromHostPtr) CopyDataFromHostPtr<int>;
void CopyData(const Tensor &other);
+ void RepeatData(std::vector<size_t> repeats, int axis, int total_repeats, const Tensor &src);
Tensor Clone() const;
+ Tensor Repeat(std::vector<size_t> repeats, int axis);
Tensor T() const;
+
#if USE_JAVA
%rename(iAdd) operator+=(const Tensor &t);
%rename(iSub) operator-=(const Tensor &t);
@@ -157,6 +160,10 @@ namespace singa{
void CopyDataToFrom(Tensor *dst, const Tensor &src, size_t num,
size_t src_offset = 0, size_t dst_offset = 0);
+ void RepeatDataToFrom(bool broadcast_flag, std::vector<size_t> repeats, int axis,
+ Tensor *dst, const Tensor &src, const size_t num,
+ const size_t dst_offset, const size_t src_offset);
+
Tensor Reshape(const Tensor &in, const std::vector<size_t> &s);
Tensor Abs(const Tensor &t);
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/src/core/device/device.cc
----------------------------------------------------------------------
diff --git a/src/core/device/device.cc b/src/core/device/device.cc
index d569015..135ae3a 100644
--- a/src/core/device/device.cc
+++ b/src/core/device/device.cc
@@ -67,7 +67,7 @@ void Device::CopyDataToFrom(Block* dst, Block* src, size_t nBytes,
void Device::RepeatDataToFrom(Block* dst, Block* src, size_t nBytes,
CopyDirection direct, bool broadcast_flag,
int axis_shape, int shape_outer, int chunk,
- vector<int> repeats, int dst_offset, int src_offset) {
+ vector<size_t> repeats, int dst_offset, int src_offset) {
const char *src_data = reinterpret_cast<const char*>(src->data()) + dst_offset;
char *dst_data = reinterpret_cast<char*>(dst->mutable_data()) + src_offset;
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/src/core/tensor/tensor.cc
----------------------------------------------------------------------
diff --git a/src/core/tensor/tensor.cc b/src/core/tensor/tensor.cc
index 22541df..b75ac40 100644
--- a/src/core/tensor/tensor.cc
+++ b/src/core/tensor/tensor.cc
@@ -216,8 +216,8 @@ void Tensor::CopyData(const Tensor &src) {
}
}
-void Tensor::RepeatData(vector<int> repeats, int axis, int total_repeats, const Tensor &src) {
- if(axis == Noaxis) {
+void Tensor::RepeatData(vector<size_t> repeats, int axis, int total_repeats, const Tensor &src) {
+ if(repeats.size() == 1) {
CHECK_EQ(Size(), src.Size()*total_repeats);
} else {
CHECK_EQ(Size(), src.Size()*total_repeats/src.shape()[axis]);
@@ -345,25 +345,44 @@ Tensor Tensor::Clone(std::shared_ptr<Device> device) const {
return t;
}
-Tensor Tensor::Repeat(vector<int> repeats, int axis, std::shared_ptr<Device> device) {
+Tensor Tensor::Repeat(vector<size_t> repeats, int axis, std::shared_ptr<Device> device) {
if (device == nullptr) device = device_;
- Tensor t;
+ vector<size_t> tshape;
int total_repeats = 0;
if (axis == Noaxis) {
total_repeats = repeats[0];
- t.shape_.push_back(Product(shape_)*total_repeats);
+ tshape.push_back(Product(shape_)*total_repeats);
} else {
- for (size_t i = 0; i < shape_[axis]; i++) {
- if(repeats[i] < 0) {
- LOG(FATAL) << "the repeats number is less than zero";
+ if (repeats.size() == 1){
+ total_repeats = repeats[0];
+ for (int i = 0; i < shape_.size(); i++) {
+ if (i == axis) {
+ tshape.push_back(shape_[i] * total_repeats);
+ } else {
+ tshape.push_back(shape_[i]);
+ }
+ }
+ } else {
+ if (repeats.size() != shape_[axis]) {
+ LOG(FATAL) << "the repeats number doesn't match the axis";
+ }
+ for (size_t i = 0; i < shape_[axis]; i++) {
+ if(repeats[i] < 0) {
+ LOG(FATAL) << "the repeats number is less than zero";
+ }
+ total_repeats += repeats[i];
+ }
+ for (int i = 0; i < shape_.size(); i++){
+ if (i == axis) {
+ tshape.push_back(total_repeats);
+ } else{
+ tshape.push_back(shape_[i]);
+ }
}
- total_repeats += repeats[i];
- t.shape_.push_back(Product(shape_)/shape_[axis]*total_repeats);
}
}
- t.device_ = device_;
- t.data_type_ = data_type_;
- t.strides_.push_back(1);
+ Tensor t(tshape, device_);
+ //t.strides_.push_back(1);
t.RepeatData(repeats, axis, total_repeats, *this);
return t;
}
@@ -522,7 +541,7 @@ void CopyDataToFrom(Tensor *dst, const Tensor &src, const size_t num,
}
}
-void RepeatDataToFrom(bool broadcast_flag, vector<int> repeats, int axis,
+void RepeatDataToFrom(bool broadcast_flag, vector<size_t> repeats, int axis,
Tensor *dst, const Tensor &src, const size_t num,
const size_t dst_offset, const size_t src_offset) {
if (repeats.size() == 1) {
@@ -543,15 +562,20 @@ void RepeatDataToFrom(bool broadcast_flag, vector<int> repeats, int axis,
auto s_offset = src_offset * width;
int chunk = width;
int axis_shape = 1;
+ int shape_outer = 1;
if (axis == Noaxis){
axis_shape = 1;
+ shape_outer = Product(src.shape());
} else {
+ for (size_t i = 0; i < axis; i++) {
+ shape_outer *= src.shape()[i];
+ }
axis_shape = src.shape()[axis];
for(size_t i = axis + 1; i < src.nDim(); i++) {
chunk *= src.shape()[i];
}
}
- int shape_outer = Product(src.shape());
+
std::shared_ptr<Device> src_dev = src.device(), dst_dev = dst->device();
Block *from = src.block(), *to = dst->block();
if (dst_dev->lang() != src_dev->lang()) {
@@ -667,6 +691,7 @@ void Tensor::SetValue(const SType x) {
CHECK_EQ(sizeof(SType), SizeOf(data_type_));
//auto size = Size();
auto ptr = block_;
+
TYPE_LANG_SWITCH(data_type_, DType, device_->lang(), Lang, {
// TODO(wangwei) cast x to DType
device_->Exec([this, x, ptr](Context * ctx) {
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/test/python/test_tensor.py
----------------------------------------------------------------------
diff --git a/test/python/test_tensor.py b/test/python/test_tensor.py
index 0b3b85b..a47bbff 100644
--- a/test/python/test_tensor.py
+++ b/test/python/test_tensor.py
@@ -167,9 +167,10 @@ class TestTensorMethods(unittest.TestCase):
def test_einsum(self):
- a = np.arange(12).reshape(3, 2, 2)
-
+ a = np.array([1.1,1.1,1.1,1.1,1.4,1.3,1.1,1.6,1.1,1.1,1.1,1.2])
+ a = np.reshape(a,(2,3,2))
ta = tensor.from_numpy(a)
+
res1 = np.einsum('kij,kij->kij', a, a)
tres1 = tensor.einsum('kij,kij->kij', ta, ta)
Tres1 = tensor.to_numpy(tres1)
@@ -177,9 +178,61 @@ class TestTensorMethods(unittest.TestCase):
tres2 = tensor.einsum('kij,kih->kjh', ta, ta)
Tres2 = tensor.to_numpy(tres2)
- self.assertEqual(np.sum(Tres1 - res1), 0.)
- self.assertEqual(np.sum(Tres2 - res2), 0.)
+ self.assertAlmostEqual(np.sum(Tres1 - res1), 0.,places=3)
+ self.assertAlmostEqual(np.sum(Tres2 - res2), 0.,places=3)
+
+ def test_repeat(self):
+
+ a = np.array([1.1,1.1,1.1,1.1,1.4,1.3,1.1,1.6,1.1,1.1,1.1,1.2])
+ a = np.reshape(a,(2,3,2))
+ ta = tensor.from_numpy(a)
+
+ ta_repeat1 = tensor.repeat(ta,2,axis = None)
+ a_repeat1 = np.repeat(a,2,axis = None)
+ Ta_repeat1 = tensor.to_numpy(ta_repeat1)
+ ta_repeat2 = tensor.repeat(ta, 4, axis = 1)
+ a_repeat2 = np.repeat(a, 4, axis = 1)
+ Ta_repeat2 = tensor.to_numpy(ta_repeat2)
+ print(Ta_repeat2)
+ print(a_repeat2)
+
+ self.assertAlmostEqual(np.sum(Ta_repeat1 - a_repeat1), 0., places=3)
+ self.assertAlmostEqual(np.sum(Ta_repeat2 - a_repeat2), 0., places=3)
+
+ def test_sum2(self):
+ a = np.array([1.1,1.1,1.1,1.1,1.4,1.3,1.1,1.6,1.1,1.1,1.1,1.2])
+ a = np.reshape(a,(2,3,2))
+ ta = tensor.from_numpy(a)
+
+ a_sum0 = np.sum(a)
+ ta_sum0 = tensor.sum2(ta)
+ Ta_sum0 = tensor.to_numpy(ta_sum0)
+ a_sum1 = np.sum(a, axis = 1)
+ ta_sum1 = tensor.sum2(ta, axis = 1)
+ Ta_sum1 = tensor.to_numpy(ta_sum1)
+ a_sum2 = np.sum(a, axis = 2)
+ ta_sum2 = tensor.sum2(ta, axis = 2)
+ Ta_sum2 = tensor.to_numpy(ta_sum2)
+
+ self.assertAlmostEqual(np.sum(a_sum0 - Ta_sum0), 0., places=3)
+ self.assertAlmostEqual(np.sum(a_sum1 - Ta_sum1), 0., places=3)
+ self.assertAlmostEqual(np.sum(a_sum2 - Ta_sum2), 0., places=3)
+
+ def test_tensordot(self):
+ a = np.array([1.1,1.1,1.1,1.1,1.4,1.3,1.1,1.6,1.1,1.1,1.1,1.2])
+ a = np.reshape(a,(2,3,2))
+
+ ta = tensor.from_numpy(a)
+
+ res1 = np.tensordot(a, a, axes = 1)
+ tres1 = tensor.tensordot(ta, ta, axes = 1)
+ Tres1 = tensor.to_numpy(tres1)
+ res2 = np.tensordot(a, a, axes = ([0,1],[2,1]))
+ tres2 = tensor.tensordot(ta, ta, axes = ([0,1],[2,1]))
+ Tres2 = tensor.to_numpy(tres2)
+ self.assertAlmostEqual(np.sum(Tres1 - res1), 0., places=3)
+ self.assertAlmostEqual(np.sum(Tres2 - res2), 0., places=3)
if __name__ == '__main__':
http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/7d25ed93/test/singa/test_tensor.cc
----------------------------------------------------------------------
diff --git a/test/singa/test_tensor.cc b/test/singa/test_tensor.cc
index 316b996..c8df3ee 100644
--- a/test/singa/test_tensor.cc
+++ b/test/singa/test_tensor.cc
@@ -129,3 +129,34 @@ TEST(TensorClass, T) {
EXPECT_EQ(t.shape()[1], o.shape()[0]);
}
+TEST(TensorClass, Repeat) {
+ float data[] = {1.0f, 2.0f, 3.0f};
+ Tensor t(Shape{3});
+ t.CopyDataFromHostPtr(data, 3);
+
+ Tensor o = t.Repeat(vector <size_t>{2},9999);
+ const float* dptr = static_cast<const float*>(o.block()->data());
+ EXPECT_FLOAT_EQ(1.0f, dptr[0]);
+ EXPECT_FLOAT_EQ(1.0f, dptr[1]);
+ EXPECT_FLOAT_EQ(2.0f, dptr[2]);
+ EXPECT_FLOAT_EQ(2.0f, dptr[3]);
+ EXPECT_FLOAT_EQ(3.0f, dptr[4]);
+ EXPECT_FLOAT_EQ(3.0f, dptr[5]);
+}
+
+TEST(TensorCLass, RepeatData) {
+ float data[] = {1.0f, 2.0f, 3.0f};
+ Tensor t(Shape{3});
+ t.CopyDataFromHostPtr(data, 3);
+
+ Tensor o(Shape{6});
+ o.RepeatData({2},9999,2,t);
+ const float* dptr = static_cast<const float*>(o.block()->data());
+ EXPECT_FLOAT_EQ(1.0f, dptr[0]);
+ EXPECT_FLOAT_EQ(1.0f, dptr[1]);
+ EXPECT_FLOAT_EQ(2.0f, dptr[2]);
+ EXPECT_FLOAT_EQ(2.0f, dptr[3]);
+ EXPECT_FLOAT_EQ(3.0f, dptr[4]);
+ EXPECT_FLOAT_EQ(3.0f, dptr[5]);
+}
+