mirror of https://github.com/alibaba/MNN.git
				
				
				
			
		
			
				
	
	
		
			2039 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			2039 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			C++
		
	
	
	
//
 | 
						|
//  NeuralNetWorkOp.cpp
 | 
						|
//  MNN
 | 
						|
//
 | 
						|
//  Created by MNN on 2019/06/27.
 | 
						|
//  Copyright © 2018, Alibaba Group Holding Limited
 | 
						|
//
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
#include <map>
 | 
						|
#include <numeric>
 | 
						|
#include <cmath>
 | 
						|
#include <MNN/expr/ExprCreator.hpp>
 | 
						|
#include "MNN/expr/ExecutorScope.hpp"
 | 
						|
#include <MNN/MNNDefine.h>
 | 
						|
#include "MNN_generated.h"
 | 
						|
#include "Utils.hpp"
 | 
						|
namespace MNN {
 | 
						|
namespace Express {
 | 
						|
static PadMode _convertPadMode(PaddingMode mode) {
 | 
						|
    switch (mode) {
 | 
						|
        case CAFFE:
 | 
						|
            return PadMode_CAFFE;
 | 
						|
        case VALID:
 | 
						|
            return PadMode_VALID;
 | 
						|
        case SAME:
 | 
						|
            return PadMode_SAME;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return PadMode_CAFFE;
 | 
						|
}
 | 
						|
static PoolPadType _convertPoollingPadMode(PaddingMode mode) {
 | 
						|
    switch (mode) {
 | 
						|
        case CAFFE:
 | 
						|
            return PoolPadType_CAFFE;
 | 
						|
        case VALID:
 | 
						|
            return PoolPadType_VALID;
 | 
						|
        case SAME:
 | 
						|
            return PoolPadType_SAME;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return PoolPadType_CAFFE;
 | 
						|
}
 | 
						|
/*create a input variable.
 | 
						|
Args:
 | 
						|
shape: A vector, the shape of the variable.
 | 
						|
data_format: A enum, NCHW/NHWC/NC4HW4 is allowed.
 | 
						|
dtype: The type of the elements of the resulting variable.
 | 
						|
Returns:
 | 
						|
output: A variable.
 | 
						|
*/
 | 
						|
VARP _Input(INTS shape, Dimensionformat data_format, halide_type_t dtype) {
 | 
						|
    Variable::Info info;
 | 
						|
    info.dim = std::move(shape);
 | 
						|
    info.order = data_format;
 | 
						|
    info.type = dtype;
 | 
						|
    return (Variable::create(Expr::create(std::move(info), nullptr, VARP::INPUT)));
 | 
						|
}
 | 
						|
VARP _Scalar(const void* ptr, halide_type_t type) {
 | 
						|
    Variable::Info info;
 | 
						|
    info.dim = {};
 | 
						|
    info.order = NHWC;
 | 
						|
    info.type = type;
 | 
						|
    return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
 | 
						|
}
 | 
						|
/*create a constant variable.
 | 
						|
Args:
 | 
						|
ptr: A pointer. Indicates the values.
 | 
						|
shape: A vector, the shape of the variable.
 | 
						|
format: A enum, NCHW/NHWC/NC4HW4 is allowed.
 | 
						|
type: The type of the elements of the resulting variable. 
 | 
						|
Returns:
 | 
						|
output: A constant variable.
 | 
						|
*/
 | 
						|
VARP _Const(const void* ptr, INTS shape, Dimensionformat format, halide_type_t type) {
 | 
						|
    Variable::Info info;
 | 
						|
    info.dim = std::move(shape);
 | 
						|
    info.order = format;
 | 
						|
    info.type = type;
 | 
						|
    return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Const(float value, INTS shape, Dimensionformat format) {
 | 
						|
    Variable::Info info;
 | 
						|
    info.dim = std::move(shape);
 | 
						|
    info.order = format;
 | 
						|
    info.type = halide_type_of<float>();
 | 
						|
    info.syncSize();
 | 
						|
    std::vector<float> values(info.size);
 | 
						|
    for (int i = 0; i < info.size; ++i) {
 | 
						|
        values[i] = value;
 | 
						|
    }
 | 
						|
    auto ptr = (void*)values.data();
 | 
						|
    return (Variable::create(Expr::create(std::move(info), ptr, VARP::CONSTANT)));
 | 
						|
}
 | 
						|
 | 
						|
VARP _TrainableParam(const void* ptr, INTS dims, Dimensionformat format, halide_type_t type) {
 | 
						|
    auto v = _Const(ptr, dims, format, type);
 | 
						|
    v.fix(VARP::TRAINABLE);
 | 
						|
    return v;
 | 
						|
}
 | 
						|
VARP _TrainableParam(float value, INTS dims, Dimensionformat format) {
 | 
						|
    auto v = _Const(value, dims, format);
 | 
						|
    v.fix(VARP::TRAINABLE);
 | 
						|
    return v;
 | 
						|
}
 | 
						|
VARP _InnerProduct(std::vector<float>&& weight, std::vector<float>&& bias, VARP x, INTS outputShape) {
 | 
						|
    std::unique_ptr<OpT> ipOp(new OpT);
 | 
						|
    ipOp->type = OpType_InnerProduct;
 | 
						|
    ipOp->main.type  = OpParameter_InnerProduct;
 | 
						|
    ipOp->main.value = new InnerProductT;
 | 
						|
    auto ipParam        = ipOp->main.AsInnerProduct();
 | 
						|
 | 
						|
    ipParam->outputCount = outputShape[1];
 | 
						|
    if(!bias.empty()) {
 | 
						|
        ipParam->biasTerm = 1;
 | 
						|
    }
 | 
						|
    ipParam->weightSize = (int)weight.size();
 | 
						|
    
 | 
						|
    ipParam->weight = std::move(weight);
 | 
						|
    ipParam->bias = std::move(bias);
 | 
						|
    return (Variable::create(Expr::create(ipOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Conv(VARP weight, VARP bias, VARP x, PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_Convolution;
 | 
						|
    auto shape   = weight->getInfo();
 | 
						|
    if (NHWC == shape->order) {
 | 
						|
        weight = _Transpose(weight, {0, 3, 1, 2});
 | 
						|
        shape  = weight->getInfo();
 | 
						|
    }
 | 
						|
    auto channel    = std::vector<int>{shape->dim[0], shape->dim[1]};
 | 
						|
    auto kernelSize = std::vector<int>{shape->dim[3], shape->dim[2]};
 | 
						|
    if (1 == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_ConvolutionDepthwise;
 | 
						|
        channel[1] = group;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[0];
 | 
						|
    conv2D->common->inputCount  = channel[1];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    if (nullptr == bias) {
 | 
						|
        return (Variable::create(Expr::create(convOp.get(), {x, weight})));
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x, weight, bias})));
 | 
						|
}
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_Convolution;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_ConvolutionDepthwise;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu6 = relu6;
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->weight = std::move(weight);
 | 
						|
    MNN_ASSERT(bias.size() == channel[1]);
 | 
						|
    conv2D->bias = std::move(bias);
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_Convolution;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_ConvolutionDepthwise;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu6 = relu6;
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() / 2 == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->quanParameter.reset(new IDSTQuanT);
 | 
						|
    conv2D->quanParameter->type = 3;
 | 
						|
    conv2D->quanParameter->buffer = std::move(weight);
 | 
						|
    conv2D->weight.clear();
 | 
						|
    MNN_ASSERT(bias.size() == channel[1]);
 | 
						|
    conv2D->bias = std::move(bias);
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
VARP _Conv(float weight, float bias, VARP x, INTS channel, INTS kernelSize, PaddingMode pad, INTS stride, INTS dilate,
 | 
						|
           int group) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_Convolution;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_ConvolutionDepthwise;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->weight.resize(channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    std::fill(conv2D->weight.begin(), conv2D->weight.end(), weight);
 | 
						|
    conv2D->bias.resize(channel[1]);
 | 
						|
    std::fill(conv2D->bias.begin(), conv2D->bias.end(), bias);
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Deconv(VARP weight, VARP bias, VARP x, PaddingMode pad, INTS stride, INTS dilate, int group, INTS pads) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type    = OpType_Deconvolution;
 | 
						|
    auto shape      = weight->getInfo();
 | 
						|
    auto channel    = std::vector<int>{shape->dim[1], shape->dim[0]};
 | 
						|
    auto kernelSize = std::vector<int>{shape->dim[3], shape->dim[2]};
 | 
						|
    if (channel[1] * channel[0] == group) {
 | 
						|
        convOp->type = OpType_DeconvolutionDepthwise;
 | 
						|
        channel[1] = group;
 | 
						|
        channel[0] = group;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[0];
 | 
						|
    conv2D->common->inputCount  = channel[1];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    if (nullptr != bias) {
 | 
						|
        return (Variable::create(Expr::create(std::move(convOp), {x, weight, bias})));
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(convOp), {x, weight})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_Deconvolution;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_DeconvolutionDepthwise;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu6 = relu6;
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->weight = std::move(weight);
 | 
						|
    MNN_ASSERT(bias.size() == channel[1]);
 | 
						|
    conv2D->bias = std::move(bias);
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
static VARP _Pool(VARP x, INTS kernel, INTS stride, PoolType type, PaddingMode pad, INTS pads) {
 | 
						|
    std::unique_ptr<OpT> pool(new OpT);
 | 
						|
    pool->type       = OpType_Pooling;
 | 
						|
    pool->main.type  = OpParameter_Pool;
 | 
						|
    pool->main.value = new PoolT;
 | 
						|
    if (kernel[0] == -1 && kernel[1] == -1) {
 | 
						|
        pool->main.AsPool()->isGlobal = true;
 | 
						|
    }
 | 
						|
    pool->main.AsPool()->padX = 0;
 | 
						|
    pool->main.AsPool()->padY = 0;
 | 
						|
    if (pads.size() >= 2) {
 | 
						|
        pool->main.AsPool()->padX = pads[0];
 | 
						|
        pool->main.AsPool()->padY = pads[1];
 | 
						|
    }
 | 
						|
    pool->main.AsPool()->padType = _convertPoollingPadMode(pad);
 | 
						|
    pool->main.AsPool()->kernelX = kernel[0];
 | 
						|
    pool->main.AsPool()->kernelY = kernel[1];
 | 
						|
    pool->main.AsPool()->strideX = stride[0];
 | 
						|
    pool->main.AsPool()->strideY = stride[1];
 | 
						|
    pool->main.AsPool()->type    = type;
 | 
						|
    return (Variable::create(Expr::create(pool.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _AvePool(VARP x, INTS kernel, INTS stride, PaddingMode pad, INTS pads) {
 | 
						|
    return _Pool(x, kernel, stride, PoolType_AVEPOOL, pad, pads);
 | 
						|
}
 | 
						|
 | 
						|
VARP _MaxPool(VARP x, INTS kernel, INTS stride, PaddingMode pad, INTS pads) {
 | 
						|
    return _Pool(x, kernel, stride, PoolType_MAXPOOL, pad, pads);
 | 
						|
}
 | 
						|
/*Reshapes a variable.
 | 
						|
Args:
 | 
						|
x: A variable. 
 | 
						|
shape: A vector, the shape of the target variable.
 | 
						|
original_format: A enum, only NCHW/NHWC is allowed, NC4HW4 is not allowed, 
 | 
						|
as it provides additional information(x comes from NCHW or NHWC) When x is NC4HW4.
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `x`.
 | 
						|
*/
 | 
						|
VARP _Reshape(VARP x, INTS shape, Dimensionformat original_format) {
 | 
						|
    std::unique_ptr<OpT> reshape(new OpT);
 | 
						|
    reshape->type                      = OpType_Reshape;
 | 
						|
    reshape->main.type                 = OpParameter_Reshape;
 | 
						|
    reshape->main.value                = new ReshapeT;
 | 
						|
    reshape->main.AsReshape()->dims    = shape;
 | 
						|
    reshape->main.AsReshape()->dimType = (MNN_DATA_FORMAT)Utils::convertFormat(original_format);
 | 
						|
    return (Variable::create(Expr::create(reshape.get(), {x})));
 | 
						|
}
 | 
						|
/*Reshapes a variable.
 | 
						|
Args:
 | 
						|
x: A variable. 
 | 
						|
shape: A variable, the shape of the target variable.
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `x`.
 | 
						|
*/
 | 
						|
VARP _Reshape(VARP x, VARP shape) {
 | 
						|
    MNN_ASSERT(nullptr != x);
 | 
						|
    std::unique_ptr<OpT> reshape(new OpT);
 | 
						|
    reshape->type                      = OpType_Reshape;
 | 
						|
    reshape->main.type                 = OpParameter_Reshape;
 | 
						|
    reshape->main.value                = new ReshapeT;
 | 
						|
    if (nullptr != x->getInfo()) {
 | 
						|
        reshape->main.AsReshape()->dimType = (MNN_DATA_FORMAT)Utils::convertFormat(x->getInfo()->order);
 | 
						|
    } else {
 | 
						|
        reshape->main.AsReshape()->dimType = MNN_DATA_FORMAT_NHWC;
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(reshape.get(), {x, shape})));
 | 
						|
}
 | 
						|
VARP _Scale(VARP x, int channels, std::vector<float>&& scales, std::vector<float>&& bias) {
 | 
						|
    std::unique_ptr<OpT> scale(new OpT);
 | 
						|
    scale->type                      = OpType_Scale;
 | 
						|
    scale->main.type                 = OpParameter_Scale;
 | 
						|
    scale->main.value                = new ScaleT;
 | 
						|
    scale->main.AsScale()->channels  = channels;
 | 
						|
    scale->main.AsScale()->scaleData = std::move(scales);
 | 
						|
    scale->main.AsScale()->biasData  = std::move(bias);
 | 
						|
    return (Variable::create(Expr::create(std::move(scale), {x})));
 | 
						|
}
 | 
						|
/*Given an input value x, it computes the output as x if x > 0 and slope * x if x <= 0. 
 | 
						|
Args:
 | 
						|
x: A variable. 
 | 
						|
slope: A float, a positive float value, it leakes the negative part by multiplying with `slope` rather than setting it to 0.0f. 
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `x`.
 | 
						|
*/
 | 
						|
VARP _Relu(VARP x, float slope) {
 | 
						|
    std::unique_ptr<OpT> relu(new OpT);
 | 
						|
    relu->type                 = OpType_ReLU;
 | 
						|
    relu->main.type            = OpParameter_Relu;
 | 
						|
    relu->main.value           = new ReluT;
 | 
						|
    relu->main.AsRelu()->slope = slope;
 | 
						|
    return (Variable::create(Expr::create(relu.get(), {x})));
 | 
						|
}
 | 
						|
/*Given an input value x, it computes Rectified Linear 6: min(max(x, 0), 6).
 | 
						|
Args:
 | 
						|
x: A variable. 
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `x`.
 | 
						|
*/
 | 
						|
VARP _Relu6(VARP x, float minValue, float maxValue) {
 | 
						|
    std::unique_ptr<OpT> relu(new OpT);
 | 
						|
    relu->type = OpType_ReLU6;
 | 
						|
    relu->main.value = new Relu6T;
 | 
						|
    relu->main.type = OpParameter_Relu6;
 | 
						|
    relu->main.AsRelu6()->maxValue = maxValue;
 | 
						|
    relu->main.AsRelu6()->minValue = minValue;
 | 
						|
    return (Variable::create(Expr::create(relu.get(), {x})));
 | 
						|
}
 | 
						|
/*Given an input value x, it computes the output as x if x > 0 and slopes * x if x <= 0. 
 | 
						|
Args:
 | 
						|
x: A variable, must be 4-D with NC4HW4 format. 
 | 
						|
slopes: A vector, has save size as x.
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `x`.
 | 
						|
*/
 | 
						|
VARP _PRelu(VARP x, std::vector<float>&& slopes) {
 | 
						|
    std::unique_ptr<OpT> prelu(new OpT);
 | 
						|
    prelu->type                       = OpType_PReLU;
 | 
						|
    prelu->main.type                  = OpParameter_PRelu;
 | 
						|
    prelu->main.value                 = new PReluT;
 | 
						|
    prelu->main.AsPRelu()->slope      = slopes;
 | 
						|
    prelu->main.AsPRelu()->slopeCount = (int)slopes.size();
 | 
						|
    return (Variable::create(Expr::create(prelu.get(), {x})));
 | 
						|
}
 | 
						|
/*Computes softmax activations.
 | 
						|
Args:
 | 
						|
logits: A non-empty variable. Must be Halide_Type_Float.
 | 
						|
axis: The dimension softmax would be performed on. The default is -1 which indicates the last dimension.
 | 
						|
Returns:
 | 
						|
output: A variable with the same type as `logits`.
 | 
						|
*/
 | 
						|
VARP _Softmax(VARP logits, int axis) {
 | 
						|
    std::unique_ptr<OpT> softmax(new OpT);
 | 
						|
    softmax->type                = OpType_Softmax;
 | 
						|
    softmax->main.type           = OpParameter_Axis;
 | 
						|
    softmax->main.value          = new AxisT;
 | 
						|
    softmax->main.AsAxis()->axis = axis;
 | 
						|
    return (Variable::create(Expr::create(softmax.get(), {logits})));
 | 
						|
}
 | 
						|
/*Computes softplus: log(exp(features) + 1).
 | 
						|
Args:
 | 
						|
features: A variable. Must be Halide_Type_Float.
 | 
						|
Returns:
 | 
						|
A variable with the same type as `features`.
 | 
						|
*/
 | 
						|
VARP _Softplus(VARP features) {
 | 
						|
    return _Log(_Add(_Exp(features), _Const(1)));
 | 
						|
}
 | 
						|
/*Computes softsign: features / (abs(features) + 1).
 | 
						|
Args:
 | 
						|
features: A variable. Must be Halide_Type_Float.
 | 
						|
Returns:
 | 
						|
A variable with the same type as `features`.
 | 
						|
*/
 | 
						|
VARP _Softsign(VARP features) {
 | 
						|
    return _Divide(features, _Add(_Abs(features), _Const(1)));
 | 
						|
}
 | 
						|
/*Concatenates variables along one dimension.
 | 
						|
Args:
 | 
						|
values: A list of variables a single variable.
 | 
						|
axis: A int. Dimension along which to concatenate. 
 | 
						|
Must be in the range [-rank(values), rank(values)). 
 | 
						|
As in Python, indexing for axis is 0-based. 
 | 
						|
Positive axis in the rage of [0, rank(values)) refers to axis-th dimension. 
 | 
						|
And negative axis refers to axis + rank(values)-th dimension.
 | 
						|
Returns:
 | 
						|
A variable resulting from concatenation of the input variables.
 | 
						|
*/
 | 
						|
VARP _Concat(VARPS values, int axis) {
 | 
						|
    std::unique_ptr<OpT> concat(new OpT);
 | 
						|
    concat->type                = OpType_Concat;
 | 
						|
    concat->main.type           = OpParameter_Axis;
 | 
						|
    concat->main.value          = new AxisT;
 | 
						|
    concat->main.AsAxis()->axis = axis;
 | 
						|
    return (Variable::create(Expr::create(concat.get(), values)));
 | 
						|
}
 | 
						|
/*Convert a variable to another format(possibily added after `input`).
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
format: The target format. 
 | 
						|
Returns:
 | 
						|
A variable. If `input` is already `format`, then return `input` directly, otherwize add a variable after `input` with `format`.
 | 
						|
*/
 | 
						|
VARP _Convert(VARP input, Dimensionformat format) {
 | 
						|
    if (nullptr != input->getInfo()) {
 | 
						|
        auto source = input->getInfo()->order;
 | 
						|
        if (source == format) {
 | 
						|
            return input;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    std::unique_ptr<OpT> convert(new OpT);
 | 
						|
    convert->type                               = OpType_ConvertTensor;
 | 
						|
    convert->main.type                          = OpParameter_TensorConvertInfo;
 | 
						|
    convert->main.value                         = new TensorConvertInfoT;
 | 
						|
    convert->main.AsTensorConvertInfo()->dest   = (MNN_DATA_FORMAT)Utils::convertFormat(format);
 | 
						|
    return (Variable::create(Expr::create(convert.get(), {input})));
 | 
						|
}
 | 
						|
/*Splits a variable value into a list of sub variables.
 | 
						|
Args:
 | 
						|
value: The variable to split.
 | 
						|
size_splits: A vector, a 1-D integer containing the sizes of each output variable along axis. 
 | 
						|
axis: A int, the dimension along which to split. Must be in the range [-rank(value), rank(value)). Defaults to 0
 | 
						|
Returns:
 | 
						|
A list of variables.
 | 
						|
*/
 | 
						|
std::vector<VARP> _Split(VARP value, INTS size_splits, int axis) {
 | 
						|
    MNN_ASSERT(size_splits.size() >= 1);
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type                        = OpType_Slice;
 | 
						|
    op->main.type                   = OpParameter_Slice;
 | 
						|
    op->main.value                  = new SliceT;
 | 
						|
    op->main.AsSlice()->axis        = axis;
 | 
						|
    op->main.AsSlice()->sourceType  = NetSource_TENSORFLOW;
 | 
						|
    op->main.AsSlice()->slicePoints = size_splits;
 | 
						|
 | 
						|
    int slices = size_splits.size() == 1 ? size_splits[0] : (int)size_splits.size();
 | 
						|
    EXPRP expr = Expr::create(std::move(op), {value}, slices);
 | 
						|
    std::vector<VARP> res;
 | 
						|
    for (int i = 0; i < slices; ++i) {
 | 
						|
        res.emplace_back(Variable::create(expr, i));
 | 
						|
    }
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
VARP _Slice(VARP x, VARP starts, VARP sizes) {
 | 
						|
    std::unique_ptr<OpT> slice(new OpT);
 | 
						|
    slice->type = OpType_SliceTf;
 | 
						|
    return (Variable::create(Expr::create(slice.get(), {x, starts, sizes})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _StridedSlice(VARP input, VARP begin, VARP end, VARP strided, int32_t beginMask,
 | 
						|
                   int32_t endMask, int32_t ellipsisMask, int32_t newAxisMask, int32_t shrinkAxisMask) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type                        = OpType_StridedSlice;
 | 
						|
    op->main.type                   = OpParameter_StridedSliceParam;
 | 
						|
    op->main.value                  = new StridedSliceParamT;
 | 
						|
 | 
						|
    op->main.AsStridedSliceParam()->T = DataType_DT_FLOAT;
 | 
						|
    op->main.AsStridedSliceParam()->beginMask      = beginMask;
 | 
						|
    op->main.AsStridedSliceParam()->endMask        = endMask;
 | 
						|
    op->main.AsStridedSliceParam()->ellipsisMask   = ellipsisMask;
 | 
						|
    op->main.AsStridedSliceParam()->newAxisMask    = newAxisMask;
 | 
						|
    op->main.AsStridedSliceParam()->shrinkAxisMask = shrinkAxisMask;
 | 
						|
    return (Variable::create(Expr::create(op.get(), {input, begin, end, strided})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _StridedSliceWrite(VARP input, VARP begin, VARP end, VARP strided, VARP write, int32_t beginMask,
 | 
						|
                        int32_t endMask, int32_t ellipsisMask, int32_t newAxisMask, int32_t shrinkAxisMask) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type                        = OpType_StridedSlice;
 | 
						|
    op->main.type                   = OpParameter_StridedSliceParam;
 | 
						|
    op->main.value                  = new StridedSliceParamT;
 | 
						|
 | 
						|
    op->main.AsStridedSliceParam()->T = DataType_DT_FLOAT;
 | 
						|
    op->main.AsStridedSliceParam()->beginMask      = beginMask;
 | 
						|
    op->main.AsStridedSliceParam()->endMask        = endMask;
 | 
						|
    op->main.AsStridedSliceParam()->ellipsisMask   = ellipsisMask;
 | 
						|
    op->main.AsStridedSliceParam()->newAxisMask    = newAxisMask;
 | 
						|
    op->main.AsStridedSliceParam()->shrinkAxisMask = shrinkAxisMask;
 | 
						|
    return (Variable::create(Expr::create(op.get(), {input, begin, end, strided, write})));
 | 
						|
}
 | 
						|
/*Transposes x.
 | 
						|
Args:
 | 
						|
x: A variable.
 | 
						|
perm: A vector, indicating the permutation of the dimensions of x.
 | 
						|
Returns:
 | 
						|
A transposed variable.
 | 
						|
*/
 | 
						|
VARP _Transpose(VARP x, INTS perm) {
 | 
						|
    auto permVar = _Const((const void*)perm.data(), {static_cast<int>(perm.size())}, NHWC, halide_type_of<int>());
 | 
						|
    return _Transpose(x, permVar);
 | 
						|
}
 | 
						|
VARP _Transpose(VARP x, VARP perm) {
 | 
						|
    std::unique_ptr<OpT> transpose(new OpT);
 | 
						|
    transpose->type                      = OpType_Transpose;
 | 
						|
    transpose->main.type                 = OpParameter_Transpose;
 | 
						|
    transpose->main.value                = new TransposeT;
 | 
						|
    transpose->main.AsTranspose()->Tperm = DataType_DT_INT32;
 | 
						|
    return (Variable::create(Expr::create(std::move(transpose), {x, perm})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _ChannelShuffle(VARP x, int group) {
 | 
						|
    x = _Convert(x, NHWC);
 | 
						|
    x = _Reshape(x, {0, 0, 0, group, -1}, NHWC);
 | 
						|
    x = _Transpose(x, {0, 1, 2, 4, 3});
 | 
						|
    x = _Reshape(x, {0, 0, 0, -1}, NHWC);
 | 
						|
    x = _Convert(x, NC4HW4);
 | 
						|
    return x;
 | 
						|
}
 | 
						|
 | 
						|
VARP _Reverse(VARP x, VARP axis) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_Reverse;
 | 
						|
    return (Variable::create(Expr::create(op.get(), {x, axis})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _ReverseSequence(VARP x, VARP y, int batchDim, int seqDim) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type                                    = OpType_ReverseSequence;
 | 
						|
    op->main.type                               = OpParameter_ReverseSequenceParam;
 | 
						|
    op->main.value                              = new ReverseSequenceParamT;
 | 
						|
    op->main.AsReverseSequenceParam()->batchDim = batchDim;
 | 
						|
    op->main.AsReverseSequenceParam()->seqDim   = seqDim;
 | 
						|
    return (Variable::create(Expr::create(op.get(), {x, y})));
 | 
						|
}
 | 
						|
/*Convert a variable to another format(possibily added before `input`).
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
format: The target format. 
 | 
						|
Returns:
 | 
						|
A variable. If `input` is already `format`, then return `input` directly, otherwize add a variable before `input` with `format`.
 | 
						|
*/
 | 
						|
 | 
						|
VARP _ChangeInputFormat(VARP input, Dimensionformat format) {
 | 
						|
    if (nullptr == input || nullptr == input->getInfo()) {
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (input->getInfo()->order == format) {
 | 
						|
        return input;
 | 
						|
    }
 | 
						|
    auto input_before   = _Input(input->getInfo()->dim, format, input->getInfo()->type);
 | 
						|
    auto convert = _Convert(input_before, input->getInfo()->order);
 | 
						|
    Variable::replace(input, convert);
 | 
						|
    return input_before;
 | 
						|
}
 | 
						|
 | 
						|
VARP _Clone(VARP source, bool deepCopy) {
 | 
						|
    if (nullptr == source || nullptr == source->expr().first) {
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (!deepCopy) {
 | 
						|
        return Variable::create(source->expr().first, source->expr().second);
 | 
						|
    }
 | 
						|
    auto info      = source->getInfo();
 | 
						|
    auto sourcePtr = source->readMap<void>();
 | 
						|
 | 
						|
    if (nullptr == info) {
 | 
						|
        MNN_ERROR("Source buffer info is not available.\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    auto inputVar = _Input(info->dim, info->order, info->type);
 | 
						|
    auto destPtr  = inputVar->writeMap<void>();
 | 
						|
    if (info->size && destPtr && sourcePtr) {
 | 
						|
        ::memcpy(destPtr, sourcePtr, info->size * info->type.bytes());
 | 
						|
    }
 | 
						|
    return inputVar;
 | 
						|
}
 | 
						|
VARP _Conv2DBackPropFilter(VARP input, VARP inputGrad, INTS kernelSize, PaddingMode pad, INTS stride, INTS dilate,
 | 
						|
                           int group, INTS pads) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type       = OpType_Conv2DBackPropFilter;
 | 
						|
    auto srcShape = input->getInfo();
 | 
						|
    auto dstShape = inputGrad->getInfo();
 | 
						|
    auto channel       = std::vector<int>{srcShape->dim[1], dstShape->dim[1]};
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padX        = pads[0];
 | 
						|
    conv2D->common->padY        = pads[1];
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    INTS weightDims             = {channel[1], channel[0] / group, kernelSize[1], kernelSize[0]};
 | 
						|
 | 
						|
    return Variable::create(Expr::create(std::move(convOp), {input, inputGrad}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _PoolGrad(VARP originInput, VARP originOutput, VARP inputGrad, INTS kernel, INTS stride, PoolingMode type,
 | 
						|
               PaddingMode pad, INTS pads) {
 | 
						|
    std::unique_ptr<OpT> pool(new OpT);
 | 
						|
    pool->type       = OpType_PoolGrad;
 | 
						|
    pool->main.type  = OpParameter_Pool;
 | 
						|
    pool->main.value = new PoolT;
 | 
						|
    if (kernel[0] == -1 && kernel[1] == -1) {
 | 
						|
        pool->main.AsPool()->isGlobal = true;
 | 
						|
    }
 | 
						|
    pool->main.AsPool()->padX = 0;
 | 
						|
    pool->main.AsPool()->padY = 0;
 | 
						|
    if (pads.size() >= 2) {
 | 
						|
        pool->main.AsPool()->padX = pads[0];
 | 
						|
        pool->main.AsPool()->padY = pads[1];
 | 
						|
    }
 | 
						|
    pool->main.AsPool()->padType = _convertPoollingPadMode(pad);
 | 
						|
    pool->main.AsPool()->kernelX = kernel[0];
 | 
						|
    pool->main.AsPool()->kernelY = kernel[1];
 | 
						|
    pool->main.AsPool()->strideX = stride[0];
 | 
						|
    pool->main.AsPool()->strideY = stride[1];
 | 
						|
    pool->main.AsPool()->type    = (PoolType)type;
 | 
						|
    return (Variable::create(Expr::create(std::move(pool), {originInput, originOutput, inputGrad})));
 | 
						|
}
 | 
						|
/*Crop images. 
 | 
						|
Args:
 | 
						|
images: 4-D variable of NC4HW4 format.  
 | 
						|
size: A variable. It takes the shape of `size` as output cropped variable's shape  while omits the values/format of `size`.
 | 
						|
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.  
 | 
						|
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.
 | 
						|
Returns:
 | 
						|
The cropped 4-D variable of NC4HW4 format.
 | 
						|
*/  
 | 
						|
VARP _Crop(VARP images, VARP size, int axis, INTS offset) {
 | 
						|
    std::unique_ptr<OpT> crop(new OpT);
 | 
						|
    crop->type                  = OpType_Crop;
 | 
						|
    crop->main.type             = OpParameter_Crop;
 | 
						|
    crop->main.value            = new CropT;
 | 
						|
    crop->main.AsCrop()->axis   = axis;
 | 
						|
    crop->main.AsCrop()->offset = offset;
 | 
						|
    return (Variable::create(Expr::create(std::move(crop), {images, size})));
 | 
						|
}
 | 
						|
/*Resize images. 
 | 
						|
Args:
 | 
						|
images: 4-D variable of NC4HW4 format.  
 | 
						|
xScale: A float. 
 | 
						|
yScale: A float.
 | 
						|
Returns:
 | 
						|
The resized 4-D variable of NC4HW4 format.  
 | 
						|
*/
 | 
						|
VARP _Resize(VARP images, float xScale, float yScale) {
 | 
						|
    std::unique_ptr<OpT> resize(new OpT);
 | 
						|
    resize->type                    = OpType_Resize;
 | 
						|
    resize->main.type               = OpParameter_Resize;
 | 
						|
    resize->main.value              = new ResizeT;
 | 
						|
    resize->main.AsResize()->xScale = xScale;
 | 
						|
    resize->main.AsResize()->yScale = yScale;
 | 
						|
    return (Variable::create(Expr::create(std::move(resize), {images})));
 | 
						|
}
 | 
						|
/*Pads a variable.
 | 
						|
Args:
 | 
						|
x: A variable.
 | 
						|
paddings: A variable of type Halide_Type_Int. The shape is [n, 2] where  n is the rank of variable. 
 | 
						|
mode: A enum, One of PadValueMode_CONSTANT, PadValueMode_SYMMETRIC, or PadValueMode_REFLECT. 
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as x.
 | 
						|
*/
 | 
						|
VARP _Pad(VARP x, VARP paddings, PadValueMode mode) {
 | 
						|
    std::unique_ptr<OpT> pad(new OpT);
 | 
						|
    pad->type       = OpType_Padding;
 | 
						|
    pad->main.type  = OpParameter_PadParam;
 | 
						|
    pad->main.value = new PadParamT;
 | 
						|
    switch (mode) {
 | 
						|
        case CONSTANT:
 | 
						|
            pad->main.AsPadParam()->mode = MNN::PadValueMode_CONSTANT;
 | 
						|
            break;
 | 
						|
        case SYMMETRIC:
 | 
						|
            pad->main.AsPadParam()->mode = MNN::PadValueMode_SYMMETRIC;
 | 
						|
            break;
 | 
						|
        case REFLECT:
 | 
						|
            pad->main.AsPadParam()->mode = MNN::PadValueMode_REFLECT;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            pad->main.AsPadParam()->mode = MNN::PadValueMode_CONSTANT;
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(pad), {x, paddings})));
 | 
						|
}
 | 
						|
/*Returns a variable with an additional dimension inserted at index axis.
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
axis: A int, specifying the dimension index at which to expand the shape of input. 
 | 
						|
Given an input of D dimensions, axis must be in range [-(D+1), D] (inclusive).
 | 
						|
Returns:
 | 
						|
A variable with the same data as input, with an additional dimension inserted at the index specified by axis.
 | 
						|
*/
 | 
						|
VARP _ExpandDims(VARP input, int axis) {
 | 
						|
    std::unique_ptr<OpT> expand(new OpT);
 | 
						|
    expand->type                      = OpType_ExpandDims;
 | 
						|
    expand->main.type                 = OpParameter_ExpandDims;
 | 
						|
    expand->main.value                = new ExpandDimsT;
 | 
						|
    expand->main.AsExpandDims()->axis = axis;
 | 
						|
    return (Variable::create(Expr::create(std::move(expand), {input})));
 | 
						|
}
 | 
						|
VARP _ExpandDims(VARP input, VARP axis) {
 | 
						|
    std::unique_ptr<OpT> expand(new OpT);
 | 
						|
    expand->type       = OpType_ExpandDims;
 | 
						|
    expand->main.type  = OpParameter_ExpandDims;
 | 
						|
    expand->main.value = new ExpandDimsT;
 | 
						|
    return (Variable::create(Expr::create(std::move(expand), {input, axis})));
 | 
						|
}
 | 
						|
/*Returns the shape of a variable.
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
Returns:
 | 
						|
A variable of Halide_Type_Int.
 | 
						|
*/ 
 | 
						|
VARP _Shape(VARP input, bool nchw) {
 | 
						|
    std::unique_ptr<OpT> shape(new OpT);
 | 
						|
    shape->type = OpType_Shape;
 | 
						|
    if (nchw) {
 | 
						|
        shape->defaultDimentionFormat = MNN_DATA_FORMAT_NCHW;
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(shape), {input})));
 | 
						|
}
 | 
						|
/*Stacks a list of rank-R variables into one rank-(R+1) variable.
 | 
						|
Packs the list of variables in `values` into a ariable with rank one higher than each variable in values,
 | 
						|
by packing them along the axis dimension. 
 | 
						|
Given a list of length N of variables of shape (A, B, C);
 | 
						|
if axis == 0 then the output variable will have the shape (N, A, B, C). 
 | 
						|
if axis == 1 then the output variable will have the shape (A, N, B, C). Etc.
 | 
						|
Args:
 | 
						|
values: A list of variable objects with the same shape and type.
 | 
						|
axis: An int. The axis to stack along. Defaults to the first dimension. Negative values wrap around, 
 | 
						|
so the valid range is [-(R+1), R+1).
 | 
						|
Returns:
 | 
						|
output: A stacked variable with the same type as `values`.
 | 
						|
*/
 | 
						|
VARP _Stack(VARPS values, int axis) {
 | 
						|
    std::unique_ptr<OpT> pack(new OpT);
 | 
						|
    pack->type                         = OpType_Pack;
 | 
						|
    pack->main.type                    = OpParameter_PackParam;
 | 
						|
    pack->main.value                   = new PackParamT;
 | 
						|
    pack->main.AsPackParam()->axis     = axis;
 | 
						|
    return (Variable::create(Expr::create(std::move(pack), values)));
 | 
						|
}
 | 
						|
/*Extracts crops from the input image variable and resizes them using bilinear sampling or nearest neighbor sampling (possibly with aspect ratio change)
 | 
						|
to a common output size specified by crop_size. 
 | 
						|
Returns a variable with crops from the input image at positions defined at the bounding box locations in boxes. 
 | 
						|
The cropped boxes are all resized (with bilinear or nearest neighbor interpolation) to a fixed size = [crop_height, crop_width]. 
 | 
						|
The result is a 4-D tensor [num_boxes, crop_height, crop_width, depth](supposing NHWC format).
 | 
						|
Arguments:
 | 
						|
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.
 | 
						|
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]. 
 | 
						|
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.
 | 
						|
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.
 | 
						|
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.
 | 
						|
method: A enum, either CropAndResizeMethod_NEAREST, or CropAndResizeMethod_BILINEAR, default to CropAndResizeMethod_BILINEAR.
 | 
						|
extrapolation_value: Value used for extrapolation, when applicable.
 | 
						|
Returns:
 | 
						|
Output: A 4-D variable of shape [num_boxes, crop_height, crop_width, depth](supposing NHWC format).
 | 
						|
*/
 | 
						|
VARP _CropAndResize(VARP image, VARP boxes, VARP box_ind, VARP crop_size, InterpolationMethod method, float extrapolation_value) {
 | 
						|
    std::unique_ptr<OpT> car(new OpT);
 | 
						|
    car->type                                       = OpType_CropAndResize;
 | 
						|
    car->main.type                                  = OpParameter_CropAndResize;
 | 
						|
    car->main.value                                 = new CropAndResizeT;
 | 
						|
    car->main.AsCropAndResize()->extrapolationValue = extrapolation_value;
 | 
						|
    switch (method) {
 | 
						|
        case NEAREST:
 | 
						|
            car->main.AsCropAndResize()->method = CropAndResizeMethod_NEAREST;
 | 
						|
            break;
 | 
						|
        case BILINEAR:
 | 
						|
        default:
 | 
						|
            car->main.AsCropAndResize()->method = CropAndResizeMethod_BILINEAR;
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(car), {image, boxes, box_ind, crop_size})));
 | 
						|
}
 | 
						|
/*Creates a variable filled with a scalar value.
 | 
						|
Args:
 | 
						|
dims: A variable. Must be 1-D Halide_Type_Int. Represents the shape of the output variable.
 | 
						|
value: A variable. 0-D (scalar). Value to fill the returned variable. 
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as value.
 | 
						|
*/
 | 
						|
VARP _Fill(VARP dims, VARP value) {
 | 
						|
    std::unique_ptr<OpT> fill(new OpT);
 | 
						|
    fill->type       = OpType_Fill;
 | 
						|
    fill->main.type  = OpParameter_Fill;
 | 
						|
    fill->main.value = new FillT;
 | 
						|
    return (Variable::create(Expr::create(std::move(fill), {dims, value})));
 | 
						|
}
 | 
						|
/*Constructs a variable by tiling a given variable.
 | 
						|
Args:
 | 
						|
input: A variable. 1-D or higher.
 | 
						|
multiples: A variable. Must be 1-D Halide_Type_Int.Length must be the same as the number of dimensions in input.
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as input.
 | 
						|
*/
 | 
						|
VARP _Tile(VARP input, VARP multiples) {
 | 
						|
    std::unique_ptr<OpT> tile(new OpT);
 | 
						|
    tile->type = OpType_Tile;
 | 
						|
    return (Variable::create(Expr::create(std::move(tile), {input, multiples})));
 | 
						|
}
 | 
						|
/*Gather slices from params according to indices.
 | 
						|
Arguments:
 | 
						|
params: The variable from which to gather values. 
 | 
						|
indices: Index variable. Must be Halide_Type_Int in range [0, ndims(params)-1].
 | 
						|
Returns:
 | 
						|
Output: Values from params gathered from indices given by indices.
 | 
						|
*/
 | 
						|
VARP _Gather(VARP params, VARP indices) {
 | 
						|
    std::unique_ptr<OpT> gather(new OpT);
 | 
						|
    gather->type       = OpType_Gather;
 | 
						|
    return (Variable::create(Expr::create(std::move(gather), {params, indices})));
 | 
						|
}
 | 
						|
/*Gather slices from params axis according to indices.
 | 
						|
Arguments:
 | 
						|
params: The variable from which to gather values. 
 | 
						|
indices: Index variable. Must be Halide_Type_Int in range [0, ndims(params)-1].
 | 
						|
axis: A int, the axis in params to gather indices from. Supports negative indexes. 
 | 
						|
If set to 0, it's same as _Gather. Currently only 0 is supported. 
 | 
						|
Returns:
 | 
						|
Output: Values from params gathered from indices given by indices.
 | 
						|
*/
 | 
						|
VARP _GatherV2(VARP params, VARP indices, VARP axis) {
 | 
						|
    std::unique_ptr<OpT> gather(new OpT);
 | 
						|
    gather->type       = OpType_GatherV2;
 | 
						|
    gather->main.type  = OpParameter_GatherV2;
 | 
						|
    gather->main.value = new GatherV2T;
 | 
						|
    if (axis.get()) {
 | 
						|
        return (Variable::create(Expr::create(std::move(gather), {params, indices, axis})));
 | 
						|
    } else {
 | 
						|
        return (Variable::create(Expr::create(std::move(gather), {params, indices})));
 | 
						|
    }
 | 
						|
}
 | 
						|
/*Removes dimensions of size 1 from the shape of a variable.
 | 
						|
Args:
 | 
						|
input: A variable. The input to squeeze.
 | 
						|
axis: A vector, Defaults to {}. If specified, only squeezes the dimensions listed. The dimension index starts at 0. 
 | 
						|
Must be in the range [-rank(input), rank(input)). 
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as input. Contains the same data as input, but has one or more dimensions of size 1 removed.
 | 
						|
*/
 | 
						|
VARP _Squeeze(VARP input, INTS axis) {
 | 
						|
    std::unique_ptr<OpT> squeeze(new OpT);
 | 
						|
    squeeze->type             = OpType_Squeeze;
 | 
						|
    auto squeezeParam         = new SqueezeParamT;
 | 
						|
    squeezeParam->squeezeDims = axis;
 | 
						|
    squeeze->main.type        = OpParameter_SqueezeParam;
 | 
						|
    squeeze->main.value       = squeezeParam;
 | 
						|
    return Variable::create(Expr::create(std::move(squeeze), {input}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Unsqueeze(VARP input, INTS axis) {
 | 
						|
    std::unique_ptr<OpT> unsqueeze(new OpT);
 | 
						|
    unsqueeze->type             = OpType_Unsqueeze;
 | 
						|
    auto squeezeParam         = new SqueezeParamT;
 | 
						|
    squeezeParam->squeezeDims = axis;
 | 
						|
    unsqueeze->main.type        = OpParameter_SqueezeParam;
 | 
						|
    unsqueeze->main.value       = squeezeParam;
 | 
						|
    return Variable::create(Expr::create(std::move(unsqueeze), {input}));
 | 
						|
}
 | 
						|
/*Computes exponential linear: alpha * (exp(features) - 1) if < 0, features otherwise.
 | 
						|
features: A variable of type Halide_Type_Float
 | 
						|
alpha: Alpha factor (positive float)
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as features.
 | 
						|
*/
 | 
						|
VARP _Elu(VARP features, float alpha) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_ELU;
 | 
						|
    auto eluParam = new ELUT;
 | 
						|
    op->main.type = OpParameter_ELU;
 | 
						|
    eluParam->alpha = alpha;
 | 
						|
    op->main.value = eluParam;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {features})));
 | 
						|
}
 | 
						|
/*Given an input value x, it computes the output as 1.0 if x > threshold and 0.0 if x <= threshold.
 | 
						|
features: A variable of type Halide_Type_Float
 | 
						|
threshold: threshold value
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as features.
 | 
						|
*/
 | 
						|
VARP _Threshold(VARP features, float threshold) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_Threshold;
 | 
						|
    auto eluParam = new ELUT;
 | 
						|
    op->main.type = OpParameter_ELU;
 | 
						|
    eluParam->alpha = threshold;
 | 
						|
    op->main.value = eluParam;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {features})));
 | 
						|
}
 | 
						|
/*Computes the size of the variable
 | 
						|
Args:
 | 
						|
input: A variable of type Halide_Type_Float or Halide_Type_Int
 | 
						|
Returns:
 | 
						|
A variable. The shape is (), and type is Halide_Type_Int
 | 
						|
*/
 | 
						|
VARP _Size(VARP input) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Size;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {input})));
 | 
						|
}
 | 
						|
 | 
						|
/*Computes scaled exponential linear: scale * alpha * (exp(features) - 1) if < 0, scale * features otherwise.
 | 
						|
Args:
 | 
						|
features: A variable of type Halide_Type_Float
 | 
						|
scale: Scaling factor (positive float)
 | 
						|
alpha: Alpha factor (positive float)
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as features.
 | 
						|
*/
 | 
						|
VARP _Selu(VARP features, float scale, float alpha) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Selu;
 | 
						|
    auto seluParam = new SeluT;
 | 
						|
    op->main.type = OpParameter_Selu;
 | 
						|
    seluParam->scale = scale;
 | 
						|
    seluParam->alpha = alpha;
 | 
						|
    op->main.value = seluParam;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {features})));
 | 
						|
 | 
						|
}
 | 
						|
/*Gather slices from params into a variable with shape specified by indices.
 | 
						|
Args:
 | 
						|
params: A variable. The variables from which to gather values.
 | 
						|
indices: A variable. Must be one of the following types: Halide_Type_Int.
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as params.
 | 
						|
*/
 | 
						|
VARP _GatherND(VARP params, VARP indices) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_GatherND;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {params, indices})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _GatherElements(VARP params, VARP indices) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_GatherElements;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {params, indices})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _GatherElements(VARP params, VARP indices, VARP axis) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_GatherElements;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {params, indices, axis})));
 | 
						|
}
 | 
						|
 | 
						|
/*BatchToSpace for N-D variables
 | 
						|
This operation reshapes the "batch" dimension 0 into M + 1 dimensions of shape block_shape + [batch], 
 | 
						|
interleaves these blocks back into the grid defined by the spatial dimensions [1, ..., M], 
 | 
						|
to obtain a result with the same rank as the input. 
 | 
						|
The spatial dimensions of this intermediate result are then optionally cropped according to crops to 
 | 
						|
produce the output. This is the reverse of SpaceToBatch. See below for a precise description.
 | 
						|
Arguments:
 | 
						|
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.
 | 
						|
block_shape: 1-D with shape [M], all values must be >= 1.
 | 
						|
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, 
 | 
						|
which corresponds to spatial dimension i. It is required that crop_start[i] + crop_end[i] <= block_shape[i] * input_shape[i + 1].
 | 
						|
This operation is equivalent to the following steps:
 | 
						|
Reshape input to reshaped of shape: [block_shape[0], ..., block_shape[M-1], batch / prod(block_shape), 
 | 
						|
input_shape[1], ..., input_shape[N-1]]
 | 
						|
Permute dimensions of reshaped to produce permuted of shape 
 | 
						|
[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]]
 | 
						|
Reshape permuted to produce reshaped_permuted of shape 
 | 
						|
[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]]
 | 
						|
Crop the start and end of dimensions [1, ..., M] of reshaped_permuted according to crops to produce the output of shape: 
 | 
						|
[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]]
 | 
						|
Some examples:
 | 
						|
for the following input of shape [4, 1, 1, 3], block_shape = [2, 2], and crops = [[0, 0], [0, 0]]:
 | 
						|
[[[[1, 2, 3]]], [[[4, 5, 6]]], [[[7, 8, 9]]], [[[10, 11, 12]]]]
 | 
						|
The output variable has shape [1, 2, 2, 3] and value:
 | 
						|
x = [[[[1, 2, 3], [4, 5, 6]],
 | 
						|
      [[7, 8, 9], [10, 11, 12]]]]
 | 
						|
Returns:
 | 
						|
Output: The output variable
 | 
						|
*/
 | 
						|
 | 
						|
VARP _BatchToSpaceND(VARP input, VARP block_shape, VARP crops) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    std::unique_ptr<BlobT> blob_blockShape(new BlobT);
 | 
						|
    std::unique_ptr<BlobT> blob_paddings(new BlobT);
 | 
						|
    
 | 
						|
    auto info_block_shape = block_shape->getInfo();
 | 
						|
    auto info_crops = crops->getInfo();
 | 
						|
    MNN_ASSERT(info_block_shape != nullptr);
 | 
						|
    MNN_ASSERT(info_crops != nullptr);
 | 
						|
    MNN_ASSERT(halide_type_int == info_block_shape->type.code);
 | 
						|
    MNN_ASSERT(halide_type_int == info_crops->type.code);
 | 
						|
  
 | 
						|
    blob_blockShape->dims = info_block_shape->dim;
 | 
						|
    blob_blockShape->dataFormat = (MNN_DATA_FORMAT)Utils::convertFormat(info_block_shape->order);
 | 
						|
    blob_blockShape->dataType = (MNN::DataType)Utils::convertDataType(info_block_shape->type);
 | 
						|
    auto data_block_shape = block_shape->readMap<int>();
 | 
						|
    for (int i=0; i<info_block_shape->size; i++)
 | 
						|
    {
 | 
						|
        blob_blockShape->int32s.emplace_back(data_block_shape[i]);
 | 
						|
    }
 | 
						|
    blob_paddings->dims = info_crops->dim;
 | 
						|
    blob_paddings->dataFormat = (MNN_DATA_FORMAT)Utils::convertFormat(info_crops->order);
 | 
						|
    blob_paddings->dataType = (MNN::DataType)Utils::convertDataType(info_crops->type);
 | 
						|
    auto data_crop = crops->readMap<int>();
 | 
						|
    for (int i=0; i<info_crops->size; i++)
 | 
						|
    {
 | 
						|
        blob_paddings->int32s.emplace_back(data_crop[i]);
 | 
						|
    }
 | 
						|
    op->main.type                         = OpParameter_SpaceBatch;
 | 
						|
    op->type                              = OpType_BatchToSpaceND;
 | 
						|
    op->main.value                        = new SpaceBatchT;
 | 
						|
    op->main.AsSpaceBatch()->blockShape = std::move(blob_blockShape);
 | 
						|
    op->main.AsSpaceBatch()->padding = std::move(blob_paddings);
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*Copies a variable setting everything outside a central band in each innermost matrix.
 | 
						|
Arguments:
 | 
						|
input: Rank k variable.
 | 
						|
num_lower: Number of subdiagonals to keep. If negative, keep entire lower triangle.
 | 
						|
num_upper: Number of superdiagonals to keep. If negative, keep entire upper triangle.
 | 
						|
Returns:
 | 
						|
Output: Rank k variable of the same shape as input. The extracted banded tensor.
 | 
						|
*/
 | 
						|
VARP _MatrixBandPart(VARP input, VARP num_lower, VARP num_upper) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_MatrixBandPart;
 | 
						|
    op->main.type = OpParameter_NONE;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {input, num_lower, num_upper})));
 | 
						|
}
 | 
						|
