Browse Source

[MS][LITE] fix static error

tags/v1.6.0
cjh9368 4 years ago
parent
commit
40ebf7f3e4
8 changed files with 54 additions and 678 deletions
  1. +24
    -0
      mindspore/core/ops/affine.h
  2. +20
    -2
      mindspore/core/ops/tensor_array.h
  3. +4
    -0
      mindspore/core/ops/tensor_array_read.h
  4. +4
    -0
      mindspore/core/ops/tensor_array_write.h
  5. +0
    -1
      mindspore/lite/tools/converter/quantizer/CMakeLists.txt
  6. +0
    -595
      mindspore/lite/tools/converter/quantizer/calc_quant_param.cc
  7. +0
    -80
      mindspore/lite/tools/converter/quantizer/calc_quant_param.h
  8. +2
    -0
      mindspore/lite/tools/converter/quantizer/full_quant_quantizer.cc

+ 24
- 0
mindspore/core/ops/affine.h View File

@@ -29,23 +29,47 @@ constexpr auto kNameAffine = "Affine";
constexpr auto kAffineContext = "context";
constexpr auto kAffineOutputDim = "output_dim";

/// \brief Assert defined Affine operator prototype of lite.
class MS_CORE_API Affine : public PrimitiveC {
public:
/// \brief Constructor.
Affine() : PrimitiveC(kNameAffine) { InitIOName({"x1", "x2"}, {"outputs"}); }
/// \brief Destructor.
~Affine() = default;
MS_DECLARE_PARENT(Affine, PrimitiveC);
/// \brief Method to init the op's attributes.
void Init(const std::vector<int64_t> &contexts, int64_t output_dim, bool transpose_a = false,
bool transpose_b = false);
/// \brief Method to set context attributes.
///
/// \param[in] keep_dims Define the context.
void set_context(const std::vector<int64_t> &);
/// \brief Method to set output_dim attributes.
///
/// \param[in] output_dim Define the output dim.
void set_output_dim(int64_t output_dim);
/// \brief Method to set transpose_a attributes.
///
/// \param[in] transpose_b Define the if transpose a tensor.
void set_transpose_a(bool transpose_a);
/// \brief Method to set transpose_b attributes.
///
/// \param[in] transpose_b Define the if transpose b tensor.
void set_transpose_b(bool transpose_b);
/// \brief Method to set activation_type attributes.
///
/// \param[in] activation_type Define the activation type.
void set_activation_type(const ActivationType &activation_type);

/// \brief Method to get transpose_a attributes.
bool get_transpose_a() const;
/// \brief Method to get transpose_b attributes.
bool get_transpose_b() const;
/// \brief Method to get context attributes.
std::vector<int64_t> get_context() const;
/// \brief Method to get output_dim attributes.
int64_t get_output_dim() const;
/// \brief Method to get activation_type attributes.
ActivationType get_activation_type() const;
};
} // namespace ops


+ 20
- 2
mindspore/core/ops/tensor_array.h View File

@@ -25,21 +25,39 @@ namespace ops {

constexpr auto kNameTensorArray = "TensorArray";

/// \brief Assert defined TensorArray operator prototype of lite.
class MS_CORE_API TensorArray : public PrimitiveC {
public:
/// \brief Constructor.
TensorArray() : PrimitiveC(kNameTensorArray) { InitIOName({"size"}, {"handle", "flow"}); }
/// \brief Destructor.
~TensorArray() = default;
MS_DECLARE_PARENT(TensorArray, PrimitiveC);
/// \brief Method to init the op's attributes.
void Init(bool dynamic_size, bool identical_element_shapes, const std::vector<int> &element_shape, int data_type);

/// \brief Method to set dynamic_size attributes.
///
/// \param[in] dynamic_size Define the dynamic_size.
void set_dynamic_size(bool dynamic_size);
/// \brief Method to set identical_element_shapes attributes.
///
/// \param[in] identical_element_shapes Define the identical element shapes
void set_identical_element_shapes(bool identical_element_shapes);
/// \brief Method to set element_shape attributes.
///
/// \param[in] element_shape Define the element shape.
void set_element_shape(const std::vector<int> &element_shape);
/// \brief Method to set data_type attributes.
///
/// \param[in] data_type Define the data type.
void set_data_type(int data_type);

/// \brief Method to get dynamic_size attributes.
bool get_dynamic_size() const;
/// \brief Method to get element_shapes attributes.
bool get_identical_element_shapes() const;
/// \brief Method to get element_shape attributes.
const std::vector<int> get_element_shape() const;
/// \brief Method to get data_type attributes.
int get_data_type() const;
};
} // namespace ops


