5454 write_back_dbf_binary ,
5555 write_back_dbf_scaling ,
5656)
57+ from .mdbf_adapter import (
58+ load_mdbf_state ,
59+ restore_mdbf_original ,
60+ save_mdbf_state ,
61+ setup_mdbf_differentiable ,
62+ setup_mdbf_forwards_only ,
63+ write_back_mdbf_amp ,
64+ write_back_mdbf_binary ,
65+ )
5766
5867logger = getLogger (__name__ )
5968
@@ -418,17 +427,33 @@ def cosine_warmup_lr_lambda(
418427# ---------------------------------------------------------------------------
419428
420429
430+ @torch .no_grad ()
431+ def _teacher_logits (
432+ teacher_model : nn .Module ,
433+ input_ids : torch .Tensor ,
434+ teacher_dev : torch .device ,
435+ student_dev : torch .device ,
436+ ) -> torch .Tensor :
437+ """Run teacher forward; move logits to *student_dev* if devices differ."""
438+ if teacher_dev == student_dev :
439+ return get_logits (teacher_model (input_ids ))
440+ logits_t = get_logits (teacher_model (input_ids .to (teacher_dev )))
441+ return logits_t .to (student_dev )
442+
443+
421444@torch .no_grad ()
422445def eval_kl (
423446 model : nn .Module ,
424447 teacher_model : nn .Module ,
425448 dataloader : List [Dict [str , torch .Tensor ]],
426449 dev : torch .device ,
427450 temperature : float = 1.0 ,
451+ teacher_dev : Optional [torch .device ] = None ,
428452) -> float :
429453 """Mean KL divergence over *dataloader* batches."""
430454 was_training = model .training
431455 model .eval ()
456+ teacher_dev = teacher_dev or dev
432457 total , n = 0.0 , 0
433458 for batch in dataloader :
434459 input_ids = batch ["input_ids" ].to (dev )
@@ -437,7 +462,7 @@ def eval_kl(
437462 attention_mask = attention_mask .to (dev )
438463
439464 logits_s = get_logits (model (input_ids ))
440- logits_t = get_logits (teacher_model ( input_ids ) )
465+ logits_t = _teacher_logits (teacher_model , input_ids , teacher_dev , dev )
441466 total += compute_kl_loss (
442467 logits_t , logits_s , temperature , attention_mask = attention_mask ,
443468 ).item ()
@@ -587,6 +612,7 @@ def run_kl_distillation(
587612 gptq_intweight_lr : float = 1e-4 ,
588613 optimize_binary : bool = False ,
589614 ste_k : float = 100.0 ,
615+ mdbf_ste_k : float = 2.0 ,
590616 calibration_dataset = None ,
591617 num_calibration_samples : int = 128 ,
592618 max_length : int = 2048 ,
@@ -616,12 +642,17 @@ def run_kl_distillation(
616642 early_stopping_patience : int = 0 ,
617643 use_mixed_precision : bool = False ,
618644 grad_accum_steps : int = 1 ,
645+ student_device : Optional [str ] = None ,
646+ teacher_device : Optional [str ] = None ,
619647) -> Dict :
620648 """Run KL-distillation global PTQ on a GPTQ or DBF quantized model.
621649
622650 The model is modified **in-place**. Returns a results dict.
623651 """
624- dev = torch .device ("cuda" if torch .cuda .is_available () else "cpu" )
652+ dev = torch .device (
653+ student_device or ("cuda" if torch .cuda .is_available () else "cpu" )
654+ )
655+ teacher_dev = torch .device (teacher_device ) if teacher_device else dev
625656
626657 # ------------------------------------------------------------------
627658 # 1. Detect method
@@ -631,7 +662,7 @@ def run_kl_distillation(
631662 logger .warning ("No quantized layers detected — skipping global PTQ." )
632663 return {"global_executed" : False , "reason" : "not_quantized" }
633664
634- if method not in ("gptq" , "dbf" ):
665+ if method not in ("gptq" , "dbf" , "mdbf" ):
635666 logger .info ("Method '%s' detected — not supported." , method )
636667 return {"global_executed" : False , "reason" : f"unsupported_method_{ method } " }
637668
@@ -665,7 +696,8 @@ def run_kl_distillation(
665696 teacher_model .eval ()
666697 for p in teacher_model .parameters ():
667698 p .requires_grad = False
668- teacher_model .to (dev )
699+ if teacher_dev .type != "cpu" :
700+ teacher_model .to (teacher_dev )
669701
670702 # ------------------------------------------------------------------
671703 # 4. Move student to GPU and set up differentiable parameters
@@ -675,6 +707,7 @@ def run_kl_distillation(
675707
676708 gptq_modules : list = []
677709 dbf_modules : list = []
710+ mdbf_modules : list = []
678711 original_forwards : Dict [str , object ] = {}
679712 param_groups : list = []
680713 binary_params : list = []
@@ -710,13 +743,33 @@ def run_kl_distillation(
710743 f", { len (binary_params )} binary" if binary_params else "" ,
711744 )
712745
746+ elif method == "mdbf" :
747+ mdbf_modules = detected_modules
748+ original_forwards , scaling_params , binary_params = setup_mdbf_differentiable (
749+ mdbf_modules , optimize_binary , ste_k = mdbf_ste_k ,
750+ )
751+ logger .info ("MDBF binary STE sharpness mdbf_ste_k=%.4g" , mdbf_ste_k )
752+ all_mdbf_params = list (scaling_params )
753+ if binary_params :
754+ all_mdbf_params += binary_params
755+ param_groups = [{"params" : all_mdbf_params , "lr" : dbf_lr }]
756+
757+ logger .info (
758+ "Trainable: %d amp params%s across %d MDBF modules" ,
759+ len (scaling_params ),
760+ f", { len (binary_params )} binary" if binary_params else "" ,
761+ len (mdbf_modules ),
762+ )
763+
713764 total_trainable = sum (len (pg ["params" ]) for pg in param_groups )
714765 if total_trainable == 0 :
715766 logger .warning ("No trainable parameters — skipping." )
716767 if method == "gptq" :
717768 restore_gptq_original (gptq_modules , original_forwards )
718769 elif method == "dbf" :
719770 restore_dbf_original (dbf_modules , original_forwards )
771+ elif method == "mdbf" :
772+ restore_mdbf_original (mdbf_modules , original_forwards )
720773 quantized_model .cpu ()
721774 del teacher_model
722775 gc .collect ()
@@ -871,17 +924,24 @@ def run_kl_distillation(
871924 if method == "gptq" :
872925 initial_state = save_gptq_state (gptq_modules )
873926 restore_gptq_original (gptq_modules , original_forwards )
874- else :
927+ elif method == "dbf" :
875928 initial_state = save_dbf_state (dbf_modules )
876929 restore_dbf_original (dbf_modules , original_forwards )
930+ else : # mdbf
931+ initial_state = save_mdbf_state (mdbf_modules )
932+ restore_mdbf_original (mdbf_modules , original_forwards )
877933
878- initial_kl = eval_kl (quantized_model , teacher_model , dataloader , dev , temperature )
934+ initial_kl = eval_kl (
935+ quantized_model , teacher_model , dataloader , dev , temperature , teacher_dev ,
936+ )
879937 logger .info ("Initial KL = %.6f" , initial_kl )
880938
881939 if method == "gptq" :
882940 setup_gptq_forwards_only (gptq_modules , original_forwards , gptq_optimize_intweight )
883941 elif method == "dbf" :
884942 setup_dbf_forwards_only (dbf_modules , original_forwards )
943+ elif method == "mdbf" :
944+ setup_mdbf_forwards_only (mdbf_modules , original_forwards )
885945
886946 # ------------------------------------------------------------------
887947 # 7. Training loop
@@ -928,8 +988,9 @@ def _forward_and_loss() -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
928988
929989 with amp_ctx :
930990 logits_s = get_logits (quantized_model (input_ids ))
931- with torch .no_grad ():
932- logits_t = get_logits (teacher_model (input_ids ))
991+ logits_t = _teacher_logits (
992+ teacher_model , input_ids , teacher_dev , dev ,
993+ )
933994
934995 kl = compute_kl_loss (
935996 logits_t , logits_s , temperature , attention_mask = attention_mask ,
@@ -1052,23 +1113,33 @@ def _forward_and_loss() -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
10521113 elif method == "dbf" :
10531114 write_back_dbf_binary (dbf_modules )
10541115 restore_dbf_original (dbf_modules , original_forwards )
1116+ elif method == "mdbf" :
1117+ write_back_mdbf_binary (mdbf_modules )
1118+ write_back_mdbf_amp (mdbf_modules )
1119+ restore_mdbf_original (mdbf_modules , original_forwards )
10551120
1056- current_kl = eval_kl (quantized_model , teacher_model , dataloader , dev , temperature )
1121+ current_kl = eval_kl (
1122+ quantized_model , teacher_model , dataloader , dev , temperature , teacher_dev ,
1123+ )
10571124
10581125 if current_kl < best_kl :
10591126 best_kl = current_kl
10601127 patience_counter = 0
10611128 if method == "gptq" :
10621129 best_state = save_gptq_state (gptq_modules )
1063- else :
1130+ elif method == "dbf" :
10641131 best_state = save_dbf_state (dbf_modules )
1132+ else : # mdbf
1133+ best_state = save_mdbf_state (mdbf_modules )
10651134 else :
10661135 patience_counter += 1
10671136
10681137 if method == "gptq" :
10691138 setup_gptq_forwards_only (gptq_modules , original_forwards , gptq_optimize_intweight )
10701139 elif method == "dbf" :
10711140 setup_dbf_forwards_only (dbf_modules , original_forwards )
1141+ elif method == "mdbf" :
1142+ setup_mdbf_forwards_only (mdbf_modules , original_forwards )
10721143
10731144 # Restore non-EMA params for continued training
10741145 if ema_tracker is not None :
@@ -1103,27 +1174,36 @@ def _forward_and_loss() -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
11031174 if best_state is not None and best_kl < initial_kl :
11041175 if method == "gptq" :
11051176 load_gptq_state (gptq_modules , best_state )
1106- else :
1177+ elif method == "dbf" :
11071178 load_dbf_state (dbf_modules , best_state )
1179+ else : # mdbf
1180+ load_mdbf_state (mdbf_modules , best_state )
11081181 logger .info ("Loaded best state (KL=%.6f)" , best_kl )
11091182 elif best_kl >= initial_kl :
11101183 logger .info ("No improvement — rolling back to initial state." )
11111184 if method == "gptq" :
11121185 load_gptq_state (gptq_modules , initial_state )
1113- else :
1186+ elif method == "dbf" :
11141187 load_dbf_state (dbf_modules , initial_state )
1188+ else : # mdbf
1189+ load_mdbf_state (mdbf_modules , initial_state )
11151190 best_kl = initial_kl
11161191 else :
11171192 if method == "gptq" :
11181193 write_back_gptq_params (gptq_modules , gptq_optimize_intweight )
11191194 elif method == "dbf" :
11201195 write_back_dbf_binary (dbf_modules )
11211196 write_back_dbf_scaling (dbf_modules )
1197+ elif method == "mdbf" :
1198+ write_back_mdbf_binary (mdbf_modules )
1199+ write_back_mdbf_amp (mdbf_modules )
11221200
11231201 if method == "gptq" :
11241202 restore_gptq_original (gptq_modules , original_forwards , cleanup = False )
11251203 elif method == "dbf" :
11261204 restore_dbf_original (dbf_modules , original_forwards , cleanup = False )
1205+ elif method == "mdbf" :
1206+ restore_mdbf_original (mdbf_modules , original_forwards , cleanup = False )
11271207
11281208 # Cleanup hooks
11291209 if use_inter_loss :
@@ -1140,14 +1220,18 @@ def _forward_and_loss() -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
11401220
11411221 # Final evaluation
11421222 quantized_model .eval ()
1143- final_kl = eval_kl (quantized_model , teacher_model , dataloader , dev , temperature )
1223+ final_kl = eval_kl (
1224+ quantized_model , teacher_model , dataloader , dev , temperature , teacher_dev ,
1225+ )
11441226
11451227 # Cleanup
11461228 if method == "gptq" :
11471229 # Final cleanup of differentiable parameters
11481230 restore_gptq_original (gptq_modules , original_forwards , cleanup = True )
11491231 elif method == "dbf" :
11501232 restore_dbf_original (dbf_modules , original_forwards , cleanup = True )
1233+ elif method == "mdbf" :
1234+ restore_mdbf_original (mdbf_modules , original_forwards , cleanup = True )
11511235
11521236 del teacher_model
11531237 gc .collect ()
0 commit comments