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.

reduction.cpp 24 kB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  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 "reduction.h"
  15. #include <math.h>
  16. namespace ncnn {
  17. DEFINE_LAYER_CREATOR(Reduction)
  18. Reduction::Reduction()
  19. {
  20. one_blob_only = true;
  21. support_inplace = false;
  22. }
  23. Reduction::~Reduction()
  24. {
  25. }
  26. #if NCNN_STDIO
  27. #if NCNN_STRING
  28. int Reduction::load_param(FILE* paramfp)
  29. {
  30. int nscan = fscanf(paramfp, "%d %d %f", &operation, &dim, &coeff);
  31. if (nscan != 3)
  32. {
  33. fprintf(stderr, "Reduction load_param failed %d\n", nscan);
  34. return -1;
  35. }
  36. return 0;
  37. }
  38. #endif // NCNN_STRING
  39. int Reduction::load_param_bin(FILE* paramfp)
  40. {
  41. fread(&operation, sizeof(int), 1, paramfp);
  42. fread(&dim, sizeof(int), 1, paramfp);
  43. fread(&coeff, sizeof(float), 1, paramfp);
  44. return 0;
  45. }
  46. #endif // NCNN_STDIO
  47. int Reduction::load_param(const unsigned char*& mem)
  48. {
  49. operation = *(int*)(mem);
  50. mem += 4;
  51. dim = *(int*)(mem);
  52. mem += 4;
  53. coeff = *(float*)(mem);
  54. mem += 4;
  55. return 0;
  56. }
  57. int Reduction::forward(const Mat& bottom_blob, Mat& top_blob) const
  58. {
  59. int w = bottom_blob.w;
  60. int h = bottom_blob.h;
  61. int channels = bottom_blob.c;
  62. int size = w * h;
  63. if (dim == 0)
  64. {
  65. // w h c -> X X X
  66. top_blob.create(1);
  67. }
  68. else if (dim == 1)
  69. {
  70. // w h c -> X X c
  71. top_blob.create(channels);
  72. }
  73. else if (dim == 2)
  74. {
  75. // w h c -> X h c
  76. top_blob.create(h, channels);
  77. }
  78. else if (dim == -1)
  79. {
  80. // w h c -> w X X
  81. top_blob.create(w);
  82. }
  83. else if (dim == -2)
  84. {
  85. // w h c -> w h X
  86. top_blob.create(w, h);
  87. }
  88. if (top_blob.empty())
  89. return -100;
  90. if (operation == ReductionOp_SUM)
  91. {
  92. if (dim == 0)
  93. {
  94. Mat sums(channels);
  95. if (sums.empty())
  96. return -100;
  97. float* sums_ptr = sums;
  98. #pragma omp parallel for
  99. for (int q=0; q<channels; q++)
  100. {
  101. const float* ptr = bottom_blob.channel(q);
  102. float sum = 0.f;
  103. for (int i=0; i<size; i++)
  104. {
  105. sum += ptr[i];
  106. }
  107. sums_ptr[q] = sum;
  108. }
  109. float* outptr = top_blob;
  110. float sum = 0.f;
  111. for (int i=0; i<channels; i++)
  112. {
  113. sum += sums_ptr[i];
  114. }
  115. outptr[0] = sum * coeff;
  116. }
  117. else if (dim == 1)
  118. {
  119. float* outptr = top_blob;
  120. #pragma omp parallel for
  121. for (int q=0; q<channels; q++)
  122. {
  123. const float* ptr = bottom_blob.channel(q);
  124. float sum = 0.f;
  125. for (int i=0; i<size; i++)
  126. {
  127. sum += ptr[i];
  128. }
  129. outptr[q] = sum * coeff;
  130. }
  131. }
  132. else if (dim == 2)
  133. {
  134. #pragma omp parallel for
  135. for (int q=0; q<channels; q++)
  136. {
  137. const float* ptr = bottom_blob.channel(q);
  138. float* outptr = top_blob.channel(q);
  139. for (int i=0; i<h; i++)
  140. {
  141. float sum = 0.f;
  142. for (int j=0; j<w; j++)
  143. {
  144. sum += ptr[j];
  145. }
  146. outptr[i] = sum * coeff;
  147. ptr += w;
  148. }
  149. }
  150. }
  151. else if (dim == -1)
  152. {
  153. Mat sums(w, 1, channels);
  154. if (sums.empty())
  155. return -100;
  156. sums.fill(0.f);
  157. #pragma omp parallel for
  158. for (int q=0; q<channels; q++)
  159. {
  160. const float* ptr = bottom_blob.channel(q);
  161. float* sums_ptr = sums.channel(q);
  162. for (int i=0; i<h; i++)
  163. {
  164. for (int j=0; j<w; j++)
  165. {
  166. sums_ptr[j] += ptr[j];
  167. }
  168. ptr += w;
  169. }
  170. }
  171. top_blob.fill(0.f);
  172. float* outptr = top_blob;
  173. for (int q=0; q<channels; q++)
  174. {
  175. const float* sums_ptr = sums.channel(q);
  176. for (int j=0; j<w; j++)
  177. {
  178. outptr[j] += sums_ptr[j];
  179. }
  180. }
  181. for (int j=0; j<w; j++)
  182. {
  183. outptr[j] *= coeff;
  184. }
  185. }
  186. else if (dim == -2)
  187. {
  188. top_blob.fill(0.f);
  189. for (int q=0; q<channels; q++)
  190. {
  191. const float* ptr = bottom_blob.channel(q);
  192. float* outptr = top_blob;
  193. for (int i=0; i<size; i++)
  194. {
  195. outptr[i] += ptr[i];
  196. }
  197. }
  198. float* outptr = top_blob;
  199. for (int i=0; i<size; i++)
  200. {
  201. outptr[i] *= coeff;
  202. }
  203. }
  204. }
  205. else if (operation == ReductionOp_ASUM)
  206. {
  207. if (dim == 0)
  208. {
  209. Mat sums(channels);
  210. if (sums.empty())
  211. return -100;
  212. float* sums_ptr = sums;
  213. #pragma omp parallel for
  214. for (int q=0; q<channels; q++)
  215. {
  216. const float* ptr = bottom_blob.channel(q);
  217. float sum = 0.f;
  218. for (int i=0; i<size; i++)
  219. {
  220. sum += fabs(ptr[i]);
  221. }
  222. sums_ptr[q] = sum;
  223. }
  224. float* outptr = top_blob;
  225. float sum = 0.f;
  226. for (int i=0; i<channels; i++)
  227. {
  228. sum += sums_ptr[i];
  229. }
  230. outptr[0] = sum * coeff;
  231. }
  232. else if (dim == 1)
  233. {
  234. float* outptr = top_blob;
  235. #pragma omp parallel for
  236. for (int q=0; q<channels; q++)
  237. {
  238. const float* ptr = bottom_blob.channel(q);
  239. float sum = 0.f;
  240. for (int i=0; i<size; i++)
  241. {
  242. sum += fabs(ptr[i]);
  243. }
  244. outptr[q] = sum * coeff;
  245. }
  246. }
  247. else if (dim == 2)
  248. {
  249. #pragma omp parallel for
  250. for (int q=0; q<channels; q++)
  251. {
  252. const float* ptr = bottom_blob.channel(q);
  253. float* outptr = top_blob.channel(q);
  254. for (int i=0; i<h; i++)
  255. {
  256. float sum = 0.f;
  257. for (int j=0; j<w; j++)
  258. {
  259. sum += fabs(ptr[j]);
  260. }
  261. outptr[i] = sum * coeff;
  262. ptr += w;
  263. }
  264. }
  265. }
  266. else if (dim == -1)
  267. {
  268. Mat sums(w, 1, channels);
  269. if (sums.empty())
  270. return -100;
  271. sums.fill(0.f);
  272. #pragma omp parallel for
  273. for (int q=0; q<channels; q++)
  274. {
  275. const float* ptr = bottom_blob.channel(q);
  276. float* sums_ptr = sums.channel(q);
  277. for (int i=0; i<h; i++)
  278. {
  279. for (int j=0; j<w; j++)
  280. {
  281. sums_ptr[j] += fabs(ptr[j]);
  282. }
  283. ptr += w;
  284. }
  285. }
  286. top_blob.fill(0.f);
  287. float* outptr = top_blob;
  288. for (int q=0; q<channels; q++)
  289. {
  290. const float* sums_ptr = sums.channel(q);
  291. for (int j=0; j<w; j++)
  292. {
  293. outptr[j] += fabs(sums_ptr[j]);
  294. }
  295. }
  296. for (int j=0; j<w; j++)
  297. {
  298. outptr[j] *= coeff;
  299. }
  300. }
  301. else if (dim == -2)
  302. {
  303. top_blob.fill(0.f);
  304. for (int q=0; q<channels; q++)
  305. {
  306. const float* ptr = bottom_blob.channel(q);
  307. float* outptr = top_blob;
  308. for (int i=0; i<size; i++)
  309. {
  310. outptr[i] += fabs(ptr[i]);
  311. }
  312. }
  313. float* outptr = top_blob;
  314. for (int i=0; i<size; i++)
  315. {
  316. outptr[i] *= coeff;
  317. }
  318. }
  319. }
  320. else if (operation == ReductionOp_SUMSQ)
  321. {
  322. if (dim == 0)
  323. {
  324. Mat sums(channels);
  325. if (sums.empty())
  326. return -100;
  327. float* sums_ptr = sums;
  328. #pragma omp parallel for
  329. for (int q=0; q<channels; q++)
  330. {
  331. const float* ptr = bottom_blob.channel(q);
  332. float sum = 0.f;
  333. for (int i=0; i<size; i++)
  334. {
  335. sum += ptr[i] * ptr[i];
  336. }
  337. sums_ptr[q] = sum;
  338. }
  339. float* outptr = top_blob;
  340. float sum = 0.f;
  341. for (int i=0; i<channels; i++)
  342. {
  343. sum += sums_ptr[i];
  344. }
  345. outptr[0] = sum * coeff;
  346. }
  347. else if (dim == 1)
  348. {
  349. float* outptr = top_blob;
  350. #pragma omp parallel for
  351. for (int q=0; q<channels; q++)
  352. {
  353. const float* ptr = bottom_blob.channel(q);
  354. float sum = 0.f;
  355. for (int i=0; i<size; i++)
  356. {
  357. sum += ptr[i] * ptr[i];
  358. }
  359. outptr[q] = sum * coeff;
  360. }
  361. }
  362. else if (dim == 2)
  363. {
  364. #pragma omp parallel for
  365. for (int q=0; q<channels; q++)
  366. {
  367. const float* ptr = bottom_blob.channel(q);
  368. float* outptr = top_blob.channel(q);
  369. for (int i=0; i<h; i++)
  370. {
  371. float sum = 0.f;
  372. for (int j=0; j<w; j++)
  373. {
  374. sum += ptr[i] * ptr[i];
  375. }
  376. outptr[i] = sum * coeff;
  377. ptr += w;
  378. }
  379. }
  380. }
  381. else if (dim == -1)
  382. {
  383. Mat sums(w, 1, channels);
  384. if (sums.empty())
  385. return -100;
  386. sums.fill(0.f);
  387. #pragma omp parallel for
  388. for (int q=0; q<channels; q++)
  389. {
  390. const float* ptr = bottom_blob.channel(q);
  391. float* sums_ptr = sums.channel(q);
  392. for (int i=0; i<h; i++)
  393. {
  394. for (int j=0; j<w; j++)
  395. {
  396. sums_ptr[j] += ptr[j] * ptr[j];
  397. }
  398. ptr += w;
  399. }
  400. }
  401. top_blob.fill(0.f);
  402. float* outptr = top_blob;
  403. for (int q=0; q<channels; q++)
  404. {
  405. const float* sums_ptr = sums.channel(q);
  406. for (int j=0; j<w; j++)
  407. {
  408. outptr[j] += sums_ptr[j];
  409. }
  410. }
  411. for (int j=0; j<w; j++)
  412. {
  413. outptr[j] *= coeff;
  414. }
  415. }
  416. else if (dim == -2)
  417. {
  418. top_blob.fill(0.f);
  419. for (int q=0; q<channels; q++)
  420. {
  421. const float* ptr = bottom_blob.channel(q);
  422. float* outptr = top_blob;
  423. for (int i=0; i<size; i++)
  424. {
  425. outptr[i] += ptr[i] * ptr[i];
  426. }
  427. }
  428. float* outptr = top_blob;
  429. for (int i=0; i<size; i++)
  430. {
  431. outptr[i] *= coeff;
  432. }
  433. }
  434. }
  435. else if (operation == ReductionOp_MEAN)
  436. {
  437. if (dim == 0)
  438. {
  439. Mat sums(channels);
  440. if (sums.empty())
  441. return -100;
  442. float* sums_ptr = sums;
  443. #pragma omp parallel for
  444. for (int q=0; q<channels; q++)
  445. {
  446. const float* ptr = bottom_blob.channel(q);
  447. float sum = 0.f;
  448. for (int i=0; i<size; i++)
  449. {
  450. sum += ptr[i];
  451. }
  452. sums_ptr[q] = sum;
  453. }
  454. float* outptr = top_blob;
  455. float sum = 0.f;
  456. for (int i=0; i<channels; i++)
  457. {
  458. sum += sums_ptr[i];
  459. }
  460. outptr[0] = sum / (channels * size) * coeff;
  461. }
  462. else if (dim == 1)
  463. {
  464. float* outptr = top_blob;
  465. #pragma omp parallel for
  466. for (int q=0; q<channels; q++)
  467. {
  468. const float* ptr = bottom_blob.channel(q);
  469. float sum = 0.f;
  470. for (int i=0; i<size; i++)
  471. {
  472. sum += ptr[i];
  473. }
  474. outptr[q] = sum / size * coeff;
  475. }
  476. }
  477. else if (dim == 2)
  478. {
  479. #pragma omp parallel for
  480. for (int q=0; q<channels; q++)
  481. {
  482. const float* ptr = bottom_blob.channel(q);
  483. float* outptr = top_blob.channel(q);
  484. for (int i=0; i<h; i++)
  485. {
  486. float sum = 0.f;
  487. for (int j=0; j<w; j++)
  488. {
  489. sum += ptr[j];
  490. }
  491. outptr[i] = sum / w * coeff;
  492. ptr += w;
  493. }
  494. }
  495. }
  496. else if (dim == -1)
  497. {
  498. Mat sums(w, 1, channels);
  499. if (sums.empty())
  500. return -100;
  501. sums.fill(0.f);
  502. #pragma omp parallel for
  503. for (int q=0; q<channels; q++)
  504. {
  505. const float* ptr = bottom_blob.channel(q);
  506. float* sums_ptr = sums.channel(q);
  507. for (int i=0; i<h; i++)
  508. {
  509. for (int j=0; j<w; j++)
  510. {
  511. sums_ptr[j] += ptr[j];
  512. }
  513. ptr += w;
  514. }
  515. }
  516. top_blob.fill(0.f);
  517. float* outptr = top_blob;
  518. for (int q=0; q<channels; q++)
  519. {
  520. const float* sums_ptr = sums.channel(q);
  521. for (int j=0; j<w; j++)
  522. {
  523. outptr[j] += sums_ptr[j];
  524. }
  525. }
  526. for (int j=0; j<w; j++)
  527. {
  528. outptr[j] *= coeff / h / channels;
  529. }
  530. }
  531. else if (dim == -2)
  532. {
  533. top_blob.fill(0.f);
  534. for (int q=0; q<channels; q++)
  535. {
  536. const float* ptr = bottom_blob.channel(q);
  537. float* outptr = top_blob;
  538. for (int i=0; i<size; i++)
  539. {
  540. outptr[i] += ptr[i];
  541. }
  542. }
  543. float* outptr = top_blob;
  544. for (int i=0; i<size; i++)
  545. {
  546. outptr[i] *= coeff / channels;
  547. }
  548. }
  549. }
  550. else if (operation == ReductionOp_MAX)
  551. {
  552. if (dim == 0)
  553. {
  554. Mat maxs(channels);
  555. if (maxs.empty())
  556. return -100;
  557. float* maxs_ptr = maxs;
  558. #pragma omp parallel for
  559. for (int q=0; q<channels; q++)
  560. {
  561. const float* ptr = bottom_blob.channel(q);
  562. float max = ptr[0];
  563. for (int i=1; i<size; i++)
  564. {
  565. max = std::max(max, ptr[i]);
  566. }
  567. maxs_ptr[q] = max;
  568. }
  569. float* outptr = top_blob;
  570. float max = maxs_ptr[0];
  571. for (int i=1; i<channels; i++)
  572. {
  573. max = std::max(max, maxs_ptr[i]);
  574. }
  575. outptr[0] = max * coeff;
  576. }
  577. else if (dim == 1)
  578. {
  579. float* outptr = top_blob;
  580. #pragma omp parallel for
  581. for (int q=0; q<channels; q++)
  582. {
  583. const float* ptr = bottom_blob.channel(q);
  584. float max = ptr[0];
  585. for (int i=1; i<size; i++)
  586. {
  587. max = std::max(max, ptr[i]);
  588. }
  589. outptr[q] = max * coeff;
  590. }
  591. }
  592. else if (dim == 2)
  593. {
  594. #pragma omp parallel for
  595. for (int q=0; q<channels; q++)
  596. {
  597. const float* ptr = bottom_blob.channel(q);
  598. float* outptr = top_blob.channel(q);
  599. for (int i=0; i<h; i++)
  600. {
  601. float max = ptr[0];
  602. for (int j=1; j<w; j++)
  603. {
  604. max = std::max(max, ptr[i]);
  605. }
  606. outptr[i] = max * coeff;
  607. ptr += w;
  608. }
  609. }
  610. }
  611. else if (dim == -1)
  612. {
  613. Mat maxs(w, 1, channels);
  614. if (maxs.empty())
  615. return -100;
  616. #pragma omp parallel for
  617. for (int q=0; q<channels; q++)
  618. {
  619. const float* ptr = bottom_blob.channel(q);
  620. float* maxs_ptr = maxs.channel(q);
  621. for (int j=0; j<w; j++)
  622. {
  623. maxs_ptr[j] = ptr[j];
  624. }
  625. ptr += w;
  626. for (int i=1; i<h; i++)
  627. {
  628. for (int j=0; j<w; j++)
  629. {
  630. maxs_ptr[j] = std::max(maxs_ptr[j], ptr[j]);
  631. }
  632. ptr += w;
  633. }
  634. }
  635. top_blob.fill(0.f);
  636. float* outptr = top_blob;
  637. const float* maxs_ptr = maxs.channel(0);
  638. for (int j=0; j<w; j++)
  639. {
  640. outptr[j] = maxs_ptr[j];
  641. }
  642. for (int q=1; q<channels; q++)
  643. {
  644. const float* maxs_ptr = maxs.channel(q);
  645. for (int j=0; j<w; j++)
  646. {
  647. outptr[j] = std::max(outptr[j], maxs_ptr[j]);
  648. }
  649. }
  650. for (int j=0; j<w; j++)
  651. {
  652. outptr[j] *= coeff;
  653. }
  654. }
  655. else if (dim == -2)
  656. {
  657. top_blob.fill(0.f);
  658. float* outptr = top_blob;
  659. const float* ptr = bottom_blob.channel(0);
  660. for (int i=0; i<size; i++)
  661. {
  662. outptr[i] = ptr[i];
  663. }
  664. for (int q=1; q<channels; q++)
  665. {
  666. const float* ptr = bottom_blob.channel(q);
  667. float* outptr = top_blob;
  668. for (int i=0; i<size; i++)
  669. {
  670. outptr[i] = std::max(outptr[i], ptr[i]);
  671. }
  672. }
  673. for (int i=0; i<size; i++)
  674. {
  675. outptr[i] *= coeff;
  676. }
  677. }
  678. }
  679. else if (operation == ReductionOp_MIN)
  680. {
  681. if (dim == 0)
  682. {
  683. Mat mins(channels);
  684. if (mins.empty())
  685. return -100;
  686. float* mins_ptr = mins;
  687. #pragma omp parallel for
  688. for (int q=0; q<channels; q++)
  689. {
  690. const float* ptr = bottom_blob.channel(q);
  691. float min = ptr[0];
  692. for (int i=1; i<size; i++)
  693. {
  694. min = std::min(min, ptr[i]);
  695. }
  696. mins_ptr[q] = min;
  697. }
  698. float* outptr = top_blob;
  699. float min = mins_ptr[0];
  700. for (int i=1; i<channels; i++)
  701. {
  702. min = std::min(min, mins_ptr[i]);
  703. }
  704. outptr[0] = min * coeff;
  705. }
  706. else if (dim == 1)
  707. {
  708. float* outptr = top_blob;
  709. #pragma omp parallel for
  710. for (int q=0; q<channels; q++)
  711. {
  712. const float* ptr = bottom_blob.channel(q);
  713. float min = ptr[0];
  714. for (int i=1; i<size; i++)
  715. {
  716. min = std::min(min, ptr[i]);
  717. }
  718. outptr[q] = min * coeff;
  719. }
  720. }
  721. else if (dim == 2)
  722. {
  723. #pragma omp parallel for
  724. for (int q=0; q<channels; q++)
  725. {
  726. const float* ptr = bottom_blob.channel(q);
  727. float* outptr = top_blob.channel(q);
  728. for (int i=0; i<h; i++)
  729. {
  730. float min = ptr[0];
  731. for (int j=1; j<w; j++)
  732. {
  733. min = std::min(min, ptr[i]);
  734. }
  735. outptr[i] = min * coeff;
  736. ptr += w;
  737. }
  738. }
  739. }
  740. else if (dim == -1)
  741. {
  742. Mat mins(w, 1, channels);
  743. if (mins.empty())
  744. return -100;
  745. #pragma omp parallel for
  746. for (int q=0; q<channels; q++)
  747. {
  748. const float* ptr = bottom_blob.channel(q);
  749. float* mins_ptr = mins.channel(q);
  750. for (int j=0; j<w; j++)
  751. {
  752. mins_ptr[j] = ptr[j];
  753. }
  754. ptr += w;
  755. for (int i=1; i<h; i++)
  756. {
  757. for (int j=0; j<w; j++)
  758. {
  759. mins_ptr[j] = std::min(mins_ptr[j], ptr[j]);
  760. }
  761. ptr += w;
  762. }
  763. }
  764. top_blob.fill(0.f);
  765. float* outptr = top_blob;
  766. const float* mins_ptr = mins.channel(0);
  767. for (int j=0; j<w; j++)
  768. {
  769. outptr[j] = mins_ptr[j];
  770. }
  771. for (int q=1; q<channels; q++)
  772. {
  773. const float* mins_ptr = mins.channel(q);
  774. for (int j=0; j<w; j++)
  775. {
  776. outptr[j] = std::min(outptr[j], mins_ptr[j]);
  777. }
  778. }
  779. for (int j=0; j<w; j++)
  780. {
  781. outptr[j] *= coeff;
  782. }
  783. }
  784. else if (dim == -2)
  785. {
  786. top_blob.fill(0.f);
  787. float* outptr = top_blob;
  788. const float* ptr = bottom_blob.channel(0);
  789. for (int i=0; i<size; i++)
  790. {
  791. outptr[i] = ptr[i];
  792. }
  793. for (int q=1; q<channels; q++)
  794. {
  795. const float* ptr = bottom_blob.channel(q);
  796. float* outptr = top_blob;
  797. for (int i=0; i<size; i++)
  798. {
  799. outptr[i] = std::min(outptr[i], ptr[i]);
  800. }
  801. }
  802. for (int i=0; i<size; i++)
  803. {
  804. outptr[i] *= coeff;
  805. }
  806. }
  807. }
  808. return 0;
  809. }
  810. } // namespace ncnn