o
    i eX                     @   s   d Z ddlZddlm  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 deZdS )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                       s   e Zd ZdZ			d fdd	Zedd Zdd	 Zd ddZe	j
dd Zd! fdd	Z				d"ddZd#ddZdd Zdd Zedd Z fddZed#ddZ  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')
    ```
    concatNc                    sf  t |tstd| |d urt |tstd| |dvr(td| dd| _t j|fi | d| _| || _|d u rK| j|dd| _n	|| _t	
|| _d	| jj | j_d
| jj | j_|   dd }|| j || j || _|rt|}|d |d  | j_||d d  | j_|j| _|j| _|j| _d| _|d|j| _d| _|j| _d S )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aver   NzInvalid merge mode. Received: zC. Merge mode should be one of {"sum", "mul", "ave", "concat", None}FT)go_backwardsforward_	backward_c                 S   s    t | dd d ur| j| _d S d S )Nzero_output_for_mask)getattrreturn_sequencesr   )layer r   Q/var/www/myenv/lib/python3.10/site-packages/keras/src/layers/rnn/bidirectional.pyforce_zero_output_for_mask   s   z:Bidirectional.__init__.<locals>.force_zero_output_for_mask   	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__r   r   r!   m   sZ   




zBidirectional.__init__c                 C   s   | j jS N)r   !_use_input_spec_as_call_signature)r4   r   r   r   r;      s   z/Bidirectional._use_input_spec_as_call_signaturec              	   C   sz   | j j| jjkrtd| j j d| jj d}|D ] }t| j |}t| j|}||kr:td| d| d| dqdS )	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 = )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   )r4   common_attributesaforward_valuebackward_valuer   r   r   r)      s0   	z"Bidirectional._verify_layer_configFc                 C   s   |  }|r|d  |d< dt|jjjv rDi }t|dd }|d ur<|j||jj< t|dg }|D ]	}|j||jj< q2|jj||dS |j|S )Nr   custom_objectscellcellsr@   )
get_configr	   getfullargspecr9   from_configargsr   __name__)r4   r   r   configr@   rA   stacked_cellscr   r   r   r"      s"   z)Bidirectional._recreate_layer_from_configc                 C   s   | j |}| jrtj|dd  dd}tj|d dd}ntj|dd}| jdkr<| }|d  d9  < t|}n| jd u rH|t		|g}| jrc| jd u rY|| t		| S |g| t		| S |S )N   F)	to_tuplesr   r   r   )
r#   compute_output_shaper.   r
   convert_shapesr*   as_listtfTensorShapecopy)r4   input_shapeoutput_shapestate_shaper   r   r   rO      s,   


z"Bidirectional.compute_output_shapec                    s  t |||| j\}}}t|tr!t|dkr|dd }|d }|du r3|du r3t j|fi |S g }g }|durut|}|d dkrLtd| ||d< ||7 }t	j
dd |}|d|d  | j_||d d | j_||7 }|dur||d	< ||7 }d
d |D }	|	| j_|	| j_||	7 }t|| _| j| j_| j| j_tt	j
|d }
t	j
|D ]}t||
krtdq|
r|g| }dd ttt	j
|D | }d|d< d|d	< | j}|| _t j|fi |}|| _|S t j|fi |S )zN`Bidirectional.__call__` implements the same API as the wrapped
        `RNN`.rL   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                 S   s   t t| dS )Nshaper   r   	int_shape)stater   r   r   <lambda>*      z(Bidirectional.__call__.<locals>.<lambda>	constantsc                 S   s   g | ]
}t t|d qS )rY   r[   ).0constantr   r   r   
<listcomp>3  s    z*Bidirectional.__call__.<locals>.<listcomp>zThe initial state of a Bidirectional layer cannot be specified with a mix of Keras tensors and non-Keras tensors (a "Keras tensor" is a tensor that was returned by a Keras layer, or by `Input`)c                 S      g | ]}d qS r:   r   ra   _r   r   r   rc   Q  s    )r   standardize_argsr2   r   listr+   r    __call__r   rR   nestmap_structurer#   
state_specr$   constants_specr   is_keras_tensorflattenranger3   )r4   inputsrX   r`   r6   additional_inputsadditional_specs
num_statesstate_specsrm   rn   tensor
full_inputfull_input_specoriginal_input_specoutputr8   r   r   ri   
  s   





	
