1 //
2 //  ReductionBufExecution.cpp
3 //  MNN
4 //
5 //  Created by MNN on 2019/10/25.
6 //  Copyright © 2018, Alibaba Group Holding Limited
7 //
8 
9 #ifndef MNN_OPENCL_BUFFER_CLOSED
10 
11 #include "backend/opencl/execution/buffer/ReductionBufExecution.hpp"
12 #include "core/Macro.h"
13 #include "core/TensorUtils.hpp"
14 
15 namespace MNN {
16 namespace OpenCL {
17 
ReductionBufExecution(const MNN::Op * op,Backend * backend)18 ReductionBufExecution::ReductionBufExecution(const MNN::Op* op, Backend* backend) : CommonExecution(backend) {
19 #ifdef LOG_VERBOSE
20     MNN_PRINT("start ReductionBufExecution init !\n");
21 #endif
22     mOpenCLBackend = static_cast<OpenCLBackend *>(backend);
23     auto reduct = op->main_as_ReductionParam();
24     if (nullptr != reduct->dim()) {
25         for (int i = 0; i < reduct->dim()->size(); ++i) {
26             mAxis.push_back(reduct->dim()->data()[i]);
27         }
28     }
29     switch (op->main_as_ReductionParam()->operation()) {
30         case ReductionType_MEAN:
31             mReductType = 0;
32             break;
33         case ReductionType_MAXIMUM:
34             mReductType = 1;
35             break;
36         case ReductionType_MINIMUM:
37             mReductType = 2;
38             break;
39         case ReductionType_PROD:
40             mReductType = 3;
41             break;
42         case ReductionType_SUM:
43             mReductType = 4;
44             break;
45         default:
46             MNN_ASSERT(false);
47             break;
48     }
49     mOp = op;
50 #ifdef LOG_VERBOSE
51     MNN_PRINT("end ReductionBufExecution init !\n");
52 #endif
53 }
54 
onResize(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs)55 ErrorCode ReductionBufExecution::onResize(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
56 
57     MNN_ASSERT(mAxis.size() == 1);
58     MNN_ASSERT(mAxis[0] == 1);
59 
60     auto runtime = mOpenCLBackend->getOpenCLRuntime();
61     auto input = inputs[0];
62     auto output = outputs[0];
63     std::vector<int> inputShape  = tensorShapeFormat(input);
64     //N=outside H=axis W=inside C=1
65     MNN_ASSERT(inputShape[3] == 1);
66 
67     mGlobalWorkSize = {static_cast<uint32_t>(inputShape[0]), static_cast<uint32_t>(inputShape[2])};
68     mLocalWorkSize = {1, 1, 1};
69 
70     std::set<std::string> buildOption;
71     switch (mReductType) {
72         case 0:
73             buildOption.emplace("-DOPERATE=num+in");
74             buildOption.emplace("-DGET_AVG");
75             break;
76         case 1:
77             buildOption.emplace("-DOPERATE=max(num,in)");
78             break;
79         case 2:
80             buildOption.emplace("-DOPERATE=min(num,in)");
81             break;
82         case 3:
83             buildOption.emplace("-DOPERATE=num*in");
84             break;
85         case 4:
86             buildOption.emplace("-DOPERATE=num+in");
87             break;
88         default:
89             MNN_ASSERT(false);
90             break;
91     }
92     mReduct1DKernel = runtime->buildKernel("reduction_buf", "reduct_buf", buildOption);
93 
94     //printf("reduce axis:%d , %d %d %d %d, useLocal:%d\n", mAxis[0], inputShape[0], inputShape[1], inputShape[2], inputShape[3], mUseLocal);
95 
96     mUnits.resize(1);
97     uint32_t idx = 0;
98 
99     mReduct1DKernel.setArg(idx++, mGlobalWorkSize[0]);
100     mReduct1DKernel.setArg(idx++, mGlobalWorkSize[1]);
101     mReduct1DKernel.setArg(idx++, openCLBuffer(input));
102     mReduct1DKernel.setArg(idx++, openCLBuffer(output));
103     mReduct1DKernel.setArg(idx++, static_cast<int32_t>(inputShape[0]));
104     mReduct1DKernel.setArg(idx++, static_cast<int32_t>(inputShape[1]));
105     mReduct1DKernel.setArg(idx++, static_cast<int32_t>(inputShape[2]));
106 
107     return NO_ERROR;
108 }
109 
onExecute(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs)110 ErrorCode ReductionBufExecution::onExecute(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
111 #ifdef LOG_VERBOSE
112     MNN_PRINT("start ReductionBufExecution onExecute !\n");
113 #endif
114 
115     #ifdef ENABLE_OPENCL_TIME_PROFILER
116         cl::Event event;
117         runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize,
118                                mOpenCLBackend->getOpenCLRuntime(), &event);
119         int costTime = (int)mOpenCLBackend->getOpenCLRuntime()->getCostTime(&event);
120         MNN_PRINT("kernel cost:%d    us Reduct1D\n",costTime);
121     #else
122         runKernel2D(mReduct1DKernel, mGlobalWorkSize, mLocalWorkSize,
123                            mOpenCLBackend->getOpenCLRuntime());
124     #endif
125 
126 #ifdef LOG_VERBOSE
127     MNN_PRINT("end ReductionBufExecution onExecute !\n");
128 #endif
129     return NO_ERROR;
130 }
131 
132 class ReductionBufCreator : public OpenCLBackend::Creator {
133 public:
134     virtual ~ReductionBufCreator() = default;
onCreate(const std::vector<Tensor * > & inputs,const std::vector<Tensor * > & outputs,const MNN::Op * op,Backend * backend) const135     virtual Execution *onCreate(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs,
136                                  const MNN::Op *op, Backend *backend) const override {
137         if (inputs[0]->getDimensionType() == Tensor::TENSORFLOW) {
138             auto openCLBackend = static_cast<OpenCLBackend *>(backend);
139             auto reduct = op->main_as_ReductionParam();
140             if (nullptr == reduct->dim()) {
141                 return NULL;
142             }
143             if(reduct->dim()->size() != 1) {
144                 return NULL;
145             }
146             switch (op->main_as_ReductionParam()->operation()) {
147                 case ReductionType_MEAN:
148                     break;
149                 case ReductionType_MAXIMUM:
150                     break;
151                 case ReductionType_MINIMUM:
152                     break;
153                 case ReductionType_PROD:
154                     break;
155                 case ReductionType_SUM:
156                     break;
157                 default:
158                     return NULL;
159                     break;
160             }
161             return new ReductionBufExecution(op, backend);
162         }
163         return NULL;
164     }
165 };
166 
167 OpenCLCreatorRegister<ReductionBufCreator> __reductionBuf_op(OpType_Reduction, BUFFER);
168 } // namespace OpenCL
169 } // namespace MNN
170 #endif /* MNN_OPENCL_BUFFER_CLOSED */
171