88
99from aphrodite import _custom_ops as ops
1010from aphrodite .common .logger import log_once
11- from aphrodite .modeling . layers . activation import SiluAndMul
11+ from aphrodite .common . utils import direct_register_custom_op
1212from aphrodite .modeling .layers .fused_moe .layer import (FusedMoE ,
1313 FusedMoEMethodBase )
1414from aphrodite .modeling .layers .linear import LinearBase , LinearMethodBase
@@ -93,8 +93,8 @@ def get_quant_method(self, layer: torch.nn.Module,
9393MMQ_QUANT_TYPES = STANDARD_QUANT_TYPES | KQUANT_TYPES
9494
9595
96- def _fuse_mul_mat (x : torch .Tensor , qweight : torch .Tensor ,
97- qweight_type : int ) -> torch .Tensor :
96+ def _fused_mul_mat_gguf (x : torch .Tensor , qweight : torch .Tensor ,
97+ qweight_type : int ) -> torch .Tensor :
9898 # HACK: when doing chunked prefill we don't generate output tokens
9999 # so input to logits generator is empty which causes invalid parameter
100100 if x .shape [0 ] == 0 :
@@ -127,6 +127,32 @@ def _fuse_mul_mat(x: torch.Tensor, qweight: torch.Tensor,
127127 return y
128128
129129
130+ def _fused_mul_mat_gguf_fake (
131+ x : torch .Tensor ,
132+ qweight : torch .Tensor ,
133+ qweight_type : int ,
134+ ) -> torch .Tensor :
135+ return torch .empty (x .shape [0 ],
136+ qweight .shape [0 ],
137+ dtype = x .dtype ,
138+ device = x .device )
139+
140+
141+ try :
142+ direct_register_custom_op (
143+ op_name = "_fused_mul_mat_gguf" ,
144+ op_func = _fused_mul_mat_gguf ,
145+ mutates_args = [],
146+ fake_impl = _fused_mul_mat_gguf_fake ,
147+ )
148+ fused_mul_mat_gguf = torch .ops .aphrodite ._fused_mul_mat_gguf
149+
150+ except AttributeError as error :
151+ raise error
152+
153+
154+
155+
130156def _fused_moe_gguf (
131157 x : torch .Tensor ,
132158 w1 : torch .Tensor ,
@@ -135,8 +161,21 @@ def _fused_moe_gguf(
135161 topk_ids : torch .Tensor ,
136162 qweight_type : int ,
137163 qweight_type2 : int ,
138- act ,
164+ activation : str ,
139165) -> torch .Tensor :
166+
167+ def act (x : torch .Tensor ):
168+ d = x .shape [- 1 ] // 2
169+ output_shape = (x .shape [:- 1 ] + (d , ))
170+ out = torch .empty (output_shape , dtype = x .dtype , device = x .device )
171+ if activation == "silu" :
172+ torch .ops ._C .silu_and_mul (out , x )
173+ elif activation == "gelu" :
174+ torch .ops ._C .gelu_and_mul (out , x )
175+ else :
176+ raise ValueError (f"Unsupported activation: { activation } " )
177+ return out
178+
140179 # lazy import to avoid triggering triton import in CPU backend
141180 from aphrodite .modeling .layers .fused_moe .fused_moe import (
142181 moe_align_block_size )
@@ -170,12 +209,12 @@ def _fused_moe_gguf(
170209 for ww , ii in zip (w , idx ):
171210 expert_up = w1 [ii ]
172211
173- out = _fuse_mul_mat (inp , expert_up , qweight_type )
212+ out = fused_mul_mat_gguf (inp , expert_up , qweight_type )
174213 out = act (out )
175214
176215 expert_down = w2 [ii ]
177- current_state = _fuse_mul_mat (out , expert_down ,
178- qweight_type2 ).mul_ (ww )
216+ current_state = fused_mul_mat_gguf (out , expert_down ,
217+ qweight_type2 ).mul_ (ww )
179218 if current_hidden_state is None :
180219 current_hidden_state = current_state
181220 else :
@@ -184,6 +223,78 @@ def _fused_moe_gguf(
184223 return out_hidden_states
185224
186225
226+ def _fused_moe_gguf_fake (
227+ x : torch .Tensor ,
228+ w1 : torch .Tensor ,
229+ w2 : torch .Tensor ,
230+ topk_weights : torch .Tensor ,
231+ topk_ids : torch .Tensor ,
232+ qweight_type : int ,
233+ qweight_type2 : int ,
234+ activation : str ,
235+ ) -> torch .Tensor :
236+ return torch .empty_like (x )
237+
238+
239+ try :
240+ direct_register_custom_op (
241+ op_name = "_fused_moe_gguf" ,
242+ op_func = _fused_moe_gguf ,
243+ mutates_args = [],
244+ fake_impl = _fused_moe_gguf_fake ,
245+ )
246+ fused_moe_gguf = torch .ops .aphrodite ._fused_moe_gguf
247+
248+ except AttributeError as error :
249+ raise error
250+
251+
252+ def _apply_gguf_embedding (
253+ x : torch .Tensor ,
254+ qweight : torch .Tensor ,
255+ qweight_type : int ,
256+ hidden_size : int ,
257+ dtype : Optional [torch .dtype ] = None ,
258+ ) -> torch .Tensor :
259+ if qweight_type in UNQUANTIZED_TYPES :
260+ return torch .embedding (qweight , x )
261+ elif qweight_type in DEQUANT_TYPES :
262+ block_size , type_size = gguf .GGML_QUANT_SIZES [qweight_type ]
263+ x_flat = x .flatten ()
264+ assert (hidden_size == qweight .shape [1 ] // type_size * block_size )
265+ quant = torch .index_select (qweight , dim = 0 , index = x_flat )
266+ dequant = ops .ggml_dequantize (quant , qweight_type , hidden_size ,
267+ x_flat .shape [0 ], dtype )
268+ return dequant .view (* x .shape , hidden_size )
269+ else :
270+ qweight_type = WeightType (qweight_type )
271+ raise NotImplementedError (
272+ f"Unsupported GGUF quantization type: { qweight_type } " )
273+
274+
275+ def _apply_gguf_embedding_fake (
276+ x : torch .Tensor ,
277+ qweight : torch .Tensor ,
278+ qweight_type : int ,
279+ hidden_size : int ,
280+ dtype : Optional [torch .dtype ] = None ,
281+ ) -> torch .Tensor :
282+ return torch .empty (x .shape [0 ], hidden_size , dtype = dtype , device = x .device )
283+
284+
285+ try :
286+ direct_register_custom_op (
287+ op_name = "_apply_gguf_embedding" ,
288+ op_func = _apply_gguf_embedding ,
289+ mutates_args = [],
290+ fake_impl = _apply_gguf_embedding_fake ,
291+ )
292+ apply_gguf_embedding = torch .ops .aphrodite ._apply_gguf_embedding
293+
294+ except AttributeError as error :
295+ raise error
296+
297+
187298class GGUFLinearMethod (LinearMethodBase ):
188299 """Linear method for GGUF.
189300
@@ -230,6 +341,53 @@ def create_weights(self, layer: torch.nn.Module,
230341 set_weight_attrs (qweight_type , extra_weight_attrs )
231342 layer .register_parameter ("qweight_type" , qweight_type )
232343
344+ def process_weights_after_loading (self , layer : torch .nn .Module ):
345+ qweight_type = layer .qweight_type .weight_type
346+ if not (qweight_type in UNQUANTIZED_TYPES
347+ or qweight_type in DEQUANT_TYPES ):
348+ qweight_type = WeightType (qweight_type )
349+ raise ValueError (
350+ f"Unsupported GGUF quantization type { qweight_type } in "
351+ f"layer { layer } ." )
352+ # For MergedColumnParallelLinear and QKVParallelLinear, we need to
353+ # materialize the padded weight parameter for CUDA Graph compatibility.
354+ self ._create_padded_weight_param (layer )
355+
356+ def _create_padded_weight_param (self , layer : torch .nn .Module ):
357+ """Create padded weight parameter for GGUF MergedLinear layer."""
358+ qweight = layer .qweight
359+ shard_id_map = qweight .shard_id_map
360+ shard_id = qweight .shard_id
361+ if len (data_container := qweight .data_container ) > 1 :
362+ dtype = {data .dtype for data in data_container }
363+ assert len (dtype ) == 1 , ValueError (
364+ f"Data container has mixed dtypes: { dtype } " )
365+ dtype = next (iter (dtype ))
366+ # concat dim0 and pad dim1
367+ padded_side = max (x .size (1 ) for x in data_container )
368+ concat_side = sum (x .size (0 ) for x in data_container )
369+ # Pad the quantized weights to dense tensor, and create a map
370+ # with the location of each shard in the padded tensor.
371+ padded_data = torch .zeros ((concat_side , padded_side ),
372+ dtype = dtype ,
373+ device = qweight .device )
374+ # (dim0_start, dim0_end, dim1_size)
375+ shard_offset_map = dict [str , tuple [int , int , int ]]()
376+ for idx in shard_id :
377+ id_in_container = shard_id_map [idx ]
378+ start = sum (
379+ x .size (0 ) for x in data_container [:id_in_container ])
380+ end = start + data_container [id_in_container ].size (0 )
381+ size = data_container [id_in_container ].size (1 )
382+ padded_data [start :end , :size ] = data_container [id_in_container ]
383+ shard_offset_map [idx ] = (start , end , size )
384+ qweight .data_container .clear ()
385+ padded_param = Parameter (padded_data , requires_grad = False )
386+ set_weight_attrs (padded_param , vars (qweight ))
387+ set_weight_attrs (padded_param ,
388+ {"shard_offset_map" : shard_offset_map })
389+ layer .register_parameter ("qweight" , padded_param )
390+
233391 def apply (self ,
234392 layer : torch .nn .Module ,
235393 x : torch .Tensor ,
@@ -239,17 +397,20 @@ def apply(self,
239397 if shard_id :
240398 # dequantize shard weights respectively
241399 shard_id = ["q" , "k" , "v" ] if "q" in shard_id else shard_id
242- qweight = layer .qweight . unbind ( 0 )
400+ qweight = layer .qweight
243401 result = []
244402 for idx in shard_id :
245- q_idx = layer .qweight .shard_id_map [idx ]
403+ start , end , offset = layer .qweight .shard_offset_map [idx ]
246404 qweight_type = layer .qweight_type .shard_weight_type [idx ]
247- result .append (_fuse_mul_mat (x , qweight [q_idx ], qweight_type ))
405+ result .append (
406+ fused_mul_mat_gguf (
407+ x , qweight [start :end , :offset ].contiguous (),
408+ qweight_type ))
248409 out = torch .cat (result , axis = 1 )
249410 else :
250411 qweight = layer .qweight
251412 qweight_type = layer .qweight_type .weight_type
252- out = _fuse_mul_mat (x , qweight , qweight_type )
413+ out = fused_mul_mat_gguf (x , qweight , qweight_type )
253414 if bias is not None :
254415 out .add_ (bias )
255416 return out
@@ -319,7 +480,6 @@ def create_weights(self, layer: torch.nn.Module, num_experts: int,
319480
320481 set_weight_attrs (w2_qweight_type , extra_weight_attrs )
321482 layer .register_parameter ("w2_qweight_type" , w2_qweight_type )
322- self .act = SiluAndMul ()
323483
324484 def apply (
325485 self ,
@@ -356,10 +516,10 @@ def apply(
356516 custom_routing_function = custom_routing_function ,
357517 scoring_func = scoring_func ,
358518 e_score_correction_bias = e_score_correction_bias )
359- return _fused_moe_gguf (x , layer .w13_qweight , layer .w2_qweight ,
360- topk_weights , topk_ids ,
361- layer .w13_qweight_type .weight_type ,
362- layer .w2_qweight_type .weight_type , self . act )
519+ return fused_moe_gguf (x , layer .w13_qweight , layer .w2_qweight ,
520+ topk_weights , topk_ids ,
521+ layer .w13_qweight_type .weight_type ,
522+ layer .w2_qweight_type .weight_type , activation )
363523
364524
365525class GGUFEmbeddingMethod (GGUFLinearMethod ):
@@ -373,34 +533,15 @@ def embedding(self, layer: torch.nn.Module,
373533 x : torch .Tensor ) -> torch .Tensor :
374534 qweight = layer .qweight
375535 qweight_type = layer .qweight_type .weight_type
536+ hidden_size = qweight .tensor_shape [1 ]
376537
377- block_size , type_size = gguf .GGML_QUANT_SIZES [qweight_type ]
378- hidden_size = qweight .shape [1 ] // type_size * block_size
379- if qweight_type < 2 :
380- return torch .embedding (qweight , x )
381- x_flat = x .flatten ()
382- quant = torch .index_select (qweight , dim = 0 , index = x_flat )
383- dequant = ops .ggml_dequantize (quant , qweight_type , hidden_size ,
384- x_flat .shape [0 ], self .params_dtype )
385- return dequant .view (* x .shape , hidden_size )
538+ return apply_gguf_embedding (x ,
539+ qweight ,
540+ qweight_type ,
541+ hidden_size ,
542+ dtype = self .params_dtype )
386543
387544
388545class GGUFUninitializedParameter (UninitializedParameter ):
389546 cls_to_become = Parameter
390547 data_container : List [torch .Tensor ]
391-
392- def materialize_nested (self ) -> Parameter :
393- dtype = {data .dtype for data in self .data_container }
394- assert len (dtype ) == 1 , ValueError (
395- f"Data container has mixed dtypes: { dtype } " )
396- dtype = next (iter (dtype ))
397- nested_data = torch .nested .nested_tensor (self .data_container ,
398- device = self .device ,
399- dtype = dtype )
400- self .data_container .clear ()
401- param = torch .Tensor ._make_subclass (self .cls_to_become ,
402- nested_data ,
403- require_grad = False )
404- for k , v in self .__dict__ .items ():
405- setattr (param , k , v )
406- return param
0 commit comments