
    0hX                         d Z ddlZddlmc 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
lmZ ddlmZ ddlmZ  ed       G d de             Zy)zBidirectional wrapper for RNNs.    N)backend)Layer)	InputSpec)	rnn_utils)Wrapper)serialization_lib)generic_utils)
tf_inspect)tf_utils)keras_exportzkeras.layers.Bidirectionalc                        e Zd ZdZ	 	 	 d fd	Zed        Zd ZddZe	j                  d        Zd fd	Z	 	 	 	 ddZdd	Zd
 Zd Zed        Z fdZedd       Z xZS )BidirectionalaY  Bidirectional wrapper for RNNs.

    Args:
      layer: `keras.layers.RNN` instance, such as `keras.layers.LSTM` or
        `keras.layers.GRU`. It could also be a `keras.layers.Layer` instance
        that meets the following criteria:
        1. Be a sequence-processing layer (accepts 3D+ inputs).
        2. Have a `go_backwards`, `return_sequences` and `return_state`
          attribute (with the same semantics as for the `RNN` class).
        3. Have an `input_spec` attribute.
        4. Implement serialization via `get_config()` and `from_config()`.
        Note that the recommended way to create new RNN layers is to write a
        custom RNN cell and use it with `keras.layers.RNN`, instead of
        subclassing `keras.layers.Layer` directly.
        - When the `returns_sequences` is true, the output of the masked
        timestep will be zero regardless of the layer's original
        `zero_output_for_mask` value.
      merge_mode: Mode by which outputs of the forward and backward RNNs will be
        combined. One of {'sum', 'mul', 'concat', 'ave', None}. If None, the
        outputs will not be combined, they will be returned as a list. Default
        value is 'concat'.
      backward_layer: Optional `keras.layers.RNN`, or `keras.layers.Layer`
        instance to be used to handle backwards input processing.
        If `backward_layer` is not provided, the layer instance passed as the
        `layer` argument will be used to generate the backward layer
        automatically.
        Note that the provided `backward_layer` layer should have properties
        matching those of the `layer` argument, in particular it should have the
        same values for `stateful`, `return_states`, `return_sequences`, etc.
        In addition, `backward_layer` and `layer` should have different
        `go_backwards` argument values.
        A `ValueError` will be raised if these requirements are not met.

    Call arguments:
      The call arguments for this layer are the same as those of the wrapped RNN
        layer.
      Beware that when passing the `initial_state` argument during the call of
      this layer, the first half in the list of elements in the `initial_state`
      list will be passed to the forward RNN call and the last half in the list
      of elements will be passed to the backward RNN call.

    Raises:
      ValueError:
        1. If `layer` or `backward_layer` is not a `Layer` instance.
        2. In case of invalid `merge_mode` argument.
        3. If `backward_layer` has mismatched properties compared to `layer`.

    Examples:

    ```python
    model = Sequential()
    model.add(Bidirectional(LSTM(10, return_sequences=True),
                                 input_shape=(5, 10)))
    model.add(Bidirectional(LSTM(10)))
    model.add(Dense(5))
    model.add(Activation('softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

    # With custom backward layer
    model = Sequential()
    forward_layer = LSTM(10, return_sequences=True)
    backward_layer = LSTM(10, activation='relu', return_sequences=True,
                          go_backwards=True)
    model.add(Bidirectional(forward_layer, backward_layer=backward_layer,
                            input_shape=(5, 10)))
    model.add(Dense(5))
    model.add(Activation('softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
    ```
    c                     t        |t              st        d|       |t        |t              st        d|       |dvrt        d| d      d| _        t	        |   |fi | d| _        | j                  |      | _        || j                  |d      | _        n!|| _        t        j                  |      | _        d	| j                  j                  z   | j                  _        d
