o
    Ne"                     @   s   d 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 ejZejZed	G d
d dejZdS )z*Keras hashed crossing preprocessing layer.    N)backend)
base_layer)base_preprocessing_layer)preprocessing_utils)layer_utils)keras_exportz6keras.layers.experimental.preprocessing.HashedCrossingc                       sV   e Zd ZdZd fdd	Zdd Zdd	 Zd
d Z fddZdd Z	dd Z
  ZS )HashedCrossinga  A preprocessing layer which crosses features using the "hashing trick".

    This layer performs crosses of categorical features using the "hasing
    trick".  Conceptually, the transformation can be thought of as:
    hash(concatenation of features) % `num_bins`.

    This layer currently only performs crosses of scalar inputs and batches of
    scalar inputs. Valid input shapes are `(batch_size, 1)`, `(batch_size,)` and
    `()`.

    For an overview and full list of preprocessing layers, see the preprocessing
    [guide](https://www.tensorflow.org/guide/keras/preprocessing_layers).

    Args:
      num_bins: Number of hash bins.
      output_mode: Specification for the output of the layer. Defaults to
        `"int"`.  Values can be `"int"`, or `"one_hot"` configuring the layer as
        follows:
          - `"int"`: Return the integer bin indices directly.
          - `"one_hot"`: Encodes each individual element in the input into an
            array the same size as `num_bins`, containing a 1 at the input's bin
            index.
      sparse: Boolean. Only applicable to `"one_hot"` mode. If True, returns a
        `SparseTensor` instead of a dense `Tensor`. Defaults to False.
      **kwargs: Keyword arguments to construct a layer.

    Examples:

    **Crossing two scalar features.**

    >>> layer = tf.keras.layers.experimental.preprocessing.HashedCrossing(
    ...     num_bins=5)
    >>> feat1 = tf.constant(['A', 'B', 'A', 'B', 'A'])
    >>> feat2 = tf.constant([101, 101, 101, 102, 102])
    >>> layer((feat1, feat2))
    <tf.Tensor: shape=(5,), dtype=int64, numpy=array([1, 4, 1, 1, 3])>

    **Crossing and one-hotting two scalar features.**

    >>> layer = tf.keras.layers.experimental.preprocessing.HashedCrossing(
    ...     num_bins=5, output_mode='one_hot')
    >>> feat1 = tf.constant(['A', 'B', 'A', 'B', 'A'])
    >>> feat2 = tf.constant([101, 101, 101, 102, 102])
    >>> layer((feat1, feat2))
    <tf.Tensor: shape=(5, 5), dtype=float32, numpy=
      array([[0., 1., 0., 0., 0.],
             [0., 0., 0., 0., 1.],
             [0., 1., 0., 0., 0.],
             [0., 1., 0., 0., 0.],
             [0., 0., 0., 1., 0.]], dtype=float32)>
    intFc                    s   d|vs
|d d u r|t krtjnt |d< t jdi | tj	d
d |t kr?t| jjs?|d }td| tj|t tf| jjdd || _|| _|| _d S )Ndtyper   TzMWhen `output_mode='int'`, `dtype` should be an integer type. Received: dtype=output_mode)Zallowable_stringsZ
layer_nameZarg_name )INTtfZint64r   Zfloatxsuper__init__r   Zkeras_kpl_gaugeZget_cellsetZas_dtypecompute_dtype
is_integer
ValueErrorr   Zvalidate_string_argONE_HOT	__class____name__num_binsr   sparse)selfr   r   r   kwargsZinput_dtyper   r   ZD:\Projects\ConvertPro\env\Lib\site-packages\keras/layers/preprocessing/hashed_crossing.pyr   W   s2   
zHashedCrossing.__init__c                 C   s   |  | dd |D }| | |d jj}|dk r"dd |D }|dk r-dd |D }tj|| j}tj|}|dkrHt	|ddg}n|dkrTt	|dg}n
|dkr^t	|g }t
j|| j| j| j| jd	S )
Nc                 S   s   g | ]}t |qS r   )utilsZensure_tensor.0xr   r   r   
<listcomp>~       z'HashedCrossing.call.<locals>.<listcomp>r      c                 S      g | ]}t |d qS r   Zexpand_dimsr   r   r   r   r"             c                 S   r%   r&   r(   r   r   r   r   r"      r)   r'   )r   depthr   r
   )_check_at_least_two_inputs_check_input_shape_and_typeshaperankr   r   Zcross_hashedr   Zto_denseZreshaper   Zencode_categorical_inputsr   r   )r   inputsr/   Zoutputsr   r   r   callz   s.   

zHashedCrossing.callc                 C   s   |  | t|d S )Nr   )r,   r   Z$compute_shape_for_encode_categorical)r   input_shapesr   r   r   compute_output_shape   s   
z#HashedCrossing.compute_output_shapec                 C   sP   dd |D }|  |}| jstdd |D r tj|| jdS tj|| jdS )Nc                 S   s   g | ]}|j  qS r   r.   as_listr   r   r   r   r"      r#   z;HashedCrossing.compute_output_signature.<locals>.<listcomp>c                 s   s    | ]	}t |tjV  qd S N)
isinstancer   SparseTensorSpecr   r   r   r   	<genexpr>   s    
z:HashedCrossing.compute_output_signature.<locals>.<genexpr>)r.   r
   )r3   r   anyr   r8   r   Z
TensorSpec)r   Zinput_specsr2   Zoutput_shaper   r   r   compute_output_signature   s   
z'HashedCrossing.compute_output_signaturec                    s&   t   }|| j| j| jd |S )N)r   r   r   )r   
get_configupdater   r   r   )r   configr   r   r   r<      s   
zHashedCrossing.get_configc                 C   s:   t |ttfstd| t|dk rtd| d S )NzQ`HashedCrossing` should be called on a list or tuple of inputs. Received: inputs=r$   zK`HashedCrossing` should be called on at least two inputs. Received: inputs=)r7   listtupler   len)r   r0   r   r   r   r,      s   z)HashedCrossing._check_at_least_two_inputsc                    s   |d j   t }|dks|dkr  d dkr td| t fdd|dd  D s6td| td	d |D rFtd
| tdd |D sVtd| d S )Nr   r$   r'   r*   zjAll `HashedCrossing` inputs should have shape `[]`, `[batch_size]` or `[batch_size, 1]`. Received: inputs=c                 3   s    | ]
}|j   kV  qd S r6   r4   r   Zfirst_shaper   r   r9      s    z=HashedCrossing._check_input_shape_and_type.<locals>.<genexpr>zFAll `HashedCrossing` inputs should have equal shape. Received: inputs=c                 s   s"    | ]}t |tjtjfV  qd S r6   )r7   r   ZRaggedTensorZSparseTensorr   r   r   r   r9      s    
zFAll `HashedCrossing` inputs should be dense tensors. Received: inputs=c                 s   s$    | ]}|j jp|j tjkV  qd S r6   )r
   r   r   stringr   r   r   r   r9      s   " zUAll `HashedCrossing` inputs should have an integer or string dtype. Received: inputs=)r.   r5   rA   r   allr:   )r   r0   r/   r   rB   r   r-      s:   z*HashedCrossing._check_input_shape_and_type)r	   F)r   
__module____qualname____doc__r   r1   r3   r;   r<   r,   r-   __classcell__r   r   r   r   r   !   s    4#&r   )rG   Ztensorflow.compat.v2compatv2r   Zkerasr   Zkeras.enginer   r   Zkeras.layers.preprocessingr   r   Zkeras.utilsr   Z tensorflow.python.util.tf_exportr   r   r   ZLayerr   r   r   r   r   <module>   s   