mindspore2022/mindspore/lite/internal/src/kernel/fp32/arithmetic.cc

198 lines
8.0 KiB
C++

/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "internal/src/kernel/fp32/arithmetic.h"
#include "internal/src/lite_log.h"
#include "internal/include/errorcode.h"
#include "internal/include/model.h"
#include "internal/include/ms_tensor.h"
#include "internal/include/lite_utils.h"
#include "nnacl/arithmetic_common.h"
#include "nnacl/fp32/arithmetic_fp32.h"
typedef int (*ArithmeticRun)(const float *input0, const float *input1, float *output, const int element_size);
typedef int (*ArithmeticOptRun)(const float *input0, const float *input1, float *output, const int element_size,
const ArithmeticParameter *param);
int BroadcastRun(float *input0, float *input1, float *output, int dim, int out_count, int break_pos,
ArithmeticRun arithmetic_run, ArithmeticParameter *params) {
if (dim > break_pos) {
return arithmetic_run(input0, input1, output, out_count);
}
for (int i = 0; i < params->out_shape_[dim]; ++i) {
int pos0_ = params->in_shape0_[dim] == 1 ? 0 : i;
int pos1_ = params->in_shape1_[dim] == 1 ? 0 : i;
int error_code =
BroadcastRun(input0 + pos0_ * params->in_strides0_[dim], input1 + pos1_ * params->in_strides1_[dim],
output + i * params->out_strides_[dim], dim + 1, out_count, break_pos, arithmetic_run, params);
if (error_code != RET_OK) {
return error_code;
}
}
return RET_OK;
}
int CalBroadCasting(const TensorPtrVector &in_tensors, int *outside, int *break_pos, ArithmeticParameter *params) {
params->broadcasting_ = false;
for (size_t i = 0; i < params->ndim_; ++i) {
if (params->in_shape0_[i] != params->in_shape1_[i]) {
if (params->in_shape0_[i] == 1) {
params->out_shape_[i] = params->in_shape1_[i];
} else if (params->in_shape1_[i] == 1) {
params->out_shape_[i] = params->in_shape0_[i];
} else {
LITE_LOG_ERROR("shapes of input tensors can not be broadCasted");
return RET_INPUT_TENSOR_ERROR;
}
params->broadcasting_ = true;
} else {
params->out_shape_[i] = params->in_shape0_[i];
}
}
if (params->broadcasting_) {
*outside = 1;
for (auto i = params->ndim_ - 1; i >= 0; --i) {
if (params->in_shape0_[i] != params->in_shape1_[i]) {
*break_pos = i;
break;
}
(*outside) *= params->out_shape_[i];
}
ComputeStrides(params->in_shape0_, params->in_strides0_, params->ndim_);
ComputeStrides(params->in_shape1_, params->in_strides1_, params->ndim_);
ComputeStrides(params->out_shape_, params->out_strides_, params->ndim_);
}
return RET_OK;
}
int RunArithmetic(const TensorPtrVector &in_tensors, const TensorPtrVector &out_tensors, ArithmeticRun arithmetic_run,
ArithmeticOptRun arithmetic_opt_run, int outside, int break_pos, ArithmeticParameter *params) {
int error_code = RET_OK;
int count = out_tensors[0]->ElementsNum();
float *input0_data = reinterpret_cast<float *>(in_tensors[0]->data_);
float *input1_data1 = reinterpret_cast<float *>(in_tensors[1]->data_);
float *output_data = reinterpret_cast<float *>(out_tensors[0]->data_);
if (params->broadcasting_) {
error_code = BroadcastRun(input0_data, input1_data1, output_data, 0, outside, break_pos, arithmetic_run, params);
} else if (arithmetic_opt_run != NULL) {
error_code = arithmetic_opt_run(input0_data, input1_data1, output_data, count, params);
} else {
error_code = arithmetic_run(input0_data, input1_data1, output_data, count);
}
if (error_code != RET_OK) {
return error_code;
}
return RET_OK;
}
int DoArithmeticInferShape(const TensorPtrVector &in_tensors, const TensorPtrVector &out_tensors, OpParameter *param) {
if (in_tensors.size() != 2 || in_tensors[0]->data_ == NULL || in_tensors[1]->data_ == NULL) {
LITE_LOG_ERROR("input tensors num not correct or input data is NULL!");
return RET_INPUT_TENSOR_ERROR;
}
if (out_tensors.size() != 1) {
LITE_LOG_ERROR("output tensors num not correct!");
return RET_ERROR;
}
int in_datatype[2] = {in_tensors[0]->data_type_, in_tensors[1]->data_type_};
int in_format[2] = {static_cast<int>(in_tensors[0]->format_), static_cast<int>(in_tensors[1]->format_)};
size_t dim_size[2] = {in_tensors[0]->shape_.size(), in_tensors[1]->shape_.size()};
int *in_shape[2] = {in_tensors[0]->shape_.data(), in_tensors[1]->shape_.data()};
int out_format;
int out_datatype;
int ret = ArithmeticInferShape(in_shape, dim_size, out_tensors[0]->shape_.data(), in_format, &out_format, in_datatype,
&out_datatype, param);
if (ret != NNACL_OK) {
LITE_ERROR_LOG("arithmetic infershape failed! ret: %d", ret);
return RET_ERROR;
}
out_tensors[0]->format_ = static_cast<Format>(out_format);
out_tensors[0]->data_type_ = static_cast<TypeId>(out_datatype);
return RET_OK;
}
int ChooseKernel(const int kernel_type, ArithmeticRun *arithmetic_run, ArithmeticParameter *params) {
if (kernel_type == KernelType::KernelType_Mul) {
if (params->activation_type_ == ActivationType::RELU) {
*arithmetic_run = ElementMulRelu;
} else if (params->activation_type_ == ActivationType::RELU6) {
*arithmetic_run = ElementMulRelu6;
} else {
*arithmetic_run = ElementMul;
}
} else {
LITE_LOG_INFO("unsupported operator type");
return RET_ERROR;
}
return RET_OK;
}
int ChooseOptKernel(const int kernel_type, ArithmeticOptRun *arithmetic_opt_run, ArithmeticParameter *params) {
if (kernel_type == KernelType::KernelType_Mul) {
if (params->activation_type_ == ActivationType::RELU) {
*arithmetic_opt_run = ElementOptMulRelu;
} else if (params->activation_type_ == ActivationType::RELU6) {
*arithmetic_opt_run = ElementOptMulRelu6;
} else {
*arithmetic_opt_run = ElementOptMul;
}
} else {
LITE_LOG_INFO("kernel not have opt version");
}
return RET_OK;
}
int DoArithmetic(const TensorPtrVector &in_tensors, const TensorPtrVector &out_tensors, Node *node,
mindspore::lite::Allocator *allocator) {
if (in_tensors.size() != 2 || in_tensors[0]->data_ == NULL || in_tensors[1]->data_ == NULL) {
LITE_LOG_ERROR("input tensors num not correct or input data is NULL!");
return RET_INPUT_TENSOR_ERROR;
}
if (out_tensors.size() != 1 || out_tensors[0]->data_ == NULL) {
LITE_LOG_ERROR("output tensors num not correct or output data is NULL!");
return RET_ERROR;
}
if (allocator == NULL) {
LITE_LOG_ERROR("allocator is NULL!");
return RET_ERROR;
}
ArithmeticParameter *params = reinterpret_cast<ArithmeticParameter *>(node->primitive_);
ArithmeticRun arithmetic_run = NULL;
int kernel_type = params->op_parameter_.type_;
int status = ChooseKernel(kernel_type, &arithmetic_run, params);
if (status != RET_OK) {
return status;
}
int outside = 0;
int break_pos = 0;
// when one of input only has one element
params->in_elements_num0_ = in_tensors[0]->ElementsNum();
params->in_elements_num1_ = in_tensors[1]->ElementsNum();
params->out_elements_num_ = out_tensors[0]->ElementsNum();
ArithmeticOptRun arithmetic_opt_run = NULL;
if (params->in_elements_num0_ == 1 || params->in_elements_num1_ == 1) {
params->broadcasting_ = false;
ChooseOptKernel(kernel_type, &arithmetic_opt_run, params);
} else {
int ret = CalBroadCasting(in_tensors, &outside, &break_pos, params);
if (ret != RET_OK) {
return ret;
}
}
return RunArithmetic(in_tensors, out_tensors, arithmetic_run, arithmetic_opt_run, outside, break_pos, params);
}