TestUtils.h 7.6 KB
Newer Older
H
hedaoyuan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* 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. */

H
hedaoyuan 已提交
15 16
#pragma once

H
hedaoyuan 已提交
17 18
/**
 * TestUtils.h is used to automatically compare CPU and GPU code is consistent.
H
hedaoyuan 已提交
19 20 21
 * This file provides a class(AutoCompare) and a template
 * function(BaseMatrixCompare) to simplify the comparison
 * of CPU and GPU member functions.
22
 * Refer test_Matrix.cpp and test_BaseMatrix.cpp for how to use autotest.
H
hedaoyuan 已提交
23 24 25 26
*/

#include <gtest/gtest.h>
#include "paddle/math/Matrix.h"
27
#include "paddle/math/SparseMatrix.h"
H
hedaoyuan 已提交
28 29
#include "TensorCheck.h"

H
hedaoyuan 已提交
30 31
namespace autotest {

32 33 34 35 36
using paddle::BaseMatrix;
using paddle::CpuIVector;
using paddle::GpuIVector;
using paddle::CpuSparseMatrix;
using paddle::GpuSparseMatrix;
H
hedaoyuan 已提交
37

38
template <typename T1, typename T2>
H
hedaoyuan 已提交
39 40 41 42 43
class ReplaceType {
public:
  typedef T1 type;
};

44
template <>
H
hedaoyuan 已提交
45 46 47 48 49
class ReplaceType<BaseMatrix, CpuMatrix> {
public:
  typedef CpuMatrix type;
};

50
template <>
H
hedaoyuan 已提交
51 52 53 54 55
class ReplaceType<BaseMatrix, GpuMatrix> {
public:
  typedef GpuMatrix type;
};

56 57 58 59 60 61 62 63 64 65 66 67
template <>
class ReplaceType<Matrix, CpuMatrix> {
public:
  typedef CpuMatrix type;
};

template <>
class ReplaceType<Matrix, GpuMatrix> {
public:
  typedef GpuMatrix type;
};

H
hedaoyuan 已提交
68
// construct a argument
69 70
template <typename T>
T construct(int height, int width);
71

72 73
template <>
float construct(int height, int width) {
H
hedaoyuan 已提交
74
  return 0.5;
75
}
76 77 78 79 80 81 82

template <>
size_t construct(int height, int width) {
  size_t offset = std::rand() % (height < width ? height : width);
  return offset;
}

83 84
template <>
CpuMatrix construct(int height, int width) {
H
hedaoyuan 已提交
85 86 87
  CpuMatrix a(height, width);
  return a;
}
88

89 90
template <>
GpuMatrix construct(int height, int width) {
H
hedaoyuan 已提交
91 92 93 94 95
  GpuMatrix a(height, width);
  return a;
}

// init a argument
96
template <typename T>
H
hedaoyuan 已提交
97
void init(T& v) {
98 99 100
  return;
}

101 102 103 104
template <>
void init(CpuMatrix& v) {
  v.randomizeUniform();
}
105

106 107 108 109
template <>
void init(GpuMatrix& v) {
  v.randomizeUniform();
}
H
hedaoyuan 已提交
110 111

// init a tuple which contains a set of arguments.
112 113 114
template <std::size_t I = 0, typename... Args>
inline typename std::enable_if<I == sizeof...(Args), void>::type initTuple(
    std::tuple<Args...>& t) {}
H
hedaoyuan 已提交
115

116 117 118
template <std::size_t I = 0, typename... Args>
    inline typename std::enable_if <
    I<sizeof...(Args), void>::type initTuple(std::tuple<Args...>& t) {
H
hedaoyuan 已提交
119 120 121 122 123
  init(std::get<I>(t));
  initTuple<I + 1>(t);
}

// copy a argument, copy src to dest
124
template <typename T1, typename T2>
H
hedaoyuan 已提交
125
void copy(T1& dest, T2& src) {
126 127 128
  dest = src;
}

129 130
template <>
void copy(GpuMatrix& dest, CpuMatrix& src) {
H
hedaoyuan 已提交
131 132 133 134
  dest.copyFrom(src);
}

// copy a tuple, copy src to dest
135 136 137 138 139 140 141 142
template <std::size_t I = 0, typename... Args1, typename... Args2>
inline typename std::enable_if<I == sizeof...(Args1), void>::type copyTuple(
    std::tuple<Args1...>& dest, std::tuple<Args2...>& src) {}

template <std::size_t I = 0, typename... Args1, typename... Args2>
    inline typename std::enable_if <
    I<sizeof...(Args1), void>::type copyTuple(std::tuple<Args1...>& dest,
                                              std::tuple<Args2...>& src) {
H
hedaoyuan 已提交
143 144 145 146 147 148
  copy(std::get<I>(dest), std::get<I>(src));
  copyTuple<I + 1>(dest, src);
}

// call member function
template <typename C,
149 150 151 152
          typename FC,
          typename R,
          typename... FArgs,
          typename... Args>
H
hedaoyuan 已提交
153 154 155 156
R call(C& obj, R (FC::*f)(FArgs...), Args&&... args) {
  return (obj.*f)(args...);
}

157 158
template <bool AsRowVector,
          bool AsColVector,
159 160 161 162
          std::size_t... I,
          typename C,
          typename R,
          typename... Args,
163
          typename AssertEq>
164
void BaseMatrixCompare(R (C::*f)(Args...), AssertEq compare) {
H
hedaoyuan 已提交
165
  for (auto height : {1, 11, 73, 128, 200, 330}) {
166
    for (auto width : {1, 3, 32, 100, 512, 1000}) {
167 168
      CpuMatrix obj1(AsRowVector ? 1 : height, AsColVector ? 1 : width);
      GpuMatrix obj2(AsRowVector ? 1 : height, AsColVector ? 1 : width);
H
hedaoyuan 已提交
169 170 171 172
      init(obj1);
      copy(obj2, obj1);

      auto tuple1 = std::make_tuple(
173 174 175 176 177
          construct<typename ReplaceType<
              typename std::decay<
                  typename std::tuple_element<I,
                                              std::tuple<Args...>>::type>::type,
              CpuMatrix>::type>(height, width)...);
H
hedaoyuan 已提交
178 179

      auto tuple2 = std::make_tuple(
180 181 182 183 184
          construct<typename ReplaceType<
              typename std::decay<
                  typename std::tuple_element<I,
                                              std::tuple<Args...>>::type>::type,
              GpuMatrix>::type>(height, width)...);
H
hedaoyuan 已提交
185 186 187 188 189 190 191

      initTuple(tuple1);
      copyTuple(tuple2, tuple1);

      call(obj1, f, std::get<I>(tuple1)...);
      call(obj2, f, std::get<I>(tuple2)...);

192
      TensorCheck(compare, obj1, obj2);
H
hedaoyuan 已提交
193 194 195 196
    }
  }
}

H
hedaoyuan 已提交
197
// AutoCompare
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
template <typename T>
class ReturnType {
public:
  typedef T type;
};

template <>
class ReturnType<CpuMatrix> {
public:
  typedef GpuMatrix type;
};

template <>
class ReturnType<CpuIVector> {
public:
  typedef GpuIVector type;
};

template <>
class ReturnType<CpuSparseMatrix> {
public:
  typedef GpuSparseMatrix type;
};

template <typename T>
H
hedaoyuan 已提交
223
typename ReturnType<T>::type autoArgs(T& v) {
224 225 226 227
  return v;
}

template <>
H
hedaoyuan 已提交
228
GpuMatrix autoArgs(CpuMatrix& v) {
229 230 231 232 233 234
  GpuMatrix a(v.getHeight(), v.getWidth());
  a.copyFrom(v);
  return a;
}

template <>
H
hedaoyuan 已提交
235
GpuIVector autoArgs(CpuIVector& v) {
236 237 238 239 240 241
  GpuIVector a(v.getSize());
  a.copyFrom(v);
  return a;
}

template <>
H
hedaoyuan 已提交
242
GpuSparseMatrix autoArgs(CpuSparseMatrix& v) {
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  GpuSparseMatrix a(v.getHeight(),
                    v.getWidth(),
                    v.getElementCnt(),
                    v.getValueType(),
                    v.getFormat());
  a.copyFrom(v, HPPL_STREAM_DEFAULT);
  hl_stream_synchronize(HPPL_STREAM_DEFAULT);
  return a;
}

class AutoCompare {
public:
  AutoCompare(size_t height, size_t width)
      : cpu(height, width), gpu(height, width) {
    init(cpu);
    copy(gpu, cpu);
  }

