o
    ?e1                     @   s   d Z 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	 ddlm
Z
 dd	lmZ dd
lmZ ddlmZ dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zedg dd"ddZd d! ZdS )#z|Gradient checker for functions.

The gradient checker verifies numerically that an function properly
computes the gradients
    N)backprop)context)dtypes)indexed_slices)ops)tensor)	array_ops)
tf_logging)	tf_exportc                 C   s(   t | tr| S d}| D ]}||9 }q|S )N   )
isinstanceint)tyx r   j/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/tensorflow/python/ops/gradient_checker_v2.py_product!   s   

r   c                 C   sB   t | tjrt rtjdd | jD dd | jD | jdS | S )aY  Converts IndexedSlices to IndexedSlicesValue with numpy indices/values.

  When eager execution is enabled, converts IndexedSlices
  to IndexedSlicesValue with numpy indices/values.

  Args:
    a: any value.

  Returns:
    If a is IndexedSlices and eager execution is enabled, calls numpy() on a's
    fields. Otherwise returns a unchanged.
  c                 S      g | ]}|  qS r   numpy.0r   r   r   r   
<listcomp>;       z(_eval_indexed_slices.<locals>.<listcomp>c                 S   r   r   r   r   r   r   r   r   <   r   )indicesvaluesdense_shape)	r   r   ZIndexedSlicesr   executing_eagerlyIndexedSlicesValuer   r   r   )ar   r   r   _eval_indexed_slices+   s   r!   c                 C   s   t | tjr
|  S t | tjrt }|| S t | tj	ret
| j}t| jt| jks:J d| j| j| f t| j| jD ]!\}}d|  krQt|k sZn J d|| f ||  |7  < qA|S | S )a@  Converts Tensors, EagerTensors, and IndexedSlicesValue to numpy arrays.

  Args:
    a: any value.

  Returns:
    If a is EagerTensor or Tensor, returns the evaluation of a by calling
    numpy() or run(). If a is IndexedSlicesValue, constructs the corresponding
    dense numpy array. Otherwise returns a unchanged.
  z8IndexedSlicesValue has %s value slices but %s indices
%sr   z*IndexedSlicesValue has invalid index %s
%s)r   r   ZEagerTensorr   r   ZTensorget_default_sessionrunr   r   npzerosr   lenr   r   zip)r    sessZarrZvalues_sliceindexr   r   r   	_to_numpyA   s&   

r*   c                    sP   t  r fdd}|S dd t||D   t fdd}|S )a,  Return a function that executes 'f'.

    In TF 2.x, this is the same as `f`.
    In TF 1.x, returns a Python function that executes the graph defined by `f`
    in a Session.

  Args:
    f: the function.
    xs_dtypes: dtypes of f's arguments.
    xs_shapes: shapes of f's arguments.

  Returns:
  c                     s    t tj|  S N)mapr   convert_to_tensorZxs_data)fr   r   decorated_eagern   s   z!_prepare.<locals>.decorated_eagerc                 S   s   g | ]\}}t j||d qS )shape)r   placeholder)r   x_dtypex_shaper   r   r   r   r   s    z_prepare.<locals>.<listcomp>c                     s&   dd | D }  j tt| dS )Nc                 S   s   g | ]}t |qS r   )r*   )r   r    r   r   r   r   z   r   z5_prepare.<locals>.decorated_graph.<locals>.<listcomp>)Z	feed_dict)r#   dictr'   r.   )r(   xsr   r   r   decorated_graphy   s   z!_prepare.<locals>.decorated_graph)r   r   r'   r   r"   )r/   	xs_dtypes	xs_shapesr0   r8   r   )r/   r(   r7   r   r   _prepare^   s   r;   c                    s  || }|j jrt|jd n|j}|jrdnd}t|}t|dd }	t|| }
tj|
|f|j jjd}tj||jd}|	 
|jj}t| |g t fdd|gdd	 |D  dgd
d	 |D  }t|
D ]T}d||< t||g|R  d }t|}t|tjrt|j|jD ]\}}||	 }||	 }||||f  |j7  < qn|dur|	 
|j ||ddf< d||< qm|
dkrt||g|R  d }|j|jkrtd|j|jf t|rtdtdd| |S )aY  Computes the theoretical Jacobian for f regarding xs[param].

  One can think of the relation among f, xs and y as y = f(xs).

  Args:
    f: the function.
    y_shape: the shape of the result.
    y_dtype: the dtype of the result.
    xs: a list of tensors.
    param: the index of the target parameter.

  Returns:
    A 2-d numpy array representing the Jacobian. It has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in xs[param]
    and "y_size" is the number of elements in the result.

  Raises:
    ValueError: If result is empty but the gradient is nonzero.
  )   r<   r   Ndtypec                    s    |d| iS )Ndyr   )r?   r7   Zgrad_fn_unprepr   r   <lambda>   s    z/_compute_theoretical_jacobian.<locals>.<lambda>c                 S      g | ]}|j qS r   r=   r   zr   r   r   r          z1_compute_theoretical_jacobian.<locals>.<listcomp>c                 S   rB   r   r1   rC   r   r   r   r      rE   r   z3Empty gradient has wrong shape: expected %s, got %sz#Empty tensor with nonzero gradientszTheoretical Jacobian =
%s)r>   
is_complextupler2   r   r$   r%   
real_dtypeas_numpy_dtyperavelviewr   Zgradients_functionr;   ranger*   r!   r   r   r   r'   r   r   Zflat
ValueErroranyloggingvlog)r/   y_shapey_dtyper7   paramr   r5   Zy_factorx_sizeZ
x_val_sizey_sizejacobianZdy_dataZdy_data_flatZgrad_fnrowZgradivZc_beginZc_endr   r@   r   _compute_theoretical_jacobian   sJ   


