o
    NeN                     @   s   d Z ddlZddlZddlm  mZ ddlm	Z	 dd Z
dddZdd
dZdd Z				d ddZdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )!z%Utilities used by convolution layers.    N)backendc                 C   s   | dkr|dkr
dS |dkrdS |dkrdS t d| d	| d
kr<|dkr(dS |dkr.dS |dkr4dS t d| d	t d|  d)Nchannels_last   ZNWC   ZNHWC   ZNDHWCzInput rank not supported: z. Expected values are [3, 4, 5]channels_firstZNCWZNCHWZNCDHWzInvalid data_format: z9. Expected values are ["channels_first", "channels_last"])
ValueError)data_formatndim r   FD:\Projects\ConvertPro\env\Lib\site-packages\keras/utils/conv_utils.pyconvert_data_format   s.   


r   Fc           	   
   C   s   d| d| d|  }t | tr| f| }n@zt| }W n ty'   t|w t||kr2t||D ]!}zt| W q4 ttfyU   |d| dt| 7 }t|w |rbdd |D }d}n	d	d |D }d
}|r||d| d| d7 }t||S )a  Transforms non-negative/positive integer/integers into an integer tuple.

    Args:
      value: The value to validate and convert. Could an int, or any iterable of
        ints.
      n: The size of the tuple to be returned.
      name: The name of the argument being validated, e.g. "strides" or
        "kernel_size". This is only used to format error messages.
      allow_zero: Default to False. A ValueError will raised if zero is received
        and this param is False.

    Returns:
      A tuple of n integers.

    Raises:
      ValueError: If something else than an int/long or iterable thereof or a
      negative value is
        passed.
    zThe `z` argument must be a tuple of z integers. Received: zincluding element z	 of type c                 S   s   h | ]}|d k r|qS r   r   .0vr   r   r   	<setcomp>f       z"normalize_tuple.<locals>.<setcomp>z>= 0c                 S   s   h | ]}|d kr|qS r   r   r   r   r   r   r   i   r   z> 0z including z( that does not satisfy the requirement `z`.)
isinstanceinttuple	TypeErrorr   lentype)	valuennameZ
allow_zero	error_msgZvalue_tupleZsingle_valueZunqualified_valuesZreq_msgr   r   r   normalize_tuple9   sJ   
r      c                 C   st   | du rdS |dv sJ ||d |d   }|dv r| }n|dkr(| | d }n
|dkr2| | d }|| d | S )a:  Determines output length of a convolution given input length.

    Args:
        input_length: integer.
        filter_size: integer.
        padding: one of "same", "valid", "full", "causal"
        stride: integer.
        dilation: dilation rate, integer.

    Returns:
        The output length (integer).
    N>   validcausalsamefullr   )r"   r!   r    r#   r   )input_lengthfilter_sizepaddingstridedilationZdilated_filter_sizeoutput_lengthr   r   r   conv_output_lengthv   s   r*   c                 C   s`   | du rdS |dv sJ |dkr|d }n|dkrd}n|dkr$|d }| d | d|  | S )	a  Determines input length of a convolution given output length.

    Args:
        output_length: integer.
        filter_size: integer.
        padding: one of "same", "valid", "full".
        stride: integer.

    Returns:
        The input length (integer).
    N>   r    r"   r#   r"      r    r   r#   r   r   )r)   r%   r&   r'   padr   r   r   conv_input_length   s   
r-   c                 C   s   |dv sJ | du rdS ||d |d   }|du rE|dkr+| | t || d }|S |dkr;| | || d  }|S |dkrC| | }|S |dkrN|d }n|dkrUd}n|dkr]|d }| d | | d|  | }|S )	a  Determines output length of a transposed convolution given input length.

    Args:
        input_length: Integer.
        filter_size: Integer.
        padding: one of `"same"`, `"valid"`, `"full"`.
        output_padding: Integer, amount of padding along the output dimension.
          Can be set to `None` in which case the output length is inferred.
        stride: Integer.
        dilation: Integer.

    Returns:
        The output length (integer).
    >   r    r"   r#   Nr   r    r   r#   r+   r"   )max)r$   r%   r&   Zoutput_paddingr'   r(   lengthr,   r   r   r   deconv_output_length   s.   
