diff --git a/onnxruntime/contrib_ops/cpu/qlinear_concat.cc b/onnxruntime/contrib_ops/cpu/qlinear_concat.cc index a331a54f4c..2adeb4d697 100644 --- a/onnxruntime/contrib_ops/cpu/qlinear_concat.cc +++ b/onnxruntime/contrib_ops/cpu/qlinear_concat.cc @@ -10,6 +10,25 @@ namespace onnxruntime { namespace contrib { +constexpr int LOOKUP_TABLE_IS_FIXED = 1; +constexpr int LOOKUP_TABLE_IS_COPY = 2; + +static inline bool has_same_scale(const Tensor* tensor_x_scale, const Tensor* tensor_y_scale) { + return *(tensor_x_scale->Data()) == *(tensor_y_scale->Data()); +} + +static inline bool has_same_zero_point(bool is_signed, const Tensor* tensor_x_zero_point, const Tensor* tensor_y_zero_point) { + if (is_signed) { + const int8_t X_zero_point = (tensor_x_zero_point == nullptr) ? static_cast(0) : *(tensor_x_zero_point->template Data()); + const int8_t Y_zero_point = (tensor_y_zero_point == nullptr) ? static_cast(0) : *(tensor_y_zero_point->template Data()); + return X_zero_point == Y_zero_point; + } else { + const uint8_t X_zero_point = (tensor_x_zero_point == nullptr) ? static_cast(0) : *(tensor_x_zero_point->template Data()); + const uint8_t Y_zero_point = (tensor_y_zero_point == nullptr) ? static_cast(0) : *(tensor_y_zero_point->template Data()); + return X_zero_point == Y_zero_point; + } +} + QLinearConcat::QLinearConcat(const OpKernelInfo& info) : OpKernel(info), ConcatBase(info) { size_t input_def_count = info.node().InputDefs().size(); ORT_ENFORCE(input_def_count >= 8 && (input_def_count - 2) % 3 == 0, @@ -17,6 +36,7 @@ QLinearConcat::QLinearConcat(const OpKernelInfo& info) : OpKernel(info), ConcatB size_t input_count = (input_def_count - 2) / 3; fixed_lookup_tables_.resize(input_count); + fixed_table_attrs_.resize(input_count, 0); const Tensor* tensor_y_scale = nullptr; const Tensor* tensor_y_zero_point = nullptr; @@ -34,7 +54,7 @@ QLinearConcat::QLinearConcat(const OpKernelInfo& info) : OpKernel(info), ConcatB const Tensor* tensor_x_scale = nullptr; const Tensor* tensor_x_zero_point = nullptr; bool get_x_scale = info.TryGetConstantInput(static_cast(def_index) + 1, &tensor_x_scale); - bool get_x_zero_point = !info.TryGetConstantInput(static_cast(def_index) + 2, &tensor_x_zero_point); + bool get_x_zero_point = info.TryGetConstantInput(static_cast(def_index) + 2, &tensor_x_zero_point); if (!get_x_scale || !get_x_zero_point) { continue; // try to optimize next one } @@ -43,15 +63,20 @@ QLinearConcat::QLinearConcat(const OpKernelInfo& info) : OpKernel(info), ConcatB "Wrong input type encountered for zero point input def @", def_index + 2); size_t input_idx = (def_index - 2) / 3; - fixed_lookup_tables_[input_idx].resize(256); - if (is_signed_int8) { - QlinearBuildLookupTable( - fixed_lookup_tables_[input_idx].data(), tensor_x_scale, tensor_x_zero_point, - tensor_y_scale, tensor_y_zero_point, identity_float); + fixed_table_attrs_[input_idx] |= LOOKUP_TABLE_IS_FIXED; + if (has_same_scale(tensor_x_scale, tensor_y_scale) && has_same_zero_point(is_signed_int8, tensor_x_zero_point, tensor_y_zero_point)) { + fixed_table_attrs_[input_idx] |= LOOKUP_TABLE_IS_COPY; } else { - QlinearBuildLookupTable( - fixed_lookup_tables_[input_idx].data(), tensor_x_scale, tensor_x_zero_point, - tensor_y_scale, tensor_y_zero_point, identity_float); + fixed_lookup_tables_[input_idx].resize(256); + if (is_signed_int8) { + QlinearBuildLookupTable( + fixed_lookup_tables_[input_idx].data(), tensor_x_scale, tensor_x_zero_point, + tensor_y_scale, tensor_y_zero_point, identity_float); + } else { + QlinearBuildLookupTable( + fixed_lookup_tables_[input_idx].data(), tensor_x_scale, tensor_x_zero_point, + tensor_y_scale, tensor_y_zero_point, identity_float); + } } } } @@ -70,6 +95,7 @@ Status QLinearConcat::Compute(OpKernelContext* ctx) const { // Hold pointers to the input tensors to be used in the PrepareForCompute() step auto input_count = input_count_x3 / 3; std::vector> dynamic_lookup_tables(input_count); + std::vector dynamic_table_attrs(input_count, 0); std::vector input_tensors(input_count); for (auto input_index = 0; input_index < input_count; ++input_index) { @@ -77,24 +103,28 @@ Status QLinearConcat::Compute(OpKernelContext* ctx) const { input_tensors[input_index] = ctx->Input(static_cast(tuple_start)); // Build lookup table for non-const parameters (scale + zero point) - if (fixed_lookup_tables_[input_index].size() == 0) { + if (!(fixed_table_attrs_[input_index] & LOOKUP_TABLE_IS_FIXED)) { // Check tensor type first const Tensor* tensor_x_scale = ctx->Input(tuple_start + 1); const Tensor* tensor_x_zero_point = ctx->Input(tuple_start + 2); ORT_ENFORCE(tensor_x_scale->IsDataType(), "Input scale is not float for quantized input @", tuple_start + 1); ORT_ENFORCE(tensor_x_zero_point->GetElementType() == tensor_y_zero_point->GetElementType(), - "Wrong input type encountered for zero point of quantized input @", tuple_start + 2); + "Wrong input type encountered for zero point of quantized input @", tuple_start + 2); - dynamic_lookup_tables[input_index].resize(256); - if (is_signed_int8) { - QlinearBuildLookupTable( - dynamic_lookup_tables[input_index].data(), tensor_x_scale, tensor_x_zero_point, - tensor_y_scale, tensor_y_zero_point, identity_float); + if (has_same_scale(tensor_x_scale, tensor_y_scale) && has_same_zero_point(is_signed_int8, tensor_x_zero_point, tensor_y_zero_point)) { + dynamic_table_attrs[input_index] |= LOOKUP_TABLE_IS_COPY; } else { - QlinearBuildLookupTable( - dynamic_lookup_tables[input_index].data(), tensor_x_scale, tensor_x_zero_point, - tensor_y_scale, tensor_y_zero_point, identity_float); + dynamic_lookup_tables[input_index].resize(256); + if (is_signed_int8) { + QlinearBuildLookupTable( + dynamic_lookup_tables[input_index].data(), tensor_x_scale, tensor_x_zero_point, + tensor_y_scale, tensor_y_zero_point, identity_float); + } else { + QlinearBuildLookupTable( + dynamic_lookup_tables[input_index].data(), tensor_x_scale, tensor_x_zero_point, + tensor_y_scale, tensor_y_zero_point, identity_float); + } } } } @@ -115,15 +145,22 @@ Status QLinearConcat::Compute(OpKernelContext* ctx) const { if (prep.num_elements == 0) continue; - const uint8_t* table = (fixed_lookup_tables_[input_index].size() > 0) - ? fixed_lookup_tables_[input_index].data() - : dynamic_lookup_tables[input_index].data(); + const uint8_t* table = (fixed_table_attrs_[input_index] & LOOKUP_TABLE_IS_FIXED) + ? fixed_lookup_tables_[input_index].data() + : dynamic_lookup_tables[input_index].data(); + const bool is_copy = (fixed_table_attrs_[input_index] & LOOKUP_TABLE_IS_FIXED) + ? bool(fixed_table_attrs_[input_index] & LOOKUP_TABLE_IS_COPY) + : bool(dynamic_table_attrs[input_index] & LOOKUP_TABLE_IS_COPY); auto input_axis_pitch = prep.axis_pitch; const uint8_t* input = static_cast(prep.tensor->DataRaw()); uint8_t* output = static_cast(p.output_tensor->MutableDataRaw()) + initial_output_offset; for (int64_t cur_in_offset = 0; cur_in_offset < prep.num_elements; cur_in_offset += input_axis_pitch) { - QLinearLookupTableTransform(input + cur_in_offset, table, output, input_axis_pitch); + if (is_copy) { + memcpy(output, input + cur_in_offset, input_axis_pitch); + } else { + QLinearLookupTableTransform(input + cur_in_offset, table, output, input_axis_pitch); + } output += p.output_axis_pitch; } diff --git a/onnxruntime/contrib_ops/cpu/qlinear_concat.h b/onnxruntime/contrib_ops/cpu/qlinear_concat.h index c51a5db0e4..1a788c6409 100644 --- a/onnxruntime/contrib_ops/cpu/qlinear_concat.h +++ b/onnxruntime/contrib_ops/cpu/qlinear_concat.h @@ -19,6 +19,7 @@ class QLinearConcat final : public OpKernel, public ConcatBase { private: std::vector> fixed_lookup_tables_; + std::vector fixed_table_attrs_; // is_static or not, is_copy or not }; } // namespace contrib