a
    Sic!                     @   s.  d Z ddlZddlZddlmZ ddl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ZG d	d
 d
eZdd Zdd Zdd Zdd Zd0ddZG dd deZG dd deZG dd deZd1ddZdd  Zd2d!d"Zd#d$ Zd3d%d&Z d'd( Z!d4d)d*Z"d+d, Z#d5d.d/Z$dS )6zUtils related to keras metrics.    N)Enum)backend)losses_utils)tf_utils)to_listg    _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.
    sumsum_over_batch_sizeweighted_meanN)__name__
__module____qualname____doc__SUMSUM_OVER_BATCH_SIZEWEIGHTED_MEAN r   r   U/var/www/html/django/DPS/env/lib/python3.9/site-packages/keras/utils/metrics_utils.pyr   !   s   
r   c                    s    fdd}t jj |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                    s   t j }| jD ],}t|r|j|st j st	dqt
j|i |  |i |}W d   n1 sr0    Y  |dur| | |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)tf
distributeget_strategyweightsr   is_tpu_strategyextendedvariable_created_in_scopein_cross_replica_context
ValueErrorr   "graph_context_for_symbolic_tensors
add_update)
metric_objargskwargsstrategyweight	update_opupdate_state_fnr   r   	decorated;   s     


,
z'update_state_wrapper.<locals>.decoratedr   __internal__	decoratormake_decorator)r&   r'   r   r%   r   update_state_wrapper1   s    
r,   c                    s    fdd}t jj |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 j }|du st jj rt jj   | }t|t jt jt	t
frVt |}n\t|trtdd | D }n>zt |}W n. ttfy   td| j d| dY n0 W d   q1 s0    Y  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>zqThe output of `metric.result()` can only be a single Tensor/Variable, or a dict of Tensors/Variables. For metric z, got result .c                 W   s   |  |d | }t|S )Nr   )experimental_local_resultsr   r-   )distributionmerge_fnr    resultr   r   r   merge_fn_wrapper   s    z;result_wrapper.<locals>.decorated.<locals>.merge_fn_wrapper)r    )r   r   get_replica_contextr)   strategy_supports_no_merge_callvariable_sync_on_read_context
isinstanceTensorVariablefloatintr-   dictitemsr   	TypeErrorRuntimeErrorname
merge_call_call_result)r   r    replica_context
raw_resultresult_tr7   	result_fnr   r   r'   h   s:    


*
z!result_wrapper.<locals>.decoratedr(   )rK   r'   r   rJ   r   result_wrapperU   s    WrL   c                    s8   | j  | jt| jt|  fdd}~ |S )z-Creates a weak reference to the bound method.c                     s      | i |S N)__get__)r    r!   clsfuncinstance_refr   r   inner   s    zweakmethod.<locals>.inner)im_classim_funcweakrefrefim_self	functoolswraps)methodrS   r   rO   r   
weakmethod   s    r\   c                 C   s,   | d ur(dd | D }|r(t d| d S )Nc                 S   s(   g | ] }|d u s |dk s |dkr|qS )Nr      r   )r.   tr   r   r   
<listcomp>   s   z+assert_thresholds_range.<locals>.<listcomp>z.Threshold values must be in [0, 1]. Received: )r   )
thresholdsinvalid_thresholdsr   r   r   assert_thresholds_range   s    rb         ?c                 C   s,   | d urt t|  t| d u r"|n| } | S rM   )rb   r   )r`   default_thresholdr   r   r   parse_init_thresholds   s    re   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   rf      s   rf   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   s0   | dv rt jS | dv rt jS td|  dd S )N)prrq   )rocrp   zInvalid AUC curve value: "z$". Expected values are ["PR", "ROC"])ro   rq   rp   r   r/   r   r   r   from_str   s    
zAUCCurve.from_strN)r   r   r   r   rp   rq   staticmethodru   r   r   r   r   ro      s
   ro   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v rt jS | dv rt jS | dv r*t jS td|  dd S )N)rx   Interpolation)ry   Majoring)rz   Minoringz%Invalid AUC summation method value: "z@". Expected values are ["interpolation", "majoring", "minoring"])rw   INTERPOLATIONMAJORINGMINORINGr   rt   r   r   r   ru     s    