r0   c                 C   s2   | d u rt  } |  }|dvrtd|  |S )N>   r   r   zWThe `data_format` argument must be one of "channels_first", "channels_last". Received: )r   Zimage_data_formatlowerr   )r   r	   r   r   r   normalize_data_format   s   r2   c                 C   s4   t | ttfr	| S |  }|dvrtd| |S )N>   r    r!   r"   zqThe `padding` argument must be a list/tuple or one of "valid", "same" (or "causal", only for `Conv1D). Received: )r   listr   r1   r   )r   r&   r   r   r   normalize_padding   s   r4   c                 C   s   |dvrt d| dt| }t|tr|f| }t|tr$|f| }t|}t|}||ks4||krAtd| d| d| t| |||}| | }t|tj}	dd |D }
t	j
|
 D ]}t| ||||}t	j
| D ]}d	|	|| < qnq_|	S )
a  Compute a mask representing the connectivity of a convolution operation.

    Assume a convolution with given parameters is applied to an input having N
    spatial dimensions with `input_shape = (d_in1, ..., d_inN)` to produce an
    output with shape `(d_out1, ..., d_outN)`. This method returns a boolean
    array of shape `(d_in1, ..., d_inN, d_out1, ..., d_outN)` with `True`
    entries indicating pairs of input and output locations that are connected by
    a weight.

    Example:

      >>> input_shape = (4,)
      >>> kernel_shape = (2,)
      >>> strides = (1,)
      >>> padding = "valid"
      >>> conv_kernel_mask(input_shape, kernel_shape, strides, padding)
      array([[ True, False, False],
             [ True,  True, False],
             [False,  True,  True],
             [False, False,  True]])

      where rows and columns correspond to inputs and outputs respectively.


    Args:
      input_shape: tuple of size N: `(d_in1, ..., d_inN)`, spatial shape of the
        input.
      kernel_shape: tuple of size N, spatial shape of the convolutional kernel /
        receptive field.
      strides: tuple of size N, strides along each spatial dimension.
      padding: type of padding, string `"same"` or `"valid"`.
        `"valid"` means no padding. `"same"` results in padding evenly to
        the left/right or up/down of the input such that output has the same
        height/width dimension as the input.

    Returns:
      A boolean 2N-D `np.ndarray` of shape
      `(d_in1, ..., d_inN, d_out1, ..., d_outN)`, where `(d_out1, ..., d_outN)`
      is the spatial shape of the output. `True` entries in the mask represent
      pairs of input-output locations that are connected by a weight.

    Raises:
      ValueError: if `input_shape`, `kernel_shape` and `strides` don't have the
          same number of dimensions.
      NotImplementedError: if `padding` is not in {`"same"`, `"valid"`}.
    >   r    r"   Padding type 8 not supported. Only "valid" and "same" are implemented.UNumber of strides, input and kernel dimensions must all match. Received: stride_dims=
, in_dims=, kernel_dims=c                 S      g | ]}t |qS r   ranger   dimr   r   r   
<listcomp>@      z$conv_kernel_mask.<locals>.<listcomp>T)NotImplementedErrorr   r   r   r   conv_output_shapenpZzerosbool	itertoolsproductconv_connected_inputs)input_shapekernel_shapestridesr&   in_dimskernel_dimsstride_dimsoutput_shapeZ
mask_shapemaskoutput_axes_ticksoutput_positioninput_axes_ticksinput_positionr   r   r   conv_kernel_mask   sF   /





