o
    7?e&                     @   s   d Z ddlZddlm  mZ ddlmZ dZdZ	dZ
dZdZdZd	Zd
ZdZdd ZG dd dZd%ddZdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ ZdS )&z0Utilities used by both the GRU and LSTM classes.    N)get_device_nameZapi_implementsZapi_preferred_deviceZCPUZGPU      z4Layer %s will use cuDNN kernels when running on GPU.zLayer %s will not use cuDNN kernels since it doesn't meet the criteria. It will use a generic GPU kernel as fallback when running on GPU.c                   C   s   dS )NF r   r   r   d/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/keras/src/layers/rnn/gru_lstm_utils.pyuse_new_gru_lstm_impl1   s   r   c                   @   s    e Zd ZdZdd Zdd ZdS )DefunWrapperz;A wrapper with no deep copy of the Defun in LSTM/GRU layer.c              	   C   s   || _ || _|| _| jdvrtd| jd| j d| jt| jd tt  i}| jdkr8ddl	m
} |j}n	dd	l	m} |j}tj|d
|d| _d S )N)lstmgruz>Defun wrapper only applies to LSTM and GRU layer, but given {}
time_majorgo_backwards_r	   r   )r	   )r
   FZ	autographZexperimental_attributes)r   r   
layer_name
ValueErrorformat_FUNCTION_API_NAME_ATTRIBUTEstruuiduuid4Zkeras.src.layers.rnnr	   Zlstm_with_backend_selectionr
   Zgru_with_backend_selectiontffunctionZdefun_layer)selfr   r   r   supportive_attributesr	   Z
layer_funcr
   r   r   r   __init__:   s4   


zDefunWrapper.__init__c                 C   s&   t | | j| j| j}||t| < |S N)typer   r   r   id)r   memoZnew_wrapperr   r   r   __deepcopy__^   s
   zDefunWrapper.__deepcopy__N)__name__
__module____qualname____doc__r   r   r   r   r   r   r   7   s    $r   Fc                    sD   fdd  fdd| D } fdd|D }t j| | ddS )a  Utility function convert variable to cuDNN compatible parameter.

    Note that Keras weights for kernels are different from the cuDNN format.
    Eg.:

    ```
      Keras                 cuDNN
      [[0, 1, 2],  <--->  [[0, 2, 4],
       [3, 4, 5]]          [1, 3, 5]]
    ```

    If the input weights need to be in a unified format, then set
    `transpose_weights=True` to convert the weights.

    Args:
      weights: list of weights for the individual kernels and recurrent kernels.
      biases: list of biases for individual gate.
      shape: the shape for the converted variables that will be feed to cuDNN.
      transpose_weights: boolean, whether to transpose the weights.

    Returns:
      The converted weights that can be feed to cuDNN ops as param.
    c                    s    rt | S | S r   )r   	transpose)w)transpose_weightsr   r   convert   s   z$canonical_to_params.<locals>.convertc                    s   g | ]
}t  |qS r   r   Zreshape.0x)r'   shaper   r   
<listcomp>   s    z'canonical_to_params.<locals>.<listcomp>c                    s   g | ]}t | qS r   r(   r)   )r,   r   r   r-      s    r   Zaxis)r   concat)weightsZbiasesr,   r&   r   )r'   r,   r&   r   canonical_to_paramsf   s   r1   c                 C   sF   t | d }t jt | t jdd}t j||d}t t | |S )a_  Check the mask tensor and see if it right padded.

    For cuDNN kernel, it uses the sequence length param to skip the tailing
    timestep. If the data is left padded, or not a strict right padding (has
    masked value in the middle of the sequence), then cuDNN kernel won't be work
    properly in those cases.

    Left padded data: [[False, False, True, True, True]].
    Right padded data: [[True, True, True, False, False]].
    Mixture of mask/unmasked data: [[True, False, True, False, False]].

    Note that for the mixed data example above, the actually data RNN should see
    are those 2 Trues (index 0 and 2), the index 1 False should be ignored and
    not pollute the internal states.

    Args:
      mask: the Boolean tensor with shape [batch, timestep]

    Returns:
      boolean scalar tensor, whether the mask is strictly right padded.
    r   r.   )maxlen)r   r,   
