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