B
    һd;                 @   s   d Z ddl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Zi Zd	d
 Zdd ZG dd dZdd Zeddd Zeddd Zdd ZdS )z3TensorFlow Debugger: Tools for debugging gradients.    N)
debug_data)debug_graphs)ops)gen_array_ops)	variablesZgradient_debug_c             C   s    t | j\}}d||t|f S )Nz
%s_%d/%s%s)r   parse_node_or_tensor_namename_GRADIENT_DEBUG_TAG)tensorgrad_debugger_uuidop_nameZslot r   ]/var/www/html/venv/lib/python3.7/site-packages/tensorflow/python/debug/lib/debug_gradients.py_tensor_to_grad_debug_op_name   s    r   c             C   s   |  d}t|dkst|d ts,t|d ttd }d|krZ|d|d }t|d |d dd d }|d d|d d }d|dd |g d|  }||fS )a  Parse the name of a debug gradient op.

  Args:
    op_name: the name of the debug gradient op.

  Returns:
    1) The UUID of the GradientsDebugger that created the debug gradient op.
    2) Name of the original tensor whose gradient is debugged by the debug
       gradient op.
  /   N_z:%d)	splitlenAssertionError
startswithr	   indexintrfindjoin)r   Z
name_itemsr   Zorig_tensor_slotZorig_base_op_nameorig_tensor_namer   r   r   _parse_grad_debug_op_name$   s    
"
r   c               @   s   e Zd ZdZdddZedd Ze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d Zdd Zdd ZdS )GradientsDebuggerzGradients Debugger.

  Allows retrieval of gradient tensors created by TensorFlow's automatic
  differentiation algorithm, i.e., `tf.gradients` and optimizer classes that
  use it.
  Nc             C   s>   t  j| _| t| j< i | _|| _d| _|r4|j| _d| _	dS )zConstructor of GradientsDebugger.

    Args:
      y_tensor: optional: the `tf.Tensor` to be differentiated, i.e., the tensor
        on the numerator of the differentiation.
    NF)
uuiduuid4hex_uuid_gradient_debuggers_gradient_tensors	_y_tensor_graphgraph_is_active_context)selfy_tensorr   r   r   __init__G   s    
zGradientsDebugger.__init__c             C   s   | j S )N)r&   )r*   r   r   r   r+   ^   s    zGradientsDebugger.y_tensorc             C   s   | j S )N)r'   )r*   r   r   r   r(   b   s    zGradientsDebugger.graphc             C   s
   d| _ d S )NT)r)   )r*   r   r   r   	__enter__f   s    zGradientsDebugger.__enter__c             C   s
   d| _ d S )NF)r)   )r*   Zunused_typeZunused_valueZunused_tracebackr   r   r   __exit__i   s    zGradientsDebugger.__exit__c             C   sX   t || j}|jjrtjntj}|||d}|j|jks<t|jj	|krTt
d| |S )a  Create a debug identity tensor that registers and forwards gradients.

    The side effect of this method is that when gradient tensor(s) are created
    with respect to the any paths that include the `input_tensor`, the gradient
    tensor(s) with respect to `input_tensor` will be registered with this
    this `GradientsDebugger` instance and can later be retrieved, with the
    methods `gradient_tensor` and `gradient_tensors`.

    Example:

    ```python
    x = tf.Variable(1.0)
    y = tf.add(x, x)

    grad_debugger = tf_debug.GradientsDebugger()
    debug_y = grad_debugger.identify_gradient(y)
    z = tf.square(debug_y)

    # Create a train op under the grad_debugger context.
    with grad_debugger:
      train_op = tf.compat.v1.train.GradientDescentOptimizer(z)

    # Now we can reflect through grad_debugger to get the gradient tensor
    # with respect to y.
    y_grad = grad_debugger.gradient_tensor(y)
    ```

    Args:
      input_tensor: the input `tf.Tensor` object whose related gradient tensors
        are to be registered with this `GradientsDebugger` instance when they
        are created, e.g., during `tf.gradients` calls or the construction
        of optimization (training) op that uses `tf.gradients`.

    Returns:
      A forwarded identity of `input_tensor`, as a `tf.Tensor`.

    Raises:
      ValueError: If an op with name that duplicates the gradient-debugging op
        already exists in the graph (highly unlikely).
    )r   z)The graph already contains an op named %s)r   r#   ZdtypeZ_is_ref_dtyper   Zdebug_gradient_ref_identityZdebug_gradient_identityr   opr   