/*Calculates the mean and variance of x.
 | 
						|
Args:
 | 
						|
x: A variable. must be 4-D with NC4HW4 format.
 | 
						|
axes: Array of ints. Axes along which to compute mean and variance. Ignored for this implementation: must be {2, 3}
 | 
						|
shift: Not used in the current implementation. 
 | 
						|
keepdims: produce moments with the same dimensionality as the input.  Ignored for this implementation: must be true.
 | 
						|
Returns:
 | 
						|
Two variable objects: mean and variance.
 | 
						|
*/
 | 
						|
std::vector<VARP> _Moments(VARP x, INTS axis, VARP shift, bool keepDims) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    axis = {2, 3};
 | 
						|
    keepDims = true;
 | 
						|
    // if axis != {2,3} or keepDims != true, print warning. 
 | 
						|
    // ignore shift.
 | 
						|
    op->type       = OpType_Moments;
 | 
						|
    auto momentsParam = new MomentsParamT;
 | 
						|
    op->main.type = OpParameter_MomentsParam;
 | 
						|
    momentsParam->dim = axis;
 | 
						|
    momentsParam->keepDims = keepDims;
 | 
						|
    op->main.value = momentsParam;
 | 
						|
    EXPRP expr = Expr::create(std::move(op), {x}, 2);
 | 
						|
    std::vector<VARP> res;
 | 
						|
    res.emplace_back(Variable::create(expr, 0));
 | 
						|
    res.emplace_back(Variable::create(expr, 1));
 | 
						|
    return res;
 | 
						|
}
 | 
						|