rZ   c                 C   sz  || j }|| j}t||jrdnd }||jrdnd }|jj}|jj}dd |D }	dd |D }
dd |D }|| }tjd| |dd }tj||f|d}t	| |	|
} t
|D ]V}| || }| ||  |7  < t| | }|| ||< | ||  |8  < t| | }|| ||< || | }| ||d	d	|f< q]tdd
| |S )aR  Computes the numeric Jacobian for f regarding xs[param].

  One can think of the relation among f, xs and y as y = f(xs).

  Args:
    f: the function.
    y_size: the number of elements of the result.
    y_dtype: the dtype of the result.
    xs: a list of tensors.
    param: the index of the target parameter.
    delta: the amount of perturbation we give to the input.

  Returns:
    A 2-d numpy array representing the Jacobian. It has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in xs[param]
    and "y_size" is the number of elements in the result.
  r<   r   c                 S   rB   r   r=   r   r   r   r   r      rE   z-_compute_numeric_jacobian.<locals>.<listcomp>c                 S   rB   r   r1   r   r   r   r   r      rE   c                 S   s   g | ]	}t t|qS r   )r$   asarrayr*   r   r   r   r   r      s    r=   r   NzNumeric Jacobian =
%s)r2   r>   r   rF   rH   rI   r$   r[   r%   r;   rL   rJ   rK   r*   rO   rP   )r/   rU   rR   r7   rS   deltar5   r4   rT   r9   r:   r   scalerV   coloriginalZy_posZy_negdiffr   r   r   _compute_numeric_jacobian   s2   

ra   c                 C   s   || }|j }tjtjtjtjtjtjg}|j|v s#J d|j	|f |}	|	j|v s1J d|	j	 t
|}
t| ||||}t| |
||||}||fS )z0Computes the theoretical and numerical jacobian.z>Cannot compute gradient for unsupported type %s of argument %sz4Cannot compute gradient for unsupported type %s of y)r>   r   Zfloat16Zbfloat16Zfloat32Zfloat64Z	complex64Z
complex128Z
base_dtypenamer   rZ   ra   )r/   rQ   rR   r7   rS   r\   r   r   Zallowed_typest2rU   Zjacob_tZjacob_nr   r   r   _compute_gradient  s    rd   c                    sf   dd D dd D }dd D }t ||}| tt fddttD  S )z)Compute gradients for a list of x values.c                 S   s   g | ]}t |qS r   )r   r-   r   r   r   r   r     s    z*_compute_gradient_list.<locals>.<listcomp>c                 S   rB   r   r=   r   r   r   r   r     rE   c                 S   rB   r   r1   r   r   r   r   r     rE   c              	      s(   g | ]}t jtj| qS r   )rd   r2   r   Zas_dtyper>   )r   rX   r\   r/   r7   r   r   r   r      s    )r;   rG   r'   rL   r&   )r/   r7   r\   r9   r:   Zf_tempr   re   r   _compute_gradient_list  s   
rf   ztest.compute_gradient)v1c                 C   s6   t |ttfstdt| |du rd}t| ||S )a  Computes the theoretical and numeric Jacobian of `f`.

  With y = f(x), computes the theoretical and numeric Jacobian dy/dx.

  Args:
    f: the function.
    x: the arguments for the function as a list or tuple of values convertible
      to a Tensor.
    delta: (optional) perturbation used to compute numeric Jacobian.

  Returns:
    A pair of lists, where the first is a list of 2-d numpy arrays representing
    the theoretical Jacobians for each argument, and the second list is the
    numerical ones. Each 2-d array has "y_size" rows
    and "x_size" columns where "x_size" is the number of elements in the
    corresponding argument and "y_size" is the number of elements in f(x).

  Raises:
    ValueError: If result is empty but the gradient is nonzero.
    ValueError: If x is not list, but any other type.

  Example:

  >>> @tf.function
  ... def test_func(x):
  ...   return x*x
  ...
  >>>
  >>> class MyTest(tf.test.TestCase):
  ...
  ...   def test_gradient_of_test_func(self):
  ...     theoretical, numerical = tf.test.compute_gradient(test_func, [1.0])
  ...     # ((array([[2.]], dtype=float32),),
  ...     #  (array([[2.000004]], dtype=float32),))
  ...     self.assertAllClose(theoretical, numerical)

  zZ`x` must be a list or tuple of values convertible to a Tensor (arguments to `f`), not a %sNg      P?)r   listrG   rM   typerf   )r/   r   r\   r   r   r   compute_gradient&  s   'rj   c                 C   sB   d}t | |D ]\}}|js|jrt|t||  }q|S )a  Computes maximum elementwise gap.

  Computes the maximum elementwise gap between two lists of tensors of the same
  shape.

  Args:
    grad1: a lists of tensors.
    grad2: a lists of tensors with the same shape as grad1.

  Returns:
    The maximum elementwise gap between the two.
  r   )r'   sizer$   maximumfabsmax)Zgrad1Zgrad2errorZj_tZj_nr   r   r   	max_errorZ  s   rp   r+   )__doc__r   r$   Ztensorflow.python.eagerr   r   Ztensorflow.python.frameworkr   r   r   r   Ztensorflow.python.opsr   Ztensorflow.python.platformr	   rO   Z tensorflow.python.util.tf_exportr
   r   r!   r*   r;   rZ   ra   rd   rf   rj   rp   r   r   r   r   <module>   s,   
"H:
3