rT   c              	   c   sb   |dvrt d| dt| }t|tr|f| }t|tr%|f| }t|}t|}	||ks5|	|krBtd|	 d| d| t| |||}
dd |
D }|d	krYd
d }n|dkrbdd }ntd| dtj| D ]?}t| ||||}tj| D ]/}t	|D ](}t	|D ]!}t
j|||||
|d}t
j||||| |d}||fV  qqq~qodS )a'  Yields output-input tuples of indices in a CNN layer.

    The generator iterates over all `(output_idx, input_idx)` tuples, where
    `output_idx` is an integer index in a flattened tensor representing a single
    output image of a convolutional layer that is connected (via the layer
    weights) to the respective single input image at `input_idx`

    Example:

      >>> input_shape = (2, 2)
      >>> kernel_shape = (2, 1)
      >>> strides = (1, 1)
      >>> padding = "valid"
      >>> filters_in = 1
      >>> filters_out = 1
      >>> data_format = "channels_last"
      >>> list(conv_kernel_idxs(input_shape, kernel_shape, strides, padding,
      ...                       filters_in, filters_out, data_format))
      [(0, 0), (0, 2), (1, 1), (1, 3)]

    Args:
      input_shape: tuple of size N: `(d_in1, ..., d_inN)`, spatial shape of the
        input.
      kernel_shape: tuple of size N, spatial shape of the convolutional kernel /
        receptive field.
      strides: tuple of size N, strides along each spatial dimension.
      padding: type of padding, string `"same"` or `"valid"`.
        `"valid"` means no padding. `"same"` results in padding evenly to
        the left/right or up/down of the input such that output has the same
        height/width dimension as the input.
      filters_in: `int`, number if filters in the input to the layer.
      filters_out: `int', number if filters in the output of the layer.
      data_format: string, "channels_first" or "channels_last".

    Yields:
      The next tuple `(output_idx, input_idx)`, where `output_idx` is an integer
      index in a flattened tensor representing a single output image of a
      convolutional layer that is connected (via the layer weights) to the
      respective single input image at `input_idx`.

    Raises:
        ValueError: if `data_format` is neither `"channels_last"` nor
          `"channels_first"`, or if number of strides, input, and kernel number
          of dimensions do not match.

        NotImplementedError: if `padding` is neither `"same"` nor `"valid"`.
    )r"   r    r5   r6   r7   r8   r9   c                 S   r:   r   r;   r=   r   r   r   r?     r@   z$conv_kernel_idxs.<locals>.<listcomp>r   c                 S   s
   |f|  S Nr   Zspatial_idxZ
filter_idxr   r   r   <lambda>  s   
 z"conv_kernel_idxs.<locals>.<lambda>r   c                 S   s
   | |f S rU   r   rV   r   r   r   rW     s    zData format `zK` not recognized.`data_format` must be "channels_first" or "channels_last".)Zmulti_indexdimsN)rA   r   r   r   r   rB   rE   rF   rG   r<   rC   Zravel_multi_index)rH   rI   rJ   r&   Z
filters_inZfilters_outr	   rK   rL   rM   rN   rP   Zconcat_idxsrQ   rR   rS   Zf_inZf_outZout_idxZin_idxr   r   r   conv_kernel_idxsK  sl   8







rY   c                 C   s   g }t | }t|D ]8}t|| d }|| | }	|| ||  }
|dkr*|
|7 }
td|
| }t| | |
|	 }|t|| q
|S )a%  Return locations of the input connected to an output position.

    Assume a convolution with given parameters is applied to an input having N
    spatial dimensions with `input_shape = (d_in1, ..., d_inN)`. This method
    returns N ranges specifying the input region that was convolved with the
    kernel to produce the output at position
    `output_position = (p_out1, ..., p_outN)`.

    Example:

      >>> input_shape = (4, 4)
      >>> kernel_shape = (2, 1)
      >>> output_position = (1, 1)
      >>> strides = (1, 1)
      >>> padding = "valid"
      >>> conv_connected_inputs(input_shape, kernel_shape, output_position,
      ...                       strides, padding)
      [range(1, 3), range(1, 2)]

    Args:
      input_shape: tuple of size N: `(d_in1, ..., d_inN)`, spatial shape of the
        input.
      kernel_shape: tuple of size N, spatial shape of the convolutional kernel /
        receptive field.
      output_position: tuple of size N: `(p_out1, ..., p_outN)`, a single
        position in the output of the convolution.
      strides: tuple of size N, strides along each spatial dimension.
      padding: type of padding, string `"same"` or `"valid"`.
        `"valid"` means no padding. `"same"` results in padding evenly to
        the left/right or up/down of the input such that output has the same
        height/width dimension as the input.

    Returns:
      N ranges `[[p_in_left1, ..., p_in_right1], ...,
                [p_in_leftN, ..., p_in_rightN]]` specifying the region in the
      input connected to output_position.
    r+   r    r   )r   r<   r   r.   minappend)rH   rI   rQ   rJ   r&   rangesZndimsdZ
left_shiftZright_shiftcenterstartendr   r   r   rG     s   (rG   c                    s@   t t} fdd|D t fdd|D S )a  Return the output shape of an N-D convolution.

    Forces dimensions where input is empty (size 0) to remain empty.

    Args:
      input_shape: tuple of size N: `(d_in1, ..., d_inN)`, spatial shape of the
        input.
      kernel_shape: tuple of size N, spatial shape of the convolutional kernel /
        receptive field.
      strides: tuple of size N, strides along each spatial dimension.
      padding: type of padding, string `"same"` or `"valid"`.
        `"valid"` means no padding. `"same"` results in padding evenly to
        the left/right or up/down of the input such that output has the same
        height/width dimension as the input.

    Returns:
      tuple of size N: `(d_out1, ..., d_outN)`, spatial shape of the output.
    c                    s&   g | ]}t  | | | qS r   )r*   r   r]   )rH   rI   r&   rJ   r   r   r?     s    z%conv_output_shape.<locals>.<listcomp>c                    s$   g | ]} | d krd n| qS r   r   ra   )rH   rN   r   r   r?     s   $ )r<   r   r   )rH   rI   rJ   r&   rX   r   )rH   rI   rN   r&   rJ   r   rB     s   rB   c           
      C   s@  t d | j}|| d }| st | | d }|d|  }| s3t | d|  }t|t jrEt | dg|  }nt | t jdg|fdd}||}|j| d }| smt || d }t |t j||fdd}	|		| jd|  |	j| d   |	W  d   S 1 sw   Y  dS )a.  Returns `unsqueeze_batch(op(squeeze_batch(inp)))`.

    Where `squeeze_batch` reshapes `inp` to shape
    `[prod(inp.shape[:-inner_rank])] + inp.shape[-inner_rank:]`
    and `unsqueeze_batch` does the reverse reshape but on the output.

    Args:
      inp: A tensor with dims `batch_shape + inner_shape` where `inner_shape`
        is length `inner_rank`.
      op: A callable that takes a single input tensor and returns a single.
        output tensor.
      inner_rank: A python integer.

    Returns:
      `unsqueeze_batch_op(squeeze_batch(inp))`.
    squeeze_batch_dimsN)Zaxis)
tfZ
name_scopeshapeZis_fully_definedr   ZTensorShapeZreshapeas_listconcat	set_shape)
inpopZ
inner_rankre   Zinner_shapeZbatch_shapeZinp_reshapedZout_reshapedZout_inner_shapeoutr   r   r   rb     s.   &$rb   )F)r   )Nr   r   )__doc__rE   numpyrC   Ztensorflow.compat.v2compatv2rd   Zkerasr   r   r   r*   r-   r0   r2   r4   rT   rY   rG   rB   rb   r   r   r   r   <module>   s(   
 
=
4Vr<