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.

convolution_arm.cpp 39 kB

7 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "convolution_arm.h"
  15. #include "benchmark.h"
  16. #include "layer_type.h"
  17. #if __ARM_NEON
  18. #include <arm_neon.h>
  19. #include "neon_mathfun.h"
  20. #endif // __ARM_NEON
  21. namespace ncnn {
  22. #include "convolution_1x1.h"
  23. #include "convolution_2x2.h"
  24. #include "convolution_3x3.h"
  25. #include "convolution_4x4.h"
  26. #include "convolution_5x5.h"
  27. #include "convolution_7x7.h"
  28. #include "convolution_sgemm.h"
  29. #include "convolution_sgemm_int8.h"
  30. #include "convolution_1x1_int8.h"
  31. #include "convolution_3x3_int8.h"
  32. #include "convolution_5x5_int8.h"
  33. #include "convolution_7x7_int8.h"
  34. DEFINE_LAYER_CREATOR(Convolution_arm)
  35. Convolution_arm::Convolution_arm()
  36. {
  37. activation = 0;
  38. }
  39. int Convolution_arm::create_pipeline(const Option& opt)
  40. {
  41. if (activation_type == 1)
  42. {
  43. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  44. ncnn::ParamDict pd;
  45. activation->load_param(pd);
  46. }
  47. else if (activation_type == 2)
  48. {
  49. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  50. ncnn::ParamDict pd;
  51. pd.set(0, activation_params[0]);// slope
  52. activation->load_param(pd);
  53. }
  54. else if (activation_type == 3)
  55. {
  56. activation = ncnn::create_layer(ncnn::LayerType::Clip);
  57. ncnn::ParamDict pd;
  58. pd.set(0, activation_params[0]);// min
  59. pd.set(1, activation_params[1]);// max
  60. activation->load_param(pd);
  61. }
  62. else if (activation_type == 4)
  63. {
  64. activation = ncnn::create_layer(ncnn::LayerType::Sigmoid);
  65. ncnn::ParamDict pd;
  66. activation->load_param(pd);
  67. }
  68. if (activation)
  69. {
  70. Option opt_cpu = opt;
  71. opt_cpu.use_vulkan_compute = false;
  72. activation->create_pipeline(opt_cpu);
  73. }
  74. const int maxk = kernel_w * kernel_h;
  75. int num_input = weight_data_size / maxk / num_output;
  76. if (opt.use_packing_layout)
  77. {
  78. // pack4
  79. if (num_input % 4 == 0 && num_output % 4 == 0)
  80. {
  81. // src = kw-kh-inch-outch
  82. // dst = 4b-4a-kw-kh-inch/4a-outch/4b
  83. {
  84. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  85. weight_data_pack4.create(maxk, num_input/4, num_output/4, (size_t)4*16, 16);
  86. for (int q=0; q+3<num_output; q+=4)
  87. {
  88. const Mat k0 = weight_data_r2.channel(q);
  89. const Mat k1 = weight_data_r2.channel(q+1);
  90. const Mat k2 = weight_data_r2.channel(q+2);
  91. const Mat k3 = weight_data_r2.channel(q+3);
  92. Mat g0 = weight_data_pack4.channel(q/4);
  93. for (int p=0; p+3<num_input; p+=4)
  94. {
  95. const float* k00 = k0.row(p);
  96. const float* k01 = k0.row(p+1);
  97. const float* k02 = k0.row(p+2);
  98. const float* k03 = k0.row(p+3);
  99. const float* k10 = k1.row(p);
  100. const float* k11 = k1.row(p+1);
  101. const float* k12 = k1.row(p+2);
  102. const float* k13 = k1.row(p+3);
  103. const float* k20 = k2.row(p);
  104. const float* k21 = k2.row(p+1);
  105. const float* k22 = k2.row(p+2);
  106. const float* k23 = k2.row(p+3);
  107. const float* k30 = k3.row(p);
  108. const float* k31 = k3.row(p+1);
  109. const float* k32 = k3.row(p+2);
  110. const float* k33 = k3.row(p+3);
  111. float* g00 = g0.row(p/4);
  112. for (int k=0; k<maxk; k++)
  113. {
  114. g00[0] = k00[k];
  115. g00[1] = k10[k];
  116. g00[2] = k20[k];
  117. g00[3] = k30[k];
  118. g00[4] = k01[k];
  119. g00[5] = k11[k];
  120. g00[6] = k21[k];
  121. g00[7] = k31[k];
  122. g00[8] = k02[k];
  123. g00[9] = k12[k];
  124. g00[10] = k22[k];
  125. g00[11] = k32[k];
  126. g00[12] = k03[k];
  127. g00[13] = k13[k];
  128. g00[14] = k23[k];
  129. g00[15] = k33[k];
  130. g00 += 16;
  131. }
  132. }
  133. }
  134. }
  135. }
  136. // pack1to4
  137. if (num_input % 4 != 0 && num_output % 4 == 0)
  138. {
  139. // src = kw-kh-inch-outch
  140. // dst = 4b-kw-kh-inch-outch/4b
  141. {
  142. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  143. weight_data_pack1to4.create(maxk, num_input, num_output/4, (size_t)4*4, 4);
  144. for (int q=0; q+3<num_output; q+=4)
  145. {
  146. const Mat k0 = weight_data_r2.channel(q);
  147. const Mat k1 = weight_data_r2.channel(q+1);
  148. const Mat k2 = weight_data_r2.channel(q+2);
  149. const Mat k3 = weight_data_r2.channel(q+3);
  150. Mat g0 = weight_data_pack1to4.channel(q/4);
  151. for (int p=0; p<num_input; p++)
  152. {
  153. const float* k00 = k0.row(p);
  154. const float* k10 = k1.row(p);
  155. const float* k20 = k2.row(p);
  156. const float* k30 = k3.row(p);
  157. float* g00 = g0.row(p);
  158. for (int k=0; k<maxk; k++)
  159. {
  160. g00[0] = k00[k];
  161. g00[1] = k10[k];
  162. g00[2] = k20[k];
  163. g00[3] = k30[k];
  164. g00 += 4;
  165. }
  166. }
  167. }
  168. }
  169. }
  170. // pack4to1
  171. if (num_input % 4 == 0 && num_output % 4 != 0)
  172. {
  173. // src = kw-kh-inch-outch
  174. // dst = 4a-kw-kh-inch/4a-outch
  175. {
  176. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  177. weight_data_pack4to1.create(maxk, num_input/4, num_output, (size_t)4*4, 4);
  178. for (int q=0; q<num_output; q++)
  179. {
  180. const Mat k0 = weight_data_r2.channel(q);
  181. Mat g0 = weight_data_pack4to1.channel(q);
  182. for (int p=0; p+3<num_input; p+=4)
  183. {
  184. const float* k00 = k0.row(p);
  185. const float* k01 = k0.row(p+1);
  186. const float* k02 = k0.row(p+2);
  187. const float* k03 = k0.row(p+3);
  188. float* g00 = g0.row(p/4);
  189. for (int k=0; k<maxk; k++)
  190. {
  191. g00[0] = k00[k];
  192. g00[1] = k01[k];
  193. g00[2] = k02[k];
  194. g00[3] = k03[k];
  195. g00 += 4;
  196. }
  197. }
  198. }
  199. }
  200. }
  201. } // opt.use_packing_layout
  202. use_winograd3x3 = false;
  203. use_sgemm1x1 = false;
  204. if (opt.use_winograd_convolution && kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  205. {
  206. // winograd is slow on small channel count
  207. if (num_input >= 16 && num_output >= 16)
  208. use_winograd3x3 = true;
  209. if (use_int8_inference)
  210. use_winograd3x3 = true;
  211. }
  212. // TODO assume more proper condition
  213. if (opt.use_sgemm_convolution && kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  214. {
  215. if (num_input >= 64 && num_output >= 64)
  216. use_sgemm1x1 = true;
  217. }
  218. if (use_int8_inference)
  219. {
  220. if (use_winograd3x3)
  221. {
  222. // conv3x3s1_winograd23_transform_kernel_int8_neon(weight_data, weight_3x3_winograd23_int8_data, num_input, num_output);
  223. conv3x3s1_winograd43_transform_kernel_int8_neon(weight_data, weight_3x3_winograd23_int8_data, num_input, num_output);
  224. }
  225. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  226. {
  227. conv3x3s2_transform_kernel_int8_neon(weight_data, weight_3x3s2_int8_data, num_input, num_output);
  228. }
  229. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  230. {
  231. conv1x1s1_sgemm_transform_kernel_int8_neon(weight_data, weight_1x1s1_sgemm_int8_data, num_input, num_output);
  232. use_sgemm1x1 = true;
  233. }
  234. else
  235. {
  236. conv_im2col_sgemm_transform_kernel_int8_neon(weight_data, weight_sgemm_int8_data, num_input, num_output, maxk);
  237. }
  238. return 0;
  239. }
  240. if (impl_type > 0)
  241. {
  242. switch(impl_type)
  243. {
  244. case 1:
  245. // winograd
  246. conv3x3s1_winograd64_transform_kernel_neon5(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  247. break;
  248. case 2:
  249. // pointwise
  250. conv1x1s1_sgemm_transform_kernel_neon(weight_data, weight_1x1_sgemm_data, num_input, num_output);
  251. break;
  252. case 3:
  253. // im2col
  254. conv_im2col_sgemm_transform_kernel_neon(weight_data, weight_sgemm_data, num_input, num_output, maxk);
  255. break;
  256. case 4:
  257. // direct
  258. break;
  259. case 5:
  260. // conv3x3s2
  261. conv3x3s2_transform_kernel_neon(weight_data, weight_3x3s2_data, num_input, num_output);
  262. break;
  263. default:
  264. return -1;
  265. }
  266. return 0;
  267. }
  268. if (use_winograd3x3)
  269. {
  270. // conv3x3s1_winograd64_transform_kernel_neon(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  271. conv3x3s1_winograd64_transform_kernel_neon5(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  272. }
  273. if (use_sgemm1x1)
  274. {
  275. conv1x1s1_sgemm_transform_kernel_neon(weight_data, weight_1x1_sgemm_data, num_input, num_output);
  276. }
  277. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  278. {
  279. conv3x3s2_transform_kernel_neon(weight_data, weight_3x3s2_data, num_input, num_output);
  280. }
  281. {
  282. conv_im2col_sgemm_transform_kernel_neon(weight_data, weight_sgemm_data, num_input, num_output, maxk);
  283. }
  284. return 0;
  285. }
  286. int Convolution_arm::destroy_pipeline(const Option& opt)
  287. {
  288. if (activation)
  289. {
  290. Option opt_cpu = opt;
  291. opt_cpu.use_vulkan_compute = false;
  292. activation->destroy_pipeline(opt_cpu);
  293. delete activation;
  294. activation = 0;
  295. }
  296. return 0;
  297. }
  298. int Convolution_arm::forwardDilation(const Mat& bottom_blob, Mat& top_blob, conv_func conv, const Option& opt) const
  299. {
  300. int w = bottom_blob.w;
  301. int h = bottom_blob.h;
  302. size_t elemsize = bottom_blob.elemsize;
  303. const int kernel_size = kernel_w;
  304. const int stride = stride_w;
  305. const int dilation = dilation_w;
  306. const int kernel_extent = dilation * (kernel_size - 1) + 1;
  307. Mat bottom_blob_bordered = bottom_blob;
  308. if (pad_w > 0 || pad_h > 0)
  309. {
  310. copy_make_border(bottom_blob, bottom_blob_bordered, pad_h, pad_h, pad_w, pad_w, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  311. if (bottom_blob_bordered.empty())
  312. return -100;
  313. w = bottom_blob_bordered.w;
  314. h = bottom_blob_bordered.h;
  315. }
  316. else if (pad_w == -233 && pad_h == -233)
  317. {
  318. int wpad = kernel_extent + (w - 1) / stride * stride - w;
  319. int hpad = kernel_extent + (h - 1) / stride * stride - h;
  320. if (wpad > 0 || hpad > 0)
  321. {
  322. copy_make_border(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  323. if (bottom_blob_bordered.empty())
  324. return -100;
  325. }
  326. w = bottom_blob_bordered.w;
  327. h = bottom_blob_bordered.h;
  328. }
  329. int outw = (w - kernel_extent) / stride + 1;
  330. int outh = (h - kernel_extent) / stride + 1;
  331. top_blob.create(outw, outh, num_output, elemsize, opt.blob_allocator);
  332. if (top_blob.empty())
  333. return -100;
  334. // Make (dilation * dilation) batches
  335. Mat inner_bottom_blob;
  336. Mat inner_top_blob;
  337. for (int x = 0; x < dilation; x ++)
  338. {
  339. for (int y = 0; y < dilation; y ++)
  340. {
  341. int inner_w = (w - y + dilation - 1) / dilation;
  342. int inner_h = (h - x + dilation - 1) / dilation;
  343. int inner_outw = (inner_w - kernel_size) / stride + 1;
  344. int inner_outh = (inner_h - kernel_size) / stride + 1;
  345. inner_bottom_blob.create(inner_w, inner_h, bottom_blob.c, elemsize, opt.workspace_allocator);
  346. if (inner_bottom_blob.empty())
  347. return -100;
  348. inner_top_blob.create(inner_outw, inner_outh, num_output, elemsize, opt.workspace_allocator);
  349. if (inner_top_blob.empty())
  350. return -100;
  351. #pragma omp parallel for num_threads(opt.num_threads)
  352. for (int c = 0; c < bottom_blob.c; c ++)
  353. {
  354. float *outptr = inner_bottom_blob.channel(c);
  355. for (int i = 0; i < inner_h; i ++)
  356. {
  357. const float *ptr = (const float *) bottom_blob_bordered.channel(c) + dilation * i * w + x * w + y;
  358. for (int j = 0; j < inner_w; j ++)
  359. {
  360. outptr[j] = ptr[j*dilation];
  361. }
  362. outptr += inner_w;
  363. }
  364. }
  365. ncnn::Option opt_g = opt;
  366. opt_g.blob_allocator = inner_top_blob.allocator;
  367. conv(inner_bottom_blob, inner_top_blob, weight_data, bias_data, opt_g);
  368. #pragma omp parallel for num_threads(opt.num_threads)
  369. for (int c = 0; c < num_output; c ++)
  370. {
  371. float *outptr = (float *) top_blob.channel(c) + x * outw + y;
  372. for (int i = 0; i < inner_outh; i ++)
  373. {
  374. const float *ptr = (const float *) inner_top_blob.channel(c) + i * inner_outw;
  375. for (int j = 0; j < inner_outw; j ++)
  376. {
  377. outptr[j*dilation] = ptr[j];
  378. }
  379. outptr += dilation * outw;
  380. }
  381. }
  382. }
  383. }
  384. return 0;
  385. }
  386. int Convolution_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  387. {
  388. // convolv with NxN kernel
  389. // value = value + bias
  390. if (opt.use_packing_layout)
  391. {
  392. int w = bottom_blob.w;
  393. int h = bottom_blob.h;
  394. int channels = bottom_blob.c;
  395. size_t elemsize = bottom_blob.elemsize;
  396. int elempack = bottom_blob.elempack;
  397. // fprintf(stderr, "Convolution input %d x %d pad = %d %d ksize=%d %d stride=%d %d\n", w, h, pad_w, pad_h, kernel_w, kernel_h, stride_w, stride_h);
  398. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  399. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  400. Mat bottom_blob_bordered = bottom_blob;
  401. if (pad_w > 0 || pad_h > 0)
  402. {
  403. copy_make_border(bottom_blob, bottom_blob_bordered, pad_h, pad_h, pad_w, pad_w, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  404. if (bottom_blob_bordered.empty())
  405. return -100;
  406. w = bottom_blob_bordered.w;
  407. h = bottom_blob_bordered.h;
  408. }
  409. else if (pad_w == -233 && pad_h == -233)
  410. {
  411. int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w;
  412. int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h;
  413. if (wpad > 0 || hpad > 0)
  414. {
  415. copy_make_border(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  416. if (bottom_blob_bordered.empty())
  417. return -100;
  418. }
  419. w = bottom_blob_bordered.w;
  420. h = bottom_blob_bordered.h;
  421. }
  422. int outw = (w - kernel_extent_w) / stride_w + 1;
  423. int outh = (h - kernel_extent_h) / stride_h + 1;
  424. int out_elempack = num_output % 4 == 0 ? 4 : 1;
  425. size_t out_elemsize = elemsize / elempack * out_elempack;
  426. const int maxk = kernel_w * kernel_h;
  427. // kernel offsets
  428. std::vector<int> _space_ofs(maxk);
  429. int* space_ofs = &_space_ofs[0];
  430. {
  431. int p1 = 0;
  432. int p2 = 0;
  433. int gap = w * dilation_h - kernel_w * dilation_w;
  434. for (int i = 0; i < kernel_h; i++)
  435. {
  436. for (int j = 0; j < kernel_w; j++)
  437. {
  438. space_ofs[p1] = p2;
  439. p1++;
  440. p2 += dilation_w;
  441. }
  442. p2 += gap;
  443. }
  444. }
  445. // float32
  446. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  447. if (top_blob.empty())
  448. return -100;
  449. if (elempack == 4 && out_elempack == 4)
  450. {
  451. // num_output
  452. #pragma omp parallel for num_threads(opt.num_threads)
  453. for (int p=0; p<num_output / out_elempack; p++)
  454. {
  455. float* outptr = top_blob.channel(p);
  456. for (int i = 0; i < outh; i++)
  457. {
  458. for (int j = 0; j < outw; j++)
  459. {
  460. float32x4_t _sum = vdupq_n_f32(0.f);
  461. if (bias_term)
  462. {
  463. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  464. }
  465. const float* kptr = (const float*)weight_data_pack4 + maxk * channels * p * 16;
  466. // channels
  467. for (int q=0; q<channels; q++)
  468. {
  469. const Mat m = bottom_blob_bordered.channel(q);
  470. const float* sptr = m.row(i*stride_h) + j*stride_w * 4;
  471. for (int k = 0; k < maxk; k++) // 29.23
  472. {
  473. float32x4_t _val = vld1q_f32( sptr + space_ofs[k] * 4 );
  474. float32x4_t _w0 = vld1q_f32( kptr );
  475. float32x4_t _w1 = vld1q_f32( kptr + 4 );
  476. float32x4_t _w2 = vld1q_f32( kptr + 8 );
  477. float32x4_t _w3 = vld1q_f32( kptr + 12 );
  478. #if __aarch64__
  479. _sum = vmlaq_laneq_f32(_sum, _w0, _val, 0);
  480. _sum = vmlaq_laneq_f32(_sum, _w1, _val, 1);
  481. _sum = vmlaq_laneq_f32(_sum, _w2, _val, 2);
  482. _sum = vmlaq_laneq_f32(_sum, _w3, _val, 3);
  483. #else
  484. _sum = vmlaq_lane_f32(_sum, _w0, vget_low_f32(_val), 0);
  485. _sum = vmlaq_lane_f32(_sum, _w1, vget_low_f32(_val), 1);
  486. _sum = vmlaq_lane_f32(_sum, _w2, vget_high_f32(_val), 0);
  487. _sum = vmlaq_lane_f32(_sum, _w3, vget_high_f32(_val), 1);
  488. #endif
  489. kptr += 16;
  490. }
  491. }
  492. if (activation_type == 1)
  493. {
  494. float32x4_t _zero = vdupq_n_f32(0.f);
  495. _sum = vmaxq_f32(_sum, _zero);
  496. }
  497. else if (activation_type == 2)
  498. {
  499. float32x4_t _zero = vdupq_n_f32(0.f);
  500. float32x4_t _slope = vdupq_n_f32(activation_params[0]);
  501. uint32x4_t _lemask = vcleq_f32(_sum, _zero);
  502. float32x4_t _ps = vmulq_f32(_sum, _slope);
  503. _sum = vbslq_f32(_lemask, _ps, _sum);
  504. }
  505. else if (activation_type == 3)
  506. {
  507. float32x4_t _min = vdupq_n_f32(activation_params[0]);
  508. float32x4_t _max = vdupq_n_f32(activation_params[1]);
  509. _sum = vmaxq_f32(_sum, _min);
  510. _sum = vminq_f32(_sum, _max);
  511. }
  512. else if (activation_type == 4)
  513. {
  514. float32x4_t _one = vdupq_n_f32(1.f);
  515. _sum = vnegq_f32(_sum);
  516. _sum = exp_ps(_sum);
  517. _sum = vaddq_f32(_sum, _one);
  518. float32x4_t _outp = vrecpeq_f32(_sum);
  519. _outp = vmulq_f32(vrecpsq_f32(_sum, _outp), _outp);
  520. // _outp = vmulq_f32(vrecpsq_f32(_sum, _outp), _outp);
  521. _sum = _outp;
  522. }
  523. vst1q_f32(outptr + j * 4, _sum);
  524. }
  525. outptr += outw * 4;
  526. }
  527. }
  528. return 0;
  529. }
  530. if (elempack == 1 && out_elempack == 4)
  531. {
  532. // num_output
  533. #pragma omp parallel for num_threads(opt.num_threads)
  534. for (int p=0; p<num_output / out_elempack; p++)
  535. {
  536. float* outptr = top_blob.channel(p);
  537. for (int i = 0; i < outh; i++)
  538. {
  539. for (int j = 0; j < outw; j++)
  540. {
  541. float32x4_t _sum = vdupq_n_f32(0.f);
  542. if (bias_term)
  543. {
  544. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  545. }
  546. const float* kptr = (const float*)weight_data_pack1to4 + maxk * channels * p * 4;
  547. // channels
  548. for (int q=0; q<channels; q++)
  549. {
  550. const Mat m = bottom_blob_bordered.channel(q);
  551. const float* sptr = m.row(i*stride_h) + j*stride_w;
  552. for (int k = 0; k < maxk; k++) // 29.23
  553. {
  554. float32x4_t _val = vdupq_n_f32( sptr[ space_ofs[k] ] );
  555. float32x4_t _w = vld1q_f32( kptr );
  556. _sum = vmlaq_f32(_sum, _val, _w);
  557. kptr += 4;
  558. }
  559. }
  560. if (activation_type == 1)
  561. {
  562. float32x4_t _zero = vdupq_n_f32(0.f);
  563. _sum = vmaxq_f32(_sum, _zero);
  564. }
  565. else if (activation_type == 2)
  566. {
  567. float32x4_t _zero = vdupq_n_f32(0.f);
  568. float32x4_t _slope = vdupq_n_f32(activation_params[0]);
  569. uint32x4_t _lemask = vcleq_f32(_sum, _zero);
  570. float32x4_t _ps = vmulq_f32(_sum, _slope);
  571. _sum = vbslq_f32(_lemask, _ps, _sum);
  572. }
  573. else if (activation_type == 3)
  574. {
  575. float32x4_t _min = vdupq_n_f32(activation_params[0]);
  576. float32x4_t _max = vdupq_n_f32(activation_params[1]);
  577. _sum = vmaxq_f32(_sum, _min);
  578. _sum = vminq_f32(_sum, _max);
  579. }
  580. else if (activation_type == 4)
  581. {
  582. float32x4_t _one = vdupq_n_f32(1.f);
  583. _sum = vnegq_f32(_sum);
  584. _sum = exp_ps(_sum);
  585. _sum = vaddq_f32(_sum, _one);
  586. float32x4_t _outp = vrecpeq_f32(_sum);
  587. _outp = vmulq_f32(vrecpsq_f32(_sum, _outp), _outp);
  588. // _outp = vmulq_f32(vrecpsq_f32(_sum, _outp), _outp);
  589. _sum = _outp;
  590. }
  591. vst1q_f32(outptr + j * 4, _sum);
  592. }
  593. outptr += outw * 4;
  594. }
  595. }
  596. return 0;
  597. }
  598. if (elempack == 4 && out_elempack == 1)
  599. {
  600. // num_output
  601. #pragma omp parallel for num_threads(opt.num_threads)
  602. for (int p=0; p<num_output; p++)
  603. {
  604. float* outptr = top_blob.channel(p);
  605. for (int i = 0; i < outh; i++)
  606. {
  607. for (int j = 0; j < outw; j++)
  608. {
  609. float sum = 0.f;
  610. if (bias_term)
  611. {
  612. sum = bias_data[p];
  613. }
  614. const float* kptr = (const float*)weight_data_pack4to1 + maxk * channels * p * 4;
  615. // channels
  616. for (int q=0; q<channels; q++)
  617. {
  618. const Mat m = bottom_blob_bordered.channel(q);
  619. const float* sptr = m.row(i*stride_h) + j*stride_w * 4;
  620. for (int k = 0; k < maxk; k++) // 29.23
  621. {
  622. float32x4_t _val = vld1q_f32( sptr + space_ofs[k] * 4 );
  623. float32x4_t _w = vld1q_f32( kptr );
  624. float32x4_t _s4 = vmulq_f32(_val, _w);
  625. #if __aarch64__
  626. sum += vaddvq_f32(_s4); // dot
  627. #else
  628. float32x2_t _ss = vadd_f32(vget_low_f32(_s4), vget_high_f32(_s4));
  629. _ss = vpadd_f32(_ss, _ss);
  630. sum += vget_lane_f32(_ss, 0);
  631. #endif
  632. kptr += 4;
  633. }
  634. }
  635. if (activation_type == 1)
  636. {
  637. sum = std::max(sum, 0.f);
  638. }
  639. else if (activation_type == 2)
  640. {
  641. float slope = activation_params[0];
  642. sum = sum > 0.f ? sum : sum * slope;
  643. }
  644. else if (activation_type == 3)
  645. {
  646. float min = activation_params[0];
  647. float max = activation_params[1];
  648. if (sum < min)
  649. sum = min;
  650. if (sum > max)
  651. sum = max;
  652. }
  653. else if (activation_type == 4)
  654. {
  655. sum = 1.f / (1.f + exp(-sum));
  656. }
  657. outptr[j] = sum;
  658. }
  659. outptr += outw;
  660. }
  661. }
  662. return 0;
  663. }
  664. } // opt.use_packed_layout
  665. if (bottom_blob.dims != 3)
  666. {
  667. return Convolution::forward(bottom_blob, top_blob, opt);
  668. }
  669. if (kernel_w != kernel_h || stride_w != stride_h)
  670. {
  671. return Convolution::forward(bottom_blob, top_blob, opt);
  672. }
  673. const int kernel_size = kernel_w;
  674. //const int stride = stride_w;
  675. int stride = stride_w;
  676. if (kernel_size > 7 || stride > 4 || dilation_w != dilation_h)
  677. {
  678. return Convolution::forward(bottom_blob, top_blob, opt);
  679. }
  680. typedef void (*conv_func)(const Mat&, Mat&, const Mat&, const Mat&, const Option&);
  681. // kernel_size x stride
  682. conv_func conv_func_table[7][4] =
  683. {
  684. {
  685. conv1x1s1_neon,
  686. conv1x1s2_neon,
  687. 0,
  688. 0
  689. }, // kernel_size = 1
  690. {
  691. conv2x2s1_neon,
  692. 0,
  693. 0,
  694. 0
  695. }, // kernel_size = 2
  696. {
  697. conv3x3s1_neon,
  698. conv3x3s2_neon,
  699. 0,
  700. 0
  701. }, // kernel_size = 3
  702. {
  703. 0,
  704. 0,
  705. 0,
  706. conv4x4s4_neon
  707. }, // kernel_size = 4
  708. {
  709. conv5x5s1_neon,
  710. conv5x5s2_neon,
  711. 0,
  712. 0
  713. }, // kernel_size = 5
  714. {
  715. 0,
  716. 0,
  717. 0,
  718. 0
  719. }, // kernel_size = 6
  720. {
  721. conv7x7s1_neon,
  722. conv7x7s2_neon,
  723. 0,
  724. 0
  725. } // kernel_size = 7
  726. };
  727. typedef void (*conv_int8_func)(const Mat&, Mat&, const Mat&, const Option&);
  728. // kernel_size x stride
  729. conv_int8_func conv_int8_func_table[7][4] =
  730. {
  731. {
  732. conv1x1s1_int8_neon,
  733. conv1x1s2_int8_neon,
  734. 0,
  735. 0
  736. }, // kernel_size = 1
  737. {
  738. 0,
  739. 0,
  740. 0,
  741. 0
  742. }, // kernel_size = 2
  743. {
  744. conv3x3s1_int8_neon,
  745. conv3x3s2_int8_neon,
  746. 0,
  747. 0
  748. }, // kernel_size = 3
  749. {
  750. 0,
  751. 0,
  752. 0,
  753. 0
  754. }, // kernel_size = 4
  755. {
  756. conv5x5s1_int8_neon,
  757. conv5x5s2_int8_neon,
  758. 0,
  759. 0
  760. }, // kernel_size = 5
  761. {
  762. 0,
  763. 0,
  764. 0,
  765. 0
  766. }, // kernel_size = 6
  767. {
  768. conv7x7s1_int8_neon,
  769. conv7x7s2_int8_neon,
  770. 0,
  771. 0
  772. } // kernel_size = 7
  773. };
  774. conv_func conv = 0;
  775. conv_int8_func conv_int8 = 0;
  776. if (use_int8_inference)
  777. {
  778. conv_int8 = conv_int8_func_table[kernel_size-1][stride-1];
  779. if (!conv_int8)
  780. {
  781. return Convolution::forward(bottom_blob, top_blob, opt);
  782. }
  783. }
  784. else
  785. {
  786. conv = conv_func_table[kernel_size-1][stride-1];
  787. if (!conv)
  788. {
  789. return Convolution::forward(bottom_blob, top_blob, opt);
  790. }
  791. if (dilation_w != 1)
  792. {
  793. if (stride != 1)
  794. return Convolution::forward(bottom_blob, top_blob, opt);
  795. return forwardDilation(bottom_blob, top_blob, conv, opt);
  796. }
  797. }
  798. int w = bottom_blob.w;
  799. int h = bottom_blob.h;
  800. int channels = bottom_blob.c;
  801. size_t elemsize = bottom_blob.elemsize;
  802. Mat bottom_blob_unbordered = bottom_blob;
  803. if (use_int8_inference && elemsize != 1)
  804. {
  805. Mat bottom_blob_int8;
  806. bottom_blob_int8.create(w, h, channels, (size_t)1u, opt.workspace_allocator);
  807. if (bottom_blob_int8.empty())
  808. return -100;
  809. // quantize, scale and round to nearest
  810. {
  811. ncnn::Option opt_g = opt;
  812. opt_g.blob_allocator = bottom_blob_int8.allocator;
  813. quantize->forward(bottom_blob, bottom_blob_int8, opt_g);
  814. }
  815. bottom_blob_unbordered = bottom_blob_int8;
  816. }
  817. Mat bottom_blob_bordered = bottom_blob_unbordered;
  818. if (pad_w > 0 || pad_h > 0)
  819. {
  820. copy_make_border(bottom_blob_unbordered, bottom_blob_bordered, pad_h, pad_h, pad_w, pad_w, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  821. if (bottom_blob_bordered.empty())
  822. return -100;
  823. w = bottom_blob_bordered.w;
  824. h = bottom_blob_bordered.h;
  825. }
  826. else if (pad_w == -233 && pad_h == -233)
  827. {
  828. int wpad = kernel_size + (w - 1) / stride * stride - w;
  829. int hpad = kernel_size + (h - 1) / stride * stride - h;
  830. if (wpad > 0 || hpad > 0)
  831. {
  832. copy_make_border(bottom_blob_unbordered, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, BORDER_CONSTANT, 0.f, opt.workspace_allocator, opt.num_threads);
  833. if (bottom_blob_bordered.empty())
  834. return -100;
  835. }
  836. w = bottom_blob_bordered.w;
  837. h = bottom_blob_bordered.h;
  838. }
  839. int outw = (w - kernel_size) / stride + 1;
  840. int outh = (h - kernel_size) / stride + 1;
  841. // int8
  842. if (use_int8_inference)
  843. {
  844. if (use_int8_requantize == true)
  845. {
  846. Mat top_blob_tm;
  847. top_blob_tm.create(outw, outh, num_output, (size_t)4u, opt.workspace_allocator);
  848. if (top_blob_tm.empty())
  849. return -100;
  850. top_blob.create(outw, outh, num_output, (size_t)1u, opt.blob_allocator);
  851. if (top_blob.empty())
  852. return -100;
  853. if (use_sgemm1x1)
  854. {
  855. conv1x1s1_sgemm_int8_requant_neon(bottom_blob_bordered, top_blob, weight_1x1s1_sgemm_int8_data, bias_data, requantize_scales, opt);
  856. if (activation)
  857. {
  858. activation->forward_inplace(top_blob, opt);
  859. }
  860. return 0;
  861. }
  862. else if (use_winograd3x3)
  863. {
  864. // conv3x3s1_winograd23_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3_winograd23_int8_data, opt);
  865. conv3x3s1_winograd43_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3_winograd23_int8_data, opt);
  866. }
  867. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  868. {
  869. conv3x3s2_packed_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3s2_int8_data, opt);
  870. }
  871. else
  872. {
  873. conv_int8(bottom_blob_bordered, top_blob_tm, weight_sgemm_int8_data, opt);
  874. }
  875. // requantize, reverse scale inplace
  876. #pragma omp parallel for num_threads(opt.num_threads)
  877. for (int p=0; p<num_output; p++)
  878. {
  879. ncnn::Option opt_g = opt;
  880. opt_g.num_threads = 1;
  881. opt_g.blob_allocator = top_blob.allocator;
  882. Mat top_blob_tm_g = top_blob_tm.channel_range(p, 1);
  883. Mat top_blob_g = top_blob.channel_range(p, 1);
  884. requantize_ops[p]->forward(top_blob_tm_g, top_blob_g, opt_g);
  885. }
  886. }
  887. else
  888. {
  889. top_blob.create(outw, outh, num_output, (size_t)4u, opt.blob_allocator);
  890. if (top_blob.empty())
  891. return -100;
  892. if (use_sgemm1x1)
  893. {
  894. conv1x1s1_sgemm_int8_neon(bottom_blob_bordered, top_blob, weight_1x1s1_sgemm_int8_data, opt);
  895. }
  896. else if (use_winograd3x3)
  897. {
  898. // conv3x3s1_winograd23_int8_neon(bottom_blob_bordered, top_blob, weight_3x3_winograd23_int8_data, opt);
  899. // conv3x3s1_winograd43_int8_neon(bottom_blob_bordered, top_blob, weight_3x3_winograd23_int8_data, opt);
  900. conv3x3s1_winograd43_dequant_int8_neon(bottom_blob_bordered, top_blob, weight_3x3_winograd23_int8_data, bias_data, dequantize_scales, opt);
  901. if (activation)
  902. {
  903. activation->forward_inplace(top_blob, opt);
  904. }
  905. return 0;
  906. }
  907. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  908. {
  909. conv3x3s2_packed_int8_neon(bottom_blob_bordered, top_blob, weight_3x3s2_int8_data, opt);
  910. }
  911. else
  912. {
  913. conv_int8(bottom_blob_bordered, top_blob, weight_sgemm_int8_data, opt);
  914. }
  915. // dequantize, reverse scale inplace
  916. #pragma omp parallel for num_threads(opt.num_threads)
  917. for (int p=0; p<num_output; p++)
  918. {
  919. ncnn::Option opt_g = opt;
  920. opt_g.num_threads = 1;
  921. opt_g.blob_allocator = top_blob.allocator;
  922. Mat top_blob_g = top_blob.channel_range(p, 1);
  923. dequantize_ops[p]->forward_inplace(top_blob_g, opt_g);
  924. }
  925. }
  926. if (activation)
  927. {
  928. activation->forward_inplace(top_blob, opt);
  929. }
  930. return 0;
  931. }
  932. // float32
  933. top_blob.create(outw, outh, num_output, elemsize, opt.blob_allocator);
  934. if (top_blob.empty())
  935. return -100;
  936. if (impl_type > 0)
  937. {
  938. // engineering is magic.
  939. switch(impl_type)
  940. {
  941. case 1:
  942. conv3x3s1_winograd64_neon5(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  943. break;
  944. case 2:
  945. conv1x1s1_sgemm_neon(bottom_blob_bordered, top_blob, weight_1x1_sgemm_data, bias_data, opt);
  946. break;
  947. case 3:
  948. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  949. break;
  950. case 4:
  951. conv(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  952. break;
  953. case 5:
  954. conv3x3s2_packed_neon(bottom_blob_bordered, top_blob, weight_3x3s2_data, bias_data, opt);
  955. break;
  956. default:
  957. return -1;
  958. }
  959. } else
  960. {
  961. if (use_winograd3x3 && w <= 120 && h <= 120)
  962. {
  963. // conv3x3s1_winograd64_neon4(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  964. conv3x3s1_winograd64_neon5(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  965. }
  966. else if (use_sgemm1x1)
  967. {
  968. conv1x1s1_sgemm_neon(bottom_blob_bordered, top_blob, weight_1x1_sgemm_data, bias_data, opt);
  969. }
  970. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  971. {
  972. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  973. }
  974. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  975. {
  976. if (outw >=8 && outh >=8)
  977. conv3x3s2_packed_neon(bottom_blob_bordered, top_blob, weight_3x3s2_data, bias_data, opt);
  978. else
  979. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  980. }
  981. else
  982. conv(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  983. }
  984. if (activation)
  985. {
  986. activation->forward_inplace(top_blob, opt);
  987. }
  988. return 0;
  989. }
  990. } // namespace ncnn