| j                  j                  z   | j                  _        | j                          d } || j                          || j                         || _        |r9t!        |      }|d |dz   | j                  _        ||dz  d  | j                  _        |j$                  | _        |j&                  | _        |j(                  | _        d| _        |j-                  d|j.                        | _        d| _        |j4                  | _        y )Nz[Please initialize `Bidirectional` layer with a `tf.keras.layers.Layer` instance. Received: zJ`backward_layer` need to be a `tf.keras.layers.Layer` instance. Received: )summulaveconcatNzInvalid merge mode. Received: zC. Merge mode should be one of {"sum", "mul", "ave", "concat", None}FT)go_backwardsforward_	backward_c                 B    t        | dd       | j                  | _        y y )Nzero_output_for_mask)getattrreturn_sequencesr   )layers    _/var/www/html/engine/venv/lib/python3.12/site-packages/tf_keras/src/layers/rnn/bidirectional.pyforce_zero_output_for_maskz:Bidirectional.__init__.<locals>.force_zero_output_for_mask   s&    u4d;G-2-C-C* H       	trainabler   )
isinstancer   
ValueError_setattr_trackingsuper__init___recreate_layer_from_configforward_layerbackward_layerr   serialize_keras_object_backward_layer_configname_name_verify_layer_config
merge_modeleninitial_weightsstatefulr   return_statesupports_maskinggetr    
_trainable_num_constants
input_spec)	selfr   r.   weightsr(   kwargsr   nw	__class__s	           r   r%   zBidirectional.__init__m   s    %'??DgG  %j.O''5&68  BB0 =8 8  "')&)!% "==eD!"&"B"BD #C #D #1D "88H ' $.0B0B0G0G#G $/$2E2E2J2J$J!!!#	D
 	#4#5#56"4#6#67$WB18271CD.29"')2DD/ % 6 6!.. $ **[%//B**r   c                 .    | j                   j                  S N)r   !_use_input_spec_as_call_signature)r8   s    r   r?   z/Bidirectional._use_input_spec_as_call_signature   s    zz;;;r   c           
      n   | j                   j                  | j                  j                  k(  r9t        d| j                   j                   d| j                  j                         d}|D ]H  }t	        | j                   |      }t	        | j                  |      }||k7  s5t        d| d| d| d       y)	zBEnsure the forward and backward layers have valid common property.ziForward layer and backward layer should have different `go_backwards` value.forward_layer.go_backwards = z,backward_layer.go_backwards = )r1   r   r2   zTForward layer and backward layer are expected to have the same value for attribute "z", got "z" for forward layer and "z" for backward layerN)r'   r   r(   r"   r   )r8   common_attributesaforward_valuebackward_values        r   r-   z"Bidirectional._verify_layer_config   s    **d.A.A.N.NN0 %%223 41&&3346  M" 		A#D$6$6:M$T%8%8!<N. 556C 8% '&'';= 			r   c                    |j                         }|r	|d    |d<   dt        j                  |j                  j                        j
                  v ri }t        |dd       }|Z|j                  ||j                  j                  <   t        |dg       }|D ]%  }|j                  ||j                  j                  <   ' |j                  j	                  ||      S |j                  j	                  |      S )Nr   custom_objectscellcellsrF   )
get_configr
   getfullargspecr<   from_configargsr   __name__)r8   r   r   configrF   rG   stacked_cellscs           r   r&   z)Bidirectional._recreate_layer_from_config   s     !!#)/)?%?F>"(()D)DEJJK  N5&$/D:>..t~~667 'gr :& GA;<;;N1;;#7#78G??..~ /   ??..v66r   c                 T   | j                   j                  |      }| j                  r5t        j                  |dd  d      }t        j                  |d   d      }nt        j                  |d      }| j
                  dk(  r3|j                         }|dxx   dz  cc<   t        j                  |      }n#| j
                  |t        j                  |      g}| j                  rC| j
                  |z   t        j                  |      z   S |gz   t        j                  |      z   S |S )N   F)	to_tuplesr   r   r   )
