44
55#include " ov_ops/dynamic_quantize.hpp"
66#include " dynamic_quantize_inst.h"
7- #include " fully_connected/fully_connected_kernel_bf_tiled.h"
87#include " fully_connected_inst.h"
98
109#include " primitive_type_base.h"
1110#include " json_object.h"
12- #include < limits>
1311#include < string>
1412
1513namespace cldnn {
1614GPU_DEFINE_PRIMITIVE_TYPE_ID (dynamic_quantize);
1715
18- static size_t get_static_last_dim (const layout& layout) {
19- const auto & shape = layout.get_partial_shape ();
20- if (shape.rank ().is_dynamic () || shape.size () == 0 || shape[shape.size () - 1 ].is_dynamic ()) {
21- return 0 ;
22- }
23-
24- return static_cast <size_t >(shape[shape.size () - 1 ].get_length ());
25- }
26-
27- static bool has_fc_decompression_zp (const fully_connected_node& fc_node) {
28- const auto & fc_prim = fc_node.get_primitive ();
29- return fc_prim->decompression_zero_point .is_valid () ||
30- fc_prim->decompression_zero_point_scalar .has_value ();
31- }
32-
33- static size_t get_fc_scale_group_size (const fully_connected_node& fc_node) {
34- const auto & fc_prim = fc_node.get_primitive ();
35- if (!fc_prim->decompression_scale .is_valid ()) {
36- return 0 ;
37- }
38-
39- const size_t scale_dep_idx = 2 + (fc_prim->bias .is_valid () ? 1 : 0 );
40- if (fc_node.get_dependencies ().size () <= scale_dep_idx) {
41- return 0 ;
42- }
43-
44- const auto ifm_size = get_static_last_dim (fc_node.weights ().get_output_layout ());
45- const auto scale_groups = get_static_last_dim (fc_node.get_dependency (scale_dep_idx).get_output_layout ());
46- if (ifm_size == 0 || scale_groups == 0 || ifm_size % scale_groups != 0 ) {
47- return 0 ;
48- }
49-
50- return ifm_size / scale_groups;
51- }
52-
53- static size_t get_fc_zp_group_size (const fully_connected_node& fc_node) {
54- const auto & fc_prim = fc_node.get_primitive ();
55- if (fc_prim->decompression_zero_point_scalar .has_value ()) {
56- return get_static_last_dim (fc_node.weights ().get_output_layout ());
57- }
58-
59- if (!fc_prim->decompression_zero_point .is_valid ()) {
60- return 0 ;
61- }
62-
63- const size_t zp_dep_idx = 2 + (fc_prim->bias .is_valid () ? 1 : 0 ) + 1 ;
64- if (fc_node.get_dependencies ().size () <= zp_dep_idx) {
65- return 0 ;
66- }
67-
68- const auto ifm_size = get_static_last_dim (fc_node.weights ().get_output_layout ());
69- const auto zp_groups = get_static_last_dim (fc_node.get_dependency (zp_dep_idx).get_output_layout ());
70- if (ifm_size == 0 || zp_groups == 0 || ifm_size % zp_groups != 0 ) {
71- return 0 ;
72- }
73-
74- return ifm_size / zp_groups;
75- }
76-
77- static bool is_fc_bf_tiled_kernel (const std::string& kernel_name) {
78- return kernel_name == " fully_connected_gpu_bf_tiled" ;
79- }
80-
81- static kernel_selector::dev_type to_kernel_selector_device_type (device_type type) {
82- return type == device_type::discrete_gpu ? kernel_selector::dev_type::discrete_gpu
83- : kernel_selector::dev_type::integrated_gpu;
84- }
85-
86- static bool can_skip_for_fully_connected (const dynamic_quantize_node& node,
87- const fully_connected_node& fc_node,
88- const layout& act_layout,
89- size_t input_batch) {
90- const auto & attrs = node.get_primitive ()->attrs ;
91-
92- if (attrs.quantization_type != ov::op::internal::DynamicQuantize::QuantizationType::Symmetric ||
93- attrs.quantization_dt != ov::element::i8 ||
94- attrs.scale_dt != ov::element::f16 ||
95- attrs.precomputed_reduction ||
96- attrs.group_sizes .empty () ||
97- attrs.group_sizes .back () == std::numeric_limits<uint64_t >::max ()) {
98- return false ;
99- }
100-
101- for (size_t i = 0 ; i + 1 < attrs.group_sizes .size (); ++i) {
102- if (attrs.group_sizes [i] != 1 ) {
103- return false ;
104- }
105- }
106-
107- if (act_layout.data_type != data_types::f16 ) {
108- return false ;
109- }
110-
111- bool has_equivalent_fc_fast_path = false ;
112- const auto & forced_impls = fc_node.get_program ().get_config ().get_force_implementations ();
113- auto forced_impl = forced_impls.find (fc_node.id ());
114- if (forced_impl != forced_impls.end ()) {
115- if (forced_impl->second .impl_type != impl_types::ocl) {
116- return false ;
117- }
118- if (!forced_impl->second .kernel_name .empty () && !is_fc_bf_tiled_kernel (forced_impl->second .kernel_name )) {
119- return false ;
120- }
121- has_equivalent_fc_fast_path = is_fc_bf_tiled_kernel (forced_impl->second .kernel_name );
122- }
123-
124- const auto * fc_impl = fc_node.get_selected_impl ();
125- if (fc_impl != nullptr ) {
126- if (fc_impl->is_onednn ()) {
127- return false ;
128- }
129- has_equivalent_fc_fast_path |= is_fc_bf_tiled_kernel (fc_impl->get_kernel_name ());
130- }
131-
132- if (fc_node.get_preferred_impl_type () == impl_types::onednn && !has_equivalent_fc_fast_path) {
133- return false ;
134- }
135-
136- const auto input_features = get_static_last_dim (act_layout);
137- const auto weight_layout = fc_node.weights ().get_output_layout ();
138- const auto weight_ifm = get_static_last_dim (weight_layout);
139- if (input_features == 0 || weight_ifm == 0 || input_features != weight_ifm) {
140- return false ;
141- }
142-
143- const auto weight_type = weight_layout.data_type ;
144- const bool has_zp = has_fc_decompression_zp (fc_node);
145- const bool is_4bit_weight = weight_type == data_types::i4 || weight_type == data_types::u4;
146- const bool is_8bit_asym_weight = weight_type == data_types::u8 && has_zp;
147- const auto & device_info = fc_node.get_program ().get_engine ().get_device_info ();
148-
149- kernel_selector::fc_kernel_bf_tiled_utils::slm_dq_eligibility_params eligibility;
150- eligibility.device_type = to_kernel_selector_device_type (device_info.dev_type );
151- eligibility.max_local_mem_size = device_info.max_local_mem_size ;
152- eligibility.is_4bit_weight = is_4bit_weight;
153- eligibility.is_8bit_asym_weight = is_8bit_asym_weight;
154- eligibility.weight_ifm = weight_ifm;
155- eligibility.scale_group_size = get_fc_scale_group_size (fc_node);
156- eligibility.zp_group_size = get_fc_zp_group_size (fc_node);
157- eligibility.has_decompression_zp = has_zp;
158- eligibility.dq_group_size = fc_node.get_program ().get_config ().get_dynamic_quantization_group_size ();
159-
160- return has_equivalent_fc_fast_path &&
161- kernel_selector::fc_kernel_bf_tiled_utils::would_use_slm_with_internal_dq (eligibility,
162- input_batch,
163- attrs.group_sizes .back ());
164- }
165-
166- // can_be_optimized flag will be turned on from primitive_inst::update_shape function only when the
167- // following primitive can reproduce DynamicQuantize semantics internally for the current shape.
16+ // We should skip dynamic_quantization execution for 2nd token of LLM because it does not show performance gain.
17+ // can_be_optimized flag will be turned on from primitive_inst::update_shape function
16818static bool should_skip_execution (const dynamic_quantize_node& node, const layout& act_layout, const dynamic_quantize::Attributes& attrs) {
16919 if (cldnn::data_type_traits::is_floating_point (attrs.quantization_dt )) {
17020 return false ; // Execute unconditionally for floating point types.
@@ -180,22 +30,16 @@ static bool should_skip_execution(const dynamic_quantize_node& node, const layou
18030 if (!(*node.get_users ().begin ())->is_type <fully_connected>())
18131 return false ;
18232
33+ // If batch size is 1, dynamic_quantize is disabled for performance reason
18334 size_t input_batch = act_layout.batch ();
18435 if (act_layout.format == format::bfyx && act_layout.get_partial_shape ().size () != 2 ) {
18536 // 3D input
18637 input_batch = act_layout.batch () * act_layout.feature ();
18738 }
18839
189- auto & fc_user = (*node.get_users ().begin ())->as <fully_connected>();
190- if (!can_skip_for_fully_connected (node, fc_user, act_layout, input_batch)) {
191- GPU_DEBUG_TRACE << node.id () << " dyn_quan is not runtime-skipped: no equivalent FC fast path" << std::endl;
192- return false ;
193- }
194-
195- const auto dynamic_quantization_threshold = node.get_program ().get_config ().get_dynamic_quantization_threshold ();
196- if (dynamic_quantization_threshold != 0 && dynamic_quantization_threshold >= input_batch) {
40+ if (node.get_program ().get_config ().get_dynamic_quantization_threshold () >= input_batch) {
19741 GPU_DEBUG_TRACE << node.id () << " dyn_quan is turned off: input batch size is too small - " << input_batch << " / "
198- << dynamic_quantization_threshold << std::endl;
42+ << node. get_program (). get_config (). get_dynamic_quantization_threshold () << std::endl;
19943 return true ;
20044 }
20145
0 commit comments