!7513 [MSLITE] Add KMeans method for quant

Merge pull request !7513 from ghzl/kmeans-quant
pull/7513/MERGE
mindspore-ci-bot 4 years ago committed by Gitee
commit 4df56b6c1e

@ -34,6 +34,7 @@ table QuantParam {
inited: bool = false;
var_corr: double = 1;
mean_corr: double = 0;
clusters: [float];
}
table Tensor {

@ -110,6 +110,12 @@ int LiteSession::ConvertTensors(const lite::Model *model) {
quant_arg.zeroPoint = quant_params->Get(j)->zeroPoint();
quant_arg.var_corr = quant_params->Get(j)->var_corr();
quant_arg.mean_corr = quant_params->Get(j)->mean_corr();
auto quant_clusters = quant_params->Get(j)->clusters();
if (quant_clusters != nullptr) {
for (size_t k = 0; k < quant_clusters->size(); k++) {
quant_arg.clusters.emplace_back(quant_clusters->Get(k));
}
}
dstTensor->AddQuantParam(quant_arg);
}
}

@ -83,7 +83,17 @@ class DequantUtil {
auto scale = param.scale;
auto zero_point = param.zeroPoint;
for (int64_t j = 0; j < input_tensor->ElementsNum(); j++) {
dequant_datas[j] = static_cast<float>((quant_datas[j] - zero_point) * scale);
if (param.clusters.size() != 0) {
int8_t index = quant_datas[j];
if (index > INT8_MAX || index < INT8_MIN) {
MS_LOG(ERROR) << "KMeans param quant is error.";
free(dequant_datas);
return nullptr;
}
dequant_datas[j] = static_cast<float>(param.clusters[index - INT8_MIN]);
} else {
dequant_datas[j] = static_cast<float>((quant_datas[j] - zero_point) * scale);
}
}
}
return dequant_datas;

