Merge pull request !5210 from zhaozhenlong/lite/issue/resize_int8_weight_calctags/v1.0.0
| @@ -86,6 +86,62 @@ int ResizeBilinearInt8(const int8_t *input_data, int8_t *output_data, const int | |||
| return NNACL_OK; | |||
| } | |||
| int ResizeBilinearInt8WithFloatWeight(const int8_t *input_data, int8_t *output_data, const int *input_shape, | |||
| const int *output_shape, const bool align_corners, QuantArg *quant_in, | |||
| QuantArg *quant_out, const QuantMulArg *mul_arg, int tid, int thread_num) { | |||
| if (input_data == NULL || output_data == NULL || input_shape == NULL || output_shape == NULL) { | |||
| return NNACL_NULL_PTR; | |||
| } | |||
| int32_t in_n = input_shape[0]; | |||
| int32_t in_h = input_shape[1]; | |||
| int32_t in_w = input_shape[2]; | |||
| int32_t in_c = input_shape[3]; | |||
| int32_t new_height = output_shape[1]; | |||
| int32_t new_width = output_shape[2]; | |||
| float height_scale, width_scale; | |||
| ComputeScaleFloat(in_h, new_height, align_corners, &height_scale); | |||
| ComputeScaleFloat(in_w, new_width, align_corners, &width_scale); | |||
| int n, h, w, c; | |||
| for (n = 0; n < in_n; n++) { | |||
| for (h = tid; h < new_height; h += thread_num) { | |||
| float actual_y; | |||
| int bottom, top; | |||
| float bottom_weight, top_weight; | |||
| ComputeInterpolationArgsFloatWeight(h, height_scale, in_h, &actual_y, &bottom, &bottom_weight, &top, &top_weight); | |||
| for (w = 0; w < new_width; w++) { | |||
| float actual_x; | |||
| int left, right; | |||
| float left_weight, right_weight; | |||
| ComputeInterpolationArgsFloatWeight(w, width_scale, in_w, &actual_x, &left, &left_weight, &right, | |||
| &right_weight); | |||
| for (c = 0; c < in_c; c++) { | |||
| float bottom_left_value = ((int32_t)input_data[offset(input_shape, n, bottom, left, c)] - quant_in->zp_) * | |||
| bottom_weight * left_weight; | |||
| float bottom_right_value = ((int32_t)input_data[offset(input_shape, n, bottom, right, c)] - quant_in->zp_) * | |||
| bottom_weight * right_weight; | |||
| float top_left_value = | |||
| ((int32_t)input_data[offset(input_shape, n, top, left, c)] - quant_in->zp_) * top_weight * left_weight; | |||
| float top_right_value = | |||
| ((int32_t)input_data[offset(input_shape, n, top, right, c)] - quant_in->zp_) * top_weight * right_weight; | |||
| float interp_value = bottom_left_value + bottom_right_value + top_left_value + top_right_value; | |||
| const int out_interp_value = MultiplyByQuantizedMultiplier((int32_t)interp_value, mul_arg->multiplier_, | |||
| mul_arg->left_shift_, mul_arg->right_shift_) + | |||
| quant_out->zp_; | |||
| int8_t out_value; | |||
| out_value = out_interp_value > INT8_MAX ? INT8_MAX : out_interp_value; | |||
| out_value = out_value < INT8_MIN ? INT8_MIN : out_value; | |||
| output_data[offset(output_shape, n, h, w, c)] = out_value; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return NNACL_OK; | |||
| } | |||
| int ResizeNearestNeighborInt8Simple(const int8_t *input_data, int8_t *output_data, const int *input_shape, | |||
| const int *output_shape, const bool align_corners, int tid, int thread_num) { | |||
| int batch, y, x, c; | |||
| @@ -133,6 +189,22 @@ void ComputeInterpolationArgs(const int32_t pos, const int32_t scale, const int3 | |||
| *scaled_high_weight = *scaled_pos - (1 << 10) * (*low); | |||
| } | |||
| void ComputeScaleFloat(const int32_t in_value, const int32_t out_value, const bool align_corners, float *scale) { | |||
| *scale = (float)in_value / out_value; | |||
| if (align_corners && out_value > 1) { | |||
| *scale = (float)(in_value - 1) / (out_value - 1); | |||
| } | |||
| } | |||
| void ComputeInterpolationArgsFloatWeight(const int32_t pos, const float scale, const int32_t size, float *actual_pos, | |||
| int32_t *low, float *low_weight, int32_t *high, float *high_weight) { | |||
| *actual_pos = pos * scale; | |||
| *low = *actual_pos > 0 ? floor(*actual_pos) : 0; | |||
| *low_weight = 1.0 - (*actual_pos - *low); | |||
| *high = *low + 1 < size ? *low + 1 : size - 1; | |||
| *high_weight = *actual_pos - (*low); | |||
| } | |||
| void ComputeNearestNeighborInt(const int32_t pos, const int in_size, const int32_t new_size, const bool align_corners, | |||
| int32_t *nearest) { | |||
| if (new_size == 0) { | |||
| @@ -31,6 +31,20 @@ int ResizeBilinearInt8(const int8_t *input_data, int8_t *output_data, const int | |||
| const bool align_corners, QuantArg *quant_in, QuantArg *quant_out, const QuantMulArg *mul_arg, | |||
| int tid, int thread_num); | |||
| int ResizeBilinearInt8WithFloatWeight(const int8_t *input_data, int8_t *output_data, const int *input_shape, | |||
| const int *output_shape, const bool align_corners, QuantArg *quant_in, | |||
| QuantArg *quant_out, const QuantMulArg *mul_arg, int tid, int thread_num); | |||
| void ComputeScale(const int32_t in_value, const int32_t out_value, const bool align_corners, int32_t *scale); | |||
| void ComputeInterpolationArgs(const int32_t pos, const int32_t scale, const int32_t size, int32_t *scaled_pos, | |||
| int32_t *low, int32_t *scaled_low_weight, int32_t *high, int32_t *scaled_high_weight); | |||
| void ComputeScaleFloat(const int32_t in_value, const int32_t out_value, const bool align_corners, float *scale); | |||
| void ComputeInterpolationArgsFloatWeight(const int32_t pos, const float scale, const int32_t size, float *actual_pos, | |||
| int32_t *low, float *low_weight, int32_t *high, float *high_weight); | |||
| int ResizeNearestNeighborInt8Simple(const int8_t *input_data, int8_t *output_data, const int *input_shape, | |||
| const int *output_shape, const bool align_corners, int tid, int thread_num); | |||
| @@ -38,11 +52,6 @@ int ResizeNearestNeighborInt8(const int8_t *input_data, int8_t *output_data, con | |||
| const int *output_shape, const bool align_corners, const QuantMulArg *multiplier, | |||
| QuantArg *quant_in, QuantArg *quant_out, int tid, int thread_num); | |||
| void ComputeScale(const int32_t in_value, const int32_t out_value, const bool align_corners, int32_t *scale); | |||
| void ComputeInterpolationArgs(const int32_t pos, const int32_t scale, const int32_t size, int32_t *scaled_pos, | |||
| int32_t *low, int32_t *scaled_low_weight, int32_t *high, int32_t *scaled_high_weight); | |||
| void ComputeNearestNeighborInt(const int32_t pos, const int in_size, const int32_t new_size, const bool align_corners, | |||
| int32_t *nearest); | |||
| #ifdef __cplusplus | |||
| @@ -35,9 +35,9 @@ int ResizeInt8CPUKernel::Init() { | |||
| if (ret != RET_OK) { | |||
| return ret; | |||
| } | |||
| quant_in_ = new(std::nothrow) QuantArg; | |||
| quant_in_ = new (std::nothrow) QuantArg; | |||
| MS_ASSERT(quant_in_); | |||
| quant_out_ = new(std::nothrow) QuantArg; | |||
| quant_out_ = new (std::nothrow) QuantArg; | |||
| MS_ASSERT(quant_out_); | |||
| auto input = in_tensors_.at(0); | |||
| quant_in_->zp_ = input->GetQuantParams().front().zeroPoint; | |||
| @@ -46,7 +46,7 @@ int ResizeInt8CPUKernel::Init() { | |||
| quant_out_->zp_ = output->GetQuantParams().front().zeroPoint; | |||
| quant_out_->scale_ = output->GetQuantParams().front().scale; | |||
| multiplier_ = new(std::nothrow) QuantMulArg; | |||
| multiplier_ = new (std::nothrow) QuantMulArg; | |||
| MS_ASSERT(multiplier_); | |||
| QuantizeRoundParameter(quant_in_->scale_ / quant_out_->scale_, &multiplier_->multiplier_, &multiplier_->left_shift_, | |||
| &multiplier_->right_shift_); | |||
| @@ -85,9 +85,14 @@ int ResizeInt8CPUKernel::RunImpl(int task_id) { | |||
| int ret = 0; | |||
| switch (method_) { | |||
| case static_cast<int>(schema::ResizeMethod_BILINEAR): { | |||
| ret = ResizeBilinearInt8(input_data, output_data, input_shape.data(), out_tensors_[0]->shape().data(), | |||
| align_corners_, quant_in_, quant_out_, multiplier_, task_id, context_->thread_num_); | |||
| if (quant_in_->zp_ == 0) { | |||
| ret = ResizeBilinearInt8(input_data, output_data, input_shape.data(), out_tensors_[0]->shape().data(), | |||
| align_corners_, quant_in_, quant_out_, multiplier_, task_id, context_->thread_num_); | |||
| } else { | |||
| ret = ResizeBilinearInt8WithFloatWeight(input_data, output_data, input_shape.data(), | |||
| out_tensors_[0]->shape().data(), align_corners_, quant_in_, quant_out_, | |||
| multiplier_, task_id, context_->thread_num_); | |||
| } | |||
| break; | |||
| } | |||
| case static_cast<int>(schema::ResizeMethod_NEAREST_NEIGHBOR): { | |||
| @@ -95,25 +100,12 @@ int ResizeInt8CPUKernel::RunImpl(int task_id) { | |||
| bool same_scale = abs(quant_out_->scale_ - quant_in_->scale_) < 1e-6; | |||
| if (same_zp && same_scale) { | |||
| ret = | |||
| ResizeNearestNeighborInt8Simple(input_data, | |||
| output_data, | |||
| input_shape.data(), | |||
| out_tensors_[0]->shape().data(), | |||
| align_corners_, | |||
| task_id, | |||
| context_->thread_num_); | |||
| ResizeNearestNeighborInt8Simple(input_data, output_data, input_shape.data(), out_tensors_[0]->shape().data(), | |||
| align_corners_, task_id, context_->thread_num_); | |||
| } else { | |||
| ret = | |||
| ResizeNearestNeighborInt8(input_data, | |||
| output_data, | |||
| input_shape.data(), | |||
| out_tensors_[0]->shape().data(), | |||
| align_corners_, | |||
| multiplier_, | |||
| quant_in_, | |||
| quant_out_, | |||
| task_id, | |||
| context_->thread_num_); | |||
| ResizeNearestNeighborInt8(input_data, output_data, input_shape.data(), out_tensors_[0]->shape().data(), | |||
| align_corners_, multiplier_, quant_in_, quant_out_, task_id, context_->thread_num_); | |||
| } | |||
| break; | |||
| } | |||
| @@ -84,14 +84,13 @@ TEST_F(TestResizeBilinearInt8, Bilinear0) { | |||
| int8_t output_data[16] = {0}; | |||
| std::vector<int> in_shape = {1, 2, 2, 1}; | |||
| std::vector<int> out_shape = {1, 4, 4, 1}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 2}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 5}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 0}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 0}; | |||
| bool align_corners = false; | |||
| int thread_num = 1; | |||
| int8_t expect[16] = {4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 5, 5, 6, 6}; | |||
| int8_t expect[16] = {0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 2, 2}; | |||
| Prepare(in_shape, out_shape, input_data, output_data, quant_in, quant_out, align_corners, thread_num); | |||
| kernel_->Init(); | |||
| kernel_->Run(); | |||
| CompareOutputInt8(output_data, expect, 16, err_percent_); | |||
| @@ -104,20 +103,19 @@ TEST_F(TestResizeBilinearInt8, Bilinear1) { | |||
| int8_t input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, | |||
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; | |||
| int8_t output_data[160] = {0}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 2}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 5}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 0}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 0}; | |||
| int thread_num = 1; | |||
| bool align_corners = false; | |||
| int8_t expect[160] = {4, 4, 5, 6, 6, 5, 6, 7, 7, 8, 7, 8, 8, 9, 9, 7, 8, 8, 9, 9, 7, 8, 8, | |||
| 9, 9, 8, 9, 10, 10, 11, 10, 11, 11, 12, 13, 10, 11, 11, 12, 13, 10, 11, 11, 12, 13, 12, | |||
| 12, 13, 13, 14, 13, 14, 14, 15, 16, 13, 14, 14, 15, 16, 10, 11, 11, 12, 13, 12, 12, 13, 13, | |||
| 14, 13, 14, 14, 15, 16, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 18, 18, 19, 20, 20, 19, 20, | |||
| 21, 21, 22, 19, 20, 21, 21, 22, 19, 20, 21, 21, 22, 21, 22, 22, 23, 23, 23, 23, 24, 24, 25, | |||
| 23, 23, 24, 24, 25, 23, 23, 24, 24, 25, 24, 25, 25, 26, 27, 26, 26, 27, 28, 28, 26, 26, 27, | |||
| 28, 28, 23, 23, 24, 24, 25, 24, 25, 25, 26, 27, 26, 26, 27, 28, 28, 26, 26, 27, 28, 28}; | |||
| int8_t expect[160] = {0, 1, 1, 2, 2, 2, 2, 3, 3, 4, 3, 4, 4, 5, 6, 3, 4, 4, 5, 6, 3, 4, 4, | |||
| 5, 6, 5, 5, 6, 7, 7, 6, 7, 8, 8, 9, 6, 7, 8, 8, 9, 6, 7, 7, 8, 9, 8, | |||
| 8, 9, 10, 10, 9, 10, 11, 11, 12, 9, 10, 11, 11, 12, 6, 7, 7, 8, 9, 8, 8, 9, 10, | |||
| 10, 9, 10, 11, 11, 12, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 14, 15, 15, 16, 17, 16, 16, | |||
| 17, 18, 18, 16, 16, 17, 18, 18, 16, 16, 17, 18, 18, 17, 18, 18, 19, 20, 19, 19, 20, 21, 21, | |||
| 19, 19, 20, 21, 21, 19, 19, 20, 21, 21, 20, 21, 22, 22, 23, 22, 23, 23, 24, 24, 22, 23, 23, | |||
| 24, 24, 19, 19, 20, 21, 21, 20, 21, 22, 22, 23, 22, 23, 23, 24, 24, 22, 23, 23, 24, 24}; | |||
| Prepare(in_shape, out_shape, input_data, output_data, quant_in, quant_out, align_corners, thread_num); | |||
| kernel_->Init(); | |||
| kernel_->Run(); | |||
| CompareOutputInt8(output_data, expect, 160, err_percent_); | |||
| @@ -131,22 +129,49 @@ TEST_F(TestResizeBilinearInt8, Bilinear2) { | |||
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; | |||
| int8_t output_data[160] = {0}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 0}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 0}; | |||
| int thread_num = 2; | |||
| bool align_corners = true; | |||
| int8_t expect[160] = {0, 1, 1, 2, 2, 1, 2, 2, 3, 4, 2, 3, 3, 4, 5, 3, 4, 4, 5, 6, 2, 3, 3, | |||
| 4, 5, 3, 4, 4, 5, 6, 4, 5, 5, 6, 7, 5, 6, 6, 7, 8, 4, 5, 5, 6, 7, 5, | |||
| 6, 6, 7, 8, 6, 7, 8, 8, 9, 7, 8, 9, 9, 10, 6, 7, 7, 8, 9, 7, 8, 9, 9, | |||
| 10, 8, 9, 10, 10, 11, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 14, 14, 15, 15, 16, 15, 15, | |||
| 16, 16, 17, 16, 16, 17, 18, 18, 15, 15, 16, 16, 17, 16, 16, 17, 18, 18, 17, 17, 18, 19, 19, | |||
| 18, 18, 19, 20, 20, 17, 17, 18, 19, 19, 18, 18, 19, 20, 20, 19, 19, 20, 21, 21, 20, 20, 21, | |||
| 22, 22, 19, 19, 20, 21, 21, 20, 20, 21, 22, 22, 21, 21, 22, 23, 23, 22, 23, 23, 24, 24}; | |||
| Prepare(in_shape, out_shape, input_data, output_data, quant_in, quant_out, align_corners, thread_num); | |||
| kernel_->Run(); | |||
| CompareOutputInt8(output_data, expect, 160, err_percent_); | |||
| } | |||
| // 2*2*2*5 -> 2*4*4*5 thread num 2, align corners zp -128 | |||
| TEST_F(TestResizeBilinearInt8, Bilinear3) { | |||
| std::vector<int> in_shape = {2, 2, 2, 5}; | |||
| std::vector<int> out_shape = {2, 4, 4, 5}; | |||
| int8_t input_data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, | |||
| 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}; | |||
| int8_t output_data[160] = {0}; | |||
| const lite::tensor::QuantArg quant_in = {0.005f, 2}; | |||
| const lite::tensor::QuantArg quant_out = {0.008f, 5}; | |||
| const lite::tensor::QuantArg quant_out = {0.005f, 2}; | |||
| int thread_num = 2; | |||
| bool align_corners = true; | |||
| int8_t expect[160] = {4, 4, 5, 6, 6, 5, 5, 6, 7, 7, 6, 6, 7, 8, 8, 7, 8, 8, 9, 9, 6, 6, 7, | |||
| 8, 8, 7, 8, 8, 9, 9, 8, 9, 9, 10, 10, 9, 10, 10, 11, 11, 8, 9, 9, 10, 10, 9, | |||
| 10, 10, 11, 11, 10, 11, 11, 12, 13, 11, 12, 12, 13, 14, 10, 11, 11, 12, 13, 11, 12, 12, 13, | |||
| 14, 12, 13, 13, 14, 15, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 17, 18, 19, 19, 20, 18, 19, | |||
| 20, 20, 21, 19, 20, 21, 21, 22, 18, 19, 20, 20, 21, 19, 20, 21, 21, 22, 20, 21, 22, 22, 23, | |||
| 21, 22, 23, 23, 24, 20, 21, 22, 22, 23, 21, 22, 23, 23, 24, 23, 23, 24, 24, 25, 24, 24, 25, | |||
| 25, 26, 23, 23, 24, 24, 25, 24, 24, 25, 25, 26, 25, 25, 26, 26, 27, 26, 26, 27, 28, 28}; | |||
| int8_t expect[160] = {0, 1, 2, 3, 4, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 5, 6, 7, 8, 9, 3, 4, 5, | |||
| 6, 7, 5, 6, 7, 8, 9, 7, 8, 9, 10, 11, 8, 9, 10, 11, 12, 7, 8, 9, 10, 11, 8, | |||
| 9, 10, 11, 12, 10, 11, 12, 13, 14, 12, 13, 14, 15, 16, 10, 11, 12, 13, 14, 12, 13, 14, 15, | |||
| 16, 13, 14, 15, 16, 17, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 22, 23, 24, 25, 26, 23, 24, | |||
| 25, 26, 27, 25, 26, 27, 28, 29, 23, 24, 25, 26, 27, 25, 26, 27, 28, 29, 27, 28, 29, 30, 31, | |||
| 28, 29, 30, 31, 32, 27, 28, 29, 30, 31, 28, 29, 30, 31, 32, 30, 31, 32, 33, 34, 32, 33, 34, | |||
| 35, 36, 30, 31, 32, 33, 34, 32, 33, 34, 35, 36, 33, 34, 35, 36, 37, 35, 36, 37, 38, 39}; | |||
| Prepare(in_shape, out_shape, input_data, output_data, quant_in, quant_out, align_corners, thread_num); | |||
| kernel_->Init(); | |||
| kernel_->Run(); | |||
| err_percent_ = 0.325f; | |||
| CompareOutputInt8(output_data, expect, 160, err_percent_); | |||
| } | |||
| } // namespace mindspore | |||