From 7fabfcaa84bb4c12fc95d5ec70cf23b7920371fe Mon Sep 17 00:00:00 2001 From: Jihoon Lee Date: Fri, 11 Dec 2020 16:58:34 +0900 Subject: [PATCH] [Fix] fix lda, ldb param **Changes proposed in this PR:** - lda, ldb, ldc is for layout so it should be set in terms of memory layout, this patch fixes the issue while adding a corresponding test **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: Jihoon Lee --- nntrainer/tensor/tensor.cpp | 23 ++-- test/unittest/unittest_nntrainer_tensor.cpp | 167 ++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+), 14 deletions(-) diff --git a/nntrainer/tensor/tensor.cpp b/nntrainer/tensor/tensor.cpp index 803f22f..fde2996 100644 --- a/nntrainer/tensor/tensor.cpp +++ b/nntrainer/tensor/tensor.cpp @@ -564,7 +564,8 @@ Tensor Tensor::dot(Tensor const &m, bool trans, bool trans_m) const { /** * @note: This dot product flattens the fist 3 axis for the purpose of * computation. So, while performing, these matrices are behaving as 2-D - * matrices. The dimensions are restored while returning back the tensor. + * matrices. The dimensions are restored while returning back the tensor + * in case of trans is false. */ Tensor &Tensor::dot(Tensor const &m, Tensor &result, bool trans, bool trans_m) const { @@ -591,9 +592,7 @@ Tensor &Tensor::dot(Tensor const &m, Tensor &result, bool trans, K = mdim1; /** == dim2 */ N = mdim2; M = dim1; - lda = K; - ldb = N; - CREATE_IF_EMPTY_DIMS(result, batch(), channel(), height(), mdim2); + CREATE_IF_EMPTY_DIMS(result, batch(), channel(), height(), N); // We are not set zero the result because of performnace reason. // However, result is not initialized properly. There might include garbage @@ -607,9 +606,7 @@ Tensor &Tensor::dot(Tensor const &m, Tensor &result, bool trans, K = mdim2; /** == dim2 */ N = mdim1; M = dim1; - lda = K; - ldb = K; - CREATE_IF_EMPTY_DIMS(result, batch(), channel(), height(), mdim1); + CREATE_IF_EMPTY_DIMS(result, batch(), channel(), height(), N); } else if (trans && !trans_m) { if (dim1 != mdim1) throw std::runtime_error( @@ -617,9 +614,7 @@ Tensor &Tensor::dot(Tensor const &m, Tensor &result, bool trans, K = mdim1; /** == dim1 */ N = mdim2; M = dim2; - lda = M; - ldb = N; - CREATE_IF_EMPTY_DIMS(result, 1, 1, dim2, mdim2); + CREATE_IF_EMPTY_DIMS(result, 1, 1, M, N); } else { if (dim1 != mdim2) throw std::runtime_error( @@ -627,11 +622,11 @@ Tensor &Tensor::dot(Tensor const &m, Tensor &result, bool trans, K = mdim2; /** == dim1 */ N = mdim1; M = dim2; - lda = M; - ldb = K; - CREATE_IF_EMPTY_DIMS(result, 1, 1, dim2, mdim1); + CREATE_IF_EMPTY_DIMS(result, 1, 1, M, N); } - ldc = N; + lda = dim2; + ldb = mdim2; + ldc = result.width(); const float *data = getData(); const float *mdata = m.getData(); diff --git a/test/unittest/unittest_nntrainer_tensor.cpp b/test/unittest/unittest_nntrainer_tensor.cpp index 91b08f9..85b2641 100644 --- a/test/unittest/unittest_nntrainer_tensor.cpp +++ b/test/unittest/unittest_nntrainer_tensor.cpp @@ -1789,6 +1789,173 @@ end_dot_01_p: EXPECT_EQ(status, ML_ERROR_NONE); } +TEST(nntrainer_Tensor, dot_transpose_p) { + { + float a_data[] = {0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 4), a_data); + float b_data[] = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 4, 3), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92, + 92, 113, 134, 155, 128, 158, 188, 218}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, true, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 4), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 4), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92, + 92, 113, 134, 155, 128, 158, 188, 218}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, true, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 4, 3), a_data); + float b_data[] = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 4, 3), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92, + 92, 113, 134, 155, 128, 158, 188, 218}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, false, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 4, 3), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 4), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92, + 92, 113, 134, 155, 128, 158, 188, 218}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, false, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 1, 4, 2, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 2), a_data); + float b_data[] = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 4, 3), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, true, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 1, 4, 2, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 2), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 4), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, true, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 2, 3), a_data); + float b_data[] = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 4, 3), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, false, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 2, 3), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 4), b_data); + float answer_data[] = {20, 23, 26, 29, 56, 68, 80, 92}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 4), answer_data); + nntrainer::Tensor ret = a.dot(b, false, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 4), a_data); + float b_data[] = {0, 2, 4, 1, 3, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 2, 3), b_data); + float answer_data[] = {10, 13, 28, 40, 46, 67, 64, 94}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, true, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 4), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 2), b_data); + float answer_data[] = {10, 13, 28, 40, 46, 67, 64, 94}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, true, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 4, 3), a_data); + float b_data[] = {0, 2, 4, 1, 3, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 2, 3), b_data); + float answer_data[] = {10, 13, 28, 40, 46, 67, 64, 94}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, false, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 4, 3), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 2), b_data); + float answer_data[] = {10, 13, 28, 40, 46, 67, 64, 94}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 4, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, false, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 1, 4, 2, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 2), a_data); + float b_data[] = {0, 2, 4, 1, 3, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 2, 3), b_data); + float answer_data[] = {10, 13, 28, 40}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, true, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 3, 1, 4, 2, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 3, 2), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 2), b_data); + float answer_data[] = {10, 13, 28, 40}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, true, false); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 2, 3), a_data); + float b_data[] = {0, 2, 4, 1, 3, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 2, 3), b_data); + float answer_data[] = {10, 13, 28, 40}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, false, true); + EXPECT_EQ(ret, answer); + } + { + float a_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor a(nntrainer::TensorDim(1, 1, 2, 3), a_data); + float b_data[] = {0, 1, 2, 3, 4, 5}; + nntrainer::Tensor b(nntrainer::TensorDim(1, 1, 3, 2), b_data); + float answer_data[] = {10, 13, 28, 40}; + nntrainer::Tensor answer(nntrainer::TensorDim(1, 1, 2, 2), answer_data); + nntrainer::Tensor ret = a.dot(b, false, false); + EXPECT_EQ(ret, answer); + } +} + TEST(nntrainer_Tensor, transpose_01_p) { int status = ML_ERROR_NONE; int batch = 3; -- 2.7.4