zAUCSummationMethod.from_strN)	r   r   r   r   r~   r   r   rv   ru   r   r   r   r   rw      s   rw   Fc                    s  |j  d  |du rd}n.tjjtj||jd|}|sJt|dg}|du rXd}n.t	|d}tjj||}|st|dg}tt
|||j}tj|ddd}tt|tj|j}|st|dg}t|dg}t
||}	t
d| |}
tj| d  d }|r*tj|}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j|	| d}tjj|
| d}tj|dd}tj|dd}tj| v stj| v rF|r2tj|	dd}tj|
dd}nt|	}t|
}g }tj| v rp| tj }||| tj| v r| tj }||| tj| v r| tj }|| }||| tj| v r| tj }|| }||| t|S )a.  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   N      ?dtype        )clip_value_minclip_value_maxr]   c                    s$   | d | d  }}t jj|| dS )Nr   r]   datasegment_idsnum_segments)r   mathunsorted_segment_sum)label_and_bucket_indexlabelbucket_indexnum_thresholdsr   r   gather_bucket  s    zC_update_confusion_matrix_variables_optimized.<locals>.gather_bucketT)reverseaxisr   )r   r   )shapeas_listr   r)   opsbroadcast_weightscastr   reshapeexpand_dimsmultiplyclip_by_valueboolr   ceilnnreluint32	transposevectorized_mapcumsumr   rf   rm   rn   
reduce_sumrk   append
assign_addrl   group)variables_to_updatey_truey_predr`   multi_labelsample_weightslabel_weightsthresholds_with_epsilonr   true_labelsfalse_labelsbucket_indicesr   tp_bucket_vfp_bucket_vrg   rh   total_true_labelstotal_false_labels
update_opsvariableri   rj   r   r   r   ,_update_confusion_matrix_variables_optimized"  s    f








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
    evaluated.

    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.
       Fr   r]   )atol)lennparangefloat32allcloser   epsilon)r`   r   even_thresholdsr   r   r    is_evenly_distributed_thresholds   s    r   c
           *   
   C   sv  |r|durt d| du r dS tdd | D sPt dtt d|   d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 }|r2t d| dtt d|du rNt||\}}n$tj||
d	}tj|||d\}}}|j
|j
 |durt||}|dur|d|f }|d|f }|	rt| |||||||dS t
|}|d }|j
jdkrd}ntjj|dd dd}t||tjg tjd	}|rXt|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ur>tj j!"tj||
d	|}tt|||}nd}|dur|st|d}tj j!"||}tt|||}|du r|}nt#||}g }dd } tj$||fi}!tj%| v }"tj&| v }#tj'| v }$|$s|"rt(|}%||%f|!tj'< |#s|"r2t(|}&|&|f|!tj&< |"r2|&|%f|!tj%< |!) D ]0\}'\}(})|'| v r:|*| |(|)|| |'  q:t+|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v r|V  qd S rM   listrf   r.   r/   r   r   r   	<genexpr>e  s   z4update_confusion_matrix_variables.<locals>.<genexpr>zhPlease provide at least one valid confusion matrix variable to update. Valid variable key options are: "z". Received: ""r   r   r   r   r   r]   one_set_of_thresholds_cond)rD   Tc                 S   s   g | ]}|t tvr|qS r   r   r   r   r   r   r_     s   z5update_confusion_matrix_variables.<locals>.<listcomp>zInvalid keys: "z$". Valid variable key options are: ")sample_weight.)r   r   r   r   r   c                 S   sF   t jt | ||jd}|d ur4|t j||jd9 }|t |dS )Nr   r]   )r   r   logical_andr   r   r   )r   predr   varlabel_and_predr   r   r   weighted_assign_add  s    z>update_confusion_matrix_variables.<locals>.weighted_assign_add),r   anyr   rf   keysvaluesr   r   r   convert_to_tensorr   r   equalr   rank,ragged_assert_compatible_and_get_flat_valuesr   r   squeeze_or_expand_dimensionsassert_is_compatible_with_filter_top_kr   ndimsr   reduce_prodwhereonesr   r   tilestackgreaterr)   r   r   r   rk   rm   rl   rn   logical_notrA   r   r   )*r   r   r   r`   top_kclass_idr   r   r   thresholds_distributed_evenlyvariable_dtyper   r   
one_thresh_invalid_keys
pred_shapenum_predictions
num_labelsthresh_label_tilepredictions_extra_dimlabels_extra_dimthresh_pretile_shapethresh_tiles
data_tilesthresh_tiledpreds_tiledpred_is_poslabel_is_posweights_tiledlabel_weights_tiledr   r   	loop_vars	update_tn	update_fp	update_fnpred_is_neglabel_is_negmatrix_condr   r   r   r   r   !update_confusion_matrix_variables  s   E

















