forked from mindspore-Ecosystem/mindspore
add external libs cmsis
This commit is contained in:
parent
7e2b8880d0
commit
d479bccef5
|
@ -7,6 +7,7 @@ include(${TOP_DIR}/cmake/utils.cmake)
|
||||||
include(${TOP_DIR}/cmake/dependency_utils.cmake)
|
include(${TOP_DIR}/cmake/dependency_utils.cmake)
|
||||||
include(${TOP_DIR}/cmake/dependency_securec.cmake)
|
include(${TOP_DIR}/cmake/dependency_securec.cmake)
|
||||||
include(${TOP_DIR}/cmake/external_libs/flatbuffers.cmake)
|
include(${TOP_DIR}/cmake/external_libs/flatbuffers.cmake)
|
||||||
|
include(${TOP_DIR}/cmake/external_libs/cmsis.cmake)
|
||||||
|
|
||||||
set(FBS_FILES
|
set(FBS_FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../schema/model.fbs
|
${CMAKE_CURRENT_SOURCE_DIR}/../schema/model.fbs
|
||||||
|
|
|
@ -33,6 +33,10 @@ set(LITE_SRC
|
||||||
${LITE_DIR}/src/tensorlist.cc
|
${LITE_DIR}/src/tensorlist.cc
|
||||||
${LITE_DIR}/src/tensor.cc
|
${LITE_DIR}/src/tensor.cc
|
||||||
${LITE_DIR}/src/common/log_adapter.cc
|
${LITE_DIR}/src/common/log_adapter.cc
|
||||||
|
${NNACL_DIR}/int8/quantize.c
|
||||||
|
${NNACL_DIR}/int8/pack_int8.c
|
||||||
|
${NNACL_DIR}/int8/matmul_int8.c
|
||||||
|
${NNACL_DIR}/int8/fixed_point.c
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB_RECURSE MICRO_ALLOCATOR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
file(GLOB_RECURSE MICRO_ALLOCATOR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
@ -43,6 +47,14 @@ file(GLOB_RECURSE MICRO_GENERATOR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
generator/*.cc
|
generator/*.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE MICRO_OPCODERS_BASE RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/opcoders/base/*.cc
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE MICRO_OPCODERS_CMSIS_NN RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/opcoders/cmsis-nn/*.cc
|
||||||
|
)
|
||||||
|
|
||||||
file(GLOB_RECURSE MICRO_UTILS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
file(GLOB_RECURSE MICRO_UTILS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
utils/*.cc
|
utils/*.cc
|
||||||
)
|
)
|
||||||
|
@ -62,6 +74,8 @@ set(MICRO_CODER_SRC
|
||||||
list(APPEND MICRO_CODER_SRC
|
list(APPEND MICRO_CODER_SRC
|
||||||
${MICRO_ALLOCATOR}
|
${MICRO_ALLOCATOR}
|
||||||
${MICRO_GENERATOR}
|
${MICRO_GENERATOR}
|
||||||
|
${MICRO_OPCODERS_BASE}
|
||||||
|
${MICRO_OPCODERS_CMSIS_NN}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(codegen main.cc
|
add_executable(codegen main.cc
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/base/conv2d_base_coder.h"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "nnacl/winograd_utils.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
#include "micro/coder/log.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int MallocConvQuantParams(ConvQuantArg *quant_arg, size_t input_arg_num, size_t filter_arg_num, size_t output_arg_num) {
|
||||||
|
MS_CHECK_TRUE(input_arg_num > 0, "invalid value of input_arg_num");
|
||||||
|
MS_CHECK_TRUE(filter_arg_num > 0, "invalid value of filter_arg_num");
|
||||||
|
MS_CHECK_TRUE(output_arg_num > 0, "invalid value of output_arg_num");
|
||||||
|
quant_arg->input_quant_args_ = static_cast<QuantArg *>(malloc(input_arg_num * sizeof(struct QuantArg)));
|
||||||
|
MS_CHECK_PTR(quant_arg->input_quant_args_);
|
||||||
|
quant_arg->filter_quant_args_ = static_cast<QuantArg *>(malloc(filter_arg_num * sizeof(QuantArg)));
|
||||||
|
MS_CHECK_PTR(quant_arg->filter_quant_args_);
|
||||||
|
quant_arg->output_quant_args_ = static_cast<QuantArg *>(malloc(output_arg_num * sizeof(QuantArg)));
|
||||||
|
MS_CHECK_PTR(quant_arg->output_quant_args_);
|
||||||
|
return mindspore::lite::RET_OK;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
string Conv2DBaseCoder::LayoutTransformFp32(schema::Format src_format, schema::Format dst_format) {
|
||||||
|
string ret;
|
||||||
|
if (src_format == schema::Format_NHWC && dst_format == schema::Format_NC4HW4) {
|
||||||
|
ret = "PackNHWCToNC4HW4Fp32";
|
||||||
|
} else if (src_format == schema::Format_NHWC && dst_format == schema::Format_NHWC4) {
|
||||||
|
ret = "PackNHWCToNHWC4Fp32";
|
||||||
|
} else if (src_format == schema::Format_NC4HW4 && dst_format == schema::Format_NHWC4) {
|
||||||
|
ret = "PackNC4HW4ToNHWC4Fp32";
|
||||||
|
} else if (src_format == schema::Format_NCHW && dst_format == schema::Format_NC4HW4) {
|
||||||
|
ret = "PackNCHWToNC4HW4Fp32";
|
||||||
|
} else if (src_format == schema::Format_NC4HW4 && dst_format == schema::Format_NHWC) {
|
||||||
|
ret = "PackNC4HW4ToNHWCFp32";
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "Unsupported transform from " << schema::EnumNameFormat(src_format) << " to "
|
||||||
|
<< schema::EnumNameFormat(dst_format);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Conv2DBaseCoder::LayoutTransformInt8(schema::Format src_format, schema::Format dst_format) {
|
||||||
|
string ret;
|
||||||
|
if (src_format == schema::Format_NHWC && dst_format == schema::Format_NHWC4) {
|
||||||
|
ret = "PackNHWCToNHWC4Int8";
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "Unsupported transform from " << schema::EnumNameFormat(src_format) << " to "
|
||||||
|
<< schema::EnumNameFormat(dst_format);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Conv2DBaseCoder::LayoutTransform(TypeId data_type, schema::Format src_format, schema::Format dst_format) {
|
||||||
|
string ret;
|
||||||
|
switch (data_type) {
|
||||||
|
case kNumberTypeInt8:
|
||||||
|
ret = LayoutTransformInt8(src_format, dst_format);
|
||||||
|
break;
|
||||||
|
case kNumberTypeFloat32:
|
||||||
|
ret = LayoutTransformFp32(src_format, dst_format);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MS_LOG(WARNING) << "unsupported data type";
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetIfPerChannel() {
|
||||||
|
auto input_channel = static_cast<size_t>(filter_tensor_->Channel());
|
||||||
|
auto output_channel = static_cast<size_t>(filter_tensor_->Batch());
|
||||||
|
|
||||||
|
uint8_t per_channel = 0b0;
|
||||||
|
if (conv_quant_arg_->input_arg_num_ != kPerTensor) {
|
||||||
|
MS_CHECK_TRUE(conv_quant_arg_->input_arg_num_ == input_channel,
|
||||||
|
"input per channel quant param length is not equal to input channel.");
|
||||||
|
per_channel = per_channel | INPUT_PER_CHANNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conv_quant_arg_->filter_arg_num_ != kPerTensor) {
|
||||||
|
MS_CHECK_TRUE(conv_quant_arg_->filter_arg_num_ == output_channel,
|
||||||
|
"weight per channel quant param length is not equal to filter num.");
|
||||||
|
per_channel = per_channel | FILTER_PER_CHANNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conv_quant_arg_->output_arg_num_ != kPerTensor) {
|
||||||
|
MS_CHECK_TRUE(conv_quant_arg_->output_arg_num_ != output_channel,
|
||||||
|
"output per channel quant param length is not equal to output channel.");
|
||||||
|
per_channel = per_channel | OUTPUT_PER_CHANNEL;
|
||||||
|
}
|
||||||
|
conv_quant_arg_->per_channel_ = per_channel;
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::MallocQuantParam() {
|
||||||
|
conv_quant_arg_ = &conv_param_->conv_quant_arg_;
|
||||||
|
size_t input_arg_num = input_tensor_->quant_params().size();
|
||||||
|
size_t filter_arg_num = filter_tensor_->quant_params().size();
|
||||||
|
size_t output_arg_num = output_tensor_->quant_params().size();
|
||||||
|
conv_quant_arg_->input_arg_num_ = input_arg_num;
|
||||||
|
conv_quant_arg_->filter_arg_num_ = filter_arg_num;
|
||||||
|
conv_quant_arg_->output_arg_num_ = output_arg_num;
|
||||||
|
MallocConvQuantParams(conv_quant_arg_, input_arg_num, filter_arg_num, output_arg_num);
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetInputTensorQuantParam() {
|
||||||
|
size_t in_arg_num = conv_quant_arg_->input_arg_num_;
|
||||||
|
if (in_arg_num == kPerTensor) {
|
||||||
|
QuantArg input_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
conv_quant_arg_->input_quant_args_[0].zp_ = input_quant_arg.zeroPoint;
|
||||||
|
conv_quant_arg_->input_quant_args_[0].scale_ = input_quant_arg.scale;
|
||||||
|
return RET_OK;
|
||||||
|
} else {
|
||||||
|
// per channel
|
||||||
|
MS_LOG(ERROR) << "Not Support Per Channel for input now.";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetFilterTensorQuantParam() {
|
||||||
|
size_t weight_arg_num = conv_quant_arg_->filter_arg_num_;
|
||||||
|
if (weight_arg_num == kPerTensor) {
|
||||||
|
QuantArg weight_quant_arg = filter_tensor_->quant_params().at(0);
|
||||||
|
conv_quant_arg_->filter_quant_args_[0].zp_ = weight_quant_arg.zeroPoint;
|
||||||
|
conv_quant_arg_->filter_quant_args_[0].scale_ = weight_quant_arg.scale;
|
||||||
|
} else {
|
||||||
|
std::vector<QuantArg> weight_quant_arg = filter_tensor_->quant_params();
|
||||||
|
for (int i = 0; i < static_cast<int>(weight_arg_num); ++i) {
|
||||||
|
conv_quant_arg_->filter_quant_args_[i].zp_ = weight_quant_arg[i].zeroPoint;
|
||||||
|
conv_quant_arg_->filter_quant_args_[i].scale_ = weight_quant_arg[i].scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetOutputTensorQuantParam() {
|
||||||
|
size_t out_arg_num = conv_quant_arg_->output_arg_num_;
|
||||||
|
if (out_arg_num == kPerTensor) {
|
||||||
|
QuantArg output_quant_arg = output_tensor_->quant_params().at(0);
|
||||||
|
conv_quant_arg_->output_quant_args_[0].zp_ = output_quant_arg.zeroPoint;
|
||||||
|
conv_quant_arg_->output_quant_args_[0].scale_ = output_quant_arg.scale;
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "Not Support Per Channel for input now.";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetQuantMultiplier() {
|
||||||
|
// now only support weight tensor is per channel, others are per tensor.
|
||||||
|
int weight_arg_num = kPerTensor;
|
||||||
|
if (conv_quant_arg_->per_channel_ & FILTER_PER_CHANNEL) {
|
||||||
|
weight_arg_num = conv_quant_arg_->filter_arg_num_;
|
||||||
|
}
|
||||||
|
conv_quant_arg_->real_multiplier_ = reinterpret_cast<double *>(malloc(weight_arg_num * sizeof(double)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->real_multiplier_);
|
||||||
|
conv_quant_arg_->left_shift_ = reinterpret_cast<int32_t *>(malloc(weight_arg_num * sizeof(int32_t)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->left_shift_);
|
||||||
|
conv_quant_arg_->right_shift_ = reinterpret_cast<int32_t *>(malloc(weight_arg_num * sizeof(int32_t)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->right_shift_);
|
||||||
|
conv_quant_arg_->quant_multiplier_ = reinterpret_cast<int32_t *>(malloc(weight_arg_num * sizeof(int32_t)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->quant_multiplier_);
|
||||||
|
conv_quant_arg_->out_act_min_ = reinterpret_cast<int32_t *>(malloc(sizeof(int32_t)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->out_act_min_);
|
||||||
|
conv_quant_arg_->out_act_max_ = reinterpret_cast<int32_t *>(malloc(sizeof(int32_t)));
|
||||||
|
MS_CHECK_PTR(conv_quant_arg_->out_act_max_);
|
||||||
|
for (int i = 0; i < weight_arg_num; ++i) {
|
||||||
|
const auto in_scale =
|
||||||
|
static_cast<double>(conv_quant_arg_->input_quant_args_[0].scale_ * conv_quant_arg_->filter_quant_args_[i].scale_);
|
||||||
|
double real_multiplier = in_scale / static_cast<double>(conv_quant_arg_->output_quant_args_[0].scale_);
|
||||||
|
conv_quant_arg_->real_multiplier_[i] = real_multiplier;
|
||||||
|
if (conv_quant_arg_->quant_multiplier_mode_ == Method_SinglePrecision) {
|
||||||
|
QuantizeRoundParameterWithSinglePrecision(real_multiplier, &conv_quant_arg_->quant_multiplier_[i],
|
||||||
|
&conv_quant_arg_->left_shift_[i], &conv_quant_arg_->right_shift_[i]);
|
||||||
|
} else if (conv_quant_arg_->quant_multiplier_mode_ == Method_DoublePrecision) {
|
||||||
|
QuantizeRoundParameterWithDoublePrecision(real_multiplier, &conv_quant_arg_->quant_multiplier_[i],
|
||||||
|
&conv_quant_arg_->left_shift_[i], &conv_quant_arg_->right_shift_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::CheckResizeValid() {
|
||||||
|
// ===============check in channel================= //
|
||||||
|
int32_t filter_in_channel = filter_tensor_->Channel();
|
||||||
|
int32_t resize_in_channel = input_tensor_->Channel();
|
||||||
|
MS_CHECK_TRUE(filter_in_channel == resize_in_channel,
|
||||||
|
"Channel of resized input should be equal to in channel of filter.");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetQuantParam() {
|
||||||
|
MS_CHECK_RET_CODE(MallocQuantParam(), "Malloc quant param failed.");
|
||||||
|
MS_CHECK_RET_CODE(SetInputTensorQuantParam(), "Set Input Tensor Quant Param Failed.");
|
||||||
|
MS_CHECK_RET_CODE(SetFilterTensorQuantParam(), "Set Filter Tensor Quant Param Failed.");
|
||||||
|
MS_CHECK_RET_CODE(SetOutputTensorQuantParam(), "Set Output Tensor Quant Param Failed.");
|
||||||
|
MS_CHECK_RET_CODE(SetIfPerChannel(), "Set if per tensor channel failed.");
|
||||||
|
MS_CHECK_RET_CODE(SetQuantMultiplier(), "Set Quant Multiplier Failed.");
|
||||||
|
// now only consider per tensor for output
|
||||||
|
MS_CHECK_PTR(conv_param_->conv_quant_arg_.out_act_min_);
|
||||||
|
MS_CHECK_PTR(conv_param_->conv_quant_arg_.out_act_max_);
|
||||||
|
MS_CHECK_PTR(conv_param_->conv_quant_arg_.output_quant_args_);
|
||||||
|
bool relu = conv_param_->act_type_ == ActType_Relu;
|
||||||
|
bool relu6 = conv_param_->act_type_ == ActType_Relu6;
|
||||||
|
CalculateActivationRangeQuantized(relu, relu6, conv_param_->conv_quant_arg_.output_quant_args_[0].zp_,
|
||||||
|
conv_param_->conv_quant_arg_.output_quant_args_[0].scale_,
|
||||||
|
&conv_param_->conv_quant_arg_.out_act_min_[0],
|
||||||
|
&conv_param_->conv_quant_arg_.out_act_max_[0]);
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::Init() {
|
||||||
|
this->conv_param_ = reinterpret_cast<ConvParameter *>(parameter_);
|
||||||
|
filter_tensor_ = input_tensors_.at(kWeightIndex);
|
||||||
|
MS_CHECK_PTR(filter_tensor_);
|
||||||
|
MS_CHECK_PTR(filter_tensor_->data_c());
|
||||||
|
if (input_tensors_.size() == kInputSize2) {
|
||||||
|
bias_tensor_ = input_tensors_.at(kBiasIndex);
|
||||||
|
MS_CHECK_PTR(bias_tensor_);
|
||||||
|
MS_CHECK_PTR(bias_tensor_->data_c());
|
||||||
|
} else {
|
||||||
|
MS_CHECK_TRUE(input_tensors_.size() == kInputSize1, "wrong input size");
|
||||||
|
}
|
||||||
|
|
||||||
|
conv_param_->input_batch_ = input_tensor_->Batch();
|
||||||
|
conv_param_->input_h_ = input_tensor_->Height();
|
||||||
|
conv_param_->input_w_ = input_tensor_->Width();
|
||||||
|
conv_param_->input_channel_ = input_tensor_->Channel();
|
||||||
|
conv_param_->output_batch_ = output_tensor_->Batch();
|
||||||
|
conv_param_->output_h_ = output_tensor_->Height();
|
||||||
|
conv_param_->output_w_ = output_tensor_->Width();
|
||||||
|
conv_param_->output_channel_ = output_tensor_->Channel();
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::CheckLayout(lite::Tensor *input_tensor) {
|
||||||
|
mindspore::TypeId data_type = input_tensor->data_type();
|
||||||
|
schema::Format input_format = input_tensor->format();
|
||||||
|
schema::Format execute_format = schema::Format_NHWC4;
|
||||||
|
convert_func_ = LayoutTransform(data_type, input_format, execute_format);
|
||||||
|
MS_CHECK_TRUE(!convert_func_.empty(), "layout convert func is nullptr.");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_CONV2D_BASE_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_CONV2D_BASE_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "src/runtime/kernel/arm/base/layout_transform.h"
|
||||||
|
#include "nnacl/conv_parameter.h"
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
class Conv2DBaseCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
Conv2DBaseCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~Conv2DBaseCoder() override {
|
||||||
|
if (conv_quant_arg_ == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(conv_quant_arg_->real_multiplier_);
|
||||||
|
free(conv_quant_arg_->left_shift_);
|
||||||
|
free(conv_quant_arg_->right_shift_);
|
||||||
|
free(conv_quant_arg_->quant_multiplier_);
|
||||||
|
free(conv_quant_arg_->out_act_min_);
|
||||||
|
free(conv_quant_arg_->out_act_max_);
|
||||||
|
free(conv_quant_arg_->input_quant_args_);
|
||||||
|
free(conv_quant_arg_->filter_quant_args_);
|
||||||
|
free(conv_quant_arg_->output_quant_args_);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int Init();
|
||||||
|
|
||||||
|
int SetQuantParam();
|
||||||
|
|
||||||
|
int MallocQuantParam();
|
||||||
|
|
||||||
|
int SetInputTensorQuantParam();
|
||||||
|
|
||||||
|
int SetFilterTensorQuantParam();
|
||||||
|
|
||||||
|
int SetOutputTensorQuantParam();
|
||||||
|
|
||||||
|
int SetQuantMultiplier();
|
||||||
|
|
||||||
|
int CheckResizeValid();
|
||||||
|
|
||||||
|
int SetIfPerChannel();
|
||||||
|
|
||||||
|
int CheckLayout(lite::Tensor *input_tensor);
|
||||||
|
|
||||||
|
string LayoutTransformFp32(schema::Format src_format, schema::Format dst_format);
|
||||||
|
|
||||||
|
string LayoutTransformInt8(schema::Format src_format, schema::Format dst_format);
|
||||||
|
|
||||||
|
string LayoutTransform(TypeId data_type, schema::Format src_format, schema::Format dst_format);
|
||||||
|
|
||||||
|
ConvParameter *conv_param_{nullptr};
|
||||||
|
|
||||||
|
ConvQuantArg *conv_quant_arg_{nullptr};
|
||||||
|
|
||||||
|
Tensor *filter_tensor_{nullptr};
|
||||||
|
|
||||||
|
Tensor *bias_tensor_{nullptr};
|
||||||
|
|
||||||
|
string convert_func_;
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_CONV2D_BASE_CODER_H_
|
|
@ -0,0 +1,95 @@
|
||||||
|
/**
|
||||||
|
* 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 <string>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
#include "micro/coder/opcoders/base/dtype_cast_coder.h"
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Cast;
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
int DTypeCastCoder::Prepare(CoderContext *const context) {
|
||||||
|
data_num_ = input_tensor_->ElementsNum();
|
||||||
|
if (data_num_ == 0) {
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
int thread_num = MSMIN(thread_num_, static_cast<int>(data_num_));
|
||||||
|
MS_CHECK_TRUE(thread_num > 0, "thread_num <= 0");
|
||||||
|
stride_ = UP_DIV(data_num_, thread_num);
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DTypeCastCoder::DoCode(CoderContext *const context) {
|
||||||
|
int task_id = 0;
|
||||||
|
int data_num = MSMIN(stride_, data_num_ - task_id * stride_);
|
||||||
|
if (data_num <= 0) {
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
TypeId input_data_type = input_tensor_->data_type();
|
||||||
|
TypeId output_data_type = output_tensor_->data_type();
|
||||||
|
|
||||||
|
std::vector<std::string> asmFiles;
|
||||||
|
if (target_ == kARM32A) {
|
||||||
|
asmFiles = {"nnacl/assembly/arm32/PostFuncBiasReluC8.S", "nnacl/assembly/arm32/PostFuncBiasReluC4.S"};
|
||||||
|
} else if (target_ == kARM64) {
|
||||||
|
asmFiles = {"nnacl/assembly/arm64/PostFuncBiasReluC8.S", "nnacl/assembly/arm64/PostFuncBiasReluC4.S"};
|
||||||
|
}
|
||||||
|
Collect(context, {"nnacl/fp32/cast.h"}, {"nnacl/fp32/cast.c", "nnacl/fp32/common_func.c"}, asmFiles);
|
||||||
|
Serializer code;
|
||||||
|
if (output_data_type != kNumberTypeFloat32) {
|
||||||
|
if (input_data_type == kNumberTypeFloat32 && output_data_type == kNumberTypeInt32) {
|
||||||
|
std::string input_str = allocator_->GetRuntimeAddr(input_tensor_);
|
||||||
|
std::string output_str = allocator_->GetRuntimeAddr(output_tensor_);
|
||||||
|
code << "\t\tfor (int i = 0; i < " << data_num << "; ++i) {\n";
|
||||||
|
code << "\t\t\t(" << output_str << ")[i] = (" << input_str << ")[i];\n";
|
||||||
|
code << "\t\t}\n";
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
} else if (input_data_type != kNumberTypeFloat32 && output_data_type == kNumberTypeInt32) {
|
||||||
|
code.CodeFunction("Float32ToInt32", input_tensor_, output_tensor_, data_num);
|
||||||
|
} else if (input_data_type == kNumberTypeFloat32 && output_data_type == kNumberTypeFloat16) {
|
||||||
|
code.CodeFunction("Float32ToFp16", input_tensor_, output_tensor_, data_num);
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "Unsupported datatype from " << input_data_type << " to " << output_data_type;
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (input_data_type) {
|
||||||
|
case kNumberTypeUInt8:
|
||||||
|
code.CodeFunction("Uint8ToFloat32", input_tensor_, output_tensor_, data_num);
|
||||||
|
break;
|
||||||
|
case kNumberTypeInt32:
|
||||||
|
code.CodeFunction("Int32ToFloat32", input_tensor_, output_tensor_, data_num);
|
||||||
|
break;
|
||||||
|
case kNumberTypeFloat16:
|
||||||
|
code.CodeFunction("Fp16ToFloat32", input_tensor_, output_tensor_, data_num);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MS_LOG(ERROR) << "Unsupported input data type " << input_data_type;
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeFloat32, PrimitiveType_Cast, CPUOpCoderCreator<DTypeCastCoder>)
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeInt8, PrimitiveType_Cast, CPUOpCoderCreator<DTypeCastCoder>)
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeUInt8, PrimitiveType_Cast, CPUOpCoderCreator<DTypeCastCoder>)
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeInt32, PrimitiveType_Cast, CPUOpCoderCreator<DTypeCastCoder>)
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_DTYPE_CAST_CODER_H
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_DTYPE_CAST_CODER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/int8/quant_dtype_cast_int8.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
class DTypeCastCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
DTypeCastCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~DTypeCastCoder() override = default;
|
||||||
|
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t stride_{0};
|
||||||
|
uint32_t data_num_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_DTYPE_CAST_CODER_H
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/base/full_connection_base_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
FullConnectionBaseCoder::~FullConnectionBaseCoder() { fc_param_ = nullptr; }
|
||||||
|
|
||||||
|
int FullConnectionBaseCoder::Init() {
|
||||||
|
this->fc_param_ = reinterpret_cast<MatMulParameter *>(parameter_);
|
||||||
|
filter_tensor_ = input_tensors_.at(kWeightIndex);
|
||||||
|
MS_CHECK_PTR(filter_tensor_);
|
||||||
|
if (input_tensors_.size() == kInputSize2) {
|
||||||
|
bias_tensor_ = input_tensors_.at(kBiasIndex);
|
||||||
|
MS_CHECK_PTR(bias_tensor_);
|
||||||
|
MS_CHECK_PTR(bias_tensor_->data_c());
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_FULLY_CONNECTED_BASE_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_FULLY_CONNECTED_BASE_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/matmul_parameter.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
class FullConnectionBaseCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
FullConnectionBaseCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~FullConnectionBaseCoder() override;
|
||||||
|
int Init();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MatMulParameter *fc_param_{nullptr};
|
||||||
|
Tensor *filter_tensor_{nullptr};
|
||||||
|
Tensor *bias_tensor_{nullptr};
|
||||||
|
int thread_count_{0};
|
||||||
|
int thread_stride_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_FULLY_CONNECTED_BASE_CODER_H_
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* 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 <string>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
#include "micro/coder/opcoders/base/quant_dtype_cast_coder.h"
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_QuantDTypeCast;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
int QuantDTypeCastCoder::Prepare(CoderContext *const context) {
|
||||||
|
this->cast_param_ = reinterpret_cast<QuantDTypeCastParameter *>(parameter_);
|
||||||
|
|
||||||
|
if (cast_param_->srcT == kNumberTypeFloat32 && cast_param_->dstT == kNumberTypeInt8) {
|
||||||
|
if (input_tensor_->data_type() != kNumberTypeFloat32 || output_tensor_->data_type() != kNumberTypeInt8) {
|
||||||
|
MS_LOG(ERROR) << "cast_param_ data type and tensor data type do not match.";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
inverse_ = false;
|
||||||
|
} else if (cast_param_->srcT == kNumberTypeInt8 && cast_param_->dstT == kNumberTypeFloat32) {
|
||||||
|
if (input_tensor_->data_type() != kNumberTypeInt8 || output_tensor_->data_type() != kNumberTypeFloat32) {
|
||||||
|
MS_LOG(ERROR) << "cast_param_ data type and tensor data type do not match.";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
inverse_ = true;
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "cast_param_ data type not supported:"
|
||||||
|
<< " src: " << cast_param_->srcT << " dst: " << cast_param_->dstT;
|
||||||
|
return RET_PARAM_INVALID;
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QuantDTypeCastCoder::DoCode(CoderContext *const context) {
|
||||||
|
// get quant params
|
||||||
|
QuantArg in_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
|
||||||
|
// single thread for now
|
||||||
|
int num_unit_thread = input_tensor_->ElementsNum();
|
||||||
|
|
||||||
|
// generate code .h .c
|
||||||
|
Collect(context, {"nnacl/int8/quant_dtype_cast_int8.h"}, {"quant_dtype_cast_int8.c"});
|
||||||
|
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
std::string function = inverse_ ? "DoDequantizeInt8ToFp32" : "DoQuantizeFp32ToInt8";
|
||||||
|
code.CodeFunction(function, input_tensor_, output_tensor_, in_quant_arg.scale, in_quant_arg.zeroPoint,
|
||||||
|
num_unit_thread);
|
||||||
|
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeFloat32, PrimitiveType_QuantDTypeCast,
|
||||||
|
CPUOpCoderCreator<QuantDTypeCastCoder>)
|
||||||
|
REG_OPERATOR_CODER(kAllTargets, kNumberTypeInt8, PrimitiveType_QuantDTypeCast, CPUOpCoderCreator<QuantDTypeCastCoder>)
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_QUANT_DTYPE_CAST_CODER_H
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_QUANT_DTYPE_CAST_CODER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/int8/quant_dtype_cast_int8.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
class QuantDTypeCastCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
QuantDTypeCastCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~QuantDTypeCastCoder() override = default;
|
||||||
|
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QuantDTypeCastParameter *cast_param_{nullptr};
|
||||||
|
std::vector<Tensor *> inputs_;
|
||||||
|
std::vector<Tensor *> outputs_;
|
||||||
|
bool inverse_{false};
|
||||||
|
int thread_num_{0};
|
||||||
|
int thread_n_num_{0};
|
||||||
|
int thread_n_stride_{0};
|
||||||
|
int num_unit_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_QUANT_DTYPE_CAST_CODER_H
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/base/reduce_base_coder.h"
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
namespace {
|
||||||
|
constexpr size_t kInputNum = 1;
|
||||||
|
constexpr size_t kOutputNum = 1;
|
||||||
|
} // namespace
|
||||||
|
int ReduceBaseCoder::CheckInputsOutputs() {
|
||||||
|
if (input_tensors_.size() < kInputNum) {
|
||||||
|
MS_LOG(ERROR) << "Reduce inputs size should be at least " << kInputNum << " but got " << input_tensors_.size();
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
if (output_tensors_.size() != kOutputNum) {
|
||||||
|
MS_LOG(ERROR) << "Reduce outputs size should be " << kOutputNum << " but got " << output_tensors_.size();
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReduceBaseCoder::CheckParameters() {
|
||||||
|
size_t input_rank = input_tensor_->shape().size();
|
||||||
|
if (static_cast<size_t>(num_axes_) > input_rank) {
|
||||||
|
MS_LOG(ERROR) << "Reduce op invalid num of reduce axes " << num_axes_ << " larger than input rank " << input_rank;
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = 0; i < num_axes_; i++) {
|
||||||
|
if (axes_[i] < -static_cast<int>(input_rank) || axes_[i] >= static_cast<int>(input_rank)) {
|
||||||
|
MS_LOG(ERROR) << "Reduce got invalid axis " << axes_[i] << ", axis should be in ["
|
||||||
|
<< -static_cast<int>(input_rank) << ", " << input_rank - 1 << "].";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
if (axes_[i] < 0) {
|
||||||
|
axes_[i] += static_cast<int>(input_rank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reduce_to_end_) {
|
||||||
|
// actual num of axes to reduce
|
||||||
|
num_axes_ = static_cast<int>(input_rank) - axes_[0];
|
||||||
|
MS_CHECK_TRUE(num_axes_ <= MAX_SHAPE_SIZE, "invalid num_axes_, greater than 8.");
|
||||||
|
for (auto i = 1; i < num_axes_; ++i) {
|
||||||
|
axes_[i] = axes_[0] + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_axes_ == 0) {
|
||||||
|
for (size_t i = 0; i < input_rank; i++) {
|
||||||
|
axes_[i] = i;
|
||||||
|
}
|
||||||
|
num_axes_ = static_cast<int>(input_rank);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReduceBaseCoder::Init() {
|
||||||
|
auto reduce_param = reinterpret_cast<ReduceParameter *>(parameter_);
|
||||||
|
if (reduce_param == nullptr) {
|
||||||
|
return RET_NULL_PTR;
|
||||||
|
}
|
||||||
|
if (input_tensors_.size() > 1) {
|
||||||
|
Tensor *axes_ptr = input_tensors_.at(1);
|
||||||
|
num_axes_ = axes_ptr->ElementsNum();
|
||||||
|
MS_CHECK_PTR(axes_ptr->MutableData());
|
||||||
|
MS_CHECK_RET_CODE(memcpy_s(axes_, sizeof(axes_), axes_ptr->MutableData(), axes_ptr->Size()), "memcpy_s failed");
|
||||||
|
} else {
|
||||||
|
num_axes_ = reduce_param->num_axes_;
|
||||||
|
MS_CHECK_RET_CODE(memcpy_s(axes_, sizeof(axes_), reduce_param->axes_, sizeof(reduce_param->axes_)),
|
||||||
|
"memcpy_s failed!");
|
||||||
|
}
|
||||||
|
mode_ = reduce_param->mode_;
|
||||||
|
MS_CHECK_RET_CODE(memcpy_s(axes_, sizeof(axes_), reduce_param->axes_, sizeof(reduce_param->axes_)),
|
||||||
|
"memcpy_s failed!");
|
||||||
|
reduce_to_end_ = reduce_param->reduce_to_end_;
|
||||||
|
MS_CHECK_RET_CODE(CheckInputsOutputs(), "CheckInputsOutputs failed!");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReduceBaseCoder::CalculateInnerOuterSize() {
|
||||||
|
outer_sizes_.clear();
|
||||||
|
inner_sizes_.clear();
|
||||||
|
axis_sizes_.clear();
|
||||||
|
std::vector<int> tmp_shape = input_tensors_.at(0)->shape();
|
||||||
|
for (int i = 0; i < num_axes_; ++i) {
|
||||||
|
int axis = axes_[i];
|
||||||
|
int outer_size = 1;
|
||||||
|
for (int j = 0; j < axis; j++) {
|
||||||
|
outer_size *= tmp_shape.at(j);
|
||||||
|
}
|
||||||
|
outer_sizes_.emplace_back(outer_size);
|
||||||
|
int inner_size = 1;
|
||||||
|
for (int k = axis + 1; k < static_cast<int>(tmp_shape.size()); k++) {
|
||||||
|
inner_size *= tmp_shape.at(k);
|
||||||
|
}
|
||||||
|
inner_sizes_.emplace_back(inner_size);
|
||||||
|
axis_sizes_.emplace_back(tmp_shape[axis]);
|
||||||
|
tmp_shape[axis] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReduceBaseCoder::CalculateTmpBufferSize() {
|
||||||
|
buffer_sizes_.clear();
|
||||||
|
std::vector<int> input_shape = input_tensor_->shape();
|
||||||
|
for (int i = 0; i < num_axes_; i++) {
|
||||||
|
int axis = axes_[i];
|
||||||
|
size_t size = 1;
|
||||||
|
for (int j = 0; j < static_cast<int>(input_shape.size()); j++) {
|
||||||
|
if (axis != j) {
|
||||||
|
size *= input_shape.at(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer_sizes_.emplace_back(size);
|
||||||
|
input_shape[axis] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ReduceBaseCoder::ReSize() {
|
||||||
|
int ret = CheckParameters();
|
||||||
|
if (ret != RET_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
CalculateTmpBufferSize();
|
||||||
|
CalculateInnerOuterSize();
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_REDUCE_BASE_CODER_H
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_REDUCE_BASE_CODER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/reduce_parameter.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
class ReduceBaseCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
ReduceBaseCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~ReduceBaseCoder() override = default;
|
||||||
|
|
||||||
|
int Init();
|
||||||
|
virtual int ReSize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int CheckInputsOutputs();
|
||||||
|
int CheckParameters();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int axes_[MAX_SHAPE_SIZE]{};
|
||||||
|
int num_axes_{0};
|
||||||
|
int mode_{0};
|
||||||
|
bool reduce_to_end_{false};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void CalculateTmpBufferSize();
|
||||||
|
void CalculateInnerOuterSize();
|
||||||
|
std::vector<size_t> buffer_sizes_;
|
||||||
|
std::vector<int> outer_sizes_;
|
||||||
|
std::vector<int> inner_sizes_;
|
||||||
|
std::vector<int> axis_sizes_;
|
||||||
|
int outer_size_{0};
|
||||||
|
int inner_size_{0};
|
||||||
|
int axis_size_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_REDUCE_BASE_CODER_H
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/base/softmax_base_coder.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
int SoftmaxBaseCoder::Init() {
|
||||||
|
this->softmax_param_ = reinterpret_cast<SoftmaxParameter *>(parameter_);
|
||||||
|
std::vector<int> in_shape = input_tensor_->shape();
|
||||||
|
size_t in_dims = in_shape.size();
|
||||||
|
MS_CHECK_TRUE(in_dims < std::extent<decltype(softmax_param_->input_shape_)>::value,
|
||||||
|
"in_dims should be less than input_shape_ size");
|
||||||
|
int ele_size = 1;
|
||||||
|
softmax_param_->n_dim_ = in_dims;
|
||||||
|
for (int i = 0; i < static_cast<int>(in_dims); i++) {
|
||||||
|
softmax_param_->input_shape_[i] = in_shape.at(i);
|
||||||
|
ele_size *= in_shape.at(i);
|
||||||
|
}
|
||||||
|
softmax_param_->element_size_ = ele_size;
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SoftmaxBaseCoder::ReSize() {
|
||||||
|
std::vector<int> in_shape = input_tensor_->shape();
|
||||||
|
size_t in_dims = in_shape.size();
|
||||||
|
MS_CHECK_TRUE(in_dims < std::extent<decltype(softmax_param_->input_shape_)>::value,
|
||||||
|
"in_dims should be less than input_shape_ size");
|
||||||
|
int ele_size = 1;
|
||||||
|
softmax_param_->n_dim_ = in_dims;
|
||||||
|
if (softmax_param_->axis_ == -1) {
|
||||||
|
softmax_param_->axis_ += in_dims;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < in_dims; i++) {
|
||||||
|
softmax_param_->input_shape_[i] = in_shape.at(i);
|
||||||
|
ele_size *= in_shape.at(i);
|
||||||
|
}
|
||||||
|
softmax_param_->element_size_ = ele_size;
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_SOFTMAX_BASE_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_SOFTMAX_BASE_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/softmax_parameter.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
class SoftmaxBaseCoder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
SoftmaxBaseCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~SoftmaxBaseCoder() override { softmax_param_ = nullptr; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int Init();
|
||||||
|
|
||||||
|
int ReSize();
|
||||||
|
|
||||||
|
SoftmaxParameter *softmax_param_{nullptr};
|
||||||
|
|
||||||
|
int thread_count_{0};
|
||||||
|
|
||||||
|
SoftmaxQuantArg quant_params_{};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_BASE_SOFTMAX_BASE_CODER_H_
|
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/add_int8_coder.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "nnacl/arithmetic.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
#include "micro/coder/log.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Add;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int AddInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
input1_ = input_tensors_.at(0);
|
||||||
|
input2 = input_tensors_.at(1);
|
||||||
|
|
||||||
|
MS_CHECK_PTR(input1_);
|
||||||
|
MS_CHECK_PTR(input2);
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(!input1_->quant_params().empty(), "input1_ quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!input2->quant_params().empty(), "input2_ quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!output_tensor_->quant_params().empty(), "output quant_params is empty");
|
||||||
|
|
||||||
|
input_1_offset_ = -input1_->quant_params().at(0).zeroPoint;
|
||||||
|
input_2_offset_ = -input2->quant_params().at(0).zeroPoint;
|
||||||
|
out_offset_ = output_tensor_->quant_params().at(0).zeroPoint;
|
||||||
|
const double input1_scale = input1_->quant_params().at(0).scale;
|
||||||
|
const double input2_scale = input2->quant_params().at(0).scale;
|
||||||
|
const double output_scale = output_tensor_->quant_params().at(0).scale;
|
||||||
|
left_shift_ = 20;
|
||||||
|
const double twice_max_input_scale = 2 * std::max(input1_scale, input2_scale);
|
||||||
|
const double real_input1_multiplier = static_cast<double>(input1_scale) / twice_max_input_scale;
|
||||||
|
const double real_input2_multiplier = static_cast<double>(input2_scale) / twice_max_input_scale;
|
||||||
|
const double real_output_multiplier =
|
||||||
|
twice_max_input_scale / ((1 << static_cast<size_t>(left_shift_)) * static_cast<double>(output_scale));
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(0 <= real_input1_multiplier && real_input1_multiplier <= 1,
|
||||||
|
"real_input1_multiplier should be in (0, 1)");
|
||||||
|
QuantizeMultiplier(real_input1_multiplier, &input_1_mult_, &input_1_shift_);
|
||||||
|
MS_CHECK_TRUE(0 <= real_input2_multiplier && real_input2_multiplier <= 1,
|
||||||
|
"real_input2_multiplier should be in (0, 1)");
|
||||||
|
QuantizeMultiplier(real_input2_multiplier, &input_2_mult_, &input_2_shift_);
|
||||||
|
MS_CHECK_TRUE(0 <= real_output_multiplier && real_output_multiplier <= 1,
|
||||||
|
"real_output_multiplier should be in (0, 1)");
|
||||||
|
QuantizeMultiplier(real_output_multiplier, &out_mult_, &out_shift_);
|
||||||
|
|
||||||
|
out_activation_min_ = std::numeric_limits<int8_t>::min();
|
||||||
|
out_activation_max_ = std::numeric_limits<int8_t>::max();
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(input1_->ElementsNum() == input2->ElementsNum(), "tensor length not match");
|
||||||
|
|
||||||
|
block_size_ = input1_->ElementsNum();
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AddInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
Collect(context, {"CMSIS/NN/Include/arm_nnfunctions.h"}, {"arm_elementwise_add_s8.c"});
|
||||||
|
|
||||||
|
code.CodeFunction("arm_elementwise_add_s8", input1_, input2, input_1_offset_, input_1_mult_, input_1_shift_,
|
||||||
|
input_2_offset_, input_2_mult_, input_2_shift_, left_shift_, output_tensor_, out_offset_, out_mult_,
|
||||||
|
out_shift_, out_activation_min_, out_activation_max_, block_size_);
|
||||||
|
|
||||||
|
MS_LOG(INFO) << "AddInt8Coder has been called";
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_Add, CPUOpCoderCreator<AddInt8Coder>)
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,56 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_ADD_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_ADD_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
class AddInt8Coder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
AddInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~AddInt8Coder() override = default;
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tensor *input1_{nullptr};
|
||||||
|
Tensor *input2{nullptr};
|
||||||
|
|
||||||
|
int32_t input_1_offset_{0};
|
||||||
|
int32_t input_1_mult_{0};
|
||||||
|
int32_t input_1_shift_{0};
|
||||||
|
int32_t input_2_offset_{0};
|
||||||
|
int32_t input_2_mult_{0};
|
||||||
|
int32_t input_2_shift_{0};
|
||||||
|
int32_t left_shift_{0};
|
||||||
|
int32_t out_offset_{0};
|
||||||
|
int32_t out_mult_{0};
|
||||||
|
int32_t out_shift_{0};
|
||||||
|
int32_t out_activation_min_{0};
|
||||||
|
int32_t out_activation_max_{0};
|
||||||
|
uint32_t block_size_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_ADD_INT8_CODER_H_
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/conv2d_base_coder.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int Conv2DBaseCoder::SetQuantArgs() {
|
||||||
|
int channel = output_tensor_->Channel();
|
||||||
|
size_t channel_data_size = static_cast<size_t>(channel) * sizeof(int32_t);
|
||||||
|
output_mult_ = reinterpret_cast<int32_t *>(malloc(channel_data_size));
|
||||||
|
MS_CHECK_PTR(output_mult_);
|
||||||
|
output_shift_ = reinterpret_cast<int32_t *>(malloc(channel_data_size));
|
||||||
|
MS_CHECK_PTR(output_shift_);
|
||||||
|
|
||||||
|
const ::QuantArg *filter_quant_args = conv_quant_arg_->filter_quant_args_;
|
||||||
|
auto input_scale = static_cast<double>(conv_quant_arg_->input_quant_args_[0].scale_);
|
||||||
|
auto output_scale = static_cast<double>(conv_quant_arg_->output_quant_args_[0].scale_);
|
||||||
|
int32_t significand;
|
||||||
|
int channel_shift;
|
||||||
|
if (conv_quant_arg_->filter_arg_num_ > 1) {
|
||||||
|
for (int i = 0; i < channel; ++i) {
|
||||||
|
// If per-tensor quantization parameter is specified, broadcast it along the
|
||||||
|
// quantization dimension (channels_out).
|
||||||
|
MS_CHECK_TRUE(conv_quant_arg_->filter_arg_num_ == static_cast<size_t>(channel), "quant num not match");
|
||||||
|
const auto filter_scale = static_cast<double>(filter_quant_args[i].scale_);
|
||||||
|
const double effective_output_scale = input_scale * filter_scale / output_scale;
|
||||||
|
QuantizeMultiplier(effective_output_scale, &significand, &channel_shift);
|
||||||
|
output_mult_[i] = significand;
|
||||||
|
output_shift_[i] = channel_shift;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// broadcast multiplier and shift to all array if per-tensor
|
||||||
|
const auto filter_scale = static_cast<double>(filter_quant_args[0].scale_);
|
||||||
|
const double effective_output_scale = input_scale * filter_scale / output_scale;
|
||||||
|
QuantizeMultiplier(effective_output_scale, &significand, &channel_shift);
|
||||||
|
for (int i = 0; i < channel; ++i) {
|
||||||
|
output_mult_[i] = significand;
|
||||||
|
output_shift_[i] = channel_shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_CMSIS_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_CMSIS_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/base/conv2d_base_coder.h"
|
||||||
|
#include "nnacl/conv_parameter.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
class Conv2DBaseCoder : public micro::Conv2DBaseCoder {
|
||||||
|
public:
|
||||||
|
explicit Conv2DBaseCoder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: micro::Conv2DBaseCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~Conv2DBaseCoder() override {
|
||||||
|
free(output_mult_);
|
||||||
|
free(output_shift_);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int SetQuantArgs();
|
||||||
|
|
||||||
|
int32_t *output_mult_{nullptr};
|
||||||
|
int32_t *output_shift_{nullptr};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_CMSIS_CODER_H_
|
|
@ -0,0 +1,163 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/conv2d_int8_coder.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/cmsis-nn/int8/dwconv_int8_coder.h"
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Conv2D;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int Conv2DInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
Conv2DBaseCoder::Init();
|
||||||
|
MS_CHECK_RET_CODE(micro::Conv2DBaseCoder::CheckLayout(input_tensor_), "CheckLayout failed");
|
||||||
|
MS_CHECK_RET_CODE(micro::Conv2DBaseCoder::SetQuantParam(), "SetQuantParam failed");
|
||||||
|
MS_CHECK_RET_CODE(Conv2DBaseCoder::SetQuantArgs(), "SetQuantArgs failed");
|
||||||
|
MS_CHECK_RET_CODE(SetParameters(), "SetParameters failed");
|
||||||
|
CheckSupportOptimize();
|
||||||
|
MS_CHECK_RET_CODE(InitTmpBuffer(), "InitTmpBuffer failed");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
std::vector<string> h_files;
|
||||||
|
std::vector<string> c_files;
|
||||||
|
h_files.emplace_back("CMSIS/NN/Include/arm_nnfunctions.h");
|
||||||
|
string buffer_str = "NULL";
|
||||||
|
if (opt_ != Convolve_1x1_fast) {
|
||||||
|
buffer_str = allocator_->GetRuntimeAddr(buffer_);
|
||||||
|
code << " memset(" << buffer_str << ", 0, " << buffer_size_ << ");\n";
|
||||||
|
}
|
||||||
|
code.CodeArray("output_shift", output_shift_, output_ch_);
|
||||||
|
code.CodeArray("output_mult", output_mult_, output_ch_);
|
||||||
|
switch (opt_) {
|
||||||
|
case Basic:
|
||||||
|
c_files = {"arm_convolve_s8.c", "arm_nn_mat_mult_kernel_s8_s16.c", "arm_q7_to_q15_with_offset.c"};
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_convolve_s8", input_tensor_, input_x_, input_y_, input_ch_, input_batches_, filter_tensor_,
|
||||||
|
output_ch_, kernel_x_, kernel_y_, pad_x_, pad_y_, stride_x_, stride_y_, bias_tensor_,
|
||||||
|
output_tensor_, "output_shift", "output_mult", out_offset_, input_offset_, out_activation_min_,
|
||||||
|
out_activation_max_, output_x_, output_y_, buffer_str);
|
||||||
|
break;
|
||||||
|
case Convolve_1_x_n:
|
||||||
|
c_files = {"arm_convolve_1_x_n_s8.c", "arm_nn_mat_mul_core_1x_s8.c"};
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_convolve_1_x_n_s8", input_tensor_, input_x_, input_ch_, input_batches_, filter_tensor_,
|
||||||
|
output_ch_, kernel_x_, pad_x_, stride_x_, bias_tensor_, output_tensor_, "output_shift",
|
||||||
|
"output_mult", out_offset_, input_offset_, out_activation_min_, out_activation_max_, output_x_,
|
||||||
|
buffer_str);
|
||||||
|
break;
|
||||||
|
case Convolve_1x1_fast:
|
||||||
|
c_files = {"arm_convolve_1x1_s8_fast.c", "arm_nn_mat_mult_nt_t_s8.c", "arm_nn_mat_mul_core_4x_s8.c",
|
||||||
|
"arm_nn_mat_mul_core_1x_s8.c"};
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_convolve_1x1_s8_fast", input_tensor_, input_x_, input_y_, input_ch_, input_batches_,
|
||||||
|
filter_tensor_, output_ch_, pad_x_, pad_y_, stride_x_, stride_y_, bias_tensor_, output_tensor_,
|
||||||
|
"output_shift", "output_mult", out_offset_, input_offset_, out_activation_min_,
|
||||||
|
out_activation_max_, output_x_, output_y_, buffer_str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MS_LOG(ERROR) << "opt enum value is not defined";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DInt8Coder::SetParameters() {
|
||||||
|
MS_CHECK_TRUE(input_tensor_->Channel() == filter_tensor_->DimensionSize(3),
|
||||||
|
"input Channel and filter size not match!");
|
||||||
|
MS_CHECK_TRUE(output_tensor_->Channel() == filter_tensor_->DimensionSize(0),
|
||||||
|
"output Channel and filter size not match!");
|
||||||
|
|
||||||
|
input_x_ = input_tensor_->Width();
|
||||||
|
input_y_ = input_tensor_->Height();
|
||||||
|
input_ch_ = input_tensor_->Channel();
|
||||||
|
input_batches_ = input_tensor_->Batch();
|
||||||
|
|
||||||
|
kernel_x_ = filter_tensor_->DimensionSize(2);
|
||||||
|
kernel_y_ = filter_tensor_->DimensionSize(1);
|
||||||
|
pad_x_ = conv_param_->pad_l_;
|
||||||
|
pad_y_ = conv_param_->pad_u_;
|
||||||
|
|
||||||
|
stride_x_ = conv_param_->stride_w_;
|
||||||
|
stride_y_ = conv_param_->stride_h_;
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(!input_tensor_->quant_params().empty(), "input quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!output_tensor_->quant_params().empty(), "output quant_params is empty");
|
||||||
|
QuantArg input_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
QuantArg output_quant_arg = output_tensor_->quant_params().at(0);
|
||||||
|
|
||||||
|
input_offset_ = -input_quant_arg.zeroPoint;
|
||||||
|
out_offset_ = output_quant_arg.zeroPoint;
|
||||||
|
|
||||||
|
output_x_ = output_tensor_->DimensionSize(2);
|
||||||
|
output_y_ = output_tensor_->DimensionSize(1);
|
||||||
|
output_ch_ = output_tensor_->Channel();
|
||||||
|
|
||||||
|
CalculateActivationRangeQuantized(conv_param_->act_type_ == ActType_Relu, conv_param_->act_type_ == ActType_Relu6,
|
||||||
|
output_quant_arg.zeroPoint, static_cast<float>(output_quant_arg.scale),
|
||||||
|
&out_activation_min_, &out_activation_max_);
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Conv2DInt8Coder::CheckSupportOptimize() {
|
||||||
|
if ((pad_x_ == 0) && (pad_y_ == 0) && (input_ch_ % 4 == 0) && (stride_x_ == 1) && (stride_y_ == 1) &&
|
||||||
|
(kernel_x_ == 1) && (kernel_y_ == 1)) {
|
||||||
|
opt_ = Convolve_1x1_fast;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((output_x_ == 1) && (input_x_ == 1) && (kernel_y_ == 1) && (output_x_ % 4 == 0) && (input_batches_ == 1)) {
|
||||||
|
opt_ = Convolve_1_x_n;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
opt_ = Basic;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Conv2DInt8Coder::InitTmpBuffer() {
|
||||||
|
switch (opt_) {
|
||||||
|
case Basic:
|
||||||
|
buffer_size_ =
|
||||||
|
(2 * input_tensor_->Channel() * filter_tensor_->Width() * filter_tensor_->Height()) * (int32_t)sizeof(int16_t);
|
||||||
|
break;
|
||||||
|
case Convolve_1_x_n:
|
||||||
|
buffer_size_ =
|
||||||
|
(2 * input_tensor_->Channel() * filter_tensor_->Width() * filter_tensor_->Height()) * sizeof(int16_t);
|
||||||
|
break;
|
||||||
|
case Convolve_1x1_fast:
|
||||||
|
// do nothing
|
||||||
|
buffer_size_ = 0;
|
||||||
|
return RET_OK;
|
||||||
|
default:
|
||||||
|
MS_LOG(ERROR) << "opt enum value is not defined";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
buffer_ = static_cast<int16_t *>(allocator_->Malloc(kNumberTypeInt16, buffer_size_, kWorkspace));
|
||||||
|
MS_CHECK_PTR(buffer_);
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_Conv2D, CPUOpCoderCreator<Conv2DInt8Coder>)
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/cmsis-nn/int8/conv2d_base_coder.h"
|
||||||
|
#include "nnacl/conv_parameter.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
class Conv2DInt8Coder : public Conv2DBaseCoder {
|
||||||
|
public:
|
||||||
|
explicit Conv2DInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: Conv2DBaseCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
int Prepare(CoderContext *context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *ctx) override;
|
||||||
|
|
||||||
|
~Conv2DInt8Coder() override = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum ConvOpt { Basic = 0, Convolve_1_x_n = 1, Convolve_1x1_fast = 2 };
|
||||||
|
|
||||||
|
void CheckSupportOptimize();
|
||||||
|
|
||||||
|
int SetParameters();
|
||||||
|
|
||||||
|
int InitTmpBuffer();
|
||||||
|
|
||||||
|
uint16_t input_x_{0};
|
||||||
|
uint16_t input_y_{0};
|
||||||
|
uint16_t input_ch_{0};
|
||||||
|
uint16_t input_batches_{0};
|
||||||
|
uint16_t output_ch_{0};
|
||||||
|
uint16_t kernel_x_{0};
|
||||||
|
uint16_t kernel_y_{0};
|
||||||
|
uint16_t pad_x_{0};
|
||||||
|
uint16_t pad_y_{0};
|
||||||
|
uint16_t stride_x_{0};
|
||||||
|
uint16_t stride_y_{0};
|
||||||
|
int32_t out_offset_{0};
|
||||||
|
int32_t input_offset_{0};
|
||||||
|
int32_t out_activation_min_{0};
|
||||||
|
int32_t out_activation_max_{0};
|
||||||
|
uint16_t output_x_{0};
|
||||||
|
uint16_t output_y_{0};
|
||||||
|
|
||||||
|
int16_t *buffer_{nullptr};
|
||||||
|
int32_t buffer_size_{0};
|
||||||
|
|
||||||
|
ConvOpt opt_{ConvOpt::Basic};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_CONV2D_INT8_CODER_H_
|
|
@ -0,0 +1,158 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/dwconv_int8_coder.h"
|
||||||
|
#include <string>
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
#include "micro/coder/log.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_DepthwiseConv2D;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int DWConvInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
Conv2DBaseCoder::Init();
|
||||||
|
MS_CHECK_RET_CODE(micro::Conv2DBaseCoder::CheckLayout(input_tensor_), "Check layout failed.");
|
||||||
|
MS_CHECK_RET_CODE(micro::Conv2DBaseCoder::SetQuantParam(), "SetQuantParam failed");
|
||||||
|
MS_CHECK_RET_CODE(Conv2DBaseCoder::SetQuantArgs(), "SetQuantArgs failed");
|
||||||
|
MS_CHECK_RET_CODE(InitWeightBias(), "InitWeightBias failed");
|
||||||
|
MS_CHECK_RET_CODE(SetParameters(), "SetParameters failed");
|
||||||
|
CheckSupportOptimize();
|
||||||
|
MS_CHECK_RET_CODE(InitTmpBuffer(), "InitTmpBuffer failed");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DWConvInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
std::vector<std::string> h_files;
|
||||||
|
std::vector<std::string> c_files;
|
||||||
|
|
||||||
|
h_files.emplace_back("CMSIS/NN/Include/arm_nnfunctions.h");
|
||||||
|
code.CodeArray("output_shift", output_shift_, output_ch_);
|
||||||
|
code.CodeArray("output_mult", output_mult_, output_ch_);
|
||||||
|
switch (optimize_) {
|
||||||
|
case Conv_3x3:
|
||||||
|
c_files.emplace_back("arm_depthwise_conv_3x3_s8.c");
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_depthwise_conv_3x3_s8", input_tensor_, input_x_, input_y_, input_ch_, filter_tensor_,
|
||||||
|
output_ch_, pad_x_, pad_y_, stride_x_, stride_y_, bias_tensor_, output_tensor_, "output_shift",
|
||||||
|
"output_mult", output_x_, output_y_, output_offset_, input_offset_, output_activation_min_,
|
||||||
|
output_activation_max_, dilation_x_, dilation_y_, "NULL");
|
||||||
|
break;
|
||||||
|
case Conv_opt:
|
||||||
|
// arm_depthwise_conv_s8_opt also depends on arm_depthwise_conv_s8
|
||||||
|
c_files.emplace_back("arm_depthwise_conv_s8.c");
|
||||||
|
c_files.emplace_back("arm_depthwise_conv_s8_opt.c");
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_depthwise_conv_s8_opt", input_tensor_, input_x_, input_y_, input_ch_, filter_tensor_,
|
||||||
|
output_ch_, kernel_x_, kernel_y_, pad_x_, pad_y_, stride_x_, stride_y_, bias_tensor_,
|
||||||
|
output_tensor_, "output_shift", "output_mult", output_x_, output_y_, output_offset_,
|
||||||
|
input_offset_, output_activation_min_, output_activation_max_, dilation_x_, dilation_y_,
|
||||||
|
"NULL");
|
||||||
|
break;
|
||||||
|
case Basic:
|
||||||
|
c_files.emplace_back("arm_depthwise_conv_s8.c");
|
||||||
|
Collect(context, h_files, c_files);
|
||||||
|
code.CodeFunction("arm_depthwise_conv_s8", input_tensor_, input_x_, input_y_, input_ch_, filter_tensor_,
|
||||||
|
output_ch_, ch_mult_, kernel_x_, kernel_y_, pad_x_, pad_y_, stride_x_, stride_y_, bias_tensor_,
|
||||||
|
output_tensor_, "output_shift", "output_mult", output_x_, output_y_, output_offset_,
|
||||||
|
input_offset_, output_activation_min_, output_activation_max_, dilation_x_, dilation_y_,
|
||||||
|
"NULL");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MS_LOG(ERROR) << "unsupported optimize_r";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DWConvInt8Coder::InitWeightBias() {
|
||||||
|
auto *origin_weight = reinterpret_cast<int8_t *>(filter_tensor_->data_c());
|
||||||
|
MS_CHECK_PTR(origin_weight);
|
||||||
|
auto pack_weight_size =
|
||||||
|
static_cast<size_t>(filter_tensor_->Batch() * filter_tensor_->Height() * filter_tensor_->Width());
|
||||||
|
packed_weight_ =
|
||||||
|
static_cast<int8_t *>(allocator_->Malloc(kNumberTypeInt8, pack_weight_size * sizeof(int8_t), kOfflinePackWeight));
|
||||||
|
MS_ASSERT(packed_weight_);
|
||||||
|
PackNCHWToNHWCInt8(origin_weight, packed_weight_, 1, filter_tensor_->Height() * filter_tensor_->Width(),
|
||||||
|
filter_tensor_->Batch());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DWConvInt8Coder::SetParameters() {
|
||||||
|
input_x_ = input_tensor_->Width();
|
||||||
|
input_y_ = input_tensor_->Height();
|
||||||
|
input_ch_ = input_tensor_->Channel();
|
||||||
|
output_ch_ = output_tensor_->Channel();
|
||||||
|
|
||||||
|
// depth_multiplier
|
||||||
|
ch_mult_ = output_tensor_->Channel() / input_tensor_->Channel();
|
||||||
|
|
||||||
|
kernel_x_ = filter_tensor_->Width();
|
||||||
|
kernel_y_ = filter_tensor_->Height();
|
||||||
|
|
||||||
|
pad_y_ = conv_param_->pad_u_;
|
||||||
|
pad_x_ = conv_param_->pad_l_;
|
||||||
|
|
||||||
|
stride_y_ = conv_param_->stride_h_;
|
||||||
|
stride_x_ = conv_param_->stride_w_;
|
||||||
|
|
||||||
|
QuantArg input_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
QuantArg output_quant_arg = output_tensor_->quant_params().at(0);
|
||||||
|
|
||||||
|
output_x_ = output_tensor_->Width();
|
||||||
|
output_y_ = output_tensor_->Height();
|
||||||
|
input_offset_ = -input_quant_arg.zeroPoint;
|
||||||
|
output_offset_ = output_quant_arg.zeroPoint;
|
||||||
|
|
||||||
|
CalculateActivationRangeQuantized(conv_param_->act_type_ == ActType_Relu, conv_param_->act_type_ == ActType_Relu6,
|
||||||
|
output_quant_arg.zeroPoint, output_quant_arg.scale, &output_activation_min_,
|
||||||
|
&output_activation_max_);
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DWConvInt8Coder::CheckSupportOptimize() {
|
||||||
|
if (ch_mult_ == 1) {
|
||||||
|
if ((kernel_x_ == 3) && (kernel_y_ == 3) && (pad_y_ <= 1)) {
|
||||||
|
optimize_ = Conv_3x3;
|
||||||
|
buffer_size_ = 0;
|
||||||
|
} else {
|
||||||
|
optimize_ = Conv_opt;
|
||||||
|
buffer_size_ = input_ch_ * kernel_x_ * kernel_y_ * sizeof(int16_t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
optimize_ = Basic;
|
||||||
|
buffer_size_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DWConvInt8Coder::InitTmpBuffer() {
|
||||||
|
if (buffer_size_ != 0) {
|
||||||
|
buffer = static_cast<int16_t *>(allocator_->Malloc(kNumberTypeInt16, buffer_size_, kWorkspace));
|
||||||
|
MS_CHECK_PTR(buffer);
|
||||||
|
} else {
|
||||||
|
buffer = nullptr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_DepthwiseConv2D, CPUOpCoderCreator<DWConvInt8Coder>)
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_DWCONV_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_DWCONV_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/cmsis-nn/int8/conv2d_base_coder.h"
|
||||||
|
#include "src/runtime/kernel/arm/int8/convolution_depthwise_int8.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
class DWConvInt8Coder : public Conv2DBaseCoder {
|
||||||
|
public:
|
||||||
|
DWConvInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: Conv2DBaseCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~DWConvInt8Coder() override = default;
|
||||||
|
|
||||||
|
int Prepare(CoderContext *context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum DwConvOpt {
|
||||||
|
Basic = 0,
|
||||||
|
Conv_3x3 = 1,
|
||||||
|
Conv_opt = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
int SetParameters();
|
||||||
|
|
||||||
|
void CheckSupportOptimize();
|
||||||
|
|
||||||
|
int InitTmpBuffer();
|
||||||
|
|
||||||
|
int InitWeightBias();
|
||||||
|
|
||||||
|
int32_t input_x_{0};
|
||||||
|
int32_t input_y_{0};
|
||||||
|
int32_t input_ch_{0};
|
||||||
|
int32_t output_ch_{0};
|
||||||
|
int32_t ch_mult_{0};
|
||||||
|
int32_t kernel_x_{0};
|
||||||
|
int32_t kernel_y_{0};
|
||||||
|
int32_t pad_x_{0};
|
||||||
|
int32_t pad_y_{0};
|
||||||
|
int32_t stride_x_{0};
|
||||||
|
int32_t stride_y_{0};
|
||||||
|
int32_t output_x_{0};
|
||||||
|
int32_t output_y_{0};
|
||||||
|
int32_t output_offset_{0};
|
||||||
|
int32_t input_offset_{0};
|
||||||
|
int32_t output_activation_min_{0};
|
||||||
|
int32_t output_activation_max_{0};
|
||||||
|
uint16_t dilation_x_{0};
|
||||||
|
uint16_t dilation_y_{0};
|
||||||
|
|
||||||
|
int8_t *packed_weight_{nullptr};
|
||||||
|
DwConvOpt optimize_{Basic};
|
||||||
|
size_t buffer_size_{0};
|
||||||
|
int16_t *buffer{nullptr};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_CMSIS_NN_DWCONV_INT8_CODER_H_
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/fullconnection_int8_coder.h"
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_FullConnection;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int FullConnectionInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
FullConnectionBaseCoder::Init();
|
||||||
|
ConfigInputOutput();
|
||||||
|
MS_CHECK_RET_CODE(SetParameters(), "SetParameters failed");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FullConnectionInt8Coder::ConfigInputOutput() { output_tensor_->set_format(schema::Format_NHWC); }
|
||||||
|
|
||||||
|
int FullConnectionInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
Collect(context, {"CMSIS/NN/Include/arm_nnfunctions.h"}, {"arm_fully_connected_s8.c", "arm_nn_vec_mat_mult_t_s8.c"});
|
||||||
|
|
||||||
|
code.CodeFunction("arm_fully_connected_s8", input_tensor_, filter_tensor_, col_dim_, row_dim_, nb_batches_,
|
||||||
|
input_offset_, filter_offset_, out_multiplier_, out_shift_, output_offset_, bias_tensor_,
|
||||||
|
output_tensor_, output_activation_min_, output_activation_max_, "NULL");
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FullConnectionInt8Coder::SetParameters() {
|
||||||
|
MS_CHECK_TRUE(output_tensor_->shape().size() == 2, "output tensor size should be 2");
|
||||||
|
MS_CHECK_TRUE(!input_tensor_->quant_params().empty(), "input quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!filter_tensor_->quant_params().empty(), "filter quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!output_tensor_->quant_params().empty(), "output quant_params is empty");
|
||||||
|
QuantArg input_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
QuantArg filter_quant_arg = filter_tensor_->quant_params().at(0);
|
||||||
|
QuantArg output_quant_arg = output_tensor_->quant_params().at(0);
|
||||||
|
|
||||||
|
double real_multiplier = input_quant_arg.scale * filter_quant_arg.scale / output_quant_arg.scale;
|
||||||
|
QuantizeMultiplier(real_multiplier, &out_multiplier_, &out_shift_);
|
||||||
|
CalculateActivationRangeQuantized(fc_param_->act_type_ == ActType_Relu, fc_param_->act_type_ == ActType_Relu6,
|
||||||
|
output_quant_arg.zeroPoint, output_quant_arg.scale, &output_activation_min_,
|
||||||
|
&output_activation_max_);
|
||||||
|
|
||||||
|
input_offset_ = -input_quant_arg.zeroPoint;
|
||||||
|
filter_offset_ = -filter_quant_arg.zeroPoint;
|
||||||
|
output_offset_ = output_quant_arg.zeroPoint;
|
||||||
|
|
||||||
|
col_dim_ = filter_tensor_->DimensionSize(filter_tensor_->shape().size() - 1);
|
||||||
|
row_dim_ = output_tensor_->DimensionSize(1);
|
||||||
|
nb_batches_ = input_tensor_->Batch();
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_FullConnection, CPUOpCoderCreator<FullConnectionInt8Coder>)
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_FULLCONNECTION_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_FULLCONNECTION_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "micro/coder/opcoders/base/full_connection_base_coder.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
class FullConnectionInt8Coder : public FullConnectionBaseCoder {
|
||||||
|
public:
|
||||||
|
FullConnectionInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: FullConnectionBaseCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
~FullConnectionInt8Coder() override = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int SetParameters();
|
||||||
|
void ConfigInputOutput();
|
||||||
|
|
||||||
|
uint16_t col_dim_{0};
|
||||||
|
uint16_t row_dim_{0};
|
||||||
|
uint16_t nb_batches_{0};
|
||||||
|
int32_t input_offset_{0};
|
||||||
|
int32_t filter_offset_{0};
|
||||||
|
int32_t out_multiplier_{0};
|
||||||
|
int32_t out_shift_{0};
|
||||||
|
int32_t output_offset_{0};
|
||||||
|
int32_t output_activation_min_{0};
|
||||||
|
int32_t output_activation_max_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_FULLCONNECTION_INT8_CODER_H_
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/mul_int8_coder.h"
|
||||||
|
#include <string>
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "nnacl/int8/quantize.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Mul;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int MulInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
input1_ = OperatorCoder::input_tensors().at(0);
|
||||||
|
input2_ = OperatorCoder::input_tensors().at(1);
|
||||||
|
|
||||||
|
MS_CHECK_PTR(input1_);
|
||||||
|
MS_CHECK_PTR(input2_);
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(!input1_->quant_params().empty(), "input1_ quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!input2_->quant_params().empty(), "input2_ quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!output_tensor_->quant_params().empty(), "output quant_params is empty");
|
||||||
|
|
||||||
|
input_1_offset_ = -input1_->quant_params().at(0).zeroPoint;
|
||||||
|
input_2_offset_ = -input2_->quant_params().at(0).zeroPoint;
|
||||||
|
out_offset_ = output_tensor_->quant_params().at(0).zeroPoint;
|
||||||
|
const double input1_scale = input1_->quant_params().at(0).scale;
|
||||||
|
const double input2_scale = input2_->quant_params().at(0).scale;
|
||||||
|
const double output_scale = output_tensor_->quant_params().at(0).scale;
|
||||||
|
|
||||||
|
const double real_multiplier = input1_scale * input2_scale / output_scale;
|
||||||
|
|
||||||
|
QuantizeMultiplier(real_multiplier, &out_mult_, &out_shift_);
|
||||||
|
|
||||||
|
CalculateActivationRangeQuantized(false, false, out_offset_, output_scale, &out_activation_min_,
|
||||||
|
&out_activation_max_);
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(input1_->ElementsNum() == input2_->ElementsNum(), "tensor length not match");
|
||||||
|
|
||||||
|
block_size_ = input1_->ElementsNum();
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MulInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
Collect(context, {"CMSIS/NN/Include/arm_nnfunctions.h"}, {"arm_elementwise_mul_s8.c"});
|
||||||
|
|
||||||
|
code.CodeFunction("arm_elementwise_mul_s8", input1_, input2_, input_1_offset_, input_2_offset_, output_tensor_,
|
||||||
|
out_offset_, out_mult_, out_shift_, out_activation_min_, out_activation_max_, block_size_);
|
||||||
|
|
||||||
|
MS_LOG(INFO) << "MulInt8Coder has been called";
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_Mul, CPUOpCoderCreator<MulInt8Coder>)
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_MUL_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_MUL_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
class MulInt8Coder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
MulInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
~MulInt8Coder() override = default;
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tensor *input1_{nullptr};
|
||||||
|
Tensor *input2_{nullptr};
|
||||||
|
|
||||||
|
int32_t input_1_offset_{0};
|
||||||
|
int32_t input_2_offset_{0};
|
||||||
|
int32_t out_offset_{0};
|
||||||
|
int32_t out_mult_{0};
|
||||||
|
int32_t out_shift_{0};
|
||||||
|
int32_t out_activation_min_{0};
|
||||||
|
int32_t out_activation_max_{0};
|
||||||
|
uint32_t block_size_{0};
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_MUL_INT8_CODER_H_
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* 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 <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/cmsis-nn/int8/pooling_int8_coder.h"
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Pooling;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
int PoolingInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
this->pooling_parameter_ = reinterpret_cast<PoolingParameter *>(parameter_);
|
||||||
|
// get tensors
|
||||||
|
MS_CHECK_RET_CODE(SetParameters(), "SetParameters failed");
|
||||||
|
|
||||||
|
if (pooling_parameter_->pool_mode_ == PoolMode_AvgPool) {
|
||||||
|
buffer_size_ = input_tensor_->Channel() * sizeof(int32_t);
|
||||||
|
buffer_ = static_cast<int32_t *>(allocator_->Malloc(kNumberTypeInt32, buffer_size_, kWorkspace));
|
||||||
|
MS_CHECK_PTR(buffer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolingInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
// init struct PoolingParameters
|
||||||
|
std::string buffer_str = "NULL";
|
||||||
|
std::string pooling_func;
|
||||||
|
|
||||||
|
std::vector<std::string> cFiles;
|
||||||
|
if (pooling_parameter_->pool_mode_ == PoolMode_AvgPool) {
|
||||||
|
cFiles = {"arm_avgpool_s8.c"};
|
||||||
|
pooling_func = "arm_avgpool_s8";
|
||||||
|
buffer_str = allocator_->GetRuntimeAddr(buffer_);
|
||||||
|
} else if (pooling_parameter_->pool_mode_ == PoolMode_MaxPool) {
|
||||||
|
cFiles = {"arm_max_pool_s8.c"};
|
||||||
|
pooling_func = "arm_max_pool_s8";
|
||||||
|
} else {
|
||||||
|
MS_LOG(ERROR) << "unsupported pad mode";
|
||||||
|
return RET_ERROR;
|
||||||
|
}
|
||||||
|
Collect(context, {"CMSIS/NN/Include/arm_nnfunctions.h"}, cFiles);
|
||||||
|
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
code.CodeFunction(pooling_func, "&nn_context", "&pool_params", "&input_dims", input_tensor_, "&filter_dims",
|
||||||
|
"&output_dims", output_tensor_);
|
||||||
|
code.CodeFunction(pooling_func, dim_src_height_, dim_src_width_, dim_dst_height_, dim_dst_width_, stride_height_,
|
||||||
|
stride_width_, dim_kernel_height_, dim_kernel_width_, padding_height_, padding_width_, act_min_,
|
||||||
|
act_max_, ch_src_, input_tensor_, buffer_str, output_tensor_);
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolingInt8Coder::SetParameters() {
|
||||||
|
dim_src_height_ = input_tensor_->Height();
|
||||||
|
dim_src_width_ = input_tensor_->Width();
|
||||||
|
dim_dst_height_ = output_tensor_->DimensionSize(1);
|
||||||
|
dim_src_width_ = output_tensor_->DimensionSize(2);
|
||||||
|
ch_src_ = input_tensor_->Channel();
|
||||||
|
|
||||||
|
stride_height_ = pooling_parameter_->stride_h_;
|
||||||
|
stride_width_ = pooling_parameter_->stride_w_;
|
||||||
|
|
||||||
|
dim_kernel_height_ = pooling_parameter_->window_h_;
|
||||||
|
dim_kernel_width_ = pooling_parameter_->window_w_;
|
||||||
|
|
||||||
|
// only use pad_u_ and pad_l_ because their value is consistent with tf
|
||||||
|
// ref: mindspore/lite/src/ops/conv2d.cc:ConvInferShape
|
||||||
|
padding_height_ = pooling_parameter_->pad_u_;
|
||||||
|
padding_width_ = pooling_parameter_->pad_l_;
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(!output_tensor_->quant_params().empty(), "output quant_params is empty");
|
||||||
|
QuantArg output_quant_arg = output_tensor_->quant_params().at(0);
|
||||||
|
CalculateActivationRangeQuantized(pooling_parameter_->act_type_ == ActType_Relu,
|
||||||
|
pooling_parameter_->act_type_ == ActType_Relu6, output_quant_arg.zeroPoint,
|
||||||
|
output_quant_arg.scale, &act_min_, &act_max_);
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(input_tensor_->Channel() == output_tensor_->Channel(),
|
||||||
|
"input Channel and output Channel size not match!");
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_Pooling, CPUOpCoderCreator<PoolingInt8Coder>)
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_POOLING_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_POOLING_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
#include "nnacl/int8/pooling_int8.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
class PoolingInt8Coder final : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
PoolingInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
~PoolingInt8Coder() override = default;
|
||||||
|
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int SetParameters();
|
||||||
|
|
||||||
|
int dim_src_height_{0};
|
||||||
|
int dim_src_width_{0};
|
||||||
|
int dim_dst_height_{0};
|
||||||
|
int dim_dst_width_{0};
|
||||||
|
int stride_height_{0};
|
||||||
|
int stride_width_{0};
|
||||||
|
int dim_kernel_height_{0};
|
||||||
|
int dim_kernel_width_{0};
|
||||||
|
int padding_height_{0};
|
||||||
|
int padding_width_{0};
|
||||||
|
int act_min_{0};
|
||||||
|
int act_max_{0};
|
||||||
|
int ch_src_{0};
|
||||||
|
|
||||||
|
int32_t *buffer_{nullptr};
|
||||||
|
size_t buffer_size_{0};
|
||||||
|
PoolingParameter *pooling_parameter_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_POOLING_INT8_CODER_H_
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/reshape_int8_coder.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_Reshape;
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int ReshapeInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
int elements_num = input_tensor_->ElementsNum();
|
||||||
|
|
||||||
|
std::vector<QuantArg> input_quant_args = input_tensor_->quant_params();
|
||||||
|
std::vector<QuantArg> output_quant_args = output_tensor_->quant_params();
|
||||||
|
MS_CHECK_TRUE(!input_quant_args.empty(), "input quant_params is empty");
|
||||||
|
MS_CHECK_TRUE(!output_quant_args.empty(), "output quant_params is empty");
|
||||||
|
// in Int8Reshape, the following values are checked. then it will do a memory copy
|
||||||
|
// para.in_args_.scale_ == para.out_args_.scale_ && para.in_args_.zp_ == para.out_args_.zp_
|
||||||
|
MS_CHECK_TRUE((input_quant_args.at(0).scale == output_quant_args.at(0).scale &&
|
||||||
|
input_quant_args.at(0).zeroPoint == output_quant_args.at(0).zeroPoint),
|
||||||
|
"the quant arg of input and output should be the same!");
|
||||||
|
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
code.CodeFunction("memcpy", output_tensor_, input_tensor_, elements_num);
|
||||||
|
|
||||||
|
MS_LOG(INFO) << "ReshapeInt8Coder has been called";
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_Reshape, CPUOpCoderCreator<ReshapeInt8Coder>)
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_RESHAPE_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_RESHAPE_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/op_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
class ReshapeInt8Coder : public OperatorCoder {
|
||||||
|
public:
|
||||||
|
ReshapeInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: OperatorCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~ReshapeInt8Coder() override = default;
|
||||||
|
int Prepare(CoderContext *const context) override { return RET_OK; }
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_RESHAPE_INT8_CODER_H_
|
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* 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 "micro/coder/opcoders/cmsis-nn/int8/softmax_int8_coder.h"
|
||||||
|
#include <limits>
|
||||||
|
#include "micro/coder/opcoders/serializers/serializer.h"
|
||||||
|
#include "micro/coder/opcoders/file_collector.h"
|
||||||
|
|
||||||
|
using mindspore::schema::PrimitiveType_SoftMax;
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
int SoftMaxInt8Coder::Prepare(CoderContext *const context) {
|
||||||
|
SoftmaxBaseCoder::Init();
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(!input_tensor_->quant_params().empty(), "input quant_params is empty");
|
||||||
|
QuantArg in_quant_arg = input_tensor_->quant_params().at(0);
|
||||||
|
quant_params_.in_quant_args_.zp_ = -in_quant_arg.zeroPoint;
|
||||||
|
|
||||||
|
std::vector<QuantArg> out_quant_args = output_tensor_->quant_params();
|
||||||
|
MS_CHECK_TRUE(!out_quant_args.empty(), "output quant_params is empty");
|
||||||
|
quant_params_.out_quant_arg_.scale_ = static_cast<float>(out_quant_args.at(0).scale);
|
||||||
|
quant_params_.out_quant_arg_.zp_ = out_quant_args.at(0).zeroPoint;
|
||||||
|
quant_params_.output_activation_min_ = std::numeric_limits<int8_t>::min();
|
||||||
|
quant_params_.output_activation_max_ = std::numeric_limits<int8_t>::max();
|
||||||
|
|
||||||
|
const int total_signed_bits = 31;
|
||||||
|
const int input_integer_bits = 5;
|
||||||
|
const double input_real_multiplier =
|
||||||
|
MSMIN(in_quant_arg.scale * (1 << (unsigned int)(total_signed_bits - input_integer_bits)),
|
||||||
|
(1ll << total_signed_bits) - 1.0);
|
||||||
|
// mult, shift
|
||||||
|
QuantizeMultiplier(input_real_multiplier, &mult_, &shift_);
|
||||||
|
// Calculate Input Radius
|
||||||
|
const double max_input_rescaled = 1.0 * ((1 << input_integer_bits) - 1) *
|
||||||
|
(1ll << static_cast<size_t>((total_signed_bits - input_integer_bits))) /
|
||||||
|
(1ll << static_cast<size_t>(shift_));
|
||||||
|
diff_min_ = -1.0 * static_cast<int>(std::floor(max_input_rescaled));
|
||||||
|
|
||||||
|
const int trailing_dim = static_cast<int>(input_tensor_->shape().size()) - 1;
|
||||||
|
const int dims_count = input_tensor_->shape().size();
|
||||||
|
MS_CHECK_TRUE(0 <= trailing_dim && trailing_dim < dims_count, "trailing_dim should be in [0, dims_count)");
|
||||||
|
num_rows_ = 1;
|
||||||
|
for (int i = 0; i < dims_count; ++i) {
|
||||||
|
num_rows_ *= (i == trailing_dim) ? 1 : input_tensor_->DimensionSize(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MS_CHECK_TRUE(input_tensor_->DimensionSize(trailing_dim) == output_tensor_->DimensionSize(trailing_dim),
|
||||||
|
"input and output DimensionSize mismatch");
|
||||||
|
row_size_ = input_tensor_->DimensionSize(trailing_dim);
|
||||||
|
|
||||||
|
ReSize();
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SoftMaxInt8Coder::DoCode(CoderContext *const context) {
|
||||||
|
Serializer code;
|
||||||
|
code.precision(kPrecision);
|
||||||
|
|
||||||
|
Collect(context, {"CMSIS/NN/Include/arm_nnfunctions.h"}, {"arm_softmax_s8.c"});
|
||||||
|
code.CodeFunction("arm_softmax_s8", input_tensor_, num_rows_, row_size_, mult_, shift_, diff_min_, output_tensor_);
|
||||||
|
|
||||||
|
MS_LOG(INFO) << "SoftMaxInt8Coder has been called";
|
||||||
|
context->AppendCode(code.str());
|
||||||
|
return RET_OK;
|
||||||
|
}
|
||||||
|
REG_OPERATOR_CODER(kARM32M, kNumberTypeInt8, PrimitiveType_SoftMax, CPUOpCoderCreator<SoftMaxInt8Coder>)
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
|
@ -0,0 +1,49 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_SOFTMAX_INT8_CODER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_SOFTMAX_INT8_CODER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include "micro/coder/opcoders/base/softmax_base_coder.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro::cmsis {
|
||||||
|
|
||||||
|
class SoftMaxInt8Coder final : public SoftmaxBaseCoder {
|
||||||
|
public:
|
||||||
|
SoftMaxInt8Coder(const std::vector<Tensor *> &in_tensors, const std::vector<Tensor *> &out_tensors,
|
||||||
|
const Model::Node *node, size_t node_index, Target target)
|
||||||
|
: SoftmaxBaseCoder(in_tensors, out_tensors, node, node_index, target) {}
|
||||||
|
|
||||||
|
~SoftMaxInt8Coder() override = default;
|
||||||
|
|
||||||
|
int Prepare(CoderContext *const context) override;
|
||||||
|
|
||||||
|
int DoCode(CoderContext *const context) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32_t num_rows_{0};
|
||||||
|
int32_t row_size_{0};
|
||||||
|
int32_t mult_{0};
|
||||||
|
int32_t shift_{0};
|
||||||
|
int32_t diff_min_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mindspore::lite::micro::cmsis
|
||||||
|
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_OPCODERS_CMSIS_NN_SOFTMAX_INT8_CODER_H_
|
|
@ -0,0 +1,233 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_LITE_MICRO_CODER_OPCODERS_SERIALIZERS_SERIALIZER_H_
|
||||||
|
#define MINDSPORE_LITE_MICRO_CODER_OPCODERS_SERIALIZERS_SERIALIZER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include "micro/coder/utils/print_utils.h"
|
||||||
|
#include "micro/coder/allocator/allocator.h"
|
||||||
|
|
||||||
|
namespace mindspore::lite::micro {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert array T[] to string
|
||||||
|
* std::ostream &operator<<(std::ostream &, const ::T &) must exist
|
||||||
|
* arr shouldn't be pointer, T* is not valid
|
||||||
|
* example:
|
||||||
|
* int arr[] = {1, 2, 3};
|
||||||
|
* ToString(arr);
|
||||||
|
* the code above would produce:
|
||||||
|
* "{1, 2, 3}"
|
||||||
|
*/
|
||||||
|
template <typename T, unsigned int N>
|
||||||
|
std::string ToString(const T (&arr)[N]) {
|
||||||
|
std::stringstream code;
|
||||||
|
int n = N;
|
||||||
|
while (n > 0 && arr[n - 1] == 0) {
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
code << "{";
|
||||||
|
for (int i = 0; i < n - 1; ++i) {
|
||||||
|
code << arr[i] << ", ";
|
||||||
|
}
|
||||||
|
if (n > 0) {
|
||||||
|
code << arr[n - 1];
|
||||||
|
}
|
||||||
|
code << "}";
|
||||||
|
return code.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Serializer {
|
||||||
|
public:
|
||||||
|
Serializer() = default;
|
||||||
|
virtual ~Serializer() = default;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code function call to generated code
|
||||||
|
* First parameter is the function name, the rest are the parameters of the function
|
||||||
|
* example:
|
||||||
|
* CodeFunction("function", "foo", "bar", "foobar", 42);
|
||||||
|
* the code above would produce:
|
||||||
|
* "function("foo", "bar", "foobar", 42);\n"
|
||||||
|
*/
|
||||||
|
template <typename... PARAMETERS>
|
||||||
|
void CodeFunction(const std::string &name, PARAMETERS... parameters) {
|
||||||
|
code << name << "(";
|
||||||
|
GenCode(parameters...);
|
||||||
|
code << ");\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Code function call to generated code, with checking the return code
|
||||||
|
* First parameter is the function name, the rest are the parameters of the function
|
||||||
|
* example:
|
||||||
|
* CodeFunctionWithCheck("function", "foo", "bar", "foobar", 42);
|
||||||
|
* the code above would produce:
|
||||||
|
* """
|
||||||
|
* if(function("foo", "bar", "foobar", 42) != 0) {\n
|
||||||
|
* return -1;
|
||||||
|
* }
|
||||||
|
* """
|
||||||
|
*/
|
||||||
|
template <typename... PARAMETERS>
|
||||||
|
void CodeFunctionWithCheck(const std::string &name, PARAMETERS... parameters) {
|
||||||
|
code << "if(" << name << "(";
|
||||||
|
GenCode(parameters...);
|
||||||
|
code << ") != RET_OK) {\n";
|
||||||
|
code << " return RET_ERROR;\n";
|
||||||
|
code << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper function for coding
|
||||||
|
* example:
|
||||||
|
* int bar[] = {1 ,3, 2};
|
||||||
|
* CodeArray("bar", bar, 3);
|
||||||
|
* the code above would produce:
|
||||||
|
* "int bar[3] = {1 ,3, 2};\n"
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void CodeArray(const std::string &name, T *data, int length, bool is_const = true) {
|
||||||
|
std::string type = GetVariableTypeName<T>();
|
||||||
|
if (is_const) {
|
||||||
|
code << "const " << type << " " << name << "[" << length << "] = {";
|
||||||
|
} else {
|
||||||
|
code << "static " << type << " " << name << "[" << length << "] = {";
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length - 1; ++i) {
|
||||||
|
code << data[i] << ", ";
|
||||||
|
}
|
||||||
|
if (length > 0) {
|
||||||
|
code << data[length - 1];
|
||||||
|
}
|
||||||
|
code << "};\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void CodeMallocExpression(T t, size_t size) {
|
||||||
|
GenCode(t);
|
||||||
|
code << " = malloc(" << size << ");\n";
|
||||||
|
code << "if (";
|
||||||
|
GenCode(t);
|
||||||
|
code << " == NULL) {\n";
|
||||||
|
code << " return RET_ERROR;\n";
|
||||||
|
code << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize precision(std::streamsize size) {
|
||||||
|
std::streamsize old = code.precision(size);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str() const { return code.str(); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Serializer &operator<<(T t) {
|
||||||
|
code << t;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper function for CodeStruct
|
||||||
|
* all parameters should be
|
||||||
|
* example:
|
||||||
|
* given:
|
||||||
|
* typedef struct Foo {
|
||||||
|
* int array[5];
|
||||||
|
* int *pointer;
|
||||||
|
* int count;
|
||||||
|
* } Foo;
|
||||||
|
* int pointer[] = {1 ,3, 2, 42};
|
||||||
|
* Foo foo = {{1, 2, 3}, pointer, 4};
|
||||||
|
* the CodeStruct should be written as:
|
||||||
|
* CodeStruct(const string &name, const Foo &foo) {
|
||||||
|
* CodeArray("pointer_gen", foo.pointer, foo.count);
|
||||||
|
* CodeBaseStruct("Foo", "foo_gen", ToString(foo.array), "pointer_gen", foo.count);
|
||||||
|
* }
|
||||||
|
* the code above would produce:
|
||||||
|
* "int pointer_gen[4] = {1 ,3, 2, 42};\n
|
||||||
|
* const Foo foo_gen = {{1, 2, 3}, pointer_gen, 4};\n"
|
||||||
|
*/
|
||||||
|
template <typename... PARAMETERS>
|
||||||
|
void CodeBaseStruct(const std::string &type, const std::string &name, PARAMETERS... parameters) {
|
||||||
|
code << "const " << type << " " << name << " = {";
|
||||||
|
GenCode(parameters...);
|
||||||
|
code << "};\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::ostringstream code;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* function GenCode(Args... args)
|
||||||
|
* Convert all parameters to string, and join connect them with comma ", "
|
||||||
|
* example:
|
||||||
|
* GenCode(true, false, static_cast<int8_t>(12), static_cast<uint8_t>(57), 'c', 5567);
|
||||||
|
* the code above would produce:
|
||||||
|
* "true, false, 12, 57, c, 5567"
|
||||||
|
*/
|
||||||
|
template <typename T, typename... REST>
|
||||||
|
void GenCode(T t, REST... args) {
|
||||||
|
GenCode(t);
|
||||||
|
code << ", ";
|
||||||
|
GenCode(args...);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
void GenCode(T t) {
|
||||||
|
code << t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert pointer to string when it's in MemoryAllocator (and it should be)
|
||||||
|
* if t is not in the table of MemoryAllocator, it would return empty string ""
|
||||||
|
* then the coder would generate something like
|
||||||
|
* {foo, , bar}
|
||||||
|
* and make the generated code
|
||||||
|
* not compilable rather than generating code like
|
||||||
|
* {foo, 0x7ffed0cd377c, bar}
|
||||||
|
* which would bring the hard coded address to the runtime and make it harder to debug
|
||||||
|
*
|
||||||
|
* if t is nullptr, "NULL" would be coded to generated code because some pointer might
|
||||||
|
* be nullptr in some cases and we want to code it.
|
||||||
|
* In this function, passing nullptr **would not** be regarded as a bug or mistake
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void GenCode(T *t) {
|
||||||
|
if (t == nullptr) {
|
||||||
|
code << "NULL";
|
||||||
|
} else {
|
||||||
|
std::string name = MemoryAllocator::GetInstance()->GetRuntimeAddr(t);
|
||||||
|
if (name.empty()) {
|
||||||
|
MS_LOG(ERROR) << "pointer is not allocated by the allocator";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
code << name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::boolalpha converts bool to string literals {"true", "false"} instead of {1, 0}
|
||||||
|
void GenCode(bool t) { code << std::boolalpha << t; }
|
||||||
|
void GenCode(int8_t t) { code << std::to_string(t); }
|
||||||
|
void GenCode(uint8_t t) { code << std::to_string(t); }
|
||||||
|
void GenCode(decltype(nullptr) t) { code << "NULL"; }
|
||||||
|
void GenCode(const char *t) { code << t; }
|
||||||
|
};
|
||||||
|
} // namespace mindspore::lite::micro
|
||||||
|
#endif // MINDSPORE_LITE_MICRO_CODER_SERIALIZERS_SERIALIZER_H_
|
Loading…
Reference in New Issue