/*Computes the difference between two lists of numbers or strings.
 | 
						|
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. 
 | 
						|
The returned list out is sorted in the same order that the numbers appear in x (duplicates are preserved). 
 | 
						|
This operation also returns a list idx that represents the position of each out element in x. 
 | 
						|
Arguments:
 | 
						|
x: 1-D variable of type Halide_Type_Int. Values to keep. 
 | 
						|
y: 1-D variable of type Halide_Type_Int. Values to remove.
 | 
						|
Returns:
 | 
						|
Output out: 1-D variable of type Halide_Type_Int. Values present in x but not in y.
 | 
						|
*/
 | 
						|
VARP _SetDiff1D(VARP x, VARP y) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_SetDiff1D;
 | 
						|
    op->main.type = OpParameter_NONE;
 | 
						|
    op->main.value = nullptr;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {x, y}));
 | 
						|
}
 | 
						|
/*Rearranges blocks of spatial data, into depth. 
 | 
						|
More specifically, it outputs a copy of the input variable where values from the height and width dimensions are moved to the depth dimension. 
 | 
						|
The block_size indicates the input block size.
 | 
						|
Non-overlapping blocks of size block_size x block_size are rearranged into depth at each location.
 | 
						|
The depth of the output variable is block_size * block_size * input_depth.
 | 
						|
The Y, X coordinates within each block of the input become the high order component of the output channel index.
 | 
						|
The input variable's height and width must be divisible by block_size
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
block_size: An int that is >= 2. The size of the spatial block.
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as input.
 | 
						|
*/
 | 
						|
