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.cpp 23 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  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.h"
  15. #include "layer_type.h"
  16. namespace ncnn {
  17. ConvolutionDepthWise::ConvolutionDepthWise()
  18. {
  19. one_blob_only = true;
  20. support_inplace = false;
  21. use_int8_requantize = false;
  22. }
  23. int ConvolutionDepthWise::load_param(const ParamDict& pd)
  24. {
  25. num_output = pd.get(0, 0);
  26. kernel_w = pd.get(1, 0);
  27. kernel_h = pd.get(11, kernel_w);
  28. dilation_w = pd.get(2, 1);
  29. dilation_h = pd.get(12, dilation_w);
  30. stride_w = pd.get(3, 1);
  31. stride_h = pd.get(13, stride_w);
  32. pad_left = pd.get(4, 0);
  33. pad_right = pd.get(15, pad_left);
  34. pad_top = pd.get(14, pad_left);
  35. pad_bottom = pd.get(16, pad_top);
  36. pad_value = pd.get(18, 0.f);
  37. bias_term = pd.get(5, 0);
  38. weight_data_size = pd.get(6, 0);
  39. group = pd.get(7, 1);
  40. int8_scale_term = pd.get(8, 0);
  41. activation_type = pd.get(9, 0);
  42. activation_params = pd.get(10, Mat());
  43. if (num_output % group != 0)
  44. {
  45. // reject invalid group
  46. return -100;
  47. }
  48. if (int8_scale_term)
  49. {
  50. use_int8_inference = true;
  51. }
  52. return 0;
  53. }
  54. int ConvolutionDepthWise::load_model(const ModelBin& mb)
  55. {
  56. weight_data = mb.load(weight_data_size, 0);
  57. if (weight_data.empty())
  58. return -100;
  59. if (bias_term)
  60. {
  61. bias_data = mb.load(num_output, 1);
  62. if (bias_data.empty())
  63. return -100;
  64. }
  65. if (int8_scale_term == 1)
  66. {
  67. weight_data_int8_scales = mb.load(group, 1);
  68. bottom_blob_int8_scales = mb.load(1, 1);
  69. float bottom_blob_int8_scale = bottom_blob_int8_scales[0];
  70. bottom_blob_int8_scales = Mat(group);
  71. bottom_blob_int8_scales.fill(bottom_blob_int8_scale);
  72. }
  73. else if (int8_scale_term == 2)
  74. {
  75. weight_data_int8_scales = mb.load(1, 1);
  76. bottom_blob_int8_scales = mb.load(1, 1);
  77. // extend group if only one provided
  78. float weight_data_int8_scale = weight_data_int8_scales[0];
  79. weight_data_int8_scales = Mat(group);
  80. weight_data_int8_scales.fill(weight_data_int8_scale);
  81. float bottom_blob_int8_scale = bottom_blob_int8_scales[0];
  82. bottom_blob_int8_scales = Mat(group);
  83. bottom_blob_int8_scales.fill(bottom_blob_int8_scale);
  84. }
  85. return 0;
  86. }
  87. int ConvolutionDepthWise::create_pipeline(const Option& opt)
  88. {
  89. // runtime quantize the weight data
  90. if (opt.use_int8_inference && weight_data.elemsize == (size_t)4u && int8_scale_term)
  91. {
  92. Mat int8_weight_data(weight_data_size, (size_t)1u);
  93. if (int8_weight_data.empty())
  94. return -100;
  95. const int weight_data_size_g = weight_data_size / group;
  96. for (int g = 0; g < group; g++)
  97. {
  98. Option opt_q = opt;
  99. opt_q.blob_allocator = int8_weight_data.allocator;
  100. const Mat weight_data_g = weight_data.range(weight_data_size_g * g, weight_data_size_g);
  101. Mat int8_weight_data_g = int8_weight_data.range(weight_data_size_g * g, weight_data_size_g);
  102. quantize_float32_to_int8(weight_data_g, int8_weight_data_g, weight_data_int8_scales[g], opt_q);
  103. }
  104. weight_data = int8_weight_data;
  105. }
  106. return 0;
  107. }
  108. int ConvolutionDepthWise::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  109. {
  110. // convolv with NxN kernel
  111. // value = value + bias
  112. if (opt.use_int8_inference && weight_data.elemsize == (size_t)1u)
  113. {
  114. return forward_int8(bottom_blob, top_blob, opt);
  115. }
  116. int w = bottom_blob.w;
  117. int h = bottom_blob.h;
  118. int channels = bottom_blob.c;
  119. size_t elemsize = bottom_blob.elemsize;
  120. if (channels % group != 0 || num_output % group != 0)
  121. {
  122. // reject invalid group
  123. return -100;
  124. }
  125. // NCNN_LOGE("ConvolutionDepthWise 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);
  126. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  127. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  128. Mat bottom_blob_bordered;
  129. make_padding(bottom_blob, bottom_blob_bordered, opt);
  130. if (bottom_blob_bordered.empty())
  131. return -100;
  132. w = bottom_blob_bordered.w;
  133. h = bottom_blob_bordered.h;
  134. int outw = (w - kernel_extent_w) / stride_w + 1;
  135. int outh = (h - kernel_extent_h) / stride_h + 1;
  136. const int maxk = kernel_w * kernel_h;
  137. // kernel offsets
  138. std::vector<int> _space_ofs(maxk);
  139. int* space_ofs = &_space_ofs[0];
  140. {
  141. int p1 = 0;
  142. int p2 = 0;
  143. int gap = w * dilation_h - kernel_w * dilation_w;
  144. for (int i = 0; i < kernel_h; i++)
  145. {
  146. for (int j = 0; j < kernel_w; j++)
  147. {
  148. space_ofs[p1] = p2;
  149. p1++;
  150. p2 += dilation_w;
  151. }
  152. p2 += gap;
  153. }
  154. }
  155. // float32
  156. top_blob.create(outw, outh, num_output, elemsize, opt.blob_allocator);
  157. if (top_blob.empty())
  158. return -100;
  159. // depth-wise
  160. if (channels == group && group == num_output)
  161. {
  162. #pragma omp parallel for num_threads(opt.num_threads)
  163. for (int g = 0; g < group; g++)
  164. {
  165. float* outptr = top_blob.channel(g);
  166. const float* kptr = (const float*)weight_data + maxk * g;
  167. const Mat m = bottom_blob_bordered.channel(g);
  168. for (int i = 0; i < outh; i++)
  169. {
  170. for (int j = 0; j < outw; j++)
  171. {
  172. float sum = 0.f;
  173. if (bias_term)
  174. sum = bias_data[g];
  175. const float* sptr = m.row(i * stride_h) + j * stride_w;
  176. for (int k = 0; k < maxk; k++)
  177. {
  178. float val = sptr[space_ofs[k]];
  179. float w = kptr[k];
  180. sum += val * w;
  181. }
  182. if (activation_type == 1)
  183. {
  184. sum = std::max(sum, 0.f);
  185. }
  186. else if (activation_type == 2)
  187. {
  188. float slope = activation_params[0];
  189. sum = sum > 0.f ? sum : sum * slope;
  190. }
  191. else if (activation_type == 3)
  192. {
  193. float min = activation_params[0];
  194. float max = activation_params[1];
  195. if (sum < min)
  196. sum = min;
  197. if (sum > max)
  198. sum = max;
  199. }
  200. else if (activation_type == 4)
  201. {
  202. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  203. }
  204. else if (activation_type == 5)
  205. {
  206. const float MISH_THRESHOLD = 20;
  207. float x = sum, y;
  208. if (x > MISH_THRESHOLD)
  209. y = x;
  210. else if (x < -MISH_THRESHOLD)
  211. y = expf(x);
  212. else
  213. y = logf(expf(x) + 1);
  214. sum = static_cast<float>(x * tanh(y));
  215. }
  216. outptr[j] = sum;
  217. }
  218. outptr += outw;
  219. }
  220. }
  221. }
  222. else
  223. {
  224. // group convolution
  225. const int channels_g = channels / group;
  226. const int num_output_g = num_output / group;
  227. #ifdef _WIN32
  228. #pragma omp parallel for num_threads(opt.num_threads)
  229. #else // _WIN32
  230. #pragma omp parallel for collapse(2) num_threads(opt.num_threads)
  231. #endif // _WIN32
  232. for (int g = 0; g < group; g++)
  233. {
  234. for (int p = 0; p < num_output_g; p++)
  235. {
  236. float* outptr = top_blob.channel(g * num_output_g + p);
  237. const float* weight_data_ptr = (const float*)weight_data + maxk * channels_g * num_output_g * g;
  238. for (int i = 0; i < outh; i++)
  239. {
  240. for (int j = 0; j < outw; j++)
  241. {
  242. float sum = 0.f;
  243. if (bias_term)
  244. sum = bias_data[num_output_g * g + p];
  245. const float* kptr = weight_data_ptr + maxk * channels_g * p;
  246. // channels_g
  247. for (int q = 0; q < channels_g; q++)
  248. {
  249. const Mat m = bottom_blob_bordered.channel(channels_g * g + q);
  250. const float* sptr = m.row(i * stride_h) + j * stride_w;
  251. for (int k = 0; k < maxk; k++)
  252. {
  253. float val = sptr[space_ofs[k]];
  254. float w = kptr[k];
  255. sum += val * w;
  256. }
  257. kptr += maxk;
  258. }
  259. if (activation_type == 1)
  260. {
  261. sum = std::max(sum, 0.f);
  262. }
  263. else if (activation_type == 2)
  264. {
  265. float slope = activation_params[0];
  266. sum = sum > 0.f ? sum : sum * slope;
  267. }
  268. else if (activation_type == 3)
  269. {
  270. float min = activation_params[0];
  271. float max = activation_params[1];
  272. if (sum < min)
  273. sum = min;
  274. if (sum > max)
  275. sum = max;
  276. }
  277. else if (activation_type == 4)
  278. {
  279. sum = static_cast<float>(1.f / (1.f + exp(-sum)));
  280. }
  281. else if (activation_type == 5)
  282. {
  283. const float MISH_THRESHOLD = 20;
  284. float x = sum, y;
  285. if (x > MISH_THRESHOLD)
  286. y = x;
  287. else if (x < -MISH_THRESHOLD)
  288. y = expf(x);
  289. else
  290. y = logf(expf(x) + 1);
  291. sum = static_cast<float>(x * tanh(y));
  292. }
  293. outptr[j] = sum;
  294. }
  295. outptr += outw;
  296. }
  297. }
  298. }
  299. }
  300. return 0;
  301. }
  302. void ConvolutionDepthWise::make_padding(const Mat& bottom_blob, Mat& bottom_blob_bordered, const Option& opt) const
  303. {
  304. int w = bottom_blob.w;
  305. int h = bottom_blob.h;
  306. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  307. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  308. bottom_blob_bordered = bottom_blob;
  309. if (pad_left > 0 || pad_right > 0 || pad_top > 0 || pad_bottom > 0)
  310. {
  311. Option opt_b = opt;
  312. opt_b.blob_allocator = opt.workspace_allocator;
  313. copy_make_border(bottom_blob, bottom_blob_bordered, pad_top, pad_bottom, pad_left, pad_right, BORDER_CONSTANT, pad_value, opt_b);
  314. }
  315. else if (pad_left == -233 && pad_right == -233 && pad_top == -233 && pad_bottom == -233)
  316. {
  317. // tensorflow padding=SAME or onnx padding=SAME_UPPER
  318. int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w;
  319. int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h;
  320. if (wpad > 0 || hpad > 0)
  321. {
  322. Option opt_b = opt;
  323. opt_b.blob_allocator = opt.workspace_allocator;
  324. copy_make_border(bottom_blob, bottom_blob_bordered, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, BORDER_CONSTANT, pad_value, opt_b);
  325. }
  326. }
  327. else if (pad_left == -234 && pad_right == -234 && pad_top == -234 && pad_bottom == -234)
  328. {
  329. // onnx padding=SAME_LOWER
  330. int wpad = kernel_extent_w + (w - 1) / stride_w * stride_w - w;
  331. int hpad = kernel_extent_h + (h - 1) / stride_h * stride_h - h;
  332. if (wpad > 0 || hpad > 0)
  333. {
  334. Option opt_b = opt;
  335. opt_b.blob_allocator = opt.workspace_allocator;
  336. copy_make_border(bottom_blob, bottom_blob_bordered, hpad - hpad / 2, hpad / 2, wpad - wpad / 2, wpad / 2, BORDER_CONSTANT, pad_value, opt_b);
  337. }
  338. }
  339. }
  340. static inline signed char float2int8(float v)
  341. {
  342. int int32 = static_cast<int>(round(v));
  343. if (int32 > 127) return 127;
  344. if (int32 < -127) return -127;
  345. return (signed char)int32;
  346. }
  347. int ConvolutionDepthWise::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
  348. {
  349. // convolv with NxN kernel
  350. // value = value + bias
  351. int w = bottom_blob.w;
  352. int h = bottom_blob.h;
  353. int channels = bottom_blob.c;
  354. size_t elemsize = bottom_blob.elemsize;
  355. if (channels % group != 0 || num_output % group != 0)
  356. {
  357. // reject invalid group
  358. return -100;
  359. }
  360. // NCNN_LOGE("ConvolutionDepthWise 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);
  361. const int kernel_extent_w = dilation_w * (kernel_w - 1) + 1;
  362. const int kernel_extent_h = dilation_h * (kernel_h - 1) + 1;
  363. Mat bottom_blob_unbordered = bottom_blob;
  364. if (elemsize != 1)
  365. {
  366. bottom_blob_unbordered.create(w, h, channels, (size_t)1u, opt.workspace_allocator);
  367. if (bottom_blob_unbordered.empty())
  368. return -100;
  369. const int channels_g = channels / group;
  370. // quantize, scale and round to nearest
  371. #pragma omp parallel for num_threads(opt.num_threads)
  372. for (int g = 0; g < group; g++)
  373. {
  374. Option opt_g = opt;
  375. opt_g.num_threads = 1;
  376. opt_g.blob_allocator = bottom_blob_unbordered.allocator;
  377. const Mat bottom_blob_g = bottom_blob.channel_range(channels_g * g, channels_g);
  378. Mat bottom_blob_int8_g = bottom_blob_unbordered.channel_range(channels_g * g, channels_g);
  379. quantize_float32_to_int8(bottom_blob_g, bottom_blob_int8_g, bottom_blob_int8_scales[g], opt_g);
  380. }
  381. }
  382. Mat bottom_blob_bordered;
  383. make_padding(bottom_blob_unbordered, bottom_blob_bordered, opt);
  384. if (bottom_blob_bordered.empty())
  385. return -100;
  386. w = bottom_blob_bordered.w;
  387. h = bottom_blob_bordered.h;
  388. int outw = (w - kernel_extent_w) / stride_w + 1;
  389. int outh = (h - kernel_extent_h) / stride_h + 1;
  390. const int maxk = kernel_w * kernel_h;
  391. // kernel offsets
  392. std::vector<int> _space_ofs(maxk);
  393. int* space_ofs = &_space_ofs[0];
  394. {
  395. int p1 = 0;
  396. int p2 = 0;
  397. int gap = w * dilation_h - kernel_w * dilation_w;
  398. for (int i = 0; i < kernel_h; i++)
  399. {
  400. for (int j = 0; j < kernel_w; j++)
  401. {
  402. space_ofs[p1] = p2;
  403. p1++;
  404. p2 += dilation_w;
  405. }
  406. p2 += gap;
  407. }
  408. }
  409. // int8
  410. size_t out_elemsize = use_int8_requantize ? 1u : 4u;
  411. top_blob.create(outw, outh, num_output, out_elemsize, opt.blob_allocator);
  412. if (top_blob.empty())
  413. return -100;
  414. // depth-wise
  415. if (channels == group && group == num_output)
  416. {
  417. #pragma omp parallel for num_threads(opt.num_threads)
  418. for (int g = 0; g < group; g++)
  419. {
  420. signed char* outptr = top_blob.channel(g);
  421. const signed char* kptr = (const signed char*)weight_data + maxk * g;
  422. const Mat m = bottom_blob_bordered.channel(g);
  423. for (int i = 0; i < outh; i++)
  424. {
  425. for (int j = 0; j < outw; j++)
  426. {
  427. int sum = 0;
  428. const signed char* sptr = m.row<signed char>(i * stride_h) + j * stride_w;
  429. for (int k = 0; k < maxk; k++)
  430. {
  431. signed char val = sptr[space_ofs[k]];
  432. signed char w = kptr[k];
  433. sum += val * w;
  434. }
  435. if (use_int8_requantize)
  436. {
  437. // requantize and relu
  438. float scale_in;
  439. if (weight_data_int8_scales[g] == 0)
  440. scale_in = 0;
  441. else
  442. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  443. float sumfp32 = sum * scale_in;
  444. if (bias_term)
  445. sumfp32 += bias_data[g];
  446. float scale_out = top_blob_int8_scale; //FIXME load param
  447. signed char sums8 = float2int8(sumfp32 * scale_out);
  448. if (activation_type == 1)
  449. {
  450. sums8 = std::max(sums8, (signed char)0);
  451. }
  452. outptr[0] = sums8;
  453. outptr += 1;
  454. }
  455. else
  456. {
  457. // dequantize and relu
  458. float scale_in;
  459. if (weight_data_int8_scales[g] == 0)
  460. scale_in = 0;
  461. else
  462. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  463. float sumfp32 = sum * scale_in;
  464. if (bias_term)
  465. sumfp32 += bias_data[g];
  466. if (activation_type == 1)
  467. {
  468. sumfp32 = std::max(sumfp32, 0.f);
  469. }
  470. ((float*)outptr)[0] = sumfp32;
  471. outptr += 4;
  472. }
  473. }
  474. }
  475. }
  476. }
  477. else
  478. {
  479. // group convolution
  480. const int channels_g = channels / group;
  481. const int num_output_g = num_output / group;
  482. #ifdef _WIN32
  483. #pragma omp parallel for num_threads(opt.num_threads)
  484. #else // _WIN32
  485. #pragma omp parallel for collapse(2) num_threads(opt.num_threads)
  486. #endif // _WIN32
  487. for (int g = 0; g < group; g++)
  488. {
  489. for (int p = 0; p < num_output_g; p++)
  490. {
  491. signed char* outptr = top_blob.channel(g * num_output_g + p);
  492. const signed char* weight_data_ptr = (const signed char*)weight_data + maxk * channels_g * num_output_g * g;
  493. for (int i = 0; i < outh; i++)
  494. {
  495. for (int j = 0; j < outw; j++)
  496. {
  497. int sum = 0;
  498. const signed char* kptr = weight_data_ptr + maxk * channels_g * p;
  499. // channels_g
  500. for (int q = 0; q < channels_g; q++)
  501. {
  502. const Mat m = bottom_blob_bordered.channel(channels_g * g + q);
  503. const signed char* sptr = m.row<signed char>(i * stride_h) + j * stride_w;
  504. for (int k = 0; k < maxk; k++)
  505. {
  506. signed char val = sptr[space_ofs[k]];
  507. signed char w = kptr[k];
  508. sum += val * w;
  509. }
  510. kptr += maxk;
  511. }
  512. if (use_int8_requantize)
  513. {
  514. // requantize and relu
  515. float scale_in;
  516. if (weight_data_int8_scales[g] == 0)
  517. scale_in = 0;
  518. else
  519. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  520. float sumfp32 = sum * scale_in;
  521. if (bias_term)
  522. sumfp32 += bias_data[g * num_output_g + p];
  523. float scale_out = top_blob_int8_scale; //FIXME load param
  524. signed char sums8 = float2int8(sumfp32 * scale_out);
  525. if (activation_type == 1)
  526. {
  527. sums8 = std::max(sums8, (signed char)0);
  528. }
  529. outptr[0] = sums8;
  530. outptr += 1;
  531. }
  532. else
  533. {
  534. // dequantize and relu
  535. float scale_in;
  536. if (weight_data_int8_scales[g] == 0)
  537. scale_in = 0;
  538. else
  539. scale_in = 1.f / (bottom_blob_int8_scales[g] * weight_data_int8_scales[g]);
  540. float sumfp32 = sum * scale_in;
  541. if (bias_term)
  542. sumfp32 += bias_data[g * num_output_g + p];
  543. if (activation_type == 1)
  544. {
  545. sumfp32 = std::max(sumfp32, 0.f);
  546. }
  547. ((float*)outptr)[0] = sumfp32;
  548. outptr += 4;
  549. }
  550. }
  551. }
  552. }
  553. }
  554. }
  555. return 0;
  556. }
  557. } // namespace ncnn