
    2Vh3                     t    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	  ed       G d d	e             Z
y)
    N)ops)utils)keras_export)Layer)serialization_libzkeras.layers.Bidirectionalc                        e Zd ZdZ	 	 	 d fd	Zd ZddZ	 	 	 ddZd Zd Z	e
d        Zdd	Zd
 Z fdZedd       Z xZS )Bidirectionala~  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 `return_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. Defaults to `"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.

    Note: instantiating a `Bidirectional` layer from an existing RNN layer
    instance will not reuse the weights state of the RNN layer instance -- the
    `Bidirectional` layer will have freshly initialized weights.

    Examples:

    ```python
    model = Sequential([
        Input(shape=(5, 10)),
        Bidirectional(LSTM(10, return_sequences=True),
        Bidirectional(LSTM(10)),
        Dense(5, activation="softmax"),
    ])
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

    # With custom backward layer
    forward_layer = LSTM(10, return_sequences=True)
    backward_layer = LSTM(10, activation='relu', return_sequences=True,
                          go_backwards=True)
    model = Sequential([
        Input(shape=(5, 10)),
        Bidirectional(forward_layer, backward_layer=backward_layer),
        Dense(5, 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      t        	|   di | t        j                  |      }dt        j                  |j                  d      z   |d   d<   t        j                  |      | _        |at        j                  |      }d	|d   d
<   dt        j                  |j                  d      z   |d   d<   t        j                  |      | _        n|| _        | j                          d } || j                          || j                         || _        |r9t        |      }|d |dz   | j                  _        ||dz  d  | j                  _        |j"                  | _        |j$                  | _        |j&                  | _        d	| _        |j*                  | _        y )NzXPlease initialize `Bidirectional` layer with a `keras.layers.Layer` instance. Received: zG`backward_layer` need to be a `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}forward_confignameTgo_backwards	backward_c                 B    t        | dd       | j                  | _        y y )Nzero_output_for_mask)getattrreturn_sequencesr   )layers    R/home/dcms/DCMS/lib/python3.12/site-packages/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        )
isinstancer   
ValueErrorsuper__init__r   serialize_keras_objectr   removeprefixr   deserialize_keras_objectforward_layerbackward_layer_verify_layer_config
merge_modeleninitial_weightsstatefulr   return_statesupports_masking
input_spec)
selfr   r(   weightsr&   kwargsr   r   nw	__class__s
            r   r!   zBidirectional.__init__S   s    %'<<A7D  %j.O''5&68  BB0 =8 8 
 	"6" #99%@#-0B0BJJ
1
 $
x  /GGO!&==eDF/3F8^,'2U5G5G

K6 (F8V$ #4"L"L#D #1D!!#	D
 	#4#5#56"4#6#67$WB18271CD.29"')2DD/ % 6 6!.. $**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.zrForward layer and backward layer should have different `go_backwards` value. Received: forward_layer.go_backwards z, backward_layer.go_backwards=)r+   r   r,   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'   z"Bidirectional._verify_layer_config   s    **d.A.A.N.NN. %%223 4/&&3346  M" 		A#D$6$6:M$T%8%8!<N. 556C 8% '&'';= 			r   c                 v   | j                   j                  |      }| j                  r
|d   |dd  }}| j                  dk(  r$t	        |      }|dxx   dz  cc<   t        |      }n| j                  ||g}| j                  r/| j                  t        |      z   |z   S t        |g      z   |z   S t        |      S )Nr      r   r   )r%   compute_output_shaper,   r(   listtuple)r/   sequences_shapeinitial_state_shapeoutput_shapestate_shapes        r   r<   z"Bidirectional.compute_output_shape   s    ))>>O(4Qab9I+L??h&-L! .L__$(,7L&\*[8;FF,(K8KHH\""r   c                    i }| j                   j                  r||d<   | j                   j                  r||d<   |||}}t        |      dz  }|d | }	||d  }
n	||}}d\  }	}
 | j                   |fd|	i|} | j                  |fd|
