Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
[platform/upstream/opencv.git] / modules / dnn / src / layers / elementwise_layers.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 // Copyright (C) 2017, Intel Corporation, all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "../precomp.hpp"
44 #include "layers_common.hpp"
45 #include "../op_cuda.hpp"
46 #include "../op_halide.hpp"
47 #include "../op_inf_engine.hpp"
48 #include "../op_vkcom.hpp"
49 #include <opencv2/dnn/shape_utils.hpp>
50 #include <iostream>
51
52 #ifdef HAVE_OPENCL
53 #include "opencl_kernels_dnn.hpp"
54 #endif
55
56 #ifdef HAVE_CUDA
57 #include "../cuda4dnn/primitives/activation.hpp"
58 using namespace cv::dnn::cuda4dnn;
59 #endif
60
61 namespace cv
62 {
63 namespace dnn
64 {
65
66 using std::abs;
67 using std::exp;
68 using std::tanh;
69 using std::pow;
70
71 template<typename Func>
72 class ElementWiseLayer : public Func::Layer
73 {
74 public:
75     class PBody : public cv::ParallelLoopBody
76     {
77     public:
78         const Func* func_;
79         const Mat* src_;
80         Mat* dst_;
81         int nstripes_;
82
83         PBody(const Func &func, const Mat &src, Mat& dst, int nstripes)
84         {
85             func_ = &func;
86             src_ = &src;
87             dst_ = &dst;
88             nstripes_ = nstripes;
89         }
90
91         void operator()(const Range &r) const CV_OVERRIDE
92         {
93             int nstripes = nstripes_, nsamples = 1, outCn = 1;
94             size_t planeSize = 1;
95
96             if (src_->dims > 1)
97             {
98                 nsamples = src_->size[0];
99                 outCn = src_->size[1];
100             }
101             else
102                 outCn = src_->size[0];
103
104             for (int i = 2; i < src_->dims; ++i)
105                 planeSize *= src_->size[i];
106
107             size_t stripeSize = (planeSize + nstripes - 1)/nstripes;
108             size_t stripeStart = r.start*stripeSize;
109             size_t stripeEnd = std::min(r.end*stripeSize, planeSize);
110
111             for( int i = 0; i < nsamples; i++ )
112             {
113                 const float* srcptr = src_->ptr<float>(i) + stripeStart;
114                 float* dstptr = dst_->ptr<float>(i) + stripeStart;
115                 func_->apply(srcptr, dstptr, (int)(stripeEnd - stripeStart), planeSize, 0, outCn);
116             }
117         }
118     };
119
120     ElementWiseLayer(const Func &f=Func()) : run_parallel(false) { func = f; }
121
122     virtual bool supportBackend(int backendId) CV_OVERRIDE
123     {
124         return func.supportBackend(backendId, this->preferableTarget);
125     }
126
127     virtual Ptr<BackendNode> tryAttach(const Ptr<BackendNode>& node) CV_OVERRIDE
128     {
129         switch (node->backendId)
130         {
131             case DNN_BACKEND_HALIDE:
132             {
133 #ifdef HAVE_HALIDE
134                 auto base = node.dynamicCast<HalideBackendNode>();
135                 Halide::Func& input = base->funcs.back();
136                 Halide::Var x("x"), y("y"), c("c"), n("n");
137                 Halide::Func top = (this->name.empty() ? Halide::Func() : Halide::Func(this->name));
138                 func.attachHalide(input(x, y, c, n), top);
139                 return Ptr<BackendNode>(new HalideBackendNode(base, top));
140 #endif  // HAVE_HALIDE
141                 break;
142             }
143         }
144         return Ptr<BackendNode>();
145     }
146
147     virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs) CV_OVERRIDE
148     {
149 #ifdef HAVE_HALIDE
150         Halide::Buffer<float> input = halideBuffer(inputs[0]);
151         Halide::Var x("x"), y("y"), c("c"), n("n");
152         Halide::Func top = (this->name.empty() ? Halide::Func() : Halide::Func(this->name));
153         func.attachHalide(input(x, y, c, n), top);
154         return Ptr<BackendNode>(new HalideBackendNode(top));
155 #endif  // HAVE_HALIDE
156         return Ptr<BackendNode>();
157     }
158
159 #ifdef HAVE_INF_ENGINE
160     virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE
161     {
162         InferenceEngine::Builder::Layer ieLayer = func.initInfEngineBuilderAPI();
163         ieLayer.setName(this->name);
164         return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
165     }
166 #endif  // HAVE_INF_ENGINE
167
168     virtual Ptr<BackendNode> initVkCom(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE
169     {
170 #ifdef HAVE_VULKAN
171         return Ptr<BackendNode>(new VkComBackendNode(inputs, func.initVkCom()));
172 #endif  // HAVE_VULKAN
173         return Ptr<BackendNode>();
174     }
175
176     virtual bool tryFuse(Ptr<dnn::Layer>& top) CV_OVERRIDE
177     {
178         return func.tryFuse(top);
179     }
180
181     void getScaleShift(Mat& scale_, Mat& shift_) const CV_OVERRIDE
182     {
183         func.getScaleShift(scale_, shift_);
184     }
185
186     bool getMemoryShapes(const std::vector<MatShape> &inputs,
187                          const int requiredOutputs,
188                          std::vector<MatShape> &outputs,
189                          std::vector<MatShape> &internals) const CV_OVERRIDE
190     {
191         Layer::getMemoryShapes(inputs, requiredOutputs, outputs, internals);
192         return true;
193     }
194
195     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
196     {
197         CV_TRACE_FUNCTION();
198
199         CV_OCL_RUN(IS_DNN_OPENCL_TARGET(this->preferableTarget),
200                    func.applyOCL(inputs_arr, outputs_arr, internals_arr))
201
202         if (inputs_arr.depth() == CV_16S)
203         {
204             Layer::forward_fallback(inputs_arr, outputs_arr, internals_arr);
205             return;
206         }
207
208         std::vector<Mat> inputs, outputs;
209         inputs_arr.getMatVector(inputs);
210         outputs_arr.getMatVector(outputs);
211
212         for (size_t i = 0; i < inputs.size(); i++)
213         {
214             const Mat &src = inputs[i];
215             Mat &dst = outputs[i];
216             CV_Assert(src.size == dst.size && src.type() == dst.type() &&
217                       src.isContinuous() && dst.isContinuous() && src.type() == CV_32F);
218
219             const int nstripes = getNumThreads();
220             PBody body(func, src, dst, nstripes);
221             parallel_for_(Range(0, nstripes), body, nstripes);
222         }
223     }
224
225     void forwardSlice(const float* src, float* dst, int len, size_t planeSize, int cn0, int cn1) const CV_OVERRIDE
226     {
227         func.apply(src, dst, len, planeSize, cn0, cn1);
228     }
229
230 #ifdef HAVE_CUDA
231     Ptr<BackendNode> initCUDA(
232         void *context_,
233         const std::vector<Ptr<BackendWrapper>>& inputs,
234         const std::vector<Ptr<BackendWrapper>>& outputs
235     ) override
236     {
237         auto context = reinterpret_cast<csl::CSLContext*>(context_);
238         return func.initCUDA(Layer::preferableTarget, context->stream);
239     }
240 #endif
241
242     virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
243                            const std::vector<MatShape> &outputs) const CV_OVERRIDE
244     {
245         long flops = 0;
246         for (int i = 0; i < outputs.size(); i++)
247         {
248             flops += total(outputs[i]) * func.getFLOPSPerElement();
249         }
250         return flops;
251     }
252
253     Func func;
254     bool run_parallel;
255 };
256
257 #ifdef HAVE_OPENCL
258 static String oclGetTMacro(const UMat &m)
259 {
260     String str_name = ocl::typeToStr(m.type());
261
262     if (str_name == "short")
263         str_name = "half";
264
265     return format("-DT=%s -Dconvert_T=convert_%s ", str_name.c_str(), str_name.c_str());
266 }
267 #endif
268
269 struct ReLUFunctor
270 {
271     typedef ReLULayer Layer;
272     float slope;
273
274     explicit ReLUFunctor(float slope_=1.f) : slope(slope_) {}
275
276     bool supportBackend(int backendId, int)
277     {
278 #ifdef HAVE_INF_ENGINE
279         if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
280             return slope >= 0 || !INF_ENGINE_VER_MAJOR_EQ(INF_ENGINE_RELEASE_2019R1);
281 #endif
282         return backendId == DNN_BACKEND_OPENCV ||
283                backendId == DNN_BACKEND_CUDA ||
284                backendId == DNN_BACKEND_HALIDE ||
285                backendId == DNN_BACKEND_VKCOM;
286     }
287
288     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
289     {
290         float s = slope;
291         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
292         {
293             int i = 0;
294 #if CV_SIMD128
295             v_float32x4 s4 = v_setall_f32(s), z = v_setzero_f32();
296             for( ; i <= len - 16; i += 16 )
297             {
298                 v_float32x4 x0 = v_load(srcptr + i);
299                 v_float32x4 x1 = v_load(srcptr + i + 4);
300                 v_float32x4 x2 = v_load(srcptr + i + 8);
301                 v_float32x4 x3 = v_load(srcptr + i + 12);
302                 x0 = v_select(x0 >= z, x0, x0*s4);
303                 x1 = v_select(x1 >= z, x1, x1*s4);
304                 x2 = v_select(x2 >= z, x2, x2*s4);
305                 x3 = v_select(x3 >= z, x3, x3*s4);
306                 v_store(dstptr + i, x0);
307                 v_store(dstptr + i + 4, x1);
308                 v_store(dstptr + i + 8, x2);
309                 v_store(dstptr + i + 12, x3);
310             }
311 #endif
312             for( ; i < len; i++ )
313             {
314                 float x = srcptr[i];
315                 dstptr[i] = x >= 0.f ? x : s*x;
316             }
317         }
318     }
319
320 #ifdef HAVE_CUDA
321     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
322     {
323         return make_cuda_node<cuda4dnn::ReLUOp>(target, stream, slope);
324     }
325 #endif
326
327 #ifdef HAVE_OPENCL
328     bool initKernel(ocl::Kernel &ker, const UMat &src) const
329     {
330         const char *buildoptSlope = (slope == 0) ? "-DRELU_NO_SLOPE" : "";
331         String buildopt = oclGetTMacro(src) + buildoptSlope;
332
333         if (!ker.create("ReLUForward", ocl::dnn::activations_oclsrc, buildopt))
334             return false;
335
336         if (slope != 0)
337             ker.set(3, (float)slope);
338
339         return true;
340     }
341
342     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
343     {
344         std::vector<UMat> inputs;
345         std::vector<UMat> outputs;
346
347         inps.getUMatVector(inputs);
348         outs.getUMatVector(outputs);
349
350         for (size_t i = 0; i < inputs.size(); i++)
351         {
352             UMat& src = inputs[i];
353             UMat& dst = outputs[i];
354             CV_Assert(src.isContinuous() && dst.isContinuous() && !src.offset && !dst.offset);
355
356             ocl::Kernel kernel;
357             CV_Assert(initKernel(kernel, src));
358             kernel.set(0, (int)src.total());
359             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
360             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
361
362             size_t gSize = src.total();
363             CV_Assert(kernel.run(1, &gSize, NULL, false));
364         }
365
366         return true;
367     }
368 #endif
369
370 #ifdef HAVE_HALIDE
371     void attachHalide(const Halide::Expr& input, Halide::Func& top)
372     {
373         Halide::Var x("x"), y("y"), c("c"), n("n");
374         if (slope)
375         {
376             top(x, y, c, n) = select(input >= 0.0f, input, slope * input);
377         }
378         else
379         {
380             top(x, y, c, n) = max(input, 0.0f);
381         }
382     }
383 #endif  // HAVE_HALIDE
384
385 #ifdef HAVE_INF_ENGINE
386     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
387     {
388         return InferenceEngine::Builder::ReLULayer("").setNegativeSlope(slope);
389     }
390 #endif  // HAVE_INF_ENGINE
391
392 #ifdef HAVE_VULKAN
393     std::shared_ptr<vkcom::OpBase> initVkCom()
394     {
395         std::shared_ptr<vkcom::OpBase> op(new vkcom::OpReLU(slope));
396         return op;
397     }
398 #endif  // HAVE_VULKAN
399
400     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
401
402     void getScaleShift(Mat&, Mat&) const {}
403
404     int64 getFLOPSPerElement() const { return 1; }
405 };
406
407 struct ReLU6Functor
408 {
409     typedef ReLU6Layer Layer;
410     float minValue, maxValue;
411
412     ReLU6Functor(float minValue_ = 0.0f, float maxValue_ = 6.0f)
413         : minValue(minValue_), maxValue(maxValue_)
414     {
415         CV_Assert(minValue <= maxValue);
416     }
417
418     bool supportBackend(int backendId, int)
419     {
420         return backendId == DNN_BACKEND_OPENCV ||
421                backendId == DNN_BACKEND_CUDA ||
422                backendId == DNN_BACKEND_HALIDE ||
423                backendId == DNN_BACKEND_INFERENCE_ENGINE;
424     }
425
426     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
427     {
428         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
429         {
430             int i = 0;
431 #if CV_SIMD128
432             v_float32x4 minV = v_setall_f32(minValue), maxV = v_setall_f32(maxValue);
433             for( ; i <= len - 16; i += 16 )
434             {
435                 v_float32x4 x0 = v_load(srcptr + i);
436                 v_float32x4 x1 = v_load(srcptr + i + 4);
437                 v_float32x4 x2 = v_load(srcptr + i + 8);
438                 v_float32x4 x3 = v_load(srcptr + i + 12);
439                 x0 = v_min(v_max(minV, x0), maxV);
440                 x1 = v_min(v_max(minV, x1), maxV);
441                 x2 = v_min(v_max(minV, x2), maxV);
442                 x3 = v_min(v_max(minV, x3), maxV);
443                 v_store(dstptr + i, x0);
444                 v_store(dstptr + i + 4, x1);
445                 v_store(dstptr + i + 8, x2);
446                 v_store(dstptr + i + 12, x3);
447             }
448 #endif
449             for( ; i < len; i++ )
450             {
451                 float x = srcptr[i];
452                 if (x >= minValue)
453                     dstptr[i] = x <= maxValue ? x : maxValue;
454                 else
455                     dstptr[i] = minValue;
456             }
457         }
458     }
459
460 #ifdef HAVE_OPENCL
461     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
462     {
463         std::vector<UMat> inputs;
464         std::vector<UMat> outputs;
465
466         inps.getUMatVector(inputs);
467         outs.getUMatVector(outputs);
468         String buildopt = oclGetTMacro(inputs[0]);
469
470         for (size_t i = 0; i < inputs.size(); i++)
471         {
472             UMat& src = inputs[i];
473             UMat& dst = outputs[i];
474
475             ocl::Kernel kernel("ReLU6Forward", ocl::dnn::activations_oclsrc, buildopt);
476             kernel.set(0, (int)src.total());
477             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
478             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
479             kernel.set(3, (float)minValue);
480             kernel.set(4, (float)maxValue);
481
482             size_t gSize = src.total();
483             CV_Assert(kernel.run(1, &gSize, NULL, false));
484         }
485
486         return true;
487     }
488 #endif
489
490 #ifdef HAVE_CUDA
491     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
492     {
493         return make_cuda_node<cuda4dnn::ClippedReLUOp>(target, stream, minValue, maxValue);
494     }
495 #endif
496
497 #ifdef HAVE_HALIDE
498     void attachHalide(const Halide::Expr& input, Halide::Func& top)
499     {
500         Halide::Var x("x"), y("y"), c("c"), n("n");
501         top(x, y, c, n) = clamp(input, minValue, maxValue);
502     }
503 #endif  // HAVE_HALIDE
504
505 #ifdef HAVE_INF_ENGINE
506     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
507     {
508         return InferenceEngine::Builder::ClampLayer("").setMinValue(minValue).setMaxValue(maxValue);
509     }
510 #endif  // HAVE_INF_ENGINE
511
512 #ifdef HAVE_VULKAN
513     std::shared_ptr<vkcom::OpBase> initVkCom()
514     {
515         // TODO: add vkcom implementation
516         return std::shared_ptr<vkcom::OpBase>();
517     }
518 #endif  // HAVE_VULKAN
519
520     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
521
522     void getScaleShift(Mat&, Mat&) const {}
523
524     int64 getFLOPSPerElement() const { return 2; }
525 };
526
527 struct TanHFunctor
528 {
529     typedef TanHLayer Layer;
530
531     bool supportBackend(int backendId, int)
532     {
533         return backendId == DNN_BACKEND_OPENCV ||
534                backendId == DNN_BACKEND_CUDA ||
535                backendId == DNN_BACKEND_HALIDE ||
536                backendId == DNN_BACKEND_INFERENCE_ENGINE;
537     }
538
539     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
540     {
541         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
542         {
543             for( int i = 0; i < len; i++ )
544             {
545                 float x = srcptr[i];
546                 dstptr[i] = tanh(x);
547             }
548         }
549     }
550
551 #ifdef HAVE_OPENCL
552     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
553     {
554         std::vector<UMat> inputs;
555         std::vector<UMat> outputs;
556
557         inps.getUMatVector(inputs);
558         outs.getUMatVector(outputs);
559         String buildopt = oclGetTMacro(inputs[0]);
560
561         for (size_t i = 0; i < inputs.size(); i++)
562         {
563             UMat& src = inputs[i];
564             UMat& dst = outputs[i];
565
566             ocl::Kernel kernel("TanHForward", ocl::dnn::activations_oclsrc, buildopt);
567             kernel.set(0, (int)src.total());
568             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
569             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
570
571             size_t gSize = src.total();
572             CV_Assert(kernel.run(1, &gSize, NULL, false));
573         }
574
575         return true;
576     }
577 #endif
578
579 #ifdef HAVE_CUDA
580     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
581     {
582         return make_cuda_node<cuda4dnn::TanHOp>(target, stream);
583     }
584 #endif
585
586 #ifdef HAVE_HALIDE
587     void attachHalide(const Halide::Expr& input, Halide::Func& top)
588     {
589         Halide::Var x("x"), y("y"), c("c"), n("n");
590         top(x, y, c, n) = tanh(input);
591     }
592 #endif  // HAVE_HALIDE
593
594 #ifdef HAVE_INF_ENGINE
595     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
596     {
597         return InferenceEngine::Builder::TanHLayer("");
598     }
599 #endif  // HAVE_INF_ENGINE
600
601 #ifdef HAVE_VULKAN
602     std::shared_ptr<vkcom::OpBase> initVkCom()
603     {
604         // TODO: add vkcom implementation
605         return std::shared_ptr<vkcom::OpBase>();
606     }
607 #endif  // HAVE_VULKAN
608
609     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
610
611     void getScaleShift(Mat&, Mat&) const {}
612
613     int64 getFLOPSPerElement() const { return 1; }
614 };
615
616 struct SigmoidFunctor
617 {
618     typedef SigmoidLayer Layer;
619
620     bool supportBackend(int backendId, int)
621     {
622         return backendId == DNN_BACKEND_OPENCV ||
623                backendId == DNN_BACKEND_CUDA ||
624                backendId == DNN_BACKEND_HALIDE ||
625                backendId == DNN_BACKEND_INFERENCE_ENGINE;
626     }
627
628     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
629     {
630         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
631         {
632             for( int i = 0; i < len; i++ )
633             {
634                 float x = srcptr[i];
635                 dstptr[i] = 1.f/(1.f + exp(-x));
636             }
637         }
638     }
639
640 #ifdef HAVE_OPENCL
641     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
642     {
643         std::vector<UMat> inputs;
644         std::vector<UMat> outputs;
645
646         inps.getUMatVector(inputs);
647         outs.getUMatVector(outputs);
648         String buildopt = oclGetTMacro(inputs[0]);
649
650         for (size_t i = 0; i < inputs.size(); i++)
651         {
652             UMat& src = inputs[i];
653             UMat& dst = outputs[i];
654
655             ocl::Kernel kernel("SigmoidForward", ocl::dnn::activations_oclsrc, buildopt);
656             kernel.set(0, (int)src.total());
657             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
658             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
659
660             size_t gSize = src.total();
661             CV_Assert(kernel.run(1, &gSize, NULL, false));
662         }
663
664         return true;
665     }
666 #endif
667
668 #ifdef HAVE_CUDA
669     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
670     {
671         return make_cuda_node<cuda4dnn::SigmoidOp>(target, stream);
672     }
673 #endif
674
675 #ifdef HAVE_HALIDE
676     void attachHalide(const Halide::Expr& input, Halide::Func& top)
677     {
678         Halide::Var x("x"), y("y"), c("c"), n("n");
679         top(x, y, c, n) = 1.0f / (1.0f + exp(-input));
680     }
681 #endif  // HAVE_HALIDE
682
683 #ifdef HAVE_INF_ENGINE
684     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
685     {
686         return InferenceEngine::Builder::SigmoidLayer("");
687     }
688 #endif  // HAVE_INF_ENGINE
689
690 #ifdef HAVE_VULKAN
691     std::shared_ptr<vkcom::OpBase> initVkCom()
692     {
693         // TODO: add vkcom implementation
694         return std::shared_ptr<vkcom::OpBase>();
695     }
696 #endif  // HAVE_VULKAN
697
698     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
699
700     void getScaleShift(Mat&, Mat&) const {}
701
702     int64 getFLOPSPerElement() const { return 3; }
703 };
704
705 struct ELUFunctor
706 {
707     typedef ELULayer Layer;
708
709     explicit ELUFunctor() {}
710
711     bool supportBackend(int backendId, int)
712     {
713         return backendId == DNN_BACKEND_OPENCV ||
714                backendId == DNN_BACKEND_CUDA ||
715                backendId == DNN_BACKEND_HALIDE ||
716                backendId == DNN_BACKEND_INFERENCE_ENGINE;
717     }
718
719     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
720     {
721         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
722         {
723             for(int i = 0; i < len; i++ )
724             {
725                 float x = srcptr[i];
726                 dstptr[i] = x >= 0.f ? x : exp(x) - 1;
727             }
728         }
729     }
730
731 #ifdef HAVE_OPENCL
732     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
733     {
734         std::vector<UMat> inputs;
735         std::vector<UMat> outputs;
736
737         inps.getUMatVector(inputs);
738         outs.getUMatVector(outputs);
739         String buildopt = oclGetTMacro(inputs[0]);
740
741         for (size_t i = 0; i < inputs.size(); i++)
742         {
743             UMat& src = inputs[i];
744             UMat& dst = outputs[i];
745
746             ocl::Kernel kernel("ELUForward", ocl::dnn::activations_oclsrc, buildopt);
747             kernel.set(0, (int)src.total());
748             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
749             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
750
751             size_t gSize = src.total();
752             CV_Assert(kernel.run(1, &gSize, NULL, false));
753         }
754
755         return true;
756     }
757 #endif
758
759 #ifdef HAVE_CUDA
760     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
761     {
762         return make_cuda_node<cuda4dnn::ELUOp>(target, stream);
763     }
764 #endif
765
766 #ifdef HAVE_HALIDE
767     void attachHalide(const Halide::Expr& input, Halide::Func& top)
768     {
769         Halide::Var x("x"), y("y"), c("c"), n("n");
770         top(x, y, c, n) = select(input >= 0.0f, input, exp(input) - 1);
771     }
772 #endif  // HAVE_HALIDE
773
774 #ifdef HAVE_INF_ENGINE
775     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
776     {
777         return InferenceEngine::Builder::ELULayer("");
778     }
779 #endif  // HAVE_INF_ENGINE
780
781 #ifdef HAVE_VULKAN
782     std::shared_ptr<vkcom::OpBase> initVkCom()
783     {
784         // TODO: add vkcom implementation
785         return std::shared_ptr<vkcom::OpBase>();
786     }
787 #endif  // HAVE_VULKAN
788
789     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
790
791     void getScaleShift(Mat&, Mat&) const {}
792
793     int64 getFLOPSPerElement() const { return 2; }
794 };
795
796 struct AbsValFunctor
797 {
798     typedef AbsLayer Layer;
799
800     bool supportBackend(int backendId, int)
801     {
802 #ifdef HAVE_INF_ENGINE
803         if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
804             return !INF_ENGINE_VER_MAJOR_EQ(INF_ENGINE_RELEASE_2019R1);
805 #endif
806         return backendId == DNN_BACKEND_OPENCV ||
807                backendId == DNN_BACKEND_CUDA ||
808                backendId == DNN_BACKEND_HALIDE;
809     }
810
811     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
812     {
813         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
814         {
815             for( int i = 0; i < len; i++ )
816             {
817                 float x = srcptr[i];
818                 dstptr[i] = abs(x);
819             }
820         }
821     }
822
823 #ifdef HAVE_OPENCL
824     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
825     {
826         std::vector<UMat> inputs;
827         std::vector<UMat> outputs;
828
829         inps.getUMatVector(inputs);
830         outs.getUMatVector(outputs);
831         String buildopt = oclGetTMacro(inputs[0]);
832
833         for (size_t i = 0; i < inputs.size(); i++)
834         {
835             UMat& src = inputs[i];
836             UMat& dst = outputs[i];
837
838             ocl::Kernel kernel("AbsValForward", ocl::dnn::activations_oclsrc, buildopt);
839             kernel.set(0, (int)src.total());
840             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
841             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
842
843             size_t gSize = src.total();
844             CV_Assert(kernel.run(1, &gSize, NULL, false));
845         }
846
847         return true;
848     }
849 #endif
850
851 #ifdef HAVE_CUDA
852     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
853     {
854         return make_cuda_node<cuda4dnn::AbsValOp>(target, stream);
855     }
856 #endif
857
858 #ifdef HAVE_HALIDE
859     void attachHalide(const Halide::Expr& input, Halide::Func& top)
860     {
861         Halide::Var x("x"), y("y"), c("c"), n("n");
862         top(x, y, c, n) = abs(input);
863     }
864 #endif  // HAVE_HALIDE
865
866 #ifdef HAVE_INF_ENGINE
867     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
868     {
869         return InferenceEngine::Builder::ReLULayer("").setNegativeSlope(-0.999999f);
870     }
871 #endif  // HAVE_INF_ENGINE
872
873 #ifdef HAVE_VULKAN
874     std::shared_ptr<vkcom::OpBase> initVkCom()
875     {
876         // TODO: add vkcom implementation
877         return std::shared_ptr<vkcom::OpBase>();
878     }
879 #endif  // HAVE_VULKAN
880
881     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
882
883     void getScaleShift(Mat&, Mat&) const {}
884
885     int64 getFLOPSPerElement() const { return 1; }
886 };
887
888 struct BNLLFunctor
889 {
890     typedef BNLLLayer Layer;
891
892     bool supportBackend(int backendId, int)
893     {
894         return backendId == DNN_BACKEND_OPENCV ||
895                backendId == DNN_BACKEND_CUDA ||
896                backendId == DNN_BACKEND_HALIDE;
897     }
898
899     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
900     {
901         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
902         {
903             for( int i = 0; i < len; i++ )
904             {
905                 float x = srcptr[i];
906                 // https://github.com/BVLC/caffe/blame/1.0/src/caffe/layers/bnll_layer.cpp#L17
907                 dstptr[i] = x > 0 ? x + log(1. + exp(-x)) : log(1. + exp(x));
908             }
909         }
910     }
911
912 #ifdef HAVE_OPENCL
913     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
914     {
915         std::vector<UMat> inputs;
916         std::vector<UMat> outputs;
917
918         inps.getUMatVector(inputs);
919         outs.getUMatVector(outputs);
920         String buildopt = oclGetTMacro(inputs[0]);
921
922         for (size_t i = 0; i < inputs.size(); i++)
923         {
924             UMat& src = inputs[i];
925             UMat& dst = outputs[i];
926
927             ocl::Kernel kernel("BNLLForward", ocl::dnn::activations_oclsrc, buildopt);
928             kernel.set(0, (int)src.total());
929             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
930             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
931
932             size_t gSize = src.total();
933             CV_Assert(kernel.run(1, &gSize, NULL, false));
934         }
935
936         return true;
937     }
938 #endif
939
940 #ifdef HAVE_CUDA
941     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
942     {
943         return make_cuda_node<cuda4dnn::BNLLOp>(target, stream);
944     }
945 #endif
946
947 #ifdef HAVE_HALIDE
948     void attachHalide(const Halide::Expr& input, Halide::Func& top)
949     {
950         Halide::Var x("x"), y("y"), c("c"), n("n");
951         // https://github.com/BVLC/caffe/blame/1.0/src/caffe/layers/bnll_layer.cpp#L17
952         top(x, y, c, n) = max(input, 0) + log(1.0f + exp(-abs(input)));
953     }
954 #endif  // HAVE_HALIDE
955
956 #ifdef HAVE_INF_ENGINE
957     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
958     {
959         CV_Error(Error::StsNotImplemented, "");
960     }
961 #endif  // HAVE_INF_ENGINE
962
963 #ifdef HAVE_VULKAN
964     std::shared_ptr<vkcom::OpBase> initVkCom()
965     {
966         // TODO: add vkcom implementation
967         return std::shared_ptr<vkcom::OpBase>();
968     }
969 #endif  // HAVE_VULKAN
970
971     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
972
973     void getScaleShift(Mat&, Mat&) const {}
974
975     int64 getFLOPSPerElement() const { return 5; }
976 };
977
978 struct PowerFunctor
979 {
980     typedef PowerLayer Layer;
981
982     float power;
983     float scale;
984     float shift;
985
986     explicit PowerFunctor(float power_ = 1.f, float scale_ = 1.f, float shift_ = 0.f)
987         : power(power_), scale(scale_), shift(shift_) {}
988
989     bool supportBackend(int backendId, int targetId)
990     {
991         if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
992             return (targetId != DNN_TARGET_OPENCL && targetId != DNN_TARGET_OPENCL_FP16) || power == 1.0 || power == 0.5;
993         else
994             return backendId == DNN_BACKEND_OPENCV ||
995                    backendId == DNN_BACKEND_CUDA ||
996                    backendId == DNN_BACKEND_HALIDE;
997     }
998
999     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
1000     {
1001         float a = scale, b = shift, p = power;
1002         if( p == 1.f )
1003         {
1004             for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
1005             {
1006                 for( int i = 0; i < len; i++ )
1007                 {
1008                     float x = srcptr[i];
1009                     dstptr[i] = a*x + b;
1010                 }
1011             }
1012         }
1013         else
1014         {
1015             for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
1016             {
1017                 for( int i = 0; i < len; i++ )
1018                 {
1019                     float x = srcptr[i];
1020                     dstptr[i] = pow(a*x + b, p);
1021                 }
1022             }
1023         }
1024     }
1025
1026 #ifdef HAVE_OPENCL
1027     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
1028     {
1029         std::vector<UMat> inputs;
1030         std::vector<UMat> outputs;
1031
1032         inps.getUMatVector(inputs);
1033         outs.getUMatVector(outputs);
1034         String buildopt = oclGetTMacro(inputs[0]);
1035
1036         for (size_t i = 0; i < inputs.size(); i++)
1037         {
1038             UMat& src = inputs[i];
1039             UMat& dst = outputs[i];
1040
1041             ocl::Kernel kernel("PowForward", ocl::dnn::activations_oclsrc, buildopt);
1042             kernel.set(0, (int)src.total());
1043             kernel.set(1, ocl::KernelArg::PtrReadOnly(src));
1044             kernel.set(2, ocl::KernelArg::PtrWriteOnly(dst));
1045             kernel.set(3, (float)power);
1046             kernel.set(4, (float)scale);
1047             kernel.set(5, (float)shift);
1048
1049             size_t gSize = src.total();
1050             CV_Assert(kernel.run(1, &gSize, NULL, false));
1051         }
1052
1053         return true;
1054     }
1055 #endif
1056
1057 #ifdef HAVE_CUDA
1058     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
1059     {
1060         return make_cuda_node<cuda4dnn::PowerOp>(target, stream, power, scale, shift);
1061     }
1062 #endif
1063
1064 #ifdef HAVE_HALIDE
1065     void attachHalide(const Halide::Expr& input, Halide::Func& top)
1066     {
1067         Halide::Var x("x"), y("y"), c("c"), n("n");
1068         Halide::Expr topExpr = (scale == 1.0f ? input : input * scale);
1069         if (shift)
1070         {
1071             topExpr += shift;
1072         }
1073         if (power != 1.0f)
1074         {
1075             topExpr = pow(topExpr, power);
1076         }
1077         top(x, y, c, n) = topExpr;
1078     }
1079 #endif  // HAVE_HALIDE
1080
1081 #ifdef HAVE_INF_ENGINE
1082     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
1083     {
1084         return InferenceEngine::Builder::PowerLayer("").setPower(power)
1085                                                        .setScale(scale)
1086                                                        .setShift(shift);
1087     }
1088 #endif  // HAVE_INF_ENGINE
1089
1090 #ifdef HAVE_VULKAN
1091     std::shared_ptr<vkcom::OpBase> initVkCom()
1092     {
1093         // TODO: add vkcom implementation
1094         return std::shared_ptr<vkcom::OpBase>();
1095     }
1096 #endif  // HAVE_VULKAN
1097
1098     bool tryFuse(Ptr<dnn::Layer>& top)
1099     {
1100         if (power != 1.0f && shift != 0.0f)
1101             return false;
1102
1103         Mat w, b;
1104         top->getScaleShift(w, b);
1105         if ((w.empty() && b.empty()) || w.total() > 1 || b.total() > 1)
1106             return false;
1107
1108         float nextScale = w.empty() ? 1.0f : w.at<float>(0);
1109         float nextShift = b.empty() ? 0.0f : b.at<float>(0);
1110         scale = std::pow(scale, power) * nextScale;
1111         shift = nextScale * shift + nextShift;
1112         return true;
1113     }
1114
1115     void getScaleShift(Mat& _scale, Mat& _shift) const
1116     {
1117         if (power == 1.0f)
1118         {
1119             _scale = Mat(1, 1, CV_32F, Scalar(scale));
1120             _shift = Mat(1, 1, CV_32F, Scalar(shift));
1121         }
1122     }
1123
1124     int64 getFLOPSPerElement() const { return power == 1 ? 2 : 10; }
1125 };
1126
1127
1128 struct ChannelsPReLUFunctor
1129 {
1130     typedef ChannelsPReLULayer Layer;
1131     Mat scale;
1132 #ifdef HAVE_OPENCL
1133     UMat scale_umat;
1134 #endif
1135
1136     explicit ChannelsPReLUFunctor(const Mat& scale_=Mat()) : scale(scale_)
1137     {
1138     }
1139
1140     bool supportBackend(int backendId, int)
1141     {
1142         return backendId == DNN_BACKEND_OPENCV ||
1143                backendId == DNN_BACKEND_CUDA ||
1144                backendId == DNN_BACKEND_HALIDE ||
1145                backendId == DNN_BACKEND_INFERENCE_ENGINE;
1146     }
1147
1148     void apply(const float* srcptr, float* dstptr, int len, size_t planeSize, int cn0, int cn1) const
1149     {
1150         CV_Assert(scale.isContinuous() && scale.type() == CV_32F);
1151
1152         const float* scaleptr = scale.ptr<float>();
1153         CV_Assert( 0 <= cn0 && cn0 < cn1 && cn1 <= (int)scale.total() );
1154
1155         for( int cn = cn0; cn < cn1; cn++, srcptr += planeSize, dstptr += planeSize )
1156         {
1157             float s = scaleptr[cn];
1158             int i = 0;
1159         #if CV_SIMD128
1160             v_float32x4 s4 = v_setall_f32(s), z = v_setzero_f32();
1161             for( ; i <= len - 16; i += 16 )
1162             {
1163                 v_float32x4 x0 = v_load(srcptr + i);
1164                 v_float32x4 x1 = v_load(srcptr + i + 4);
1165                 v_float32x4 x2 = v_load(srcptr + i + 8);
1166                 v_float32x4 x3 = v_load(srcptr + i + 12);
1167                 x0 = v_select(x0 >= z, x0, x0*s4);
1168                 x1 = v_select(x1 >= z, x1, x1*s4);
1169                 x2 = v_select(x2 >= z, x2, x2*s4);
1170                 x3 = v_select(x3 >= z, x3, x3*s4);
1171                 v_store(dstptr + i, x0);
1172                 v_store(dstptr + i + 4, x1);
1173                 v_store(dstptr + i + 8, x2);
1174                 v_store(dstptr + i + 12, x3);
1175             }
1176         #endif
1177             for( ; i < len; i++ )
1178             {
1179                 float x = srcptr[i];
1180                 dstptr[i] = x >= 0.f ? x : s*x;
1181             }
1182         }
1183     }
1184
1185 #ifdef HAVE_OPENCL
1186     bool applyOCL(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
1187     {
1188         if (scale_umat.empty())
1189             scale.copyTo(scale_umat);
1190
1191         std::vector<UMat> inputs;
1192         std::vector<UMat> outputs;
1193
1194         inps.getUMatVector(inputs);
1195         outs.getUMatVector(outputs);
1196         String buildopt = oclGetTMacro(inputs[0]);
1197
1198         for (size_t i = 0; i < inputs.size(); i++)
1199         {
1200             UMat& src = inputs[i];
1201             UMat& dst = outputs[i];
1202
1203             ocl::Kernel kernel("PReLUForward", ocl::dnn::activations_oclsrc, buildopt);
1204             kernel.set(0, (int)src.total());
1205             kernel.set(1, (int)src.size[1]);
1206             kernel.set(2, (int)total(shape(src), 2));
1207             kernel.set(3, ocl::KernelArg::PtrReadOnly(src));
1208             kernel.set(4, ocl::KernelArg::PtrWriteOnly(dst));
1209             kernel.set(5, ocl::KernelArg::PtrReadOnly(scale_umat));
1210
1211             size_t gSize = src.total();
1212             CV_Assert(kernel.run(1, &gSize, NULL, false));
1213         }
1214
1215         return true;
1216     }
1217 #endif
1218
1219 #ifdef HAVE_CUDA
1220     Ptr<BackendNode> initCUDA(int target, csl::Stream stream)
1221     {
1222         return make_cuda_node<cuda4dnn::ChannelwiseReLUOp>(target, stream, scale);
1223     }
1224 #endif
1225
1226 #ifdef HAVE_HALIDE
1227     void attachHalide(const Halide::Expr& input, Halide::Func& top)
1228     {
1229         Halide::Var x("x"), y("y"), c("c"), n("n");
1230         auto weights = wrapToHalideBuffer(scale, {(int)scale.total()});
1231         top(x, y, c, n) = select(input >= 0.0f, input, weights(c) * input);
1232     }
1233 #endif  // HAVE_HALIDE
1234
1235 #ifdef HAVE_INF_ENGINE
1236     InferenceEngine::Builder::Layer initInfEngineBuilderAPI()
1237     {
1238         InferenceEngine::Builder::Layer l = InferenceEngine::Builder::PReLULayer("");
1239         const size_t numChannels = scale.total();
1240         addConstantData("weights", wrapToInfEngineBlob(scale, {numChannels}, InferenceEngine::Layout::C), l);
1241         return l;
1242     }
1243 #endif  // HAVE_INF_ENGINE
1244
1245 #ifdef HAVE_VULKAN
1246     std::shared_ptr<vkcom::OpBase> initVkCom()
1247     {
1248         // TODO: add vkcom implementation
1249         return std::shared_ptr<vkcom::OpBase>();
1250     }
1251 #endif  // HAVE_VULKAN
1252
1253     bool tryFuse(Ptr<dnn::Layer>&) { return false; }
1254
1255     void getScaleShift(Mat&, Mat&) const {}
1256
1257     int64 getFLOPSPerElement() const { return 1; }
1258 };
1259
1260 #define ACTIVATION_CREATOR_FOR(_Layer, _Functor, ...) \
1261 Ptr<_Layer> _Layer::create() { \
1262     return return Ptr<_Layer>( new ElementWiseLayer<_Functor>(_Functor()) ); }
1263
1264
1265 Ptr<ReLULayer> ReLULayer::create(const LayerParams& params)
1266 {
1267     float negativeSlope = params.get<float>("negative_slope", 0.f);
1268     Ptr<ReLULayer> l(new ElementWiseLayer<ReLUFunctor>(ReLUFunctor(negativeSlope)));
1269     l->setParamsFrom(params);
1270     l->negativeSlope = negativeSlope;
1271
1272     return l;
1273 }
1274
1275 Ptr<ReLU6Layer> ReLU6Layer::create(const LayerParams& params)
1276 {
1277     float minValue = params.get<float>("min_value", 0.0f);
1278     float maxValue = params.get<float>("max_value", 6.0f);
1279     Ptr<ReLU6Layer> l(new ElementWiseLayer<ReLU6Functor>(ReLU6Functor(minValue, maxValue)));
1280     l->setParamsFrom(params);
1281     l->minValue = minValue;
1282     l->maxValue = maxValue;
1283
1284     return l;
1285 }
1286
1287 Ptr<TanHLayer> TanHLayer::create(const LayerParams& params)
1288 {
1289     Ptr<TanHLayer> l(new ElementWiseLayer<TanHFunctor>());
1290     l->setParamsFrom(params);
1291
1292     return l;
1293 }
1294
1295 Ptr<SigmoidLayer> SigmoidLayer::create(const LayerParams& params)
1296 {
1297     Ptr<SigmoidLayer> l(new ElementWiseLayer<SigmoidFunctor>());
1298     l->setParamsFrom(params);
1299
1300     return l;
1301 }
1302
1303 Ptr<ELULayer> ELULayer::create(const LayerParams& params)
1304 {
1305     Ptr<ELULayer> l(new ElementWiseLayer<ELUFunctor>(ELUFunctor()));
1306     l->setParamsFrom(params);
1307
1308     return l;
1309 }
1310
1311 Ptr<AbsLayer> AbsLayer::create(const LayerParams& params)
1312 {
1313     Ptr<AbsLayer> l(new ElementWiseLayer<AbsValFunctor>());
1314     l->setParamsFrom(params);
1315
1316     return l;
1317 }
1318
1319 Ptr<BNLLLayer> BNLLLayer::create(const LayerParams& params)
1320 {
1321     Ptr<BNLLLayer> l(new ElementWiseLayer<BNLLFunctor>());
1322     l->setParamsFrom(params);
1323
1324     return l;
1325 }
1326
1327 Ptr<PowerLayer> PowerLayer::create(const LayerParams& params)
1328 {
1329     float power = params.get<float>("power", 1.0f);
1330     float scale = params.get<float>("scale", 1.0f);
1331     float shift = params.get<float>("shift", 0.0f);
1332     Ptr<PowerLayer> l(new ElementWiseLayer<PowerFunctor>(PowerFunctor(power, scale, shift)));
1333     l->setParamsFrom(params);
1334     l->power = power;
1335     l->scale = scale;
1336     l->shift = shift;
1337
1338     return l;
1339 }
1340
1341 Ptr<Layer> ChannelsPReLULayer::create(const LayerParams& params)
1342 {
1343     CV_Assert(params.blobs.size() == 1);
1344     if (params.blobs[0].total() == 1)
1345     {
1346         LayerParams reluParams = params;
1347         reluParams.set("negative_slope", params.blobs[0].at<float>(0));
1348         return ReLULayer::create(reluParams);
1349     }
1350     Ptr<ChannelsPReLULayer> l(new ElementWiseLayer<ChannelsPReLUFunctor>(ChannelsPReLUFunctor(params.blobs[0])));
1351     l->setParamsFrom(params);
1352
1353     return l;
1354 }
1355
1356 }
1357 }