
    ij4                         d Z ddlZddlmZ ddlmZ ddlmZ ddlmZ ddlm	Z	 ddlm
Z
 dd	lmZ dd
lmZ ddddZddddZ G d d      Zy)a  AWQ (Activation-aware Weight Quantization) algorithm implementation.

AWQ protects salient weights by finding optimal per-channel scales based on
activation magnitudes, then applies those scales before quantization.

Reference: https://arxiv.org/abs/2306.00978
    N)ops)Dense)EinsumDense)compute_quantization_parameters)dequantize_with_sz_map)dequantize_with_zero_point)quantize_with_sz_map)quantize_with_zero_point   num_grid_points
group_sizec          	      f   t        j                  |       d   }t        j                  |d      }t        j                  t        j                  |d      t        j
                  |      |      }d}t        j                  |fd      }t        |dz         D ]  }||z  }	|	dk(  rt        j
                  |      }
nt        j                  ||	      }
t        j                  |
d      }
t        j                  t        j                  t        j                  |
      t        j                  |
                  }t        j                  |d      }t        j                  |
|      }
t        j                  | |
      }|dk(  r1t        |d	d
ddd      \  }}}t!        ||||      }t#        |||      }n_t        |d	d
d|d      \  }}}t        j                  t        j$                  d|      |z  d      }t'        |||||      }t)        ||||      }t        j                  ||
      }t        j*                  t        j,                  | |            }t        j                  |t        j*                  |            }t        j.                  |      }||}|
}t        j                  ||      }|s|}|
} |S )a  Search for optimal AWQ scales using grid search.

    The AWQ algorithm finds scaling factors that protect salient weights.
    For each channel, we search for an optimal ratio in [0, 1] that minimizes
    the activation-weighted quantization error.

    The key insight: we MULTIPLY weights by scales before quantization to
    expand salient weights. This ensures quantization noise is small relative
    to the expanded weight magnitude. During inference, we divide by scales
    to restore the original magnitude.

    Scale formula: scales = x_max.pow(ratio).clamp(min=1e-4)
    Loss function: Activation-weighted MSE (approximates output error)

    Args:
        weights: Weight tensor [out_features, in_features] (transposed kernel).
        activation_magnitudes: Per-channel activation magnitudes [in_features].
        num_grid_points: Number of grid search points. Defaults to 20.
        group_size: Group size for quantization (-1 for per-channel).

    Returns:
        best_scales: Optimal per-channel scales [in_features].
       float32g:0yE>Ndtyper   g-C6?r      FTbits	symmetricper_channelr   compute_dtypeint32)r   shapecastwhereless	ones_likeonesrangepowermaximumsqrtmultiplymaxmindivider   r
   r   aranger	   r   squaresubtractmean)weightsactivation_magnitudesr   r   in_featuresx_max	best_lossbest_scalesiratioscales
scale_meanweights_scaledscale_qzero_qmaxq	quantizeddequantizedg_idxreconstructedweight_errorweighted_errorloss	is_betters                           m/var/www/html/emotional.easysim.app/public_html/venv/lib/python3.12/site-packages/keras/src/quantizers/awq.pyawq_search_optimal_scalesrE      ss   < ))G$Q'K HH*I6EIIchhud+S]]5-A5IEI((K>;K ?Q&' L%O# A:]]5)FYYue,FVT* XXcll3776?CGGFOLM
[[T2
FJ/ gv6$C '%!GVT 1I 5YPK %D %'%!GVT HHSZZ;7:EwOE -I 17FEK
 

;7
 zz#,,w"FGlCJJu4EFxx' I Ky1I 	$YL%\     c                   t        j                  |       d   }t        | |||      }t        j                  | |      }|dk(  r<t	        |ddddd      \  }}}	t        ||||	      }
t        j                  |fd	      }ngt	        |ddd|d      \  }}}	t        j                  t        j                  d
|      |z  d      }t        |||||	      }
t        j                  |d      }|
||||fS )a>  Quantize a weight matrix using AWQ.

    This function performs the complete AWQ quantization process:
    1. Find optimal per-channel scales via grid search
    2. Apply scales to weights
    3. Compute quantization parameters
    4. Quantize weights

    Args:
        weights_transpose: Weight matrix [out_features, in_features].
        activation_magnitudes: Per-channel activation magnitudes [in_features].
        num_grid_points: Number of grid search points.
        group_size: Group size for quantization.

    Returns:
        quantized_weights: Quantized weights [out_features, in_features].
        scales: Quantization scales [out_features, num_groups].
        zeros: Zero points [out_features, num_groups].
        awq_scales: AWQ per-channel scales [in_features].
        g_idx: Group indices [in_features].
    r   r   r   r   FTr   r   r   r   r   )
r   r   rE   r&   r   r
   zerosr   r*   r	   )weights_transposer/   r   r   r0   