+ 4
- 0
mindspore/core/ops/tensor_array_read.h View File

@@ -25,11 +25,15 @@ namespace ops {

constexpr auto kNameTensorArrayRead = "TensorArrayRead";

/// \brief Assert defined TensorArrayRead operator prototype of lite.
class MS_CORE_API TensorArrayRead : public PrimitiveC {
public:
/// \brief Constructor.
TensorArrayRead() : PrimitiveC(kNameTensorArrayRead) { InitIOName({"handle", "index", "flow_in"}, {"tensor"}); }
/// \brief Destructor.
~TensorArrayRead() = default;
MS_DECLARE_PARENT(TensorArrayRead, PrimitiveC);
/// \brief Method to init the op's attributes.
void Init() {}
};
} // namespace ops


+ 4
- 0
mindspore/core/ops/tensor_array_write.h View File

@@ -25,13 +25,17 @@ namespace ops {

constexpr auto kNameTensorArrayWrite = "TensorArrayWrite";

/// \brief Assert defined TensorArrayWrite operator prototype of lite.
class MS_CORE_API TensorArrayWrite : public PrimitiveC {
public:
/// \brief Constructor.
TensorArrayWrite() : PrimitiveC(kNameTensorArrayWrite) {
InitIOName({"handle", "index", "value", "flow_in"}, {"flow_out"});
}
/// \brief Destructor.
~TensorArrayWrite() = default;
MS_DECLARE_PARENT(TensorArrayWrite, PrimitiveC);
/// \brief Method to init the op's attributes.
void Init() {}
};
} // namespace ops


+ 0
- 1
mindspore/lite/tools/converter/quantizer/CMakeLists.txt View File

@@ -4,7 +4,6 @@ include_directories(${3RD_DIR}/flatbuffers/include)
include_directories(${3RD_DIR}/opencv/build/include/opencv4)

