o
    i 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_nameapi_implementsapi_preferred_deviceCPU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	   R/var/www/myenv/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	autographexperimental_attributes)r   r   
layer_name
ValueErrorformat_FUNCTION_API_NAME_ATTRIBUTEstruuiduuid4keras.src.layers.rnnr   lstm_with_backend_selectionr   gru_with_backend_selectiontffunctiondefun_layer)selfr   r   r   supportive_attributesr   
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"   memo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   reshape.0x)r3   shaper	   r
   
<listcomp>   s    z'canonical_to_params.<locals>.<listcomp>c                    s   g | ]}t | qS r	   r4   r6   )r9   r	   r
   r:      s    r   axis)r   concat)weightsbiasesr9   r2   r	   )r3   r9   r2   r
   canonical_to_paramsf   s   r@   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   r9   
reduce_sumcastint32sequence_mask
reduce_allequal)maskmax_seq_lengthcount_of_trueright_padded_maskr	   r	   r
   is_sequence_right_padded   s   rL   c                 C   s   t t jt | ddS )Nr   r;   )r   
reduce_anyrF   logical_not)rH   r	   r	   r
   has_fully_masked_sequence   s   rO   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 )Nis_rocm_buildFT)r   	sysconfigget_build_inforF   mathrG   
reduce_min
reduce_maxr0   logical_andrL   rN   rO   )rH   r   sequence_lengthsr	   r	   r
   is_cudnn_supported_inputs   s$   

rX   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   rB   rC   rD   )rH   r   timestep_indexr	   r	   r
   calculate_sequence_by_mask   s   rZ   c                 C   s&   t | t|i}|| tj|d|dS )NFr   )r   _FUNCTION_DEVICE_ATTRIBUTEupdater   r    )unique_api_namepreferred_devicefuncr#   function_attributesr	   r	   r
   generate_defun_backend   s   
ra   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v1
DeviceSpecfrom_stringdevice_type)current_devicer	   r	   r
   get_context_device_type   s   rh   c                 C   s@   t d t j| t jddW  d    S 1 sw   Y  d S )Nz/cpu:0runtime)dtypename)r   deviceconstantfloat32)runtime_namer	   r	   r
   ri      s   $ri   c                 C   s   t | tjr
|  S | S )z/Read the value of a variable if it is variable.)
isinstancer   Variable
read_value)vr	   r	   r
   read_variable_value   s   rt   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.
    )get_concrete_functionadd_to_graphadd_gradient_functions_to_graph)r_   argskwargsconcrete_funcr	   r	   r
   function_register   s   r{   )F)r/   r   tensorflow.compat.v2rb   v2r   tensorflow.python.eager.contextr   r   r[   CPU_DEVICE_NAMEGPU_DEVICE_NAMERUNTIME_UNKNOWNRUNTIME_CPURUNTIME_GPUCUDNN_AVAILABLE_MSGCUDNN_NOT_AVAILABLE_MSGr   r   r@   rL   rO   rX   rZ   ra   rh   ri   rt   r{   r	   r	   r	   r
   <module>   s4   
/!
