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.

swish_arm.cpp 8.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 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 "swish_arm.h"
  15. #if __ARM_NEON
  16. #include "neon_mathfun.h"
  17. #include <arm_neon.h>
  18. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  19. #include "neon_mathfun_fp16s.h"
  20. #endif
  21. #endif // __ARM_NEON
  22. #include <math.h>
  23. namespace ncnn {
  24. Swish_arm::Swish_arm()
  25. {
  26. #if __ARM_NEON
  27. support_packing = true;
  28. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  29. support_fp16_storage = true;
  30. #endif
  31. #endif // __ARM_NEON
  32. support_bf16_storage = true;
  33. }
  34. int Swish_arm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
  35. {
  36. int elembits = bottom_top_blob.elembits();
  37. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  38. if (opt.use_fp16_storage && elembits == 16)
  39. {
  40. if (opt.use_fp16_arithmetic)
  41. return forward_inplace_fp16sa(bottom_top_blob, opt);
  42. else
  43. return forward_inplace_fp16s(bottom_top_blob, opt);
  44. }
  45. #endif
  46. if (opt.use_bf16_storage && elembits == 16)
  47. return forward_inplace_bf16s(bottom_top_blob, opt);
  48. int w = bottom_top_blob.w;
  49. int h = bottom_top_blob.h;
  50. int channels = bottom_top_blob.c;
  51. int size = w * h;
  52. int elempack = bottom_top_blob.elempack;
  53. #if __ARM_NEON
  54. if (elempack == 4)
  55. {
  56. #pragma omp parallel for num_threads(opt.num_threads)
  57. for (int q = 0; q < channels; q++)
  58. {
  59. float* ptr = bottom_top_blob.channel(q);
  60. float32x4_t _one = vdupq_n_f32(1.f);
  61. for (int i = 0; i < size; i++)
  62. {
  63. float32x4_t _p = vld1q_f32(ptr);
  64. _p = div_ps(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  65. vst1q_f32(ptr, _p);
  66. ptr += 4;
  67. }
  68. }
  69. return 0;
  70. }
  71. #endif // __ARM_NEON
  72. #pragma omp parallel for num_threads(opt.num_threads)
  73. for (int q = 0; q < channels; q++)
  74. {
  75. float* ptr = bottom_top_blob.channel(q);
  76. #if __ARM_NEON
  77. int nn = size >> 2;
  78. int remain = size - (nn << 2);
  79. #else
  80. int remain = size;
  81. #endif // __ARM_NEON
  82. #if __ARM_NEON
  83. float32x4_t _one = vdupq_n_f32(1.f);
  84. for (; nn > 0; nn--)
  85. {
  86. float32x4_t _p = vld1q_f32(ptr);
  87. _p = div_ps(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  88. vst1q_f32(ptr, _p);
  89. ptr += 4;
  90. }
  91. #endif // __ARM_NEON
  92. for (; remain > 0; remain--)
  93. {
  94. *ptr = *ptr / (1.f + exp(-*ptr));
  95. ptr++;
  96. }
  97. }
  98. return 0;
  99. }
  100. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  101. int Swish_arm::forward_inplace_fp16s(Mat& bottom_top_blob, const Option& opt) const
  102. {
  103. int w = bottom_top_blob.w;
  104. int h = bottom_top_blob.h;
  105. int channels = bottom_top_blob.c;
  106. int size = w * h;
  107. int elempack = bottom_top_blob.elempack;
  108. if (elempack == 4)
  109. {
  110. #pragma omp parallel for num_threads(opt.num_threads)
  111. for (int q = 0; q < channels; q++)
  112. {
  113. __fp16* ptr = bottom_top_blob.channel(q);
  114. float32x4_t _one = vdupq_n_f32(1.f);
  115. for (int i = 0; i < size; i++)
  116. {
  117. float32x4_t _p = vcvt_f32_f16(vld1_f16(ptr));
  118. _p = vdivq_f32(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  119. vst1_f16(ptr, vcvt_f16_f32(_p));
  120. ptr += 4;
  121. }
  122. }
  123. return 0;
  124. }
  125. #pragma omp parallel for num_threads(opt.num_threads)
  126. for (int q = 0; q < channels; q++)
  127. {
  128. __fp16* ptr = bottom_top_blob.channel(q);
  129. float32x4_t _one = vdupq_n_f32(1.f);
  130. int i = 0;
  131. for (; i + 3 < size; i += 4)
  132. {
  133. float32x4_t _p = vcvt_f32_f16(vld1_f16(ptr));
  134. _p = vdivq_f32(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  135. vst1_f16(ptr, vcvt_f16_f32(_p));
  136. ptr += 4;
  137. }
  138. for (; i < size; i++)
  139. {
  140. float v = (float)*ptr;
  141. v = v / (1.f + exp(-v));
  142. *ptr = (__fp16)v;
  143. ptr++;
  144. }
  145. }
  146. return 0;
  147. }
  148. int Swish_arm::forward_inplace_fp16sa(Mat& bottom_top_blob, const Option& opt) const
  149. {
  150. int w = bottom_top_blob.w;
  151. int h = bottom_top_blob.h;
  152. int channels = bottom_top_blob.c;
  153. int size = w * h;
  154. int elempack = bottom_top_blob.elempack;
  155. if (elempack == 8)
  156. {
  157. #pragma omp parallel for num_threads(opt.num_threads)
  158. for (int q = 0; q < channels; q++)
  159. {
  160. __fp16* ptr = bottom_top_blob.channel(q);
  161. float16x8_t _one = vdupq_n_f16(1.f);
  162. for (int i = 0; i < size; i++)
  163. {
  164. float16x8_t _p = vld1q_f16(ptr);
  165. _p = vdivq_f16(_p, vaddq_f16(_one, exp_ps(vnegq_f16(_p))));
  166. vst1q_f16(ptr, _p);
  167. ptr += 8;
  168. }
  169. }
  170. return 0;
  171. }
  172. if (elempack == 4)
  173. {
  174. #pragma omp parallel for num_threads(opt.num_threads)
  175. for (int q = 0; q < channels; q++)
  176. {
  177. __fp16* ptr = bottom_top_blob.channel(q);
  178. float16x4_t _one = vdup_n_f16(1.f);
  179. for (int i = 0; i < size; i++)
  180. {
  181. float16x4_t _p = vld1_f16(ptr);
  182. _p = vdiv_f16(_p, vadd_f16(_one, exp_ps(vneg_f16(_p))));
  183. vst1_f16(ptr, _p);
  184. ptr += 4;
  185. }
  186. }
  187. return 0;
  188. }
  189. #pragma omp parallel for num_threads(opt.num_threads)
  190. for (int q = 0; q < channels; q++)
  191. {
  192. __fp16* ptr = bottom_top_blob.channel(q);
  193. float16x4_t _one = vdup_n_f16(1.f);
  194. int i = 0;
  195. for (; i + 3 < size; i += 4)
  196. {
  197. float16x4_t _p = vld1_f16(ptr);
  198. _p = vdiv_f16(_p, vadd_f16(_one, exp_ps(vneg_f16(_p))));
  199. vst1_f16(ptr, _p);
  200. ptr += 4;
  201. }
  202. for (; i < size; i++)
  203. {
  204. __fp16 v = *ptr;
  205. v = v / ((__fp16)1.f + exp(-v));
  206. *ptr = v;
  207. ptr++;
  208. }
  209. }
  210. return 0;
  211. }
  212. #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  213. int Swish_arm::forward_inplace_bf16s(Mat& bottom_top_blob, const Option& opt) const
  214. {
  215. int w = bottom_top_blob.w;
  216. int h = bottom_top_blob.h;
  217. int channels = bottom_top_blob.c;
  218. int size = w * h;
  219. int elempack = bottom_top_blob.elempack;
  220. #if __ARM_NEON
  221. if (elempack == 4)
  222. {
  223. #pragma omp parallel for num_threads(opt.num_threads)
  224. for (int q = 0; q < channels; q++)
  225. {
  226. unsigned short* ptr = bottom_top_blob.channel(q);
  227. float32x4_t _one = vdupq_n_f32(1.f);
  228. for (int i = 0; i < size; i++)
  229. {
  230. float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  231. _p = div_ps(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  232. vst1_u16(ptr, vcvt_bf16_f32(_p));
  233. ptr += 4;
  234. }
  235. }
  236. return 0;
  237. }
  238. #endif // __ARM_NEON
  239. #pragma omp parallel for num_threads(opt.num_threads)
  240. for (int q = 0; q < channels; q++)
  241. {
  242. unsigned short* ptr = bottom_top_blob.channel(q);
  243. #if __ARM_NEON
  244. int nn = size >> 2;
  245. int remain = size - (nn << 2);
  246. #else
  247. int remain = size;
  248. #endif // __ARM_NEON
  249. #if __ARM_NEON
  250. float32x4_t _one = vdupq_n_f32(1.f);
  251. for (; nn > 0; nn--)
  252. {
  253. float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  254. _p = div_ps(_p, vaddq_f32(_one, exp_ps(vnegq_f32(_p))));
  255. vst1_u16(ptr, vcvt_bf16_f32(_p));
  256. ptr += 4;
  257. }
  258. #endif // __ARM_NEON
  259. for (; remain > 0; remain--)
  260. {
  261. float v = bfloat16_to_float32(*ptr);
  262. v = v / (1.f + exp(-v));
  263. *ptr = float32_to_bfloat16(v);
  264. ptr++;
  265. }
  266. }
  267. return 0;
  268. }
  269. } // namespace ncnn