file(GLOB QUANTIZER
${CMAKE_CURRENT_SOURCE_DIR}/calc_quant_param.cc
${CMAKE_CURRENT_SOURCE_DIR}/quant_helper/*
${CMAKE_CURRENT_SOURCE_DIR}/quantizer.cc
${CMAKE_CURRENT_SOURCE_DIR}/quantize_util.cc


+ 0
- 595
mindspore/lite/tools/converter/quantizer/calc_quant_param.cc View File

@@ -1,595 +0,0 @@
/**
* Copyright 2019-2021 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 "tools/converter/quantizer/calc_quant_param.h"
#include <cfloat>
#include <memory>
#include <algorithm>
#include <utility>
#include "tools/common/tensor_util.h"
#include "schema/inner/ops_generated.h"
#include "src/common/utils.h"
#include "tools/converter/quantizer/quantize_util.h"

namespace mindspore::lite {
namespace {
constexpr size_t kBiasSize = 3;
constexpr size_t kBiasAddSize = 2;
} // namespace
STATUS QuantParamCalcer::ComputeConstQuantParam(const schema::TensorT &tensor, QuantParamT *quantParam) {
MS_ASSERT(quantParam != nullptr);
// int32 weight no need to quant
if (tensor.dataType == TypeId::kNumberTypeInt32 || tensor.dataType == TypeId::kNumberTypeUInt8) {
return RET_OK;
}
if (tensor.dataType != TypeId::kNumberTypeFloat) {
MS_LOG(DEBUG) << "Const Tensor without quantParam should has float dataType, in fact: " << tensor.dataType;
return RET_ERROR;
}
const auto *constData = reinterpret_cast<const float *>(tensor.data.data());
MS_ASSERT(constData != nullptr);
size_t constTensorShapeSize = GetShapeSize(tensor);
float min = 0.0f;
float max = 0.0f;
// find min and max
for (size_t i = 0; i < constTensorShapeSize; i++) {
min = std::min(min, constData[i]);
max = std::max(max, constData[i]);
}
if (min == 0.0f && max == 0.0f) {
max = 1.0f;
}
bool isQuantExact = true;
for (size_t i = 0; i < constTensorShapeSize; i++) {
isQuantExact &= (constData[i] == min || constData[i] == max);
}
if (!isQuantExact) {
MS_LOG(DEBUG) << "compute quantParam for const tensor may be a cause of poor inference accuracy";
}
return quant::CalQuantizationParams(quantParam, min, max);
}

// init inTensor quantParam from preNode if possible
// init outTensor quantParam from postNode if possible
int QuantParamCalcer::Calc(MetaGraphT *graph, const CNodeT &node) {
MS_ASSERT(node.inputIndex.size() > 0);
MS_ASSERT(node.quantParam.size() == node.inputIndex.size() + node.outputIndex.size());
inputParamDone = 0;
auto inputTensorSize = node.inputIndex.size();
for (size_t i = 0; i < inputTensorSize; i++) {
MS_ASSERT(graph->allTensors.size() > node.inputIndex.at(i));
auto &tensor = graph->allTensors.at(node.inputIndex.at(i));
MS_ASSERT(tensor != nullptr);
auto quantParam = GetTensorQuantParam(tensor);
if (quantParam == nullptr) {
continue;
}
if (quantParam->inited) { // inited
inputParamDone++;
continue;
}
if (!tensor->data.empty() && !IsContain(graph->inputIndex, node.inputIndex.at(i))) {
auto status = ComputeConstQuantParam((*tensor), quantParam.get());
if (status != RET_OK) {
MS_LOG(DEBUG) << "ComputeConstQuantParam failed: " << status;
return status;
}
tensor->quantParams.front() = std::move(quantParam);
inputParamDone++;
continue;
}
}
outputParamDone = 0;
for (unsigned int i : node.outputIndex) {
MS_ASSERT(graph->allTensors.size() > i);
auto &tensor = graph->allTensors.at(i);
MS_ASSERT(tensor != nullptr);
auto quantParam = GetTensorQuantParam(tensor);
if (quantParam != nullptr && quantParam->inited) { // inited
outputParamDone++;
continue;
}
MS_ASSERT(tensor->data.empty());
}
return RET_OK;
}

int CommonCalcer::Calc(MetaGraphT *subGraph, const CNodeT &node) {
MS_ASSERT(subGraph != nullptr);
auto status = QuantParamCalcer::Calc(subGraph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: " << status;
return status;
}
if (inputParamDone != node.inputIndex.size()) {
MS_LOG(DEBUG) << "Can not determine inputTensor quantParam, node " << node.name;
return RET_ERROR;
}
if (outputParamDone != node.outputIndex.size()) {
MS_LOG(DEBUG) << "Can not determine outputTensor quantParam, node " << node.name;
return RET_ERROR;
}
return RET_OK;
}

int ConvCalcer::Calc(MetaGraphT *subGraph, const CNodeT &node) {
MS_ASSERT(subGraph != nullptr);
auto status = CommonCalcer::Calc(subGraph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call CommonCalcer::Calc failed: " << status;
return status;
}
if (node.inputIndex.size() == kBiasSize) {
MS_CHECK_TRUE_MSG(subGraph->allTensors.size() > node.inputIndex.at(kBiasSize - 1), RET_ERROR, "invalid access.");
auto &biasTensor = subGraph->allTensors.at(node.inputIndex.at(kBiasSize - 1));
for (auto &quantParam : biasTensor->quantParams) {
quantParam->dstDtype = TypeId::kNumberTypeInt32;
}
}
return RET_OK;
}

int BiasAddCalcer::Calc(MetaGraphT *subGraph, const CNodeT &node) {
MS_ASSERT(subGraph != nullptr);
auto status = CommonCalcer::Calc(subGraph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call CommonCalcer::Calc failed: " << status;
return status;
}
if (node.inputIndex.size() == kBiasAddSize) {
MS_CHECK_TRUE_MSG(subGraph->allTensors.size() > node.inputIndex.at(kBiasSize - 1), RET_ERROR, "invalid access.");
auto &biasTensor = subGraph->allTensors.at(node.inputIndex.at(kBiasAddSize - 1));
for (auto &quantParam : biasTensor->quantParams) {
quantParam->dstDtype = TypeId::kNumberTypeInt32;
}
}
return RET_OK;
}

int LinearCalcer::Calc(MetaGraphT *graph, const CNodeT &node) {
MS_ASSERT(graph != nullptr);
auto status = QuantParamCalcer::Calc(graph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: " << status;
return status;
}
if (inputParamDone != node.inputIndex.size()) {
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.outputIndex.at(0), RET_ERROR, "invalid access.");
auto &outTensor = graph->allTensors.at(node.outputIndex.at(0));
MS_ASSERT(outTensor != nullptr);
auto outputQuantParam = GetTensorQuantParam(outTensor);
MS_CHECK_TRUE_MSG(outputQuantParam != nullptr, RET_ERROR, "outputQuantParam is nullptr.");
if (outputQuantParam == nullptr || !outputQuantParam->inited) {
MS_LOG(DEBUG) << "Can not determine inputTensor quantParam from outputTensor for node " << node.name;
return RET_ERROR;
}
for (unsigned int i : node.inputIndex) {
MS_CHECK_TRUE_MSG(graph->allTensors.size() > i, RET_ERROR, "invalid access.");
auto &inTensor = graph->allTensors.at(i);
MS_CHECK_TRUE_MSG(inTensor != nullptr, RET_ERROR, "inTensor is nullptr.");
auto inQuantParam = GetTensorQuantParam(inTensor);
if (inQuantParam == nullptr || inQuantParam->inited) {
continue;
}
inTensor->quantParams.front() = std::move(outputQuantParam);
}
}
if (outputParamDone != node.outputIndex.size()) {
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.inputIndex.at(0), RET_ERROR, "invalid access.");
auto &inTensor = graph->allTensors.at(node.inputIndex.at(0));
MS_CHECK_TRUE_MSG(inTensor != nullptr, RET_ERROR, "inTensor is nullptr.");
auto inQuantParam = GetTensorQuantParam(inTensor);
if (inQuantParam == nullptr || !inQuantParam->inited) {
MS_LOG(DEBUG) << "Can not determine outputTensor quantParam from inputTensor for node %s" << node.name;
return RET_ERROR;
}
for (unsigned int i : node.outputIndex) {
MS_CHECK_TRUE_MSG(graph->allTensors.size() > i, RET_ERROR, "invalid access.");
auto &outTensor = graph->allTensors.at(i);
MS_CHECK_TRUE_MSG(outTensor != nullptr, RET_ERROR, "outTensor is nullptr.");
auto outQuantParam = GetTensorQuantParam(outTensor);
if (outQuantParam == nullptr) {
outTensor->quantParams.emplace_back(std::move(inQuantParam));
continue;
}
if (outQuantParam->inited) {
continue;
}
outTensor->quantParams.front() = std::move(inQuantParam);
}
}
return RET_OK;
}

class CalcConcat : public QuantParamCalcer {
public:
CalcConcat() = default;
~CalcConcat() override = default;

int Calc(MetaGraphT *graph, const CNodeT &node) override {
MS_ASSERT(graph != nullptr);
MS_ASSERT(node.outputIndex.size() == 1);
auto status = QuantParamCalcer::Calc(graph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: " << status;
return status;
}
if (inputParamDone != node.inputIndex.size()) {
MS_LOG(DEBUG) << "Can not determine concat inputTensor quantParam, node " << node.name;
return RET_ERROR;
}
if (outputParamDone != 1) {
MS_ASSERT(outputParamDone == 0);
float minMin = FLT_MAX;
float maxMax = FLT_MIN;
bool narrowRange = false;
int numBits = -1;
for (size_t i = 0; i < node.inputIndex.size(); i++) {
MS_CHECK_TRUE_MSG(graph->allTensors.size() > i, RET_ERROR, "invalid access.");
auto &inTensor = graph->allTensors.at(i);
MS_CHECK_TRUE_MSG(inTensor != nullptr, RET_ERROR, "inTensor is nullptr.");
auto inQuantParam = GetTensorQuantParam(inTensor);
if (inQuantParam == nullptr || !inQuantParam->inited) {
return RET_ERROR;
}
if (numBits == -1) {
narrowRange = inQuantParam->narrowRange;
numBits = inQuantParam->numBits;
} else {
MS_ASSERT(narrowRange == quantParam->narrowRange);
MS_ASSERT(numBits == quantParam->numBits);
}
if (minMin > inQuantParam->min) {
minMin = inQuantParam->min;
}
if (maxMax < inQuantParam->max) {
maxMax = inQuantParam->max;
}
}

MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.outputIndex.front(), RET_ERROR, "Invalid access.");
auto &outTensor = graph->allTensors.at(node.outputIndex.front());
MS_CHECK_TRUE_MSG(outTensor != nullptr, RET_ERROR, "outTensor is nullptr.");
auto outQuantParam = std::make_unique<QuantParamT>();
MS_CHECK_TRUE_MSG(outQuantParam != nullptr, RET_ERROR, "outQuantParam is nullptr.");
status = quant::CalQuantizationParams(outQuantParam.get(), minMin, maxMax, narrowRange, numBits);
if (status != RET_OK) {
MS_LOG(DEBUG) << "in aware quantization run CalQuantizationParams failed!";
return RET_ERROR;
}
outTensor->quantParams.emplace_back(std::move(outQuantParam));
outputParamDone++;
}

return RET_OK;
}
};

class CalcAdd : public QuantParamCalcer {
public:
CalcAdd() = default;
~CalcAdd() override = default;

int Calc(MetaGraphT *graph, const CNodeT &node) override {
MS_ASSERT(node.inputIndex.size() == 2);
MS_ASSERT(node.outputIndex.size() == 1);
auto status = QuantParamCalcer::Calc(graph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: " << status;
return status;
}

if (inputParamDone != 2) {
MS_LOG(DEBUG) << "Can not determine add inputTensor quantParam, node " << node.name;
return RET_ERROR;
}
if (outputParamDone != 1) {
MS_ASSERT(outputParamDone == 0);
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.outputIndex.front(), RET_ERROR, "Invalid access.");
auto &outTensor = graph->allTensors.at(node.outputIndex.front());
MS_CHECK_TRUE_MSG(outTensor != nullptr, RET_ERROR, "outTensor is nullptr.");
auto outQuantParam = std::make_unique<QuantParamT>();

MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.inputIndex.at(0), RET_ERROR, "Invalid access.");
auto &tensor0 = graph->allTensors.at(node.inputIndex.at(0));
MS_CHECK_TRUE_MSG(tensor0 != nullptr, RET_ERROR, "tensor0 is nullptr.");
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.inputIndex.at(1), RET_ERROR, "Invalid access.");
auto &tensor1 = graph->allTensors.at(node.inputIndex.at(1));
MS_CHECK_TRUE_MSG(tensor1 != nullptr, RET_ERROR, "tensor1 is nullptr.");
auto biasTensor = &tensor0;
auto paramTensor = &tensor1;
if (!tensor0->data.empty() && (tensor0->dims.empty() || tensor0->dims.size() == 1)) {
biasTensor = &tensor0;
paramTensor = &tensor1;
} else if (!tensor1->data.empty() && (tensor1->dims.empty() || tensor1->dims.size() == 1)) {
biasTensor = &tensor1;
paramTensor = &tensor0;
} else {
MS_LOG(DEBUG) << "Can not determine add outputTensor quantParam, node " << node.name;
return RET_ERROR;
}
auto quantParam = GetTensorQuantParam(*paramTensor);
MS_CHECK_TRUE_MSG(quantParam != nullptr, RET_ERROR, "quantParam is nullptr.");
MS_ASSERT(quantParam->inited);
auto min = quantParam->min;
auto max = quantParam->max;
{
if ((*biasTensor)->dataType == TypeId::kNumberTypeFloat) {
MS_ASSERT((*biasTensor)->data.size() == sizeof(float) / sizeof(uint8_t));
void *oriTensorData = (*biasTensor)->data.data();
auto *bias = static_cast<float *>(oriTensorData);
status = quant::CalQuantizationParams(outQuantParam.get(), min + (*bias), max + (*bias));
if (status != RET_OK) {
MS_LOG(DEBUG) << "in aware quantization run CalQuantizationParams failed!";
return RET_ERROR;
}
} else if ((*biasTensor)->dataType == TypeId::kNumberTypeUInt8) {
MS_ASSERT((*biasTensor)->data.size() == 1);
void *oriTensorData = (*biasTensor)->data.data();
auto *bias = static_cast<uint8_t *>(oriTensorData);
status = quant::CalQuantizationParams(outQuantParam.get(), min + (*bias), max + (*bias));
if (status != RET_OK) {
MS_LOG(DEBUG) << "in aware quantization run CalQuantizationParams failed!";
return RET_ERROR;
}
} else {
MS_LOG(DEBUG) << "Unsupported tensor dataType: " << (*biasTensor)->dataType;
return RET_ERROR;
}
}
outTensor->quantParams.front() = std::move(outQuantParam);
}
return RET_OK;
}
};

class CalcRealDiv : public QuantParamCalcer {
public:
CalcRealDiv() = default;
~CalcRealDiv() override = default;

int Calc(MetaGraphT *graph, const CNodeT &node) override {
MS_ASSERT(node.inputIndex.size() == 2);
MS_ASSERT(node.outputIndex.size() == 1);
auto status = QuantParamCalcer::Calc(graph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: " << status;
return status;
}

if (inputParamDone != 2) {
MS_LOG(DEBUG) << "Can not determine realdiv inputTensor quantParam, node " << node.name;
return RET_ERROR;
}
if (outputParamDone != 1) {
MS_ASSERT(outputParamDone == 0);
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.outputIndex.front(), RET_ERROR, "Invalid access.");
auto &outTensor = graph->allTensors.at(node.outputIndex.front());
MS_CHECK_TRUE_MSG(outTensor != nullptr, RET_ERROR, "outTensor is nullptr.");
auto outQuantParam = std::make_unique<QuantParamT>();
MS_CHECK_TRUE_MSG(outQuantParam != nullptr, RET_ERROR, "outQuantParam is nullptr.");
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.inputIndex.at(0), RET_ERROR, "Invalid access.");
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.inputIndex.at(1), RET_ERROR, "Invalid access.");
auto &tensor1 = graph->allTensors.at(node.inputIndex.at(1));
MS_CHECK_TRUE_MSG(tensor1 != nullptr, RET_ERROR, "tensor1 is nullptr.");
if (!tensor1->data.empty() && (tensor1->dims.empty() || tensor1->dims.size() == 1)) {
auto quantParam = GetTensorQuantParam(tensor1);
auto min = quantParam->min;
auto max = quantParam->max;
{
if (tensor1->dataType == TypeId::kNumberTypeFloat) {
MS_ASSERT(tensor1->data.size() == sizeof(float) / sizeof(uint8_t));
void *oriTensorData = tensor1->data.data();
auto *div = static_cast<float *>(oriTensorData);
MS_ASSERT(*div != 0);
status = quant::CalQuantizationParams(outQuantParam.get(), min / (*div), max / (*div));
if (status != RET_OK) {
MS_LOG(DEBUG) << "in aware quantization run CalQuantizationParams failed!";
return RET_ERROR;
}
} else if (tensor1->dataType == TypeId::kNumberTypeUInt8) {
MS_ASSERT(tensor1->data.size() == 1);
void *oriTensorData = tensor1->data.data();
auto *div = static_cast<uint8_t *>(oriTensorData);
status = quant::CalQuantizationParams(outQuantParam.get(), min / (*div), max + (*div));
if (status != RET_OK) {
MS_LOG(DEBUG) << "in aware quantization run CalQuantizationParams failed!";
return RET_ERROR;
}
} else {
MS_LOG(DEBUG) << "Unsupported tensor dataType: " << tensor1->dataType;
return RET_ERROR;
}
outTensor->quantParams.front() = std::move(outQuantParam);
}
} else {
MS_LOG(DEBUG) << "Can not determine realDiv outputTensor quantParam, node " << node.name;
return RET_ERROR;
}
}
return RET_OK;
}
};

class CalcToSet : public QuantParamCalcer {
public:
CalcToSet(float min, float max) : min(min), max(max) {}
~CalcToSet() override = default;

int Calc(MetaGraphT *graph, const CNodeT &node) override {
MS_ASSERT(node.inputIndex.size() == 1);
MS_ASSERT(node.outputIndex.size() == 1);
auto status = QuantParamCalcer::Calc(graph, node);
if (status != RET_OK) {
MS_LOG(DEBUG) << "Call QuantParamCalcer::Calc failed: %d" << status;
return status;
}
// input
if (inputParamDone != node.inputIndex.size()) {
MS_LOG(DEBUG) << "Can not determine inputTensor quantParam, node " << node.name;
return RET_ERROR;
}
// output
if (outputParamDone != node.outputIndex.size()) {
std::unique_ptr<QuantParamT> quantParam = std::make_unique<QuantParamT>();
if (quantParam == nullptr) {
MS_LOG(DEBUG) << "new QuantParamT failed";
return RET_ERROR;
}
quantParam->scale = (max - min) / (UINT8_MAX + 1);
MS_ASSERT(quantParam->scale != 0);
quantParam->zeroPoint = int32_t(std::round((UINT8_MAX + 1) - max / quantParam->scale));
quantParam->min = min;
quantParam->max = max;
quantParam->inited = true;
MS_CHECK_TRUE_MSG(graph->allTensors.size() > node.outputIndex.front(), RET_ERROR, "Invalid access.");
auto &outTensor = graph->allTensors.at(node.outputIndex.front());
MS_ASSERT(outTensor != nullptr);
outTensor->quantParams.emplace_back(std::move(quantParam));
outputParamDone++;
}
return RET_OK;
}

protected:
float min;
float max;
};

class CalcActivation : public QuantParamCalcer {
public:
CalcActivation() = default;
~CalcActivation() override = default;

int Calc(MetaGraphT *subGraph, const CNodeT &node) override {
MS_ASSERT(node.inputIndex.size() == 1);
MS_ASSERT(node.outputIndex.size() == 1);
MS_ASSERT(node.attr.AsActivation() != nullptr);
if (node.primitive->value.AsActivation()->activation_type == schema::ActivationType_SIGMOID) {
auto calcToSet = CalcToSet(0, 1);
return calcToSet.Calc(subGraph, node);
} else {
auto calCommon = CommonCalcer();
return calCommon.Calc(subGraph, node);
}
}
};
QuantParamCalcRegister::~QuantParamCalcRegister() = default;

QuantParamCalcRegister::QuantParamCalcRegister() {
bool hasError = false;
std::shared_ptr<QuantParamCalcer> baseCalcer = std::make_shared<QuantParamCalcer>();
if (baseCalcer == nullptr) {
MS_LOG(DEBUG) << "new QuantParamCalcer failed";
hasError = true;
}
std::shared_ptr<QuantParamCalcer> commonCalcer = std::make_shared<CommonCalcer>();
if (commonCalcer == nullptr) {
MS_LOG(DEBUG) << "new commonCalcer failed";
hasError = true;
}

std::shared_ptr<QuantParamCalcer> linearCalcer = std::make_shared<LinearCalcer>();
if (linearCalcer == nullptr) {
MS_LOG(DEBUG) << "new linearCalcer failed";
hasError = true;
}
if (!hasError) {
auto concatPtr = std::make_shared<CalcConcat>();
if (concatPtr == nullptr) {
MS_LOG(DEBUG) << "new concatPtr failed";
}
_registerMap[schema::PrimitiveType_Concat] = concatPtr;
auto activationPtr = std::make_shared<CalcActivation>();
if (activationPtr == nullptr) {
MS_LOG(DEBUG) << "new activationPtr failed";
}
_registerMap[schema::PrimitiveType_Activation] = activationPtr;
auto addPtr = std::make_shared<CalcAdd>();
if (addPtr == nullptr) {
MS_LOG(DEBUG) << "new addPtr failed";
}
_registerMap[schema::PrimitiveType_AddFusion] = addPtr;
_registerMap[schema::PrimitiveType_MulFusion] = commonCalcer;
auto convPtr = std::make_shared<ConvCalcer>();
if (convPtr == nullptr) {
MS_LOG(DEBUG) << "new convPtr failed";
}
_registerMap[schema::PrimitiveType_ScaleFusion] = convPtr;
auto convPtr2 = std::make_shared<ConvCalcer>();
if (convPtr2 == nullptr) {
MS_LOG(DEBUG) << "new convPtr2 failed";
}
_registerMap[schema::PrimitiveType_Conv2DFusion] = convPtr2;
auto convPtr3 = std::make_shared<ConvCalcer>();
if (convPtr3 == nullptr) {
MS_LOG(DEBUG) << "new convPtr3 failed";
}
_registerMap[schema::PrimitiveType_Conv2dTransposeFusion] = convPtr3;
_registerMap[schema::PrimitiveType_AvgPoolFusion] = linearCalcer;
_registerMap[schema::PrimitiveType_MaxPoolFusion] = linearCalcer;
_registerMap[schema::PrimitiveType_Resize] = linearCalcer;
_registerMap[schema::PrimitiveType_Reshape] = linearCalcer;
_registerMap[schema::PrimitiveType_StridedSlice] = linearCalcer;
_registerMap[schema::PrimitiveType_Shape] = linearCalcer;
auto ToSetPtr = std::make_shared<CalcToSet>(0, 1);
if (ToSetPtr == nullptr) {
MS_LOG(DEBUG) << "new ToSetPtr failed";
}
_registerMap[schema::PrimitiveType_Softmax] = ToSetPtr;
_registerMap[schema::PrimitiveType_Squeeze] = linearCalcer;
auto realDivPtr = std::make_shared<CalcRealDiv>();
if (realDivPtr == nullptr) {
MS_LOG(DEBUG) << "new realDivPtr failed";
}
_registerMap[schema::PrimitiveType_RealDiv] = realDivPtr;
_registerMap[schema::PrimitiveType_ReduceFusion] = commonCalcer;
auto biadAddPtr = std::make_shared<BiasAddCalcer>();
if (biadAddPtr == nullptr) {
MS_LOG(DEBUG) << "new biadAddPtr failed";
}
_registerMap[schema::PrimitiveType_BiasAdd] = biadAddPtr;
_registerMap[schema::PrimitiveType_Transpose] = linearCalcer;
auto convPtr4 = std::make_shared<ConvCalcer>();
if (convPtr4 == nullptr) {
MS_LOG(DEBUG) << "new convPtr4 failed";
}
_registerMap[schema::PrimitiveType_MatMul] = convPtr4;
auto convPtr5 = std::make_shared<ConvCalcer>();
if (convPtr5 == nullptr) {
MS_LOG(DEBUG) << "new convPtr5 failed";
}
_registerMap[schema::PrimitiveType_FullConnection] = convPtr5;
// detection_postprocess op's quant param will not infer only fetch from preNode or postNode
// because we will not insert quantTransNode after this node in tflite_graph_8bit model if input data is float.
// if quantTransNode is inserted after detection_postprocess node, there will be some errors
_registerMap[schema::PrimitiveType_DetectionPostProcess] = baseCalcer;
}
}

QuantParamCalcRegister *QuantParamCalcRegister::GetInstance() {
static QuantParamCalcRegister instance;
return &instance;
}

std::shared_ptr<QuantParamCalcer> QuantParamCalcRegister::GetQuantParamCalcer(schema::PrimitiveType opType) {
auto it = _registerMap.find(opType);
if (it != _registerMap.end()) {
return it->second;
}
return nullptr;
}
} // namespace mindspore::lite

+ 0
- 80
mindspore/lite/tools/converter/quantizer/calc_quant_param.h View File

@@ -1,80 +0,0 @@
/**
* Copyright 2019-2021 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_TOOLS_CONVERTER_QUANTIZER_CALC_QUANT_PARAM_H
#define MINDSPORE_LITE_TOOLS_CONVERTER_QUANTIZER_CALC_QUANT_PARAM_H

#include <unordered_map>
#include <memory>
#include "include/errorcode.h"
#include "schema/inner/model_generated.h"

namespace mindspore::lite {
static constexpr int CONVLUTION_INPUT_NUM = 3;

class QuantParamCalcer {
public:
virtual ~QuantParamCalcer() = default;
virtual int Calc(schema::MetaGraphT *graph, const schema::CNodeT &node);

protected:
static STATUS ComputeConstQuantParam(const schema::TensorT &tensor, schema::QuantParamT *quantParam);

protected:
size_t inputParamDone = 0;
size_t outputParamDone = 0;
};

class CommonCalcer : public QuantParamCalcer {
public:
CommonCalcer() = default;
~CommonCalcer() override = default;
int Calc(schema::MetaGraphT *subGraph, const schema::CNodeT &node) override;
};

class ConvCalcer : public CommonCalcer {
public:
ConvCalcer() = default;
~ConvCalcer() override = default;
int Calc(schema::MetaGraphT *subGraph, const schema::CNodeT &node) override;
};

class BiasAddCalcer : public CommonCalcer {
public:
BiasAddCalcer() = default;
~BiasAddCalcer() override = default;
int Calc(schema::MetaGraphT *subGraph, const schema::CNodeT &node) override;
};

class LinearCalcer : public QuantParamCalcer {
public:
LinearCalcer() = default;
~LinearCalcer() override = default;
int Calc(schema::MetaGraphT *graph, const schema::CNodeT &node) override;
};

class QuantParamCalcRegister {
public:
virtual ~QuantParamCalcRegister();
std::shared_ptr<QuantParamCalcer> GetQuantParamCalcer(schema::PrimitiveType opType);
static QuantParamCalcRegister *GetInstance();

private:
QuantParamCalcRegister();
std::unordered_map<schema::PrimitiveType, std::shared_ptr<QuantParamCalcer>> _registerMap;
};
} // namespace mindspore::lite
#endif

+ 2
- 0
mindspore/lite/tools/converter/quantizer/full_quant_quantizer.cc View File

@@ -107,6 +107,7 @@ STATUS ComputeBiasDataAndQuantParam(const std::vector<double> &bias_scales, cons
MS_LOG(DEBUG) << "quanted bias over flow, maybe the scale of weight: " << weight_quant_params[0].scale
<< " is too small, need to update";
double activate_scale = input_scales[0];
MS_CHECK_TRUE_MSG(activate_scale != 0, RET_ERROR, "activate_scale == 0");
double filter_scale = std::abs(max_raw_data) / (activate_scale * quanted_bias_abs_limit);
weight_quant_params[0].scale = filter_scale;
weight_quant_params[0].zeroPoint = 0;
@@ -182,6 +183,7 @@ void DivergInfo::DumpHistogram() {
void DivergInfo::HandleBinForKL(int quant_bint_nums, int bin_index, std::vector<float> *quantized_histogram,
std::vector<float> *expanded_histogram) {
MS_ASSERT(quantized_histogram != nullptr && expanded_histogram != nullptr);
MS_ASSERT(quant_bint_nums != 0);
const float bin_interval = static_cast<float>(bin_index) / static_cast<float>(quant_bint_nums);
// merge i bins to target bins
for (int i = 0; i < quant_bint_nums; ++i) {


Loading…
Cancel
Save