B
    ӻdq                 @   s  d Z ddlZddlZddlm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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# ddl$m%Z% dZ&G dd deZ'dd Z(dd Z)dd Z*d d! Z+d8d#d$Z,G d%d& d&eZ-G d'd( d(eZ.G d)d* d*eZ/d9d,d-Z0d.d/ Z1d:d0d1Z2d2d3 Z3d;d4d5Z4d6d7 Z5dS )<zUtils related to keras metrics.    N)Enum)compat)distribution_strategy_context)dtypes)ops)backend)losses_utils)tf_utils)to_list)	array_ops)	check_ops)clip_ops)control_flow_ops)gen_math_ops)math_ops)nn_ops)	variables)weights_broadcast_ops)ragged_tensor)tf_decoratorg    _c               @   s   e Zd ZdZdZdZdZdS )	Reductiona  Types of metrics reduction.

  Contains the following values:

  * `SUM`: Scalar sum of weighted values.
  * `SUM_OVER_BATCH_SIZE`: Scalar sum of weighted values divided by
        number of elements.
  * `WEIGHTED_MEAN`: Scalar sum of weighted values divided by sum of weights.
  sumZsum_over_batch_sizeZweighted_meanN)__name__
__module____qualname____doc__ZSUMZSUM_OVER_BATCH_SIZEZWEIGHTED_MEAN r   r   ]/var/www/html/venv/lib/python3.7/site-packages/tensorflow/python/keras/utils/metrics_utils.pyr   1   s   	r   c                s    fdd}t  |S )zDecorator to wrap metric `update_state()` with `add_update()`.

  Args:
    update_state_fn: function that accumulates metric statistics.

  Returns:
    Decorated function that wraps `update_state_fn()` with `add_update()`.
  c          	      sv   t  }x4| jD ]*}t|r|j|st  stdqW t	j
||  ||}W dQ R X |dk	rr| | |S )z'Decorated function with `add_update()`.zTrying to run metric.update_state in replica context when the metric was not created in TPUStrategy scope. Make sure the keras Metric is created in TPUstrategy scope. N)r   get_strategyweightsr   Zis_tpu_strategyextendedZvariable_created_in_scopeZin_cross_replica_context
ValueErrorr	   Z"graph_context_for_symbolic_tensorsZ
add_update)
metric_objargskwargsZstrategyweightZ	update_op)update_state_fnr   r   	decoratedJ   s    


z'update_state_wrapper.<locals>.decorated)r   make_decorator)r&   r'   r   )r&   r   update_state_wrapper@   s    
r)   c                s    fdd}t  |S )a~  Decorator to wrap metric `result()` function in `merge_call()`.

  Result computation is an idempotent operation that simply calculates the
  metric value using the state variables.

  If metric state variables are distributed across replicas/devices and
  `result()` is requested from the context of one device - This function wraps
  `result()` in a distribution strategy `merge_call()`. With this,
  the metric state variables will be aggregated across devices.

  Args:
    result_fn: function that computes the metric result.

  Returns:
    Decorated function that wraps `result_fn()` in distribution strategy
    `merge_call()`.
  c          
      s   t  }t  }|r*|dks*t  j st    | }t|tj	t
jttfr^t|}nXt|tr|dd | D }n:yt|}W n* ttfk
r   td| j|f Y nX W dQ R X ndd }|j| f| d}|| _|S )z#Decorated function with merge_call.Nc             S   s   i | ]\}}t ||qS r   )r   identity).0keyvaluer   r   r   
<dictcomp>   s   z5result_wrapper.<locals>.decorated.<locals>.<dictcomp>zThe output of `metric.result()` can only be a single Tensor/Variable, or a dict of Tensors/Variables. For metric %s, got result %s.c             W   s   |  |d | }t|S )Nr   )Zexperimental_local_resultsr   r*   )distributionZmerge_fnr#   resultr   r   r   merge_fn_wrapper   s    z;result_wrapper.<locals>.decorated.<locals>.merge_fn_wrapper)r#   )r   has_strategyZget_replica_contextr   r    Z_use_merge_callZvariable_sync_on_read_context
isinstancer   ZTensorvariables_moduleVariablefloatintr   r*   dictitemsr!   	TypeErrorRuntimeErrornameZ
merge_callZ_call_result)r"   r#   r2   Zreplica_contextZ
raw_resultZresult_tr1   )	result_fnr   r   r'   s   s.    

 z!result_wrapper.<locals>.decorated)r   r(   )r=   r'   r   )r=   r   result_wrapper`   s    Or>   c                s8   | j  | jt| jt|  fdd}~ |S )z-Creates a weak reference to the bound method.c                 s      | |S )N)__get__)r#   r$   )clsfuncinstance_refr   r   inner   s    zweakmethod.<locals>.inner)Zim_classZim_funcweakrefrefZim_self	functoolswraps)methodrC   r   )r@   rA   rB   r   