  template <typename C, typename R, typename... FArgs, typename... Args>
  void operator()(R (C::*f)(FArgs...), Args&&... args) {
    call(cpu, f, args...);
    call(gpu, f, autoArgs(args)...);

    TensorCheckErr(cpu, gpu);
  }

protected:
  CpuMatrix cpu;
  GpuMatrix gpu;
};

H
hedaoyuan 已提交
274 275
}  // namespace autotest

276
template <std::size_t... I, typename C, typename R, typename... Args>
277
void BaseMatrixCompare(R (C::*f)(Args...)) {
H
hedaoyuan 已提交
278
  static_assert(sizeof...(I) == sizeof...(Args),
279
                "size of parameter packs are not equal");
H
hedaoyuan 已提交
280

281 282 283 284 285 286
#ifndef PADDLE_TYPE_DOUBLE
  autotest::AssertEqual compare(1e-5);
#else
  autotest::AssertEqual compare(1e-10);
#endif

287
  autotest::BaseMatrixCompare<false, false, I...>(f, compare);
288 289
}

290
template <std::size_t... I, typename C, typename R, typename... Args>
291
void BaseMatrixAsColVector(R (C::*f)(Args...)) {
292
  static_assert(sizeof...(I) == sizeof...(Args),
293
                "size of parameter packs are not equal");
294 295 296 297 298 299 300

#ifndef PADDLE_TYPE_DOUBLE
  autotest::AssertEqual compare(1e-3);
#else
  autotest::AssertEqual compare(1e-8);
#endif

301
  autotest::BaseMatrixCompare<false, true, I...>(f, compare);
302 303
}

304
template <std::size_t... I, typename C, typename R, typename... Args>
305
void BaseMatrixAsRowVector(R (C::*f)(Args...)) {
306
  static_assert(sizeof...(I) == sizeof...(Args),
307
                "size of parameter packs are not equal");
308 309 310 311 312 313

#ifndef PADDLE_TYPE_DOUBLE
  autotest::AssertEqual compare(1e-3);
#else
  autotest::AssertEqual compare(1e-8);
#endif
314
  autotest::BaseMatrixCompare<true, false, I...>(f, compare);
H
hedaoyuan 已提交
315
}