/* 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; }; 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 <> size_t construct(int height, int width) { size_t offset = std::rand() % (height < width ? height : width); return offset; } 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(size_t& v) { return; } 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 < I::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(size_t& dest, size_t& 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 < I::type copyTuple(std::tuple& dest, std::tuple& src) { copy(std::get(dest), std::get(src)); copyTuple(dest, src); } // Compare output template inline typename std::enable_if::type checkTuple( std::tuple& args1, std::tuple& args2, AssertEq compare) {} template inline typename std::enable_if < I::type checkTuple(std::tuple& args1, std::tuple& args2, AssertEq compare) { TensorCheck(compare, std::get(args1), std::get(args2)); checkTuple(args1, args2, compare); } // 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...), AssertEq compare, bool checkArgs = false) { for (auto height : {1, 11, 73, 128, 200, 330}) { for (auto width : {1, 3, 32, 100, 512, 1000}) { CpuMatrix obj1(AsRowVector ? 1 : height, AsColVector ? 1 : width); GpuMatrix obj2(AsRowVector ? 1 : height, AsColVector ? 1 : 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)...); TensorCheck(compare, obj1, obj2); if (checkArgs) { checkTuple(tuple1, tuple2, compare); } } } } } // namespace autotest template void BaseMatrixCompare(R (C::*f)(Args...), bool checkArgs = false) { static_assert(sizeof...(I) == sizeof...(Args), "size of parameter packs are not equal"); #ifndef PADDLE_TYPE_DOUBLE autotest::AssertEqual compare(1e-5); #else autotest::AssertEqual compare(1e-10); #endif autotest::BaseMatrixCompare(f, compare, checkArgs); } template void BaseMatrixAsColVector(R (C::*f)(Args...)) { static_assert(sizeof...(I) == sizeof...(Args), "size of parameter packs are not equal"); #ifndef PADDLE_TYPE_DOUBLE autotest::AssertEqual compare(1e-3); #else autotest::AssertEqual compare(1e-8); #endif autotest::BaseMatrixCompare(f, compare); } template void BaseMatrixAsRowVector(R (C::*f)(Args...)) { static_assert(sizeof...(I) == sizeof...(Args), "size of parameter packs are not equal"); #ifndef PADDLE_TYPE_DOUBLE autotest::AssertEqual compare(1e-3); #else autotest::AssertEqual compare(1e-8); #endif autotest::BaseMatrixCompare(f, compare); }