r'   compute_output_shaper2   r   convert_shapesr.   as_listtfTensorShapecopy)r8   input_shapeoutput_shapestate_shapes       r   rV   z"Bidirectional.compute_output_shape   s   ))>>{K"11QR EK $22Q5L $22L ??h&'//1L!>>,7L__$($))L*ABL&#k1DIIk4JJJ >K/$))K2HHHr   c                 H   t        j                  |||| j                        \  }}}t        |t              rt        |      dkD  r|dd }|d   }||t        |   |fi |S g }g }|t        |      }|dz  dkD  rt        d|       ||d<   ||z  }t        j                  j                  d |      }|d|dz   | j                  _        ||dz  d | j                  _        ||z  }|||d<   ||z  }|D 	cg c]!  }	t        t!        j"                  |	      	      # }
}	|
| j                  _        |
| j                  _        ||
z  }t        |      | _        | j                  | j                  _        | j                  | j                  _        t!        j&                  t        j                  j)                  |      d         }t        j                  j)                  |      D ]%  }t!        j&                  |      |k7  st        d
       |r~|g|z   }t+        t        t        j                  j)                  |                  D cg c]  }d c}|z   }d|d<   d|d<   | j,                  }|| _        t        |   |fi |}|| _        |S t        |   |fi |S c c}	w c c}w )zN`Bidirectional.__call__` implements the same API as the wrapped
        `RNN`.rS   Nr   r   zWhen passing `initial_state` to a Bidirectional RNN, the state should be a list containing the states of the underlying RNNs. Received: initial_statec                 @    t        t        j                  |             S )Nshape)r   r   	int_shape)states    r   <lambda>z(Bidirectional.__call__.<locals>.<lambda>*  s    ig.?.?.FG r   	constantsrb   zThe initial state of a Bidirectional layer cannot be specified with a mix of TF-Keras tensors and non-Keras tensors (a "Keras tensor" is a tensor that was returned by a TF-Keras layer, or by `Input`))r   standardize_argsr6   r!   listr/   r$   __call__r"   rY   nestmap_structurer'   
