perf_layer.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. #include "perf_precomp.hpp"
  5. #include <opencv2/dnn/shape_utils.hpp>
  6. namespace opencv_test {
  7. struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
  8. {
  9. template<int DIMS>
  10. void test_slice(const int* inputShape, const int* begin, const int* end)
  11. {
  12. int backendId = get<0>(GetParam());
  13. int targetId = get<1>(GetParam());
  14. Mat input(DIMS, inputShape, CV_32FC1, Scalar::all(0));
  15. for (int i = 0; i < (int)input.total(); ++i)
  16. input.ptr<float>()[i] = (float)(i & 4095);
  17. std::vector<Range> range(DIMS);
  18. for (int i = 0; i < DIMS; ++i)
  19. range[i] = Range(begin[i], end[i]);
  20. Net net;
  21. LayerParams lp;
  22. lp.type = "Slice";
  23. lp.name = "testLayer";
  24. lp.set("begin", DictValue::arrayInt<int*>((int*)&begin[0], DIMS));
  25. lp.set("end", DictValue::arrayInt<int*>((int*)&end[0], DIMS));
  26. net.addLayerToPrev(lp.name, lp.type, lp);
  27. // warmup
  28. {
  29. net.setInput(input);
  30. net.setPreferableBackend(backendId);
  31. net.setPreferableTarget(targetId);
  32. Mat out = net.forward();
  33. EXPECT_GT(cv::norm(out, NORM_INF), 0);
  34. #if 0
  35. //normAssert(out, input(range));
  36. cout << input(range).clone().reshape(1, 1) << endl;
  37. cout << out.reshape(1, 1) << endl;
  38. #endif
  39. }
  40. TEST_CYCLE()
  41. {
  42. Mat res = net.forward();
  43. }
  44. SANITY_CHECK_NOTHING();
  45. }
  46. };
  47. static std::set<std::string> nary_eltwise_cuda_deny_ops = {"equal", "greater", "less", "mean", "pow", "sub"};
  48. struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
  49. {
  50. void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
  51. {
  52. int backendId = get<0>(GetParam());
  53. int targetId = get<1>(GetParam());
  54. if (!isRef && backendId == DNN_BACKEND_CUDA)
  55. {
  56. if (a_shape.size() != b_shape.size())
  57. throw SkipTestException("The test is skipped because inputs with different shape size are not supported.");
  58. for(int i = 0; i < a_shape.size(); i++)
  59. if (a_shape[i] != b_shape[i] && a_shape[i] != 1 && b_shape[i] != 1)
  60. throw SkipTestException("The test is skipped because inputs are not supported.");
  61. if (nary_eltwise_cuda_deny_ops.find(op) != nary_eltwise_cuda_deny_ops.end())
  62. throw SkipTestException("The operator '" + op + "' is skipped because is not support with cuda currently.");
  63. }
  64. Mat a(a_shape, CV_32FC1);
  65. Mat b(b_shape, CV_32FC1);
  66. Scalar mean = 0.f;
  67. Scalar std = 1.f;
  68. randn(a, mean, std);
  69. randn(b, mean, std);
  70. Net net;
  71. LayerParams lp;
  72. if (isRef)
  73. lp.type = "Eltwise";
  74. else
  75. lp.type = "NaryEltwise";
  76. lp.name = "testLayer";
  77. lp.set("operation", op);
  78. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  79. net.connect(0, 1, id, 1);
  80. // warmup
  81. {
  82. std::vector<String> inpNames(2);
  83. inpNames[0] = "a";
  84. inpNames[1] = "b";
  85. net.setInputsNames(inpNames);
  86. net.setInput(a, inpNames[0]);
  87. net.setInput(b, inpNames[1]);
  88. net.setPreferableBackend(backendId);
  89. net.setPreferableTarget(targetId);
  90. Mat out = net.forward();
  91. }
  92. TEST_CYCLE()
  93. {
  94. Mat res = net.forward();
  95. }
  96. SANITY_CHECK_NOTHING();
  97. }
  98. int N = 8;
  99. int C = 256;
  100. int H = 128;
  101. int W = 100;
  102. };
  103. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_add)
  104. {
  105. test_layer({N, C, H, W}, {N, C, H, W}, "add");
  106. }
  107. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_div)
  108. {
  109. test_layer({N, C, H, W}, {N, C, H, W}, "div");
  110. }
  111. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_div)
  112. {
  113. test_layer({N, C, H, W}, {N, C, H, W}, "div", true);
  114. }
  115. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_equal)
  116. {
  117. test_layer({N, C, H, W}, {N, C, H, W}, "equal");
  118. }
  119. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_greater)
  120. {
  121. test_layer({N, C, H, W}, {N, C, H, W}, "greater");
  122. }
  123. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_less)
  124. {
  125. test_layer({N, C, H, W}, {N, C, H, W}, "less");
  126. }
  127. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_max)
  128. {
  129. test_layer({N, C, H, W}, {N, C, H, W}, "max");
  130. }
  131. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_max)
  132. {
  133. test_layer({N, C, H, W}, {N, C, H, W}, "max", true);
  134. }
  135. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_mean)
  136. {
  137. test_layer({N, C, H, W}, {N, C, H, W}, "mean");
  138. }
  139. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_min)
  140. {
  141. test_layer({N, C, H, W}, {N, C, H, W}, "min");
  142. }
  143. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_min)
  144. {
  145. test_layer({N, C, H, W}, {N, C, H, W}, "min", true);
  146. }
  147. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_mul)
  148. {
  149. test_layer({N, C, H, W}, {N, C, H, W}, "mul");
  150. }
  151. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_mul)
  152. {
  153. test_layer({N, C, H, W}, {N, C, H, W}, "prod", true);
  154. }
  155. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_pow)
  156. {
  157. test_layer({N, C, H, W}, {N, C, H, W}, "pow");
  158. }
  159. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_sub)
  160. {
  161. test_layer({N, C, H, W}, {N, C, H, W}, "sub");
  162. }
  163. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_sum)
  164. {
  165. test_layer({N, C, H, W}, {N, C, H, W}, "sum");
  166. }
  167. PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_sum)
  168. {
  169. test_layer({N, C, H, W}, {N, C, H, W}, "sum", true);
  170. }
  171. PERF_TEST_P_(Layer_NaryEltwise, NCHW_C_sum)
  172. {
  173. test_layer({N, C, H, W}, {C, 1, 1}, "sum");
  174. }
  175. PERF_TEST_P_(Layer_NaryEltwise, NHWC_C)
  176. {
  177. test_layer({N, H, W, C}, {1, C}, "sum");
  178. }
  179. PERF_TEST_P_(Layer_NaryEltwise, NHWC_H)
  180. {
  181. test_layer({N, H, W, C}, {1, H, 1, 1}, "sum");
  182. }
  183. PERF_TEST_P_(Layer_Slice, YOLOv4_tiny_1)
  184. {
  185. const int inputShape[4] = {1, 64, 104, 104};
  186. const int begin[] = {0, 32, 0, 0};
  187. const int end[] = {1, 64, 104, 104};
  188. test_slice<4>(inputShape, begin, end);
  189. }
  190. PERF_TEST_P_(Layer_Slice, YOLOv4_tiny_2)
  191. {
  192. const int inputShape[4] = {1, 128, 52, 52};
  193. const int begin[] = {0, 64, 0, 0};
  194. const int end[] = {1, 128, 52, 52};
  195. test_slice<4>(inputShape, begin, end);
  196. }
  197. PERF_TEST_P_(Layer_Slice, YOLOv4_tiny_3)
  198. {
  199. const int inputShape[4] = {1, 256, 26, 26};
  200. const int begin[] = {0, 128, 0, 0};
  201. const int end[] = {1, 256, 26, 26};
  202. test_slice<4>(inputShape, begin, end);
  203. }
  204. PERF_TEST_P_(Layer_Slice, FastNeuralStyle_eccv16)
  205. {
  206. const int inputShape[4] = {1, 128, 80, 100};
  207. const int begin[] = {0, 0, 2, 2};
  208. const int end[] = {1, 128, 76, 96};
  209. test_slice<4>(inputShape, begin, end);
  210. }
  211. using Layer_Scatter = TestBaseWithParam<tuple<std::vector<int>, std::string, int, tuple<Backend, Target>>>;
  212. PERF_TEST_P_(Layer_Scatter, scatter) {
  213. std::vector<int> shape = get<0>(GetParam());
  214. std::string reduction = get<1>(GetParam());
  215. int axis = get<2>(GetParam());
  216. int backend_id = get<0>(get<3>(GetParam()));
  217. int target_id = get<1>(get<3>(GetParam()));
  218. Mat data(shape, CV_32FC1);
  219. Mat indices(shape, CV_32FC1);
  220. Mat updates(shape, CV_32FC1);
  221. randn(data, 0.f, 1.f);
  222. randu(indices, 0, shape[axis]);
  223. randn(updates, 0.f, 1.f);
  224. indices.convertTo(indices, CV_32SC1, 1, -1);
  225. Net net;
  226. LayerParams lp;
  227. lp.type = "Scatter";
  228. lp.name = "testLayer";
  229. lp.set("reduction", reduction);
  230. lp.set("axis", axis);
  231. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  232. net.connect(0, 0, id, 0);
  233. net.connect(0, 1, id, 1);
  234. net.connect(0, 2, id, 2);
  235. // warmup
  236. {
  237. std::vector<String> input_names{"data", "indices", "updates"};
  238. net.setInputsNames(input_names);
  239. net.setInput(data, input_names[0]);
  240. net.setInput(indices, input_names[1]);
  241. net.setInput(updates, input_names[2]);
  242. net.setPreferableBackend(backend_id);
  243. net.setPreferableTarget(target_id);
  244. Mat out = net.forward();
  245. }
  246. // perf
  247. TEST_CYCLE()
  248. {
  249. Mat res = net.forward();
  250. }
  251. SANITY_CHECK_NOTHING();
  252. }
  253. INSTANTIATE_TEST_CASE_P(/**/, Layer_Scatter, Combine(
  254. Values(std::vector<int>{2, 128, 64, 50}),
  255. Values(std::string("none"), std::string("add")),
  256. Values(0), // use Values(0, 1, 2, 3) for more details
  257. dnnBackendsAndTargets(/* withInferenceEngine= */ false,
  258. /* withHalide= */ false,
  259. /* withCpuOCV= */ true,
  260. /* withVkCom= */ false,
  261. /* withCUDA= */ false,
  262. /* withNgraph= */ false,
  263. /* withWebnn= */ false,
  264. /* withCann= */ false) // only test on CPU
  265. ));
  266. using Layer_ScatterND = TestBaseWithParam<tuple<std::vector<int>, std::string, tuple<Backend, Target>>>;
  267. PERF_TEST_P_(Layer_ScatterND, scatterND) {
  268. std::vector<int> shape = get<0>(GetParam());
  269. std::string reduction = get<1>(GetParam());
  270. int backend_id = get<0>(get<2>(GetParam()));
  271. int target_id = get<1>(get<2>(GetParam()));
  272. std::vector<int> indices_shape(shape);
  273. indices_shape.push_back(int(shape.size()));
  274. Mat data(shape, CV_32FC1);
  275. Mat indices(indices_shape, CV_32FC1);
  276. Mat updates(shape, CV_32FC1);
  277. randn(data, 0.f, 1.f);
  278. randn(updates, 0.f, 1.f);
  279. // Create indices such that indices[n_i, c_j, h_k, w_l, :4] = [i, j, k, l]
  280. std::vector<int> current_index_tuple(shape.size());
  281. int total = data.total();
  282. std::vector<int> indices_step;
  283. for (int i = 0; i < indices.dims; i++)
  284. {
  285. int step = indices.step.p[i] / sizeof(float);
  286. indices_step.push_back(step);
  287. }
  288. int t, j, idx, offset_at_idx, offset;
  289. auto *indices_ptr = indices.ptr<float>();
  290. for (int i = 0; i < total; i++)
  291. {
  292. t = i;
  293. for (j = shape.size() - 1; j >= 0; j--)
  294. {
  295. idx = t / shape[j];
  296. offset_at_idx = (int)(t - idx * shape[j]);
  297. current_index_tuple[j] = offset_at_idx;
  298. t = idx;
  299. }
  300. offset = 0;
  301. for (j = 0; j < shape.size(); j++)
  302. offset += current_index_tuple[j] * indices_step[j];
  303. for (j = 0; j < shape.size(); j++)
  304. indices_ptr[offset + j] = current_index_tuple[j];
  305. }
  306. Net net;
  307. LayerParams lp;
  308. lp.type = "ScatterND";
  309. lp.name = "testLayer";
  310. lp.set("reduction", reduction);
  311. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  312. net.connect(0, 0, id, 0);
  313. net.connect(0, 1, id, 1);
  314. net.connect(0, 2, id, 2);
  315. // warmup
  316. {
  317. std::vector<String> input_names{"data", "indices", "updates"};
  318. net.setInputsNames(input_names);
  319. net.setInput(data, input_names[0]);
  320. net.setInput(indices, input_names[1]);
  321. net.setInput(updates, input_names[2]);
  322. net.setPreferableBackend(backend_id);
  323. net.setPreferableTarget(target_id);
  324. Mat out = net.forward();
  325. }
  326. TEST_CYCLE()
  327. {
  328. Mat res = net.forward();
  329. }
  330. SANITY_CHECK_NOTHING();
  331. }
  332. INSTANTIATE_TEST_CASE_P(/**/, Layer_ScatterND, Combine(
  333. Values(std::vector<int>{2, 128, 64, 50}),
  334. Values(std::string("none"), std::string("add")),
  335. dnnBackendsAndTargets(/* withInferenceEngine= */ false,
  336. /* withHalide= */ false,
  337. /* withCpuOCV= */ true,
  338. /* withVkCom= */ false,
  339. /* withCUDA= */ false,
  340. /* withNgraph= */ false,
  341. /* withWebnn= */ false,
  342. /* withCann= */ false) // only test on CPU
  343. ));
  344. struct Layer_LayerNorm : public TestBaseWithParam<tuple<Backend, Target> >
  345. {
  346. void test_layer(const std::vector<int>& x_shape)
  347. {
  348. int backendId = get<0>(GetParam());
  349. int targetId = get<1>(GetParam());
  350. Mat x(x_shape, CV_32FC1);
  351. Mat scale(x_shape.back(), 1, CV_32FC1);
  352. Mat b(x_shape.back(), 1, CV_32FC1);
  353. randu(x, 0.f, 1.f);
  354. randu(scale, 0.f, 1.f);
  355. randu(b, 0.f, 1.f);
  356. Net net;
  357. LayerParams lp;
  358. lp.type = "LayerNormalization";
  359. lp.name = "testLayer";
  360. lp.set("axis", 2);
  361. lp.set("hasBias", true);
  362. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  363. net.connect(0, 0, id, 0);
  364. net.connect(0, 1, id, 1);
  365. net.connect(0, 2, id, 2);
  366. // warmup
  367. {
  368. std::vector<String> inpNames(3);
  369. inpNames[0] = "x";
  370. inpNames[1] = "scale";
  371. inpNames[2] = "b";
  372. net.setInputsNames(inpNames);
  373. net.setInput(x, inpNames[0]);
  374. net.setInput(scale, inpNames[1]);
  375. net.setInput(b, inpNames[2]);
  376. net.setPreferableBackend(backendId);
  377. net.setPreferableTarget(targetId);
  378. Mat out = net.forward();
  379. }
  380. TEST_CYCLE()
  381. {
  382. Mat res = net.forward();
  383. }
  384. SANITY_CHECK_NOTHING();
  385. }
  386. int N = 1;
  387. int H = 50;
  388. int W = 768;
  389. };
  390. PERF_TEST_P_(Layer_LayerNorm, LayerNorm)
  391. {
  392. test_layer({N, H ,W});
  393. }
  394. struct Layer_LayerNormExpanded : public TestBaseWithParam<tuple<Backend, Target> >
  395. {
  396. void test_layer(const std::vector<int>& x_shape)
  397. {
  398. int backendId = get<0>(GetParam());
  399. int targetId = get<1>(GetParam());
  400. Mat x(x_shape, CV_32FC1);
  401. Mat scale(1, x_shape.back(), CV_32FC1); // transpose to pass shape check
  402. Mat b(1, x_shape.back(), CV_32FC1); // transpose to pass shape check
  403. randu(x, 0.f, 1.f);
  404. randu(scale, 0.f, 1.f);
  405. randu(b, 0.f, 1.f);
  406. // sub graph structure:
  407. // -> ReduceMean -> -> Pow(2) -> ReduceMean -> Add(epsilon) -> Sqrt ->
  408. // x Sub Div -> Mul(scale) -> Add(bias)
  409. // ---------------> ------------------------------------------------->
  410. Net net;
  411. LayerParams lp_rm;
  412. lp_rm.type = "Reduce";
  413. lp_rm.name = "reducemean1";
  414. lp_rm.set("reduce", "AVE");
  415. std::vector<int> deleteDims(1, x_shape.back());
  416. lp_rm.set("deleted_dims", DictValue::arrayInt(&deleteDims[0], deleteDims.size()));
  417. std::vector<int> targetDims(x_shape.begin(), x_shape.end());
  418. targetDims[x_shape.size() - 1] = 1;
  419. lp_rm.set("target_dims", DictValue::arrayInt(&targetDims[0], targetDims.size()));
  420. int id_rm = net.addLayerToPrev(lp_rm.name, lp_rm.type, lp_rm);
  421. net.connect(0, 0, id_rm, 0);
  422. LayerParams lp_sub;
  423. lp_sub.type = "NaryEltwise";
  424. lp_sub.name = "sub1";
  425. lp_sub.set("operation", "sub");
  426. int id_sub = net.addLayer(lp_sub.name, lp_sub.type, lp_sub);
  427. net.connect(0, 0, id_sub, 0);
  428. net.connect(id_rm, 0, id_sub, 1);
  429. Mat pow_const(1, 1, CV_32FC1);
  430. pow_const.at<float>(0) = 2.f;
  431. LayerParams lp_pow_const;
  432. lp_pow_const.type = "Const";
  433. lp_pow_const.name = "const1";
  434. lp_pow_const.blobs.push_back(pow_const);
  435. int id_pow_const = net.addLayer(lp_pow_const.name, lp_pow_const.type, lp_pow_const);
  436. LayerParams lp_pow;
  437. lp_pow.type = "NaryEltwise";
  438. lp_pow.name = "pow1";
  439. lp_pow.set("operation", "pow");
  440. int id_pow = net.addLayer(lp_pow.name, lp_pow.type, lp_pow);
  441. net.connect(id_sub, 0, id_pow, 0);
  442. net.connect(id_pow_const, 0, id_pow, 1);
  443. LayerParams lp_rm1;
  444. lp_rm1.type = "Reduce";
  445. lp_rm1.name = "reducemean2";
  446. lp_rm1.set("reduce", "AVE");
  447. lp_rm1.set("deleted_dims", DictValue::arrayInt(&deleteDims[0], deleteDims.size()));
  448. lp_rm1.set("target_dims", DictValue::arrayInt(&targetDims[0], targetDims.size()));
  449. int id_rm1 = net.addLayer(lp_rm1.name, lp_rm1.type, lp_rm1);
  450. net.connect(id_pow, 0, id_rm1, 0);
  451. Mat add_const(1, 1, CV_32F);
  452. add_const.at<float>(0) = 1e-5;
  453. LayerParams lp_add_const;
  454. lp_add_const.type = "Const";
  455. lp_add_const.name = "const2";
  456. lp_add_const.blobs.push_back(add_const);
  457. int id_add_const = net.addLayer(lp_add_const.name, lp_add_const.type, lp_add_const);
  458. LayerParams lp_add;
  459. lp_add.type = "NaryEltwise";
  460. lp_add.name = "add1";
  461. lp_add.set("operation", "add");
  462. int id_add = net.addLayer(lp_add.name, lp_add.type, lp_add);
  463. net.connect(id_rm1, 0, id_add, 0);
  464. net.connect(id_add_const, 0, id_add, 1);
  465. LayerParams lp_sqrt;
  466. lp_sqrt.type = "Sqrt";
  467. lp_sqrt.name = "sqrt1";
  468. int id_sqrt = net.addLayer(lp_sqrt.name, lp_sqrt.type, lp_sqrt);
  469. net.connect(id_add, 0, id_sqrt, 0);
  470. LayerParams lp_div;
  471. lp_div.type = "NaryEltwise";
  472. lp_div.name = "div1";
  473. lp_div.set("operation", "div");
  474. int id_div = net.addLayer(lp_div.name, lp_div.type, lp_div);
  475. net.connect(id_sub, 0, id_div, 0);
  476. net.connect(id_sqrt, 0, id_div, 1);
  477. LayerParams lp_mul;
  478. lp_mul.type = "NaryEltwise";
  479. lp_mul.name = "mul1";
  480. lp_mul.set("operation", "mul");
  481. int id_mul = net.addLayer(lp_mul.name, lp_mul.type, lp_mul);
  482. net.connect(id_div, 0, id_mul, 0);
  483. net.connect(0, 1, id_mul, 1);
  484. LayerParams lp_add1;
  485. lp_add1.type = "NaryEltwise";
  486. lp_add1.name = "add2";
  487. lp_add1.set("operation", "add");
  488. int id_add1 = net.addLayer(lp_add1.name, lp_add1.type, lp_add1);
  489. net.connect(id_mul, 0, id_add1, 0);
  490. net.connect(0, 2, id_add1, 1);
  491. // warmup
  492. {
  493. std::vector<String> inpNames(3);
  494. inpNames[0] = "x";
  495. inpNames[1] = "scale";
  496. inpNames[2] = "b";
  497. net.setInputsNames(inpNames);
  498. net.setInput(x, inpNames[0]);
  499. net.setInput(scale, inpNames[1]);
  500. net.setInput(b, inpNames[2]);
  501. net.setPreferableBackend(backendId);
  502. net.setPreferableTarget(targetId);
  503. Mat out = net.forward();
  504. }
  505. TEST_CYCLE()
  506. {
  507. Mat res = net.forward();
  508. }
  509. SANITY_CHECK_NOTHING();
  510. }
  511. int N = 1;
  512. int H = 50;
  513. int W = 768;
  514. };
  515. PERF_TEST_P_(Layer_LayerNormExpanded, DISABLED_LayerNormExpanded)
  516. {
  517. test_layer({N, H ,W});
  518. }
  519. struct Layer_GatherElements : public TestBaseWithParam<tuple<Backend, Target> >
  520. {
  521. void test_layer(const std::vector<int>& data_shape, const std::vector<int>& indices_shape, int axis = 0)
  522. {
  523. int backendId = get<0>(GetParam());
  524. int targetId = get<1>(GetParam());
  525. Mat data(data_shape, CV_32FC1);
  526. Mat indices(indices_shape, CV_32FC1);
  527. randu(data, 0.f, 1.f);
  528. randu(indices, 0, data_shape[axis]);
  529. Net net;
  530. LayerParams lp;
  531. lp.type = "GatherElements";
  532. lp.name = "testLayer";
  533. lp.set("axis", axis);
  534. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  535. net.connect(0, 0, id, 0);
  536. net.connect(0, 1, id, 1);
  537. // warmup
  538. {
  539. std::vector<String> inpNames(3);
  540. inpNames[0] = "data";
  541. inpNames[1] = "indices";
  542. net.setInputsNames(inpNames);
  543. net.setInput(data, inpNames[0]);
  544. net.setInput(indices, inpNames[1]);
  545. net.setPreferableBackend(backendId);
  546. net.setPreferableTarget(targetId);
  547. Mat out = net.forward();
  548. }
  549. TEST_CYCLE()
  550. {
  551. Mat res = net.forward();
  552. }
  553. SANITY_CHECK_NOTHING();
  554. }
  555. };
  556. PERF_TEST_P_(Layer_GatherElements, GatherElements)
  557. {
  558. test_layer({2700, 1, 2914}, {2700, 1, 81}, 2);
  559. }
  560. struct Layer_InstanceNorm : public TestBaseWithParam<tuple<Backend, Target> >
  561. {
  562. void test_layer(const std::vector<int>& x_shape)
  563. {
  564. int backendId = get<0>(GetParam());
  565. int targetId = get<1>(GetParam());
  566. Mat x(x_shape, CV_32FC1);
  567. Mat scale(x_shape[1], 1, CV_32FC1);
  568. Mat b(x_shape[1], 1, CV_32FC1);
  569. randu(x, 0.f, 1.f);
  570. randu(scale, 0.f, 1.f);
  571. randu(b, 0.f, 1.f);
  572. Net net;
  573. LayerParams lp;
  574. lp.type = "InstanceNormalization";
  575. lp.name = "testLayer";
  576. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  577. net.connect(0, 0, id, 0);
  578. net.connect(0, 1, id, 1);
  579. net.connect(0, 2, id, 2);
  580. // warmup
  581. {
  582. std::vector<String> inpNames{"x", "scale", "b"};
  583. net.setInputsNames(inpNames);
  584. net.setInput(x, inpNames[0]);
  585. net.setInput(scale, inpNames[1]);
  586. net.setInput(b, inpNames[2]);
  587. net.setPreferableBackend(backendId);
  588. net.setPreferableTarget(targetId);
  589. Mat out = net.forward();
  590. }
  591. TEST_CYCLE()
  592. {
  593. Mat res = net.forward();
  594. }
  595. SANITY_CHECK_NOTHING();
  596. }
  597. int N = 2;
  598. int C = 64;
  599. int H = 180;
  600. int W = 240;
  601. };
  602. PERF_TEST_P_(Layer_InstanceNorm, InstanceNorm)
  603. {
  604. test_layer({N, C, H, W});
  605. }
  606. struct Layer_Attention : public TestBaseWithParam<tuple<Backend, Target>> {
  607. void test_layer(const std::vector<int> x_shape, const std::vector<int> qkv_hidden_sizes, const int num_heads) {
  608. int backendId = get<0>(GetParam());
  609. int targetId = get<1>(GetParam());
  610. auto qk_hidden_size = qkv_hidden_sizes[0];
  611. auto v_hidden_size = qkv_hidden_sizes[2];
  612. auto input_hidden_size = x_shape[2];
  613. auto hidden_size = qk_hidden_size + qk_hidden_size + v_hidden_size;
  614. Mat x(x_shape, CV_32F);
  615. Mat weight(std::vector<int>{input_hidden_size, hidden_size}, CV_32F);
  616. Mat bias(std::vector<int>{hidden_size}, CV_32F);
  617. randu(x, 0.f, 1.f);
  618. randu(weight, 0.f, 1.f);
  619. randu(bias, 0.f, 1.f);
  620. LayerParams lp;
  621. lp.type = "Attention";
  622. lp.name = "testLayer";
  623. lp.set("num_heads", num_heads);
  624. lp.set("qkv_hidden_sizes", DictValue::arrayInt(qkv_hidden_sizes.data(), qkv_hidden_sizes.size()));
  625. Net net;
  626. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  627. net.connect(0, 0, id, 0);
  628. net.connect(0, 1, id, 1);
  629. net.connect(0, 2, id, 2);
  630. {
  631. std::vector<std::string> input_names{"x", "weight", "bias"};
  632. net.setInputsNames(input_names);
  633. net.setInput(x, input_names[0]);
  634. net.setInput(weight, input_names[1]);
  635. net.setInput(bias, input_names[2]);
  636. net.setPreferableBackend(backendId);
  637. net.setPreferableTarget(targetId);
  638. Mat out = net.forward();
  639. }
  640. TEST_CYCLE()
  641. {
  642. Mat out = net.forward();
  643. }
  644. SANITY_CHECK_NOTHING();
  645. }
  646. };
  647. PERF_TEST_P_(Layer_Attention, VisionTransformer) {
  648. test_layer({1, 197, 768}, {768, 768, 768}, 12);
  649. }
  650. struct Layer_GroupNorm : public TestBaseWithParam<tuple<Backend, Target> >
  651. {
  652. void test_layer(const std::vector<int>& x_shape, int num_groups)
  653. {
  654. int backendId = get<0>(GetParam());
  655. int targetId = get<1>(GetParam());
  656. Mat x(x_shape, CV_32FC1);
  657. Mat scale(x_shape[1], 1, CV_32FC1);
  658. Mat b(x_shape[1], 1, CV_32FC1);
  659. randu(x, 0.f, 1.f);
  660. randu(scale, 0.f, 1.f);
  661. randu(b, 0.f, 1.f);
  662. Net net;
  663. LayerParams lp;
  664. lp.type = "GroupNormalization";
  665. lp.name = "testLayer";
  666. lp.set("num_groups", num_groups);
  667. int id = net.addLayerToPrev(lp.name, lp.type, lp);
  668. net.connect(0, 0, id, 0);
  669. net.connect(0, 1, id, 1);
  670. net.connect(0, 2, id, 2);
  671. // warmup
  672. {
  673. std::vector<String> inpNames{"x", "scale", "b"};
  674. net.setInputsNames(inpNames);
  675. net.setInput(x, inpNames[0]);
  676. net.setInput(scale, inpNames[1]);
  677. net.setInput(b, inpNames[2]);
  678. net.setPreferableBackend(backendId);
  679. net.setPreferableTarget(targetId);
  680. Mat out = net.forward();
  681. }
  682. TEST_CYCLE()
  683. {
  684. Mat res = net.forward();
  685. }
  686. SANITY_CHECK_NOTHING();
  687. }
  688. int N = 2;
  689. int C = 64;
  690. int H = 180;
  691. int W = 240;
  692. int num_groups = 16;
  693. };
  694. PERF_TEST_P_(Layer_GroupNorm, GroupNorm)
  695. {
  696. test_layer({N, C, H, W}, num_groups);
  697. }
  698. INSTANTIATE_TEST_CASE_P(/**/, Layer_Slice, dnnBackendsAndTargets(false, false));
  699. INSTANTIATE_TEST_CASE_P(/**/, Layer_NaryEltwise, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  700. #ifdef HAVE_CUDA
  701. INSTANTIATE_TEST_CASE_P(CUDA, Layer_NaryEltwise, testing::Values(std::make_tuple(DNN_BACKEND_CUDA, DNN_TARGET_CUDA)));
  702. #endif
  703. #ifdef HAVE_VULKAN
  704. INSTANTIATE_TEST_CASE_P(VULKAN, Layer_NaryEltwise, testing::Values(std::make_tuple(DNN_BACKEND_VKCOM, DNN_TARGET_VULKAN)));
  705. #endif
  706. INSTANTIATE_TEST_CASE_P(/**/, Layer_LayerNorm, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  707. INSTANTIATE_TEST_CASE_P(/**/, Layer_LayerNormExpanded, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  708. INSTANTIATE_TEST_CASE_P(/**/, Layer_GatherElements, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  709. INSTANTIATE_TEST_CASE_P(/**/, Layer_InstanceNorm, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  710. INSTANTIATE_TEST_CASE_P(/**/, Layer_Attention, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  711. INSTANTIATE_TEST_CASE_P(/**/, Layer_GroupNorm, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU)));
  712. typedef TestBaseWithParam<tuple<Vec4i, int, bool, tuple<Backend, Target> > > Layer_FullyConnected;
  713. PERF_TEST_P_(Layer_FullyConnected, fc)
  714. {
  715. std::vector<int> inpShape;
  716. inpShape.reserve(4);
  717. for (int i = 0; i < 4; ++i) {
  718. int dim = get<0>(GetParam())[i];
  719. if (dim == 0)
  720. break;
  721. inpShape.push_back(dim);
  722. }
  723. Mat input(inpShape, CV_32F);
  724. randn(input, 0, 1);
  725. int axis = input.dims - 1;
  726. int outDims = get<1>(GetParam());
  727. bool isMatMul = get<2>(GetParam());
  728. int backendId = get<0>(get<3>(GetParam()));
  729. int targetId = get<1>(get<3>(GetParam()));
  730. if (inpShape.size() == 4 && inpShape[0] == 5 && inpShape[1] == 16 && inpShape[2] == 512 && inpShape[3] == 128 && outDims >= 512)
  731. applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG);
  732. std::vector<int> weightShape;
  733. if (isMatMul) {
  734. weightShape = inpShape;
  735. weightShape[weightShape.size() - 2] = outDims;
  736. } else {
  737. weightShape = {outDims, (int)input.total(axis, input.dims)};
  738. }
  739. Mat weights(weightShape, CV_32F);
  740. randn(weights, 0, 1);
  741. LayerParams lp;
  742. lp.set("axis", input.dims - 1);
  743. lp.set("is_matmul", weights.dims > 2);
  744. lp.set("bias_term", false);
  745. lp.set("num_output", (int)weights.total(0, weights.dims - 1));
  746. lp.blobs.resize(1, weights);
  747. Net net;
  748. net.addLayerToPrev("matmul", "InnerProduct", lp);
  749. net.setInput(input);
  750. net.setPreferableBackend(backendId);
  751. net.setPreferableTarget(targetId);
  752. // warmup
  753. Mat output = net.forward();
  754. TEST_CYCLE()
  755. {
  756. net.forward();
  757. }
  758. SANITY_CHECK_NOTHING();
  759. }
  760. INSTANTIATE_TEST_CASE_P(/**/, Layer_FullyConnected, Combine(
  761. Values( // input size
  762. Vec4i(5, 512, 384),
  763. Vec4i(5, 16, 512, 128)
  764. ),
  765. Values(256, 512, 1024), // output dimension
  766. testing::Bool(), // is_matmul
  767. dnnBackendsAndTargets()
  768. ));
  769. typedef TestBaseWithParam<tuple<std::vector<int>, int, tuple<Backend, Target> > > Layer_Softmax;
  770. PERF_TEST_P_(Layer_Softmax, softmax_3d) {
  771. std::vector<int> shape = get<0>(GetParam());
  772. int axis = get<1>(GetParam());
  773. int backendId = get<0>(get<2>(GetParam()));
  774. int targetId = get<1>(get<2>(GetParam()));
  775. Mat data(shape, CV_32FC1);
  776. Scalar mean = 0.f;
  777. Scalar std = 1.f;
  778. randn(data, mean, std);
  779. Net net;
  780. LayerParams lp;
  781. lp.type = "Softmax";
  782. lp.name = "testLayer";
  783. lp.set("axis", axis);
  784. net.addLayerToPrev(lp.name, lp.type, lp);
  785. // warmup
  786. {
  787. net.setInput(data);
  788. net.setPreferableBackend(backendId);
  789. net.setPreferableTarget(targetId);
  790. Mat out = net.forward();
  791. }
  792. TEST_CYCLE() {
  793. Mat res = net.forward();
  794. }
  795. SANITY_CHECK_NOTHING();
  796. }
  797. INSTANTIATE_TEST_CASE_P(/**/, Layer_Softmax, Combine(
  798. Values( // input size
  799. std::vector<int>({16, 50, 50}),
  800. std::vector<int>({16, 197, 197}),
  801. std::vector<int>({16, 1024, 1024})
  802. ),
  803. Values(0, 1, 2), // axis
  804. dnnBackendsAndTargets(/* withInferenceEngine= */ false,
  805. /* withHalide= */ false,
  806. /* withCpuOCV= */ true,
  807. /* withVkCom= */ false,
  808. /* withCUDA= */ false,
  809. /* withNgraph= */ false,
  810. /* withWebnn= */ false,
  811. /* withCann= */ false) // only test on CPU
  812. ));
  813. struct Layer_Elementwise : public TestBaseWithParam<tuple<Backend, Target>> {
  814. void test_layer(const std::string &op_type, const std::vector<int> &input_shape) {
  815. int backend_id = get<0>(GetParam());
  816. int target_id = get<1>(GetParam());
  817. Mat input(input_shape, CV_32F);
  818. randu(input, -10.0f, 10.f);
  819. LayerParams lp;
  820. lp.type = op_type;
  821. lp.name = cv::format("PerfLayer/%s", op_type.c_str());
  822. Net net;
  823. net.addLayerToPrev(lp.name, lp.type, lp);
  824. // Warmup
  825. {
  826. net.setInput(input);
  827. net.setPreferableBackend(backend_id);
  828. net.setPreferableTarget(target_id);
  829. net.forward();
  830. }
  831. TEST_CYCLE() {
  832. net.forward();
  833. }
  834. SANITY_CHECK_NOTHING();
  835. }
  836. int N = 2;
  837. int C = 32;
  838. int H = 416;
  839. int W = 416;
  840. };
  841. PERF_TEST_P_(Layer_Elementwise, Gelu) {
  842. test_layer("Gelu", std::vector<int>{1, 50, 3072});
  843. }
  844. PERF_TEST_P_(Layer_Elementwise, Swish) {
  845. test_layer("Swish", std::vector<int>{N, C, H, W});
  846. }
  847. PERF_TEST_P_(Layer_Elementwise, Mish) {
  848. test_layer("Mish", std::vector<int>{N, C, H, W});
  849. }
  850. PERF_TEST_P_(Layer_Elementwise, Elu) {
  851. test_layer("ELU", std::vector<int>{N, C, H, W});
  852. }
  853. PERF_TEST_P_(Layer_Elementwise, Celu) {
  854. test_layer("Celu", std::vector<int>{N, C, H, W});
  855. }
  856. PERF_TEST_P_(Layer_Elementwise, Selu) {
  857. test_layer("Selu", std::vector<int>{N, C, H, W});
  858. }
  859. PERF_TEST_P_(Layer_Elementwise, HardSwish) {
  860. test_layer("HardSwish", std::vector<int>{N, C, H, W});
  861. }
  862. INSTANTIATE_TEST_CASE_P(/**/, Layer_Elementwise,
  863. dnnBackendsAndTargets(/* withInferenceEngine= */ true,
  864. /* withHalide= */ false,
  865. /* withCpuOCV= */ true,
  866. /* withVkCom= */ false,
  867. /* withCUDA= */ true,
  868. /* withNgraph= */ true,
  869. /* withWebnn= */ false,
  870. /* withCann= */ false));
  871. struct Layer_TopK : public TestBaseWithParam<tuple<Backend, Target>> {
  872. void test_layer(const std::vector<int> &input_shape, const int K, const int axis) {
  873. int backend_id = get<0>(GetParam());
  874. int target_id = get<1>(GetParam());
  875. Mat input_data(input_shape, CV_32F);
  876. randn(input_data, -1.f, 1.f);
  877. Net net;
  878. LayerParams lp;
  879. lp.type = "TopK";
  880. lp.name = "testLayer";
  881. lp.set("k", K);
  882. lp.set("axis", axis);
  883. net.addLayerToPrev(lp.name, lp.type, lp);
  884. // Warmup
  885. {
  886. net.setInput(input_data);
  887. net.setPreferableBackend(backend_id);
  888. net.setPreferableTarget(target_id);
  889. net.forward();
  890. }
  891. TEST_CYCLE() {
  892. net.forward();
  893. }
  894. SANITY_CHECK_NOTHING();
  895. }
  896. std::vector<int> input_shape_2d{1000, 100};
  897. std::vector<int> input_shape_3d{100, 100, 100};
  898. };
  899. PERF_TEST_P_(Layer_TopK, TopK_2D_Axis0) {
  900. test_layer(input_shape_2d, input_shape_2d[0] / 2, 0);
  901. }
  902. PERF_TEST_P_(Layer_TopK, TopK_2D_Axis0_K5) {
  903. test_layer(input_shape_2d, 5, 0);
  904. }
  905. PERF_TEST_P_(Layer_TopK, TopK_2D_Axis1) {
  906. test_layer(input_shape_2d, input_shape_2d[1] / 2, 1);
  907. }
  908. PERF_TEST_P_(Layer_TopK, TopK_3D_Axis0) {
  909. test_layer(input_shape_3d, input_shape_3d[0] / 2, 0);
  910. }
  911. PERF_TEST_P_(Layer_TopK, TopK_3D_Axis1) {
  912. test_layer(input_shape_3d, input_shape_3d[1] / 2, 1);
  913. }
  914. PERF_TEST_P_(Layer_TopK, TopK_3D_Axis2) {
  915. test_layer(input_shape_3d, input_shape_3d[2] / 2, 2);
  916. }
  917. INSTANTIATE_TEST_CASE_P(/**/, Layer_TopK,
  918. dnnBackendsAndTargets(/* withInferenceEngine= */ false,
  919. /* withHalide= */ false,
  920. /* withCpuOCV= */ true,
  921. /* withVkCom= */ false,
  922. /* withCUDA= */ false,
  923. /* withNgraph= */ false,
  924. /* withWebnn= */ false,
  925. /* withCann= */ false));
  926. } // namespace