i|}| j
                  rt        |dd  |dd  z         }|d   }|d   }t        j                  || j                        }t        j                  || j                        }| j                  rt        j                  |d      }| j                  d	k(  rt        j                  ||gd
      }nl| j                  dk(  r||z   }nW| j                  dk(  r	||z   dz  }n?| j                  dk(  r||z  }n*| j                  ||f}nt        d| j                   d      | j
                  r| j                  |z   S |fz   S |S )Ntrainingmaskr   NNinitial_stater:   r   )axisr   r;   r   r   r   z/Unrecognized value for `merge_mode`. Received: z0Expected one of {"concat", "sum", "ave", "mul"}.)r%   _call_has_training_arg_call_has_mask_argr)   r&   r,   r>   r   castcompute_dtyper   flipr(   concatenater   )r/   	sequencesrG   rE   rD   r1   forward_inputsbackward_inputshalfforward_statebackward_stateyy_revstatesoutputs                  r   callzBidirectional.call   s    44!)F:00!F6N$
 /8ON}%*D)%40M*451N.7ON,6)M>D
*7
;A
 $##
+9
=C
 1QR559,-F!A!HEHHQ**+ 2 23  HHU+E??h&__aZb9F__%YF__%%i1_F__%YF__$ZF!__-BC 
 &&9v%%r   c                 $    | j                          y N)reset_stater/   s    r   reset_stateszBidirectional.reset_states  s    r   c                     | j                   st        d      | j                  j                          | j                  j                          y )NzLayer must be stateful.)r+   AttributeErrorr%   r\   r&   r]   s    r   r\   zBidirectional.reset_state  s9    }} !:;;&&('')r   c                     | j                   j                  rL| j                  j                  r6t        | j                   j                  | j                  j                  z         S y r[   )r%   rW   r&   r>   r]   s    r   rW   zBidirectional.states  sJ    $$)<)<)C)C++22T5H5H5O5OOPPr   c                     | j                   j                  s| j                   j                  |       | j                  j                  s| j                  j                  |       y y r[   )r%   builtbuildr&   )r/   r?   r@   s      r   rd   zBidirectional.build  sM    !!''$$_5""((%%o6 )r   c                 (   t        |t              r|d   }| j                  r| j                  s||f}n|}n| j                  sdnd }| j                  r@| j
                  4d | j
                  D        }t        |t              r||dz  z   S |f|dz  z   S |S )Nr   rF   c              3       K   | ]  }d   y wr[   r   ).0_s     r   	<genexpr>z-Bidirectional.compute_mask.<locals>.<genexpr>#  s     41$4s   r   )r   r=   r   r(   r,   rW   )r/   rh   rE   output_mask
state_masks        r   compute_maskzBidirectional.compute_mask  s    dD!7D  ??#Tl".2oo,4K!844J+t,"Z!^33>JN22r   c                     d| j                   i}t        j                  | j                        |d<   t        j                  | j                        |d<   t
        |          }i ||S )Nr(   r   r&   )r(   r   r"   r%   r&   r    
get_config)r/   r   base_configr3   s      r   rn   zBidirectional.get_config)  sn    0+BB
w $5#K#K$
  g(*(+(((r   c                     t        j                  |      }t        j                  |d   |      |d<   |j	                  dd       }|t        j                  ||      }||d<    | di |}|S )Nr   )custom_objectsr&   r   )copydeepcopyr   r$   pop)clsr   rq   backward_layer_configr&   r   s         r   from_configzBidirectional.from_config4  s{     v&+DD7ON
w !'

+;T B ,.GG%nN (6F#$fr   )r   NNr[   )NNN)__name__
__module____qualname____doc__r!   r'   r<   rY   r^   r\   propertyrW   rd   rl   rn   classmethodrw   __classcell__)r3   s   @r   r	   r	   
   sx    ET @+D0#, ?B*  
7$	)  r   r	   )rr   	keras.srcr   r   keras.src.api_exportr   keras.src.layers.layerr   keras.src.savingr   r	   r   r   r   <module>r      s;       - ( . *+zE z ,zr   