1 //
2 // NeuralNetWorkOp.cpp
3 // MNN
4 //
5 // Created by MNN on 2019/06/27.
6 // Copyright © 2018, Alibaba Group Holding Limited
7 //
8
9 #include <algorithm>
10 #include <map>
11 #include <numeric>
12 #include <cmath>
13 #include <MNN/expr/ExprCreator.hpp>
14 #include <MNN/MNNDefine.h>
15 #include "MNN_generated.h"
16 #include "Utils.hpp"
17 namespace MNN {
18 namespace Express {
_convertPadMode(PaddingMode mode)19 static PadMode _convertPadMode(PaddingMode mode) {
20 switch (mode) {
21 case CAFFE:
22 return PadMode_CAFFE;
23 case VALID:
24 return PadMode_VALID;
25 case SAME:
26 return PadMode_SAME;
27 default:
28 break;
29 }
30 return PadMode_CAFFE;
31 }
_convertPoollingPadMode(PaddingMode mode)32 static PoolPadType _convertPoollingPadMode(PaddingMode mode) {
33 switch (mode) {
34 case CAFFE:
35 return PoolPadType_CAFFE;
36 case VALID:
37 return PoolPadType_VALID;
38 case SAME:
39 return PoolPadType_SAME;
40 default:
41 break;
42 }
43 return PoolPadType_CAFFE;
44 }
45 /*create a input variable.
46 Args:
47 shape: A vector, the shape of the variable.
48 data_format: A enum, NCHW/NHWC/NC4HW4 is allowed.
49 dtype: The type of the elements of the resulting variable.
50 Returns:
51 output: A variable.
52 */
_Input(INTS shape,Dimensionformat data_format,halide_type_t dtype)53 VARP _Input(INTS shape, Dimensionformat data_format, halide_type_t dtype) {
54 Variable::Info info;
55 info.dim = std::move(shape);
56 info.order = data_format;
57 info.type = dtype;
58 return (Variable::create(Expr::create(std::move(info), nullptr, VARP::INPUT)));
59 }
_Scalar(const void * ptr,halide_type_t type)60 VARP _Scalar(const void* ptr, halide_type_t type) {
61 Variable::Info info;
62 info.dim = {};
63 info.order = NHWC;
64 info.type = type;
65 return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
66 }
67 /*create a constant variable.
68 Args:
69 ptr: A pointer. Indicates the values.
70 shape: A vector, the shape of the variable.
71 format: A enum, NCHW/NHWC/NC4HW4 is allowed.
72 type: The type of the elements of the resulting variable.
73 Returns:
74 output: A constant variable.
75 */
_Const(const void * ptr,INTS shape,Dimensionformat format,halide_type_t type)76 VARP _Const(const void* ptr, INTS shape, Dimensionformat format, halide_type_t type) {
77 Variable::Info info;
78 info.dim = std::move(shape);
79 info.order = format;
80 info.type = type;
81 return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
82 }
83
_Const(float value,INTS shape,Dimensionformat format)84 VARP _Const(float value, INTS shape, Dimensionformat format) {
85 Variable::Info info;
86 info.dim = std::move(shape);
87 info.order = format;
88 info.type = halide_type_of<float>();
89 info.syncSize();
90 std::vector<float> values(info.size);
91 for (int i = 0; i < info.size; ++i) {
92 values[i] = value;
93 }
94 auto ptr = (void*)values.data();
95 return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
96 }
97
_TrainableParam(const void * ptr,INTS dims,Dimensionformat format,halide_type_t type)98 VARP _TrainableParam(const void* ptr, INTS dims, Dimensionformat format, halide_type_t type) {
99 auto v = _Const(ptr, dims, format, type);
100 v.fix(VARP::TRAINABLE);
101 return v;
102 }
_TrainableParam(float value,INTS dims,Dimensionformat format)103 VARP _TrainableParam(float value, INTS dims, Dimensionformat format) {
104 auto v = _Const(value, dims, format);
105 v.fix(VARP::TRAINABLE);
106 return v;
107 }
_InnerProduct(std::vector<float> && weight,std::vector<float> && bias,VARP x,INTS outputShape)108 VARP _InnerProduct(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS outputShape) {
109 std::unique_ptr<OpT> ipOp(new OpT);
110 ipOp->type = OpType_InnerProduct;
111 ipOp->main.type = OpParameter_InnerProduct;
112 ipOp->main.value = new InnerProductT;
113 auto ipParam = ipOp->main.AsInnerProduct();
114
115 ipParam->outputCount = outputShape[1];
116 if(!bias.empty()) {
117 ipParam->biasTerm = 1;
118 }
119 ipParam->weightSize = (int)weight.size();
120
121 ipParam->weight = std::move(weight);
122 ipParam->bias = std::move(bias);
123 return (Variable::create(Expr::create(ipOp.get(), {x})));
124 }
125
_Conv(VARP weight,VARP bias,VARP x,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads)126 VARP _Conv(VARP weight, VARP bias, VARP x, PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads) {
127 std::unique_ptr<OpT> convOp(new OpT);
128 convOp->type = OpType_Convolution;
129 auto shape = weight->getInfo();
130 if (NHWC == shape->order) {
131 weight = _Transpose(weight, {0, 3, 1, 2});
132 shape = weight->getInfo();
133 }
134 auto channel = std::vector<int>{shape->dim[0], shape->dim[1]};
135 auto kernelSize = std::vector<int>{shape->dim[3], shape->dim[2]};
136 if (1 == channel[1] && channel[0] == group) {
137 convOp->type = OpType_ConvolutionDepthwise;
138 channel[1] = group;
139 }
140 convOp->main.type = OpParameter_Convolution2D;
141 convOp->main.value = new Convolution2DT;
142 auto conv2D = convOp->main.AsConvolution2D();
143 conv2D->common.reset(new Convolution2DCommonT);
144 if (pads.size() == 2) {
145 conv2D->common->padX = pads[0];
146 conv2D->common->padY = pads[1];
147 } else {
148 conv2D->common->pads = std::move(pads);
149 }
150 conv2D->common->padMode = _convertPadMode(pad);
151 conv2D->common->strideX = stride[0];
152 conv2D->common->strideY = stride[1];
153 conv2D->common->group = group;
154 conv2D->common->outputCount = channel[0];
155 conv2D->common->inputCount = channel[1];
156 conv2D->common->dilateX = dilate[0];
157 conv2D->common->dilateY = dilate[1];
158 conv2D->common->kernelX = kernelSize[0];
159 conv2D->common->kernelY = kernelSize[1];
160 if (nullptr == bias) {
161 return (Variable::create(Expr::create(convOp.get(), {x, weight})));
162 }
163 return (Variable::create(Expr::create(convOp.get(), {x, weight, bias})));
164 }
_Conv(std::vector<float> && weight,std::vector<float> && bias,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,bool relu6)165 VARP _Conv(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
166 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu, bool relu6) {
167 std::unique_ptr<OpT> convOp(new OpT);
168 convOp->type = OpType_Convolution;
169 if (channel[0] == channel[1] && channel[0] == group) {
170 convOp->type = OpType_ConvolutionDepthwise;
171 }
172 convOp->main.type = OpParameter_Convolution2D;
173 convOp->main.value = new Convolution2DT;
174 auto conv2D = convOp->main.AsConvolution2D();
175 conv2D->common.reset(new Convolution2DCommonT);
176 conv2D->common->padMode = _convertPadMode(pad);
177 if (pads.size() == 2) {
178 conv2D->common->padX = pads[0];
179 conv2D->common->padY = pads[1];
180 } else {
181 conv2D->common->pads = std::move(pads);
182 }
183 conv2D->common->strideX = stride[0];
184 conv2D->common->strideY = stride[1];
185 conv2D->common->group = group;
186 conv2D->common->outputCount = channel[1];
187 conv2D->common->inputCount = channel[0];
188 conv2D->common->dilateX = dilate[0];
189 conv2D->common->dilateY = dilate[1];
190 conv2D->common->kernelX = kernelSize[0];
191 conv2D->common->kernelY = kernelSize[1];
192 conv2D->common->relu6 = relu6;
193 conv2D->common->relu = relu;
194 MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
195 conv2D->weight = std::move(weight);
196 MNN_ASSERT(bias.size() == channel[1]);
197 conv2D->bias = std::move(bias);
198 return (Variable::create(Expr::create(convOp.get(), {x})));
199 }
_Conv(std::vector<int8_t> && weight,std::vector<float> && bias,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,bool relu6,int nbits)200 VARP _Conv(std::vector<int8_t>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
201 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu, bool relu6, int nbits) {
202 std::unique_ptr<OpT> convOp(new OpT);
203 convOp->type = OpType_Convolution;
204 if (channel[0] == channel[1] && channel[0] == group) {
205 convOp->type = OpType_ConvolutionDepthwise;
206 }
207 convOp->main.type = OpParameter_Convolution2D;
208 convOp->main.value = new Convolution2DT;
209 auto conv2D = convOp->main.AsConvolution2D();
210 conv2D->common.reset(new Convolution2DCommonT);
211 conv2D->common->padMode = _convertPadMode(pad);
212 if (pads.size() == 2) {
213 conv2D->common->padX = pads[0];
214 conv2D->common->padY = pads[1];
215 } else {
216 conv2D->common->pads = std::move(pads);
217 }
218 conv2D->common->strideX = stride[0];
219 conv2D->common->strideY = stride[1];
220 conv2D->common->group = group;
221 conv2D->common->outputCount = channel[1];
222 conv2D->common->inputCount = channel[0];
223 conv2D->common->dilateX = dilate[0];
224 conv2D->common->dilateY = dilate[1];
225 conv2D->common->kernelX = kernelSize[0];
226 conv2D->common->kernelY = kernelSize[1];
227 conv2D->common->relu6 = relu6;
228 conv2D->common->relu = relu;
229 MNN_ASSERT(weight.size() / 2 == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
230 conv2D->quanParameter.reset(new IDSTQuanT);
231 conv2D->quanParameter->type = 3;
232 conv2D->quanParameter->buffer = std::move(weight);
233 conv2D->weight.clear();
234 MNN_ASSERT(bias.size() == channel[1]);
235 conv2D->bias = std::move(bias);
236 return (Variable::create(Expr::create(convOp.get(), {x})));
237 }
_Conv(float weight,float bias,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group)238 VARP _Conv(float weight, float bias, VARP x, INTS channel, INTS kernelSize, PaddingMode pad, INTS stride, INTS dilate,
239 int group) {
240 std::unique_ptr<OpT> convOp(new OpT);
241 convOp->type = OpType_Convolution;
242 if (channel[0] == channel[1] && channel[0] == group) {
243 convOp->type = OpType_ConvolutionDepthwise;
244 }
245 convOp->main.type = OpParameter_Convolution2D;
246 convOp->main.value = new Convolution2DT;
247 auto conv2D = convOp->main.AsConvolution2D();
248 conv2D->common.reset(new Convolution2DCommonT);
249 conv2D->common->padMode = _convertPadMode(pad);
250 conv2D->common->strideX = stride[0];
251 conv2D->common->strideY = stride[1];
252 conv2D->common->group = group;
253 conv2D->common->outputCount = channel[1];
254 conv2D->common->inputCount = channel[0];
255 conv2D->common->dilateX = dilate[0];
256 conv2D->common->dilateY = dilate[1];
257 conv2D->common->kernelX = kernelSize[0];
258 conv2D->common->kernelY = kernelSize[1];
259 conv2D->weight.resize(channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
260 std::fill(conv2D->weight.begin(), conv2D->weight.end(), weight);
261 conv2D->bias.resize(channel[1]);
262 std::fill(conv2D->bias.begin(), conv2D->bias.end(), bias);
263 return (Variable::create(Expr::create(convOp.get(), {x})));
264 }
265
_Deconv(VARP weight,VARP bias,VARP x,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads)266 VARP _Deconv(VARP weight, VARP bias, VARP x, PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads) {
267 std::unique_ptr<OpT> convOp(new OpT);
268 convOp->type = OpType_Deconvolution;
269 auto shape = weight->getInfo();
270 auto channel = std::vector<int>{shape->dim[1], shape->dim[0]};
271 auto kernelSize = std::vector<int>{shape->dim[3], shape->dim[2]};
272 if (channel[1] * channel[0] == group) {
273 convOp->type = OpType_DeconvolutionDepthwise;
274 channel[1] = group;
275 channel[0] = group;
276 }
277 convOp->main.type = OpParameter_Convolution2D;
278 convOp->main.value = new Convolution2DT;
279 auto conv2D = convOp->main.AsConvolution2D();
280 conv2D->common.reset(new Convolution2DCommonT);
281 if (pads.size() == 2) {
282 conv2D->common->padX = pads[0];
283 conv2D->common->padY = pads[1];
284 } else {
285 conv2D->common->pads = std::move(pads);
286 }
287 conv2D->common->padMode = _convertPadMode(pad);
288 conv2D->common->strideX = stride[0];
289 conv2D->common->strideY = stride[1];
290 conv2D->common->group = group;
291 conv2D->common->outputCount = channel[0];
292 conv2D->common->inputCount = channel[1];
293 conv2D->common->dilateX = dilate[0];
294 conv2D->common->dilateY = dilate[1];
295 conv2D->common->kernelX = kernelSize[0];
296 conv2D->common->kernelY = kernelSize[1];
297 if (nullptr != bias) {
298 return (Variable::create(Expr::create(std::move(convOp), {x, weight, bias})));
299 }
300 return (Variable::create(Expr::create(std::move(convOp), {x, weight})));
301 }
302
_Deconv(std::vector<float> && weight,std::vector<float> && bias,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,bool relu6)303 VARP _Deconv(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS channel, INTS kernelSize,
304 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu, bool relu6) {
305 std::unique_ptr<OpT> convOp(new OpT);
306 convOp->type = OpType_Deconvolution;
307 if (channel[0] == channel[1] && channel[0] == group) {
308 convOp->type = OpType_DeconvolutionDepthwise;
309 }
310 convOp->main.type = OpParameter_Convolution2D;
311 convOp->main.value = new Convolution2DT;
312 auto conv2D = convOp->main.AsConvolution2D();
313 conv2D->common.reset(new Convolution2DCommonT);
314 conv2D->common->padMode = _convertPadMode(pad);
315 if (pads.size() == 2) {
316 conv2D->common->padX = pads[0];
317 conv2D->common->padY = pads[1];
318 } else {
319 conv2D->common->pads = std::move(pads);
320 }
321 conv2D->common->strideX = stride[0];
322 conv2D->common->strideY = stride[1];
323 conv2D->common->group = group;
324 conv2D->common->outputCount = channel[1];
325 conv2D->common->inputCount = channel[0];
326 conv2D->common->dilateX = dilate[0];
327 conv2D->common->dilateY = dilate[1];
328 conv2D->common->kernelX = kernelSize[0];
329 conv2D->common->kernelY = kernelSize[1];
330 conv2D->common->relu6 = relu6;
331 conv2D->common->relu = relu;
332 MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
333 conv2D->weight = std::move(weight);
334 MNN_ASSERT(bias.size() == channel[1]);
335 conv2D->bias = std::move(bias);
336 return (Variable::create(Expr::create(convOp.get(), {x})));
337 }
338
_Pool(VARP x,INTS kernel,INTS stride,PoolType type,PaddingMode pad,INTS pads)339 static VARP _Pool(VARP x, INTS kernel, INTS stride, PoolType type, PaddingMode pad, INTS pads) {
340 std::unique_ptr<OpT> pool(new OpT);
341 pool->type = OpType_Pooling;
342 pool->main.type = OpParameter_Pool;
343 pool->main.value = new PoolT;
344 if (kernel[0] == -1 && kernel[1] == -1) {
345 pool->main.AsPool()->isGlobal = true;
346 }
347 pool->main.AsPool()->padX = 0;
348 pool->main.AsPool()->padY = 0;
349 if (pads.size() >= 2) {
350 pool->main.AsPool()->padX = pads[0];
351 pool->main.AsPool()->padY = pads[1];
352 }
353 pool->main.AsPool()->padType = _convertPoollingPadMode(pad);
354 pool->main.AsPool()->kernelX = kernel[0];
355 pool->main.AsPool()->kernelY = kernel[1];
356 pool->main.AsPool()->strideX = stride[0];
357 pool->main.AsPool()->strideY = stride[1];
358 pool->main.AsPool()->type = type;
359 return (Variable::create(Expr::create(pool.get(), {x})));
360 }
361
_AvePool(VARP x,INTS kernel,INTS stride,PaddingMode pad,INTS pads)362 VARP _AvePool(VARP x, INTS kernel, INTS stride, PaddingMode pad, INTS pads) {
363 return _Pool(x, kernel, stride, PoolType_AVEPOOL, pad, pads);
364 }
365
_MaxPool(VARP x,INTS kernel,INTS stride,PaddingMode pad,INTS pads)366 VARP _MaxPool(VARP x, INTS kernel, INTS stride, PaddingMode pad, INTS pads) {
367 return _Pool(x, kernel, stride, PoolType_MAXPOOL, pad, pads);
368 }
369 /*Reshapes a variable.
370 Args:
371 x: A variable.
372 shape: A vector, the shape of the target variable.
373 original_format: A enum, only NCHW/NHWC is allowed, NC4HW4 is not allowed,
374 as it provides additional information(x comes from NCHW or NHWC) When x is NC4HW4.
375 Returns:
376 output: A variable with the same type as `x`.
377 */
_Reshape(VARP x,INTS shape,Dimensionformat original_format)378 VARP _Reshape(VARP x, INTS shape, Dimensionformat original_format) {
379 std::unique_ptr<OpT> reshape(new OpT);
380 reshape->type = OpType_Reshape;
381 reshape->main.type = OpParameter_Reshape;
382 reshape->main.value = new ReshapeT;
383 reshape->main.AsReshape()->dims = shape;
384 reshape->main.AsReshape()->dimType = (MNN_DATA_FORMAT)Utils::convertFormat(original_format);
385 return (Variable::create(Expr::create(reshape.get(), {x})));
386 }
387 /*Reshapes a variable.
388 Args:
389 x: A variable.
390 shape: A variable, the shape of the target variable.
391 Returns:
392 output: A variable with the same type as `x`.
393 */
_Reshape(VARP x,VARP shape)394 VARP _Reshape(VARP x, VARP shape) {
395 MNN_ASSERT(nullptr != x);
396 std::unique_ptr<OpT> reshape(new OpT);
397 reshape->type = OpType_Reshape;
398 reshape->main.type = OpParameter_Reshape;
399 reshape->main.value = new ReshapeT;
400 if (nullptr != x->getInfo()) {
401 reshape->main.AsReshape()->dimType = (MNN_DATA_FORMAT)Utils::convertFormat(x->getInfo()->order);
402 } else {
403 reshape->main.AsReshape()->dimType = MNN_DATA_FORMAT_NHWC;
404 }
405 return (Variable::create(Expr::create(reshape.get(), {x, shape})));
406 }
_Scale(VARP x,int channels,std::vector<float> && scales,std::vector<float> && bias)407 VARP _Scale(VARP x, int channels, std::vector<float>&& scales, std::vector<float>&& bias) {
408 std::unique_ptr<OpT> scale(new OpT);
409 scale->type = OpType_Scale;
410 scale->main.type = OpParameter_Scale;
411 scale->main.value = new ScaleT;
412 scale->main.AsScale()->channels = channels;
413 scale->main.AsScale()->scaleData = std::move(scales);
414 scale->main.AsScale()->biasData = std::move(bias);
415 return (Variable::create(Expr::create(std::move(scale), {x})));
416 }
417 /*Given an input value x, it computes the output as x if x > 0 and slope * x if x <= 0.
418 Args:
419 x: A variable.
420 slope: A float, a positive float value, it leakes the negative part by multiplying with `slope` rather than setting it to 0.0f.
421 Returns:
422 output: A variable with the same type as `x`.
423 */
_Relu(VARP x,float slope)424 VARP _Relu(VARP x, float slope) {
425 std::unique_ptr<OpT> relu(new OpT);
426 relu->type = OpType_ReLU;
427 relu->main.type = OpParameter_Relu;
428 relu->main.value = new ReluT;
429 relu->main.AsRelu()->slope = slope;
430 return (Variable::create(Expr::create(relu.get(), {x})));
431 }
432 /*Given an input value x, it computes Rectified Linear 6: min(max(x, 0), 6).
433 Args:
434 x: A variable.
435 Returns:
436 output: A variable with the same type as `x`.
437 */
_Relu6(VARP x,float minValue,float maxValue)438 VARP _Relu6(VARP x, float minValue, float maxValue) {
439 std::unique_ptr<OpT> relu(new OpT);
440 relu->type = OpType_ReLU6;
441 relu->main.value = new Relu6T;
442 relu->main.type = OpParameter_Relu6;
443 relu->main.AsRelu6()->maxValue = maxValue;
444 relu->main.AsRelu6()->minValue = minValue;
445 return (Variable::create(Expr::create(relu.get(), {x})));
446 }
447 /*Given an input value x, it computes the output as x if x > 0 and slopes * x if x <= 0.
448 Args:
449 x: A variable, must be 4-D with NC4HW4 format.
450 slopes: A vector, has save size as x.
451 Returns:
452 output: A variable with the same type as `x`.
453 */
_PRelu(VARP x,std::vector<float> && slopes)454 VARP _PRelu(VARP x, std::vector<float>&& slopes) {
455 std::unique_ptr<OpT> prelu(new OpT);
456 prelu->type = OpType_PReLU;
457 prelu->main.type = OpParameter_PRelu;
458 prelu->main.value = new PReluT;
459 prelu->main.AsPRelu()->slope = slopes;
460 prelu->main.AsPRelu()->slopeCount = (int)slopes.size();
461 return (Variable::create(Expr::create(prelu.get(), {x})));
462 }
463 /*Computes softmax activations.
464 Args:
465 logits: A non-empty variable. Must be Halide_Type_Float.
466 axis: The dimension softmax would be performed on. The default is -1 which indicates the last dimension.
467 Returns:
468 output: A variable with the same type as `logits`.
469 */
_Softmax(VARP logits,int axis)470 VARP _Softmax(VARP logits, int axis) {
471 std::unique_ptr<OpT> softmax(new OpT);
472 softmax->type = OpType_Softmax;
473 softmax->main.type = OpParameter_Axis;
474 softmax->main.value = new AxisT;
475 softmax->main.AsAxis()->axis = axis;
476 return (Variable::create(Expr::create(softmax.get(), {logits})));
477 }
478 /*Computes softplus: log(exp(features) + 1).
479 Args:
480 features: A variable. Must be Halide_Type_Float.
481 Returns:
482 A variable with the same type as `features`.
483 */
_Softplus(VARP features)484 VARP _Softplus(VARP features) {
485 return _Log(_Add(_Exp(features), _Const(1)));
486 }
487 /*Computes softsign: features / (abs(features) + 1).
488 Args:
489 features: A variable. Must be Halide_Type_Float.
490 Returns:
491 A variable with the same type as `features`.
492 */
_Softsign(VARP features)493 VARP _Softsign(VARP features) {
494 return _Divide(features, _Add(_Abs(features), _Const(1)));
495 }
496 /*Concatenates variables along one dimension.
497 Args:
498 values: A list of variables a single variable.
499 axis: A int. Dimension along which to concatenate.
500 Must be in the range [-rank(values), rank(values)).
501 As in Python, indexing for axis is 0-based.
502 Positive axis in the rage of [0, rank(values)) refers to axis-th dimension.
503 And negative axis refers to axis + rank(values)-th dimension.
504 Returns:
505 A variable resulting from concatenation of the input variables.
506 */
_Concat(VARPS values,int axis)507 VARP _Concat(VARPS values, int axis) {
508 std::unique_ptr<OpT> concat(new OpT);
509 concat->type = OpType_Concat;
510 concat->main.type = OpParameter_Axis;
511 concat->main.value = new AxisT;
512 concat->main.AsAxis()->axis = axis;
513 return (Variable::create(Expr::create(concat.get(), values)));
514 }
515 /*Convert a variable to another format(possibily added after `input`).
516 Args:
517 input: A variable.
518 format: The target format.
519 Returns:
520 A variable. If `input` is already `format`, then return `input` directly, otherwize add a variable after `input` with `format`.
521 */
_Convert(VARP input,Dimensionformat format)522 VARP _Convert(VARP input, Dimensionformat format) {
523 if (nullptr != input->getInfo()) {
524 auto source = input->getInfo()->order;
525 if (source == format) {
526 return input;
527 }
528 }
529 std::unique_ptr<OpT> convert(new OpT);
530 convert->type = OpType_ConvertTensor;
531 convert->main.type = OpParameter_TensorConvertInfo;
532 convert->main.value = new TensorConvertInfoT;
533 convert->main.AsTensorConvertInfo()->dest = (MNN_DATA_FORMAT)Utils::convertFormat(format);
534 return (Variable::create(Expr::create(convert.get(), {input})));
535 }
536 /*Splits a variable value into a list of sub variables.
537 Args:
538 value: The variable to split.
539 size_splits: A vector, a 1-D integer containing the sizes of each output variable along axis.
540 axis: A int, the dimension along which to split. Must be in the range [-rank(value), rank(value)). Defaults to 0
541 Returns:
542 A list of variables.
543 */
_Split(VARP value,INTS size_splits,int axis)544 std::vector<VARP> _Split(VARP value, INTS size_splits, int axis) {
545 MNN_ASSERT(size_splits.size() >= 1);
546 std::unique_ptr<OpT> op(new OpT);
547 op->type = OpType_Slice;
548 op->main.type = OpParameter_Slice;
549 op->main.value = new SliceT;
550 op->main.AsSlice()->axis = axis;
551 op->main.AsSlice()->sourceType = NetSource_TENSORFLOW;
552 op->main.AsSlice()->slicePoints = size_splits;
553
554 int slices = size_splits.size() == 1 ? size_splits[0] : (int)size_splits.size();
555 EXPRP expr = Expr::create(std::move(op), {value}, slices);
556 std::vector<VARP> res;
557 for (int i = 0; i < slices; ++i) {
558 res.emplace_back(Variable::create(expr, i));
559 }
560 return res;
561 }
562
_Slice(VARP x,VARP starts,VARP sizes)563 VARP _Slice(VARP x, VARP starts, VARP sizes) {
564 std::unique_ptr<OpT> slice(new OpT);
565 slice->type = OpType_SliceTf;
566 return (Variable::create(Expr::create(slice.get(), {x, starts, sizes})));
567 }
568
_StridedSlice(VARP input,VARP begin,VARP end,VARP strided,int32_t beginMask,int32_t endMask,int32_t ellipsisMask,int32_t newAxisMask,int32_t shrinkAxisMask)569 VARP _StridedSlice(VARP input, VARP begin, VARP end, VARP strided, int32_t beginMask,
570 int32_t endMask, int32_t ellipsisMask, int32_t newAxisMask, int32_t shrinkAxisMask) {
571 std::unique_ptr<OpT> op(new OpT);
572 op->type = OpType_StridedSlice;
573 op->main.type = OpParameter_StridedSliceParam;
574 op->main.value = new StridedSliceParamT;
575
576 op->main.AsStridedSliceParam()->T = DataType_DT_FLOAT;
577 op->main.AsStridedSliceParam()->beginMask = beginMask;
578 op->main.AsStridedSliceParam()->endMask = endMask;
579 op->main.AsStridedSliceParam()->ellipsisMask = ellipsisMask;
580 op->main.AsStridedSliceParam()->newAxisMask = newAxisMask;
581 op->main.AsStridedSliceParam()->shrinkAxisMask = shrinkAxisMask;
582 return (Variable::create(Expr::create(op.get(), {input, begin, end, strided})));
583 }
584 /*Transposes x.
585 Args:
586 x: A variable.
587 perm: A vector, indicating the permutation of the dimensions of x.
588 Returns:
589 A transposed variable.
590 */
_Transpose(VARP x,INTS perm)591 VARP _Transpose(VARP x, INTS perm) {
592 auto permVar = _Const((const void*)perm.data(), {static_cast<int>(perm.size())}, NHWC, halide_type_of<int>());
593 return _Transpose(x, permVar);
594 }
_Transpose(VARP x,VARP perm)595 VARP _Transpose(VARP x, VARP perm) {
596 std::unique_ptr<OpT> transpose(new OpT);
597 transpose->type = OpType_Transpose;
598 transpose->main.type = OpParameter_Transpose;
599 transpose->main.value = new TransposeT;
600 transpose->main.AsTranspose()->Tperm = DataType_DT_INT32;
601 return (Variable::create(Expr::create(std::move(transpose), {x, perm})));
602 }
603
_ChannelShuffle(VARP x,int group)604 VARP _ChannelShuffle(VARP x, int group) {
605 x = _Convert(x, NHWC);
606 x = _Reshape(x, {0, 0, 0, group, -1}, NHWC);
607 x = _Transpose(x, {0, 1, 2, 4, 3});
608 x = _Reshape(x, {0, 0, 0, -1}, NHWC);
609 x = _Convert(x, NC4HW4);
610 return x;
611 }
_ReverseSequence(VARP x,VARP y,int batchDim,int seqDim)612 VARP _ReverseSequence(VARP x, VARP y, int batchDim, int seqDim) {
613 std::unique_ptr<OpT> op(new OpT);
614 op->type = OpType_ReverseSequence;
615 op->main.type = OpParameter_ReverseSequenceParam;
616 op->main.value = new ReverseSequenceParamT;
617 op->main.AsReverseSequenceParam()->batchDim = batchDim;
618 op->main.AsReverseSequenceParam()->seqDim = seqDim;
619 return (Variable::create(Expr::create(op.get(), {x, y})));
620 }
621 /*Convert a variable to another format(possibily added before `input`).
622 Args:
623 input: A variable.
624 format: The target format.
625 Returns:
626 A variable. If `input` is already `format`, then return `input` directly, otherwize add a variable before `input` with `format`.
627 */
628
_ChangeInputFormat(VARP input,Dimensionformat format)629 VARP _ChangeInputFormat(VARP input, Dimensionformat format) {
630 if (nullptr == input || nullptr == input->getInfo()) {
631 return nullptr;
632 }
633 if (input->getInfo()->order == format) {
634 return input;
635 }
636 auto input_before = _Input(input->getInfo()->dim, format, input->getInfo()->type);
637 auto convert = _Convert(input_before, input->getInfo()->order);
638 Variable::replace(input, convert);
639 return input_before;
640 }
641
_Clone(VARP source,bool deepCopy)642 VARP _Clone(VARP source, bool deepCopy) {
643 if (nullptr == source || nullptr == source->expr().first) {
644 return nullptr;
645 }
646 if (!deepCopy) {
647 return Variable::create(source->expr().first, source->expr().second);
648 }
649 auto info = source->getInfo();
650 auto sourcePtr = source->readMap<void>();
651
652 if (nullptr == info) {
653 MNN_ERROR("Source buffer info is not available.\n");
654 return nullptr;
655 }
656 auto inputVar = _Input(info->dim, info->order, info->type);
657 auto destPtr = inputVar->writeMap<void>();
658 if (info->size && destPtr && sourcePtr) {
659 ::memcpy(destPtr, sourcePtr, info->size * info->type.bytes());
660 }
661 return inputVar;
662 }
_Conv2DBackPropFilter(VARP input,VARP inputGrad,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads)663 VARP _Conv2DBackPropFilter(VARP input, VARP inputGrad, INTS kernelSize, PaddingMode pad, INTS stride, INTS dilate,
664 int group, INTS pads) {
665 std::unique_ptr<OpT> convOp(new OpT);
666 convOp->type = OpType_Conv2DBackPropFilter;
667 auto srcShape = input->getInfo();
668 auto dstShape = inputGrad->getInfo();
669 auto channel = std::vector<int>{srcShape->dim[1], dstShape->dim[1]};
670 convOp->main.type = OpParameter_Convolution2D;
671 convOp->main.value = new Convolution2DT;
672 auto conv2D = convOp->main.AsConvolution2D();
673 conv2D->common.reset(new Convolution2DCommonT);
674 conv2D->common->padX = pads[0];
675 conv2D->common->padY = pads[1];
676 conv2D->common->padMode = _convertPadMode(pad);
677 conv2D->common->strideX = stride[0];
678 conv2D->common->strideY = stride[1];
679 conv2D->common->group = group;
680 conv2D->common->outputCount = channel[1];
681 conv2D->common->inputCount = channel[0];
682 conv2D->common->dilateX = dilate[0];
683 conv2D->common->dilateY = dilate[1];
684 conv2D->common->kernelX = kernelSize[0];
685 conv2D->common->kernelY = kernelSize[1];
686 INTS weightDims = {channel[1], channel[0] / group, kernelSize[1], kernelSize[0]};
687
688 return Variable::create(Expr::create(std::move(convOp), {input, inputGrad}));
689 }
690
_PoolGrad(VARP originInput,VARP originOutput,VARP inputGrad,INTS kernel,INTS stride,PoolingMode type,PaddingMode pad,INTS pads)691 VARP _PoolGrad(VARP originInput, VARP originOutput, VARP inputGrad, INTS kernel, INTS stride, PoolingMode type,
692 PaddingMode pad, INTS pads) {
693 std::unique_ptr<OpT> pool(new OpT);
694 pool->type = OpType_PoolGrad;
695 pool->main.type = OpParameter_Pool;
696 pool->main.value = new PoolT;
697 if (kernel[0] == -1 && kernel[1] == -1) {
698 pool->main.AsPool()->isGlobal = true;
699 }
700 pool->main.AsPool()->padX = 0;
701 pool->main.AsPool()->padY = 0;
702 if (pads.size() >= 2) {
703 pool->main.AsPool()->padX = pads[0];
704 pool->main.AsPool()->padY = pads[1];
705 }
706 pool->main.AsPool()->padType = _convertPoollingPadMode(pad);
707 pool->main.AsPool()->kernelX = kernel[0];
708 pool->main.AsPool()->kernelY = kernel[1];
709 pool->main.AsPool()->strideX = stride[0];
710 pool->main.AsPool()->strideY = stride[1];
711 pool->main.AsPool()->type = (PoolType)type;
712 return (Variable::create(Expr::create(std::move(pool), {originInput, originOutput, inputGrad})));
713 }
714 /*Crop images.
715 Args:
716 images: 4-D variable of NC4HW4 format.
717 size: A variable. It takes the shape of `size` as output cropped variable's shape while omits the values/format of `size`.
718 axis: A int indicating the dimention to crop. Must be >=2. All dimensions up to but excluding `axis` are preserved, while the dimensions including and trailing `axis` are cropped.
719 offset: A vector of int indicating the offsets. length(`offset`) must be >=1 and <=2. If length(`offset`) is 1, then all dimensions are offset by this amount.Otherwise, the number of offsets must equal the number of cropped axes in each dimension accordingly.
720 Returns:
721 The cropped 4-D variable of NC4HW4 format.
722 */
_Crop(VARP images,VARP size,int axis,INTS offset)723 VARP _Crop(VARP images, VARP size, int axis, INTS offset) {
724 std::unique_ptr<OpT> crop(new OpT);
725 crop->type = OpType_Crop;
726 crop->main.type = OpParameter_Crop;
727 crop->main.value = new CropT;
728 crop->main.AsCrop()->axis = axis;
729 crop->main.AsCrop()->offset = offset;
730 return (Variable::create(Expr::create(std::move(crop), {images, size})));
731 }
732 /*Resize images.
733 Args:
734 images: 4-D variable of NC4HW4 format.
735 xScale: A float.
736 yScale: A float.
737 Returns:
738 The resized 4-D variable of NC4HW4 format.
739 */
_Resize(VARP images,float xScale,float yScale)740 VARP _Resize(VARP images, float xScale, float yScale) {
741 std::unique_ptr<OpT> resize(new OpT);
742 resize->type = OpType_Resize;
743 resize->main.type = OpParameter_Resize;
744 resize->main.value = new ResizeT;
745 resize->main.AsResize()->xScale = xScale;
746 resize->main.AsResize()->yScale = yScale;
747 return (Variable::create(Expr::create(std::move(resize), {images})));
748 }
749 /*Pads a variable.
750 Args:
751 x: A variable.
752 paddings: A variable of type Halide_Type_Int. The shape is [n, 2] where n is the rank of variable.
753 mode: A enum, One of PadValueMode_CONSTANT, PadValueMode_SYMMETRIC, or PadValueMode_REFLECT.
754 Returns:
755 A variable. Has the same type as x.
756 */
_Pad(VARP x,VARP paddings,PadValueMode mode)757 VARP _Pad(VARP x, VARP paddings, PadValueMode mode) {
758 std::unique_ptr<OpT> pad(new OpT);
759 pad->type = OpType_Padding;
760 pad->main.type = OpParameter_PadParam;
761 pad->main.value = new PadParamT;
762 switch (mode) {
763 case CONSTANT:
764 pad->main.AsPadParam()->mode = MNN::PadValueMode_CONSTANT;
765 break;
766 case SYMMETRIC:
767 pad->main.AsPadParam()->mode = MNN::PadValueMode_SYMMETRIC;
768 break;
769 case REFLECT:
770 pad->main.AsPadParam()->mode = MNN::PadValueMode_REFLECT;
771 break;
772 default:
773 pad->main.AsPadParam()->mode = MNN::PadValueMode_CONSTANT;
774 break;
775 }
776 return (Variable::create(Expr::create(std::move(pad), {x, paddings})));
777 }
778 /*Returns a variable with an additional dimension inserted at index axis.
779 Args:
780 input: A variable.
781 axis: A int, specifying the dimension index at which to expand the shape of input.
782 Given an input of D dimensions, axis must be in range [-(D+1), D] (inclusive).
783 Returns:
784 A variable with the same data as input, with an additional dimension inserted at the index specified by axis.
785 */
_ExpandDims(VARP input,int axis)786 VARP _ExpandDims(VARP input, int axis) {
787 std::unique_ptr<OpT> expand(new OpT);
788 expand->type = OpType_ExpandDims;
789 expand->main.type = OpParameter_ExpandDims;
790 expand->main.value = new ExpandDimsT;
791 expand->main.AsExpandDims()->axis = axis;
792 return (Variable::create(Expr::create(std::move(expand), {input})));
793 }
_ExpandDims(VARP input,VARP axis)794 VARP _ExpandDims(VARP input, VARP axis) {
795 std::unique_ptr<OpT> expand(new OpT);
796 expand->type = OpType_ExpandDims;
797 expand->main.type = OpParameter_ExpandDims;
798 expand->main.value = new ExpandDimsT;
799 return (Variable::create(Expr::create(std::move(expand), {input, axis})));
800 }
801 /*Returns the shape of a variable.
802 Args:
803 input: A variable.
804 Returns:
805 A variable of Halide_Type_Int.
806 */
_Shape(VARP input,bool nchw)807 VARP _Shape(VARP input, bool nchw) {
808 std::unique_ptr<OpT> shape(new OpT);
809 shape->type = OpType_Shape;
810 if (nchw) {
811 shape->defaultDimentionFormat = MNN_DATA_FORMAT_NCHW;
812 }
813 return (Variable::create(Expr::create(std::move(shape), {input})));
814 }
815 /*Stacks a list of rank-R variables into one rank-(R+1) variable.
816 Packs the list of variables in `values` into a ariable with rank one higher than each variable in values,
817 by packing them along the axis dimension.
818 Given a list of length N of variables of shape (A, B, C);
819 if axis == 0 then the output variable will have the shape (N, A, B, C).
820 if axis == 1 then the output variable will have the shape (A, N, B, C). Etc.
821 Args:
822 values: A list of variable objects with the same shape and type.
823 axis: An int. The axis to stack along. Defaults to the first dimension. Negative values wrap around,
824 so the valid range is [-(R+1), R+1).
825 Returns:
826 output: A stacked variable with the same type as `values`.
827 */
_Stack(VARPS values,int axis)828 VARP _Stack(VARPS values, int axis) {
829 std::unique_ptr<OpT> pack(new OpT);
830 pack->type = OpType_Pack;
831 pack->main.type = OpParameter_PackParam;
832 pack->main.value = new PackParamT;
833 pack->main.AsPackParam()->axis = axis;
834 return (Variable::create(Expr::create(std::move(pack), values)));
835 }
836 /*Extracts crops from the input image variable and resizes them using bilinear sampling or nearest neighbor sampling (possibly with aspect ratio change)
837 to a common output size specified by crop_size.
838 Returns a variable with crops from the input image at positions defined at the bounding box locations in boxes.
839 The cropped boxes are all resized (with bilinear or nearest neighbor interpolation) to a fixed size = [crop_height, crop_width].
840 The result is a 4-D tensor [num_boxes, crop_height, crop_width, depth](supposing NHWC format).
841 Arguments:
842 image: A 4-D variable of shape [batch, image_height, image_width, depth](supposing NHWC format). Both image_height and image_width need to be positive.
843 boxes: A 2-D variable of shape [num_boxes, 4]. The i-th row of the variable specifies the coordinates of a box in the box_ind[i] image and is specified in normalized coordinates [y1, x1, y2, x2].
844 A normalized coordinate value of y is mapped to the image coordinate at y * (image_height - 1), so as the [0, 1] interval of normalized image height is mapped to [0, image_height - 1] in image height coordinates. We do allow y1 > y2, in which case the sampled crop is an up-down flipped version of the original image. The width dimension is treated similarly. Normalized coordinates outside the [0, 1] range are allowed, in which case we use extrapolation_value to extrapolate the input image values.
845 box_ind: A 1-D variable of shape [num_boxes] with int values in [0, batch). The value of box_ind[i] specifies the image that the i-th box refers to.
846 crop_size: A 1-D variable of 2 elements, size = [crop_height, crop_width]. All cropped image patches are resized to this size. The aspect ratio of the image content is not preserved. Both crop_height and crop_width need to be positive.
847 method: A enum, either CropAndResizeMethod_NEAREST, or CropAndResizeMethod_BILINEAR, default to CropAndResizeMethod_BILINEAR.
848 extrapolation_value: Value used for extrapolation, when applicable.
849 Returns:
850 Output: A 4-D variable of shape [num_boxes, crop_height, crop_width, depth](supposing NHWC format).
851 */
_CropAndResize(VARP image,VARP boxes,VARP box_ind,VARP crop_size,InterpolationMethod method,float extrapolation_value)852 VARP _CropAndResize(VARP image, VARP boxes, VARP box_ind, VARP crop_size, InterpolationMethod method, float extrapolation_value) {
853 std::unique_ptr<OpT> car(new OpT);
854 car->type = OpType_CropAndResize;
855 car->main.type = OpParameter_CropAndResize;
856 car->main.value = new CropAndResizeT;
857 car->main.AsCropAndResize()->extrapolationValue = extrapolation_value;
858 switch (method) {
859 case NEAREST:
860 car->main.AsCropAndResize()->method = CropAndResizeMethod_NEAREST;
861 break;
862 case BILINEAR:
863 default:
864 car->main.AsCropAndResize()->method = CropAndResizeMethod_BILINEAR;
865 break;
866 }
867 return (Variable::create(Expr::create(std::move(car), {image, boxes, box_ind, crop_size})));
868 }
869 /*Creates a variable filled with a scalar value.
870 Args:
871 dims: A variable. Must be 1-D Halide_Type_Int. Represents the shape of the output variable.
872 value: A variable. 0-D (scalar). Value to fill the returned variable.
873 Returns:
874 A variable. Has the same type as value.
875 */
_Fill(VARP dims,VARP value)876 VARP _Fill(VARP dims, VARP value) {
877 std::unique_ptr<OpT> fill(new OpT);
878 fill->type = OpType_Fill;
879 fill->main.type = OpParameter_Fill;
880 fill->main.value = new FillT;
881 return (Variable::create(Expr::create(std::move(fill), {dims, value})));
882 }
883 /*Constructs a variable by tiling a given variable.
884 Args:
885 input: A variable. 1-D or higher.
886 multiples: A variable. Must be 1-D Halide_Type_Int.Length must be the same as the number of dimensions in input.
887 Returns:
888 A variable. Has the same type as input.
889 */
_Tile(VARP input,VARP multiples)890 VARP _Tile(VARP input, VARP multiples) {
891 std::unique_ptr<OpT> tile(new OpT);
892 tile->type = OpType_Tile;
893 return (Variable::create(Expr::create(std::move(tile), {input, multiples})));
894 }
895 /*Gather slices from params according to indices.
896 Arguments:
897 params: The variable from which to gather values.
898 indices: Index variable. Must be Halide_Type_Int in range [0, ndims(params)-1].
899 Returns:
900 Output: Values from params gathered from indices given by indices.
901 */
_Gather(VARP params,VARP indices)902 VARP _Gather(VARP params, VARP indices) {
903 std::unique_ptr<OpT> gather(new OpT);
904 gather->type = OpType_Gather;
905 return (Variable::create(Expr::create(std::move(gather), {params, indices})));
906 }
907 /*Gather slices from params axis according to indices.
908 Arguments:
909 params: The variable from which to gather values.
910 indices: Index variable. Must be Halide_Type_Int in range [0, ndims(params)-1].
911 axis: A int, the axis in params to gather indices from. Supports negative indexes.
912 If set to 0, it's same as _Gather. Currently only 0 is supported.
913 Returns:
914 Output: Values from params gathered from indices given by indices.
915 */
_GatherV2(VARP params,VARP indices,VARP axis)916 VARP _GatherV2(VARP params, VARP indices, VARP axis) {
917 std::unique_ptr<OpT> gather(new OpT);
918 gather->type = OpType_GatherV2;
919 gather->main.type = OpParameter_GatherV2;
920 gather->main.value = new GatherV2T;
921 if (axis.get()) {
922 return (Variable::create(Expr::create(std::move(gather), {params, indices, axis})));
923 } else {
924 return (Variable::create(Expr::create(std::move(gather), {params, indices})));
925 }
926 }
927 /*Removes dimensions of size 1 from the shape of a variable.
928 Args:
929 input: A variable. The input to squeeze.
930 axis: A vector, Defaults to {}. If specified, only squeezes the dimensions listed. The dimension index starts at 0.
931 Must be in the range [-rank(input), rank(input)).
932 Returns:
933 A variable. Has the same type as input. Contains the same data as input, but has one or more dimensions of size 1 removed.
934 */
_Squeeze(VARP input,INTS axis)935 VARP _Squeeze(VARP input, INTS axis) {
936 std::unique_ptr<OpT> squeeze(new OpT);
937 squeeze->type = OpType_Squeeze;
938 auto squeezeParam = new SqueezeParamT;
939 squeezeParam->squeezeDims = axis;
940 squeeze->main.type = OpParameter_SqueezeParam;
941 squeeze->main.value = squeezeParam;
942 return Variable::create(Expr::create(std::move(squeeze), {input}));
943 }
944
_Unsqueeze(VARP input,INTS axis)945 VARP _Unsqueeze(VARP input, INTS axis) {
946 std::unique_ptr<OpT> unsqueeze(new OpT);
947 unsqueeze->type = OpType_Unsqueeze;
948 auto squeezeParam = new SqueezeParamT;
949 squeezeParam->squeezeDims = axis;
950 unsqueeze->main.type = OpParameter_SqueezeParam;
951 unsqueeze->main.value = squeezeParam;
952 return Variable::create(Expr::create(std::move(unsqueeze), {input}));
953 }
954 /*Computes exponential linear: alpha * (exp(features) - 1) if < 0, features otherwise.
955 features: A variable of type Halide_Type_Float
956 alpha: Alpha factor (positive float)
957 Returns:
958 A variable. Has the same type as features.
959 */
_Elu(VARP features,float alpha)960 VARP _Elu(VARP features, float alpha) {
961 std::unique_ptr<OpT> op(new OpT);
962 op->type = OpType_ELU;
963 auto eluParam = new ELUT;
964 op->main.type = OpParameter_ELU;
965 eluParam->alpha = alpha;
966 op->main.value = eluParam;
967 return (Variable::create(Expr::create(std::move(op), {features})));
968 }
969 /*Given an input value x, it computes the output as 1.0 if x > threshold and 0.0 if x <= threshold.
970 features: A variable of type Halide_Type_Float
971 threshold: threshold value
972 Returns:
973 A variable. Has the same type as features.
974 */
_Threshold(VARP features,float threshold)975 VARP _Threshold(VARP features, float threshold) {
976 std::unique_ptr<OpT> op(new OpT);
977 op->type = OpType_Threshold;
978 auto eluParam = new ELUT;
979 op->main.type = OpParameter_ELU;
980 eluParam->alpha = threshold;
981 op->main.value = eluParam;
982 return (Variable::create(Expr::create(std::move(op), {features})));
983 }
984 /*Computes the size of the variable
985 Args:
986 input: A variable of type Halide_Type_Float or Halide_Type_Int
987 Returns:
988 A variable. The shape is (), and type is Halide_Type_Int
989 */
_Size(VARP input)990 VARP _Size(VARP input) {
991 std::unique_ptr<OpT> op(new OpT);
992 op->type = OpType_Size;
993 return (Variable::create(Expr::create(std::move(op), {input})));
994 }
995
996 /*Computes scaled exponential linear: scale * alpha * (exp(features) - 1) if < 0, scale * features otherwise.
997 Args:
998 features: A variable of type Halide_Type_Float
999 scale: Scaling factor (positive float)
1000 alpha: Alpha factor (positive float)
1001 Returns:
1002 A variable. Has the same type as features.
1003 */
_Selu(VARP features,float scale,float alpha)1004 VARP _Selu(VARP features, float scale, float alpha) {
1005 std::unique_ptr<OpT> op(new OpT);
1006 op->type = OpType_Selu;
1007 auto seluParam = new SeluT;
1008 op->main.type = OpParameter_Selu;
1009 seluParam->scale = scale;
1010 seluParam->alpha = alpha;
1011 op->main.value = seluParam;
1012 return (Variable::create(Expr::create(std::move(op), {features})));
1013
1014 }
1015 /*Gather slices from params into a variable with shape specified by indices.
1016 Args:
1017 params: A variable. The variables from which to gather values.
1018 indices: A variable. Must be one of the following types: Halide_Type_Int.
1019 Returns:
1020 A variable. Has the same type as params.
1021 */
_GatherND(VARP params,VARP indices)1022 VARP _GatherND(VARP params, VARP indices) {
1023 std::unique_ptr<OpT> op(new OpT);
1024 op->type = OpType_GatherND;
1025 return (Variable::create(Expr::create(std::move(op), {params, indices})));
1026 }
1027
1028 /*BatchToSpace for N-D variables
1029 This operation reshapes the "batch" dimension 0 into M + 1 dimensions of shape block_shape + [batch],
1030 interleaves these blocks back into the grid defined by the spatial dimensions [1, ..., M],
1031 to obtain a result with the same rank as the input.
1032 The spatial dimensions of this intermediate result are then optionally cropped according to crops to
1033 produce the output. This is the reverse of SpaceToBatch. See below for a precise description.
1034 Arguments:
1035 input: must be 4-D with NC4HW4 format. N-D with shape input_shape = [batch] + spatial_shape + remaining_shape, where spatial_shape has M dimensions.
1036 block_shape: 1-D with shape [M], all values must be >= 1.
1037 crops: 2-D with shape [M, 2], all values must be >= 0. crops[i] = [crop_start, crop_end] specifies the amount to crop from input dimension i + 1,
1038 which corresponds to spatial dimension i. It is required that crop_start[i] + crop_end[i] <= block_shape[i] * input_shape[i + 1].
1039 This operation is equivalent to the following steps:
1040 Reshape input to reshaped of shape: [block_shape[0], ..., block_shape[M-1], batch / prod(block_shape),
1041 input_shape[1], ..., input_shape[N-1]]
1042 Permute dimensions of reshaped to produce permuted of shape
1043 [batch / prod(block_shape),input_shape[1], block_shape[0], ..., input_shape[M], block_shape[M-1],input_shape[M+1], ..., input_shape[N-1]]
1044 Reshape permuted to produce reshaped_permuted of shape
1045 [batch / prod(block_shape),input_shape[1] * block_shape[0], ..., input_shape[M] * block_shape[M-1],input_shape[M+1], ..., input_shape[N-1]]
1046 Crop the start and end of dimensions [1, ..., M] of reshaped_permuted according to crops to produce the output of shape:
1047 [batch / prod(block_shape),input_shape[1] * block_shape[0] - crops[0,0] - crops[0,1], ..., input_shape[M] * block_shape[M-1] - crops[M-1,0] - crops[M-1,1],input_shape[M+1], ..., input_shape[N-1]]
1048 Some examples:
1049 for the following input of shape [4, 1, 1, 3], block_shape = [2, 2], and crops = [[0, 0], [0, 0]]:
1050 [[[[1, 2, 3]]], [[[4, 5, 6]]], [[[7, 8, 9]]], [[[10, 11, 12]]]]
1051 The output variable has shape [1, 2, 2, 3] and value:
1052 x = [[[[1, 2, 3], [4, 5, 6]],
1053 [[7, 8, 9], [10, 11, 12]]]]
1054 Returns:
1055 Output: The output variable
1056 */
1057
_BatchToSpaceND(VARP input,VARP block_shape,VARP crops)1058 VARP _BatchToSpaceND(VARP input, VARP block_shape, VARP crops) {
1059 std::unique_ptr<OpT> op(new OpT);
1060 std::unique_ptr<BlobT> blob_blockShape(new BlobT);
1061 std::unique_ptr<BlobT> blob_paddings(new BlobT);
1062
1063 auto info_block_shape = block_shape->getInfo();
1064 auto info_crops = crops->getInfo();
1065 MNN_ASSERT(info_block_shape != nullptr);
1066 MNN_ASSERT(info_crops != nullptr);
1067 MNN_ASSERT(halide_type_int == info_block_shape->type.code);
1068 MNN_ASSERT(halide_type_int == info_crops->type.code);
1069
1070 blob_blockShape->dims = info_block_shape->dim;
1071 blob_blockShape->dataFormat = (MNN_DATA_FORMAT)Utils::convertFormat(info_block_shape->order);
1072 blob_blockShape->dataType = (MNN::DataType)Utils::convertDataType(info_block_shape->type);
1073 auto data_block_shape = block_shape->readMap<int>();
1074 for (int i=0; i<info_block_shape->size; i++)
1075 {
1076 blob_blockShape->int32s.emplace_back(data_block_shape[i]);
1077 }
1078 blob_paddings->dims = info_crops->dim;
1079 blob_paddings->dataFormat = (MNN_DATA_FORMAT)Utils::convertFormat(info_crops->order);
1080 blob_paddings->dataType = (MNN::DataType)Utils::convertDataType(info_crops->type);
1081 auto data_crop = crops->readMap<int>();
1082 for (int i=0; i<info_crops->size; i++)
1083 {
1084 blob_paddings->int32s.emplace_back(data_crop[i]);
1085 }
1086 op->main.type = OpParameter_SpaceBatch;
1087 op->type = OpType_BatchToSpaceND;
1088 op->main.value = new SpaceBatchT;
1089 op->main.AsSpaceBatch()->blockShape = std::move(blob_blockShape);
1090 op->main.AsSpaceBatch()->padding = std::move(blob_paddings);
1091 return Variable::create(Expr::create(std::move(op), {input}));
1092 }
1093 /*Copies a variable setting everything outside a central band in each innermost matrix.
1094 Arguments:
1095 input: Rank k variable.
1096 num_lower: Number of subdiagonals to keep. If negative, keep entire lower triangle.
1097 num_upper: Number of superdiagonals to keep. If negative, keep entire upper triangle.
1098 Returns:
1099 Output: Rank k variable of the same shape as input. The extracted banded tensor.
1100 */
_MatrixBandPart(VARP input,VARP num_lower,VARP num_upper)1101 VARP _MatrixBandPart(VARP input, VARP num_lower, VARP num_upper) {
1102 std::unique_ptr<OpT> op(new OpT);
1103 op->type = OpType_MatrixBandPart;
1104 op->main.type = OpParameter_NONE;
1105 return (Variable::create(Expr::create(std::move(op), {input, num_lower, num_upper})));
1106 }
1107 /*Calculates the mean and variance of x.
1108 Args:
1109 x: A variable. must be 4-D with NC4HW4 format.
1110 axes: Array of ints. Axes along which to compute mean and variance. Ignored for this implementation: must be {2, 3}
1111 shift: Not used in the current implementation.
1112 keepdims: produce moments with the same dimensionality as the input. Ignored for this implementation: must be true.
1113 Returns:
1114 Two variable objects: mean and variance.
1115 */
_Moments(VARP x,INTS axis,VARP shift,bool keepDims)1116 std::vector<VARP> _Moments(VARP x, INTS axis, VARP shift, bool keepDims) {
1117 std::unique_ptr<OpT> op(new OpT);
1118 axis = {2, 3};
1119 keepDims = true;
1120 // if axis != {2,3} or keepDims != true, print warning.
1121 // ignore shift.
1122 op->type = OpType_Moments;
1123 auto momentsParam = new MomentsParamT;
1124 op->main.type = OpParameter_MomentsParam;
1125 momentsParam->dim = axis;
1126 momentsParam->keepDims = keepDims;
1127 op->main.value = momentsParam;
1128 EXPRP expr = Expr::create(std::move(op), {x}, 2);
1129 std::vector<VARP> res;
1130 res.emplace_back(Variable::create(expr, 0));
1131 res.emplace_back(Variable::create(expr, 1));
1132 return res;
1133 }
1134 /*Computes the difference between two lists of numbers or strings.
1135 Given a list x and a list y, this operation returns a list out that represents all values that are in x but not in y.
1136 The returned list out is sorted in the same order that the numbers appear in x (duplicates are preserved).
1137 This operation also returns a list idx that represents the position of each out element in x.
1138 Arguments:
1139 x: 1-D variable of type Halide_Type_Int. Values to keep.
1140 y: 1-D variable of type Halide_Type_Int. Values to remove.
1141 Returns:
1142 Output out: 1-D variable of type Halide_Type_Int. Values present in x but not in y.
1143 */
_SetDiff1D(VARP x,VARP y)1144 VARP _SetDiff1D(VARP x, VARP y) {
1145 std::unique_ptr<OpT> op(new OpT);
1146 op->type = OpType_SetDiff1D;
1147 op->main.type = OpParameter_NONE;
1148 op->main.value = nullptr;
1149 return Variable::create(Expr::create(std::move(op), {x, y}));
1150 }
1151 /*Rearranges blocks of spatial data, into depth.
1152 More specifically, it outputs a copy of the input variable where values from the height and width dimensions are moved to the depth dimension.
1153 The block_size indicates the input block size.
1154 Non-overlapping blocks of size block_size x block_size are rearranged into depth at each location.
1155 The depth of the output variable is block_size * block_size * input_depth.
1156 The Y, X coordinates within each block of the input become the high order component of the output channel index.
1157 The input variable's height and width must be divisible by block_size
1158 Args:
1159 input: A variable.
1160 block_size: An int that is >= 2. The size of the spatial block.
1161 Returns:
1162 A variable. Has the same type as input.
1163 */
_SpaceToDepth(VARP input,int block_size)1164 VARP _SpaceToDepth(VARP input, int block_size) {
1165 std::unique_ptr<OpT> op(new OpT);
1166 op->type = OpType_SpaceToDepth;
1167 auto param = new DepthSpaceParamT;
1168 param->blockSize = block_size;
1169 op->main.type = OpParameter_DepthSpaceParam;
1170 op->main.value = param;
1171 return Variable::create(Expr::create(std::move(op), {input}));
1172 }
1173
1174 /*This operation divides "spatial" dimensions [1, ..., M] of the input into a grid of blocks of shape block_shape,
1175 and interleaves these blocks with the "batch" dimension
1176 such that in the output, the spatial dimensions [1, ..., M] correspond to the position within the grid,
1177 and the batch dimension combines both the position within a spatial block and the original batch position.
1178 Prior to division into blocks, the spatial dimensions of the input are optionally zero padded according to paddings.
1179 See below for a precise description.
1180 Args:
1181 input: A variable. must be 4-D with NC4HW4 format. N-D with shape input_shape = [batch] + spatial_shape + remaining_shape, where spatial_shape has M dimensions.
1182 block_shape: A variable. Must be one of the following types: int32, int64. 1-D with shape [M], all values must be >= 1.
1183 paddings: A variable. Must be one of the following types: int32, int64. 2-D with shape [M, 2], all values must be >= 0. paddings[i] = [pad_start, pad_end] specifies the padding for input dimension i + 1, which corresponds to spatial dimension i. It is required that block_shape[i] divides input_shape[i + 1] + pad_start + pad_end.
1184 Returns:
1185 A variable. Has the same type as input.
1186 */
_SpaceToBatchND(VARP input,VARP block_shape,VARP paddings)1187 VARP _SpaceToBatchND(VARP input, VARP block_shape, VARP paddings) {
1188 std::unique_ptr<OpT> op(new OpT);
1189 std::unique_ptr<BlobT> blob_blockShape(new BlobT);
1190 std::unique_ptr<BlobT> blob_paddings(new BlobT);
1191 op->type = OpType_SpaceToBatchND;
1192 auto param = new SpaceBatchT;
1193 auto info_block_shape = block_shape->getInfo();
1194 auto info_paddings = paddings->getInfo();
1195 MNN_ASSERT(info_block_shape != nullptr);
1196 MNN_ASSERT(info_paddings != nullptr);
1197 MNN_ASSERT(halide_type_int == info_block_shape->type.code);
1198 MNN_ASSERT(halide_type_int == info_paddings->type.code);
1199
1200 blob_blockShape->dims = info_block_shape->dim;
1201 blob_blockShape->dataFormat = (MNN::MNN_DATA_FORMAT)Utils::convertFormat(info_block_shape->order);
1202 blob_blockShape->dataType = (MNN::DataType)Utils::convertDataType(info_block_shape->type);
1203 auto data_block_shape = block_shape->readMap<int>();
1204 for (int i=0; i<info_block_shape->size; i++)
1205 {
1206 blob_blockShape->int32s.emplace_back(data_block_shape[i]);
1207 }
1208 blob_paddings->dims = info_paddings->dim;
1209 blob_paddings->dataFormat = (MNN::MNN_DATA_FORMAT)Utils::convertFormat(info_paddings->order);
1210 blob_paddings->dataType = (MNN::DataType)Utils::convertDataType(info_paddings->type);
1211 auto data_paddings = paddings->readMap<int>();
1212 for (int i=0; i<info_paddings->size; i++)
1213 {
1214 blob_paddings->int32s.emplace_back(data_paddings[i]);
1215 }
1216 param->blockShape = std::move(blob_blockShape);
1217 param->padding = std::move(blob_paddings);
1218 op->main.type = OpParameter_SpaceBatch;
1219 op->main.value = param;
1220 return Variable::create(Expr::create(std::move(op), {input}));
1221 }
1222 /*Creates a variable with all elements set to zero.
1223 Args:
1224 input: A variable.
1225 Returns:
1226 A variable with all elements set to zero.
1227 */
1228
_ZerosLike(VARP input)1229 VARP _ZerosLike(VARP input) {
1230 std::unique_ptr<OpT> op(new OpT);
1231 op->type = OpType_ZerosLike;
1232 op->main.type = OpParameter_NONE;
1233 op->main.value = nullptr;
1234 return Variable::create(Expr::create(std::move(op), {input}));
1235 }
1236 /*Unpacks the given dimension of a rank-R tensor into rank-(R-1) variable.
1237 For example, given a variable of shape (A, B, C, D);
1238 If axis == 0 then the i'th variable in output is the slice value[i, :, :, :] and each variable in output will have shape (B, C, D).
1239 (Note that the dimension unpacked along is gone, unlike split).
1240 If axis == 1 then the i'th variable in output is the slice value[:, i, :, :] and each variable in output will have shape (A, C, D).
1241 Args:
1242 value: A rank R > 0 variable to be unstacked.
1243 num: An int. The length of the dimension axis. Automatically inferred if None (the default).
1244 axis: An int. The axis to unstack along. Defaults to the first dimension. Negative values wrap around, so the valid range is [-R, R).
1245 Returns:
1246 The list of variable objects unstacked from value.
1247 */
_Unstack(VARP value,int axis)1248 std::vector <VARP> _Unstack(VARP value, int axis) {
1249 std::unique_ptr<OpT> op(new OpT);
1250 op->type = OpType_Unpack;
1251 auto info_value = value->getInfo();
1252 MNN_ASSERT(info_value != nullptr);
1253 auto dims = info_value->dim;
1254 auto dimsize = dims.size();
1255 MNN_ASSERT(dimsize >= 1);
1256 axis = axis % dimsize;
1257 if(axis < 0) {
1258 axis += dimsize;
1259 }
1260 auto size = dims[axis];
1261 MNN_ASSERT(size > 0);
1262 auto axisParam = new AxisT;
1263 axisParam->axis = axis;
1264 op->main.type = OpParameter_Axis;
1265 op->main.value = axisParam;
1266 EXPRP expr = Expr::create(std::move(op), {value}, size);
1267 std::vector<VARP> res;
1268 for (int i = 0; i < size; ++i) {
1269 res.emplace_back(Variable::create(expr, i));
1270 }
1271 return res;
1272 }
1273
1274 /*Returns the rank of a variable.
1275 Returns a 0-D int32 variable representing the rank of input.
1276 Note: The rank of a variable is not the same as the rank of a matrix.
1277 It's the number of indices required to uniquely select each element of the variable.
1278 It's also known as "order", "degree", or "ndims."
1279 Args:
1280 input: A variable.
1281 Returns:
1282 A 0-D variable of type Halide_Type_Int
1283 */
_Rank(VARP input)1284 VARP _Rank(VARP input) {
1285 std::unique_ptr<OpT> op(new OpT);
1286 op->type = OpType_Rank;
1287 op->main.type = OpParameter_NONE;
1288 op->main.value = nullptr;
1289 return Variable::create(Expr::create(std::move(op), {input}));
1290 }
1291 /*Creates a sequence of numbers.
1292 Args:
1293 start: A 0-D variable (scalar).
1294 limit: A 0-D variable (scalar).
1295 delta: A 0-D variable (scalar).
1296 */
_Range(VARP start,VARP limit,VARP delta)1297 VARP _Range(VARP start, VARP limit, VARP delta) {
1298 std::unique_ptr<OpT> op(new OpT);
1299 op->type = OpType_Range;
1300 auto rangeParam = new RangeT;
1301 rangeParam->Tidx = (MNN::DataType)Utils::convertDataType(start->getInfo()->type);
1302 op->main.type = OpParameter_Range;
1303 op->main.value = rangeParam;
1304 return Variable::create(Expr::create(std::move(op), {start, limit, delta}));
1305 }
1306 /*Rearranges data from depth into blocks of spatial data.
1307 It is the reverse transformation of SpaceToDepth. More specifically,
1308 it outputs a copy of the input variable where values from the depth dimension are moved in spatial blocks to the height and width dimensions.
1309 Args:
1310 input: A variable.
1311 block_size: An int that is >= 2. The size of the spatial block, same as in Space2Depth.
1312 Returns:
1313 A variable. Has the same type as input.
1314 */
_DepthToSpace(VARP input,int block_size)1315 VARP _DepthToSpace(VARP input, int block_size) {
1316 std::unique_ptr<OpT> op(new OpT);
1317 op->type = OpType_DepthToSpace;
1318 auto depthtospaceParam = new DepthSpaceParamT;
1319 depthtospaceParam->blockSize = block_size;
1320 op->main.type = OpParameter_DepthSpaceParam;
1321 op->main.value = depthtospaceParam;
1322 return Variable::create(Expr::create(std::move(op), {input}));
1323 }
1324 /*SSD network's priorbox layer.
1325 Args:
1326 feature: A variable. Contains the feature map. Namely bottom[0] in caffe.
1327 image: A variable. Contains the image. Namely bottom[1] in caffe.
1328 min_size: Minimum box size (in pixels).
1329 max_size: Maximum box size (in pixels).
1330 aspect_ratio: Various of aspect ratios. Duplicate ratios are ignored. If none is provided, use default 1.0.
1331 flip: If true, flips each aspect ratio. For example, if there is aspect ratio "r", generates aspect ratio "1.0/r" as well. Default true.
1332 clip: If true, clips the prior so that it is within [0, 1]. Default false.
1333 variance: Variance for adjusting the prior bboxes.
1334 img_h: image height. If 0, uses information in image.
1335 img_w: image width. If 0, uses information in image.
1336 step_h: step in height.
1337 step_w: step in width.
1338 offset: Offset to the top left corner of each cell.
1339 Returns:
1340 A variable.
1341 */
_PriorBox(VARP feature,VARP image,std::vector<float> min_size,std::vector<float> max_size,std::vector<float> aspect_ratio,bool flip,bool clip,std::vector<float> variance,unsigned int img_h,unsigned int img_w,float step_h,float step_w,float offset)1342 VARP _PriorBox(VARP feature, VARP image, std::vector<float> min_size, std::vector<float> max_size, std::vector<float>aspect_ratio,
1343 bool flip, bool clip, std::vector<float>variance,
1344 unsigned int img_h, unsigned int img_w, float step_h, float step_w, float offset) {
1345 std::unique_ptr<OpT> op(new OpT);
1346 op->type = OpType_PriorBox;
1347 auto param = new PriorBoxT;
1348 param->minSizes = min_size;
1349 param->maxSizes = max_size;
1350 param->aspectRatios = aspect_ratio;
1351 param->flip = flip;
1352 param->clip = clip;
1353 param->variances = variance;
1354 param->imageHeight = img_h;
1355 param->imageWidth = img_w;
1356 param->stepHeight = step_h;
1357 param->stepWidth = step_w;
1358 param->offset = offset;
1359 op->main.type = OpParameter_PriorBox;
1360 op->main.value = param;
1361 return Variable::create(Expr::create(std::move(op), {feature, image}));
1362 }
1363 /*SSD network's permute layer.
1364 Args:
1365 input: A variable. Contains the feature map. Namely bottom[0] in caffe.
1366 dims: A vector. Contains the order.
1367 Returns:
1368 A variable.
1369 */
_Permute(VARP input,INTS dims)1370 VARP _Permute(VARP input, INTS dims) {
1371 std::unique_ptr<OpT> op(new OpT);
1372 op->type = OpType_Permute;
1373 auto param = new PermuteT;
1374 param->dims = dims;
1375 op->main.type = OpParameter_Permute;
1376 op->main.value = param;
1377 return Variable::create(Expr::create(std::move(op), {input}));
1378 }
1379 /*SSD network's detectionoutput layer.
1380 Args:
1381 location: A variable.
1382 confidence: A variable.
1383 priorbox: A variable.
1384 num_classes: number of classes.
1385 share_location: indicates wheter share location between different classes, default true.
1386 background_label_id: default = 0.
1387 nms_threshhold: nonmaximumsupression threshhold.
1388 mns_topk: nonmaximumsupression topk.
1389 code_type: indicates the mode to encode bbox, default = CORNER.
1390 variance_encoded_in_target: indicates whether encode variance in target, default false.
1391 keep_top_k: indicates the number of boxes kept, default -1(all boxes are kept).
1392 confidence_threshold: the threshhold for confidence.
1393 visualize_threshold: The threshold used to visualize the detection results.
1394 Returns:
1395 A variable.
1396 */
_DetectionOutput(VARP location,VARP confidence,VARP priorbox,unsigned int num_classes,bool share_location,int background_label_id,float nms_threshhold,int nms_topk,int code_type,bool variance_encoded_in_target,int keep_top_k,float confidence_threshold,float visualize_threshold)1397 VARP _DetectionOutput(VARP location, VARP confidence, VARP priorbox,
1398 unsigned int num_classes, bool share_location, int background_label_id,
1399 float nms_threshhold, int nms_topk, int code_type,
1400 bool variance_encoded_in_target,
1401 int keep_top_k, float confidence_threshold, float visualize_threshold){
1402 std::unique_ptr<OpT> op(new OpT);
1403 op->type = OpType_DetectionOutput;
1404 auto param = new DetectionOutputT;
1405 param->classCount = num_classes;
1406 param->shareLocation = share_location;
1407 param->backgroundLable = background_label_id;
1408 param->nmsThresholdold = nms_threshhold;
1409 param->nmsTopK = nms_topk;
1410 param->codeType = code_type;
1411 param->varianceEncodedTarget = variance_encoded_in_target;
1412 param->keepTopK = keep_top_k;
1413 param->confidenceThreshold = confidence_threshold;
1414 param->objectnessScore = visualize_threshold;
1415 op->main.type = OpParameter_DetectionOutput;
1416 op->main.value = param;
1417 return Variable::create(Expr::create(std::move(op), {location, confidence, priorbox}));
1418 }
1419 /*SSD network's detectionpostprocess layer.
1420 Args:
1421 encode_boxes: A variable.
1422 class_predictions: A variable.
1423 anchors: A variable.
1424 num_classes: number of classes.
1425 max_detections: A int, indicates max detections.
1426 max_class_per_detection: A int, indicates max class per detection.
1427 detections_per_class: A int, indicates detections per class.
1428 nms_threshhold: A float, the threshold for nms.
1429 iou_threshold: A float, the threshold for iou.
1430 use_regular_nms: A bool, indicates whether use regular nms method, only false is implemented currently.
1431 centersize_encoding: A float vector, indicates the centersize encoding.
1432 Returns:
1433 4 variable, detection_boxes, detection_class, detection_scores, num_detections
1434 */
_DetectionPostProcess(VARP encode_boxes,VARP class_predictions,VARP anchors,int num_classes,int max_detections,int max_class_per_detection,int detections_per_class,float nms_threshold,float iou_threshold,bool use_regular_nms,std::vector<float> centersize_encoding)1435 std::vector<VARP> _DetectionPostProcess(VARP encode_boxes, VARP class_predictions, VARP anchors,
1436 int num_classes, int max_detections,
1437 int max_class_per_detection, int detections_per_class,
1438 float nms_threshold, float iou_threshold,
1439 bool use_regular_nms, std::vector<float> centersize_encoding){
1440 std::unique_ptr<OpT> op(new OpT);
1441 op->type = OpType_DetectionPostProcess;
1442 auto param = new DetectionPostProcessParamT;
1443 param->numClasses = num_classes;
1444 param->maxDetections = max_detections;
1445 param->maxClassesPerDetection = max_class_per_detection;
1446 param->detectionsPerClass = detections_per_class;
1447 param->nmsScoreThreshold = nms_threshold;
1448 param->iouThreshold = iou_threshold;
1449 param->useRegularNMS = use_regular_nms;
1450 param->centerSizeEncoding = centersize_encoding;
1451 op->main.type = OpParameter_DetectionPostProcessParam;
1452 op->main.value = param;
1453 EXPRP expr = Expr::create(std::move(op), {encode_boxes, class_predictions, anchors}, 4);
1454 std::vector<VARP> res;
1455 for (int i = 0; i < 4; ++i) {
1456 res.emplace_back(Variable::create(expr, i));
1457 }
1458 return res;
1459 }
1460
_Interp(VARPS xs,float widthScale,float heightScale,int outputWidth,int outputHeight,int resizeType,bool alignCorners)1461 VARP _Interp(VARPS xs, float widthScale, float heightScale, int outputWidth, int outputHeight, int resizeType, bool alignCorners) {
1462 std::unique_ptr<OpT> interp(new OpT);
1463 interp->type = OpType_Interp;
1464 auto param = new InterpT;
1465 param->widthScale = widthScale;
1466 param->heightScale = heightScale;
1467 param->outputWidth = outputWidth;
1468 param->outputHeight = outputHeight;
1469 param->resizeType = resizeType;
1470 param->alignCorners = alignCorners;
1471 interp->main.value = param;
1472 interp->main.type = OpParameter_Interp;
1473 return Variable::create(Expr::create(std::move(interp), xs));
1474 }
_ZeroGrad(VARP x)1475 VARP _ZeroGrad(VARP x) {
1476 std::unique_ptr<OpT> op(new OpT);
1477 op->type = OpType_ZeroGrad;
1478 return Variable::create(Expr::create(std::move(op), {x}));
1479 }
1480
_Conv(std::vector<int8_t> && weight,std::vector<int> && bias,std::vector<float> && scale,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,int nbits)1481 VARP _Conv(std::vector<int8_t>&& weight, std::vector<int>&& bias, std::vector<float>&& scale, VARP x, INTS channel, INTS kernelSize,
1482 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu, int nbits) {
1483 std::unique_ptr<OpT> convOp(new OpT);
1484 convOp->type = OpType_ConvInt8;
1485 if (channel[0] == channel[1] && channel[0] == group) {
1486 convOp->type = OpType_DepthwiseConvInt8;
1487 }
1488 convOp->main.type = OpParameter_Convolution2D;
1489 convOp->main.value = new Convolution2DT;
1490 auto conv2D = convOp->main.AsConvolution2D();
1491 conv2D->common.reset(new Convolution2DCommonT);
1492 conv2D->common->padMode = _convertPadMode(pad);
1493 if (pads.size() == 2) {
1494 conv2D->common->padX = pads[0];
1495 conv2D->common->padY = pads[1];
1496 } else {
1497 conv2D->common->pads = std::move(pads);
1498 }
1499 conv2D->common->strideX = stride[0];
1500 conv2D->common->strideY = stride[1];
1501 conv2D->common->group = group;
1502 conv2D->common->outputCount = channel[1];
1503 conv2D->common->inputCount = channel[0];
1504 conv2D->common->dilateX = dilate[0];
1505 conv2D->common->dilateY = dilate[1];
1506 conv2D->common->kernelX = kernelSize[0];
1507 conv2D->common->kernelY = kernelSize[1];
1508 conv2D->common->relu = relu;
1509 MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
1510 conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
1511 conv2D->symmetricQuan->bias = std::move(bias);
1512 conv2D->symmetricQuan->scale = std::move(scale);
1513 conv2D->symmetricQuan->weight = std::move(weight);
1514 conv2D->symmetricQuan->nbits = nbits;
1515 return (Variable::create(Expr::create(convOp.get(), {x})));
1516 }
1517
_Conv(std::vector<int8_t> && weight,std::vector<int> && bias,std::vector<float> && scale,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,int8_t inputZeroPoint,int8_t outputZeroPoint,int8_t minValue,int8_t maxValue,bool accumulateToInt16)1518 VARP _Conv(std::vector<int8_t>&& weight, std::vector<int>&& bias, std::vector<float>&& scale,
1519 VARP x, INTS channel, INTS kernelSize,
1520 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu,
1521 int8_t inputZeroPoint, int8_t outputZeroPoint,
1522 int8_t minValue, int8_t maxValue, bool accumulateToInt16) {
1523 std::unique_ptr<OpT> convOp(new OpT);
1524 convOp->type = OpType_ConvInt8;
1525 if (channel[0] == channel[1] && channel[0] == group) {
1526 convOp->type = OpType_DepthwiseConvInt8;
1527 }
1528 convOp->main.type = OpParameter_Convolution2D;
1529 convOp->main.value = new Convolution2DT;
1530 auto conv2D = convOp->main.AsConvolution2D();
1531 conv2D->common.reset(new Convolution2DCommonT);
1532 conv2D->common->padMode = _convertPadMode(pad);
1533 if (pads.size() == 2) {
1534 conv2D->common->padX = pads[0];
1535 conv2D->common->padY = pads[1];
1536 } else {
1537 conv2D->common->pads = std::move(pads);
1538 }
1539 conv2D->common->strideX = stride[0];
1540 conv2D->common->strideY = stride[1];
1541 conv2D->common->group = group;
1542 conv2D->common->outputCount = channel[1];
1543 conv2D->common->inputCount = channel[0];
1544 conv2D->common->dilateX = dilate[0];
1545 conv2D->common->dilateY = dilate[1];
1546 conv2D->common->kernelX = kernelSize[0];
1547 conv2D->common->kernelY = kernelSize[1];
1548 conv2D->common->relu = relu;
1549 MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
1550 conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
1551 if (bias.size() == 0) {
1552 bias.resize(channel[1]);
1553 std::fill(bias.begin(), bias.end(), 0);
1554 }
1555 conv2D->symmetricQuan->bias = std::move(bias);
1556 conv2D->symmetricQuan->scale = std::move(scale);
1557 conv2D->symmetricQuan->zeroPoint = std::move(inputZeroPoint);
1558 conv2D->symmetricQuan->outputZeroPoint = std::move(outputZeroPoint);
1559 MNN_ASSERT(maxValue > minValue);
1560 conv2D->symmetricQuan->clampMin = minValue;
1561 conv2D->symmetricQuan->clampMax = maxValue;
1562 conv2D->symmetricQuan->weight = std::move(weight);
1563
1564 if (accumulateToInt16) {
1565 conv2D->symmetricQuan->method = MNN::QuantizeAlgo::QuantizeAlgo_OVERFLOW_AWARE;
1566 }
1567
1568 return (Variable::create(Expr::create(convOp.get(), {x})));
1569 }
1570
_Conv(std::vector<int8_t> && weight,std::vector<float> && bias,std::vector<float> && weightScale,VARP x,INTS channel,INTS kernelSize,PaddingMode pad,INTS stride,INTS dilate,int group,INTS pads,bool relu,float scaleIn,float scaleOut,int8_t inputZeroPoint,int8_t outputZeroPoint,int8_t minValue,int8_t maxValue,float weightClampValue,bool accumulateToInt16)1571 VARP _Conv(std::vector<int8_t>&& weight, std::vector<float>&& bias, std::vector<float>&& weightScale,
1572 VARP x, INTS channel, INTS kernelSize,
1573 PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads, bool relu,
1574 float scaleIn, float scaleOut,
1575 int8_t inputZeroPoint, int8_t outputZeroPoint,
1576 int8_t minValue, int8_t maxValue, float weightClampValue, bool accumulateToInt16) {
1577 std::unique_ptr<OpT> convOp(new OpT);
1578 convOp->type = OpType_ConvInt8;
1579 if (channel[0] == channel[1] && channel[0] == group) {
1580 convOp->type = OpType_DepthwiseConvInt8;
1581 }
1582 convOp->main.type = OpParameter_Convolution2D;
1583 convOp->main.value = new Convolution2DT;
1584 auto conv2D = convOp->main.AsConvolution2D();
1585 conv2D->common.reset(new Convolution2DCommonT);
1586 conv2D->common->padMode = _convertPadMode(pad);
1587 if (pads.size() == 2) {
1588 conv2D->common->padX = pads[0];
1589 conv2D->common->padY = pads[1];
1590 } else {
1591 conv2D->common->pads = std::move(pads);
1592 }
1593 conv2D->common->strideX = stride[0];
1594 conv2D->common->strideY = stride[1];
1595 conv2D->common->group = group;
1596 conv2D->common->outputCount = channel[1];
1597 conv2D->common->inputCount = channel[0];
1598 conv2D->common->dilateX = dilate[0];
1599 conv2D->common->dilateY = dilate[1];
1600 conv2D->common->kernelX = kernelSize[0];
1601 conv2D->common->kernelY = kernelSize[1];
1602 conv2D->common->relu = relu;
1603 MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
1604 conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
1605 if (bias.size() == 0) {
1606 bias.resize(channel[1]);
1607 std::fill(bias.begin(), bias.end(), 0);
1608 }
1609
1610 conv2D->bias = bias;
1611
1612 conv2D->symmetricQuan->weight = std::move(weight);
1613 conv2D->symmetricQuan->zeroPoint = std::move(inputZeroPoint);
1614 conv2D->symmetricQuan->outputZeroPoint = std::move(outputZeroPoint);
1615 MNN_ASSERT(maxValue > minValue);
1616 conv2D->symmetricQuan->clampMin = minValue;
1617 conv2D->symmetricQuan->clampMax = maxValue;
1618 conv2D->symmetricQuan->nbits = int(std::log(weightClampValue * 2 + 2) / std::log(2.0f));
1619
1620 // const int kn = conv2D->common->outputCount;
1621 // const int ks = weight.size() / kn;
1622 // std::vector<float> scales(kn, 1.0f);
1623 // std::vector<float> weightFloat;
1624 // for (int i = 0; i < weight.size(); i++) {
1625 // weightFloat.emplace_back(weight[i] * weightScale[i / ks]);
1626 // }
1627 // conv2D->quanParameter = IDSTEncoder::encode(weightFloat, weightScale, ks, kn, false, weight.data(), -int(weightClampValue));
1628
1629 conv2D->quanParameter.reset(new IDSTQuanT);
1630 conv2D->quanParameter->alpha = std::move(weightScale);
1631 conv2D->quanParameter->scaleIn = scaleIn;
1632 conv2D->quanParameter->scaleOut = scaleOut;
1633 conv2D->quanParameter->aMin = -int(weightClampValue);
1634
1635 if (accumulateToInt16) {
1636 conv2D->symmetricQuan->method = MNN::QuantizeAlgo::QuantizeAlgo_OVERFLOW_AWARE;
1637 }
1638
1639 return (Variable::create(Expr::create(convOp.get(), {x})));
1640 }
1641
_CosineSimilarity(VARP input0,VARP input1,VARP inputDim)1642 VARP _CosineSimilarity(VARP input0, VARP input1, VARP inputDim) {
1643 std::unique_ptr<MNN::OpT> cosineSimilarityOp(new MNN::OpT);
1644 cosineSimilarityOp->type = MNN::OpType_CosineSimilarity;
1645 return (Variable::create(Expr::create(std::move(cosineSimilarityOp), {input0, input1, inputDim})));
1646 }
1647
_GridSample(VARP input,VARP grid,InterpolationMethod mode,GridSamplePaddingMode paddingMode,bool alignCorners)1648 VARP _GridSample(VARP input, VARP grid, InterpolationMethod mode, GridSamplePaddingMode paddingMode, bool alignCorners) {
1649 std::unique_ptr<OpT> op(new OpT);
1650 op->type = OpType_GridSample;
1651 op->main.type = OpParameter_GridSample;
1652 op->main.value = new GridSampleT;
1653 switch (mode) {
1654 case NEAREST:
1655 op->main.AsGridSample()->mode = SampleMode_NEAREST;
1656 break;
1657 case BILINEAR:
1658 default:
1659 op->main.AsGridSample()->mode = SampleMode_BILINEAR;
1660 break;
1661 }
1662 switch (paddingMode) {
1663 case GRID_SAMPLE_PADDING_BORDER:
1664 op->main.AsGridSample()->paddingMode = BorderMode_CLAMP;
1665 break;
1666 case GRID_SAMPLE_PADDING_REFLECTION:
1667 op->main.AsGridSample()->paddingMode = BorderMode_REFLECTION;
1668 break;
1669 case GRID_SAMPLE_PADDING_ZEROS:
1670 default:
1671 op->main.AsGridSample()->paddingMode = BorderMode_ZEROS;
1672 break;
1673 }
1674 op->main.AsGridSample()->alignCorners = alignCorners;
1675 return (Variable::create(Expr::create(std::move(op), {input, grid})));
1676 }
1677
_FloatToInt8(VARP x,VARP scale,char minValue,char maxValue)1678 VARP _FloatToInt8(VARP x, VARP scale, char minValue/*For future*/, char maxValue/*For future*/) {
1679 auto xInfo = x->getInfo();
1680 auto scaleInfo = scale->getInfo();
1681 auto scalePtr = scale->readMap<float>();
1682 if (nullptr == scalePtr || nullptr == xInfo || nullptr == scaleInfo) {
1683 MNN_ERROR("Error for FloatToInt8 because var not ready\n");
1684 return nullptr;
1685 }
1686 if (xInfo->order != NC4HW4 || xInfo->type.code != halide_type_float) {
1687 MNN_ERROR("Not Support Input for FloatToInt8 because var not NC4HW4 or not float\n");
1688 return nullptr;
1689 }
1690 if ((scaleInfo->size != xInfo->dim[1]) && (scaleInfo->size != 1)) {
1691 MNN_ERROR("Scale's size not match input's channel: %d - %d\n", scaleInfo->size, xInfo->dim[1]);
1692 return nullptr;
1693 }
1694 std::unique_ptr<OpT> op(new OpT);
1695 op->type = OpType_FloatToInt8;
1696 op->main.type = OpParameter_QuantizedFloatParam;
1697 op->main.value = new QuantizedFloatParamT;
1698 op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
1699 ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
1700 return Variable::create(Expr::create(op.get(), {x}));
1701 }
1702
_FloatToInt8(VARP x,VARP scale,int8_t minValue,int8_t maxValue,int8_t zeroPoint)1703 VARP _FloatToInt8(VARP x, VARP scale, int8_t minValue, int8_t maxValue, int8_t zeroPoint) {
1704 auto xInfo = x->getInfo();
1705 auto scaleInfo = scale->getInfo();
1706 auto scalePtr = scale->readMap<float>();
1707 if (nullptr == scalePtr || nullptr == xInfo || nullptr == scaleInfo) {
1708 MNN_ERROR("Error for FloatToInt8 because var not ready\n");
1709 return nullptr;
1710 }
1711 if (xInfo->order != NC4HW4 || xInfo->type.code != halide_type_float) {
1712 MNN_ERROR("Not Support Input for FloatToInt8 because var not NC4HW4 or not float\n");
1713 return nullptr;
1714 }
1715 if ((scaleInfo->size != xInfo->dim[1]) && (scaleInfo->size != 1)) {
1716 MNN_ERROR("Scale's size not match input's channel: %d - %d\n", scaleInfo->size, xInfo->dim[1]);
1717 return nullptr;
1718 }
1719 std::unique_ptr<OpT> op(new OpT);
1720 op->type = OpType_FloatToInt8;
1721 op->main.type = OpParameter_QuantizedFloatParam;
1722 op->main.value = new QuantizedFloatParamT;
1723 op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
1724 ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
1725 op->main.AsQuantizedFloatParam()->zeroPoint = zeroPoint;
1726 MNN_ASSERT(maxValue > minValue);
1727 op->main.AsQuantizedFloatParam()->clampMin = int8_t(minValue);
1728 op->main.AsQuantizedFloatParam()->clampMax = int8_t(maxValue);
1729 return Variable::create(Expr::create(op.get(), {x}));
1730 }
1731
_Int8ToFloat(VARP x,VARP scale)1732 VARP _Int8ToFloat(VARP x, VARP scale) {
1733 auto xInfo = x->getInfo();
1734 auto scaleInfo = scale->getInfo();
1735 auto scalePtr = scale->readMap<float>();
1736 if (nullptr == scalePtr || nullptr == xInfo || nullptr == scaleInfo) {
1737 MNN_ERROR("Error for _Int8ToFloat because var not ready\n");
1738 return nullptr;
1739 }
1740 if (xInfo->order != NC4HW4 || xInfo->type.code != halide_type_int) {
1741 MNN_ERROR("Not Support Input for _Int8ToFloat because var not NC4HW4 or not int8\n");
1742 return nullptr;
1743 }
1744 if ((scaleInfo->size != xInfo->dim[1]) && (scaleInfo->size != 1)) {
1745 MNN_ERROR("_Int8ToFloat Scale's size not match input's channel\n");
1746 return nullptr;
1747 }
1748 std::unique_ptr<OpT> op(new OpT);
1749 op->type = OpType_Int8ToFloat;
1750 op->main.type = OpParameter_QuantizedFloatParam;
1751 op->main.value = new QuantizedFloatParamT;
1752 op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
1753 ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
1754 return Variable::create(Expr::create(op.get(), {x}));
1755 }
1756
_Int8ToFloat(VARP x,VARP scale,int8_t zeroPoint)1757 VARP _Int8ToFloat(VARP x, VARP scale, int8_t zeroPoint) {
1758 auto xInfo = x->getInfo();
1759 auto scaleInfo = scale->getInfo();
1760 auto scalePtr = scale->readMap<float>();
1761 if (nullptr == scalePtr || nullptr == xInfo || nullptr == scaleInfo) {
1762 MNN_ERROR("Error for _Int8ToFloat because var not ready\n");
1763 return nullptr;
1764 }
1765 if (xInfo->order != NC4HW4 || xInfo->type.code != halide_type_int) {
1766 MNN_ERROR("Not Support Input for _Int8ToFloat because var not NC4HW4 or not int8\n");
1767 return nullptr;
1768 }
1769 if ((scaleInfo->size != xInfo->dim[1]) && (scaleInfo->size != 1)) {
1770 MNN_ERROR("_Int8ToFloat Scale's size not match input's channel\n");
1771 return nullptr;
1772 }
1773 std::unique_ptr<OpT> op(new OpT);
1774 op->type = OpType_Int8ToFloat;
1775 op->main.type = OpParameter_QuantizedFloatParam;
1776 op->main.value = new QuantizedFloatParamT;
1777 op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
1778 ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
1779 op->main.AsQuantizedFloatParam()->zeroPoint = zeroPoint;
1780 return Variable::create(Expr::create(op.get(), {x}));
1781 }
1782
_Select(VARP select,VARP input0,VARP input1)1783 VARP _Select(VARP select, VARP input0, VARP input1) {
1784 std::unique_ptr<MNN::OpT> selectOp(new MNN::OpT);
1785 selectOp->type = MNN::OpType_Select;
1786 return (Variable::create(Expr::create(std::move(selectOp), {select, input0, input1})));
1787 }
1788
_TopKV2(VARP input0,VARP input1)1789 std::vector<VARP> _TopKV2(VARP input0, VARP input1) {
1790 std::unique_ptr<OpT> op(new OpT);
1791 op->type = OpType_TopKV2;
1792 auto expr = Expr::create(op.get(), {input0, input1}, 2);
1793 std::vector<VARP> res(2);
1794 res[0] = Variable::create(expr, 0);
1795 res[1] = Variable::create(expr, 1);
1796 return res;
1797 }
1798
1799
1800 } // namespace Express
1801 } // namespace MNN
1802