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.

relu_arm.cpp 36 kB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  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 "relu_arm.h"
  15. #if __ARM_NEON
  16. #include <arm_neon.h>
  17. #endif // __ARM_NEON
  18. namespace ncnn {
  19. ReLU_arm::ReLU_arm()
  20. {
  21. #if __ARM_NEON
  22. support_packing = true;
  23. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  24. support_fp16_storage = true;
  25. #endif
  26. #endif // __ARM_NEON
  27. support_bf16_storage = true;
  28. }
  29. int ReLU_arm::forward_inplace(Mat& bottom_top_blob, const Option& opt) const
  30. {
  31. if (bottom_top_blob.elemsize == 1u)
  32. return forward_inplace_int8_neon(bottom_top_blob, opt);
  33. int elembits = bottom_top_blob.elembits();
  34. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  35. if (opt.use_fp16_storage && elembits == 16)
  36. return forward_inplace_fp16s(bottom_top_blob, opt);
  37. #endif
  38. if (opt.use_bf16_storage && elembits == 16)
  39. return forward_inplace_bf16s(bottom_top_blob, opt);
  40. int w = bottom_top_blob.w;
  41. int h = bottom_top_blob.h;
  42. int channels = bottom_top_blob.c;
  43. int size = w * h;
  44. int elempack = bottom_top_blob.elempack;
  45. #if __ARM_NEON
  46. if (elempack == 4)
  47. {
  48. if (slope == 0.f)
  49. {
  50. #pragma omp parallel for num_threads(opt.num_threads)
  51. for (int q = 0; q < channels; q++)
  52. {
  53. float* ptr = bottom_top_blob.channel(q);
  54. #if __aarch64__
  55. asm volatile(
  56. "eor v16.16b, v16.16b, v16.16b \n"
  57. "lsr w4, %w2, #3 \n" // w4 = nn = size >> 3
  58. "cmp w4, #0 \n"
  59. "beq 1f \n"
  60. "0: \n"
  61. "prfm pldl1keep, [%0, #512] \n"
  62. "ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%0], #64 \n"
  63. "prfm pldl1keep, [%0, #512] \n"
  64. "ld1 {v4.4s, v5.4s, v6.4s, v7.4s}, [%0] \n"
  65. "fmax v0.4s, v0.4s, v16.4s \n"
  66. "fmax v1.4s, v1.4s, v16.4s \n"
  67. "fmax v2.4s, v2.4s, v16.4s \n"
  68. "fmax v3.4s, v3.4s, v16.4s \n"
  69. "sub %0, %0, #64 \n"
  70. "fmax v4.4s, v4.4s, v16.4s \n"
  71. "fmax v5.4s, v5.4s, v16.4s \n"
  72. "fmax v6.4s, v6.4s, v16.4s \n"
  73. "fmax v7.4s, v7.4s, v16.4s \n"
  74. "st1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%0], #64 \n"
  75. "subs w4, w4, #1 \n"
  76. "st1 {v4.4s, v5.4s, v6.4s, v7.4s}, [%0], #64 \n"
  77. "bne 0b \n"
  78. "1: \n"
  79. "and w4, %w2, #7 \n" // w4 = remain = size & 7
  80. "cmp w4, #4 \n" // w4 >= 4
  81. "blt 2f \n"
  82. "prfm pldl1keep, [%0, #512] \n"
  83. "ld1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%0] \n"
  84. "fmax v0.4s, v0.4s, v16.4s \n"
  85. "fmax v1.4s, v1.4s, v16.4s \n"
  86. "fmax v2.4s, v2.4s, v16.4s \n"
  87. "fmax v3.4s, v3.4s, v16.4s \n"
  88. "sub w4, w4, #4 \n"
  89. "st1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%0], #64 \n"
  90. "2: \n"
  91. "cmp w4, #2 \n" // w4 >= 2
  92. "blt 3f \n"
  93. "prfm pldl1keep, [%0, #256] \n"
  94. "ld1 {v0.4s, v1.4s}, [%0] \n"
  95. "fmax v0.4s, v0.4s, v16.4s \n"
  96. "fmax v1.4s, v1.4s, v16.4s \n"
  97. "sub w4, w4, #2 \n"
  98. "st1 {v0.4s, v1.4s}, [%0], #32 \n"
  99. "3: \n"
  100. "cmp w4, #0 \n" // w4 > 0
  101. "beq 4f \n"
  102. "prfm pldl1keep, [%0, #128] \n"
  103. "ld1 {v0.4s}, [%0] \n"
  104. "fmax v0.4s, v0.4s, v16.4s \n"
  105. "st1 {v0.4s}, [%0], #16 \n"
  106. "4: \n"
  107. : "=r"(ptr) // %0
  108. : "0"(ptr),
  109. "r"(size) // %2
  110. : "cc", "memory", "x4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16");
  111. #else // __aarch64__
  112. asm volatile(
  113. "veor q12, q12 \n"
  114. "lsr r4, %2, #3 \n" // r4 = nn = size >> 3
  115. "cmp r4, #0 \n"
  116. "beq 1f \n"
  117. "0: \n"
  118. "pld [%0, #512] \n"
  119. "vldm %0!, {d0-d7} \n"
  120. "pld [%0, #512] \n"
  121. "vldm %0, {d16-d23} \n"
  122. "vmax.f32 q0, q0, q12 \n"
  123. "vmax.f32 q1, q1, q12 \n"
  124. "vmax.f32 q2, q2, q12 \n"
  125. "vmax.f32 q3, q3, q12 \n"
  126. "sub %0, %0, #64 \n"
  127. "vmax.f32 q8, q8, q12 \n"
  128. "vmax.f32 q9, q9, q12 \n"
  129. "vmax.f32 q10, q10, q12 \n"
  130. "vmax.f32 q11, q11, q12 \n"
  131. "vstm %0!, {d0-d7} \n"
  132. "subs r4, r4, #1 \n"
  133. "vstm %0!, {d16-d23} \n"
  134. "bne 0b \n"
  135. "1: \n"
  136. "and r4, %2, #7 \n" // r4 = remain = size & 7
  137. "cmp r4, #4 \n" // r4 >= 4
  138. "blt 2f \n"
  139. "pld [%0, #512] \n"
  140. "vldm %0, {d0-d7} \n"
  141. "vmax.f32 q0, q0, q12 \n"
  142. "vmax.f32 q1, q1, q12 \n"
  143. "vmax.f32 q2, q2, q12 \n"
  144. "vmax.f32 q3, q3, q12 \n"
  145. "sub r4, r4, #4 \n"
  146. "vstm %0!, {d0-d7} \n"
  147. "2: \n"
  148. "cmp r4, #2 \n" // r4 >= 2
  149. "blt 3f \n"
  150. "pld [%0, #256] \n"
  151. "vld1.f32 {d0-d3}, [%0 :128] \n"
  152. "vmax.f32 q0, q0, q12 \n"
  153. "vmax.f32 q1, q1, q12 \n"
  154. "sub r4, r4, #2 \n"
  155. "vst1.f32 {d0-d3}, [%0 :128]! \n"
  156. "3: \n"
  157. "cmp r4, #0 \n" // r4 > 0
  158. "beq 4f \n"
  159. "pld [%0, #128] \n"
  160. "vld1.f32 {d0-d1}, [%0 :128] \n"
  161. "vmax.f32 q0, q0, q12 \n"
  162. "vst1.f32 {d0-d1}, [%0 :128]! \n"
  163. "4: \n"
  164. : "=r"(ptr) // %0
  165. : "0"(ptr),
  166. "r"(size) // %2
  167. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  168. #endif // __aarch64__
  169. }
  170. }
  171. else
  172. {
  173. #pragma omp parallel for num_threads(opt.num_threads)
  174. for (int q = 0; q < channels; q++)
  175. {
  176. float* ptr = bottom_top_blob.channel(q);
  177. float32x4_t _zero = vdupq_n_f32(0.f);
  178. float32x4_t _slope = vdupq_n_f32(slope);
  179. for (int i = 0; i < size; i++)
  180. {
  181. float32x4_t _p = vld1q_f32(ptr);
  182. uint32x4_t _lemask = vcleq_f32(_p, _zero);
  183. float32x4_t _ps = vmulq_f32(_p, _slope);
  184. _p = vbslq_f32(_lemask, _ps, _p);
  185. vst1q_f32(ptr, _p);
  186. ptr += 4;
  187. }
  188. }
  189. }
  190. return 0;
  191. }
  192. #endif // __ARM_NEON
  193. if (slope == 0.f)
  194. {
  195. #pragma omp parallel for num_threads(opt.num_threads)
  196. for (int q = 0; q < channels; q++)
  197. {
  198. float* ptr = bottom_top_blob.channel(q);
  199. #if __ARM_NEON
  200. int nn = size >> 2;
  201. int remain = size - (nn << 2);
  202. #else
  203. int remain = size;
  204. #endif // __ARM_NEON
  205. #if __ARM_NEON
  206. #if __aarch64__
  207. float32x4_t _zero = vdupq_n_f32(0.f);
  208. for (; nn > 0; nn--)
  209. {
  210. float32x4_t _p = vld1q_f32(ptr);
  211. _p = vmaxq_f32(_p, _zero);
  212. vst1q_f32(ptr, _p);
  213. ptr += 4;
  214. }
  215. #else
  216. if (nn > 0)
  217. {
  218. asm volatile(
  219. "veor q1, q0, q0 \n"
  220. "0: \n"
  221. "pld [%1, #128] \n"
  222. "vld1.f32 {d0-d1}, [%1 :128] \n"
  223. "vmax.f32 q0, q0, q1 \n"
  224. "subs %0, #1 \n"
  225. "vst1.f32 {d0-d1}, [%1 :128]! \n"
  226. "bne 0b \n"
  227. : "=r"(nn), // %0
  228. "=r"(ptr) // %1
  229. : "0"(nn),
  230. "1"(ptr)
  231. : "cc", "memory", "q0", "q1");
  232. }
  233. #endif // __aarch64__
  234. #endif // __ARM_NEON
  235. for (; remain > 0; remain--)
  236. {
  237. *ptr = std::max(*ptr, 0.f);
  238. ptr++;
  239. }
  240. }
  241. }
  242. else
  243. {
  244. #pragma omp parallel for num_threads(opt.num_threads)
  245. for (int q = 0; q < channels; q++)
  246. {
  247. float* ptr = bottom_top_blob.channel(q);
  248. #if __ARM_NEON
  249. int nn = size >> 2;
  250. int remain = size - (nn << 2);
  251. #else
  252. int remain = size;
  253. #endif // __ARM_NEON
  254. #if __ARM_NEON
  255. #if __aarch64__
  256. float32x4_t _zero = vdupq_n_f32(0.f);
  257. float32x4_t _slope = vdupq_n_f32(slope);
  258. for (; nn > 0; nn--)
  259. {
  260. float32x4_t _p = vld1q_f32(ptr);
  261. uint32x4_t _lemask = vcleq_f32(_p, _zero);
  262. float32x4_t _ps = vmulq_f32(_p, _slope);
  263. _p = vbslq_f32(_lemask, _ps, _p);
  264. vst1q_f32(ptr, _p);
  265. ptr += 4;
  266. }
  267. #else
  268. if (nn > 0)
  269. {
  270. asm volatile(
  271. "veor q1, q0, q0 \n"
  272. "vdup.f32 q2, %4 \n"
  273. "0: \n"
  274. "pld [%1, #128] \n"
  275. "vld1.f32 {d0-d1}, [%1 :128] \n"
  276. "vcle.f32 q3, q0, q1 \n"
  277. "vmul.f32 q4, q0, q2 \n"
  278. "vbit.32 q0, q4, q3 \n"
  279. "subs %0, #1 \n"
  280. "vst1.f32 {d0-d1}, [%1 :128]! \n"
  281. "bne 0b \n"
  282. : "=r"(nn), // %0
  283. "=r"(ptr) // %1
  284. : "0"(nn),
  285. "1"(ptr),
  286. "r"(slope) // %4
  287. : "cc", "memory", "q0", "q1", "q2", "q3", "q4");
  288. }
  289. #endif // __aarch64__
  290. #endif // __ARM_NEON
  291. for (; remain > 0; remain--)
  292. {
  293. if (*ptr < 0)
  294. *ptr *= slope;
  295. ptr++;
  296. }
  297. }
  298. }
  299. return 0;
  300. }
  301. #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  302. int ReLU_arm::forward_inplace_fp16s(Mat& bottom_top_blob, const Option& opt) const
  303. {
  304. int w = bottom_top_blob.w;
  305. int h = bottom_top_blob.h;
  306. int channels = bottom_top_blob.c;
  307. int size = w * h;
  308. int elempack = bottom_top_blob.elempack;
  309. if (elempack == 8)
  310. {
  311. if (slope == 0.f)
  312. {
  313. #pragma omp parallel for num_threads(opt.num_threads)
  314. for (int q = 0; q < channels; q++)
  315. {
  316. __fp16* ptr = bottom_top_blob.channel(q);
  317. asm volatile(
  318. "eor v16.16b, v16.16b, v16.16b \n"
  319. "lsr w4, %w2, #2 \n" // w4 = nn = size >> 2
  320. "cmp w4, #0 \n"
  321. "beq 1f \n"
  322. "0: \n"
  323. "prfm pldl1keep, [%0, #512] \n"
  324. "ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0] \n"
  325. "fmax v0.8h, v0.8h, v16.8h \n"
  326. "fmax v1.8h, v1.8h, v16.8h \n"
  327. "fmax v2.8h, v2.8h, v16.8h \n"
  328. "fmax v3.8h, v3.8h, v16.8h \n"
  329. "subs w4, w4, #1 \n"
  330. "st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0], #64 \n"
  331. "bne 0b \n"
  332. "1: \n"
  333. "and w4, %w2, #3 \n" // w4 = remain = size & 3
  334. "cmp w4, #2 \n" // w4 >= 2
  335. "blt 2f \n"
  336. "prfm pldl1keep, [%0, #256] \n"
  337. "ld1 {v0.8h, v1.8h}, [%0] \n"
  338. "fmax v0.8h, v0.8h, v16.8h \n"
  339. "fmax v1.8h, v1.8h, v16.8h \n"
  340. "sub w4, w4, #2 \n"
  341. "st1 {v0.8h, v1.8h}, [%0], #32 \n"
  342. "2: \n"
  343. "cmp w4, #0 \n" // w4 > 0
  344. "beq 3f \n"
  345. "prfm pldl1keep, [%0, #128] \n"
  346. "ld1 {v0.8h}, [%0] \n"
  347. "fmax v0.8h, v0.8h, v16.8h \n"
  348. "st1 {v0.8h}, [%0], #16 \n"
  349. "3: \n"
  350. : "=r"(ptr) // %0
  351. : "0"(ptr),
  352. "r"(size) // %2
  353. : "cc", "memory", "x4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16");
  354. }
  355. }
  356. else
  357. {
  358. #pragma omp parallel for num_threads(opt.num_threads)
  359. for (int q = 0; q < channels; q++)
  360. {
  361. __fp16* ptr = bottom_top_blob.channel(q);
  362. float16x8_t _zero = vdupq_n_f16((__fp16)0.f);
  363. float16x8_t _slope = vdupq_n_f16((__fp16)slope);
  364. for (int i = 0; i < size; i++)
  365. {
  366. float16x8_t _p = vld1q_f16(ptr);
  367. uint16x8_t _lemask = vcleq_f16(_p, _zero);
  368. float16x8_t _ps = vmulq_f16(_p, _slope);
  369. _p = vbslq_f16(_lemask, _ps, _p);
  370. vst1q_f16(ptr, _p);
  371. ptr += 8;
  372. }
  373. }
  374. }
  375. return 0;
  376. }
  377. if (elempack == 4)
  378. {
  379. if (slope == 0.f)
  380. {
  381. #pragma omp parallel for num_threads(opt.num_threads)
  382. for (int q = 0; q < channels; q++)
  383. {
  384. __fp16* ptr = bottom_top_blob.channel(q);
  385. float16x8_t _zero = vdupq_n_f16((__fp16)0.f);
  386. int i = 0;
  387. for (; i + 1 < size; i += 2)
  388. {
  389. float16x8_t _p = vld1q_f16(ptr);
  390. _p = vmaxq_f16(_p, _zero);
  391. vst1q_f16(ptr, _p);
  392. ptr += 8;
  393. }
  394. for (; i < size; i++)
  395. {
  396. float16x4_t _p = vld1_f16(ptr);
  397. _p = vmax_f16(_p, vget_low_f16(_zero));
  398. vst1_f16(ptr, _p);
  399. ptr += 4;
  400. }
  401. }
  402. }
  403. else
  404. {
  405. #pragma omp parallel for num_threads(opt.num_threads)
  406. for (int q = 0; q < channels; q++)
  407. {
  408. __fp16* ptr = bottom_top_blob.channel(q);
  409. float16x8_t _zero = vdupq_n_f16((__fp16)0.f);
  410. float16x8_t _slope = vdupq_n_f16((__fp16)slope);
  411. int i = 0;
  412. for (; i + 1 < size; i += 2)
  413. {
  414. float16x8_t _p = vld1q_f16(ptr);
  415. uint16x8_t _lemask = vcleq_f16(_p, _zero);
  416. float16x8_t _ps = vmulq_f16(_p, _slope);
  417. _p = vbslq_f16(_lemask, _ps, _p);
  418. vst1q_f16(ptr, _p);
  419. ptr += 8;
  420. }
  421. for (; i < size; i++)
  422. {
  423. float16x4_t _p = vld1_f16(ptr);
  424. uint16x4_t _lemask = vcle_f16(_p, vget_low_f16(_zero));
  425. float16x4_t _ps = vmul_f16(_p, vget_low_f16(_slope));
  426. _p = vbsl_f16(_lemask, _ps, _p);
  427. vst1_f16(ptr, _p);
  428. ptr += 4;
  429. }
  430. }
  431. }
  432. return 0;
  433. }
  434. if (slope == 0.f)
  435. {
  436. #pragma omp parallel for num_threads(opt.num_threads)
  437. for (int q = 0; q < channels; q++)
  438. {
  439. __fp16* ptr = bottom_top_blob.channel(q);
  440. float16x8_t _zero = vdupq_n_f16((__fp16)0.f);
  441. int i = 0;
  442. for (; i + 7 < size; i += 8)
  443. {
  444. float16x8_t _p = vld1q_f16(ptr);
  445. _p = vmaxq_f16(_p, _zero);
  446. vst1q_f16(ptr, _p);
  447. ptr += 8;
  448. }
  449. for (; i + 3 < size; i += 4)
  450. {
  451. float16x4_t _p = vld1_f16(ptr);
  452. _p = vmax_f16(_p, vget_low_f16(_zero));
  453. vst1_f16(ptr, _p);
  454. ptr += 4;
  455. }
  456. for (; i < size; i++)
  457. {
  458. __fp16 v = ptr[0];
  459. if (v < (__fp16)0.f)
  460. ptr[0] = (__fp16)0.f;
  461. ptr += 1;
  462. }
  463. }
  464. }
  465. else
  466. {
  467. #pragma omp parallel for num_threads(opt.num_threads)
  468. for (int q = 0; q < channels; q++)
  469. {
  470. __fp16* ptr = bottom_top_blob.channel(q);
  471. float16x8_t _zero = vdupq_n_f16((__fp16)0.f);
  472. float16x8_t _slope = vdupq_n_f16((__fp16)slope);
  473. int i = 0;
  474. for (; i + 7 < size; i += 8)
  475. {
  476. float16x8_t _p = vld1q_f16(ptr);
  477. uint16x8_t _lemask = vcleq_f16(_p, _zero);
  478. float16x8_t _ps = vmulq_f16(_p, _slope);
  479. _p = vbslq_f16(_lemask, _ps, _p);
  480. vst1q_f16(ptr, _p);
  481. ptr += 8;
  482. }
  483. for (; i + 3 < size; i += 4)
  484. {
  485. float16x4_t _p = vld1_f16(ptr);
  486. uint16x4_t _lemask = vcle_f16(_p, vget_low_f16(_zero));
  487. float16x4_t _ps = vmul_f16(_p, vget_low_f16(_slope));
  488. _p = vbsl_f16(_lemask, _ps, _p);
  489. vst1_f16(ptr, _p);
  490. ptr += 4;
  491. }
  492. for (; i < size; i++)
  493. {
  494. __fp16 v = ptr[0];
  495. if (v < (__fp16)0.f)
  496. ptr[0] = v * (__fp16)slope;
  497. ptr += 1;
  498. }
  499. }
  500. }
  501. return 0;
  502. }
  503. #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
  504. int ReLU_arm::forward_inplace_bf16s(Mat& bottom_top_blob, const Option& opt) const
  505. {
  506. int w = bottom_top_blob.w;
  507. int h = bottom_top_blob.h;
  508. int channels = bottom_top_blob.c;
  509. int size = w * h;
  510. int elempack = bottom_top_blob.elempack;
  511. #if __ARM_NEON
  512. if (elempack == 4)
  513. {
  514. if (slope == 0.f)
  515. {
  516. #pragma omp parallel for num_threads(opt.num_threads)
  517. for (int q = 0; q < channels; q++)
  518. {
  519. unsigned short* ptr = bottom_top_blob.channel(q);
  520. #if __aarch64__
  521. asm volatile(
  522. "eor v16.16b, v16.16b, v16.16b \n"
  523. "lsr w4, %w2, #3 \n" // w4 = nn = size >> 3
  524. "cmp w4, #0 \n"
  525. "beq 1f \n"
  526. "0: \n"
  527. "prfm pldl1keep, [%0, #512] \n"
  528. "ld1 {v4.8h, v5.8h, v6.8h, v7.8h}, [%0] \n"
  529. "shll v0.4s, v4.4h, #16 \n"
  530. "shll2 v1.4s, v4.8h, #16 \n"
  531. "shll v2.4s, v5.4h, #16 \n"
  532. "shll2 v3.4s, v5.8h, #16 \n"
  533. "shll v4.4s, v6.4h, #16 \n"
  534. "shll2 v5.4s, v6.8h, #16 \n"
  535. "shll v6.4s, v7.4h, #16 \n"
  536. "shll2 v7.4s, v7.8h, #16 \n"
  537. "fmax v0.4s, v0.4s, v16.4s \n"
  538. "fmax v1.4s, v1.4s, v16.4s \n"
  539. "fmax v2.4s, v2.4s, v16.4s \n"
  540. "fmax v3.4s, v3.4s, v16.4s \n"
  541. "fmax v4.4s, v4.4s, v16.4s \n"
  542. "fmax v5.4s, v5.4s, v16.4s \n"
  543. "fmax v6.4s, v6.4s, v16.4s \n"
  544. "fmax v7.4s, v7.4s, v16.4s \n"
  545. "shrn v0.4h, v0.4s, #16 \n"
  546. "shrn2 v0.8h, v1.4s, #16 \n"
  547. "shrn v1.4h, v2.4s, #16 \n"
  548. "shrn2 v1.8h, v3.4s, #16 \n"
  549. "shrn v2.4h, v4.4s, #16 \n"
  550. "shrn2 v2.8h, v5.4s, #16 \n"
  551. "shrn v3.4h, v6.4s, #16 \n"
  552. "shrn2 v3.8h, v7.4s, #16 \n"
  553. "subs w4, w4, #1 \n"
  554. "st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0], #64 \n"
  555. "bne 0b \n"
  556. "1: \n"
  557. "and w4, %w2, #7 \n" // w4 = remain = size & 7
  558. "cmp w4, #4 \n" // w4 >= 4
  559. "blt 2f \n"
  560. "prfm pldl1keep, [%0, #256] \n"
  561. "ld1 {v0.4h, v1.4h, v2.4h, v3.4h}, [%0] \n"
  562. "shll v0.4s, v0.4h, #16 \n"
  563. "shll v1.4s, v1.4h, #16 \n"
  564. "shll v2.4s, v2.4h, #16 \n"
  565. "shll v3.4s, v3.4h, #16 \n"
  566. "fmax v0.4s, v0.4s, v16.4s \n"
  567. "fmax v1.4s, v1.4s, v16.4s \n"
  568. "fmax v2.4s, v2.4s, v16.4s \n"
  569. "fmax v3.4s, v3.4s, v16.4s \n"
  570. "shrn v0.4h, v0.4s, #16 \n"
  571. "shrn v1.4h, v1.4s, #16 \n"
  572. "shrn v2.4h, v2.4s, #16 \n"
  573. "shrn v3.4h, v3.4s, #16 \n"
  574. "sub w4, w4, #4 \n"
  575. "st1 {v0.4h, v1.4h, v2.4h, v3.4h}, [%0], #32 \n"
  576. "2: \n"
  577. "cmp w4, #2 \n" // w4 >= 2
  578. "blt 3f \n"
  579. "prfm pldl1keep, [%0, #128] \n"
  580. "ld1 {v0.4h, v1.4h}, [%0] \n"
  581. "shll v0.4s, v0.4h, #16 \n"
  582. "shll v1.4s, v1.4h, #16 \n"
  583. "fmax v0.4s, v0.4s, v16.4s \n"
  584. "fmax v1.4s, v1.4s, v16.4s \n"
  585. "shrn v0.4h, v0.4s, #16 \n"
  586. "shrn v1.4h, v1.4s, #16 \n"
  587. "sub w4, w4, #2 \n"
  588. "st1 {v0.4h, v1.4h}, [%0], #16 \n"
  589. "3: \n"
  590. "cmp w4, #0 \n" // w4 > 0
  591. "beq 4f \n"
  592. "prfm pldl1keep, [%0, #64] \n"
  593. "ld1 {v0.4h}, [%0] \n"
  594. "shll v0.4s, v0.4h, #16 \n"
  595. "fmax v0.4s, v0.4s, v16.4s \n"
  596. "shrn v0.4h, v0.4s, #16 \n"
  597. "st1 {v0.4h}, [%0], #8 \n"
  598. "4: \n"
  599. : "=r"(ptr) // %0
  600. : "0"(ptr),
  601. "r"(size) // %2
  602. : "cc", "memory", "x4", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16");
  603. #else // __aarch64__
  604. asm volatile(
  605. "veor q12, q12 \n"
  606. "lsr r4, %2, #3 \n" // r4 = nn = size >> 3
  607. "cmp r4, #0 \n"
  608. "beq 1f \n"
  609. "0: \n"
  610. "pld [%0, #512] \n"
  611. "vldm %0, {d16-d23} \n"
  612. "vshll.u16 q0, d16, #16 \n"
  613. "vshll.u16 q1, d17, #16 \n"
  614. "vshll.u16 q2, d18, #16 \n"
  615. "vshll.u16 q3, d19, #16 \n"
  616. "vshll.u16 q8, d20, #16 \n"
  617. "vshll.u16 q9, d21, #16 \n"
  618. "vshll.u16 q10, d22, #16 \n"
  619. "vshll.u16 q11, d23, #16 \n"
  620. "vmax.f32 q0, q0, q12 \n"
  621. "vmax.f32 q1, q1, q12 \n"
  622. "vmax.f32 q2, q2, q12 \n"
  623. "vmax.f32 q3, q3, q12 \n"
  624. "vmax.f32 q8, q8, q12 \n"
  625. "vmax.f32 q9, q9, q12 \n"
  626. "vmax.f32 q10, q10, q12 \n"
  627. "vmax.f32 q11, q11, q12 \n"
  628. "vshrn.u32 d0, q0, #16 \n"
  629. "vshrn.u32 d1, q1, #16 \n"
  630. "vshrn.u32 d2, q2, #16 \n"
  631. "vshrn.u32 d3, q3, #16 \n"
  632. "vshrn.u32 d4, q8, #16 \n"
  633. "vshrn.u32 d5, q9, #16 \n"
  634. "vshrn.u32 d6, q10, #16 \n"
  635. "vshrn.u32 d7, q11, #16 \n"
  636. "subs r4, r4, #1 \n"
  637. "vstm %0!, {d0-d7} \n"
  638. "bne 0b \n"
  639. "1: \n"
  640. "and r4, %2, #7 \n" // r4 = remain = size & 7
  641. "cmp r4, #4 \n" // r4 >= 4
  642. "blt 2f \n"
  643. "pld [%0, #256] \n"
  644. "vld1.u16 {d4-d7}, [%0 :64] \n"
  645. "vshll.u16 q0, d4, #16 \n"
  646. "vshll.u16 q1, d5, #16 \n"
  647. "vshll.u16 q2, d6, #16 \n"
  648. "vshll.u16 q3, d7, #16 \n"
  649. "vmax.f32 q0, q0, q12 \n"
  650. "vmax.f32 q1, q1, q12 \n"
  651. "vmax.f32 q2, q2, q12 \n"
  652. "vmax.f32 q3, q3, q12 \n"
  653. "vshrn.u32 d0, q0, #16 \n"
  654. "vshrn.u32 d1, q1, #16 \n"
  655. "vshrn.u32 d2, q2, #16 \n"
  656. "vshrn.u32 d3, q3, #16 \n"
  657. "sub r4, r4, #4 \n"
  658. "vst1.u16 {d0-d3}, [%0 :64]! \n"
  659. "2: \n"
  660. "cmp r4, #2 \n" // r4 >= 2
  661. "blt 3f \n"
  662. "pld [%0, #128] \n"
  663. "vld1.u16 {d2-d3}, [%0 :64] \n"
  664. "vshll.u16 q0, d2, #16 \n"
  665. "vshll.u16 q1, d3, #16 \n"
  666. "vmax.f32 q0, q0, q12 \n"
  667. "vmax.f32 q1, q1, q12 \n"
  668. "vshrn.u32 d0, q0, #16 \n"
  669. "vshrn.u32 d1, q1, #16 \n"
  670. "sub r4, r4, #2 \n"
  671. "vst1.u16 {d0-d1}, [%0 :64]! \n"
  672. "3: \n"
  673. "cmp r4, #0 \n" // r4 > 0
  674. "beq 4f \n"
  675. "pld [%0, #64] \n"
  676. "vld1.u16 {d0}, [%0 :64] \n"
  677. "vshll.u16 q0, d0, #16 \n"
  678. "vmax.f32 q0, q0, q12 \n"
  679. "vshrn.u32 d0, q0, #16 \n"
  680. "vst1.u16 {d0}, [%0 :64]! \n"
  681. "4: \n"
  682. : "=r"(ptr) // %0
  683. : "0"(ptr),
  684. "r"(size) // %2
  685. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  686. #endif // __aarch64__
  687. // float32x4_t _zero = vdupq_n_f32(0.f);
  688. // for (int i=0; i<size; i++)
  689. // {
  690. // float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  691. // _p = vmaxq_f32(_p, _zero);
  692. // vst1_u16(ptr, vcvt_bf16_f32(_p));
  693. //
  694. // ptr += 4;
  695. // }
  696. }
  697. }
  698. else
  699. {
  700. #pragma omp parallel for num_threads(opt.num_threads)
  701. for (int q = 0; q < channels; q++)
  702. {
  703. unsigned short* ptr = bottom_top_blob.channel(q);
  704. float32x4_t _zero = vdupq_n_f32(0.f);
  705. float32x4_t _slope = vdupq_n_f32(slope);
  706. for (int i = 0; i < size; i++)
  707. {
  708. float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  709. uint32x4_t _lemask = vcleq_f32(_p, _zero);
  710. float32x4_t _ps = vmulq_f32(_p, _slope);
  711. _p = vbslq_f32(_lemask, _ps, _p);
  712. vst1_u16(ptr, vcvt_bf16_f32(_p));
  713. ptr += 4;
  714. }
  715. }
  716. }
  717. return 0;
  718. }
  719. #endif // __ARM_NEON
  720. if (slope == 0.f)
  721. {
  722. #pragma omp parallel for num_threads(opt.num_threads)
  723. for (int q = 0; q < channels; q++)
  724. {
  725. unsigned short* ptr = bottom_top_blob.channel(q);
  726. int i = 0;
  727. #if __ARM_NEON
  728. float32x4_t _zero = vdupq_n_f32(0.f);
  729. for (; i + 3 < size; i += 4)
  730. {
  731. float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  732. _p = vmaxq_f32(_p, _zero);
  733. vst1_u16(ptr, vcvt_bf16_f32(_p));
  734. ptr += 4;
  735. }
  736. #endif // __ARM_NEON
  737. for (; i < size; i++)
  738. {
  739. float v = bfloat16_to_float32(ptr[0]);
  740. if (v < 0.f)
  741. ptr[0] = float32_to_bfloat16(0.f);
  742. ptr += 1;
  743. }
  744. }
  745. }
  746. else
  747. {
  748. #pragma omp parallel for num_threads(opt.num_threads)
  749. for (int q = 0; q < channels; q++)
  750. {
  751. unsigned short* ptr = bottom_top_blob.channel(q);
  752. int i = 0;
  753. #if __ARM_NEON
  754. float32x4_t _zero = vdupq_n_f32(0.f);
  755. float32x4_t _slope = vdupq_n_f32(slope);
  756. for (; i + 3 < size; i += 4)
  757. {
  758. float32x4_t _p = vcvt_f32_bf16(vld1_u16(ptr));
  759. uint32x4_t _lemask = vcleq_f32(_p, _zero);
  760. float32x4_t _ps = vmulq_f32(_p, _slope);
  761. _p = vbslq_f32(_lemask, _ps, _p);
  762. vst1_u16(ptr, vcvt_bf16_f32(_p));
  763. ptr += 4;
  764. }
  765. #endif // __ARM_NEON
  766. for (; i < size; i++)
  767. {
  768. float v = bfloat16_to_float32(ptr[0]);
  769. if (v < 0.f)
  770. ptr[0] = float32_to_bfloat16(v * slope);
  771. ptr += 1;
  772. }
  773. }
  774. }
  775. return 0;
  776. }
  777. int ReLU_arm::forward_inplace_int8_neon(Mat& bottom_top_blob, const Option& opt) const
  778. {
  779. int w = bottom_top_blob.w;
  780. int h = bottom_top_blob.h;
  781. int channels = bottom_top_blob.c;
  782. int size = w * h;
  783. if (slope == 0.f)
  784. {
  785. #pragma omp parallel for num_threads(opt.num_threads)
  786. for (int q = 0; q < channels; q++)
  787. {
  788. signed char* ptr = bottom_top_blob.channel(q);
  789. #if __ARM_NEON
  790. int nn = size >> 4;
  791. int remain = size - (nn << 4);
  792. #else
  793. int remain = size;
  794. #endif // __ARM_NEON
  795. #if __ARM_NEON
  796. #if __aarch64__
  797. int8x16_t _zero = vdupq_n_s8(0);
  798. for (; nn > 0; nn--)
  799. {
  800. int8x16_t _p = vld1q_s8(ptr);
  801. _p = vmaxq_s8(_p, _zero);
  802. vst1q_s8(ptr, _p);
  803. ptr += 16;
  804. }
  805. #else
  806. if (nn > 0)
  807. {
  808. asm volatile(
  809. "veor q1, q0, q0 \n"
  810. "0: \n"
  811. "pld [%1, #128] \n"
  812. "vld1.s8 {d0-d1}, [%1 :128] \n"
  813. "vmax.s8 q0, q0, q1 \n"
  814. "subs %0, #1 \n"
  815. "vst1.s8 {d0-d1}, [%1 :128]! \n"
  816. "bne 0b \n"
  817. : "=r"(nn), // %0
  818. "=r"(ptr) // %1
  819. : "0"(nn),
  820. "1"(ptr)
  821. : "cc", "memory", "q0", "q1");
  822. }
  823. #endif // __aarch64__
  824. #endif // __ARM_NEON
  825. for (; remain > 0; remain--)
  826. {
  827. if (*ptr < 0)
  828. *ptr = 0;
  829. ptr++;
  830. }
  831. }
  832. }
  833. else
  834. {
  835. // TODO
  836. // #pragma omp parallel for num_threads(opt.num_threads)
  837. // for (int q=0; q<channels; q++)
  838. // {
  839. // float* ptr = bottom_top_blob.channel(q);
  840. // for (int i=0; i<size; i++)
  841. // {
  842. // if (ptr[i] < 0)
  843. // ptr[i] *= slope;
  844. // }
  845. // }
  846. }
  847. return 0;
  848. }
  849. } // namespace ncnn