VARP _SpaceToDepth(VARP input, int block_size) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_SpaceToDepth;
 | 
						|
    auto param =  new DepthSpaceParamT;
 | 
						|
    param->blockSize = block_size;
 | 
						|
    op->main.type = OpParameter_DepthSpaceParam;
 | 
						|
    op->main.value = param;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
 | 
						|
/*This operation divides "spatial" dimensions [1, ..., M] of the input into a grid of blocks of shape block_shape, 
 | 
						|
and interleaves these blocks with the "batch" dimension 
 | 
						|
such that in the output, the spatial dimensions [1, ..., M] correspond to the position within the grid,
 | 
						|
and the batch dimension combines both the position within a spatial block and the original batch position.
 | 
						|
Prior to division into blocks, the spatial dimensions of the input are optionally zero padded according to paddings. 
 | 
						|
See below for a precise description.
 | 
						|
Args:
 | 
						|
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.
 | 
						|
block_shape: A variable. Must be one of the following types: int32, int64. 1-D with shape [M], all values must be >= 1.
 | 
						|
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.
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as input.
 | 
						|
*/
 | 
						|
VARP _SpaceToBatchND(VARP input, VARP block_shape, VARP paddings) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    std::unique_ptr<BlobT> blob_blockShape(new BlobT);
 | 
						|
    std::unique_ptr<BlobT> blob_paddings(new BlobT);
 | 
						|
    op->type       = OpType_SpaceToBatchND;
 | 
						|
    auto param =  new SpaceBatchT;
 | 
						|
    auto info_block_shape = block_shape->getInfo();
 | 
						|
    auto info_paddings = paddings->getInfo();
 | 
						|
    MNN_ASSERT(info_block_shape != nullptr);
 | 
						|
    MNN_ASSERT(info_paddings != nullptr);
 | 
						|
    MNN_ASSERT(halide_type_int == info_block_shape->type.code);
 | 
						|
    MNN_ASSERT(halide_type_int == info_paddings->type.code);
 | 
						|
  
 | 
						|
    blob_blockShape->dims = info_block_shape->dim;
 | 
						|
    blob_blockShape->dataFormat = (MNN::MNN_DATA_FORMAT)Utils::convertFormat(info_block_shape->order);
 | 
						|
    blob_blockShape->dataType = (MNN::DataType)Utils::convertDataType(info_block_shape->type);
 | 
						|
    auto data_block_shape = block_shape->readMap<int>();
 | 
						|
    for (int i=0; i<info_block_shape->size; i++)
 | 
						|
    {
 | 
						|
        blob_blockShape->int32s.emplace_back(data_block_shape[i]);
 | 
						|
    }
 | 
						|
    blob_paddings->dims = info_paddings->dim;
 | 
						|
    blob_paddings->dataFormat = (MNN::MNN_DATA_FORMAT)Utils::convertFormat(info_paddings->order);
 | 
						|
    blob_paddings->dataType = (MNN::DataType)Utils::convertDataType(info_paddings->type);
 | 
						|
    auto data_paddings = paddings->readMap<int>();
 | 
						|
    for (int i=0; i<info_paddings->size; i++)
 | 
						|
    {
 | 
						|
        blob_paddings->int32s.emplace_back(data_paddings[i]);
 | 
						|
    }
 | 
						|
    param->blockShape = std::move(blob_blockShape);
 | 
						|
    param->padding = std::move(blob_paddings);
 | 
						|
    op->main.type = OpParameter_SpaceBatch;
 | 
						|
    op->main.value = param;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*Creates a variable with all elements set to zero.
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
Returns:
 | 
						|