@ -35,6 +35,7 @@ struct QuantArg {
int32_t zeroPoint;
double var_corr{1};
double mean_corr{0};
std::vector<float> clusters{};
};
class Tensor : public mindspore::tensor::MSTensor {

@ -101,7 +101,7 @@ STATUS DivergInfo::ComputeThreshold() {
}
if (method_x == kMethodOutlier) {
this->percent_result = PercentMethod(min_datas, max_datas);
this->percent_result = OutlierMethod(min_datas, max_datas);
this->best_T = std::max(std::fabs(percent_result.first), std::fabs(percent_result.second));
return RET_OK;
}

@ -20,6 +20,7 @@
#include <algorithm>
#include <memory>
#include <vector>
#include <set>
#include "src/ops/primitive_c.h"
#include "mindspore/lite/tools/converter/quantizer/general_bitpacking.h"
#include "src/common/utils.h"
@ -305,8 +306,8 @@ STATUS PostBitPack(float *weight, size_t shapeSize, size_t bitNum) {
return RET_OK;
}
bool SearchLowerBound(const std::vector<float> &data, const size_t &index, const float &max_tmp, float *min_tmp,
size_t *min_idx) {
static bool SearchLowerBound(const std::vector<float> &data, const size_t &index, const float &max_tmp, float *min_tmp,
size_t *min_idx) {
size_t length = data.size();
if (max_tmp - data.at(index) < delta) {
return false;
@ -320,8 +321,8 @@ bool SearchLowerBound(const std::vector<float> &data, const size_t &index, const
return true;
}
bool SearchUpperBound(const std::vector<float> &data, const size_t &index, float *max_tmp, const float &min_tmp,
size_t *max_idx) {
static bool SearchUpperBound(const std::vector<float> &data, const size_t &index, float *max_tmp, const float &min_tmp,
size_t *max_idx) {
size_t length = data.size();
if (data.at(index) - min_tmp < delta) {
return false;
@ -335,7 +336,7 @@ bool SearchUpperBound(const std::vector<float> &data, const size_t &index, float
return true;
}
float CalPercentile(const std::vector<float> &datas, const int &outlier_percent) {
static float CalPercentile(const std::vector<float> &datas, const int &outlier_percent) {
const int size = datas.size();
float val = outlier_percent / 100.0 * size;
int index = std::ceil(val);
@ -348,7 +349,7 @@ float CalPercentile(const std::vector<float> &datas, const int &outlier_percent)
return result;
}
std::pair<float, float> PercentMethod(std::vector<float> min_datas, std::vector<float> max_datas) {
std::pair<float, float> OutlierMethod(std::vector<float> min_datas, std::vector<float> max_datas) {
std::sort(max_datas.begin(), max_datas.end());
std::sort(min_datas.begin(), min_datas.end());
float min_val = CalPercentile(min_datas, percent);
@ -372,6 +373,64 @@ std::pair<float, float> PercentMethod(std::vector<float> min_datas, std::vector<
std::pair<float, float> result{min_tmp, max_tmp};
return result;
}
static std::vector<float> InitClusters(float *data, size_t elem_count, size_t k) {
std::set<float> set_unique{};
for (size_t i = 0; i < elem_count; i++) {
set_unique.emplace(data[i]);
}
std::vector<float> data_unique;
data_unique.assign(set_unique.begin(), set_unique.end());
std::vector<float> clusters{};
if (set_unique.size() < k) {
return clusters;
}
// init cluster
float ratio = static_cast<float>(data_unique.size()) / (k - 1);
std::sort(data_unique.begin(), data_unique.end());
for (size_t i = 0; i < k; i++) {
size_t index = std::floor(i * ratio);
if (i * ratio - index > 0) {
clusters.emplace_back((data_unique[index] + data_unique[index + 1]) / 2);
} else {
clusters.emplace_back(data_unique[index]);
}
}
return clusters;
}
std::vector<int8_t> KMeans(float *data, size_t elem_count, size_t k, size_t epochs, schema::QuantParamT *quantParam) {
std::vector<float> clusters = InitClusters(data, elem_count, k);
std::vector<int8_t> clusters_index{};
if (clusters.size() < k) {
MS_LOG(WARNING) << "K is less than the size of data so KMeans function is not executed.";
return clusters_index;
}
for (size_t epoch = 0; epoch < epochs; epoch++) {
clusters_index.clear();
std::vector<std::vector<float>> clusters_data(clusters.size());
for (size_t i = 0; i < elem_count; i++) {
size_t index = 0;
float min_distance = pow(data[i] - clusters[0], 2);
for (size_t j = 1; j < clusters.size(); j++) {
if (pow(data[i] - clusters[j], 2) < min_distance) {
min_distance = pow(data[i] - clusters[j], 2);
index = j;
}
}
clusters_index.emplace_back(index + INT8_MIN);
clusters_data[index].emplace_back(data[i]);
}
for (size_t j = 0; j < clusters.size(); j++) {
if (clusters_data[j].size() > 0) {
clusters[j] = std::accumulate(clusters_data[j].begin(), clusters_data[j].end(), 0.0) / clusters_data[j].size();
}
}
}
// update data
quantParam->clusters = clusters;
return clusters_index;
}
} // namespace quant
} // namespace lite
} // namespace mindspore

@ -72,15 +72,9 @@ STATUS CalQuantizationParams(schema::QuantParamT *quantParam, double mMin, doubl
STATUS CalQuantizationParams(schema::QuantParamT *quantParam, double mMin, double mMax, bool narrowRange = false,
int numBits = UINT8_QUANTIZATION);
bool SearchLowerBound(const std::vector<float> &data, const size_t &index, const float &max_tmp, float *min_tmp,
size_t *min_idx);
std::pair<float, float> OutlierMethod(std::vector<float> min_datas, std::vector<float> max_datas);
bool SearchUpperBound(const std::vector<float> &data, const size_t &index, float *max_tmp, const float &min_tmp,
size_t *max_idx);
float CalPercentile(const std::vector<float> &datas, const int &percent);
std::pair<float, float> PercentMethod(std::vector<float> min_datas, std::vector<float> max_datas);
std::vector<int8_t> KMeans(float *data, size_t elem_count, size_t k, size_t epochs, schema::QuantParamT *quantParam);
template <typename T>
T QuantizeData(const float originData, const schema::QuantParamT *quantParam) {
@ -213,7 +207,7 @@ STATUS QuantFilter(ParamValueLitePtr weight, std::shared_ptr<PrimitiveC> primiti
average_raw += raw_data;
}
}
if (quantType == QuantType_WeightQuant) {
if (quantType == QuantType_WeightQuant && quant_param.clusters.size() == 0) {
// mean
average_dequant = average_dequant / one_filter_size;
average_raw = average_raw / one_filter_size;
@ -261,17 +255,21 @@ STATUS QuantFilter(ParamValueLitePtr weight, std::shared_ptr<PrimitiveC> primiti
}
schema::QuantParamT quant_param;
STATUS status = CalQuantizationParams(&quant_param, min, max, false, quant_max, quant_min, bitNum);
if (status != RET_OK) {
MS_LOG(ERROR) << "CalQuantizationParams failed" << status;
return status;
if (quant_param.clusters.size() == 0) {
STATUS status = CalQuantizationParams(&quant_param, min, max, false, quant_max, quant_min, bitNum);
if (status != RET_OK) {
MS_LOG(ERROR) << "CalQuantizationParams failed" << status;
return status;
}
}
quant_params.emplace_back(quant_param);
// update data and datatype
for (uint32_t i = 0; i < elem_count; i++) {
float raw_data = raw_datas[i];
auto quant_data = QuantizeData<T>(raw_data, quant_param, quant_max, quant_min);
quant_datas[i] = quant_data;
if (quant_param.clusters.size() == 0) {
auto quant_data = QuantizeData<T>(raw_data, quant_param, quant_max, quant_min);
quant_datas[i] = quant_data;
}
}
auto ret = memcpy_s(raw_datas, weight->tensor_size(), quant_datas.data(), elem_count * sizeof(T));
if (ret != EOK) {

Loading…
Cancel
Save