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 71 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932
  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 "cpu.h"
  17. #include "layer_type.h"
  18. #if __ARM_NEON
  19. #include <arm_neon.h>
  20. #include "neon_mathfun.h"
  21. #endif // __ARM_NEON
  22. #include "neon_activation.h"
  23. namespace ncnn {
  24. #include "convolution_sgemm.h"
  25. #include "convolution_sgemm_int8.h"
  26. #include "convolution_1x1.h"
  27. #include "convolution_1x1_bf16s.h"
  28. #include "convolution_1x1_int8.h"
  29. #include "convolution_2x2.h"
  30. #include "convolution_3x3.h"
  31. #include "convolution_3x3_int8.h"
  32. #include "convolution_4x4.h"
  33. #include "convolution_5x5.h"
  34. #include "convolution_7x7.h"
  35. #if __ARM_NEON
  36. #include "convolution_1x1_pack4.h"
  37. #include "convolution_1x1_pack4_bf16s.h"
  38. #include "convolution_1x1_pack4to1.h"
  39. #include "convolution_1x1_pack4to1_bf16s.h"
  40. #include "convolution_3x3_pack1to4.h"
  41. #include "convolution_3x3_pack1to4_bf16s.h"
  42. #include "convolution_3x3_pack4.h"
  43. #include "convolution_3x3_pack4_bf16s.h"
  44. #include "convolution_3x3_pack4to1.h"
  45. #include "convolution_3x3_pack4to1_bf16s.h"
  46. #include "convolution_5x5_pack4.h"
  47. #include "convolution_5x5_pack4_bf16s.h"
  48. #include "convolution_7x7_pack1to4.h"
  49. #include "convolution_7x7_pack1to4_bf16s.h"
  50. #endif // __ARM_NEON
  51. DEFINE_LAYER_CREATOR(Convolution_arm)
  52. Convolution_arm::Convolution_arm()
  53. {
  54. #if __ARM_NEON
  55. support_packing = true;
  56. #endif // __ARM_NEON
  57. support_bf16_storage = true;
  58. activation = 0;
  59. convolution_dilation1 = 0;
  60. }
  61. int Convolution_arm::create_pipeline(const Option& opt)
  62. {
  63. if (activation_type == 1)
  64. {
  65. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  66. ncnn::ParamDict pd;
  67. activation->load_param(pd);
  68. }
  69. else if (activation_type == 2)
  70. {
  71. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  72. ncnn::ParamDict pd;
  73. pd.set(0, activation_params[0]); // slope
  74. activation->load_param(pd);
  75. }
  76. else if (activation_type == 3)
  77. {
  78. activation = ncnn::create_layer(ncnn::LayerType::Clip);
  79. ncnn::ParamDict pd;
  80. pd.set(0, activation_params[0]); // min
  81. pd.set(1, activation_params[1]); // max
  82. activation->load_param(pd);
  83. }
  84. else if (activation_type == 4)
  85. {
  86. activation = ncnn::create_layer(ncnn::LayerType::Sigmoid);
  87. ncnn::ParamDict pd;
  88. activation->load_param(pd);
  89. }
  90. else if (activation_type == 5)
  91. {
  92. activation = ncnn::create_layer(ncnn::LayerType::Mish);
  93. ncnn::ParamDict pd;
  94. activation->load_param(pd);
  95. }
  96. if (activation)
  97. {
  98. activation->create_pipeline(opt);
  99. }
  100. if (opt.use_bf16_storage)
  101. {
  102. return create_pipeline_bf16s(opt);
  103. }
  104. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  105. {
  106. support_packing = false;
  107. return create_pipeline_int8_arm(opt);
  108. }
  109. if ((!support_packing || !opt.use_packing_layout) && kernel_w == kernel_h && dilation_w != 1 && dilation_h == dilation_w && stride_w == 1 && stride_h == 1)
  110. {
  111. convolution_dilation1 = ncnn::create_layer(ncnn::LayerType::Convolution);
  112. // set param
  113. ncnn::ParamDict pd;
  114. pd.set(0, num_output); // num_output
  115. pd.set(1, kernel_w);
  116. pd.set(11, kernel_h);
  117. pd.set(2, 1);
  118. pd.set(12, 1);
  119. pd.set(3, 1); // stride_w
  120. pd.set(13, 1); // stride_h
  121. pd.set(4, 0); // pad_w
  122. pd.set(14, 0); // pad_h
  123. pd.set(5, bias_term);
  124. pd.set(6, weight_data_size);
  125. convolution_dilation1->load_param(pd);
  126. // set weights
  127. if (bias_term)
  128. {
  129. ncnn::Mat weights[2];
  130. weights[0] = weight_data;
  131. weights[1] = bias_data;
  132. convolution_dilation1->load_model(ModelBinFromMatArray(weights));
  133. }
  134. else
  135. {
  136. ncnn::Mat weights[1];
  137. weights[0] = weight_data;
  138. convolution_dilation1->load_model(ModelBinFromMatArray(weights));
  139. }
  140. convolution_dilation1->create_pipeline(opt);
  141. return 0;
  142. }
  143. const int maxk = kernel_w * kernel_h;
  144. const int num_input = weight_data_size / maxk / num_output;
  145. int elempack = (support_packing && opt.use_packing_layout && num_input % 4 == 0) ? 4 : 1;
  146. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  147. #if __ARM_NEON
  148. // pack4
  149. if (elempack == 4 && out_elempack == 4)
  150. {
  151. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  152. {
  153. conv1x1s1_sgemm_transform_kernel_pack4_neon(weight_data, weight_data_pack4, num_input, num_output);
  154. }
  155. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  156. {
  157. conv1x1s1_sgemm_transform_kernel_pack4_neon(weight_data, weight_data_pack4, num_input, num_output);
  158. }
  159. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  160. {
  161. conv3x3s1_winograd64_transform_kernel_pack4_neon(weight_data, weight_data_pack4, num_input, num_output);
  162. }
  163. else
  164. {
  165. // src = kw-kh-inch-outch
  166. // dst = 4b-4a-kw-kh-inch/4a-outch/4b
  167. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  168. weight_data_pack4.create(maxk, num_input / 4, num_output / 4, (size_t)4 * 16, 16);
  169. for (int q = 0; q + 3 < num_output; q += 4)
  170. {
  171. const Mat k0 = weight_data_r2.channel(q);
  172. const Mat k1 = weight_data_r2.channel(q + 1);
  173. const Mat k2 = weight_data_r2.channel(q + 2);
  174. const Mat k3 = weight_data_r2.channel(q + 3);
  175. Mat g0 = weight_data_pack4.channel(q / 4);
  176. for (int p = 0; p + 3 < num_input; p += 4)
  177. {
  178. const float* k00 = k0.row(p);
  179. const float* k01 = k0.row(p + 1);
  180. const float* k02 = k0.row(p + 2);
  181. const float* k03 = k0.row(p + 3);
  182. const float* k10 = k1.row(p);
  183. const float* k11 = k1.row(p + 1);
  184. const float* k12 = k1.row(p + 2);
  185. const float* k13 = k1.row(p + 3);
  186. const float* k20 = k2.row(p);
  187. const float* k21 = k2.row(p + 1);
  188. const float* k22 = k2.row(p + 2);
  189. const float* k23 = k2.row(p + 3);
  190. const float* k30 = k3.row(p);
  191. const float* k31 = k3.row(p + 1);
  192. const float* k32 = k3.row(p + 2);
  193. const float* k33 = k3.row(p + 3);
  194. float* g00 = g0.row(p / 4);
  195. for (int k = 0; k < maxk; k++)
  196. {
  197. g00[0] = k00[k];
  198. g00[1] = k10[k];
  199. g00[2] = k20[k];
  200. g00[3] = k30[k];
  201. g00[4] = k01[k];
  202. g00[5] = k11[k];
  203. g00[6] = k21[k];
  204. g00[7] = k31[k];
  205. g00[8] = k02[k];
  206. g00[9] = k12[k];
  207. g00[10] = k22[k];
  208. g00[11] = k32[k];
  209. g00[12] = k03[k];
  210. g00[13] = k13[k];
  211. g00[14] = k23[k];
  212. g00[15] = k33[k];
  213. g00 += 16;
  214. }
  215. }
  216. }
  217. }
  218. }
  219. // pack1to4
  220. if (elempack == 1 && out_elempack == 4)
  221. {
  222. // src = kw-kh-inch-outch
  223. // dst = 4b-kw-kh-inch-outch/4b
  224. {
  225. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  226. weight_data_pack1to4.create(maxk, num_input, num_output / 4, (size_t)4 * 4, 4);
  227. for (int q = 0; q + 3 < num_output; q += 4)
  228. {
  229. const Mat k0 = weight_data_r2.channel(q);
  230. const Mat k1 = weight_data_r2.channel(q + 1);
  231. const Mat k2 = weight_data_r2.channel(q + 2);
  232. const Mat k3 = weight_data_r2.channel(q + 3);
  233. Mat g0 = weight_data_pack1to4.channel(q / 4);
  234. for (int p = 0; p < num_input; p++)
  235. {
  236. const float* k00 = k0.row(p);
  237. const float* k10 = k1.row(p);
  238. const float* k20 = k2.row(p);
  239. const float* k30 = k3.row(p);
  240. float* g00 = g0.row(p);
  241. for (int k = 0; k < maxk; k++)
  242. {
  243. g00[0] = k00[k];
  244. g00[1] = k10[k];
  245. g00[2] = k20[k];
  246. g00[3] = k30[k];
  247. g00 += 4;
  248. }
  249. }
  250. }
  251. }
  252. }
  253. // pack4to1
  254. if (elempack == 4 && out_elempack == 1)
  255. {
  256. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  257. {
  258. conv1x1s1_sgemm_transform_kernel_pack4to1_neon(weight_data, weight_data_pack4to1, num_input, num_output);
  259. }
  260. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  261. {
  262. conv1x1s1_sgemm_transform_kernel_pack4to1_neon(weight_data, weight_data_pack4to1, num_input, num_output);
  263. }
  264. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  265. {
  266. conv3x3s1_winograd64_transform_kernel_pack4to1_neon(weight_data, weight_data_pack4to1, num_input, num_output);
  267. }
  268. else
  269. {
  270. // src = kw-kh-inch-outch
  271. // dst = 4a-kw-kh-inch/4a-outch
  272. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  273. weight_data_pack4to1.create(maxk, num_input / 4, num_output, (size_t)4 * 4, 4);
  274. for (int q = 0; q < num_output; q++)
  275. {
  276. const Mat k0 = weight_data_r2.channel(q);
  277. Mat g0 = weight_data_pack4to1.channel(q);
  278. for (int p = 0; p + 3 < num_input; p += 4)
  279. {
  280. const float* k00 = k0.row(p);
  281. const float* k01 = k0.row(p + 1);
  282. const float* k02 = k0.row(p + 2);
  283. const float* k03 = k0.row(p + 3);
  284. float* g00 = g0.row(p / 4);
  285. for (int k = 0; k < maxk; k++)
  286. {
  287. g00[0] = k00[k];
  288. g00[1] = k01[k];
  289. g00[2] = k02[k];
  290. g00[3] = k03[k];
  291. g00 += 4;
  292. }
  293. }
  294. }
  295. }
  296. }
  297. #endif // __ARM_NEON
  298. // pack1
  299. if (elempack == 1 && out_elempack == 1)
  300. {
  301. use_winograd3x3 = false;
  302. use_sgemm1x1 = false;
  303. if (opt.use_winograd_convolution && kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  304. {
  305. // winograd is slow on small channel count
  306. if (num_input >= 16 && num_output >= 16)
  307. use_winograd3x3 = true;
  308. if (use_winograd3x3)
  309. {
  310. // conv3x3s1_winograd64_transform_kernel_neon(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  311. conv3x3s1_winograd64_transform_kernel_neon5(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  312. }
  313. }
  314. // TODO assume more proper condition
  315. if (opt.use_sgemm_convolution && kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  316. {
  317. if (num_input >= 64 && num_output >= 64)
  318. use_sgemm1x1 = true;
  319. if (use_sgemm1x1)
  320. {
  321. conv1x1s1_sgemm_transform_kernel_neon(weight_data, weight_1x1_sgemm_data, num_input, num_output);
  322. }
  323. }
  324. if (impl_type > 0 && impl_type < 6 && impl_type != 4)
  325. {
  326. switch (impl_type)
  327. {
  328. case 1:
  329. // winograd
  330. conv3x3s1_winograd64_transform_kernel_neon5(weight_data, weight_3x3_winograd64_data, num_input, num_output);
  331. break;
  332. case 2:
  333. // pointwise
  334. conv1x1s1_sgemm_transform_kernel_neon(weight_data, weight_1x1_sgemm_data, num_input, num_output);
  335. break;
  336. case 3:
  337. // im2col
  338. conv_im2col_sgemm_transform_kernel_neon(weight_data, weight_sgemm_data, num_input, num_output, maxk);
  339. break;
  340. // case 4:
  341. // // direct
  342. // break;
  343. case 5:
  344. // conv3x3s2
  345. conv3x3s2_transform_kernel_neon(weight_data, weight_3x3s2_data, num_input, num_output);
  346. break;
  347. }
  348. }
  349. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  350. {
  351. conv3x3s2_transform_kernel_neon(weight_data, weight_3x3s2_data, num_input, num_output);
  352. }
  353. if (opt.use_sgemm_convolution && kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  354. {
  355. conv_im2col_sgemm_transform_kernel_neon(weight_data, weight_sgemm_data, num_input, num_output, maxk);
  356. }
  357. if (opt.use_sgemm_convolution && kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  358. {
  359. conv_im2col_sgemm_transform_kernel_neon(weight_data, weight_sgemm_data, num_input, num_output, maxk);
  360. }
  361. }
  362. return 0;
  363. }
  364. int Convolution_arm::destroy_pipeline(const Option& opt)
  365. {
  366. if (activation)
  367. {
  368. activation->destroy_pipeline(opt);
  369. delete activation;
  370. activation = 0;
  371. }
  372. if (convolution_dilation1)
  373. {
  374. convolution_dilation1->destroy_pipeline(opt);
  375. delete convolution_dilation1;
  376. convolution_dilation1 = 0;
  377. }
  378. return 0;
  379. }
  380. int Convolution_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  381. {
  382. if (bottom_blob.dims != 3)
  383. {
  384. return Convolution::forward(bottom_blob, top_blob, opt);
  385. }
  386. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  387. {
  388. return forward_int8_arm(bottom_blob, top_blob, opt);
  389. }
  390. if (opt.use_bf16_storage)
  391. return forward_bf16s(bottom_blob, top_blob, opt);
  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. // NCNN_LOGE("Convolution input %d x %d pad = %d %d ksize=%d %d stride=%d %d", 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;
  401. make_padding(bottom_blob, bottom_blob_bordered, opt);
  402. if (bottom_blob_bordered.empty())
  403. return -100;
  404. w = bottom_blob_bordered.w;
  405. h = bottom_blob_bordered.h;
  406. int outw = (w - kernel_extent_w) / stride_w + 1;
  407. int outh = (h - kernel_extent_h) / stride_h + 1;
  408. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  409. size_t out_elemsize = elemsize / elempack * out_elempack;
  410. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  411. if (top_blob.empty())
  412. return -100;
  413. if ((!support_packing || !opt.use_packing_layout) && kernel_w == kernel_h && dilation_w != 1 && dilation_h == dilation_w && stride_w == 1 && stride_h == 1)
  414. {
  415. if (outw >= dilation_w && outh >= dilation_h)
  416. {
  417. return forwardDilation_arm(bottom_blob_bordered, top_blob, opt);
  418. }
  419. }
  420. const int maxk = kernel_w * kernel_h;
  421. // kernel offsets
  422. std::vector<int> _space_ofs(maxk);
  423. int* space_ofs = &_space_ofs[0];
  424. {
  425. int p1 = 0;
  426. int p2 = 0;
  427. int gap = w * dilation_h - kernel_w * dilation_w;
  428. for (int i = 0; i < kernel_h; i++)
  429. {
  430. for (int j = 0; j < kernel_w; j++)
  431. {
  432. space_ofs[p1] = p2;
  433. p1++;
  434. p2 += dilation_w;
  435. }
  436. p2 += gap;
  437. }
  438. }
  439. #if __ARM_NEON
  440. if (elempack == 4 && out_elempack == 4)
  441. {
  442. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  443. {
  444. conv1x1s1_sgemm_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  445. if (activation)
  446. {
  447. activation->forward_inplace(top_blob, opt);
  448. }
  449. }
  450. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  451. {
  452. conv1x1s2_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  453. if (activation)
  454. {
  455. activation->forward_inplace(top_blob, opt);
  456. }
  457. }
  458. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  459. {
  460. conv3x3s1_winograd64_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  461. if (activation)
  462. {
  463. activation->forward_inplace(top_blob, opt);
  464. }
  465. }
  466. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  467. {
  468. conv3x3s2_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  469. if (activation)
  470. {
  471. activation->forward_inplace(top_blob, opt);
  472. }
  473. }
  474. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  475. {
  476. conv5x5s1_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  477. if (activation)
  478. {
  479. activation->forward_inplace(top_blob, opt);
  480. }
  481. }
  482. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  483. {
  484. conv5x5s2_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  485. if (activation)
  486. {
  487. activation->forward_inplace(top_blob, opt);
  488. }
  489. }
  490. else
  491. {
  492. // num_output
  493. #pragma omp parallel for num_threads(opt.num_threads)
  494. for (int p = 0; p < num_output / out_elempack; p++)
  495. {
  496. float* outptr = top_blob.channel(p);
  497. for (int i = 0; i < outh; i++)
  498. {
  499. for (int j = 0; j < outw; j++)
  500. {
  501. float32x4_t _sum = vdupq_n_f32(0.f);
  502. if (bias_term)
  503. {
  504. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  505. }
  506. const float* kptr = (const float*)weight_data_pack4 + maxk * channels * p * 16;
  507. // channels
  508. for (int q = 0; q < channels; q++)
  509. {
  510. const Mat m = bottom_blob_bordered.channel(q);
  511. const float* sptr = m.row(i * stride_h) + j * stride_w * 4;
  512. for (int k = 0; k < maxk; k++) // 29.23
  513. {
  514. float32x4_t _val = vld1q_f32(sptr + space_ofs[k] * 4);
  515. float32x4_t _w0 = vld1q_f32(kptr);
  516. float32x4_t _w1 = vld1q_f32(kptr + 4);
  517. float32x4_t _w2 = vld1q_f32(kptr + 8);
  518. float32x4_t _w3 = vld1q_f32(kptr + 12);
  519. #if __aarch64__
  520. _sum = vmlaq_laneq_f32(_sum, _w0, _val, 0);
  521. _sum = vmlaq_laneq_f32(_sum, _w1, _val, 1);
  522. _sum = vmlaq_laneq_f32(_sum, _w2, _val, 2);
  523. _sum = vmlaq_laneq_f32(_sum, _w3, _val, 3);
  524. #else
  525. _sum = vmlaq_lane_f32(_sum, _w0, vget_low_f32(_val), 0);
  526. _sum = vmlaq_lane_f32(_sum, _w1, vget_low_f32(_val), 1);
  527. _sum = vmlaq_lane_f32(_sum, _w2, vget_high_f32(_val), 0);
  528. _sum = vmlaq_lane_f32(_sum, _w3, vget_high_f32(_val), 1);
  529. #endif
  530. kptr += 16;
  531. }
  532. }
  533. _sum = activation_ps(_sum, activation_type, activation_params);
  534. vst1q_f32(outptr + j * 4, _sum);
  535. }
  536. outptr += outw * 4;
  537. }
  538. }
  539. }
  540. }
  541. if (elempack == 1 && out_elempack == 4)
  542. {
  543. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  544. {
  545. conv3x3s1_pack1to4_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4, bias_data, opt);
  546. if (activation)
  547. {
  548. activation->forward_inplace(top_blob, opt);
  549. }
  550. }
  551. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  552. {
  553. conv3x3s2_pack1to4_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4, bias_data, opt);
  554. if (activation)
  555. {
  556. activation->forward_inplace(top_blob, opt);
  557. }
  558. }
  559. else if (kernel_w == 7 && kernel_h == 7 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  560. {
  561. conv7x7s2_pack1to4_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4, bias_data, opt);
  562. if (activation)
  563. {
  564. activation->forward_inplace(top_blob, opt);
  565. }
  566. }
  567. else
  568. {
  569. // num_output
  570. #pragma omp parallel for num_threads(opt.num_threads)
  571. for (int p = 0; p < num_output / out_elempack; p++)
  572. {
  573. float* outptr = top_blob.channel(p);
  574. for (int i = 0; i < outh; i++)
  575. {
  576. for (int j = 0; j < outw; j++)
  577. {
  578. float32x4_t _sum = vdupq_n_f32(0.f);
  579. if (bias_term)
  580. {
  581. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  582. }
  583. const float* kptr = (const float*)weight_data_pack1to4 + maxk * channels * p * 4;
  584. // channels
  585. for (int q = 0; q < channels; q++)
  586. {
  587. const Mat m = bottom_blob_bordered.channel(q);
  588. const float* sptr = m.row(i * stride_h) + j * stride_w;
  589. for (int k = 0; k < maxk; k++) // 29.23
  590. {
  591. float32x4_t _val = vdupq_n_f32(sptr[space_ofs[k]]);
  592. float32x4_t _w = vld1q_f32(kptr);
  593. _sum = vmlaq_f32(_sum, _val, _w);
  594. kptr += 4;
  595. }
  596. }
  597. _sum = activation_ps(_sum, activation_type, activation_params);
  598. vst1q_f32(outptr + j * 4, _sum);
  599. }
  600. outptr += outw * 4;
  601. }
  602. }
  603. }
  604. }
  605. if (elempack == 4 && out_elempack == 1)
  606. {
  607. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  608. {
  609. conv1x1s1_sgemm_pack4to1_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1, bias_data, opt);
  610. if (activation)
  611. {
  612. activation->forward_inplace(top_blob, opt);
  613. }
  614. }
  615. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  616. {
  617. conv1x1s2_pack4to1_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1, bias_data, opt);
  618. if (activation)
  619. {
  620. activation->forward_inplace(top_blob, opt);
  621. }
  622. }
  623. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  624. {
  625. // TODO more proper condition
  626. conv3x3s1_winograd64_pack4to1_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1, bias_data, opt);
  627. // conv3x3s1_pack4to1_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1, bias_data, opt);
  628. if (activation)
  629. {
  630. activation->forward_inplace(top_blob, opt);
  631. }
  632. }
  633. else
  634. {
  635. // num_output
  636. #pragma omp parallel for num_threads(opt.num_threads)
  637. for (int p = 0; p < num_output; p++)
  638. {
  639. float* outptr = top_blob.channel(p);
  640. for (int i = 0; i < outh; i++)
  641. {
  642. for (int j = 0; j < outw; j++)
  643. {
  644. float sum = 0.f;
  645. if (bias_term)
  646. {
  647. sum = bias_data[p];
  648. }
  649. const float* kptr = (const float*)weight_data_pack4to1 + maxk * channels * p * 4;
  650. // channels
  651. for (int q = 0; q < channels; q++)
  652. {
  653. const Mat m = bottom_blob_bordered.channel(q);
  654. const float* sptr = m.row(i * stride_h) + j * stride_w * 4;
  655. for (int k = 0; k < maxk; k++) // 29.23
  656. {
  657. float32x4_t _val = vld1q_f32(sptr + space_ofs[k] * 4);
  658. float32x4_t _w = vld1q_f32(kptr);
  659. float32x4_t _s4 = vmulq_f32(_val, _w);
  660. #if __aarch64__
  661. sum += vaddvq_f32(_s4); // dot
  662. #else
  663. float32x2_t _ss = vadd_f32(vget_low_f32(_s4), vget_high_f32(_s4));
  664. _ss = vpadd_f32(_ss, _ss);
  665. sum += vget_lane_f32(_ss, 0);
  666. #endif
  667. kptr += 4;
  668. }
  669. }
  670. sum = activation_ss(sum, activation_type, activation_params);
  671. outptr[j] = sum;
  672. }
  673. outptr += outw;
  674. }
  675. }
  676. }
  677. }
  678. #endif // __ARM_NEON
  679. if (elempack == 1 && out_elempack == 1)
  680. {
  681. if (impl_type > 0 && impl_type < 6 && impl_type != 4)
  682. {
  683. // engineering is magic.
  684. switch (impl_type)
  685. {
  686. case 1:
  687. conv3x3s1_winograd64_neon5(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  688. break;
  689. case 2:
  690. conv1x1s1_sgemm_neon(bottom_blob_bordered, top_blob, weight_1x1_sgemm_data, bias_data, opt);
  691. break;
  692. case 3:
  693. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  694. break;
  695. // case 4: FIXME fallback to auto path
  696. // conv(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  697. // break;
  698. case 5:
  699. conv3x3s2_packed_neon(bottom_blob_bordered, top_blob, weight_3x3s2_data, bias_data, opt);
  700. break;
  701. }
  702. if (activation)
  703. {
  704. activation->forward_inplace(top_blob, opt);
  705. }
  706. }
  707. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  708. {
  709. if (use_sgemm1x1)
  710. {
  711. conv1x1s1_sgemm_neon(bottom_blob_bordered, top_blob, weight_1x1_sgemm_data, bias_data, opt);
  712. }
  713. else
  714. {
  715. conv1x1s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  716. }
  717. if (activation)
  718. {
  719. activation->forward_inplace(top_blob, opt);
  720. }
  721. }
  722. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  723. {
  724. if (opt.use_sgemm_convolution)
  725. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  726. else
  727. conv1x1s2_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  728. if (activation)
  729. {
  730. activation->forward_inplace(top_blob, opt);
  731. }
  732. }
  733. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  734. {
  735. if (use_winograd3x3 && w <= 120 && h <= 120)
  736. {
  737. // conv3x3s1_winograd64_neon4(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  738. conv3x3s1_winograd64_neon5(bottom_blob_bordered, top_blob, weight_3x3_winograd64_data, bias_data, opt);
  739. }
  740. else
  741. {
  742. conv3x3s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  743. }
  744. if (activation)
  745. {
  746. activation->forward_inplace(top_blob, opt);
  747. }
  748. }
  749. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  750. {
  751. if (opt.use_sgemm_convolution && !(outw >= 8 && outh >= 8))
  752. conv_im2col_sgemm_neon(bottom_blob_bordered, top_blob, weight_sgemm_data, bias_data, kernel_w, kernel_h, stride_w, stride_h, opt);
  753. else
  754. conv3x3s2_packed_neon(bottom_blob_bordered, top_blob, weight_3x3s2_data, bias_data, opt);
  755. if (activation)
  756. {
  757. activation->forward_inplace(top_blob, opt);
  758. }
  759. }
  760. else if (kernel_w == 4 && kernel_h == 4 && dilation_w == 1 && dilation_h == 1 && stride_w == 4 && stride_h == 4)
  761. {
  762. conv4x4s4_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  763. if (activation)
  764. {
  765. activation->forward_inplace(top_blob, opt);
  766. }
  767. }
  768. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  769. {
  770. conv5x5s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  771. if (activation)
  772. {
  773. activation->forward_inplace(top_blob, opt);
  774. }
  775. }
  776. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  777. {
  778. conv5x5s2_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  779. if (activation)
  780. {
  781. activation->forward_inplace(top_blob, opt);
  782. }
  783. }
  784. else if (kernel_w == 7 && kernel_h == 7 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  785. {
  786. conv7x7s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  787. if (activation)
  788. {
  789. activation->forward_inplace(top_blob, opt);
  790. }
  791. }
  792. else if (kernel_w == 7 && kernel_h == 7 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  793. {
  794. conv7x7s2_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  795. if (activation)
  796. {
  797. activation->forward_inplace(top_blob, opt);
  798. }
  799. }
  800. else
  801. {
  802. // num_output
  803. #pragma omp parallel for num_threads(opt.num_threads)
  804. for (int p = 0; p < num_output; p++)
  805. {
  806. float* outptr = top_blob.channel(p);
  807. for (int i = 0; i < outh; i++)
  808. {
  809. for (int j = 0; j < outw; j++)
  810. {
  811. float sum = 0.f;
  812. if (bias_term)
  813. {
  814. sum = bias_data[p];
  815. }
  816. const float* kptr = (const float*)weight_data + maxk * channels * p;
  817. // channels
  818. for (int q = 0; q < channels; q++)
  819. {
  820. const Mat m = bottom_blob_bordered.channel(q);
  821. const float* sptr = m.row(i * stride_h) + j * stride_w;
  822. for (int k = 0; k < maxk; k++)
  823. {
  824. float val = sptr[space_ofs[k]];
  825. float w = kptr[k];
  826. sum += val * w;
  827. }
  828. kptr += maxk;
  829. }
  830. if (activation_type == 1)
  831. {
  832. sum = std::max(sum, 0.f);
  833. }
  834. else if (activation_type == 2)
  835. {
  836. float slope = activation_params[0];
  837. sum = sum > 0.f ? sum : sum * slope;
  838. }
  839. else if (activation_type == 3)
  840. {
  841. float min = activation_params[0];
  842. float max = activation_params[1];
  843. if (sum < min)
  844. sum = min;
  845. if (sum > max)
  846. sum = max;
  847. }
  848. else if (activation_type == 4)
  849. {
  850. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  851. }
  852. else if (activation_type == 5)
  853. {
  854. sum = static_cast<float>(sum * tanh(log(exp(sum) + 1.f)));
  855. }
  856. outptr[j] = sum;
  857. }
  858. outptr += outw;
  859. }
  860. }
  861. }
  862. }
  863. return 0;
  864. }
  865. int Convolution_arm::create_pipeline_bf16s(const Option& opt)
  866. {
  867. const int maxk = kernel_w * kernel_h;
  868. const int num_input = weight_data_size / maxk / num_output;
  869. int elempack = (support_packing && opt.use_packing_layout && num_input % 4 == 0) ? 4 : 1;
  870. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  871. #if __ARM_NEON
  872. // pack4
  873. if (elempack == 4 && out_elempack == 4)
  874. {
  875. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  876. {
  877. conv1x1s1_sgemm_transform_kernel_pack4_bf16s_neon(weight_data, weight_data_pack4_bf16, num_input, num_output);
  878. }
  879. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  880. {
  881. conv1x1s1_sgemm_transform_kernel_pack4_bf16s_neon(weight_data, weight_data_pack4_bf16, num_input, num_output);
  882. }
  883. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  884. {
  885. conv3x3s1_winograd64_transform_kernel_pack4_neon(weight_data, weight_data_pack4_bf16, num_input, num_output);
  886. }
  887. else
  888. {
  889. // src = kw-kh-inch-outch
  890. // dst = 4b-4a-kw-kh-inch/4a-outch/4b
  891. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  892. weight_data_pack4_bf16.create(maxk, num_input / 4, num_output / 4, (size_t)2 * 16, 16);
  893. for (int q = 0; q + 3 < num_output; q += 4)
  894. {
  895. const Mat k0 = weight_data_r2.channel(q);
  896. const Mat k1 = weight_data_r2.channel(q + 1);
  897. const Mat k2 = weight_data_r2.channel(q + 2);
  898. const Mat k3 = weight_data_r2.channel(q + 3);
  899. Mat g0 = weight_data_pack4_bf16.channel(q / 4);
  900. for (int p = 0; p + 3 < num_input; p += 4)
  901. {
  902. const float* k00 = k0.row(p);
  903. const float* k01 = k0.row(p + 1);
  904. const float* k02 = k0.row(p + 2);
  905. const float* k03 = k0.row(p + 3);
  906. const float* k10 = k1.row(p);
  907. const float* k11 = k1.row(p + 1);
  908. const float* k12 = k1.row(p + 2);
  909. const float* k13 = k1.row(p + 3);
  910. const float* k20 = k2.row(p);
  911. const float* k21 = k2.row(p + 1);
  912. const float* k22 = k2.row(p + 2);
  913. const float* k23 = k2.row(p + 3);
  914. const float* k30 = k3.row(p);
  915. const float* k31 = k3.row(p + 1);
  916. const float* k32 = k3.row(p + 2);
  917. const float* k33 = k3.row(p + 3);
  918. unsigned short* g00 = g0.row<unsigned short>(p / 4);
  919. for (int k = 0; k < maxk; k++)
  920. {
  921. g00[0] = float32_to_bfloat16(k00[k]);
  922. g00[1] = float32_to_bfloat16(k10[k]);
  923. g00[2] = float32_to_bfloat16(k20[k]);
  924. g00[3] = float32_to_bfloat16(k30[k]);
  925. g00[4] = float32_to_bfloat16(k01[k]);
  926. g00[5] = float32_to_bfloat16(k11[k]);
  927. g00[6] = float32_to_bfloat16(k21[k]);
  928. g00[7] = float32_to_bfloat16(k31[k]);
  929. g00[8] = float32_to_bfloat16(k02[k]);
  930. g00[9] = float32_to_bfloat16(k12[k]);
  931. g00[10] = float32_to_bfloat16(k22[k]);
  932. g00[11] = float32_to_bfloat16(k32[k]);
  933. g00[12] = float32_to_bfloat16(k03[k]);
  934. g00[13] = float32_to_bfloat16(k13[k]);
  935. g00[14] = float32_to_bfloat16(k23[k]);
  936. g00[15] = float32_to_bfloat16(k33[k]);
  937. g00 += 16;
  938. }
  939. }
  940. }
  941. }
  942. }
  943. // pack1to4
  944. if (elempack == 1 && out_elempack == 4)
  945. {
  946. // src = kw-kh-inch-outch
  947. // dst = 4b-kw-kh-inch-outch/4b
  948. {
  949. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  950. weight_data_pack1to4_bf16.create(maxk, num_input, num_output / 4, (size_t)2 * 4, 4);
  951. for (int q = 0; q + 3 < num_output; q += 4)
  952. {
  953. const Mat k0 = weight_data_r2.channel(q);
  954. const Mat k1 = weight_data_r2.channel(q + 1);
  955. const Mat k2 = weight_data_r2.channel(q + 2);
  956. const Mat k3 = weight_data_r2.channel(q + 3);
  957. Mat g0 = weight_data_pack1to4_bf16.channel(q / 4);
  958. for (int p = 0; p < num_input; p++)
  959. {
  960. const float* k00 = k0.row(p);
  961. const float* k10 = k1.row(p);
  962. const float* k20 = k2.row(p);
  963. const float* k30 = k3.row(p);
  964. unsigned short* g00 = g0.row<unsigned short>(p);
  965. for (int k = 0; k < maxk; k++)
  966. {
  967. g00[0] = float32_to_bfloat16(k00[k]);
  968. g00[1] = float32_to_bfloat16(k10[k]);
  969. g00[2] = float32_to_bfloat16(k20[k]);
  970. g00[3] = float32_to_bfloat16(k30[k]);
  971. g00 += 4;
  972. }
  973. }
  974. }
  975. }
  976. }
  977. // pack4to1
  978. if (elempack == 4 && out_elempack == 1)
  979. {
  980. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  981. {
  982. conv1x1s1_sgemm_transform_kernel_pack4to1_bf16s_neon(weight_data, weight_data_pack4to1_bf16, num_input, num_output);
  983. }
  984. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  985. {
  986. conv1x1s1_sgemm_transform_kernel_pack4to1_bf16s_neon(weight_data, weight_data_pack4to1_bf16, num_input, num_output);
  987. }
  988. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  989. {
  990. conv3x3s1_winograd64_transform_kernel_pack4to1_neon(weight_data, weight_data_pack4to1_bf16, num_input, num_output);
  991. }
  992. else
  993. {
  994. // src = kw-kh-inch-outch
  995. // dst = 4a-kw-kh-inch/4a-outch
  996. Mat weight_data_r2 = weight_data.reshape(maxk, num_input, num_output);
  997. weight_data_pack4to1_bf16.create(maxk, num_input / 4, num_output, (size_t)2 * 4, 4);
  998. for (int q = 0; q < num_output; q++)
  999. {
  1000. const Mat k0 = weight_data_r2.channel(q);
  1001. Mat g0 = weight_data_pack4to1_bf16.channel(q);
  1002. for (int p = 0; p + 3 < num_input; p += 4)
  1003. {
  1004. const float* k00 = k0.row(p);
  1005. const float* k01 = k0.row(p + 1);
  1006. const float* k02 = k0.row(p + 2);
  1007. const float* k03 = k0.row(p + 3);
  1008. unsigned short* g00 = g0.row<unsigned short>(p / 4);
  1009. for (int k = 0; k < maxk; k++)
  1010. {
  1011. g00[0] = float32_to_bfloat16(k00[k]);
  1012. g00[1] = float32_to_bfloat16(k01[k]);
  1013. g00[2] = float32_to_bfloat16(k02[k]);
  1014. g00[3] = float32_to_bfloat16(k03[k]);
  1015. g00 += 4;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. }
  1021. #endif // __ARM_NEON
  1022. // pack1
  1023. if (elempack == 1 && out_elempack == 1)
  1024. {
  1025. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1026. {
  1027. conv1x1s1_sgemm_transform_kernel_bf16s_neon(weight_data, weight_data_bf16, num_input, num_output);
  1028. }
  1029. else
  1030. {
  1031. ncnn::cast_float32_to_bfloat16(weight_data, weight_data_bf16, opt);
  1032. }
  1033. }
  1034. return 0;
  1035. }
  1036. int Convolution_arm::forward_bf16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  1037. {
  1038. int w = bottom_blob.w;
  1039. int h = bottom_blob.h;
  1040. int channels = bottom_blob.c;
  1041. size_t elemsize = bottom_blob.elemsize;
  1042. int elempack = bottom_blob.elempack;
  1043. // NCNN_LOGE("Convolution input %d x %d pad = %d %d ksize=%d %d stride=%d %d", w, h, pad_w, pad_h, kernel_w, kernel_h, stride_w, stride_h);
  1044. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  1045. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  1046. Mat bottom_blob_bordered;
  1047. make_padding(bottom_blob, bottom_blob_bordered, opt);
  1048. if (bottom_blob_bordered.empty())
  1049. return -100;
  1050. w = bottom_blob_bordered.w;
  1051. h = bottom_blob_bordered.h;
  1052. int outw = (w - kernel_extent_w) / stride_w + 1;
  1053. int outh = (h - kernel_extent_h) / stride_h + 1;
  1054. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  1055. size_t out_elemsize = elemsize / elempack * out_elempack;
  1056. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  1057. if (top_blob.empty())
  1058. return -100;
  1059. // FIXME
  1060. // if ((!support_packing || !opt.use_packing_layout) && kernel_w == kernel_h && dilation_w != 1 && dilation_h == dilation_w && stride_w == 1 && stride_h == 1)
  1061. // {
  1062. // return forwardDilation_arm(bottom_blob_bordered, top_blob, opt);
  1063. // }
  1064. const int maxk = kernel_w * kernel_h;
  1065. // kernel offsets
  1066. std::vector<int> _space_ofs(maxk);
  1067. int* space_ofs = &_space_ofs[0];
  1068. {
  1069. int p1 = 0;
  1070. int p2 = 0;
  1071. int gap = w * dilation_h - kernel_w * dilation_w;
  1072. for (int i = 0; i < kernel_h; i++)
  1073. {
  1074. for (int j = 0; j < kernel_w; j++)
  1075. {
  1076. space_ofs[p1] = p2;
  1077. p1++;
  1078. p2 += dilation_w;
  1079. }
  1080. p2 += gap;
  1081. }
  1082. }
  1083. #if __ARM_NEON
  1084. if (elempack == 4 && out_elempack == 4)
  1085. {
  1086. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1087. {
  1088. conv1x1s1_sgemm_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1089. if (activation)
  1090. {
  1091. activation->forward_inplace(top_blob, opt);
  1092. }
  1093. }
  1094. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1095. {
  1096. conv1x1s2_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1097. if (activation)
  1098. {
  1099. activation->forward_inplace(top_blob, opt);
  1100. }
  1101. }
  1102. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1103. {
  1104. conv3x3s1_winograd64_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1105. if (activation)
  1106. {
  1107. activation->forward_inplace(top_blob, opt);
  1108. }
  1109. }
  1110. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1111. {
  1112. conv3x3s2_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1113. if (activation)
  1114. {
  1115. activation->forward_inplace(top_blob, opt);
  1116. }
  1117. }
  1118. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1119. {
  1120. conv5x5s1_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1121. if (activation)
  1122. {
  1123. activation->forward_inplace(top_blob, opt);
  1124. }
  1125. }
  1126. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1127. {
  1128. conv5x5s2_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  1129. if (activation)
  1130. {
  1131. activation->forward_inplace(top_blob, opt);
  1132. }
  1133. }
  1134. else
  1135. {
  1136. // num_output
  1137. #pragma omp parallel for num_threads(opt.num_threads)
  1138. for (int p = 0; p < num_output / out_elempack; p++)
  1139. {
  1140. unsigned short* outptr = top_blob.channel(p);
  1141. for (int i = 0; i < outh; i++)
  1142. {
  1143. for (int j = 0; j < outw; j++)
  1144. {
  1145. float32x4_t _sum = vdupq_n_f32(0.f);
  1146. if (bias_term)
  1147. {
  1148. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  1149. }
  1150. const unsigned short* kptr = weight_data_pack4_bf16.channel(p);
  1151. // channels
  1152. for (int q = 0; q < channels; q++)
  1153. {
  1154. const Mat m = bottom_blob_bordered.channel(q);
  1155. const unsigned short* sptr = m.row<const unsigned short>(i * stride_h) + j * stride_w * 4;
  1156. for (int k = 0; k < maxk; k++)
  1157. {
  1158. float32x4_t _val = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(sptr + space_ofs[k] * 4), 16));
  1159. float32x4_t _w0 = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr), 16));
  1160. float32x4_t _w1 = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr + 4), 16));
  1161. float32x4_t _w2 = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr + 8), 16));
  1162. float32x4_t _w3 = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr + 12), 16));
  1163. #if __aarch64__
  1164. _sum = vmlaq_laneq_f32(_sum, _w0, _val, 0);
  1165. _sum = vmlaq_laneq_f32(_sum, _w1, _val, 1);
  1166. _sum = vmlaq_laneq_f32(_sum, _w2, _val, 2);
  1167. _sum = vmlaq_laneq_f32(_sum, _w3, _val, 3);
  1168. #else
  1169. _sum = vmlaq_lane_f32(_sum, _w0, vget_low_f32(_val), 0);
  1170. _sum = vmlaq_lane_f32(_sum, _w1, vget_low_f32(_val), 1);
  1171. _sum = vmlaq_lane_f32(_sum, _w2, vget_high_f32(_val), 0);
  1172. _sum = vmlaq_lane_f32(_sum, _w3, vget_high_f32(_val), 1);
  1173. #endif
  1174. kptr += 16;
  1175. }
  1176. }
  1177. _sum = activation_ps(_sum, activation_type, activation_params);
  1178. vst1_u16(outptr + j * 4, vshrn_n_u32(vreinterpretq_u32_f32(_sum), 16));
  1179. }
  1180. outptr += outw * 4;
  1181. }
  1182. }
  1183. }
  1184. }
  1185. if (elempack == 1 && out_elempack == 4)
  1186. {
  1187. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1188. {
  1189. conv3x3s1_pack1to4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4_bf16, bias_data, opt);
  1190. if (activation)
  1191. {
  1192. activation->forward_inplace(top_blob, opt);
  1193. }
  1194. }
  1195. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1196. {
  1197. conv3x3s2_pack1to4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4_bf16, bias_data, opt);
  1198. if (activation)
  1199. {
  1200. activation->forward_inplace(top_blob, opt);
  1201. }
  1202. }
  1203. else if (kernel_w == 7 && kernel_h == 7 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1204. {
  1205. conv7x7s2_pack1to4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack1to4_bf16, bias_data, opt);
  1206. if (activation)
  1207. {
  1208. activation->forward_inplace(top_blob, opt);
  1209. }
  1210. }
  1211. else
  1212. {
  1213. // num_output
  1214. #pragma omp parallel for num_threads(opt.num_threads)
  1215. for (int p = 0; p < num_output / out_elempack; p++)
  1216. {
  1217. unsigned short* outptr = top_blob.channel(p);
  1218. for (int i = 0; i < outh; i++)
  1219. {
  1220. for (int j = 0; j < outw; j++)
  1221. {
  1222. float32x4_t _sum = vdupq_n_f32(0.f);
  1223. if (bias_term)
  1224. {
  1225. _sum = vld1q_f32(((const float*)bias_data) + p * 4);
  1226. }
  1227. const unsigned short* kptr = weight_data_pack1to4_bf16.channel(p);
  1228. // channels
  1229. for (int q = 0; q < channels; q++)
  1230. {
  1231. const Mat m = bottom_blob_bordered.channel(q);
  1232. const unsigned short* sptr = m.row<const unsigned short>(i * stride_h) + j * stride_w;
  1233. for (int k = 0; k < maxk; k++)
  1234. {
  1235. float32x4_t _val = vdupq_n_f32(bfloat16_to_float32(sptr[space_ofs[k]]));
  1236. float32x4_t _w = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr), 16));
  1237. _sum = vmlaq_f32(_sum, _val, _w);
  1238. kptr += 4;
  1239. }
  1240. }
  1241. _sum = activation_ps(_sum, activation_type, activation_params);
  1242. vst1_u16(outptr + j * 4, vshrn_n_u32(vreinterpretq_u32_f32(_sum), 16));
  1243. }
  1244. outptr += outw * 4;
  1245. }
  1246. }
  1247. }
  1248. }
  1249. if (elempack == 4 && out_elempack == 1)
  1250. {
  1251. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1252. {
  1253. conv1x1s1_sgemm_pack4to1_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1_bf16, bias_data, opt);
  1254. if (activation)
  1255. {
  1256. activation->forward_inplace(top_blob, opt);
  1257. }
  1258. }
  1259. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1260. {
  1261. conv1x1s2_pack4to1_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1_bf16, bias_data, opt);
  1262. if (activation)
  1263. {
  1264. activation->forward_inplace(top_blob, opt);
  1265. }
  1266. }
  1267. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1268. {
  1269. // TODO more proper condition
  1270. conv3x3s1_winograd64_pack4to1_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1_bf16, bias_data, opt);
  1271. // conv3x3s1_pack4to1_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4to1_bf16, bias_data, opt);
  1272. if (activation)
  1273. {
  1274. activation->forward_inplace(top_blob, opt);
  1275. }
  1276. }
  1277. else
  1278. {
  1279. // num_output
  1280. #pragma omp parallel for num_threads(opt.num_threads)
  1281. for (int p = 0; p < num_output; p++)
  1282. {
  1283. unsigned short* outptr = top_blob.channel(p);
  1284. for (int i = 0; i < outh; i++)
  1285. {
  1286. for (int j = 0; j < outw; j++)
  1287. {
  1288. float sum = 0.f;
  1289. if (bias_term)
  1290. {
  1291. sum = bias_data[p];
  1292. }
  1293. const unsigned short* kptr = weight_data_pack4to1_bf16.channel(p);
  1294. // channels
  1295. for (int q = 0; q < channels; q++)
  1296. {
  1297. const Mat m = bottom_blob_bordered.channel(q);
  1298. const unsigned short* sptr = m.row<const unsigned short>(i * stride_h) + j * stride_w * 4;
  1299. for (int k = 0; k < maxk; k++)
  1300. {
  1301. float32x4_t _val = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(sptr + space_ofs[k] * 4), 16));
  1302. float32x4_t _w = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr), 16));
  1303. float32x4_t _s4 = vmulq_f32(_val, _w);
  1304. #if __aarch64__
  1305. sum += vaddvq_f32(_s4); // dot
  1306. #else
  1307. float32x2_t _ss = vadd_f32(vget_low_f32(_s4), vget_high_f32(_s4));
  1308. _ss = vpadd_f32(_ss, _ss);
  1309. sum += vget_lane_f32(_ss, 0);
  1310. #endif
  1311. kptr += 4;
  1312. }
  1313. }
  1314. sum = activation_ss(sum, activation_type, activation_params);
  1315. outptr[j] = float32_to_bfloat16(sum);
  1316. }
  1317. outptr += outw;
  1318. }
  1319. }
  1320. }
  1321. }
  1322. #endif // __ARM_NEON
  1323. if (elempack == 1 && out_elempack == 1)
  1324. {
  1325. if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1326. {
  1327. conv1x1s1_sgemm_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_bf16, bias_data, opt);
  1328. if (activation)
  1329. {
  1330. activation->forward_inplace(top_blob, opt);
  1331. }
  1332. }
  1333. else
  1334. {
  1335. // num_output
  1336. #pragma omp parallel for num_threads(opt.num_threads)
  1337. for (int p = 0; p < num_output; p++)
  1338. {
  1339. unsigned short* outptr = top_blob.channel(p);
  1340. for (int i = 0; i < outh; i++)
  1341. {
  1342. for (int j = 0; j < outw; j++)
  1343. {
  1344. float sum = 0.f;
  1345. if (bias_term)
  1346. {
  1347. sum = bias_data[p];
  1348. }
  1349. const unsigned short* kptr = (const unsigned short*)weight_data_bf16 + maxk * channels * p;
  1350. // channels
  1351. for (int q = 0; q < channels; q++)
  1352. {
  1353. const Mat m = bottom_blob_bordered.channel(q);
  1354. const unsigned short* sptr = m.row<unsigned short>(i * stride_h) + j * stride_w;
  1355. for (int k = 0; k < maxk; k++)
  1356. {
  1357. float val = bfloat16_to_float32(sptr[space_ofs[k]]);
  1358. float w = bfloat16_to_float32(kptr[k]);
  1359. sum += val * w;
  1360. }
  1361. kptr += maxk;
  1362. }
  1363. if (activation_type == 1)
  1364. {
  1365. sum = std::max(sum, 0.f);
  1366. }
  1367. else if (activation_type == 2)
  1368. {
  1369. float slope = activation_params[0];
  1370. sum = sum > 0.f ? sum : sum * slope;
  1371. }
  1372. else if (activation_type == 3)
  1373. {
  1374. float min = activation_params[0];
  1375. float max = activation_params[1];
  1376. if (sum < min)
  1377. sum = min;
  1378. if (sum > max)
  1379. sum = max;
  1380. }
  1381. else if (activation_type == 4)
  1382. {
  1383. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  1384. }
  1385. else if (activation_type == 5)
  1386. {
  1387. sum = static_cast<float>(sum * tanh(log(exp(sum) + 1.f)));
  1388. }
  1389. outptr[j] = float32_to_bfloat16(sum);
  1390. }
  1391. outptr += outw;
  1392. }
  1393. }
  1394. }
  1395. }
  1396. return 0;
  1397. }
  1398. int Convolution_arm::create_pipeline_int8_arm(const Option& opt)
  1399. {
  1400. const int maxk = kernel_w * kernel_h;
  1401. const int num_input = weight_data_size / maxk / num_output;
  1402. use_winograd3x3_int8 = false;
  1403. use_sgemm1x1_int8 = false;
  1404. if (opt.use_winograd_convolution && kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1405. {
  1406. use_winograd3x3_int8 = true;
  1407. // conv3x3s1_winograd23_transform_kernel_int8_neon(weight_data, weight_3x3_winograd23_data_int8, num_input, num_output);
  1408. conv3x3s1_winograd43_transform_kernel_int8_neon(weight_data, weight_3x3_winograd23_data_int8, num_input, num_output);
  1409. }
  1410. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1411. {
  1412. conv3x3s2_transform_kernel_int8_neon(weight_data, weight_3x3s2_data_int8, num_input, num_output);
  1413. }
  1414. else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1415. {
  1416. use_sgemm1x1_int8 = true;
  1417. conv1x1s1_sgemm_transform_kernel_int8_neon(weight_data, weight_1x1s1_sgemm_data_int8, num_input, num_output);
  1418. }
  1419. else
  1420. {
  1421. conv_im2col_sgemm_transform_kernel_int8_neon(weight_data, weight_sgemm_data_int8, num_input, num_output, maxk);
  1422. }
  1423. return 0;
  1424. }
  1425. int Convolution_arm::forward_int8_arm(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  1426. {
  1427. if (dilation_w > 1 || dilation_h > 1)
  1428. {
  1429. return Convolution::forward(bottom_blob, top_blob, opt);
  1430. }
  1431. int w = bottom_blob.w;
  1432. int h = bottom_blob.h;
  1433. // int channels = bottom_blob.c;
  1434. size_t elemsize = bottom_blob.elemsize;
  1435. // NCNN_LOGE("Convolution_arm input %d x %d ksize=%d %d stride=%d %d", w, h, kernel_w, kernel_h, stride_w, stride_h);
  1436. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  1437. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  1438. Mat bottom_blob_unbordered = bottom_blob;
  1439. if (elemsize != 1)
  1440. {
  1441. Option opt_g = opt;
  1442. opt_g.blob_allocator = opt.workspace_allocator;
  1443. quantize_float32_to_int8(bottom_blob, bottom_blob_unbordered, bottom_blob_int8_scale, opt_g);
  1444. }
  1445. Mat bottom_blob_bordered;
  1446. make_padding(bottom_blob_unbordered, bottom_blob_bordered, opt);
  1447. if (bottom_blob_bordered.empty())
  1448. return -100;
  1449. w = bottom_blob_bordered.w;
  1450. h = bottom_blob_bordered.h;
  1451. int outw = (w - kernel_extent_w) / stride_w + 1;
  1452. int outh = (h - kernel_extent_h) / stride_h + 1;
  1453. // int8
  1454. size_t out_elemsize = use_int8_requantize ? 1u : 4u;
  1455. top_blob.create(outw, outh, num_output, out_elemsize, opt.blob_allocator);
  1456. if (top_blob.empty())
  1457. return -100;
  1458. // int8
  1459. if (use_int8_requantize == true)
  1460. {
  1461. Mat top_blob_tm;
  1462. top_blob_tm.create(outw, outh, num_output, (size_t)4u, opt.workspace_allocator);
  1463. if (top_blob_tm.empty())
  1464. return -100;
  1465. if (use_sgemm1x1_int8)
  1466. {
  1467. std::vector<float> requantize_scales;
  1468. for (int p = 0; p < num_output; p++)
  1469. {
  1470. float scale_in;
  1471. if (weight_data_int8_scales[p] == 0)
  1472. scale_in = 0;
  1473. else
  1474. scale_in = 1.f / (bottom_blob_int8_scale * weight_data_int8_scales[p]);
  1475. float scale_out = top_blob_int8_scale;
  1476. requantize_scales.push_back(scale_in);
  1477. requantize_scales.push_back(scale_out);
  1478. }
  1479. conv1x1s1_sgemm_int8_requant_neon(bottom_blob_bordered, top_blob, weight_1x1s1_sgemm_data_int8, bias_data, requantize_scales, opt);
  1480. if (activation)
  1481. {
  1482. activation->forward_inplace(top_blob, opt);
  1483. }
  1484. return 0;
  1485. }
  1486. else if (use_winograd3x3_int8)
  1487. {
  1488. // conv3x3s1_winograd23_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3_winograd23_data_int8, opt);
  1489. conv3x3s1_winograd43_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3_winograd23_data_int8, opt);
  1490. }
  1491. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1492. {
  1493. conv3x3s2_packed_int8_neon(bottom_blob_bordered, top_blob_tm, weight_3x3s2_data_int8, opt);
  1494. }
  1495. else
  1496. {
  1497. conv_im2col_sgemm_int8_neon(bottom_blob_bordered, top_blob_tm, weight_sgemm_data_int8, kernel_w, kernel_h, stride_w, stride_h, opt);
  1498. }
  1499. // requantize, reverse scale inplace
  1500. #pragma omp parallel for num_threads(opt.num_threads)
  1501. for (int p = 0; p < num_output; p++)
  1502. {
  1503. Option opt_g = opt;
  1504. opt_g.num_threads = 1;
  1505. opt_g.blob_allocator = top_blob.allocator;
  1506. Mat top_blob_tm_g = top_blob_tm.channel_range(p, 1);
  1507. Mat top_blob_g = top_blob.channel_range(p, 1);
  1508. // requantize and relu
  1509. float scale_in;
  1510. if (weight_data_int8_scales[p] == 0)
  1511. scale_in = 0;
  1512. else
  1513. scale_in = 1.f / (bottom_blob_int8_scale * weight_data_int8_scales[p]);
  1514. float scale_out = top_blob_int8_scale; //FIXME load param
  1515. requantize_int8_to_int8(top_blob_tm_g, top_blob_g, scale_in, scale_out, bias_term ? (const float*)bias_data + p : 0, bias_term ? 1 : 0, 0, opt_g);
  1516. }
  1517. }
  1518. else
  1519. {
  1520. if (use_sgemm1x1_int8)
  1521. {
  1522. conv1x1s1_sgemm_int8_neon(bottom_blob_bordered, top_blob, weight_1x1s1_sgemm_data_int8, opt);
  1523. }
  1524. else if (use_winograd3x3_int8)
  1525. {
  1526. // conv3x3s1_winograd23_int8_neon(bottom_blob_bordered, top_blob, weight_3x3_winograd23_data_int8, opt);
  1527. conv3x3s1_winograd43_int8_neon(bottom_blob_bordered, top_blob, weight_3x3_winograd23_data_int8, opt);
  1528. }
  1529. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1530. {
  1531. conv3x3s2_packed_int8_neon(bottom_blob_bordered, top_blob, weight_3x3s2_data_int8, opt);
  1532. }
  1533. else
  1534. {
  1535. conv_im2col_sgemm_int8_neon(bottom_blob_bordered, top_blob, weight_sgemm_data_int8, kernel_w, kernel_h, stride_w, stride_h, opt);
  1536. }
  1537. // dequantize, reverse scale inplace
  1538. #pragma omp parallel for num_threads(opt.num_threads)
  1539. for (int p = 0; p < num_output; p++)
  1540. {
  1541. Option opt_g = opt;
  1542. opt_g.num_threads = 1;
  1543. opt_g.blob_allocator = top_blob.allocator;
  1544. Mat top_blob_g = top_blob.channel_range(p, 1);
  1545. // dequantize
  1546. float scale_in;
  1547. if (weight_data_int8_scales[p] == 0)
  1548. scale_in = 0;
  1549. else
  1550. scale_in = 1.f / (bottom_blob_int8_scale * weight_data_int8_scales[p]);
  1551. dequantize_int32_to_float32(top_blob_g, scale_in, bias_term ? (const float*)bias_data + p : 0, bias_term ? 1 : 0, opt_g);
  1552. }
  1553. }
  1554. if (activation)
  1555. {
  1556. activation->forward_inplace(top_blob, opt);
  1557. }
  1558. return 0;
  1559. }
  1560. int Convolution_arm::forwardDilation_arm(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  1561. {
  1562. int w = bottom_blob.w;
  1563. int h = bottom_blob.h;
  1564. size_t elemsize = bottom_blob.elemsize;
  1565. const int kernel_size = kernel_w;
  1566. const int stride = stride_w;
  1567. const int dilation = dilation_w;
  1568. const int kernel_extent = dilation * (kernel_size - 1) + 1;
  1569. int outw = (w - kernel_extent) / stride + 1;
  1570. int outh = (h - kernel_extent) / stride + 1;
  1571. top_blob.create(outw, outh, num_output, elemsize, opt.blob_allocator);
  1572. if (top_blob.empty())
  1573. return -100;
  1574. // Make (dilation * dilation) batches
  1575. Mat inner_bottom_blob;
  1576. Mat inner_top_blob;
  1577. for (int x = 0; x < dilation; x++)
  1578. {
  1579. for (int y = 0; y < dilation; y++)
  1580. {
  1581. int inner_w = (w - y + dilation - 1) / dilation;
  1582. int inner_h = (h - x + dilation - 1) / dilation;
  1583. int inner_outw = (inner_w - kernel_size) / stride + 1;
  1584. int inner_outh = (inner_h - kernel_size) / stride + 1;
  1585. inner_bottom_blob.create(inner_w, inner_h, bottom_blob.c, elemsize, opt.workspace_allocator);
  1586. if (inner_bottom_blob.empty())
  1587. return -100;
  1588. inner_top_blob.create(inner_outw, inner_outh, num_output, elemsize, opt.workspace_allocator);
  1589. if (inner_top_blob.empty())
  1590. return -100;
  1591. #pragma omp parallel for num_threads(opt.num_threads)
  1592. for (int c = 0; c < bottom_blob.c; c++)
  1593. {
  1594. float* outptr = inner_bottom_blob.channel(c);
  1595. for (int i = 0; i < inner_h; i++)
  1596. {
  1597. const float* ptr = (const float*)bottom_blob.channel(c) + dilation * i * w + x * w + y;
  1598. for (int j = 0; j < inner_w; j++)
  1599. {
  1600. outptr[j] = ptr[j * dilation];
  1601. }
  1602. outptr += inner_w;
  1603. }
  1604. }
  1605. Option opt_g = opt;
  1606. opt_g.blob_allocator = inner_top_blob.allocator;
  1607. convolution_dilation1->forward(inner_bottom_blob, inner_top_blob, opt_g);
  1608. #pragma omp parallel for num_threads(opt.num_threads)
  1609. for (int c = 0; c < num_output; c++)
  1610. {
  1611. float* outptr = (float*)top_blob.channel(c) + x * outw + y;
  1612. for (int i = 0; i < inner_outh; i++)
  1613. {
  1614. const float* ptr = (const float*)inner_top_blob.channel(c) + i * inner_outw;
  1615. for (int j = 0; j < inner_outw; j++)
  1616. {
  1617. outptr[j * dilation] = ptr[j];
  1618. }
  1619. outptr += dilation * outw;
  1620. }
  1621. }
  1622. }
  1623. }
  1624. if (activation)
  1625. {
  1626. activation->forward_inplace(top_blob, opt);
  1627. }
  1628. return 0;
  1629. }
  1630. } // namespace ncnn