zBidirectional.__call__c                 C   s  i }t | jjdr||d< t | jjdr||d< t | jjdr&||d< t | jjdrt|trt|dkr|d g}|d g}t|| j d d }	||d|	 7 }| jsb|||	d 7 }n|||	| j  7 }||| j d 7 }||| j d 7 }d	\}
}d|v rd|d< n%|dur||}}t|d }|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  }|d }|d }| jrt| jd
drdnd}t||}| jdkrt||g}n7| jdkr || }n,| jdkr-|| d }n| jdkr8|| }n| jdu rC||g}n	td| j d| j
r_| jdu rZ|| S |g| S |S )zB`Bidirectional.call` implements the same API as the wrapped `RNN`.trainingmaskr`   rX   rL   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   rh   r+   r2   r#   r$   r.   r   r   r   reverser*   concatenater   )r4   rq   r{   r|   rX   r`   r6   forward_inputsbackward_inputspivotforward_statebackward_statehalfyy_revstatestime_dimrz   r   r   r   r   a  s   	







zBidirectional.callc                 C   s   | j std|d u r| j  | j  d S t|ttfs%td| t	|d }| j|d |  | j||d   d S )NzLayer must be stateful.zRUnrecognized value for `states`. Expected `states` to be list or tuple. Received: r   )
r-   AttributeErrorr#   reset_statesr$   r   rh   tupler   r+   )r4   r   r   r   r   r   r     s   
zBidirectional.reset_statesc                 C   s~   t | jj | j| W d    n1 sw   Y  t | jj | j| W d    n1 s5w   Y  d| _d S )NT)r   
name_scoper#   r'   buildr$   built)r4   rU   r   r   r   r     s   
zBidirectional.buildc                 C   s   t |tr	|d }| jr| js||g}n|}n	| jsd d gnd }| jr@| jj}dd |D }t |tr9||d  S |g|d  S |S )Nr   c                 S   rd   r:   r   re   r   r   r   rc     r_   z.Bidirectional.compute_mask.<locals>.<listcomp>r   )r   rh   r   r*   r.   r#   r   )r4   rq   r|   output_maskr   
state_maskr   r   r   compute_mask  s   


zBidirectional.compute_maskc                 C   s0   i }t | jdr|| jj || jj |S )Nconstraints)hasattrr#   updater   r$   )r4   r   r   r   r   r     s
   zBidirectional.constraintsc                    sT   d| j i}| jr| j|d< t| dr| j|d< t  }tt| t|  S )Nr*   num_constantsr&   r$   )	r*   r2   r   r&   r    rD   dictrh   items)r4   rI   base_configr8   r   r   rD     s   




zBidirectional.get_configc                 C   sv   t |}|dd}ddlm} ||d |d|d< |dd }|d ur/|||d}||d< | di |}||_|S )Nr   r   )deserializer   rC   r$   r   )rT   deepcopypopkeras.src.layersr   r2   )clsrI   r@   r   deserialize_layerbackward_layer_configr$   r   r   r   r   rF      s   

zBidirectional.from_config)r   NN)Fr}   )NNNNr:   )rH   
__module____qualname____doc__r!   propertyr;   r)   r"   r
   shape_type_conversionrO   ri   r   r   r   r   r   rD   classmethodrF   __classcell__r   r   r8   r   r   $   s4    JJ


Z

`

r   )r   rT   tensorflow.compat.v2compatv2rR   	keras.srcr   keras.src.engine.base_layerr   keras.src.engine.input_specr   keras.src.layers.rnnr   !keras.src.layers.rnn.base_wrapperr   keras.src.savingr   keras.src.utilsr   r	   r
    tensorflow.python.util.tf_exportr   r   r   r   r   r   <module>   s   