A variable with all elements set to zero.
 | 
						|
*/
 | 
						|
 | 
						|
VARP _ZerosLike(VARP input) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_ZerosLike;
 | 
						|
    op->main.type = OpParameter_NONE;
 | 
						|
    op->main.value = nullptr;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*Unpacks the given dimension of a rank-R tensor into rank-(R-1) variable.
 | 
						|
For example, given a variable of shape (A, B, C, D);
 | 
						|
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). 
 | 
						|
(Note that the dimension unpacked along is gone, unlike split).
 | 
						|
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). 
 | 
						|
Args:
 | 
						|
value: A rank R > 0 variable to be unstacked.
 | 
						|
num: An int. The length of the dimension axis. Automatically inferred if None (the default).
 | 
						|
axis: An int. The axis to unstack along. Defaults to the first dimension. Negative values wrap around, so the valid range is [-R, R).
 | 
						|
Returns:
 | 
						|
The list of variable objects unstacked from value.
 | 
						|
*/
 | 
						|
std::vector <VARP> _Unstack(VARP value, int axis) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Unpack;
 | 
						|
    auto info_value = value->getInfo();
 | 
						|
    MNN_ASSERT(info_value != nullptr);
 | 
						|
    auto dims = info_value->dim;
 | 
						|
    auto dimsize = dims.size();
 | 
						|
    MNN_ASSERT(dimsize >= 1);
 | 
						|
    axis = axis % dimsize;
 | 
						|
    if(axis < 0) {
 | 
						|
        axis += dimsize;
 | 
						|
    }
 | 
						|
    auto size = dims[axis];
 | 
						|
    MNN_ASSERT(size > 0);
 | 
						|
    auto axisParam = new AxisT;
 | 
						|
    axisParam->axis = axis;
 | 
						|
    op->main.type = OpParameter_Axis;
 | 
						|
    op->main.value = axisParam;
 | 
						|
    EXPRP expr = Expr::create(std::move(op), {value}, size);
 | 
						|
    std::vector<VARP> res;
 | 
						|
    for (int i = 0; i < size; ++i) {
 | 
						|
        res.emplace_back(Variable::create(expr, i));
 | 
						|
    }
 | 
						|
    return res;   
 | 
						|
}
 | 
						|
 | 
						|