weakmethod   s    rI   c             C   s,   | d k	r(dd | D }|r(t d|d S )Nc             S   s(   g | ] }|d ks |dk s |dkr|qS )Nr      r   )r+   tr   r   r   
<listcomp>   s    z+assert_thresholds_range.<locals>.<listcomp>z6Threshold values must be in [0, 1]. Invalid values: {})r!   format)
thresholdsZinvalid_thresholdsr   r   r   assert_thresholds_range   s    rO         ?c             C   s,   | d k	rt t|  t| d kr"|n| } | S )N)rO   r
   )rN   Zdefault_thresholdr   r   r   parse_init_thresholds   s    rQ   c               @   s   e Zd ZdZdZdZdZdS )ConfusionMatrixtpfptnfnN)r   r   r   TRUE_POSITIVESFALSE_POSITIVESTRUE_NEGATIVESFALSE_NEGATIVESr   r   r   r   rR      s   rR   c               @   s$   e Zd ZdZdZdZedd ZdS )AUCCurvezType of AUC Curve (ROC or PR).ROCPRc             C   s,   | dkrt jS | dkrt jS td|  d S )N)prr]   )Zrocr\   zInvalid AUC curve value "%s".)r[   r]   r\   r!   )r,   r   r   r   from_str   s
    zAUCCurve.from_strN)r   r   r   r   r\   r]   staticmethodr_   r   r   r   r   r[      s   r[   c               @   s(   e Zd ZdZdZdZdZedd ZdS )AUCSummationMethoda&  Type of AUC summation method.

  https://en.wikipedia.org/wiki/Riemann_sum)

  Contains the following values:
  * 'interpolation': Applies mid-point summation scheme for `ROC` curve. For
    `PR` curve, interpolates (true/false) positives but not the ratio that is
    precision (see Davis & Goadrich 2006 for details).
  * 'minoring': Applies left summation for increasing intervals and right
    summation for decreasing intervals.
  * 'majoring': Applies right summation for increasing intervals and left
    summation for decreasing intervals.
  interpolationmajoringminoringc             C   s:   | dkrt jS | dkrt jS | dkr*t jS td|  d S )N)rb   Interpolation)rc   ZMajoring)rd   ZMinoringz(Invalid AUC summation method value "%s".)ra   INTERPOLATIONMAJORINGMINORINGr!   )r,   r   r   r   r_     s    zAUCSummationMethod.from_strN)	r   r   r   r   rf   rg   rh   r`   r_   r   r   r   r   ra      s
   ra   Fc                s  |j  d  |dkrd}n*ttj||jd|}|sFt|dg}|dkrTd}n*t	|d}t||}|s~t|dg}t
||}tj|ddd}tt|tj|j}|st|dg}t|dg}t
||}	t
d| |}
t| d  d }|rt|}t|tj}|rt|	}	t|
}
t|} fd	d
}t||	|f}t||
|f}ttj|ddd}ttj|ddd}n<tj|	| d}tj|
| d}tj|dd}tj|dd}tj| kstj| kr,|rtj|	dd}tj|
dd}nt|	}t|
}g }tj| krV| tj }||| tj| kr|| tj }||| tj| kr| tj }|| }||| tj| kr| tj }|| }||| t !|S )ao  Update confusion matrix variables with memory efficient alternative.

  Note that the thresholds need to be evenly distributed within the list, eg,
  the diff between consecutive elements are the same.

  To compute TP/FP/TN/FN, we are measuring a binary classifier
    C(t) = (predictions >= t)
  at each threshold 't'. So we have
    TP(t) = sum( C(t) * true_labels )
    FP(t) = sum( C(t) * false_labels )

  But, computing C(t) requires computation for each t. To make it fast,
  observe that C(t) is a cumulative integral, and so if we have
    thresholds = [t_0, ..., t_{n-1}];  t_0 < ... < t_{n-1}
  where n = num_thresholds, and if we can compute the bucket function
    B(i) = Sum( (predictions == t), t_i <= t < t{i+1} )
  then we get
    C(t_i) = sum( B(j), j >= i )
  which is the reversed cumulative sum in tf.cumsum().

  We can compute B(i) efficiently by taking advantage of the fact that
  our thresholds are evenly distributed, in that
    width = 1.0 / (num_thresholds - 1)
    thresholds = [0.0, 1*width, 2*width, 3*width, ..., 1.0]
  Given a prediction value p, we can map it to its bucket by
    bucket_index(p) = floor( p * (num_thresholds - 1) )
  so we can use tf.math.unsorted_segment_sum() to update the buckets in one
  pass.

  Consider following example:
  y_true = [0, 0, 1, 1]
  y_pred = [0.1, 0.5, 0.3, 0.9]
  thresholds = [0.0, 0.5, 1.0]
  num_buckets = 2   # [0.0, 1.0], (1.0, 2.0]
  bucket_index(y_pred) = tf.math.floor(y_pred * num_buckets)
                       = tf.math.floor([0.2, 1.0, 0.6, 1.8])
                       = [0, 0, 0, 1]
  # The meaning of this bucket is that if any of the label is true,
  # then 1 will be added to the corresponding bucket with the index.
  # Eg, if the label for 0.2 is true, then 1 will be added to bucket 0. If the
  # label for 1.8 is true, then 1 will be added to bucket 1.
  #
  # Note the second item "1.0" is floored to 0, since the value need to be
  # strictly larger than the bucket lower bound.
  # In the implementation, we use tf.math.ceil() - 1 to achieve this.
  tp_bucket_value = tf.math.unsorted_segment_sum(true_labels, bucket_indices,
                                                 num_segments=num_thresholds)
                  = [1, 1, 0]
  # For [1, 1, 0] here, it means there is 1 true value contributed by bucket 0,
  # and 1 value contributed by bucket 1. When we aggregate them to together,
  # the result become [a + b + c, b + c, c], since large thresholds will always
  # contribute to the value for smaller thresholds.
  true_positive = tf.math.cumsum(tp_bucket_value, reverse=True)
                = [2, 1, 0]

  This implementation exhibits a run time and space complexity of O(T + N),
  where T is the number of thresholds and N is the size of predictions.
  Metrics that rely on standard implementation instead exhibit a complexity of
  O(T * N).

  Args:
    variables_to_update: Dictionary with 'tp', 'fn', 'tn', 'fp' as valid keys
      and corresponding variables to update as values.
    y_true: A floating point `Tensor` whose shape matches `y_pred`. Will be cast
      to `bool`.
    y_pred: A floating point `Tensor` of arbitrary shape and whose values are in
      the range `[0, 1]`.
    thresholds: A sorted floating point `Tensor` with value in `[0, 1]`.
      It need to be evenly distributed (the diff between each element need to be
      the same).
    multi_label: Optional boolean indicating whether multidimensional
      prediction/labels should be treated as multilabel responses, or flattened
      into a single label. When True, the valus of `variables_to_update` must
      have a second dimension equal to the number of labels in y_true and
      y_pred, and those tensors must not be RaggedTensors.
    sample_weights: Optional `Tensor` whose rank is either 0, or the same rank
      as `y_true`, and must be broadcastable to `y_true` (i.e., all dimensions
      must be either `1`, or the same as the corresponding `y_true` dimension).
    label_weights: Optional tensor of non-negative weights for multilabel
      data. The weights are applied when calculating TP, FP, FN, and TN without
      explicit multilabel handling (i.e. when the data is to be flattened).
    thresholds_with_epsilon: Optional boolean indicating whether the leading and
      tailing thresholds has any epsilon added for floating point imprecisions.
      It will change how we handle the leading and tailing bucket.

  Returns:
    Update op.
  r   Ng      ?)dtypeg        )Zclip_value_minZclip_value_maxrJ   c                s"   | d | d  }}t j|| dS )Nr   rJ   )datasegment_idsnum_segments)r   unsorted_segment_sum)Zlabel_and_bucket_indexlabelZbucket_index)num_thresholdsr   r   gather_bucket  s    zC_update_confusion_matrix_variables_optimized.<locals>.gather_bucketT)reverseaxis)rk   rl   rm   )rr   )rs   )"shapeas_listr   broadcast_weightsr   castri   r   reshapeexpand_dimsmultiplyr   Zclip_by_valuer   boolceilr   Zreluint32Ztranspose_v2parallel_control_flow_opsZvectorized_mapZcumsumrn   rR   rY   rZ   
reduce_sumrW   append
assign_addrX   r   group)variables_to_updatey_truey_predrN   multi_labelsample_weightslabel_weightsthresholds_with_epsilonr   Ztrue_labelsZfalse_labelsZbucket_indicesrq   Ztp_bucket_vZfp_bucket_vrS   rT   Ztotal_true_labelsZtotal_false_labels
update_opsvariablerU   rV   r   )rp   r   ,_update_confusion_matrix_variables_optimized  s    a










r   c             C   s@   t | }|dk rdS tj|tjd|d  }tj| |t dS )a  Check if the thresholds list is evenly distributed.

  We could leverage evenly distributed thresholds to use less memory when
  calculate metrcis like AUC where each individual threshold need to be
  evaluted.

  Args:
    thresholds: A python list or tuple, or 1D numpy array whose value is ranged
      in [0, 1].

  Returns:
    boolean, whether the values in the inputs are evenly distributed.
     F)ri   rJ   )Zatol)lennpZarangeZfloat32Zallcloser   epsilon)rN   rp   Zeven_thresholdsr   r   r    is_evenly_distributed_thresholds  s    r   c
       *   
   C   s  |r|dk	rt d| dkr dS tdd | D sJt dtt|  t|  d j}
tj	||
d}tj	||
d}|	r|d dk p|d	 d
k}t
j||
d}|j d }|rtjtj	dtjdt|dd}n&t||g|\\}}}tj	dtjd}dd | D }|r&t d|ttt
tj|tj	d|jdddtj|tj	d
|jdddgF |dkrt||\}}n$tj	||
d}tj|||d\}}}W dQ R X |j|j |dk	rt||}|dk	r|d|f }|d|f }|	r"tdddr"t| |||||||dS t|}|d }|jj dkrHd}nt!j"|dd dd}t#||tj$g tjd}|rt%|d}t%tj	|tjdd}n,t&|dd	g}t&tj	|tjddd	g}|r|dd	g}d||g}|ddg}n|d	g}d|| g}|dg}t't&||t(|}t'||}t)||}t'||}|dk	rt*+tj	||
d|}t't&|||}nd}|dk	r|st%|d}t*+||}t't&|||}|dkr|}nt,||}g }dd } tj-||fi}!tj.| k}"tj/| k}#tj0| k}$|$s&|"r>t1|}%||%f|!tj0< |#sJ|"rvt1|}&|&|f|!tj/< |"rv|&|%f|!tj.< x<|!2 D ]0\}'\}(})|'| kr|3| |(|)|| |'  qW t45|S )a
  Returns op to update the given confusion matrix variables.

  For every pair of values in y_true and y_pred:

  true_positive: y_true == True and y_pred > thresholds
  false_negatives: y_true == True and y_pred <= thresholds
  true_negatives: y_true == False and y_pred <= thresholds
  false_positive: y_true == False and y_pred > thresholds

  The results will be weighted and added together. When multiple thresholds are
  provided, we will repeat the same for every threshold.

  For estimation of these metrics over a stream of data, the function creates an
  `update_op` operation that updates the given variables.

  If `sample_weight` is `None`, weights default to 1.
  Use weights of 0 to mask values.

  Args:
    variables_to_update: Dictionary with 'tp', 'fn', 'tn', 'fp' as valid keys
      and corresponding variables to update as values.
    y_true: A `Tensor` whose shape matches `y_pred`. Will be cast to `bool`.
    y_pred: A floating point `Tensor` of arbitrary shape and whose values are in
      the range `[0, 1]`.
    thresholds: A float value, float tensor, python list, or tuple of float
      thresholds in `[0, 1]`, or NEG_INF (used when top_k is set).
    top_k: Optional int, indicates that the positive labels should be limited to
      the top k predictions.
    class_id: Optional int, limits the prediction and labels to the class
      specified by this argument.
    sample_weight: Optional `Tensor` whose rank is either 0, or the same rank as
      `y_true`, and must be broadcastable to `y_true` (i.e., all dimensions must
      be either `1`, or the same as the corresponding `y_true` dimension).
    multi_label: Optional boolean indicating whether multidimensional
      prediction/labels should be treated as multilabel responses, or flattened
      into a single label. When True, the valus of `variables_to_update` must
      have a second dimension equal to the number of labels in y_true and
      y_pred, and those tensors must not be RaggedTensors.
    label_weights: (optional) tensor of non-negative weights for multilabel
      data. The weights are applied when calculating TP, FP, FN, and TN without
      explicit multilabel handling (i.e. when the data is to be flattened).
    thresholds_distributed_evenly: Boolean, whether the thresholds are evenly
      distributed within the list. An optimized method will be used if this is
      the case. See _update_confusion_matrix_variables_optimized() for more
      details.

  Returns:
    Update op.

  Raises:
    ValueError: If `y_pred` and `y_true` have mismatched shapes, or if
      `sample_weight` is not `None` and its shape doesn't match `y_pred`, or if
      `variables_to_update` contains invalid keys.
  Nz`label_weights` for multilabel data should be handled outside of `update_confusion_matrix_variables` when `multi_label` is True.c             s   s   | ]}|t tkr|V  qd S )N)listrR   )r+   r,   r   r   r   	<genexpr>@  s    z4update_confusion_matrix_variables.<locals>.<genexpr>z{Please provide at least one valid confusion matrix variable to update. Valid variable key options are: "{}". Received: "{}"r   )ri   g        rj   g      ?rJ   Zone_set_of_thresholds_cond)r<   Tc             S   s   g | ]}|t tkr|qS r   )r   rR   )r+   r,   r   r   r   rL   e  s    z5update_confusion_matrix_variables.<locals>.<listcomp>z6Invalid keys: {}. Valid variable key options are: "{}"zpredictions must be >= 0)messagezpredictions must be <= 1)sample_weight.i        )r   r   r   r   )inputrs   c             S   sF   t jt | ||jd}|d k	r4|t j||jd9 }|t |dS )N)ri   rJ   )r   rw   logical_andri   r   r   )ro   predr   varZlabel_and_predr   r   r   weighted_assign_add  s
    z>update_confusion_matrix_variables.<locals>.weighted_assign_add)6r!   anyrM   r   rR   keysvaluesri   r   rw   r   Z"convert_to_tensor_v2_with_dispatchrt   ru   equalr   r}   r   Zrank,ragged_assert_compatible_and_get_flat_valuesr{   control_dependenciesr   Zassert_greater_equalZassert_less_equalr   Zsqueeze_or_expand_dimensionsZassert_is_compatible_with_filter_top_kr   Zforward_compatibler   Zndimsr   ZProdZwhere_v2Zonesry   rx   ZtilestackZgreaterr   rv   rz   rW   rY   rX   rZ   Zlogical_notr9   r   r   r   )*r   r   r   rN   top_kZclass_idr   r   r   Zthresholds_distributed_evenlyZvariable_dtyper   rp   Z
one_thresh_Zinvalid_keysZ
pred_shapeZnum_predictionsZ
num_labelsZthresh_label_tileZpredictions_extra_dimZlabels_extra_dimZthresh_pretile_shapeZthresh_tilesZ
data_tilesZthresh_tiledZpreds_tiledZpred_is_posZlabel_is_posZweights_tiledZlabel_weights_tiledr   r   Z	loop_varsZ	update_tnZ	update_fpZ	update_fnZpred_is_negZlabel_is_negZmatrix_condro   r   r   r   r   !update_confusion_matrix_variables  s    @

















r   c             C   sL   t j| |dd\}}tjtj|t| d dddd}| | td|   S )ac  Filters top-k values in the last dim of x and set the rest to NEG_INF.

  Used for computing top-k prediction values in dense labels (which has the same
  shape as predictions) for recall and precision top-k metrics.

  Args:
    x: tensor with any dimensions.
    k: the number of values to keep.

  Returns:
    tensor with same shape and dtype as x.
  F)sortedrj   )rs   rJ   )r   r   r   r   r   Zone_hotrt   NEG_INF)xkr   Z	top_k_idxZ
top_k_maskr   r   r   r     s     r   c       
   
   C   sJ  t | tr0tdd | D }tdd | D }nt | tj}|}|r|dks\t |tjrd}t | tst| g} d}dd | D }t|}t |tjrt|d	 |jg}t	| t
|jd
}W dQ R X g }x6| D ].}	t	| |t
|	jd
 W dQ R X qW |r|d	 n|} n&|r,tdnt |tjrBtd| |fS )a  If ragged, it checks the compatibility and then returns the flat_values.

     Note: If two tensors are dense, it does not check their compatibility.
     Note: Although two ragged tensors with different ragged ranks could have
           identical overall rank and dimension sizes and hence be compatible,
           we do not support those cases.
  Args:
     values: A list of potentially ragged tensor of the same ragged_rank.
     mask: A potentially ragged tensor of the same ragged_rank as elements in
       Values.

  Returns:
     A tuple in which the first element is the list of tensors and the second
     is the mask tensor. ([Values], mask). Mask and the element in Values
     are equal to the flat_values of the input arguments (if they were ragged).
  c             s   s   | ]}t |tjV  qd S )N)r3   r   RaggedTensor)r+   rtr   r   r   r     s    z?ragged_assert_compatible_and_get_flat_values.<locals>.<genexpr>c             s   s   | ]}t |tjV  qd S )N)r3   r   r   )r+   r   r   r   r   r     s    NFTc             S   s   g | ]
}|j qS r   )nested_row_splits)r+   r   r   r   r   rL   '  s    z@ragged_assert_compatible_and_get_flat_values.<locals>.<listcomp>r   rj   z1One of the inputs does not have acceptable types.z2Ragged mask is not allowed with non-ragged inputs.)r3   r   allr   r   r   _assert_splits_matchr   r   r   r   ry   flat_valuesr   r:   )
r   maskZis_all_raggedZis_any_raggedZto_be_strippedZnested_row_split_listZassertion_listZassertion_list_for_maskr   r-   r   r   r   r     s8    


"
r   c                sJ   d x(D ] }t |t d kr
t q
W  fdddd D S )a7  Checks that the given splits lists are identical.

  Performs static tests to ensure that the given splits lists are identical,
  and returns a list of control dependency op tensors that check that they are
  fully identical.

  Args:
    nested_splits_lists: A list of nested_splits_lists, where each split_list is
      a list of `splits` tensors from a `RaggedTensor`, ordered from outermost
      ragged dimension to innermost ragged dimension.

  Returns:
    A list of control dependency op tensors.
  Raises:
    ValueError: If the splits are not identical.
  z(Inputs must have identical ragged splitsr   c                s4   g | ],}t d  |D ]\}}tj|| dqqS )r   )r   )zipr   Zassert_equal)r+   splits_lists1s2)	error_msgnested_splits_listsr   r   rL   X  s   z(_assert_splits_match.<locals>.<listcomp>rJ   N)r   r!   )r   r   r   )r   r   r   r   B  s    
r   )rP   )FNNF)NNNFNF)N)6r   rF   rD   enumr   numpyr   Ztensorflow.python.compatr   Ztensorflow.python.distributer   Ztensorflow.python.frameworkr   r   Ztensorflow.python.kerasr   Ztensorflow.python.keras.utilsr   r	   Z+tensorflow.python.keras.utils.generic_utilsr
   Ztensorflow.python.opsr   r   r   r   r   r   r   r   r4   r   Z"tensorflow.python.ops.parallel_forr~   Ztensorflow.python.ops.raggedr   Ztensorflow.python.utilr   r   r   r)   r>   rI   rO   rQ   rR   r[   ra   r   r   r   r   r   r   r   r   r   r   <module>   sd    e	
#   
 C     
 p
>