ValueError)r*   Zinput_tensorZgrad_debug_op_nameZidentity_opZdebug_grad_identityr   r   r   identify_gradientl   s    +
z#GradientsDebugger.identify_gradientc             C   sV   t |ts|g}g }x"|D ]}|t|jd  qW dd| d }| ||S )a  Watch gradient tensors by x-tensor(s).

    The side effect of this method is that when gradient tensor(s) are created
    with respect to the any paths that include the `x_tensor`s, the gradient
    tensor(s) with respect to the tensor will be registered with this
    this `GradientsDebugger` instance and can later be retrieved, with the
    methods `gradient_tensor` and `gradient_tensors`.

    Unlike the method `identify_gradient`, this method is used to retrieve
    gradient tensors after the construction of the forward subgraph has
    completed (but before the construction of the backward subgraph).

    This method is the same as `watch_gradients_by_x_tensor_names` except that
    the tensors are specified by the Python `tf.Tensor` or `tf.Variable`
    objects, instead by name patterns.

    Example:

    ```python
    x = tf.Variable(1.0)
    y = tf.add(x, x, name="y")
    z = tf.square(debug_y)

    # Create a train op under the grad_debugger context.
    grad_debugger = tf_debug.GradientsDebugger()
    with grad_debugger.watch_gradients_by_tensors(y):
      train_op = tf.compat.v1.train.GradientDescentOptimizer(z)

    # Now we can reflect through grad_debugger to get the gradient tensor
    # with respect to y.
    y_grad = grad_debugger.gradient_tensor(y)
    # or
    y_grad = grad_debugger.gradient_tensor("y:0")
    ```

    Args:
      graph: the `tf.Graph` to watch the gradients on.
      tensors: a `tf.Tensor` or `tf.Variable` object, or a list of such objects.

    Returns:
      The GradientsDebugger instance itself.
    $(|))
isinstancelistappendreescaper   r   watch_gradients_by_tensor_names)r*   r(   Ztensorstensor_name_regexr
   r   r   r   watch_gradients_by_tensors   s    ,

z,GradientsDebugger.watch_gradients_by_tensorsc       
   	   C   s   t |}|  x| D ]x}xr|jD ]h}||jr*| |}xLt|	 D ]<}||j
krbqRx*t|jD ]\}}	|	|krn||| qnW qRW q*W qW W dQ R X | S )aQ  Watch gradient tensors by name(s) of the x-tensor(s).

    The side effect of this method is that when gradient tensor(s) are created
    with respect to the x-tensors, the gradient tensor(s) will be registered
    with this `GradientsDebugger` instance and can later be retrieved.

    Unlike the `identify_gradient` method, this method is used after the
    construction of the forward graph has completed. Unlike the
    `watch_gradients_by_tensor` method, this method does not use handles to the
    tensors of interest; it uses their names.

    This method is the same as `watch_gradients_by_tensors` except that the
    x-tensors are specified by name patterns, instead of `tf.Tensor` or
    `tf.Variable` objects.

    Example:

    ```python
    x = tf.Variable(1.0, name="x")
    y = tf.add(x, x, name="y")
    z = tf.square(debug_y)

    # Create a train op under the grad_debugger context.
    grad_debugger = tf_debug.GradientsDebugger()
    with grad_debugger.watch_gradients_by_tensor_names(r"(x|y):0$"):
      train_op = tf.compat.v1.train.GradientDescentOptimizer(z)

    # Now we can reflect through grad_debugger to get the gradient tensor
    # with respect to x and y.
    x_grad = grad_debugger.gradient_tensor("x:0")
    y_grad = grad_debugger.gradient_tensor("y:0")
    ```

    Args:
      graph: the `tf.Graph` to watch the gradients on.
      tensor_name_regex: the regular-expression pattern of the name(s) of the
        x-tensor(s) to watch. x-tensor refers to the tensors on the denominator
        of the differentiation.

    Returns:
      The GradientsDebugger instance itself.
    N)r9   compileZ
as_defaultZget_operationsoutputsmatchr   r1   r7   Z	consumersr/   	enumerateinputsZ_update_input)
r*   r(   r<   Ztensor_name_patternr/   outputZdebug_opZconsumeriZconsumer_inputr   r   r   r;      s    +



&z1GradientsDebugger.watch_gradients_by_tensor_namesc             C   s8   | j d kr|j| _ n | j |jkr4td|j| j f d S )Nz;The graph of the value (%s) is not the same as the graph %s)r'   r(   r0   )r*   r
   r   r   r   _check_same_graph  s    

z#GradientsDebugger._check_same_graphc             C   s*   t tdks| jr&| | || j|< dS )zRegister the gradient tensor for an x-tensor.

    Args:
      x_tensor_name: (`str`) the name of the independent `tf.Tensor`, i.e.,
        the tensor on the denominator of the differentiation.
      gradient_tensor: the gradient `tf.Tensor`.
    r   N)r   r$   r)   rE   r%   )r*   x_tensor_namegradient_tensorr   r   r   register_gradient_tensor   s    