/*Returns the rank of a variable.
 | 
						|
Returns a 0-D int32 variable representing the rank of input.
 | 
						|
Note: The rank of a variable is not the same as the rank of a matrix. 
 | 
						|
It's the number of indices required to uniquely select each element of the variable. 
 | 
						|
It's also known as "order", "degree", or "ndims."
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
Returns:
 | 
						|
A 0-D variable of type Halide_Type_Int
 | 
						|
*/
 | 
						|
VARP _Rank(VARP input) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Rank;
 | 
						|
    op->main.type = OpParameter_NONE;
 | 
						|
    op->main.value = nullptr;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*Creates a sequence of numbers.
 | 
						|
Args:
 | 
						|
start: A 0-D variable (scalar). 
 | 
						|
limit: A 0-D variable (scalar). 
 | 
						|
delta: A 0-D variable (scalar). 
 | 
						|
*/
 | 
						|
VARP _Range(VARP start, VARP limit, VARP delta) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Range;
 | 
						|
    auto rangeParam = new RangeT;
 | 
						|
    op->main.type = OpParameter_Range;
 | 
						|
    op->main.value = rangeParam;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {start, limit, delta}));
 | 
						|
}
 | 
						|
/*Rearranges data from depth into blocks of spatial data. 
 | 
						|
It is the reverse transformation of SpaceToDepth. More specifically,
 | 
						|
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. 
 | 
						|
Args:
 | 
						|
input: A variable.
 | 
						|
block_size: An int that is >= 2. The size of the spatial block, same as in Space2Depth.
 | 
						|
Returns:
 | 
						|
A variable. Has the same type as input.
 | 
						|
*/
 | 
						|
VARP _DepthToSpace(VARP input, int block_size) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_DepthToSpace;
 | 
						|
    auto depthtospaceParam = new DepthSpaceParamT;
 | 
						|
    depthtospaceParam->blockSize = block_size;
 | 
						|
    op->main.type = OpParameter_DepthSpaceParam;
 | 
						|
    op->main.value = depthtospaceParam;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*SSD network's priorbox layer. 
 | 
						|
Args:
 | 
						|
feature: A variable. Contains the feature map. Namely bottom[0] in caffe. 
 | 
						|
image: A variable. Contains the image. Namely bottom[1] in caffe.
 | 
						|
min_size: Minimum box size (in pixels). 
 | 
						|
max_size: Maximum box size (in pixels).
 | 
						|
aspect_ratio: Various of aspect ratios. Duplicate ratios are ignored. If none is provided, use default 1.0. 
 | 
						|
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. 
 | 
						|
clip: If true, clips the prior so that it is within [0, 1]. Default false. 
 | 
						|
variance: Variance for adjusting the prior bboxes. 
 | 
						|
img_h: image height. If 0, uses information in image. 
 | 
						|
img_w: image width.  If 0, uses information in image.
 | 
						|
step_h: step in height. 
 | 
						|
step_w: step in width. 
 | 
						|
offset: Offset to the top left corner of each cell. 
 | 
						|
Returns: 
 | 
						|
A variable. 
 | 
						|
*/
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_PriorBox;
 | 
						|
    auto param =  new PriorBoxT;
 | 
						|
    param->minSizes = min_size;
 | 
						|
    param->maxSizes = max_size;
 | 
						|
    param->aspectRatios = aspect_ratio;
 | 
						|
    param->flip = flip;
 | 
						|
    param->clip = clip;
 | 
						|
    param->variances = variance;
 | 
						|
    param->imageHeight = img_h;
 | 
						|
    param->imageWidth = img_w;
 | 
						|
    param->stepHeight = step_h;
 | 
						|
    param->stepWidth = step_w;
 | 
						|
    param->offset = offset;
 | 
						|
    op->main.type = OpParameter_PriorBox;
 | 
						|
    op->main.value = param;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {feature, image}));
 | 
						|
}
 | 
						|
/*SSD network's permute layer.  
 | 
						|
Args:
 | 
						|
input: A variable. Contains the feature map. Namely bottom[0] in caffe. 
 | 
						|
dims:  A vector. Contains the order.
 | 
						|
Returns: 
 | 
						|
A variable. 
 | 
						|
*/
 | 
						|
VARP _Permute(VARP input, INTS dims) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_Permute;
 | 
						|
    auto param =  new PermuteT;
 | 
						|
    param->dims = dims;
 | 
						|
    op->main.type = OpParameter_Permute;
 | 
						|
    op->main.value = param;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {input}));
 | 
						|
}
 | 
						|
/*SSD network's detectionoutput layer.  
 | 
						|
Args:
 | 
						|
location: A variable. 
 | 
						|
confidence:  A variable.
 | 
						|
priorbox: A variable.
 | 
						|
num_classes: number of classes.
 | 
						|
share_location: indicates wheter share location between different classes, default true. 
 | 
						|
background_label_id: default = 0. 
 | 
						|
nms_threshhold: nonmaximumsupression threshhold.
 | 
						|
mns_topk: nonmaximumsupression topk.
 | 
						|
code_type: indicates the mode to encode bbox,  default = CORNER. 
 | 
						|
variance_encoded_in_target: indicates whether encode variance in target, default false. 
 | 
						|
keep_top_k: indicates the number of boxes kept, default -1(all boxes are kept). 
 | 
						|
confidence_threshold: the threshhold for confidence. 
 | 
						|
visualize_threshold: The threshold used to visualize the detection results.
 | 
						|
Returns: 
 | 
						|
A variable. 
 | 
						|
*/
 | 
						|
VARP _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){
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_DetectionOutput;
 | 
						|
    auto param =  new DetectionOutputT;
 | 
						|
    param->classCount = num_classes;
 | 
						|
    param->shareLocation = share_location;
 | 
						|
    param->backgroundLable = background_label_id;
 | 
						|
    param->nmsThresholdold = nms_threshhold;
 | 
						|
    param->nmsTopK = nms_topk;
 | 
						|
    param->codeType = code_type;
 | 
						|
    param->varianceEncodedTarget = variance_encoded_in_target;
 | 
						|
    param->keepTopK = keep_top_k;
 | 
						|
    param->confidenceThreshold = confidence_threshold;
 | 
						|
    param->objectnessScore = visualize_threshold;
 | 
						|
    op->main.type = OpParameter_DetectionOutput;
 | 
						|
    op->main.value = param;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {location, confidence, priorbox}));
 | 
						|
}
 | 
						|
/*SSD network's detectionpostprocess layer.  
 | 
						|
Args:
 | 
						|
encode_boxes: A variable. 
 | 
						|
class_predictions:  A variable.
 | 
						|
anchors: A variable.
 | 
						|
num_classes: number of classes.
 | 
						|
max_detections: A int, indicates max detections.
 | 
						|
max_class_per_detection: A int, indicates max class per detection. 
 | 
						|
detections_per_class: A int, indicates detections per class. 
 | 
						|
nms_threshhold: A float, the threshold for nms.
 | 
						|
iou_threshold: A float, the threshold for iou. 
 | 
						|
use_regular_nms: A bool, indicates whether use regular nms method, only false is implemented currently. 
 | 
						|
centersize_encoding: A float vector, indicates the centersize encoding.  
 | 
						|
Returns: 
 | 
						|
4 variable, detection_boxes, detection_class, detection_scores, num_detections
 | 
						|
*/
 | 
						|
