
    6bi4X                         S r SSKrSSKJs  Jr  SSKJr  SSKJ	r	  SSK
Jr  SSKJr  SSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  SSKJr  \" S5       " S S\5      5       rg)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                      ^  \ rS rSrSr   SU 4S jjr\S 5       rS rSS jr	\
R                  S 5       rSU 4S jjr    SS	 jrSS
 jrS rS r\S 5       rU 4S jr\SS j5       rSrU =r$ )Bidirectional$   a]  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                   > [        U[        5      (       d  [        SU 35      eUb#  [        U[        5      (       d  [        SU 35      eUS;  a  [        SU S35      eSU l        [        TU ]  " U40 UD6  SU l        U R                  U5      U l        Uc  U R                  USS9U l        O!X@l        [        R                  " U5      U l        S	U R                  R                  -   U R                  l        S
U R                  R                  -   U R                  l        U R                  5         S nU" U R                  5        U" U R                  5        X l        U(       a8  [!        U5      nUS US-   U R                  l        X7S-  S  U R                  l        UR$                  U l        UR&                  U l        UR(                  U l        SU l        UR-                  SUR.                  5      U l        SU l        UR4                  U l        g )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                 D    [        U SS 5      b  U R                  U l        g g )Nzero_output_for_mask)getattrreturn_sequencesr   )layers    _/home/james-whalen/.local/lib/python3.13/site-packages/tf_keras/src/layers/rnn/bidirectional.pyforce_zero_output_for_mask: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   r0   weightsr*   kwargsr   nw	__class__s	           r   r'   Bidirectional.__init__m   s    %''??DgG  %j.O.O''5&68  BB0 =8 8  "')&)!% "==eD!"&"B"BD #C #D #1 "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                 .    U R                   R                  $ N)r   !_use_input_spec_as_call_signature)r:   s    r   rB   /Bidirectional._use_input_spec_as_call_signature   s    zz;;;r    c           
      t   U R                   R                  U R                  R                  :X  a9  [        SU R                   R                   SU R                  R                   35      eSnU HI  n[	        U R                   U5      n[	        U R                  U5      nX4:w  d  M6  [        SU SU SU S35      e   g)	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 = )r3   r   r4   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   )r:   common_attributesaforward_valuebackward_values        r   r/   "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                    UR                  5       nU(       a  US   (       + US'   S[        R                  " UR                  R                  5      R
                  ;   a  0 n[        USS 5      nUbZ  UR                  XER                  R                  '   [        US/ 5      nU H%  nUR                  XGR                  R                  '   M'     UR                  R	                  X4S9$ UR                  R	                  U5      $ )Nr   custom_objectscellcellsrK   )
get_configr
   getfullargspecr>   from_configargsr   __name__)r:   r   r   configrK   rL   stacked_cellscs           r   r(   )Bidirectional._recreate_layer_from_config   s     !!#)/)?%?F>"(()D)DEJJK  N5&$/D:>..~~667 'gr :&A;<;;N;;#7#78 '??.. /   ??..v66r    c                 j   U R                   R                  U5      nU R                  (       a1  [        R                  " USS  SS9n[        R                  " US   SS9nO[        R                  " USS9nU R
                  S:X  a4  UR                  5       nUS==   S-  ss'   [        R                  " U5      nO%U R
                  c  U[        R                  " U5      /nU R                  (       aF  U R
                  c  UW-   [        R                  " U5      -   $ U/W-   [        R                  " U5      -   $ U$ )N   F)	to_tuplesr   r   r!   )
r)   compute_output_shaper4   r   convert_shapesr0   as_listtfTensorShapecopy)r:   input_shapeoutput_shapestate_shapes       r   r\   "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  > [         R                  " XX0R                  5      u  pn[        U[        5      (       a  [        U5      S:  a  USS nUS   nUc  Uc  [        TU ]  " U40 UD6$ / n/ nUb|  [        U5      nUS-  S:  a  [        SU 35      eX$S'   XR-  n[        R                  R                  S U5      nUSUS-   U R                  l        XS-  S U R                  l        Xh-  nUb  X4S'   XS-  nU V	s/ s H   n	[        [         R"                  " U	5      S	9PM"     n
n	XR                  l        XR                  l        Xj-  n[        U5      U l        U R                  U R                  l        U R                  U R                  l        [         R&                  " [        R                  R)                  U5      S   5      n[        R                  R)                  U5       H(  n[         R&                  " U5      U:w  d  M  [        S
5      e   U(       a  U/U-   n[+        [        [        R                  R)                  U5      5      5       Vs/ s H  nSPM     snU-   nSUS'   SUS'   U R,                  nXl        [        TU ]  " U40 UD6nUU l        U$ [        TU ]  " U40 UD6$ s  sn	f s  snf )zF`Bidirectional.__call__` implements the same API as the wrapped
`RNN`.rY   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                 <    [        [        R                  " U 5      S9$ )Nshape)r   r   	int_shape)states    r   <lambda>(Bidirectional.__call__.<locals>.<lambda>*  s    ig.?.?.FGr    	constantsri   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_argsr8   r#   listr1   r&   __call__r$   r_   nestmap_structurer)   
state_specr*   r   r   rk   constants_specis_keras_tensorflattenranger9   )r:   inputsrg   ro   r<   additional_inputsadditional_specs
num_statesstate_specsconstantrv   rw   tensor
full_input_full_input_specoriginal_input_specoutputr>   s                     r   rr   Bidirectional.__call__
  s    ,5+E+E9.A.A,
(y fd##6{Q &qr
AYF Y%67#F5f55 $]+JA~! ! "/1  '4?#.''//GK -88I*/,JD)-8q9J-KD*+ "+;* !* )H  1 1( ;< )   1?-1?.."%i.D040C0CD-151D1DD.!11GGOO-.q1
 ggoo&78F&&v./A D  9  $55J $C(?$@AAA !O '+F?#"&F; #'//-OW%j;F;F1DOM7#F5f55Y<s   ='J*J/c                 H   0 n[         R                  " U R                  R                  S5      (       a  X&S'   [         R                  " U R                  R                  S5      (       a  X6S'   [         R                  " U R                  R                  S5      (       a  XVS'   [         R                  " U R                  R                  S5      (       Ga  [	        U[
        5      (       a  [        U5      S:  a  US   /nUS   /n[        U5      U R                  -
  S-  S-   n	XqSU	 -  nU R                  (       d  XU	S -  nO5XXR                  *  -  nXqU R                  * S -  nXU R                  * S -  nS	u  pSU;   a  SUS'   O#Ub  Xp[        U5      S-  nUSU n
XLS nOXpS	u  pU R                  " U4SU
0UD6nU R                  " U4SU0UD6nO&U R                  " U40 UD6nU R                  " U40 UD6nU R                  (       a  USS USS -   nUS   nUS   nU R                  (       a7  [        U R                  S
S5      (       a  SOSn[        R                  " UU5      nU R                  S:X  a  [        R                   " X/5      nOlU R                  S:X  a  X-   nOWU R                  S:X  a  X-   S-  nO?U R                  S:X  a  X-  nO*U R                  c  X/nO[#        SU R                   S35      eU R                  (       a  U R                  c  UW-   $ U/W-   $ U$ )zB`Bidirectional.call` implements the same API as the wrapped `RNN`.trainingmaskro   rg   rY   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#   rq   r1   r8   r)   r*   r4   r   r   r   reverser0   concatenater$   )r:   rz   r   r   rg   ro   r<   forward_inputsbackward_inputspivotforward_statebackward_statehalfyy_revstatestime_dimr   s                     r   r   Bidirectional.calla  sB      *==!):  &99!6N  +>>"+;  /BB&$''CK!O
 #))#)!9+Vt':'::q@1D5/1**#ef~5O $e7J7J6J'KKO"d.A.A-A-C&DDN#t/B/B.B.D'EEO0:-&(*.F;'*
 39=)Q. -et 4!.u!5280:-"".;?EA ''/=AGE ""64V4A''9&9EqrUU12Y&F!A!HE  T//uEE1  OOE84E??h&((!4F__%YF__%i1_F__%YF__$ZF!__-EF  &&8f$$r    c                    U R                   (       d  [        S5      eUc5  U R                  R                  5         U R                  R                  5         g [        U[        [        45      (       d  [        SU 35      e[        U5      S-  nU R                  R                  US U 5        U R                  R                  XS  5        g )NzLayer must be stateful.zRUnrecognized value for `states`. Expected `states` to be list or tuple. Received: r!   )
r3   AttributeErrorr)   reset_statesr*   r#   rq   tupler$   r1   )r:   r   r   s      r   r   Bidirectional.reset_states  s    }} !:;;>++-,,.ftUm44 !!'*  v;!#D++F5DM:,,VE];r    c                    [         R                  " U R                  R                  5         U R                  R	                  U5        S S S 5        [         R                  " U R
                  R                  5         U R
                  R	                  U5        S S S 5        SU l        g ! , (       d  f       Nd= f! , (       d  f       N'= f)NT)r   
name_scoper)   r-   buildr*   built)r:   rb   s     r   r   Bidirectional.build  s     2 2 7 78$$[1 9 3 3 8 89%%k2 :
	 9899s   B%9B6%
B36
Cc                    [        U[        5      (       a  US   nU R                  (       a  U R                  (       d  X"/nOUnOU R                  (       d  S S /OS nU R                  (       aM  U R
                  R                  nU Vs/ s H  nS PM     nn[        U[        5      (       a  X6S-  -   $ U/US-  -   $ U$ s  snf )Nr   r!   )r#   rq   r   r0   r4   r)   r   )r:   rz   r   output_maskr   r   
state_masks          r   compute_maskBidirectional.compute_mask  s    dD!!7D  ??#l".2oo4,4K''..F(./1$J/+t,,"!^33=:>11	 0s   B;c                     0 n[        U R                  S5      (       aJ  UR                  U R                  R                  5        UR                  U R                  R                  5        U$ )Nconstraints)hasattrr)   updater   r*   )r:   r   s     r   r   Bidirectional.constraints  sT    4%%}55t11==>t22>>?r    c                 4  > SU R                   0nU R                  (       a  U R                  US'   [        U S5      (       a  U R                  US'   [        TU ]  5       n[        [        UR                  5       5      [        UR                  5       5      -   5      $ )Nr0   num_constantsr,   r*   )	r0   r8   r   r,   r&   rO   dictrq   items)r:   rT   base_configr>   s      r   rO   Bidirectional.get_config  s    0&*&9&9F?#4122'+'B'BF#$g(*D**,-V\\^0DDEEr    c                     [         R                  " U5      nUR                  SS5      nSSKJn  U" US   US9US'   UR                  SS 5      nUb
  U" XRS9nXaS'   U " S0 UD6nX7l        U$ )Nr   r   )deserializer   rN   r*    )ra   deepcopypoptf_keras.src.layersr   r8   )clsrT   rK   r   deserialize_layerbackward_layer_configr*   r   s           r   rQ   Bidirectional.from_config   s     v&

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

+;T B ,.%N (6#$f,r    )r,   r8   r%   r7   r*   r   r)   r9   r0   r   r4   r3   r5   )r   NN)Fr   )NNNNrA   )rS   
__module____qualname____firstlineno____doc__r'   propertyrB   r/   r(   r   shape_type_conversionr\   rr   r   r   r   r   r   rO   classmethodrQ   __static_attributes____classcell__)r>   s   @r   r   r   $   s    ET H+T < <076 ## $6U6t ^@<&&  F  r    r   )r   ra   tensorflow.compat.v2compatv2r_   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 , ) ' : *+pG p ,pr    