z*GradientsDebugger.register_gradient_tensorc             C   s*   |  |}|| jkr td| | j| S )a  Get the gradient tensor of an x-tensor.

    Args:
      x_tensor: (`tf.Tensor`, `tf.Variable` or `str`) The x-tensor object or its
        name. x-tensor refers to the independent `tf.Tensor`, i.e., the tensor
        on the denominator of the differentiation.

    Returns:
      If found, the gradient tensor.

    Raises:
      TypeError: If `x_tensor` is not a `tf.Tensor`, `tf.Variable` or `str`.
      LookupError: If the `x_tensor` has not been registered with a gradient
        tensor.
    zKThis GradientsDebugger has not received any gradient tensor for x-tensor %s)_get_tensor_namer%   LookupError)r*   x_tensorrF   r   r   r   rG   .  s    

z!GradientsDebugger.gradient_tensorc             C   s   | j S )zGet the gradient tensors that this object is aware of.

    Returns:
      A dict mapping x-tensor names to gradient tensor objects. x-tensor refers
      to the tensors on the denominator of the differentation.
    )r%   )r*   r   r   r   gradient_tensorsE  s    z"GradientsDebugger.gradient_tensorsc             C   s:   t |tjtjfr|jS t |tr&|S tdt| d S )NzKx_tensor must be a str or tf.Tensor or tf.Variable, but instead has type %s)	r6   r   ZTensorr   Variabler   str	TypeErrortype)r*   r
   r   r   r   rI   N  s    
z"GradientsDebugger._get_tensor_name)N)__name__
__module____qualname____doc__r,   propertyr+   r(   r-   r.   r1   r=   r;   rE   rH   rG   rL   rI   r   r   r   r   r   >   s   
95>	r   c               C   s   t   dS )z1Clear all globally registered gradient debuggers.N)r$   clearr   r   r   r   clear_gradient_debuggersY  s    rW   ZDebugGradientIdentityc             C   s&   t | j\}}t| }||| |S )z+Gradient function for the DebugIdentity op.)r   r   r$   rH   )r/   dyr   r   grad_debuggerr   r   r   _identify_gradient_grad^  s    rZ   ZDebugGradientRefIdentityc             C   s
   t | |S )z+Gradient function for the DebugIdentity op.)rZ   )r/   rX   r   r   r   _identify_gradient_grad_refh  s    r[   c             C   sp   |j r,| jr,|j | jkr,td| j|j f | |}t|j\}}y|||dS  tj	k
rj   g S X dS )a  Find gradient values from a `DebugDumpDir` object.

  Args:
    grad_debugger: the `tf_debug.GradientsDebugger` instance to be used.
    x_tensor: (`tf.Tensor`, `tf.Variable` or `str`) The x-tensor object or its
      name. x-tensor refers to the independent `tf.Tensor`, i.e., the tensor
      on the denominator of the differentiation.
    dump: A `tfdbg.DebugDumpDir` object.

  Returns:
    If this `GradientsDebugger` instance has the gradient tensor of `x_tensor`
      registered: a list of `numpy.ndarray` representing the value of the
      gradient tensor from `dump`. The list could be empty, if the gradient
      tensor is not executed in the `tf.Session.run()` call that generated
      the `dump`. The list could also contain multiple values of the gradient
      tensor, e.g., if gradient tensor is computed repeatedly in a
      `tf.while_loop` during the run that generated the `dump`.

  Raises:
    LookupError: If this `GradientsDebugger` instance does not have the
      gradient tensor of `x_tensor` registered.
    ValueError: If this `GradientsDebugger` has a `tf.Graph` object that
      does not match the `tf.Graph` object of the `dump`.
    TypeError: If `x_tensor` is not a `tf.Tensor`, `tf.Variable` or `str`.
  zmThis GradientsDebugger instance has a graph (%s) that differs from the graph of the DebugDumpDir object (%s).ZDebugIdentityN)
Zpython_graphr(   r0   rG   r   r   r   Zget_tensorsr   Z'WatchKeyDoesNotExistInDebugDumpDirError)rY   rK   dumprG   Z	node_nameZoutput_slotr   r   r   gradient_values_from_dumpn  s    
r]   )rT   r9   r    Ztensorflow.python.debug.libr   r   Ztensorflow.python.frameworkr   Ztensorflow.python.opsr   r   r	   r$   r   r   r   rW   ZRegisterGradientrZ   r[   r]   r   r   r   r   <module>   s$     