reduce_sumcastint32Zsequence_mask
reduce_allequal)maskZmax_seq_lengthZcount_of_trueZright_padded_maskr   r   r   is_sequence_right_padded   s   r9   c                 C   s   t t jt | ddS )Nr   r.   )r   Z
reduce_anyr6   logical_not)r8   r   r   r   has_fully_masked_sequence   s   r;   c                 C   s   t j d r+|s|d urdS | d urt | S |d ur)t jt |t |S dS | d u r1dS |r8t | } t 	t
| t t| S )NZis_rocm_buildFT)r   	sysconfigZget_build_infor6   mathr7   Z
reduce_minZ
reduce_maxr$   logical_andr9   r:   r;   )r8   r   Zsequence_lengthsr   r   r   is_cudnn_supported_inputs   s$   

r?   c                 C   s$   |rdnd}t jt | t j|dS )aO  Calculate the sequence length tensor (1-D) based on the masking tensor.

    The masking tensor is a 2D boolean tensor with shape [batch, timestep]. For
    any timestep that should be masked, the corresponding field will be False.
    Consider the following example:
      a = [[True, True, False, False],
           [True, True, True, False]]
    It is a (2, 4) tensor, and the corresponding sequence length result should
    be 1D tensor with value [2, 3]. Note that the masking tensor must be right
    padded that could be checked by, e.g., `is_sequence_right_padded()`.

    Args:
      mask: Boolean tensor with shape [batch, timestep] or [timestep, batch] if
        time_major=True.
      time_major: Boolean, which indicates whether the mask is time major or
        batch major.
    Returns:
      sequence_length: 1D int32 tensor.
    r   r   r.   )r   r3   r4   r5   )r8   r   Ztimestep_indexr   r   r   calculate_sequence_by_mask   s   r@   c                 C   s&   t | t|i}|| tj|d|dS )NFr   )r   _FUNCTION_DEVICE_ATTRIBUTEupdater   r   )Zunique_api_nameZpreferred_devicefuncr   Zfunction_attributesr   r   r   generate_defun_backend   s   
rD   c                  C   s$   t  } | du r	dS tjjj| jS )zAParse the current context and return the device type, eg CPU/GPU.N)r   r   compatv1Z
DeviceSpecZfrom_stringZdevice_type)Zcurrent_devicer   r   r   get_context_device_type   s   rG   c                 C   s@   t d t j| t jddW  d    S 1 sw   Y  d S )Nz/cpu:0runtime)Zdtypename)r   ZdeviceZconstantZfloat32)Zruntime_namer   r   r   rH      s   $rH   c                 C   s   t | tjr
|  S | S )z/Read the value of a variable if it is variable.)
isinstancer   VariableZ
read_value)vr   r   r   read_variable_value   s   rM   c                 O   s$   | j |i |}|  |  |S )a  Register a specialization of a `Function` into the graph.

    This won't actually call the function with the inputs, and only put the
    function definition into graph. Register function with different input param
    will result into multiple version of functions registered in graph.

    Args:
      func: the `Function` instance that generated by a @defun
      *args: input arguments for the Python function.
      **kwargs: input keyword arguments for the Python function.

    Returns:
      a `ConcreteFunction` object specialized to inputs and execution context.

    Raises:
      ValueError: When the input function is not a defun wrapped python
        function.
    )Zget_concrete_functionZadd_to_graphZadd_gradient_functions_to_graph)rC   argskwargsZconcrete_funcr   r   r   function_register   s   rP   )F)r#   r   Ztensorflow.compat.v2rE   v2r   Ztensorflow.python.eager.contextr   r   rA   ZCPU_DEVICE_NAMEZGPU_DEVICE_NAMEZRUNTIME_UNKNOWNZRUNTIME_CPUZRUNTIME_GPUZCUDNN_AVAILABLE_MSGZCUDNN_NOT_AVAILABLE_MSGr   r   r1   r9   r;   r?   r@   rD   rG   rH   rM   rP   r   r   r   r   <module>   s4   
/!