state_specr(   r   r   rd   constants_specis_keras_tensorflattenranger7   )r8   inputsr`   rg   r:   additional_inputsadditional_specs
num_statesstate_specsconstantrn   ro   tensor
full_input_full_input_specoriginal_input_specoutputr<   s                     r   rj   zBidirectional.__call__
  s    ,5+E+EM9d.A.A,
(y fd#6{Q &qr
AYF Y%67#F5f55 $]+JA~! ! "/1  '4F?#.''//GK -88I*/,JD)-8q9J-KD*+ "+F;* !*  1 1( ;<N  1?D-1?D.."%i.D040C0CD-151D1DD.!11GGOO-.q1
 ggoo&78 	F&&v./A D 	  $55J $C(?$@A !O '+F?#"&F; #'//-DOW%j;F;F1DOM7#F5f55Y<s   9&J	Jc                    i }t        j                  | j                  j                  d      r||d<   t        j                  | j                  j                  d      r||d<   t        j                  | j                  j                  d      r||d<   t        j                  | j                  j                  d      r t	        |t
              rt        |      dkD  r|d   g}|d   g}t        |      | j                  z
  dz  dz   }	||d|	 z  }| j                  s	|||	d z  }n9|||	| j                    z  }||| j                   d z  }||| j                   d z  }d	\  }
}d|v r.d|d<   n(|||}}t        |      dz  }|d| }
||d }n	||}}d	\  }
} | j                  |fd|
i|} | j                  |fd|i|}n& | j                  |fi |} | j                  |fi |}| j                  r|dd |dd z   }|d   }|d   }| j                  r1t        | j                  d
d      rdnd}t        j                  ||      }| j                  dk(  rt        j                   ||g      }nl| j                  dk(  r||z   }nW| j                  dk(  r	||z   dz  }n?| j                  dk(  r||z  }n*| j                  ||g}nt#        d| j                   d      | j                  r| j                  |z   S |gz   S |S )zB`Bidirectional.call` implements the same API as the wrapped `RNN`.trainingmaskrg   r`   rS   r   r   NNN
time_majorFr   r   r   r   z/Unrecognized value for `merge_mode`. Received: z3Expected values are ["concat", "sum", "ave", "mul"])r	   has_argr   callr!   ri   r/   r6   r'   r(   r2   r   r   r   reverser.   concatenater"   )r8   rr   r   r   r`   rg   r:   forward_inputsbackward_inputspivotforward_statebackward_statehalfyy_revstatestime_dimr}   s                     r   r   zBidirectional.calla  sa      *=!)F:  &9!F6N  +>"+F;  /B&$'CK!O
 #))#)!9+Vt':'::q@1D&5/1**#vef~5O $vet7J7J6J'KKO"fd.A.A-A-C&DDN#vt/B/B.B.D'EEO0:-~&(*.F;'*
 39&=)Q. -et 4!.tu!528&0:-~""".;?EA (D''/=AGE #""64V4A'D''9&9EqrUU12Y&F!A!HE  T//uE1  OOE84E??h&((!U4F__%YF__%%i1_F__%YF__$ZF!__-EF  &&8f$$r   c                 |   | j                   st        d      |5| j                  j                          | j                  j                          y t        |t        t        f      st        d|       t        |      dz  }| j                  j                  |d |        | j                  j                  ||d         y )NzLayer must be stateful.zRUnrecognized value for `states`. Expected `states` to be list or tuple. Received: r   )
r1   AttributeErrorr'   reset_statesr(   r!   ri   tupler"   r/   )r8   r   r   s      r   r   zBidirectional.reset_states  s    }} !:;;>++-,,.ftUm4 !!'*  v;!#D++F5DM:,,VDE];r   c                    t        j                  | j                  j                        5  | j                  j	                  |       d d d        t        j                  | j
                  j                        5  | j
                  j	                  |       d d d        t        j                  | |       y # 1 sw Y   mxY w# 1 sw Y   ,xY wr>   )r   
name_scoper'   r+   buildr(   r   )r8   r\   s     r   r   zBidirectional.build  s     2 2 7 78 	2$$[1	2 3 3 8 89 	3%%k2	3 	D+&	2 	2	3 	3s   B27B>2B;>Cc                 B   t        |t              r|d   }| j                  r| j                  s||g}n|}n| j                  sd d gnd }| j                  rF| j
                  j                  }|D cg c]  }d  }}t        |t              r||dz  z   S |g|dz  z   S |S c c}w )Nr   r   )r!   ri   r   r.   r2   r'   r   )r8   rr   r   output_maskr   rz   
state_masks          r   compute_maskzBidirectional.compute_mask  s    dD!7D  ??#Tl".2oo4,4K''..F(./1$/J/+t,"Z!^33=:>11	 0s   .	Bc                     i }t        | j                  d      rJ|j                  | j                  j                         |j                  | j                  j                         |S )Nconstraints)hasattrr'   updater   r(   )r8   r   s     r   r   zBidirectional.constraints  sQ    4%%}5t11==>t22>>?r   c                     d| j                   i}| j                  r| j                  |d<   t        | d      r| j                  |d<   t        |          }t        t        |j                               t        |j                               z         S )Nr.   num_constantsr*   r(   )	r.   r6   r   r*   r$   rJ   dictri   items)r8   rO   base_configr<   s      r   rJ   zBidirectional.get_config  s|    0&*&9&9F?#412'+'B'BF#$g(*D**,-V\\^0DDEEr   c                     t        j                  |      }|j                  dd      }ddlm}  ||d   |      |d<   |j                  dd       }| |||      }||d<    | di |}||_        |S )Nr   r   )deserializer   rI   r(    )r[   deepcopypoptf_keras.src.layersr   r6   )clsrO   rF   r   deserialize_layerbackward_layer_configr(   r   s           r   rL   zBidirectional.from_config  s     v&

?A6H+7ON
w !'

+;T B ,.%nN (6F#$f,r   )r   NN)Fr   )NNNNr>   )rN   
__module____qualname____doc__r%   propertyr?   r-   r&   r   shape_type_conversionrV   rj   r   r   r   r   r   rJ   classmethodrL   __classcell__)r<   s   @r   r   r   $   s    ET H+T < <076 ## $6U6t ^@<&'&  F  r   r   )r   r[   tensorflow.compat.v2compatv2rY   tf_keras.srcr   tf_keras.src.engine.base_layerr   tf_keras.src.engine.input_specr   tf_keras.src.layers.rnnr   $tf_keras.src.layers.rnn.base_wrapperr   tf_keras.src.savingr   tf_keras.src.utilsr	   r
   r    tensorflow.python.util.tf_exportr   r   r   r   r   <module>r      sY    &  ! !   0 4 - 8 1 , ) ' : *+qG q ,qr   