From ff7b4284f41f31b8ee11db67c06c14e3fb51ae12 Mon Sep 17 00:00:00 2001 From: hedaoyuan Date: Mon, 28 Nov 2016 14:56:25 +0800 Subject: [PATCH] Add a auto compare for BaseMatrix --- paddle/math/tests/CMakeLists.txt | 1 + paddle/math/tests/TensorCheck.h | 113 +++++++++++++++++++ paddle/math/tests/TestUtils.h | 149 ++++++++++++++++++++++++++ paddle/math/tests/test_BaseMatrix.cpp | 56 ++++++++++ 4 files changed, 319 insertions(+) create mode 100644 paddle/math/tests/TensorCheck.h create mode 100644 paddle/math/tests/TestUtils.h create mode 100644 paddle/math/tests/test_BaseMatrix.cpp diff --git a/paddle/math/tests/CMakeLists.txt b/paddle/math/tests/CMakeLists.txt index 247be983ba3..5ac7888748e 100644 --- a/paddle/math/tests/CMakeLists.txt +++ b/paddle/math/tests/CMakeLists.txt @@ -14,3 +14,4 @@ add_simple_unittest(test_perturbation) add_simple_unittest(test_CpuGpuVector) add_simple_unittest(test_Allocator) add_simple_unittest(test_FPException) +add_simple_unittest(test_BaseMatrix) diff --git a/paddle/math/tests/TensorCheck.h b/paddle/math/tests/TensorCheck.h new file mode 100644 index 00000000000..6ca303cc7c5 --- /dev/null +++ b/paddle/math/tests/TensorCheck.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed 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. */ + +#include +#include +#include "paddle/math/Matrix.h" + +using namespace paddle; // NOLINT +using namespace std; // NOLINT + +namespace autotest { + +class CheckEqual { +public: + inline int operator()(real a, real b) { + if (a != b) { + return 1; + } + + return 0; + } +}; + +class CheckWithErr { +public: + CheckWithErr() { +#ifndef PADDLE_TYPE_DOUBLE + err_ = 1e-5; +#else + err_ = 1e-10; +#endif + } + + inline int operator()(real a, real b) { + if (std::fabs(a - b) > err_) { + if ((std::fabs(a - b) / std::fabs(a)) > (err_ / 10.0f)) { + return 1; + } + } + return 0; + } + +private: + real err_; +}; + +template +void TensorCheck(Check op, const CpuMatrix& matrix1, const CpuMatrix& matrix2) { + CHECK(matrix1.getHeight() == matrix2.getHeight()); + CHECK(matrix1.getWidth() == matrix2.getWidth()); + + int height = matrix1.getHeight(); + int width = matrix1.getWidth(); + const real* data1 = matrix1.getData(); + const real* data2 = matrix2.getData(); + int count = 0; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + real a = data1[i * width + j]; + real b = data2[i * width + j]; + count += op(a, b); + } + } + EXPECT_EQ(count, 0) << "There are " << count << " different element."; +} + +template +class CopyToCpu; + +template <> +class CopyToCpu { +public: + explicit CopyToCpu(const CpuMatrix& arg) : arg_(arg) {} + const CpuMatrix& copiedArg() const { return arg_; } + +private: + const CpuMatrix& arg_; +}; + +template <> +class CopyToCpu { +public: + explicit CopyToCpu(const GpuMatrix& arg) + : arg_(arg.getHeight(), arg.getWidth()) { + arg_.copyFrom(arg); + } + CpuMatrix& copiedArg() { return arg_; } + +private: + CpuMatrix arg_; +}; + +template +extern void TensorCheckErr(const Tensor1& tensor1, const Tensor2& tensor2) { + TensorCheck( + CheckWithErr(), + CopyToCpu(tensor1).copiedArg(), + CopyToCpu(tensor2).copiedArg()); +} + +} // namespace autotest + diff --git a/paddle/math/tests/TestUtils.h b/paddle/math/tests/TestUtils.h new file mode 100644 index 00000000000..5c9049cacc2 --- /dev/null +++ b/paddle/math/tests/TestUtils.h @@ -0,0 +1,149 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed 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. */ + + +/** + * TestUtils.h is used to automatically compare CPU and GPU code is consistent. + * + * Auto compare BaseMatrix member function: + * Use case: + * a. void BaseMatrix::tanh(BaseMatrixT& b); + * Compare method: BaseMatrixCompare<0>(&BaseMatrix::tanh); + * + * b. + * +*/ + +#include +#include "paddle/math/Matrix.h" +#include "TensorCheck.h" + +using namespace paddle; // NOLINT + +namespace autotest { + +template +class ReplaceType { +public: + typedef T1 type; +}; + +template<> +class ReplaceType { +public: + typedef CpuMatrix type; +}; + +template<> +class ReplaceType { +public: + typedef GpuMatrix type; +}; + +// construct a argument +template T construct(int height, int width); +template<> float construct(int height, int width) { return 0.0; } +template<> CpuMatrix construct(int height, int width) { + CpuMatrix a(height, width); + return a; +} +template<> GpuMatrix construct(int height, int width) { + GpuMatrix a(height, width); + return a; +} + +// init a argument +template void init(T& v); +template<> void init(float& v) { v = 0.5; } +template<> void init(CpuMatrix& v) { v.randomizeUniform(); } +template<> void init(GpuMatrix& v) { v.randomizeUniform(); } + +// init a tuple which contains a set of arguments. +template +inline typename std::enable_if::type +initTuple(std::tuple& t){} + +template +inline typename std::enable_if::type +initTuple(std::tuple& t) { + init(std::get(t)); + initTuple(t); +} + +// copy a argument, copy src to dest +template void copy(T1& dest, T2& src); +template<> void copy(float& dest, float& src) { dest = src; } +template<> void copy(GpuMatrix& dest, CpuMatrix& src) { + dest.copyFrom(src); +} + +// copy a tuple, copy src to dest +template +inline typename std::enable_if::type +copyTuple(std::tuple& dest, std::tuple& src) {} + +template +inline typename std::enable_if::type +copyTuple(std::tuple& dest, std::tuple& src) { + copy(std::get(dest), std::get(src)); + copyTuple(dest, src); +} + +// call member function +template +R call(C& obj, R (FC::*f)(FArgs...), Args&&... args) { + return (obj.*f)(args...); +} + +template +void BaseMatrixCompare(R (C::*f)(Args...)) { + for (auto height : {1, 11, 73, 128, 200, 330}) { + for (auto width : {1, 3, 32, 100, 512, 1000, 3210}) { + CpuMatrix obj1(height, width); + GpuMatrix obj2(height, width); + init(obj1); + copy(obj2, obj1); + + auto tuple1 = std::make_tuple( + construct>::type>::type, + CpuMatrix>::type>(height, width)...); + + auto tuple2 = std::make_tuple( + construct>::type>::type, + GpuMatrix>::type>(height, width)...); + + initTuple(tuple1); + copyTuple(tuple2, tuple1); + + call(obj1, f, std::get(tuple1)...); + call(obj2, f, std::get(tuple2)...); + + TensorCheckErr(obj1, obj2); + } + } +} + +} // namespace autotest + +template +void BaseMatrixCompare(R (C::*f)(Args...)) { + static_assert(sizeof...(I) == sizeof...(Args), + "size of parameter packs are not equal"); + + autotest::BaseMatrixCompare(f); +} + diff --git a/paddle/math/tests/test_BaseMatrix.cpp b/paddle/math/tests/test_BaseMatrix.cpp new file mode 100644 index 00000000000..c06580ca82e --- /dev/null +++ b/paddle/math/tests/test_BaseMatrix.cpp @@ -0,0 +1,56 @@ +/* Copyright (c) 2016 Baidu, Inc. All Rights Reserve. + +Licensed 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. */ + +#ifndef PADDLE_ONLY_CPU +/** + * This test file compares the implementation of CPU and GPU function + * in BaseMatrix.cpp. + */ + +#include +#include "paddle/utils/Util.h" +#include "paddle/math/BaseMatrix.h" +#include "TestUtils.h" + +using namespace paddle; // NOLINT +using namespace std; // NOLINT + +TEST(BaseMatrix, apply) { + // member function with no argument + BaseMatrixCompare(&BaseMatrix::neg); + + // If the member function are overloaded, use static_cast to specify which + // member function need be test. + BaseMatrixCompare( + static_cast(&BaseMatrix::exp)); + BaseMatrixCompare( + static_cast(&BaseMatrix::sqrt)); + + // member function with one argument + + BaseMatrixCompare<0>(&BaseMatrix::tanh); + + BaseMatrixCompare<0>( + static_cast(&BaseMatrix::assign)); + BaseMatrixCompare<0>( + static_cast(&BaseMatrix::pow)); +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + initMain(argc, argv); + return RUN_ALL_TESTS(); +} + +#endif -- GitLab