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.

convolutiondepthwise_arm.cpp 53 kB

7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518
  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 "convolutiondepthwise_arm.h"
  15. #include "layer_type.h"
  16. #if __ARM_NEON
  17. #include <arm_neon.h>
  18. #include "neon_mathfun.h"
  19. #endif // __ARM_NEON
  20. #include "neon_activation.h"
  21. namespace ncnn {
  22. #include "convolutiondepthwise_3x3.h"
  23. #include "convolutiondepthwise_3x3_int8.h"
  24. #include "convolutiondepthwise_5x5.h"
  25. #if __ARM_NEON
  26. #include "convolutiondepthwise_3x3_pack4.h"
  27. #include "convolutiondepthwise_3x3_pack4_bf16s.h"
  28. #include "convolutiondepthwise_5x5_pack4.h"
  29. #include "convolutiondepthwise_5x5_pack4_bf16s.h"
  30. #endif // __ARM_NEON
  31. ConvolutionDepthWise_arm::ConvolutionDepthWise_arm()
  32. {
  33. #if __ARM_NEON
  34. support_packing = true;
  35. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  36. support_fp16_storage = true;
  37. #endif
  38. #endif // __ARM_NEON
  39. support_bf16_storage = true;
  40. activation = 0;
  41. }
  42. int ConvolutionDepthWise_arm::create_pipeline(const Option& opt)
  43. {
  44. if (activation_type == 1)
  45. {
  46. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  47. ncnn::ParamDict pd;
  48. activation->load_param(pd);
  49. }
  50. else if (activation_type == 2)
  51. {
  52. activation = ncnn::create_layer(ncnn::LayerType::ReLU);
  53. ncnn::ParamDict pd;
  54. pd.set(0, activation_params[0]); // slope
  55. activation->load_param(pd);
  56. }
  57. else if (activation_type == 3)
  58. {
  59. activation = ncnn::create_layer(ncnn::LayerType::Clip);
  60. ncnn::ParamDict pd;
  61. pd.set(0, activation_params[0]); // min
  62. pd.set(1, activation_params[1]); // max
  63. activation->load_param(pd);
  64. }
  65. else if (activation_type == 4)
  66. {
  67. activation = ncnn::create_layer(ncnn::LayerType::Sigmoid);
  68. ncnn::ParamDict pd;
  69. activation->load_param(pd);
  70. }
  71. else if (activation_type == 5)
  72. {
  73. activation = ncnn::create_layer(ncnn::LayerType::Mish);
  74. ncnn::ParamDict pd;
  75. activation->load_param(pd);
  76. }
  77. if (activation)
  78. {
  79. activation->create_pipeline(opt);
  80. }
  81. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  82. {
  83. support_packing = false;
  84. }
  85. // create Convolution op for each group
  86. const int maxk = kernel_w * kernel_h;
  87. int channels = (weight_data_size / group) / maxk / (num_output / group) * group;
  88. // depth-wise
  89. if (channels == group && group == num_output)
  90. {
  91. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  92. {
  93. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  94. {
  95. return 0;
  96. }
  97. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  98. {
  99. return 0;
  100. }
  101. }
  102. int elempack = (support_packing && opt.use_packing_layout && channels % 4 == 0) ? 4 : 1;
  103. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  104. if (opt.use_fp16_storage)
  105. {
  106. if (elempack == 4)
  107. {
  108. Mat weight_data_r2 = weight_data.reshape(maxk, group);
  109. convert_packing(weight_data_r2, weight_data_pack4, 4);
  110. ncnn::cast_float32_to_float16(weight_data_pack4, weight_data_pack4_fp16, opt);
  111. }
  112. if (elempack == 1)
  113. {
  114. ncnn::cast_float32_to_float16(weight_data, weight_data_fp16, opt);
  115. }
  116. ncnn::cast_float32_to_float16(bias_data, bias_data_fp16, opt);
  117. return 0;
  118. }
  119. #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  120. if (opt.use_bf16_storage)
  121. {
  122. #if __ARM_NEON
  123. if (elempack == 4)
  124. {
  125. Mat weight_data_r2 = weight_data.reshape(maxk, group);
  126. convert_packing(weight_data_r2, weight_data_pack4, 4);
  127. ncnn::cast_float32_to_bfloat16(weight_data_pack4, weight_data_pack4_bf16, opt);
  128. }
  129. #endif // __ARM_NEON
  130. if (elempack == 1)
  131. {
  132. ncnn::cast_float32_to_bfloat16(weight_data, weight_data_bf16, opt);
  133. }
  134. return 0;
  135. }
  136. #if __ARM_NEON
  137. // pack4
  138. if (elempack == 4)
  139. {
  140. Mat weight_data_r2 = weight_data.reshape(maxk, group);
  141. convert_packing(weight_data_r2, weight_data_pack4, 4);
  142. return 0;
  143. }
  144. #endif // __ARM_NEON
  145. if (elempack == 1)
  146. {
  147. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  148. {
  149. return 0;
  150. }
  151. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  152. {
  153. return 0;
  154. }
  155. if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  156. {
  157. return 0;
  158. }
  159. if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  160. {
  161. return 0;
  162. }
  163. }
  164. }
  165. // group convolution
  166. for (int i = 0; i < (int)group_ops.size(); i++)
  167. delete group_ops[i];
  168. group_ops.clear();
  169. const int channels_g = channels / group;
  170. const int num_output_g = num_output / group;
  171. group_ops.resize(group);
  172. for (int g = 0; g < group; g++)
  173. {
  174. Mat weight_data_g = weight_data.range(maxk * channels_g * num_output_g * g, maxk * channels_g * num_output_g);
  175. Mat bias_data_g;
  176. if (bias_term)
  177. bias_data_g = bias_data.range(num_output_g * g, num_output_g);
  178. ncnn::Layer* op = ncnn::create_layer(ncnn::LayerType::Convolution);
  179. // FIXME
  180. // ((ncnn::Convolution*)op)->use_int8_requantize = use_int8_requantize;
  181. // set param
  182. ncnn::ParamDict pd;
  183. pd.set(0, num_output_g); // num_output
  184. pd.set(1, kernel_w);
  185. pd.set(11, kernel_h);
  186. pd.set(2, dilation_w);
  187. pd.set(12, dilation_h);
  188. pd.set(3, stride_w);
  189. pd.set(13, stride_h);
  190. pd.set(4, 0); // pad_w
  191. pd.set(14, 0); // pad_h
  192. pd.set(5, bias_term);
  193. pd.set(6, maxk * channels_g * num_output_g); // weight_data_size
  194. pd.set(8, int8_scale_term);
  195. pd.set(9, activation_type);
  196. pd.set(10, activation_params);
  197. op->load_param(pd);
  198. // set weights
  199. if (bias_term)
  200. {
  201. ncnn::Mat weights[4];
  202. weights[0] = weight_data_g;
  203. weights[1] = bias_data_g;
  204. if (int8_scale_term)
  205. {
  206. Mat weight_data_int8_scales_g(num_output_g);
  207. weight_data_int8_scales_g.fill(weight_data_int8_scales[g]);
  208. weights[2] = weight_data_int8_scales_g;
  209. weights[3] = bottom_blob_int8_scales.range(g, 1);
  210. }
  211. op->load_model(ModelBinFromMatArray(weights));
  212. }
  213. else
  214. {
  215. ncnn::Mat weights[3];
  216. weights[0] = weight_data_g;
  217. if (int8_scale_term)
  218. {
  219. Mat weight_data_int8_scales_g(num_output_g);
  220. weight_data_int8_scales_g.fill(weight_data_int8_scales[g]);
  221. weights[1] = weight_data_int8_scales_g;
  222. weights[2] = bottom_blob_int8_scales.range(g, 1);
  223. }
  224. op->load_model(ModelBinFromMatArray(weights));
  225. }
  226. op->create_pipeline(opt);
  227. group_ops[g] = op;
  228. }
  229. return 0;
  230. }
  231. int ConvolutionDepthWise_arm::destroy_pipeline(const Option& opt)
  232. {
  233. if (activation)
  234. {
  235. activation->destroy_pipeline(opt);
  236. delete activation;
  237. activation = 0;
  238. }
  239. for (int i = 0; i < (int)group_ops.size(); i++)
  240. {
  241. group_ops[i]->destroy_pipeline(opt);
  242. delete group_ops[i];
  243. }
  244. group_ops.clear();
  245. return 0;
  246. }
  247. int ConvolutionDepthWise_arm::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  248. {
  249. // convolv with NxN kernel
  250. // value = value + bias
  251. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  252. {
  253. return forward_int8_arm(bottom_blob, top_blob, opt);
  254. }
  255. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  256. if (opt.use_fp16_storage)
  257. {
  258. if (opt.use_fp16_arithmetic)
  259. return forward_fp16sa(bottom_blob, top_blob, opt);
  260. else
  261. return forward_fp16s(bottom_blob, top_blob, opt);
  262. }
  263. #endif
  264. if (opt.use_bf16_storage)
  265. return forward_bf16s(bottom_blob, top_blob, opt);
  266. int w = bottom_blob.w;
  267. int h = bottom_blob.h;
  268. int channels = bottom_blob.c;
  269. size_t elemsize = bottom_blob.elemsize;
  270. int elempack = bottom_blob.elempack;
  271. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  272. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  273. Mat bottom_blob_bordered;
  274. make_padding(bottom_blob, bottom_blob_bordered, opt);
  275. if (bottom_blob_bordered.empty())
  276. return -100;
  277. w = bottom_blob_bordered.w;
  278. h = bottom_blob_bordered.h;
  279. int outw = (w - kernel_extent_w) / stride_w + 1;
  280. int outh = (h - kernel_extent_h) / stride_h + 1;
  281. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  282. size_t out_elemsize = elemsize / elempack * out_elempack;
  283. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  284. if (top_blob.empty())
  285. return -100;
  286. // depth-wise
  287. if (channels * elempack == group && group == num_output)
  288. {
  289. #if __ARM_NEON
  290. if (elempack == 4)
  291. {
  292. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  293. {
  294. convdw3x3s1_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  295. if (activation)
  296. {
  297. activation->forward_inplace(top_blob, opt);
  298. }
  299. return 0;
  300. }
  301. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  302. {
  303. convdw3x3s2_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  304. if (activation)
  305. {
  306. activation->forward_inplace(top_blob, opt);
  307. }
  308. return 0;
  309. }
  310. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  311. {
  312. convdw5x5s1_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  313. if (activation)
  314. {
  315. activation->forward_inplace(top_blob, opt);
  316. }
  317. return 0;
  318. }
  319. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  320. {
  321. convdw5x5s2_pack4_neon(bottom_blob_bordered, top_blob, weight_data_pack4, bias_data, opt);
  322. if (activation)
  323. {
  324. activation->forward_inplace(top_blob, opt);
  325. }
  326. return 0;
  327. }
  328. else
  329. {
  330. const int maxk = kernel_w * kernel_h;
  331. // kernel offsets
  332. std::vector<int> _space_ofs(maxk);
  333. int* space_ofs = &_space_ofs[0];
  334. {
  335. int p1 = 0;
  336. int p2 = 0;
  337. int gap = w * dilation_h - kernel_w * dilation_w;
  338. for (int i = 0; i < kernel_h; i++)
  339. {
  340. for (int j = 0; j < kernel_w; j++)
  341. {
  342. space_ofs[p1] = p2;
  343. p1++;
  344. p2 += dilation_w;
  345. }
  346. p2 += gap;
  347. }
  348. }
  349. #pragma omp parallel for num_threads(opt.num_threads)
  350. for (int g = 0; g < channels; g++)
  351. {
  352. float* outptr = top_blob.channel(g);
  353. const float* kptr = (const float*)weight_data_pack4 + maxk * g * 4;
  354. const Mat m = bottom_blob_bordered.channel(g);
  355. for (int i = 0; i < outh; i++)
  356. {
  357. for (int j = 0; j < outw; j++)
  358. {
  359. float32x4_t _sum = vdupq_n_f32(0.f);
  360. if (bias_term)
  361. {
  362. _sum = vld1q_f32(((const float*)bias_data) + g * 4);
  363. }
  364. const float* sptr = m.row(i * stride_h) + j * stride_w * 4;
  365. for (int k = 0; k < maxk; k++)
  366. {
  367. float32x4_t _val = vld1q_f32(sptr + space_ofs[k] * 4);
  368. float32x4_t _w = vld1q_f32(kptr + k * 4);
  369. _sum = vmlaq_f32(_sum, _val, _w);
  370. }
  371. _sum = activation_ps(_sum, activation_type, activation_params);
  372. vst1q_f32(outptr + j * 4, _sum);
  373. }
  374. outptr += outw * 4;
  375. }
  376. }
  377. return 0;
  378. }
  379. }
  380. #endif // __ARM_NEON
  381. if (elempack == 1)
  382. {
  383. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  384. {
  385. convdw3x3s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  386. if (activation)
  387. {
  388. activation->forward_inplace(top_blob, opt);
  389. }
  390. return 0;
  391. }
  392. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  393. {
  394. convdw3x3s2_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  395. if (activation)
  396. {
  397. activation->forward_inplace(top_blob, opt);
  398. }
  399. return 0;
  400. }
  401. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  402. {
  403. convdw5x5s1_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  404. if (activation)
  405. {
  406. activation->forward_inplace(top_blob, opt);
  407. }
  408. return 0;
  409. }
  410. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  411. {
  412. convdw5x5s2_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, opt);
  413. if (activation)
  414. {
  415. activation->forward_inplace(top_blob, opt);
  416. }
  417. return 0;
  418. }
  419. }
  420. }
  421. // group convolution
  422. const int channels_g = channels * elempack / group;
  423. const int num_output_g = num_output / group;
  424. int g_elempack = (support_packing && opt.use_packing_layout && channels_g % 4 == 0) ? 4 : 1;
  425. int out_g_elempack = (support_packing && opt.use_packing_layout && num_output_g % 4 == 0) ? 4 : 1;
  426. // unpacking
  427. Mat bottom_blob_bordered_unpacked = bottom_blob_bordered;
  428. if (elempack == 4 && g_elempack == 1)
  429. {
  430. Option opt_p = opt;
  431. opt_p.blob_allocator = opt.workspace_allocator;
  432. convert_packing(bottom_blob_bordered, bottom_blob_bordered_unpacked, 1, opt_p);
  433. }
  434. Mat top_blob_unpacked = top_blob;
  435. if (out_g_elempack == 1 && out_elempack == 4)
  436. {
  437. top_blob_unpacked.create(outw, outh, num_output, out_elemsize / out_elempack, 1, opt.workspace_allocator);
  438. if (top_blob_unpacked.empty())
  439. return -100;
  440. }
  441. for (int g = 0; g < group; g++)
  442. {
  443. const Mat bottom_blob_bordered_g = bottom_blob_bordered_unpacked.channel_range(channels_g * g / g_elempack, channels_g / g_elempack);
  444. Mat top_blob_g = top_blob_unpacked.channel_range(num_output_g * g / out_g_elempack, num_output_g / out_g_elempack);
  445. const ncnn::Layer* op = group_ops[g];
  446. Option opt_g = opt;
  447. opt_g.blob_allocator = top_blob_unpacked.allocator;
  448. // forward
  449. op->forward(bottom_blob_bordered_g, top_blob_g, opt_g);
  450. }
  451. // packing
  452. if (out_g_elempack == 1 && out_elempack == 4)
  453. {
  454. convert_packing(top_blob_unpacked, top_blob, 4, opt);
  455. }
  456. else
  457. {
  458. top_blob = top_blob_unpacked;
  459. }
  460. return 0;
  461. }
  462. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  463. int ConvolutionDepthWise_arm::forward_fp16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  464. {
  465. int w = bottom_blob.w;
  466. int h = bottom_blob.h;
  467. int channels = bottom_blob.c;
  468. size_t elemsize = bottom_blob.elemsize;
  469. int elempack = bottom_blob.elempack;
  470. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  471. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  472. Mat bottom_blob_bordered;
  473. make_padding(bottom_blob, bottom_blob_bordered, opt);
  474. if (bottom_blob_bordered.empty())
  475. return -100;
  476. w = bottom_blob_bordered.w;
  477. h = bottom_blob_bordered.h;
  478. int outw = (w - kernel_extent_w) / stride_w + 1;
  479. int outh = (h - kernel_extent_h) / stride_h + 1;
  480. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  481. size_t out_elemsize = elemsize / elempack * out_elempack;
  482. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  483. if (top_blob.empty())
  484. return -100;
  485. // depth-wise
  486. if (channels * elempack == group && group == num_output)
  487. {
  488. if (elempack == 4)
  489. {
  490. {
  491. const int maxk = kernel_w * kernel_h;
  492. // kernel offsets
  493. std::vector<int> _space_ofs(maxk);
  494. int* space_ofs = &_space_ofs[0];
  495. {
  496. int p1 = 0;
  497. int p2 = 0;
  498. int gap = w * dilation_h - kernel_w * dilation_w;
  499. for (int i = 0; i < kernel_h; i++)
  500. {
  501. for (int j = 0; j < kernel_w; j++)
  502. {
  503. space_ofs[p1] = p2;
  504. p1++;
  505. p2 += dilation_w;
  506. }
  507. p2 += gap;
  508. }
  509. }
  510. #pragma omp parallel for num_threads(opt.num_threads)
  511. for (int g = 0; g < channels; g++)
  512. {
  513. __fp16* outptr = top_blob.channel(g);
  514. const __fp16* kptr = (const __fp16*)weight_data_pack4_fp16 + maxk * g * 4;
  515. const Mat m = bottom_blob_bordered.channel(g);
  516. for (int i = 0; i < outh; i++)
  517. {
  518. for (int j = 0; j < outw; j++)
  519. {
  520. float32x4_t _sum = vdupq_n_f32(0.f);
  521. if (bias_term)
  522. {
  523. _sum = vld1q_f32(((const float*)bias_data) + g * 4);
  524. }
  525. const __fp16* sptr = m.row<const __fp16>(i * stride_h) + j * stride_w * 4;
  526. for (int k = 0; k < maxk; k++)
  527. {
  528. float32x4_t _val = vcvt_f32_f16(vld1_f16(sptr + space_ofs[k] * 4));
  529. float32x4_t _w = vcvt_f32_f16(vld1_f16(kptr + k * 4));
  530. _sum = vfmaq_f32(_sum, _val, _w);
  531. }
  532. _sum = activation_ps(_sum, activation_type, activation_params);
  533. vst1_f16(outptr + j * 4, vcvt_f16_f32(_sum));
  534. }
  535. outptr += outw * 4;
  536. }
  537. }
  538. }
  539. return 0;
  540. }
  541. if (elempack == 1)
  542. {
  543. {
  544. const int maxk = kernel_w * kernel_h;
  545. // kernel offsets
  546. std::vector<int> _space_ofs(maxk);
  547. int* space_ofs = &_space_ofs[0];
  548. {
  549. int p1 = 0;
  550. int p2 = 0;
  551. int gap = w * dilation_h - kernel_w * dilation_w;
  552. for (int i = 0; i < kernel_h; i++)
  553. {
  554. for (int j = 0; j < kernel_w; j++)
  555. {
  556. space_ofs[p1] = p2;
  557. p1++;
  558. p2 += dilation_w;
  559. }
  560. p2 += gap;
  561. }
  562. }
  563. #pragma omp parallel for num_threads(opt.num_threads)
  564. for (int g = 0; g < group; g++)
  565. {
  566. __fp16* outptr = top_blob.channel(g);
  567. const __fp16* kptr = (const __fp16*)weight_data_fp16 + maxk * g;
  568. const Mat m = bottom_blob_bordered.channel(g);
  569. for (int i = 0; i < outh; i++)
  570. {
  571. for (int j = 0; j < outw; j++)
  572. {
  573. float sum = 0.f;
  574. if (bias_term)
  575. sum = bias_data[g];
  576. const __fp16* sptr = m.row<const __fp16>(i * stride_h) + j * stride_w;
  577. for (int k = 0; k < maxk; k++)
  578. {
  579. float val = (float)sptr[space_ofs[k]];
  580. float w = (float)kptr[k];
  581. sum += val * w;
  582. }
  583. sum = activation_ss(sum, activation_type, activation_params);
  584. outptr[j] = (__fp16)sum;
  585. }
  586. outptr += outw;
  587. }
  588. }
  589. }
  590. }
  591. return 0;
  592. }
  593. // group convolution
  594. const int channels_g = channels * elempack / group;
  595. const int num_output_g = num_output / group;
  596. int g_elempack = (support_packing && opt.use_packing_layout && channels_g % 4 == 0) ? 4 : 1;
  597. int out_g_elempack = (support_packing && opt.use_packing_layout && num_output_g % 4 == 0) ? 4 : 1;
  598. // unpacking
  599. Mat bottom_blob_bordered_unpacked = bottom_blob_bordered;
  600. if (elempack == 4 && g_elempack == 1)
  601. {
  602. Option opt_p = opt;
  603. opt_p.blob_allocator = opt.workspace_allocator;
  604. convert_packing(bottom_blob_bordered, bottom_blob_bordered_unpacked, 1, opt_p);
  605. }
  606. Mat top_blob_unpacked = top_blob;
  607. if (out_g_elempack == 1 && out_elempack == 4)
  608. {
  609. top_blob_unpacked.create(outw, outh, num_output, out_elemsize / out_elempack, 1, opt.workspace_allocator);
  610. if (top_blob_unpacked.empty())
  611. return -100;
  612. }
  613. for (int g = 0; g < group; g++)
  614. {
  615. const Mat bottom_blob_bordered_g = bottom_blob_bordered_unpacked.channel_range(channels_g * g / g_elempack, channels_g / g_elempack);
  616. Mat top_blob_g = top_blob_unpacked.channel_range(num_output_g * g / out_g_elempack, num_output_g / out_g_elempack);
  617. const ncnn::Layer* op = group_ops[g];
  618. Option opt_g = opt;
  619. opt_g.blob_allocator = top_blob_unpacked.allocator;
  620. // forward
  621. op->forward(bottom_blob_bordered_g, top_blob_g, opt_g);
  622. }
  623. // packing
  624. if (out_g_elempack == 1 && out_elempack == 4)
  625. {
  626. convert_packing(top_blob_unpacked, top_blob, 4, opt);
  627. }
  628. else
  629. {
  630. top_blob = top_blob_unpacked;
  631. }
  632. return 0;
  633. }
  634. int ConvolutionDepthWise_arm::forward_fp16sa(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  635. {
  636. int w = bottom_blob.w;
  637. int h = bottom_blob.h;
  638. int channels = bottom_blob.c;
  639. size_t elemsize = bottom_blob.elemsize;
  640. int elempack = bottom_blob.elempack;
  641. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  642. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  643. Mat bottom_blob_bordered;
  644. make_padding(bottom_blob, bottom_blob_bordered, opt);
  645. if (bottom_blob_bordered.empty())
  646. return -100;
  647. w = bottom_blob_bordered.w;
  648. h = bottom_blob_bordered.h;
  649. int outw = (w - kernel_extent_w) / stride_w + 1;
  650. int outh = (h - kernel_extent_h) / stride_h + 1;
  651. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  652. size_t out_elemsize = elemsize / elempack * out_elempack;
  653. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  654. if (top_blob.empty())
  655. return -100;
  656. // depth-wise
  657. if (channels * elempack == group && group == num_output)
  658. {
  659. if (elempack == 4)
  660. {
  661. {
  662. const int maxk = kernel_w * kernel_h;
  663. // kernel offsets
  664. std::vector<int> _space_ofs(maxk);
  665. int* space_ofs = &_space_ofs[0];
  666. {
  667. int p1 = 0;
  668. int p2 = 0;
  669. int gap = w * dilation_h - kernel_w * dilation_w;
  670. for (int i = 0; i < kernel_h; i++)
  671. {
  672. for (int j = 0; j < kernel_w; j++)
  673. {
  674. space_ofs[p1] = p2;
  675. p1++;
  676. p2 += dilation_w;
  677. }
  678. p2 += gap;
  679. }
  680. }
  681. #pragma omp parallel for num_threads(opt.num_threads)
  682. for (int g = 0; g < channels; g++)
  683. {
  684. __fp16* outptr = top_blob.channel(g);
  685. const __fp16* kptr = (const __fp16*)weight_data_pack4_fp16 + maxk * g * 4;
  686. const Mat m = bottom_blob_bordered.channel(g);
  687. for (int i = 0; i < outh; i++)
  688. {
  689. for (int j = 0; j < outw; j++)
  690. {
  691. float16x4_t _sum = vdup_n_f16((__fp16)0.f);
  692. if (bias_term)
  693. {
  694. _sum = vld1_f16(((const __fp16*)bias_data_fp16) + g * 4);
  695. }
  696. const __fp16* sptr = m.row<const __fp16>(i * stride_h) + j * stride_w * 4;
  697. for (int k = 0; k < maxk; k++)
  698. {
  699. float16x4_t _val = vld1_f16(sptr + space_ofs[k] * 4);
  700. float16x4_t _w = vld1_f16(kptr + k * 4);
  701. _sum = vfma_f16(_sum, _val, _w);
  702. }
  703. _sum = activation_ps(_sum, activation_type, activation_params);
  704. vst1_f16(outptr + j * 4, _sum);
  705. }
  706. outptr += outw * 4;
  707. }
  708. }
  709. }
  710. return 0;
  711. }
  712. if (elempack == 1)
  713. {
  714. {
  715. const int maxk = kernel_w * kernel_h;
  716. // kernel offsets
  717. std::vector<int> _space_ofs(maxk);
  718. int* space_ofs = &_space_ofs[0];
  719. {
  720. int p1 = 0;
  721. int p2 = 0;
  722. int gap = w * dilation_h - kernel_w * dilation_w;
  723. for (int i = 0; i < kernel_h; i++)
  724. {
  725. for (int j = 0; j < kernel_w; j++)
  726. {
  727. space_ofs[p1] = p2;
  728. p1++;
  729. p2 += dilation_w;
  730. }
  731. p2 += gap;
  732. }
  733. }
  734. #pragma omp parallel for num_threads(opt.num_threads)
  735. for (int g = 0; g < group; g++)
  736. {
  737. __fp16* outptr = top_blob.channel(g);
  738. const __fp16* kptr = (const __fp16*)weight_data_fp16 + maxk * g;
  739. const Mat m = bottom_blob_bordered.channel(g);
  740. for (int i = 0; i < outh; i++)
  741. {
  742. for (int j = 0; j < outw; j++)
  743. {
  744. float sum = 0.f;
  745. if (bias_term)
  746. sum = bias_data[g];
  747. const __fp16* sptr = m.row<const __fp16>(i * stride_h) + j * stride_w;
  748. for (int k = 0; k < maxk; k++)
  749. {
  750. __fp16 val = sptr[space_ofs[k]];
  751. __fp16 w = kptr[k];
  752. sum += val * w;
  753. }
  754. if (activation_type == 1)
  755. {
  756. sum = std::max(sum, 0.f);
  757. }
  758. else if (activation_type == 2)
  759. {
  760. float slope = activation_params[0];
  761. sum = sum > 0.f ? sum : sum * slope;
  762. }
  763. else if (activation_type == 3)
  764. {
  765. float min = activation_params[0];
  766. float max = activation_params[1];
  767. if (sum < min)
  768. sum = min;
  769. if (sum > max)
  770. sum = max;
  771. }
  772. else if (activation_type == 4)
  773. {
  774. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  775. }
  776. else if (activation_type == 5)
  777. {
  778. sum = static_cast<float>(sum * tanh(log(exp(sum) + 1.f)));
  779. }
  780. outptr[j] = (__fp16)sum;
  781. }
  782. outptr += outw;
  783. }
  784. }
  785. }
  786. }
  787. return 0;
  788. }
  789. // group convolution
  790. const int channels_g = channels * elempack / group;
  791. const int num_output_g = num_output / group;
  792. int g_elempack = (support_packing && opt.use_packing_layout && channels_g % 4 == 0) ? 4 : 1;
  793. int out_g_elempack = (support_packing && opt.use_packing_layout && num_output_g % 4 == 0) ? 4 : 1;
  794. // unpacking
  795. Mat bottom_blob_bordered_unpacked = bottom_blob_bordered;
  796. if (elempack == 4 && g_elempack == 1)
  797. {
  798. Option opt_p = opt;
  799. opt_p.blob_allocator = opt.workspace_allocator;
  800. convert_packing(bottom_blob_bordered, bottom_blob_bordered_unpacked, 1, opt_p);
  801. }
  802. Mat top_blob_unpacked = top_blob;
  803. if (out_g_elempack == 1 && out_elempack == 4)
  804. {
  805. top_blob_unpacked.create(outw, outh, num_output, out_elemsize / out_elempack, 1, opt.workspace_allocator);
  806. if (top_blob_unpacked.empty())
  807. return -100;
  808. }
  809. for (int g = 0; g < group; g++)
  810. {
  811. const Mat bottom_blob_bordered_g = bottom_blob_bordered_unpacked.channel_range(channels_g * g / g_elempack, channels_g / g_elempack);
  812. Mat top_blob_g = top_blob_unpacked.channel_range(num_output_g * g / out_g_elempack, num_output_g / out_g_elempack);
  813. const ncnn::Layer* op = group_ops[g];
  814. Option opt_g = opt;
  815. opt_g.blob_allocator = top_blob_unpacked.allocator;
  816. // forward
  817. op->forward(bottom_blob_bordered_g, top_blob_g, opt_g);
  818. }
  819. // packing
  820. if (out_g_elempack == 1 && out_elempack == 4)
  821. {
  822. convert_packing(top_blob_unpacked, top_blob, 4, opt);
  823. }
  824. else
  825. {
  826. top_blob = top_blob_unpacked;
  827. }
  828. return 0;
  829. }
  830. #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  831. int ConvolutionDepthWise_arm::forward_bf16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  832. {
  833. int w = bottom_blob.w;
  834. int h = bottom_blob.h;
  835. int channels = bottom_blob.c;
  836. size_t elemsize = bottom_blob.elemsize;
  837. int elempack = bottom_blob.elempack;
  838. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  839. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  840. Mat bottom_blob_bordered;
  841. make_padding(bottom_blob, bottom_blob_bordered, opt);
  842. if (bottom_blob_bordered.empty())
  843. return -100;
  844. w = bottom_blob_bordered.w;
  845. h = bottom_blob_bordered.h;
  846. int outw = (w - kernel_extent_w) / stride_w + 1;
  847. int outh = (h - kernel_extent_h) / stride_h + 1;
  848. int out_elempack = (support_packing && opt.use_packing_layout && num_output % 4 == 0) ? 4 : 1;
  849. size_t out_elemsize = elemsize / elempack * out_elempack;
  850. top_blob.create(outw, outh, num_output / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
  851. if (top_blob.empty())
  852. return -100;
  853. // depth-wise
  854. if (channels * elempack == group && group == num_output)
  855. {
  856. #if __ARM_NEON
  857. if (elempack == 4)
  858. {
  859. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  860. {
  861. convdw3x3s1_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  862. if (activation)
  863. {
  864. activation->forward_inplace(top_blob, opt);
  865. }
  866. }
  867. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  868. {
  869. convdw3x3s2_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  870. if (activation)
  871. {
  872. activation->forward_inplace(top_blob, opt);
  873. }
  874. }
  875. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  876. {
  877. convdw5x5s1_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  878. if (activation)
  879. {
  880. activation->forward_inplace(top_blob, opt);
  881. }
  882. }
  883. else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  884. {
  885. convdw5x5s2_pack4_bf16s_neon(bottom_blob_bordered, top_blob, weight_data_pack4_bf16, bias_data, opt);
  886. if (activation)
  887. {
  888. activation->forward_inplace(top_blob, opt);
  889. }
  890. }
  891. else
  892. {
  893. const int maxk = kernel_w * kernel_h;
  894. // kernel offsets
  895. std::vector<int> _space_ofs(maxk);
  896. int* space_ofs = &_space_ofs[0];
  897. {
  898. int p1 = 0;
  899. int p2 = 0;
  900. int gap = w * dilation_h - kernel_w * dilation_w;
  901. for (int i = 0; i < kernel_h; i++)
  902. {
  903. for (int j = 0; j < kernel_w; j++)
  904. {
  905. space_ofs[p1] = p2;
  906. p1++;
  907. p2 += dilation_w;
  908. }
  909. p2 += gap;
  910. }
  911. }
  912. #pragma omp parallel for num_threads(opt.num_threads)
  913. for (int g = 0; g < channels; g++)
  914. {
  915. unsigned short* outptr = top_blob.channel(g);
  916. const unsigned short* kptr = (const unsigned short*)weight_data_pack4_bf16 + maxk * g * 4;
  917. const Mat m = bottom_blob_bordered.channel(g);
  918. for (int i = 0; i < outh; i++)
  919. {
  920. for (int j = 0; j < outw; j++)
  921. {
  922. float32x4_t _sum = vdupq_n_f32(0.f);
  923. if (bias_term)
  924. {
  925. _sum = vld1q_f32(((const float*)bias_data) + g * 4);
  926. }
  927. const unsigned short* sptr = m.row<const unsigned short>(i * stride_h) + j * stride_w * 4;
  928. for (int k = 0; k < maxk; k++)
  929. {
  930. float32x4_t _val = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(sptr + space_ofs[k] * 4), 16));
  931. float32x4_t _w = vreinterpretq_f32_u32(vshll_n_u16(vld1_u16(kptr + k * 4), 16));
  932. _sum = vmlaq_f32(_sum, _val, _w);
  933. }
  934. _sum = activation_ps(_sum, activation_type, activation_params);
  935. vst1_u16(outptr + j * 4, vshrn_n_u32(vreinterpretq_u32_f32(_sum), 16));
  936. }
  937. outptr += outw * 4;
  938. }
  939. }
  940. }
  941. return 0;
  942. }
  943. #endif // __ARM_NEON
  944. if (elempack == 1)
  945. {
  946. // if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  947. // {
  948. // convdw3x3s1_neon(bottom_blob_bordered, top_blob, weight_data_bf16, bias_data, opt);
  949. //
  950. // if (activation)
  951. // {
  952. // activation->forward_inplace(top_blob, opt);
  953. // }
  954. //
  955. // return 0;
  956. // }
  957. // else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  958. // {
  959. // convdw3x3s2_neon(bottom_blob_bordered, top_blob, weight_data_bf16, bias_data, opt);
  960. //
  961. // if (activation)
  962. // {
  963. // activation->forward_inplace(top_blob, opt);
  964. // }
  965. //
  966. // return 0;
  967. // }
  968. // else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  969. // {
  970. // convdw5x5s1_neon(bottom_blob_bordered, top_blob, weight_data_bf16, bias_data, opt);
  971. //
  972. // if (activation)
  973. // {
  974. // activation->forward_inplace(top_blob, opt);
  975. // }
  976. //
  977. // return 0;
  978. // }
  979. // else if (kernel_w == 5 && kernel_h == 5 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  980. // {
  981. // convdw5x5s2_neon(bottom_blob_bordered, top_blob, weight_data_bf16, bias_data, opt);
  982. //
  983. // if (activation)
  984. // {
  985. // activation->forward_inplace(top_blob, opt);
  986. // }
  987. //
  988. // return 0;
  989. // }
  990. // else
  991. {
  992. const int maxk = kernel_w * kernel_h;
  993. // kernel offsets
  994. std::vector<int> _space_ofs(maxk);
  995. int* space_ofs = &_space_ofs[0];
  996. {
  997. int p1 = 0;
  998. int p2 = 0;
  999. int gap = w * dilation_h - kernel_w * dilation_w;
  1000. for (int i = 0; i < kernel_h; i++)
  1001. {
  1002. for (int j = 0; j < kernel_w; j++)
  1003. {
  1004. space_ofs[p1] = p2;
  1005. p1++;
  1006. p2 += dilation_w;
  1007. }
  1008. p2 += gap;
  1009. }
  1010. }
  1011. #pragma omp parallel for num_threads(opt.num_threads)
  1012. for (int g = 0; g < group; g++)
  1013. {
  1014. unsigned short* outptr = top_blob.channel(g);
  1015. const unsigned short* kptr = (const unsigned short*)weight_data_bf16 + maxk * g;
  1016. const Mat m = bottom_blob_bordered.channel(g);
  1017. for (int i = 0; i < outh; i++)
  1018. {
  1019. for (int j = 0; j < outw; j++)
  1020. {
  1021. float sum = 0.f;
  1022. if (bias_term)
  1023. sum = bias_data[g];
  1024. const unsigned short* sptr = m.row<const unsigned short>(i * stride_h) + j * stride_w;
  1025. for (int k = 0; k < maxk; k++)
  1026. {
  1027. float val = bfloat16_to_float32(sptr[space_ofs[k]]);
  1028. float w = bfloat16_to_float32(kptr[k]);
  1029. sum += val * w;
  1030. }
  1031. if (activation_type == 1)
  1032. {
  1033. sum = std::max(sum, 0.f);
  1034. }
  1035. else if (activation_type == 2)
  1036. {
  1037. float slope = activation_params[0];
  1038. sum = sum > 0.f ? sum : sum * slope;
  1039. }
  1040. else if (activation_type == 3)
  1041. {
  1042. float min = activation_params[0];
  1043. float max = activation_params[1];
  1044. if (sum < min)
  1045. sum = min;
  1046. if (sum > max)
  1047. sum = max;
  1048. }
  1049. else if (activation_type == 4)
  1050. {
  1051. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  1052. }
  1053. else if (activation_type == 5)
  1054. {
  1055. sum = static_cast<float>(sum * tanh(log(exp(sum) + 1.f)));
  1056. }
  1057. outptr[j] = float32_to_bfloat16(sum);
  1058. }
  1059. outptr += outw;
  1060. }
  1061. }
  1062. }
  1063. }
  1064. return 0;
  1065. }
  1066. // group convolution
  1067. const int channels_g = channels * elempack / group;
  1068. const int num_output_g = num_output / group;
  1069. int g_elempack = (support_packing && opt.use_packing_layout && channels_g % 4 == 0) ? 4 : 1;
  1070. int out_g_elempack = (support_packing && opt.use_packing_layout && num_output_g % 4 == 0) ? 4 : 1;
  1071. // unpacking
  1072. Mat bottom_blob_bordered_unpacked = bottom_blob_bordered;
  1073. if (elempack == 4 && g_elempack == 1)
  1074. {
  1075. Option opt_p = opt;
  1076. opt_p.blob_allocator = opt.workspace_allocator;
  1077. convert_packing(bottom_blob_bordered, bottom_blob_bordered_unpacked, 1, opt_p);
  1078. }
  1079. Mat top_blob_unpacked = top_blob;
  1080. if (out_g_elempack == 1 && out_elempack == 4)
  1081. {
  1082. top_blob_unpacked.create(outw, outh, num_output, out_elemsize / out_elempack, 1, opt.workspace_allocator);
  1083. if (top_blob_unpacked.empty())
  1084. return -100;
  1085. }
  1086. for (int g = 0; g < group; g++)
  1087. {
  1088. const Mat bottom_blob_bordered_g = bottom_blob_bordered_unpacked.channel_range(channels_g * g / g_elempack, channels_g / g_elempack);
  1089. Mat top_blob_g = top_blob_unpacked.channel_range(num_output_g * g / out_g_elempack, num_output_g / out_g_elempack);
  1090. const ncnn::Layer* op = group_ops[g];
  1091. Option opt_g = opt;
  1092. opt_g.blob_allocator = top_blob_unpacked.allocator;
  1093. // forward
  1094. op->forward(bottom_blob_bordered_g, top_blob_g, opt_g);
  1095. }
  1096. // packing
  1097. if (out_g_elempack == 1 && out_elempack == 4)
  1098. {
  1099. convert_packing(top_blob_unpacked, top_blob, 4, opt);
  1100. }
  1101. else
  1102. {
  1103. top_blob = top_blob_unpacked;
  1104. }
  1105. return 0;
  1106. }
  1107. int ConvolutionDepthWise_arm::forward_int8_arm(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  1108. {
  1109. int w = bottom_blob.w;
  1110. int h = bottom_blob.h;
  1111. int channels = bottom_blob.c;
  1112. size_t elemsize = bottom_blob.elemsize;
  1113. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  1114. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  1115. Mat bottom_blob_unbordered = bottom_blob;
  1116. if (elemsize != 1)
  1117. {
  1118. bottom_blob_unbordered.create(w, h, channels, (size_t)1u, opt.workspace_allocator);
  1119. if (bottom_blob_unbordered.empty())
  1120. return -100;
  1121. const int channels_g = channels / group;
  1122. // quantize, scale and round to nearest
  1123. #pragma omp parallel for num_threads(opt.num_threads)
  1124. for (int g = 0; g < group; g++)
  1125. {
  1126. Option opt_g = opt;
  1127. opt_g.num_threads = 1;
  1128. opt_g.blob_allocator = bottom_blob_unbordered.allocator;
  1129. const Mat bottom_blob_g = bottom_blob.channel_range(channels_g * g, channels_g);
  1130. Mat bottom_blob_int8_g = bottom_blob_unbordered.channel_range(channels_g * g, channels_g);
  1131. quantize_float32_to_int8(bottom_blob_g, bottom_blob_int8_g, bottom_blob_int8_scales[g], opt_g);
  1132. }
  1133. }
  1134. Mat bottom_blob_bordered;
  1135. make_padding(bottom_blob_unbordered, bottom_blob_bordered, opt);
  1136. if (bottom_blob_bordered.empty())
  1137. return -100;
  1138. w = bottom_blob_bordered.w;
  1139. h = bottom_blob_bordered.h;
  1140. int outw = (w - kernel_extent_w) / stride_w + 1;
  1141. int outh = (h - kernel_extent_h) / stride_h + 1;
  1142. // int8
  1143. size_t out_elemsize = use_int8_requantize ? 1u : 4u;
  1144. top_blob.create(outw, outh, num_output, out_elemsize, opt.blob_allocator);
  1145. if (top_blob.empty())
  1146. return -100;
  1147. // depth-wise
  1148. if (channels == group && group == num_output)
  1149. {
  1150. if (use_int8_requantize)
  1151. {
  1152. std::vector<float> requantize_scales;
  1153. for (int g = 0; g < group; g++)
  1154. {
  1155. float scale_in;
  1156. if (weight_data_int8_scales[g] == 0)
  1157. scale_in = 0;
  1158. else
  1159. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  1160. float scale_out = top_blob_int8_scale;
  1161. requantize_scales.push_back(scale_in);
  1162. requantize_scales.push_back(scale_out);
  1163. }
  1164. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1165. {
  1166. convdw3x3s1_int8_requant_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, requantize_scales, opt);
  1167. if (activation)
  1168. {
  1169. activation->forward_inplace(top_blob, opt);
  1170. }
  1171. return 0;
  1172. }
  1173. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1174. {
  1175. convdw3x3s2_int8_requant_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, requantize_scales, opt);
  1176. if (activation)
  1177. {
  1178. activation->forward_inplace(top_blob, opt);
  1179. }
  1180. return 0;
  1181. }
  1182. }
  1183. else
  1184. {
  1185. // std::vector<float> dequantize_scales;
  1186. // for (int g=0; g<group; g++)
  1187. // {
  1188. // float top_rescale = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  1189. //
  1190. // dequantize_scales.push_back(top_rescale);
  1191. // }
  1192. if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1)
  1193. {
  1194. convdw3x3s1_int8_neon(bottom_blob_bordered, top_blob, weight_data, opt);
  1195. // convdw3x3s1_int8_dequant_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, dequantize_scales, opt);
  1196. // dequantize, reverse scale inplace
  1197. #pragma omp parallel for num_threads(opt.num_threads)
  1198. for (int g = 0; g < group; g++)
  1199. {
  1200. // dequantize and relu
  1201. float scale_in;
  1202. if (weight_data_int8_scales[g] == 0)
  1203. scale_in = 0;
  1204. else
  1205. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  1206. Option opt_g = opt;
  1207. opt_g.num_threads = 1;
  1208. opt_g.blob_allocator = top_blob.allocator;
  1209. Mat top_blob_g = top_blob.channel(g);
  1210. dequantize_int32_to_float32(top_blob_g, scale_in, bias_term ? (const float*)bias_data + g : 0, bias_term ? 0 : 1, opt_g);
  1211. }
  1212. if (activation)
  1213. {
  1214. activation->forward_inplace(top_blob, opt);
  1215. }
  1216. return 0;
  1217. }
  1218. else if (kernel_w == 3 && kernel_h == 3 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2)
  1219. {
  1220. convdw3x3s2_int8_neon(bottom_blob_bordered, top_blob, weight_data, opt);
  1221. // convdw3x3s2_int8_dequant_neon(bottom_blob_bordered, top_blob, weight_data, bias_data, dequantize_scales, opt);
  1222. // dequantize, reverse scale inplace
  1223. #pragma omp parallel for num_threads(opt.num_threads)
  1224. for (int g = 0; g < group; g++)
  1225. {
  1226. // dequantize and relu
  1227. float scale_in;
  1228. if (weight_data_int8_scales[g] == 0)
  1229. scale_in = 0;
  1230. else
  1231. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  1232. Option opt_g = opt;
  1233. opt_g.num_threads = 1;
  1234. opt_g.blob_allocator = top_blob.allocator;
  1235. Mat top_blob_g = top_blob.channel(g);
  1236. dequantize_int32_to_float32(top_blob_g, scale_in, bias_term ? (const float*)bias_data + g : 0, bias_term ? 0 : 1, opt_g);
  1237. }
  1238. if (activation)
  1239. {
  1240. activation->forward_inplace(top_blob, opt);
  1241. }
  1242. return 0;
  1243. }
  1244. }
  1245. }
  1246. // group convolution
  1247. const int channels_g = channels / group;
  1248. const int num_output_g = num_output / group;
  1249. #pragma omp parallel for num_threads(opt.num_threads)
  1250. for (int g = 0; g < group; g++)
  1251. {
  1252. const Mat bottom_blob_bordered_g = bottom_blob_bordered.channel_range(channels_g * g, channels_g);
  1253. Mat top_blob_g = top_blob.channel_range(num_output_g * g, num_output_g);
  1254. const ncnn::Layer* op = group_ops[g];
  1255. Option opt_g = opt;
  1256. opt_g.blob_allocator = top_blob.allocator;
  1257. // forward
  1258. op->forward(bottom_blob_bordered_g, top_blob_g, opt_g);
  1259. }
  1260. return 0;
  1261. }
  1262. } // namespace ncnn