U
    di,                     @   s   d dl mZmZmZmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlmZ erdddlmZ e rvd d	lmZ e
 rd d
lZeeZdd ZG dd deZd
S )    )TYPE_CHECKINGAnyDictList   )prepare_for_hqq_linear)is_accelerate_availableis_hqq_availableis_torch_availablelogging   )HfQuantizer)get_module_from_name)PreTrainedModel)remove_hook_from_moduleNc                 C   s.   | dd d }| }|D ]}|j| }q|S )N.)splitZ_modules)modelnameZmodule_treeparentm r   I/tmp/pip-unpacked-wheel-bm_b0l5e/transformers/quantizers/quantizer_hqq.pyfind_parent%   s
    r   c                       s   e Zd ZdZdZdZdZdgZ fddZdd Z	d	e
e ee
e d
ddZd	e
e e
e e
e dddZd	deeeef edddZd	dedeeef e
e dddZdd Zd&d	e
e dddZd	ddd Zd'd!d"Zeed#d$d%Z  ZS )(HqqHfQuantizerz
    HQQ quantizer base HF class.
    nn.Linear modules are first tagged with quant_config in _process_model_before_weight_loading().
    The actual quantization and offloading to the GPU is done in check_quantized_param().
    FTZhqqc                    s    t  j|f| d | _d| _d S )NF)super__init__torch_dtypeusing_multi_gpu)selfquantization_configkwargs	__class__r   r   r   9   s    zHqqHfQuantizer.__init__c                 O   s   t  std|dds&|ddr.tdtj s@td| jd krpd|kr^|d | _ntj	| _t
d |d	d }t|trd
| ksd| krtdntt| dk| _d S )NzA valid HQQ version (>=0.2.1) is not available. Please follow the instructions to install it: `https://github.com/mobiusml/hqq/`.Zfrom_tfFZ	from_flaxzwConverting weights from tf/flax weights is currently not supported, please make sure the weights are in PyTorch format.z/No GPU found. A GPU is needed for quantization.r   zUSetting torch_dtype to torch.float32 as the default value since it was not specified.
device_mapcpuZdiskzYou are attempting to use an HQQ model with a device_map that contains a CPU or disk device. This is not supported. Please remove the CPU or disk device from the device_map.r   )r	   ImportErrorget
ValueErrortorchcudaZis_availableRuntimeErrorr   Zfloat32loggerinfo
isinstancedictvalueslensetr   )r    argsr"   r%   r   r   r   validate_environment>   s,    



z#HqqHfQuantizer.validate_environmentr   )r   missing_keysprefixreturnc                 K   s   | j rdd |D S |S d S )Nc                 S   s   g | ]}d |kr|qS )weightr   ).0keyr   r   r   
<listcomp>b   s      z6HqqHfQuantizer.update_missing_keys.<locals>.<listcomp>)pre_quantized)r    r   r6   r7   r"   r   r   r   update_missing_keys^   s    z"HqqHfQuantizer.update_missing_keys)r   expected_keysloaded_keysr8   c                    s"  | j s
|S  fdd t|}t rddlm} | D ]\}}||_q:t } || |t|jjd 8 }|d d t	j
dd dh }	t }
|D ]$tfd	d
|D r|
 q||
8 }|D ]Rd |kr|d  n|fdd|	D  d |kr|d  qt|S )Nc                    s:   |   D ],\}}t|tjjr*||j  || qd S N)Znamed_childrenr/   r*   nnLinearaddr   )r   Zlayersr   module)_find_hqq_quantizable_layersr   r   rF   n   s    zIHqqHfQuantizer.update_expected_keys.<locals>._find_hqq_quantizable_layersr   	HQQLinearZskip_modulesr&   Zlinear_layerquant_configcompute_dtypedevicebiasc                 3   s   | ]}| kV  qd S rA   r   )r:   _module)r;   r   r   	<genexpr>   s     z6HqqHfQuantizer.update_expected_keys.<locals>.<genexpr>z.weightc                    s   h | ]} d  | qS )r   r   )r:   Z_ref_key)rN   r   r   	<setcomp>   s     z6HqqHfQuantizer.update_expected_keys.<locals>.<setcomp>z.bias)r=   r3   r	   hqq.core.quantizerH   Znamed_modulesr   configr!   r*   Zfloat16Zstate_dict_keysanyrD   updatelist)r    r   r?   r@   Znew_keysrH   r   rE   Z_valid_modulesZ	_ref_keysZ_rm_keysr   )rF   rN   r;   r   update_expected_keysg   s>    
   z#HqqHfQuantizer.update_expected_keysztorch.Tensor)r   param_value
