@@ -451,12 +451,15 @@ def __init__(
451451 vram_limit : float = None ,
452452 name : str = "" ,
453453 disk_map : DiskMap = None ,
454+ quantize = None ,
455+ metadata : dict = None ,
454456 ** kwargs
455457 ):
456- if "disk" in (offload_dtype , offload_device , onload_dtype , onload_device ):
458+ disk_offload = "disk" in (offload_dtype , offload_device , onload_dtype , onload_device )
459+ if disk_offload and (disk_map is None or quantize is None ):
457460 raise ValueError (
458- "Layer quantization is incompatible with disk offload: DiskMap holds plain "
459- "tensors only and cannot rebuild packed weights with their quant state."
461+ "Disk offload for quantized layers requires both `disk_map` and `quantize`, "
462+ "so each layer can rebuild its packed weight and quant state lazily ."
460463 )
461464 super ().__init__ (
462465 offload_dtype ,
@@ -471,8 +474,32 @@ def __init__(
471474 )
472475 self .module = module
473476 self .name = name
477+ self .disk_offload = disk_offload
478+ self .disk_map = disk_map
479+ self .quantize = quantize
480+ self .metadata = metadata
481+ self ._required_keys = None
474482 self .init_lora_hotload ()
475483
484+ def _disk_required_keys (self ):
485+ if self ._required_keys is None :
486+ weight_prefix = self .name + ".weight."
487+ self ._required_keys = [
488+ key for key in self .disk_map
489+ if key == self .name + ".weight" or key .startswith (weight_prefix ) or key == self .name + ".bias"
490+ ]
491+ return self ._required_keys
492+
493+ def _load_from_disk (self , device , target = None ):
494+ module = self .module if target is None else target
495+ prefix = self .name + "."
496+ subdict = {key : self .disk_map [key ] for key in self ._disk_required_keys ()}
497+ rebuilt = self .quantize .unflatten_state_dict (subdict , self .metadata or {})
498+ state = {key [len (prefix ):]: value for key , value in rebuilt .items ()}
499+ module .load_state_dict (state , assign = True )
500+ module .to (device = device )
501+ return module
502+
476503 def _module_device (self ):
477504 tensor = next (self .module .parameters (), None )
478505 if tensor is None :
@@ -481,23 +508,35 @@ def _module_device(self):
481508
482509 def offload (self ):
483510 if self .state != 0 :
484- self .module .to (device = self .offload_device )
511+ if self .disk_offload :
512+ self .module = self .quantize .backend .create_quantized_linear_shell (self .module , self .computation_dtype )
513+ else :
514+ self .module .to (device = self .offload_device )
485515 self .state = 0
486516
487517 def onload (self ):
488518 if self .state < 1 :
489- self .module .to (device = self .onload_device )
519+ if self .disk_offload and self .onload_device != "disk" and self .offload_device == "disk" :
520+ self ._load_from_disk (self .onload_device )
521+ elif self .onload_device != "disk" :
522+ self .module .to (device = self .onload_device )
490523 self .state = 1
491524
492525 def preparing (self ):
493526 if self .state != 2 :
494- self .module .to (device = self .preparing_device )
527+ if self .disk_offload and self .preparing_device != "disk" and self .onload_device == "disk" :
528+ self ._load_from_disk (self .preparing_device )
529+ elif self .preparing_device != "disk" :
530+ self .module .to (device = self .preparing_device )
495531 self .state = 2
496532
497533 def computation_module (self ):
498534 device = self .preparing_device if self .state == 2 else self .onload_device
499535 if device == self .computation_device :
500536 return self .module
537+ if self .disk_offload and device == "disk" :
538+ transient = self .quantize .backend .create_quantized_linear_shell (self .module , self .computation_dtype )
539+ return self ._load_from_disk (self .computation_device , target = transient )
501540 return copy .deepcopy (self .module ).to (device = self .computation_device )
502541
503542 def forward (self , x , * args , ** kwargs ):
@@ -522,7 +561,7 @@ def enable_vram_management_recursively(model: torch.nn.Module, module_map: dict,
522561 for name , module in model .named_children ():
523562 layer_name = name if name_prefix == "" else name_prefix + "." + name
524563 if quantize is not None and quantize .is_quantized_linear (module ):
525- module_ = AutoWrappedQuantizedModule (module , ** vram_config , vram_limit = vram_limit , name = layer_name , disk_map = disk_map , ** kwargs )
564+ module_ = AutoWrappedQuantizedModule (module , ** vram_config , vram_limit = vram_limit , name = layer_name , disk_map = disk_map , quantize = quantize , ** kwargs )
526565 setattr (model , name , module_ )
527566 continue
528567 for source_module , target_module in module_map .items ():
0 commit comments