std::vector<VARP> _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){
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_DetectionPostProcess;
 | 
						|
    auto param =  new DetectionPostProcessParamT;
 | 
						|
    param->numClasses = num_classes;
 | 
						|
    param->maxDetections = max_detections;
 | 
						|
    param->maxClassesPerDetection = max_class_per_detection;
 | 
						|
    param->detectionsPerClass = detections_per_class;
 | 
						|
    param->nmsScoreThreshold = nms_threshold;
 | 
						|
    param->iouThreshold = iou_threshold;
 | 
						|
    param->useRegularNMS = use_regular_nms;
 | 
						|
    param->centerSizeEncoding = centersize_encoding;
 | 
						|
    op->main.type = OpParameter_DetectionPostProcessParam;
 | 
						|
    op->main.value = param;
 | 
						|
    EXPRP expr = Expr::create(std::move(op), {encode_boxes, class_predictions, anchors}, 4);
 | 
						|
    std::vector<VARP> res;
 | 
						|
    for (int i = 0; i < 4; ++i) {
 | 
						|
        res.emplace_back(Variable::create(expr, i));
 | 
						|
    }
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
VARP _Interp(VARPS xs, float widthScale, float heightScale, int outputWidth, int outputHeight, int resizeType, bool alignCorners) {
 | 
						|
    std::unique_ptr<OpT> interp(new OpT);
 | 
						|
    interp->type        = OpType_Interp;
 | 
						|
    auto param          = new InterpT;
 | 
						|
    param->widthScale   = widthScale;
 | 
						|
    param->heightScale  = heightScale;
 | 
						|
    param->outputWidth  = outputWidth;
 | 
						|
    param->outputHeight = outputHeight;
 | 
						|
    param->resizeType   = resizeType;
 | 
						|
    param->alignCorners = alignCorners;
 | 
						|
    if ((resizeType == 2 || resizeType == 3) && alignCorners) {
 | 
						|
        param->ctm = MNN::CoordinateTransformationMode_AlignCorners;
 | 
						|
    }
 | 
						|
    if ((resizeType == 2 || resizeType == 3) && !alignCorners) {
 | 
						|
        param->ctm = MNN::CoordinateTransformationMode_PytorchHalfPixels;
 | 
						|
    }
 | 
						|
    interp->main.value  = param;
 | 
						|
    interp->main.type   = OpParameter_Interp;
 | 
						|
    return Variable::create(Expr::create(std::move(interp), xs));
 | 
						|
}
 | 
						|
VARP _ZeroGrad(VARP x) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_ZeroGrad;
 | 
						|
    return Variable::create(Expr::create(std::move(op), {x}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_ConvInt8;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_DepthwiseConvInt8;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
 | 
						|
    conv2D->symmetricQuan->bias = std::move(bias);
 | 
						|
    conv2D->symmetricQuan->scale = std::move(scale);
 | 
						|
    conv2D->symmetricQuan->weight = std::move(weight);
 | 
						|
    conv2D->symmetricQuan->nbits = nbits;
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_ConvInt8;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_DepthwiseConvInt8;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() >= channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
 | 
						|
    if (bias.size() == 0) {
 | 
						|
        bias.resize(channel[1]);
 | 
						|
        std::fill(bias.begin(), bias.end(), 0);
 | 
						|
    }
 | 
						|
    conv2D->symmetricQuan->bias = std::move(bias);
 | 
						|
    conv2D->symmetricQuan->scale = std::move(scale);
 | 
						|
    conv2D->symmetricQuan->zeroPoint = std::move(inputZeroPoint);
 | 
						|
    conv2D->symmetricQuan->outputZeroPoint = std::move(outputZeroPoint);
 | 
						|
    MNN_ASSERT(maxValue > minValue);
 | 
						|
    conv2D->symmetricQuan->clampMin = minValue;
 | 
						|
    conv2D->symmetricQuan->clampMax = maxValue;
 | 
						|
    conv2D->symmetricQuan->weight = std::move(weight);
 | 
						|
 | 
						|
    if (accumulateToInt16) {
 | 
						|
        conv2D->symmetricQuan->method = MNN::QuantizeAlgo::QuantizeAlgo_OVERFLOW_AWARE;
 | 
						|
    }
 | 
						|
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _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) {
 | 
						|
    std::unique_ptr<OpT> convOp(new OpT);
 | 
						|
    convOp->type = OpType_ConvInt8;
 | 
						|
    if (channel[0] == channel[1] && channel[0] == group) {
 | 
						|
        convOp->type = OpType_DepthwiseConvInt8;
 | 
						|
    }
 | 
						|
    convOp->main.type  = OpParameter_Convolution2D;
 | 
						|
    convOp->main.value = new Convolution2DT;
 | 
						|
    auto conv2D        = convOp->main.AsConvolution2D();
 | 
						|
    conv2D->common.reset(new Convolution2DCommonT);
 | 
						|
    conv2D->common->padMode     = _convertPadMode(pad);
 | 
						|
    if (pads.size() == 2) {
 | 
						|
        conv2D->common->padX        = pads[0];
 | 
						|
        conv2D->common->padY        = pads[1];
 | 
						|
    } else {
 | 
						|
        conv2D->common->pads = std::move(pads);
 | 
						|
    }
 | 
						|
    conv2D->common->strideX     = stride[0];
 | 
						|
    conv2D->common->strideY     = stride[1];
 | 
						|
    conv2D->common->group       = group;
 | 
						|
    conv2D->common->outputCount = channel[1];
 | 
						|
    conv2D->common->inputCount  = channel[0];
 | 
						|
    conv2D->common->dilateX     = dilate[0];
 | 
						|
    conv2D->common->dilateY     = dilate[1];
 | 
						|
    conv2D->common->kernelX     = kernelSize[0];
 | 
						|
    conv2D->common->kernelY     = kernelSize[1];
 | 
						|
    conv2D->common->relu = relu;
 | 
						|
    MNN_ASSERT(weight.size() == channel[1] * (channel[0] / group) * kernelSize[0] * kernelSize[1]);
 | 
						|
    conv2D->symmetricQuan.reset(new QuantizedFloatParamT);
 | 
						|
    if (bias.size() == 0) {
 | 
						|
        bias.resize(channel[1]);
 | 
						|
        std::fill(bias.begin(), bias.end(), 0);
 | 
						|
    }
 | 
						|
 | 
						|
    conv2D->bias = bias;
 | 
						|
    
 | 
						|
    conv2D->symmetricQuan->weight = std::move(weight);
 | 
						|
    conv2D->symmetricQuan->zeroPoint = std::move(inputZeroPoint);
 | 
						|
    conv2D->symmetricQuan->outputZeroPoint = std::move(outputZeroPoint);
 | 
						|
    MNN_ASSERT(maxValue > minValue);
 | 
						|
    conv2D->symmetricQuan->clampMin = minValue;
 | 
						|
    conv2D->symmetricQuan->clampMax = maxValue;
 | 
						|
    conv2D->symmetricQuan->nbits = int(std::log(weightClampValue * 2 + 2) / std::log(2.0f));
 | 
						|
 | 
						|
    // const int kn = conv2D->common->outputCount;
 | 
						|
    // const int ks = weight.size() / kn;
 | 
						|
    // std::vector<float> scales(kn, 1.0f);
 | 
						|
    // std::vector<float> weightFloat;
 | 
						|
    // for (int i = 0; i < weight.size(); i++) {
 | 
						|
    //     weightFloat.emplace_back(weight[i] * weightScale[i / ks]);
 | 
						|
    // }
 | 
						|
    // conv2D->quanParameter = IDSTEncoder::encode(weightFloat, weightScale, ks, kn, false, weight.data(), -int(weightClampValue));
 | 
						|
 | 
						|
    conv2D->quanParameter.reset(new IDSTQuanT);
 | 
						|
    conv2D->quanParameter->alpha = std::move(weightScale);
 | 
						|
    conv2D->quanParameter->scaleIn = scaleIn;
 | 
						|
    conv2D->quanParameter->scaleOut = scaleOut;
 | 
						|
    conv2D->quanParameter->aMin = -int(weightClampValue);
 | 
						|
 | 
						|
    if (accumulateToInt16) {
 | 
						|
        conv2D->symmetricQuan->method = MNN::QuantizeAlgo::QuantizeAlgo_OVERFLOW_AWARE;
 | 
						|
    }
 | 
						|
 | 
						|
    return (Variable::create(Expr::create(convOp.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _CosineSimilarity(VARP input0, VARP input1, VARP inputDim) {
 | 
						|
    std::unique_ptr<MNN::OpT> cosineSimilarityOp(new MNN::OpT);
 | 
						|
    cosineSimilarityOp->type = MNN::OpType_CosineSimilarity;
 | 
						|
    return (Variable::create(Expr::create(std::move(cosineSimilarityOp), {input0, input1, inputDim})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _GridSample(VARP input, VARP grid, InterpolationMethod mode, GridSamplePaddingMode paddingMode, bool alignCorners) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type                                       = OpType_GridSample;
 | 
						|
    op->main.type                                  = OpParameter_GridSample;
 | 
						|
    op->main.value                                 = new GridSampleT;
 | 
						|
    switch (mode) {
 | 
						|
        case NEAREST:
 | 
						|
            op->main.AsGridSample()->mode = SampleMode_NEAREST;
 | 
						|
            break;
 | 
						|
        case BILINEAR:
 | 
						|
        default:
 | 
						|
            op->main.AsGridSample()->mode = SampleMode_BILINEAR;
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    switch (paddingMode) {
 | 
						|
        case GRID_SAMPLE_PADDING_BORDER:
 | 
						|
            op->main.AsGridSample()->paddingMode = BorderMode_CLAMP;
 | 
						|
            break;
 | 
						|
        case GRID_SAMPLE_PADDING_REFLECTION:
 | 
						|
            op->main.AsGridSample()->paddingMode = BorderMode_REFLECTION;
 | 
						|
            break;
 | 
						|
        case GRID_SAMPLE_PADDING_ZEROS:
 | 
						|
        default:
 | 
						|
            op->main.AsGridSample()->paddingMode = BorderMode_ZEROS;
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    op->main.AsGridSample()->alignCorners = alignCorners;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {input, grid})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _FloatToInt8(VARP x, VARP scale, char minValue/*For future*/, char maxValue/*For future*/) {
 | 
						|
    auto scaleInfo = scale->getInfo();
 | 
						|
    auto scalePtr = scale->readMap<float>();
 | 
						|
    if (nullptr == scalePtr || nullptr == scaleInfo) {
 | 
						|
        MNN_ERROR("Error for FloatToInt8 because scale not ready\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_FloatToInt8;
 | 
						|
    op->main.type = OpParameter_QuantizedFloatParam;
 | 
						|
    op->main.value = new QuantizedFloatParamT;
 | 
						|
    op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
 | 
						|
    ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
 | 
						|
    return Variable::create(Expr::create(op.get(), {x}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _FloatToInt8(VARP x, VARP scale, int8_t minValue, int8_t maxValue, int8_t zeroPoint) {
 | 
						|
    auto scaleInfo = scale->getInfo();
 | 
						|
    auto scalePtr = scale->readMap<float>();
 | 
						|
    if (nullptr == scalePtr || nullptr == scaleInfo) {
 | 
						|
        MNN_ERROR("Error for FloatToInt8 because var not ready\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_FloatToInt8;
 | 
						|
    op->main.type = OpParameter_QuantizedFloatParam;
 | 
						|
    op->main.value = new QuantizedFloatParamT;
 | 
						|
    op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
 | 
						|
    ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
 | 
						|
    op->main.AsQuantizedFloatParam()->zeroPoint = zeroPoint;
 | 
						|
    MNN_ASSERT(maxValue > minValue);
 | 
						|
    op->main.AsQuantizedFloatParam()->clampMin = int8_t(minValue);
 | 
						|
    op->main.AsQuantizedFloatParam()->clampMax = int8_t(maxValue);
 | 
						|
    return Variable::create(Expr::create(op.get(), {x}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Int8ToFloat(VARP x, VARP scale) {
 | 
						|
    auto xInfo = x->getInfo();
 | 
						|
    auto scaleInfo = scale->getInfo();
 | 
						|
    auto scalePtr = scale->readMap<float>();
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_Int8ToFloat;
 | 
						|
    op->main.type = OpParameter_QuantizedFloatParam;
 | 
						|
    op->main.value = new QuantizedFloatParamT;
 | 
						|
    op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
 | 
						|
    ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
 | 
						|
    return Variable::create(Expr::create(op.get(), {x}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Int8ToFloat(VARP x, VARP scale, int8_t zeroPoint) {
 | 
						|
    auto xInfo = x->getInfo();
 | 
						|
    auto scaleInfo = scale->getInfo();
 | 
						|
    auto scalePtr = scale->readMap<float>();
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_Int8ToFloat;
 | 
						|
    op->main.type = OpParameter_QuantizedFloatParam;
 | 
						|
    op->main.value = new QuantizedFloatParamT;
 | 
						|
    op->main.AsQuantizedFloatParam()->tensorScale.resize(scaleInfo->size);
 | 
						|
    ::memcpy(op->main.AsQuantizedFloatParam()->tensorScale.data(), scalePtr, scaleInfo->size * sizeof(float));
 | 
						|
    op->main.AsQuantizedFloatParam()->zeroPoint = zeroPoint;
 | 
						|
    return Variable::create(Expr::create(op.get(), {x}));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Select(VARP select, VARP input0, VARP input1) {
 | 
						|
    std::unique_ptr<MNN::OpT> selectOp(new MNN::OpT);
 | 
						|
    selectOp->type = MNN::OpType_Select;
 | 
						|
    return (Variable::create(Expr::create(std::move(selectOp), {select, input0, input1})));
 | 
						|
}
 | 
						|
 | 
						|
std::vector<VARP> _TopKV2(VARP input0, VARP input1) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_TopKV2;
 | 
						|
    auto expr = Expr::create(op.get(), {input0, input1}, 2);
 | 
						|
    std::vector<VARP> res(2);
 | 
						|
    res[0] = Variable::create(expr, 0);
 | 
						|
    res[1] = Variable::create(expr, 1);
 | 
						|
    return res;
 | 
						|
}
 | 
						|
 | 
						|
VARP _ImageProcess(VARP input, CV::ImageProcess::Config config, CV::Matrix matrix, int oh, int ow, int oc, int dtype, uint8_t padVal) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_ImageProcess;
 | 
						|
    op->main.type = OpParameter_ImageProcessParam;
 | 
						|
    auto process = new ImageProcessParamT;
 | 
						|
    op->main.value = process;
 | 
						|
    process->destFormat = (MNN::ImageFormatType)config.destFormat;
 | 
						|
    process->sourceFormat = (MNN::ImageFormatType)config.sourceFormat;
 | 
						|
    process->filterType = (MNN::FilterType)config.filterType;
 | 
						|
    process->wrap = (MNN::WrapType)config.wrap;
 | 
						|
    process->shape = {1, oc, oh, ow};
 | 
						|
    process->outputType = (DataType)dtype;
 | 
						|
    process->paddingValue = padVal;
 | 
						|
    process->mean.resize(4);
 | 
						|
    process->normal.resize(4);
 | 
						|
    process->transform.resize(9);
 | 
						|
    for (int i = 0; i < 4; i++) {
 | 
						|
        process->mean[i] = config.mean[i];
 | 
						|
        process->normal[i] = config.normal[i];
 | 
						|
    }
 | 
						|
    for (int i = 0; i < 9; i++) {
 | 
						|
        process->transform[i] = matrix.get(i);
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {input})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Where(VARP x) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_Where;
 | 
						|
    op->main.type = OpParameter_Extra;
 | 
						|
    op->main.value = new ExtraT;
 | 
						|
    return (Variable::create(Expr::create(std::move(op), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Sort(VARP x, int axis, bool arg, bool descend) {
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type = OpType_TopKV2;
 | 
						|
    op->main.type = OpParameter_TopKV2;
 | 
						|
    auto topk = new TopKV2T;
 | 
						|
    topk->largest = descend;
 | 
						|
    op->main.value = topk;
 | 
						|
    auto shape = x->getInfo()->dim;
 | 
						|
    axis = axis < 0 ? shape.size() + axis : axis;
 | 
						|
    int k = x->getInfo()->dim[axis];
 | 
						|
    std::vector<VARP> inputs {x, _Scalar(k)};
 | 
						|
    if (axis + 1 != shape.size()) {
 | 
						|
        inputs.push_back(_Scalar(axis));
 | 
						|
    }
 | 
						|
    auto expr = Expr::create(op.get(), inputs, 2);
 | 
						|
    return Variable::create(expr, arg);
 | 
						|
}
 | 
						|
 | 
						|
VARP _Raster(const std::vector<VARP>& vars, const std::vector<int>& region, const std::vector<int>& shape) {
 | 
						|
    auto expr = Utils::makeRaster(vars, region, shape, halide_type_of<float>(), MNN_DATA_FORMAT_UNKNOWN);
 | 
						|
    return (Variable::create(expr));
 | 
						|
}
 | 
						|
VARP _RasterRaw(const std::vector<VARP>& vars, const std::vector<int>& region, const std::vector<int>& shape, halide_type_t dataType, Dimensionformat eformat) {
 | 
						|
    auto format = Utils::convertFormat(eformat);
 | 
						|
    auto expr = Utils::makeRaster(vars, region, shape, dataType, (MNN_DATA_FORMAT)format);
 | 
						|
    return (Variable::create(expr));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Nms(VARP boxes, VARP scores, int maxDetections, float iouThreshold, float scoreThreshold) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = OpType_NonMaxSuppressionV2;
 | 
						|
    std::vector<VARP> vars {boxes, scores, _Scalar(maxDetections)};
 | 
						|
    if (iouThreshold >= 0) {
 | 
						|
        vars.push_back(_Scalar(iouThreshold));
 | 
						|
    }
 | 
						|
    if (scoreThreshold >= 0) {
 | 
						|
        vars.push_back(_Scalar(scoreThreshold));
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(std::move(op), vars)));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Im2Col(VARP x, INTS kernelSize, INTS dilate, INTS pads, INTS stride) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_Im2Col;
 | 
						|
    op->main.type  = OpParameter_Convolution2D;
 | 
						|
    auto param = new MNN::Convolution2DT;
 | 
						|
    auto common    = new Convolution2DCommonT;
 | 
						|
    param->common.reset(common);
 | 
						|
    op->main.value = param;
 | 
						|
    common->padX        = pads[0];
 | 
						|
    common->padY        = pads[1];
 | 
						|
    common->strideX     = stride[0];
 | 
						|
    common->strideY     = stride[1];
 | 
						|
    common->dilateX     = dilate[0];
 | 
						|
    common->dilateY     = dilate[1];
 | 
						|
    common->kernelX     = kernelSize[0];
 | 
						|
    common->kernelY     = kernelSize[1];
 | 
						|
    return (Variable::create(Expr::create(op.get(), {x})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _Col2Im(VARP x, VARP outputShape, INTS kernelSize, INTS dilate, INTS pads, INTS stride) {
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_Col2Im;
 | 
						|
    op->main.type  = OpParameter_Convolution2D;
 | 
						|
    auto param = new MNN::Convolution2DT;
 | 
						|
    auto common    = new Convolution2DCommonT;
 | 
						|
    param->common.reset(common);
 | 
						|
    op->main.value = param;
 | 
						|
    common->padX        = pads[0];
 | 
						|
    common->padY        = pads[1];
 | 
						|
    common->strideX     = stride[0];
 | 
						|
    common->strideY     = stride[1];
 | 
						|
    common->dilateX     = dilate[0];
 | 
						|
    common->dilateY     = dilate[1];
 | 
						|
    common->kernelX     = kernelSize[0];
 | 
						|
    common->kernelY     = kernelSize[1];
 | 
						|
    return (Variable::create(Expr::create(op.get(), {x, outputShape})));
 | 
						|
}
 | 
						|
 | 
						|
VARPS _Loop(VARPS x, const std::string& submoduleName) {
 | 
						|
    auto subgraph = ExecutorScope::Current()->findSubGraph(submoduleName);
 | 
						|
    if (nullptr == subgraph) {
 | 
						|
        MNN_ERROR("Loop Error: Can't find submoduleName: %s\n", submoduleName.c_str());
 | 
						|
        return VARPS{};
 | 
						|
    }
 | 
						|
    auto info = subgraph->info.get();
 | 
						|
    if (info->inputs.size() != x.size()) {
 | 
						|
        MNN_ERROR("Loop Error: input number not match: x: %d : submodule: %d\n", (int)x.size(), (int)info->inputs.size());
 | 
						|
        return VARPS{};
 | 
						|
    }
 | 
						|
    std::unique_ptr<MNN::OpT> op(new MNN::OpT);
 | 
						|
    op->type = MNN::OpType_While;
 | 
						|
    op->main.type  = OpParameter_WhileParam;
 | 
						|
    auto param = new MNN::WhileParamT;
 | 
						|
    op->main.value = param;
 | 
						|
    param->body_graph = submoduleName;
 | 
						|
    // Body Input: 2 + N, Body Output: 1 + N + K, Op output: N + K
 | 
						|
    int N = (int)info->inputs.size() - 2;
 | 
						|
    int K = (int)info->outputs.size() - N - 1;
 | 
						|
    MNN_ASSERT(info->inputs.size() >= 2);
 | 
						|
    EXPRP expr = Expr::create(op.get(), x, N+K);
 | 
						|
    VARPS outputs(N+K);
 | 
						|
    for (int i=0; i<N+K; ++i) {
 | 
						|
        outputs[i] = Variable::create(expr, i);
 | 
						|
    }
 | 
						|
    return outputs;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
VARP _ROIPooling(VARP input, VARP roi, int pooledHeight, int pooledWidth, float spatialScale, bool outputGrad, VARP backwardDiff) {
 | 
						|
    if (input == nullptr) {
 | 
						|
        MNN_ERROR("input nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (input->getInfo() == nullptr) {
 | 
						|
        MNN_ERROR("input info nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (input->getInfo()->order != NC4HW4) {
 | 
						|
        MNN_ERROR("input format must be nc4hw4\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    std::unique_ptr<RoiParametersT> roiPooling(new RoiParametersT);
 | 
						|
    roiPooling->pooledHeight = pooledHeight;
 | 
						|
    roiPooling->pooledWidth  = pooledWidth;
 | 
						|
    roiPooling->spatialScale = spatialScale;
 | 
						|
    roiPooling->outputGrad = outputGrad;
 | 
						|
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_ROIPooling;
 | 
						|
    op->main.type  = OpParameter_RoiParameters;
 | 
						|
    op->main.value = roiPooling.release();
 | 
						|
 | 
						|
    if (outputGrad == false) {
 | 
						|
        return (Variable::create(Expr::create(op.get(), {input, roi})));
 | 
						|
    }
 | 
						|
 | 
						|
    if (backwardDiff == nullptr) {
 | 
						|
        MNN_ERROR("backwardDiff is null for roi_pool backward mode\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (backwardDiff->getInfo() == nullptr) {
 | 
						|
        MNN_ERROR("backwardDiff info nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (backwardDiff->getInfo()->order != NC4HW4) {
 | 
						|
        MNN_ERROR("backwardDiff format must be nc4hw4\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    return (Variable::create(Expr::create(op.get(), {input, roi, backwardDiff})));
 | 
						|
}
 | 
						|
 | 
						|
VARP _ROIAlign(VARP input, VARP roi, int pooledHeight, int pooledWidth, float spatialScale, int samplingRatio, bool aligned, PoolingMode poolType, bool outputGrad, VARP backwardDiff) {
 | 
						|
    if (input == nullptr) {
 | 
						|
        MNN_ERROR("input nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (input->getInfo() == nullptr) {
 | 
						|
        MNN_ERROR("input info nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (input->getInfo()->order != NC4HW4) {
 | 
						|
        MNN_ERROR("input format must be nc4hw4\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    std::unique_ptr<RoiParametersT> roiAlign(new RoiParametersT);
 | 
						|
    roiAlign->pooledWidth   = pooledWidth;
 | 
						|
    roiAlign->pooledHeight  = pooledHeight;
 | 
						|
    roiAlign->spatialScale  = spatialScale;
 | 
						|
    roiAlign->samplingRatio = samplingRatio;
 | 
						|
    roiAlign->aligned       = aligned;
 | 
						|
    roiAlign->poolType      = (PoolType)poolType;
 | 
						|
    roiAlign->outputGrad = outputGrad;
 | 
						|
 | 
						|
    std::unique_ptr<OpT> op(new OpT);
 | 
						|
    op->type       = OpType_ROIAlign;
 | 
						|
    op->main.type  = OpParameter_RoiParameters;
 | 
						|
    op->main.value = roiAlign.release();
 | 
						|
 | 
						|
    if (outputGrad == false) {
 | 
						|
        return (Variable::create(Expr::create(op.get(), {input, roi})));
 | 
						|
    }
 | 
						|
 | 
						|
    if (poolType == PoolingMode::MAXPOOL) {
 | 
						|
        MNN_ERROR("backward of RoiAlign with max pool type is not supported currently, see TODO in CPUROIAlign.cpp\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (backwardDiff == nullptr) {
 | 
						|
        MNN_ERROR("backwardDiff is null for roi_align backward mode\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (backwardDiff->getInfo() == nullptr) {
 | 
						|
        MNN_ERROR("backwardDiff info nullptr\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    if (backwardDiff->getInfo()->order != NC4HW4) {
 | 
						|
        MNN_ERROR("backwardDiff format must be nc4hw4\n");
 | 
						|
        return nullptr;
 | 
						|
    }
 | 
						|
    auto bI = _Split(roi, {1, 4}, 1);
 | 
						|
    auto info0 = bI[0]->getInfo();
 | 
						|
    auto ptr0 = bI[0]->readMap<float>();
 | 
						|
    return (Variable::create(Expr::create(op.get(), {input, bI[1], _Cast<int>(bI[0]), backwardDiff})));
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Express
 | 
						|
} // namespace MNN
 |