r  c                 C   sN   t jj| |dd\}}t jt j|t | d dddd}| | td|   S )as  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)sortedr   r   r]   )r   r   r   r   one_hotr   NEG_INF)xkr   	top_k_idx
top_k_maskr   r   r   r     s
    r   c           
   	   C   s  t | tr0tdd | D }tdd | D }nt | tj}|}|rB|du s\t |tjrBd}t | tst| g} d}dd | D }t|}t |tjrt|d	 |jg}t| t	|j
d
}W d   n1 s0    Y  g }| D ]D}	t|$ |t	|	j
d
 W d   q1 s"0    Y  q|r<|d	 n|} n8|rXtd|  n"t |tjrztd|  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 rM   r;   r   RaggedTensorr.   rtr   r   r   r   F      z?ragged_assert_compatible_and_get_flat_values.<locals>.<genexpr>c                 s   s   | ]}t |tjV  qd S rM   r  r  r   r   r   r   G  r  NFTc                 S   s   g | ]
}|j qS r   )nested_row_splitsr  r   r   r   r_   T  r  z@ragged_assert_compatible_and_get_flat_values.<locals>.<listcomp>r   r   z<Some of the inputs are not tf.RaggedTensor. Input received: zCRagged mask is not allowed with non-ragged inputs. Input received: z, mask received: )r;   r   allr   r   r  _assert_splits_matchr  control_dependenciesr   flat_valuesr   rB   )
r   maskis_all_raggedis_any_raggedto_be_strippednested_row_split_listassertion_listassertion_list_for_maskr  r0   r   r   r   r   3  sL    

,6r   c                    sL   d  D ] }t |t d krt q fdddd D S )aO  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 splits. Input received: r   c                    s6   g | ].}t d  |D ]\}}tjj|| dqqS )r   )message)zipr   	debuggingassert_equal)r.   splits_lists1s2	error_msgnested_splits_listsr   r   r_     s   z(_assert_splits_match.<locals>.<listcomp>r]   N)r   r   )r%  r   r   r#  r   r  w  s    

r  c                 C   sB   t |}t ||j}t ||k|j}t t | |t S )a  Creates int Tensor, 1 for label-prediction match, 0 for mismatch.

    Args:
      y_true: Ground truth values, of shape (batch_size, d0, .. dN).
      y_pred: The predicted values, of shape (batch_size, d0, .. dN).
      threshold: (Optional) Float representing the threshold for deciding
        whether prediction values are 1 or 0.

    Returns:
      Binary matches, of shape (batch_size, d0, .. dN).
    )r   r   r   r   r   r   floatx)r   r   	thresholdr   r   r   binary_matches  s    
r(  c                 C   s   d}t |}t | } t | }|jj}| jj}|durp|durptt| tt|krpt | dg} d}t jj	|dd}t
|t
| krt |t
| }t t | |t }|rt j||d}|S )af  Creates float Tensor, 1.0 for label-prediction match, 0.0 for mismatch.

    You can provide logits of classes as `y_pred`, since argmax of
    logits and probabilities are same.

    Args:
      y_true: Integer ground truth values.
      y_pred: The prediction values.

    Returns:
      Match tensor: 1.0 for label-prediction match, 0.0 for mismatch.
    FNr   Tr   r   )r   r   r   r   r   r   	int_shapesqueezer   argmaxr   r   r   r&  r   )r   r   reshape_matchesy_true_org_shapey_pred_ranky_true_rankmatchesr   r   r   sparse_categorical_matches  s*    


r2     c                 C   s   d}t | } t |}| jj}|jj}t | }|durz|durz|dkr`t |d|jd g}|dkrzd}t | dg} t jt jj|t | d|dt	 d	}|rt j||d
S |S )aj  Creates float Tensor, 1.0 for label-TopK_prediction match, 0.0 for
    mismatch.

    Args:
      y_true: tensor of true targets.
      y_pred: tensor of predicted targets.
      k: (Optional) Number of top elements to look at for computing accuracy.
        Defaults to 5.

    Returns:
      Match tensor: 1.0 for label-prediction match, 0.0 for mismatch.
    FN   r   r]   Tr   )predictionstargetsr  r   r)  )
r   r   r   r   r   r   r   in_top_kr   r&  )r   r   r  r-  r0  r/  r.  r1  r   r   r    sparse_top_k_categorical_matches  s*    


r8  )rc   )FNNF)NNNFNF)N)rc   )r3  )%r   rY   rV   enumr   numpyr   tensorflow.compat.v2compatv2r   kerasr   keras.utilsr   r   keras.utils.generic_utilsr   r  r   r,   rL   r\   rb   re   rf   ro   rw   r   r   r  r   r   r  r(  r2  r8  r   r   r   r   <module>   sR   $m
	'    
 _      
  	
D
(