You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

warp_perspective.cpp 13 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #include "test/common/warp_perspective.h"
  2. #include "test/common/benchmarker.h"
  3. #include "test/common/checker.h"
  4. #include "test/common/task_record_check.h"
  5. using namespace megdnn;
  6. using namespace test;
  7. using namespace warp_perspective;
  8. void WarpPerspectiveMatIdxProxy::deduce_layout(WarpPerspective*, TensorLayoutArray&) {}
  9. void WarpPerspectiveMatIdxProxy::deduce_layout(
  10. WarpPerspectiveBackwardData*, TensorLayoutArray&) {}
  11. void WarpPerspectiveMatIdxProxy::deduce_layout(
  12. WarpPerspectiveBackwardMat*, TensorLayoutArray&) {}
  13. void WarpPerspectiveMatIdxProxy::exec(
  14. WarpPerspective* opr, const TensorNDArray& tensors) {
  15. if (!W.valid()) {
  16. W = WorkspaceWrapper(opr->handle(), 0);
  17. }
  18. megdnn_assert(tensors.size() == 4);
  19. W.update(opr->get_workspace_in_bytes(
  20. tensors[0].layout, tensors[1].layout, tensors[2].layout,
  21. tensors[3].layout));
  22. opr->exec(tensors[0], tensors[1], tensors[2], tensors[3], W.workspace());
  23. }
  24. void WarpPerspectiveMatIdxProxy::exec(
  25. WarpPerspectiveBackwardData* opr, const TensorNDArray& tensors) {
  26. if (!W.valid()) {
  27. W = WorkspaceWrapper(opr->handle(), 0);
  28. }
  29. megdnn_assert(tensors.size() == 4);
  30. W.update(opr->get_workspace_in_bytes(
  31. tensors[0].layout, tensors[1].layout, tensors[2].layout,
  32. tensors[3].layout));
  33. opr->exec(tensors[0], tensors[1], tensors[2], tensors[3], W.workspace());
  34. }
  35. void WarpPerspectiveMatIdxProxy::exec(
  36. WarpPerspectiveBackwardMat* opr, const TensorNDArray& tensors) {
  37. if (!W.valid()) {
  38. W = WorkspaceWrapper(opr->handle(), 0);
  39. }
  40. megdnn_assert(tensors.size() == 5);
  41. W.update(opr->get_workspace_in_bytes(
  42. tensors[0].layout, tensors[1].layout, tensors[2].layout, tensors[3].layout,
  43. tensors[4].layout));
  44. opr->exec(
  45. tensors[0], tensors[1], tensors[2], tensors[3], tensors[4], W.workspace());
  46. }
  47. void WarpPerspectiveMultiSrcProxy::deduce_layout(
  48. WarpPerspectiveForward*, TensorLayoutArray&) {}
  49. void WarpPerspectiveMultiSrcProxy::exec(
  50. WarpPerspectiveForward* opr, const TensorNDArray& tensors) {
  51. if (!W.valid()) {
  52. W = WorkspaceWrapper(opr->handle(), 0);
  53. }
  54. megdnn_assert(tensors.size() >= 3);
  55. bool has_mat_idx = false;
  56. TensorLayout mat_idx_layout;
  57. TensorND mat_idx_tensor;
  58. TensorLayoutArray layouts(tensors.size());
  59. std::transform(
  60. tensors.begin(), tensors.end(), layouts.begin(),
  61. [](const TensorND& tensor) { return tensor.layout; });
  62. auto srcs_layouts = layouts;
  63. srcs_layouts.pop_back(); // dst
  64. if (srcs_layouts.back().ndim == 1) {
  65. has_mat_idx = true;
  66. mat_idx_layout = srcs_layouts.back();
  67. srcs_layouts.pop_back(); // mat_idx;
  68. }
  69. auto mat_layout = srcs_layouts.back();
  70. srcs_layouts.pop_back(); // mat
  71. if (has_mat_idx)
  72. W.update(opr->get_workspace_in_bytes(
  73. srcs_layouts, mat_layout, mat_idx_layout, layouts.back()));
  74. else
  75. W.update(opr->get_workspace_in_bytes(srcs_layouts, mat_layout, layouts.back()));
  76. auto srcs_tensors = tensors;
  77. srcs_tensors.pop_back(); // dst
  78. if (has_mat_idx) {
  79. mat_idx_tensor = srcs_tensors.back();
  80. srcs_tensors.pop_back(); // mat_idx;
  81. }
  82. auto mat_tensor = srcs_tensors.back();
  83. srcs_tensors.pop_back(); // mat
  84. if (has_mat_idx)
  85. opr->exec(
  86. srcs_tensors, mat_tensor, mat_idx_tensor, tensors.back(),
  87. W.workspace());
  88. else
  89. opr->exec(srcs_tensors, mat_tensor, tensors.back(), W.workspace());
  90. }
  91. std::vector<TestArg> warp_perspective::get_cv_args() {
  92. std::vector<TestArg> args;
  93. // in warp_perspective_cv INTER_AREA == INTER_LINEAR
  94. using BorderMode = param::WarpPerspective::BorderMode;
  95. using InterpolationMode = param::WarpPerspective::InterpolationMode;
  96. param::WarpPerspective cur_param;
  97. for (size_t i = 4; i < 129; i *= 4) {
  98. for (size_t ic : {1, 2, 3}) {
  99. for (BorderMode bmode : {
  100. BorderMode::REPLICATE,
  101. BorderMode::REFLECT,
  102. BorderMode::REFLECT_101,
  103. BorderMode::WRAP,
  104. BorderMode::CONSTANT,
  105. }) {
  106. for (InterpolationMode imode :
  107. {InterpolationMode::NEAREST, InterpolationMode::LINEAR,
  108. InterpolationMode::CUBIC, InterpolationMode::LANCZOS4}) {
  109. cur_param.bmode = bmode;
  110. cur_param.format = param::WarpPerspective::Format::NHWC;
  111. cur_param.imode = imode;
  112. args.emplace_back(
  113. cur_param, TensorShape{1, i, i, ic}, TensorShape{1, 3, 3},
  114. TensorShape{1}, TensorShape{1, i, i, ic});
  115. args.emplace_back(
  116. cur_param, TensorShape{1, i, i * 2, ic},
  117. TensorShape{1, 3, 3}, TensorShape{1},
  118. TensorShape{1, i, i * 2, ic});
  119. args.emplace_back(
  120. cur_param, TensorShape{1, i * 3, i, ic},
  121. TensorShape{1, 3, 3}, TensorShape{1},
  122. TensorShape{1, i * 3, i, ic});
  123. cur_param.border_val = 0.78f;
  124. args.emplace_back(
  125. cur_param, TensorShape{1, i, i, ic}, TensorShape{1, 3, 3},
  126. TensorShape{1}, TensorShape{1, 8, 8, ic});
  127. args.emplace_back(
  128. cur_param, TensorShape{1, i, i * 2, ic},
  129. TensorShape{1, 3, 3}, TensorShape{1},
  130. TensorShape{1, 8, 8, ic});
  131. args.emplace_back(
  132. cur_param, TensorShape{1, i * 3, i, ic},
  133. TensorShape{1, 3, 3}, TensorShape{1},
  134. TensorShape{1, 8, 8, ic});
  135. }
  136. }
  137. }
  138. }
  139. return args;
  140. }
  141. void warp_perspective::run_mat_idx_test(Handle* handle) {
  142. constexpr int N_SRC = 5;
  143. Checker<WarpPerspectiveForward, WarpPerspectiveMatIdxProxy> checker(handle);
  144. WarpPerspectiveMatRNG mat_rng;
  145. checker.set_rng(1, &mat_rng);
  146. UniformIntRNG mat_idx_rng{0, N_SRC - 1};
  147. checker.set_dtype(2, dtype::Int32());
  148. checker.set_rng(2, &mat_idx_rng);
  149. WarpPerspective::Param param;
  150. param.bmode = WarpPerspective::Param::BorderMode::REFLECT;
  151. param.imode = param::WarpPerspective::InterpolationMode::LINEAR;
  152. checker.set_param(param);
  153. checker.execs({{N_SRC, 3, 10, 11}, {2, 3, 3}, {2}, {2, 3, 11, 12}});
  154. checker.execs({{N_SRC, 14, 17, 13}, {123, 3, 3}, {123}, {123, 14, 16, 15}});
  155. // test NHWC
  156. param.format = WarpPerspective::Param::Format::NHWC;
  157. checker.set_param(param)
  158. .set_rng(2, &mat_idx_rng)
  159. .set_epsilon(1e-1)
  160. .set_dtype(2, dtype::Int32());
  161. checker.execs({{N_SRC, 10, 11, 3}, {2, 3, 3}, {2}, {2, 11, 12, 3}});
  162. }
  163. void warp_perspective::run_int8_test_record(int debug_level) {
  164. using Param = WarpPerspective::Param;
  165. TaskRecordChecker<WarpPerspectiveForward> checker(debug_level);
  166. UniformIntRNG input_rng{-128, 127};
  167. WarpPerspectiveMatRNG mat_rng;
  168. class ResizeBy2xMatRNG : public RNG {
  169. void gen(const TensorND& tensor_) override {
  170. float* ptr = tensor_.ptr<float>();
  171. auto N = tensor_.layout.shape[0];
  172. megdnn_assert(
  173. tensor_.layout.is_contiguous() && tensor_.layout.ndim == 3 &&
  174. tensor_.layout[1] == 3 && tensor_.layout[2] == 3);
  175. for (size_t n = 0; n < N; ++n) {
  176. // | 1 0 0 |
  177. // mat = | 0 1 0 |
  178. // | 0 0 2 |
  179. // resize_2x
  180. ptr[0] = ptr[4] = 1;
  181. ptr[8] = 2;
  182. ptr[1] = ptr[2] = ptr[3] = ptr[5] = ptr[6] = ptr[7] = 0;
  183. ptr += 9;
  184. }
  185. }
  186. } resize_2x_mat_rng;
  187. checker.set_rng(0, &input_rng)
  188. .set_rng(1, &mat_rng)
  189. .set_dtype(0, dtype::Int8())
  190. .set_dtype(1, dtype::Float32())
  191. .set_dtype(2, dtype::Int8())
  192. .set_param(
  193. {Param::InterpolationMode::LINEAR, Param::BorderMode::CONSTANT,
  194. Param::Format::NCHW, 0.f});
  195. checker.execs({{99, 48, 17, 17}, {99, 3, 3}, {99, 48, 22, 22}})
  196. .execs({{12, 3, 224, 224}, {12, 3, 3}, {12, 3, 256, 256}});
  197. checker.set_rng(1, &resize_2x_mat_rng);
  198. checker.execs({{98, 48, 17, 17}, {98, 3, 3}, {98, 48, 34, 34}})
  199. .execs({{13, 3, 224, 224}, {13, 3, 3}, {13, 3, 448, 448}});
  200. }
  201. void warp_perspective::run_int8_test(Handle* handle) {
  202. using Param = WarpPerspective::Param;
  203. Checker<WarpPerspectiveForward> checker(handle);
  204. UniformIntRNG input_rng{-128, 127};
  205. WarpPerspectiveMatRNG mat_rng;
  206. class ResizeBy2xMatRNG : public RNG {
  207. void gen(const TensorND& tensor_) override {
  208. float* ptr = tensor_.ptr<float>();
  209. auto N = tensor_.layout.shape[0];
  210. megdnn_assert(
  211. tensor_.layout.is_contiguous() && tensor_.layout.ndim == 3 &&
  212. tensor_.layout[1] == 3 && tensor_.layout[2] == 3);
  213. for (size_t n = 0; n < N; ++n) {
  214. // | 1 0 0 |
  215. // mat = | 0 1 0 |
  216. // | 0 0 2 |
  217. // resize_2x
  218. ptr[0] = ptr[4] = 1;
  219. ptr[8] = 2;
  220. ptr[1] = ptr[2] = ptr[3] = ptr[5] = ptr[6] = ptr[7] = 0;
  221. ptr += 9;
  222. }
  223. }
  224. } resize_2x_mat_rng;
  225. if (handle->type() == Handle::HandleType::CUDA) {
  226. // As currently the computation is performed in floating points instead
  227. // of full int, it could be slightly different on GPU.
  228. checker.set_epsilon(1.1).set_max_avg_error(7e-5);
  229. }
  230. checker.set_rng(0, &input_rng)
  231. .set_rng(1, &mat_rng)
  232. .set_dtype(0, dtype::Int8())
  233. .set_dtype(1, dtype::Float32())
  234. .set_dtype(2, dtype::Int8())
  235. .set_param(
  236. {Param::InterpolationMode::LINEAR, Param::BorderMode::CONSTANT,
  237. Param::Format::NCHW, 0.f});
  238. checker.execs({{99, 48, 17, 17}, {99, 3, 3}, {99, 48, 22, 22}})
  239. .execs({{12, 3, 224, 224}, {12, 3, 3}, {12, 3, 256, 256}});
  240. checker.set_rng(1, &resize_2x_mat_rng);
  241. checker.execs({{98, 48, 17, 17}, {98, 3, 3}, {98, 48, 34, 34}})
  242. .execs({{13, 3, 224, 224}, {13, 3, 3}, {13, 3, 448, 448}});
  243. }
  244. void warp_perspective::run_quint8_test(Handle* handle) {
  245. using Param = WarpPerspective::Param;
  246. Checker<WarpPerspectiveForward> checker(handle);
  247. UniformIntRNG input_rng{0, 255};
  248. WarpPerspectiveMatRNG mat_rng;
  249. class ResizeBy2xMatRNG : public RNG {
  250. void gen(const TensorND& tensor_) override {
  251. float* ptr = tensor_.ptr<float>();
  252. auto N = tensor_.layout.shape[0];
  253. megdnn_assert(
  254. tensor_.layout.is_contiguous() && tensor_.layout.ndim == 3 &&
  255. tensor_.layout[1] == 3 && tensor_.layout[2] == 3);
  256. for (size_t n = 0; n < N; ++n) {
  257. // | 1 0 0 |
  258. // mat = | 0 1 0 |
  259. // | 0 0 2 |
  260. // resize_2x
  261. ptr[0] = ptr[4] = 1;
  262. ptr[8] = 2;
  263. ptr[1] = ptr[2] = ptr[3] = ptr[5] = ptr[6] = ptr[7] = 0;
  264. ptr += 9;
  265. }
  266. }
  267. } resize_2x_mat_rng;
  268. if (handle->type() == Handle::HandleType::CUDA) {
  269. // As currently the computation is performed in floating points instead
  270. // of full int, it could be slightly different on GPU.
  271. checker.set_epsilon(1.1).set_max_avg_error(7e-5);
  272. }
  273. checker.set_rng(0, &input_rng)
  274. .set_rng(1, &mat_rng)
  275. .set_dtype(0, dtype::Quantized8Asymm(0.6f, static_cast<uint8_t>(127)))
  276. .set_dtype(1, dtype::Float32())
  277. .set_dtype(2, dtype::Quantized8Asymm(0.6f, static_cast<uint8_t>(127)))
  278. .set_param(
  279. {Param::InterpolationMode::LINEAR, Param::BorderMode::CONSTANT,
  280. Param::Format::NCHW, 0.f});
  281. checker.execs({{99, 48, 17, 17}, {99, 3, 3}, {99, 48, 22, 22}})
  282. .execs({{12, 3, 224, 224}, {12, 3, 3}, {12, 3, 256, 256}});
  283. checker.set_rng(1, &resize_2x_mat_rng);
  284. checker.execs({{98, 48, 17, 17}, {98, 3, 3}, {98, 48, 34, 34}})
  285. .execs({{13, 3, 224, 224}, {13, 3, 3}, {13, 3, 448, 448}});
  286. }
  287. // vim: syntax=cpp.doxygen