param_name
state_dictr8   c           	      K   sh   t  rddlm} t||\}}| jrNt|tjjs>t||oL|dkoL|dkS t|tjjob|dkS d S )Nr   rG   r9   rM   )	r	   rQ   rH   r   r=   r/   r*   rB   rC   )	r    r   rW   rX   rY   r"   rH   rE   tensor_namer   r   r   check_quantized_param   s    z$HqqHfQuantizer.check_quantized_paramztorch.device)r   rW   rX   target_devicerY   unexpected_keysc                 C   s  t  rddlm} t||\}}	d|ddd }
t||
}|
dd }i }| D ]@\}}|
d |kr\|||dd < |dk	r\||kr\|| q\| j	r*t
||rdS |dd| j|d}|| |jdk	rt
|jtjrtj|j|_| jr
| |}t||| |`~tj  dS |D ]}t||tj||  q.t|dr|||j| j|dd	}|jdk	rt
|jtjrtj|j|_| jr| |}t||| n|j| j|d
}t||| tj  dS )a  
        Each nn.Linear layer is processsed here.
        We first check if the corresponding module state_dict contains already HQQ quantized parameters.
        If not, we create a temp linear layer with the module state_dict params and use it for quantization
        r   rG   r   Nr   rI   rJ   T)rK   rL   Zdel_orig)ZdtyperL   )r	   rQ   rH   r   joinr   r   itemsremover=   r/   r   Zload_state_dictrM   r*   ZTensorrB   	Parameterr   _patch_layer_for_multigpusetattr__dict__r+   Zempty_cachehasattrrJ   to)r    r   rW   rX   r\   rY   r]   rH   rE   rZ   Z
layer_nameparent_modulenodeZmodule_state_dictkv	hqq_layerr;   r   r   r   create_quantized_param   s`    





z%HqqHfQuantizer.create_quantized_paramc                    s$   t dd   fdd_S )Nc                 S   s4   t || j|   }| jd k	r0|| j7 }|S rA   )r*   matmulrf   rL   Z
dequantizetrM   )r    xoutr   r   r   forward_with_device  s    

zEHqqHfQuantizer._patch_layer_for_multigpu.<locals>.forward_with_devicec                    s
    | S rA   r   )ro   rq   rk   r   r   <lambda>      z:HqqHfQuantizer._patch_layer_for_multigpu.<locals>.<lambda>)r   Zforward)r    rk   r   rr   r   rb     s    z(HqqHfQuantizer._patch_layer_for_multigpuN)r   keep_in_fp32_modulesc                 K   s"   |d k	r|ng }t || jd}d S )N)r!   )r   r!   )r    r   r%   ru   r"   r   r   r   $_process_model_before_weight_loading  s    z3HqqHfQuantizer._process_model_before_weight_loading)r   c                 K   s   d|_ |  |_|S NT)Zis_hqq_quantizedis_serializableZis_hqq_serializable)r    r   r"   r   r   r   #_process_model_after_weight_loading  s    
z2HqqHfQuantizer._process_model_after_weight_loadingc                 C   s   dS rw   r   )r    Zsafe_serializationr   r   r   rx   #  s    zHqqHfQuantizer.is_serializable)r8   c                 C   s   dS rw   r   )r    r   r   r   is_trainable&  s    zHqqHfQuantizer.is_trainable)N)N)__name__
__module____qualname____doc__Zuse_keep_in_fp32_modulesZ requires_parameters_quantizationZrequires_calibrationZrequired_packagesr   r5   r   strr>   rV   r   r   boolr[   rl   rb   rv   ry   rx   propertyrz   __classcell__r   r   r#   r   r   -   sP   !  
  4

W 
r   )typingr   r   r   r   Zintegrationsr   utilsr   r	   r
   r   baser   Zquantizers_utilsr   Zmodeling_utilsr   Zaccelerate.hooksr   r*   Z
get_loggerr{   r-   r   r   r   r   r   r   <module>   s   
