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.

softmax_arm.cpp 17 kB

8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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 "softmax_arm.h"
  15. #include <float.h>
  16. #include <math.h>
  17. #if __ARM_NEON
  18. #include <arm_neon.h>
  19. #include "neon_mathfun.h"
  20. #endif // __ARM_NEON
  21. namespace ncnn {
  22. DEFINE_LAYER_CREATOR(Softmax_arm)
  23. Softmax_arm::Softmax_arm()
  24. {
  25. #if __ARM_NEON
  26. support_packing = true;
  27. #endif // __ARM_NEON
  28. }
  29. int Softmax_arm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
  30. {
  31. int dims = bottom_top_blob.dims;
  32. size_t elemsize = bottom_top_blob.elemsize;
  33. int elempack = bottom_top_blob.elempack;
  34. #if __ARM_NEON
  35. if (opt.use_packing_layout)
  36. {
  37. if (elempack == 4)
  38. {
  39. if (dims == 1) // axis == 0
  40. {
  41. int w = bottom_top_blob.w;
  42. float* ptr = bottom_top_blob;
  43. float32x4_t _max = vdupq_n_f32(-FLT_MAX);
  44. for (int i=0; i<w; i++)
  45. {
  46. float32x4_t _p = vld1q_f32(ptr + i * 4);
  47. _max = vmaxq_f32(_max, _p);
  48. }
  49. #if __aarch64__
  50. _max = vpmaxq_f32(_max, _max);
  51. _max = vpmaxq_f32(_max, _max);
  52. #else
  53. _max = vmaxq_f32(_max, vrev64q_f32(_max));
  54. _max = vmaxq_f32(_max, vextq_f32(_max, _max, 2));
  55. #endif
  56. float32x4_t _sum = vdupq_n_f32(0.f);
  57. for (int i=0; i<w; i++)
  58. {
  59. float32x4_t _p = vld1q_f32(ptr + i * 4);
  60. _p = exp_ps(vsubq_f32(_p, _max));
  61. vst1q_f32(ptr + i * 4, _p);
  62. _sum = vaddq_f32(_sum, _p);
  63. }
  64. #if __aarch64__
  65. _sum = vpaddq_f32(_sum, _sum);
  66. _sum = vpaddq_f32(_sum, _sum);
  67. #else
  68. _sum = vaddq_f32(_sum, vrev64q_f32(_sum));
  69. _sum = vaddq_f32(_sum, vextq_f32(_sum, _sum, 2));
  70. #endif
  71. for (int i=0; i<w; i++)
  72. {
  73. float32x4_t _p = vld1q_f32(ptr + i * 4);
  74. #if __aarch64__
  75. _p = vdivq_f32(_p, _sum);
  76. #else
  77. _p = div_ps(_p, _sum);
  78. #endif
  79. vst1q_f32(ptr + i * 4, _p);
  80. }
  81. return 0;
  82. }
  83. if (dims == 2 && axis == 0)
  84. {
  85. int w = bottom_top_blob.w;
  86. int h = bottom_top_blob.h;
  87. Mat max;
  88. max.create(w, 4u, 1, opt.workspace_allocator);
  89. if (max.empty())
  90. return -100;
  91. max.fill(-FLT_MAX);
  92. for (int i=0; i<h; i++)
  93. {
  94. const float* ptr = bottom_top_blob.row(i);
  95. for (int j=0; j<w; j++)
  96. {
  97. float32x4_t _p = vld1q_f32(ptr);
  98. #if __aarch64__
  99. float max0 = vmaxvq_f32(_p);
  100. #else
  101. float32x2_t _max2 = vmax_f32(vget_low_f32(_p), vget_high_f32(_p));
  102. float32x2_t _mm2 = vpmax_f32(_max2, _max2);
  103. float max0 = vget_lane_f32(_mm2, 0);
  104. #endif
  105. max[j] = std::max(max[j], max0);
  106. ptr += 4;
  107. }
  108. }
  109. Mat sum;
  110. sum.create(w, 4u, 1, opt.workspace_allocator);
  111. if (sum.empty())
  112. return -100;
  113. sum.fill(0.f);
  114. for (int i=0; i<h; i++)
  115. {
  116. float* ptr = bottom_top_blob.row(i);
  117. for (int j=0; j<w; j++)
  118. {
  119. float32x4_t _p = vld1q_f32(ptr);
  120. float32x4_t _max = vdupq_n_f32(max[j]);
  121. _p = exp_ps(vsubq_f32(_p, _max));
  122. vst1q_f32(ptr, _p);
  123. #if __aarch64__
  124. float sum0 = vaddvq_f32(_p);
  125. #else
  126. float32x2_t _sum2 = vadd_f32(vget_low_f32(_p), vget_high_f32(_p));
  127. float32x2_t _ss2 = vpadd_f32(_sum2, _sum2);
  128. float sum0 = vget_lane_f32(_ss2, 0);
  129. #endif
  130. sum[j] += sum0;
  131. ptr += 4;
  132. }
  133. }
  134. for (int i=0; i<h; i++)
  135. {
  136. float* ptr = bottom_top_blob.row(i);
  137. for (int j=0; j<w; j++)
  138. {
  139. float32x4_t _p = vld1q_f32(ptr);
  140. float32x4_t _sum = vdupq_n_f32(sum[j]);
  141. #if __aarch64__
  142. _p = vdivq_f32(_p, _sum);
  143. #else
  144. _p = div_ps(_p, _sum);
  145. #endif
  146. vst1q_f32(ptr, _p);
  147. ptr += 4;
  148. }
  149. }
  150. return 0;
  151. }
  152. if (dims == 2 && axis == 1)
  153. {
  154. int w = bottom_top_blob.w;
  155. int h = bottom_top_blob.h;
  156. #pragma omp parallel for num_threads(opt.num_threads)
  157. for (int i=0; i<h; i++)
  158. {
  159. float* ptr = bottom_top_blob.row(i);
  160. float32x4_t _max = vdupq_n_f32(-FLT_MAX);
  161. for (int j=0; j<w; j++)
  162. {
  163. float32x4_t _p = vld1q_f32(ptr + j * 4);
  164. _max = vmaxq_f32(_max, _p);
  165. }
  166. float32x4_t _sum = vdupq_n_f32(0.f);
  167. for (int j=0; j<w; j++)
  168. {
  169. float32x4_t _p = vld1q_f32(ptr + j * 4);
  170. _p = exp_ps(vsubq_f32(_p, _max));
  171. vst1q_f32(ptr + j * 4, _p);
  172. _sum = vaddq_f32(_sum, _p);
  173. }
  174. for (int j=0; j<w; j++)
  175. {
  176. float32x4_t _p = vld1q_f32(ptr + j * 4);
  177. #if __aarch64__
  178. _p = vdivq_f32(_p, _sum);
  179. #else
  180. _p = div_ps(_p, _sum);
  181. #endif
  182. vst1q_f32(ptr + j * 4, _p);
  183. }
  184. }
  185. return 0;
  186. }
  187. if (dims == 3 && axis == 0)
  188. {
  189. int w = bottom_top_blob.w;
  190. int h = bottom_top_blob.h;
  191. int channels = bottom_top_blob.c;
  192. int size = w * h;
  193. Mat max;
  194. max.create(w, h, 4u, 1, opt.workspace_allocator);
  195. if (max.empty())
  196. return -100;
  197. max.fill(-FLT_MAX);
  198. for (int q=0; q<channels; q++)
  199. {
  200. const float* ptr = bottom_top_blob.channel(q);
  201. for (int i=0; i<size; i++)
  202. {
  203. float32x4_t _p = vld1q_f32(ptr);
  204. #if __aarch64__
  205. float max0 = vmaxvq_f32(_p);
  206. #else
  207. float32x2_t _max2 = vmax_f32(vget_low_f32(_p), vget_high_f32(_p));
  208. float32x2_t _mm2 = vpmax_f32(_max2, _max2);
  209. float max0 = vget_lane_f32(_mm2, 0);
  210. #endif
  211. max[i] = std::max(max[i], max0);
  212. ptr += 4;
  213. }
  214. }
  215. Mat sum;
  216. sum.create(w, h, 4u, 1, opt.workspace_allocator);
  217. if (sum.empty())
  218. return -100;
  219. sum.fill(0.f);
  220. for (int q=0; q<channels; q++)
  221. {
  222. float* ptr = bottom_top_blob.channel(q);
  223. for (int i=0; i<size; i++)
  224. {
  225. float32x4_t _p = vld1q_f32(ptr);
  226. float32x4_t _max = vdupq_n_f32(max[i]);
  227. _p = exp_ps(vsubq_f32(_p, _max));
  228. vst1q_f32(ptr, _p);
  229. #if __aarch64__
  230. float sum0 = vaddvq_f32(_p);
  231. #else
  232. float32x2_t _sum2 = vadd_f32(vget_low_f32(_p), vget_high_f32(_p));
  233. float32x2_t _ss2 = vpadd_f32(_sum2, _sum2);
  234. float sum0 = vget_lane_f32(_ss2, 0);
  235. #endif
  236. sum[i] += sum0;
  237. ptr += 4;
  238. }
  239. }
  240. #pragma omp parallel for num_threads(opt.num_threads)
  241. for (int q=0; q<channels; q++)
  242. {
  243. float* ptr = bottom_top_blob.channel(q);
  244. for (int i=0; i<size; i++)
  245. {
  246. float32x4_t _p = vld1q_f32(ptr);
  247. float32x4_t _sum = vdupq_n_f32(sum[i]);
  248. #if __aarch64__
  249. _p = vdivq_f32(_p, _sum);
  250. #else
  251. _p = div_ps(_p, _sum);
  252. #endif
  253. vst1q_f32(ptr, _p);
  254. ptr += 4;
  255. }
  256. }
  257. return 0;
  258. }
  259. if (dims == 3 && axis == 1)
  260. {
  261. int w = bottom_top_blob.w;
  262. int h = bottom_top_blob.h;
  263. int channels = bottom_top_blob.c;
  264. Mat max;
  265. max.create(w, channels, elemsize, elempack, opt.workspace_allocator);
  266. if (max.empty())
  267. return -100;
  268. max.fill(vdupq_n_f32(-FLT_MAX));
  269. #pragma omp parallel for num_threads(opt.num_threads)
  270. for (int q=0; q<channels; q++)
  271. {
  272. const float* ptr = bottom_top_blob.channel(q);
  273. for (int i=0; i<h; i++)
  274. {
  275. float* maxptr = max.row(q);
  276. for (int j=0; j<w; j++)
  277. {
  278. float32x4_t _p = vld1q_f32(ptr);
  279. float32x4_t _max = vld1q_f32(maxptr);
  280. _max = vmaxq_f32(_max, _p);
  281. vst1q_f32(maxptr, _max);
  282. ptr += 4;
  283. maxptr += 4;
  284. }
  285. }
  286. }
  287. Mat sum;
  288. sum.create(w, channels, elemsize, elempack, opt.workspace_allocator);
  289. if (sum.empty())
  290. return -100;
  291. sum.fill(vdupq_n_f32(0.f));
  292. #pragma omp parallel for num_threads(opt.num_threads)
  293. for (int q=0; q<channels; q++)
  294. {
  295. float* ptr = bottom_top_blob.channel(q);
  296. for (int i=0; i<h; i++)
  297. {
  298. float* maxptr = max.row(q);
  299. float* sumptr = sum.row(q);
  300. for (int j=0; j<w; j++)
  301. {
  302. float32x4_t _p = vld1q_f32(ptr);
  303. float32x4_t _max = vld1q_f32(maxptr);
  304. _p = exp_ps(vsubq_f32(_p, _max));
  305. vst1q_f32(ptr, _p);
  306. float32x4_t _sum = vld1q_f32(sumptr);
  307. _sum = vaddq_f32(_sum, _p);
  308. vst1q_f32(sumptr, _sum);
  309. ptr += 4;
  310. maxptr += 4;
  311. sumptr += 4;
  312. }
  313. }
  314. }
  315. #pragma omp parallel for num_threads(opt.num_threads)
  316. for (int q=0; q<channels; q++)
  317. {
  318. float* ptr = bottom_top_blob.channel(q);
  319. for (int i=0; i<h; i++)
  320. {
  321. float* sumptr = sum.row(q);
  322. for (int j=0; j<w; j++)
  323. {
  324. float32x4_t _p = vld1q_f32(ptr);
  325. float32x4_t _sum = vld1q_f32(sumptr);
  326. #if __aarch64__
  327. _p = vdivq_f32(_p, _sum);
  328. #else
  329. _p = div_ps(_p, _sum);
  330. #endif
  331. vst1q_f32(ptr, _p);
  332. ptr += 4;
  333. sumptr += 4;
  334. }
  335. }
  336. }
  337. return 0;
  338. }
  339. if (dims == 3 && axis == 2)
  340. {
  341. int w = bottom_top_blob.w;
  342. int h = bottom_top_blob.h;
  343. int channels = bottom_top_blob.c;
  344. #pragma omp parallel for num_threads(opt.num_threads)
  345. for (int q=0; q<channels; q++)
  346. {
  347. float* ptr = bottom_top_blob.channel(q);
  348. for (int i=0; i<h; i++)
  349. {
  350. float32x4_t _max = vdupq_n_f32(-FLT_MAX);
  351. for (int j=0; j<w; j++)
  352. {
  353. float32x4_t _p = vld1q_f32(ptr + j * 4);
  354. _max = vmaxq_f32(_max, _p);
  355. }
  356. float32x4_t _sum = vdupq_n_f32(0.f);
  357. for (int j=0; j<w; j++)
  358. {
  359. float32x4_t _p = vld1q_f32(ptr + j * 4);
  360. _p = exp_ps(vsubq_f32(_p, _max));
  361. vst1q_f32(ptr + j * 4, _p);
  362. _sum = vaddq_f32(_sum, _p);
  363. }
  364. for (int j=0; j<w; j++)
  365. {
  366. float32x4_t _p = vld1q_f32(ptr + j * 4);
  367. #if __aarch64__
  368. _p = vdivq_f32(_p, _sum);
  369. #else
  370. _p = div_ps(_p, _sum);
  371. #endif
  372. vst1q_f32(ptr + j * 4, _p);
  373. }
  374. ptr += w * 4;
  375. }
  376. }
  377. return 0;
  378. }
  379. return 0;
  380. }
  381. } // opt.use_packing_layout
  382. #endif // __ARM_NEON
  383. if (dims != 3 || axis != 0)
  384. return Softmax::forward_inplace(bottom_top_blob, opt);
  385. // value = exp( value - global max value )
  386. // sum all value
  387. // value = value / sum
  388. int w = bottom_top_blob.w;
  389. int h = bottom_top_blob.h;
  390. int channels = bottom_top_blob.c;
  391. int size = w * h;
  392. Mat max;
  393. max.create(w, h, elemsize, opt.workspace_allocator);
  394. if (max.empty())
  395. return -100;
  396. max.fill(-FLT_MAX);
  397. for (int q=0; q<channels; q++)
  398. {
  399. float* ptr = bottom_top_blob.channel(q);
  400. float* maxptr = max;
  401. for (int i=0; i<size; i++)
  402. {
  403. maxptr[i] = std::max(maxptr[i], ptr[i]);
  404. }
  405. }
  406. #pragma omp parallel for num_threads(opt.num_threads)
  407. for (int q=0; q<channels; q++)
  408. {
  409. float* ptr = bottom_top_blob.channel(q);
  410. float* maxptr = max;
  411. #if __ARM_NEON
  412. int nn = size >> 2;
  413. int remain = size - (nn << 2);
  414. #else
  415. int remain = size;
  416. #endif // __ARM_NEON
  417. #if __ARM_NEON
  418. for (; nn>0; nn--)
  419. {
  420. float32x4_t _p = vld1q_f32(ptr);
  421. float32x4_t _max = vld1q_f32(maxptr);
  422. _p = exp_ps(vsubq_f32(_p, _max));
  423. vst1q_f32(ptr, _p);
  424. ptr += 4;
  425. maxptr += 4;
  426. }
  427. #endif // __ARM_NEON
  428. for (; remain>0; remain--)
  429. {
  430. *ptr = exp(*ptr - *maxptr);
  431. ptr++;
  432. maxptr++;
  433. }
  434. }
  435. Mat sum;
  436. sum.create(w, h, elemsize, opt.workspace_allocator);
  437. if (sum.empty())
  438. return -100;
  439. sum.fill(0.f);
  440. for (int q=0; q<channels; q++)
  441. {
  442. float* ptr = bottom_top_blob.channel(q);
  443. float* sumptr = sum;
  444. #if __ARM_NEON
  445. int nn = size >> 2;
  446. int remain = size - (nn << 2);
  447. #else
  448. int remain = size;
  449. #endif // __ARM_NEON
  450. #if __ARM_NEON
  451. for (; nn>0; nn--)
  452. {
  453. float32x4_t _p = vld1q_f32(ptr);
  454. float32x4_t _sum = vld1q_f32(sumptr);
  455. _sum = vaddq_f32(_sum, _p);
  456. vst1q_f32(sumptr, _sum);
  457. ptr += 4;
  458. sumptr += 4;
  459. }
  460. #endif // __ARM_NEON
  461. for (; remain>0; remain--)
  462. {
  463. *sumptr += *ptr;
  464. ptr++;
  465. sumptr++;
  466. }
  467. }
  468. #pragma omp parallel for num_threads(opt.num_threads)
  469. for (int q=0; q<channels; q++)
  470. {
  471. float* ptr = bottom_top_blob.channel(q);
  472. float* sumptr = sum;
  473. #if __ARM_NEON
  474. int nn = size >> 2;
  475. int remain = size - (nn << 2);
  476. #else
  477. int remain = size;
  478. #endif // __ARM_NEON
  479. #if __ARM_NEON
  480. for (; nn>0; nn--)
  481. {
  482. float32x4_t _p = vld1q_f32(ptr);
  483. float32x4_t _sum = vld1q_f32(sumptr);
  484. #if __aarch64__
  485. _p = vdivq_f32(_p, _sum);
  486. #else
  487. _p = div_ps(_p, _sum);
  488. #endif // __aarch64__
  489. vst1q_f32(ptr, _p);
  490. ptr += 4;
  491. sumptr += 4;
  492. }
  493. #endif // __ARM_NEON
  494. for (; remain>0; remain--)
  495. {
  496. *ptr /= *sumptr;
  497. ptr++;
  498. sumptr++;
  499. }
  500. }
  501. return 0;
  502. }
  503. } // namespace ncnn