awq_scalesr8   r9   r:   r;   r<   r>   s               rD   awq_quantize_matrixrK      s   8 ))-.q1K +'	J \\"3Z@NR ?#!
 -GVT
	
 		;.	: !@!#!
 A{3zA7K )GVUD
	
 	*gvz588rF   c                   *    e Zd ZdZddZd Zd Zd Zy)AWQaE  AWQ quantizer for a single layer.

    This class accumulates activation statistics during calibration and
    performs AWQ quantization on layer weights.

    The AWQ algorithm works by:
    1. Collecting per-channel maximum activation magnitudes
    2. Using activation magnitudes to determine weight saliency
    3. Finding optimal per-channel scales via grid search
    4. Applying scales before quantization to protect salient weights

    Args:
        layer: The layer to quantize (Dense or EinsumDense).
        config: AWQConfig instance with quantization parameters.
    Nc                    ddl m} || _        |xs
  |d d       | _        d| _        t        |t              s)t        |t              re|j                  j                  dk(  rL|j                  j                  | _        | j                  d   | _        | j                  d   | _        || _        n!t        |t              r|j                  j                  dk(  r|j                  j                  | _        t        | j                        }|j!                  t#        |            }|dk(  r|\  }}}|| _        ||z  | _        n*|dv r|\  }}}	||z  | _        |	| _        nt%        d|       t'        j(                  t+        j,                  |j                  | j                  | j                  f      	      | _        nt/        d
t1        |             t+        j2                  | j                  fd      | _        y )Nr   )	AWQConfig)dataset	tokenizer   r      )r   rR   z9Cannot determine dimensions for EinsumDense kernel shape )kernelz Unsupported layer type for AWQ: r   r   )keras.src.quantizers.awq_configrO   original_layerconfignum_samples
isinstancer   r   rT   ndimr   kernel_shaperowscolumnslayerlistindexr'   
ValueErrortypesSimpleNamespacer   reshape	TypeErrortyperH   r/   )
selfr^   rW   rO   r   d_model_dim_indexr0   headshead_dimout_featuress
             rD   __init__zAWQ.__init__   s   =#G	$$ G eU#uk*u||/@/@A/E % 2 2D))!,DI,,Q/DLDJ{+0A0AQ0F % 2 2D**+E %CJ 7 A%/4,UH'	$x/"f,05-x!H,	+ "G%  ..{{5<<$))T\\1JKDJ >tE{mLMM &)YY		|9%M"rF   c                    |t        d      t        j                  |      dk(  rt        d      t        |j                        dkD  r%t        j
                  |d|j                  d   f      }t        j                  |d      }t        j                  t        j                  |      d      }t        j                  | j                  |      | _
        | j                  t        t        j                  |      d         z   | _        y)	a  Update per-channel activation magnitude statistics.

        This method tracks the maximum absolute activation value for each
        input channel across all calibration batches.

        Args:
            input_batch: Input activations tensor [batch, ..., in_features].
        NzInput tensor cannot be None.r   zInput tensor cannot be empty.rR   r   r   )axis)ra   r   sizelenr   rd   r   r'   absr$   r/   rX   int)rg   input_batchx	batch_maxs       rD   update_activation_magnitudesz AWQ.update_activation_magnitudes#  s     ;<<88K A%<== {  !A%++kB8I8I"8M3NOKHH[), GGCGGAJQ/	 &)[[&&	&
"  ++c#))A,q/.BBrF   c                    ddl m} t        j                  | j                  j
                        }t        || j                  | j                  j                  | j                  j                        \  }}}}}t        j                  |d      }|j                  |dd      \  }}	}	| j                  `| j                  j                  j!                  |       | j                  j"                  j!                  |       | j                  j$                  j!                  |       | j                  j&                  j!                  |       | j                  j(                  j!                  |       d| j                  _        y)zPerform AWQ quantization on the layer.

        This method:
        1. Runs the AWQ grid search to find optimal scales
        2. Quantizes the layer weights
        3. Updates the layer's quantized variables
        r   )
quantizersr   uint8)rn   r   TN)	keras.srcrx   r   	transposer^   rT   rK   r/   rW   r   r   r   	pack_int4rV   _kernelquantized_kernelassignkernel_scalekernel_zerorJ   r>   is_awq_calibrated)
rg   rx   weights_matrixr<   scalezerorJ   r>   quantized_packed_s
             rD   quantize_layerzAWQ.quantize_layer@  s4    	)tzz'8'89 5H&& KK77{{--	5
1	5$
E HHY0	 ",!5!5AW "6 "
!Q
 ',,334DE((//6''..t4&&--j9!!((/04-rF   c                     | ` | `y)z"Free memory used by the quantizer.N)r/   r^   )rg   s    rD   freezAWQ.freef  s    &JrF   )N)__name__
__module____qualname____doc__rl   rv   r   r    rF   rD   rM   rM      s     +NZC:$5LrF   rM   )r   rb   rz   r   keras.src.layersr   r   keras.src.quantizers.quantizersr   r   r   r	   r
   rE   rK   rM   r   rF   rD   <module>r      sQ      " ( K B F @ D x~ R9jD DrF   