
    ~WhB                        d Z ddlmc mZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ  edg            G d	 d
                      Z	 ddZddZd Zd Zej        fdZ edg           dej        dfd            Zd Zd Zd Zd Zd ZdS )z$Utilities related to loss functions.    N)backend)keras_tensor)tf_utils)keras_exportzkeras.losses.Reduction)v1c                   N    e Zd ZdZdZdZdZdZed             Z	ed             Z
dS )	ReductionV2a  Types of loss reduction.

    Contains the following values:

    * `AUTO`: Indicates that the reduction option will be determined by the
      usage context. For almost all cases this defaults to
      `SUM_OVER_BATCH_SIZE`. When used with `tf.distribute.Strategy`, outside of
      built-in training loops such as `tf.keras` `compile` and `fit`, we expect
      reduction value to be `SUM` or `NONE`. Using `AUTO` in that case will
      raise an error.
    * `NONE`: No **additional** reduction is applied to the output of the
      wrapped loss function. When non-scalar losses are returned to Keras
      functions like `fit`/`evaluate`, the unreduced vector loss is passed to
      the optimizer but the reported loss will be a scalar value.

       Caution: **Verify the shape of the outputs when using** `Reduction.NONE`.
       The builtin loss functions wrapped by the loss classes reduce one
       dimension (`axis=-1`, or `axis` if specified by loss function).
       `Reduction.NONE` just means that no **additional** reduction is applied
       by the class wrapper. For categorical losses with an example input shape
       of `[batch, W, H, n_classes]` the `n_classes` dimension is reduced. For
       pointwise losses you must include a dummy axis so that `[batch, W, H, 1]`
       is reduced to `[batch, W, H]`. Without the dummy axis `[batch, W, H]`
       will be incorrectly reduced to `[batch, W]`.

    * `SUM`: Scalar sum of weighted losses.
    * `SUM_OVER_BATCH_SIZE`: Scalar `SUM` divided by number of elements in
       losses.  This reduction type is not supported when used with
       `tf.distribute.Strategy` outside of built-in training loops like
       `tf.keras` `compile`/`fit`.

       You can implement 'SUM_OVER_BATCH_SIZE' using global batch size like:
       ```
       with strategy.scope():
         loss_obj = tf.keras.losses.CategoricalCrossentropy(
             reduction=tf.keras.losses.Reduction.NONE)
         ....
         loss = tf.reduce_sum(loss_obj(labels, predictions)) *
             (1. / global_batch_size)
       ```

    Please see the [custom training guide](
    https://www.tensorflow.org/tutorials/distribute/custom_training) for more
    details on this.
    autononesumsum_over_batch_sizec                 6    | j         | j        | j        | j        fS N)AUTONONESUMSUM_OVER_BATCH_SIZE)clss    ^/var/www/html/movieo_spanner_bot/venv/lib/python3.11/site-packages/keras/utils/losses_utils.pyallzReductionV2.allQ   s    #(CGS-DEE    c                     ||                                  vr(t          d| d|                                   d          d S )NzInvalid Reduction Key: z. Expected keys are "")r   
ValueError)r   keys     r   validatezReductionV2.validateU   sM    cggiiP#PPCGGIIPPP    r   N)__name__
__module____qualname____doc__r   r   r   r   classmethodr   r    r   r   r	   r	      sm        , ,\ DD
C/F F [F   [  r   r	   c                     t          j        |pd          5  t          j                  st	          j                  t          j                   st	          j                    j        }|j        } j        }|j        }||||z
  }||dz   k    r7|j        d         	                    d          rt	          j
        dg          n?||dz
  k    r6|j        d         	                    d          rt	          j
         dg            fcddd           S t	          j                  t	          j                   z
  }| |j        d         	                    d          r2t	          j        t	          j        |dz   |          fdfd          | |j        d         	                    d          r2t	          j        t	          j        |dz
  |           fd fd            fcddd           S # 1 swxY w Y   dS )	aH  Squeeze last dim if ranks differ from expected by exactly 1.

    In the common case where we expect shapes to match, `expected_rank_diff`
    defaults to 0, and we squeeze the last dimension of the larger rank if they
    differ by 1.

    But, for example, if `labels` contains class IDs and `predictions` contains
    1 probability per class, we expect `predictions` to have 1 more dimension
    than `labels`, so `expected_rank_diff` would be 1. In this case, we'd
    squeeze `labels` if `rank(predictions) - rank(labels) == 0`, and
    `predictions` if `rank(predictions) - rank(labels) == 2`.

    This will use static shape if available. Otherwise, it will add graph
    operations, which could result in a performance hit.

    Args:
      labels: Label values, a `Tensor` whose dimensions match `predictions`.
      predictions: Predicted values, a `Tensor` of arbitrary dimensions.
      expected_rank_diff: Expected result of `rank(predictions) - rank(labels)`.
      name: Name of the op.

    Returns:
      Tuple of `labels` and `predictions`, possibly with last dim squeezed.
    remove_squeezable_dimensionsN   c                  0    t          j         dg          S Nr&   tfsqueezepredictionss   r   <lambda>z.remove_squeezable_dimensions.<locals>.<lambda>   s    
;55 r   c                       S r   r"   r,   s   r   r.   z.remove_squeezable_dimensions.<locals>.<lambda>   s     r   c                  0    t          j         dg          S r(   r)   labelss   r   r.   z.remove_squeezable_dimensions.<locals>.<lambda>   s    
6B400 r   c                       S r   r"   r1   s   r   r.   z.remove_squeezable_dimensions.<locals>.<lambda>   s     r   )r   
name_scoper   is_tensor_or_extension_typer*   convert_to_tensorshapendimsdimsis_compatible_withr+   rankcondequal)	r2   r-   expected_rank_diffnamepredictions_shapepredictions_ranklabels_shapelabels_rank	rank_diffs	   ``       r   r$   r$   ]   s   6 
	DB$B	C	C (# (#3K@@ 	<.{;;K3F;; 	2)&11F'-,2|"(#*:*F(;6I.2227H7M8  ## 3 !jrd;;014449J:  ## 5 FRD11;&)(# (# (# (# (# (# (# (#. GK((276??:	$"2&99!<< % '+a/;;5555#### K
 b!44Q77   W+a/;;0000 F
 {"Q(# (# (# (# (# (# (# (# (# (# (# (# (# (# (# (# (# (#s   C8G?CG??HHc                 r     j         }|j        }ˉj         }|j        }|+|)||z
  dk    s|d         dk    rt                     \   nt          j                   t          j                  z
   fdt          j        dt          j                    d                    fd}t          j        t          j        d          |          \    fS j         }|j        }	|	dk    r fS |F|	D|	|z
  dk    rt          j        dg          n||	z
  dk    rt          j        dg           fS t          j                  }
|
t          j                   z
  fdfdfd	}t          j        t          j        |
d          fd
|           fS )a  Squeeze or expand last dimension if needed.

    1. Squeezes last dim of `y_pred` or `y_true` if their rank differs by 1
    (using `remove_squeezable_dimensions`).
    2. Squeezes or expands last dim of `sample_weight` if its rank differs by 1
    from the new rank of `y_pred`.
    If `sample_weight` is scalar, it is kept scalar.

    This will use static shape if available. Otherwise, it will add graph
    operations, which could result in a performance hit.

    Args:
      y_pred: Predicted values, a `Tensor` of arbitrary dimensions.
      y_true: Optional label `Tensor` whose dimensions match `y_pred`.
      sample_weight: Optional weight scalar or `Tensor` whose dimensions match
        `y_pred`.

    Returns:
      Tuple of `y_pred`, `y_true` and `sample_weight`. Each of them possibly has
      the last dimension squeezed,
      `sample_weight` could be extended by one dimension.
      If `sample_weight` is None, (y_pred, y_true) is returned.
    Nr%   r&   c                  $    t                     S r   )r$   y_predy_trues   r   r.   z.squeeze_or_expand_dimensions.<locals>.<lambda>   s    #?#O#O r   c                  8    t          j         fd          S )Nc                       fS r   r"   rG   s   r   r.   z@squeeze_or_expand_dimensions.<locals>.<lambda>.<locals>.<lambda>   s    ff5E r   )r*   r<   )is_last_dim_1squeeze_dimsrH   rI   s   r   r.   z.squeeze_or_expand_dimensions.<locals>.<lambda>   s'    |-E-E-E-E-E* * r   r   c                  0    t          j         dg          S r(   r)   sample_weights   r   r.   z.squeeze_or_expand_dimensions.<locals>.<lambda>   s    BJ}rd$C$C r   c                  f    fd} t          j        t          j        d          | fd          S )Nc                  0    t          j         dg          S r(   )r*   expand_dimsrO   s   r   r.   zMsqueeze_or_expand_dimensions.<locals>._maybe_expand_weights.<locals>.<lambda>   s    t!D!D r   r&   c                       S r   r"   rO   s   r   r.   zMsqueeze_or_expand_dimensions.<locals>._maybe_expand_weights.<locals>.<lambda>   s    ] r   r*   r<   r=   )expand_weightsrD   rP   s    r   _maybe_expand_weightsz;squeeze_or_expand_dimensions.<locals>._maybe_expand_weights   sB    DDDDwHY##^5J5J5J5J
 
 	
r   c                  V    t          j        t          j        d                     S )Nr%   rU   )rW   maybe_squeeze_weightsrD   s   r   _maybe_adjust_weightsz;squeeze_or_expand_dimensions.<locals>._maybe_adjust_weights   s,    wHY""$9;P
 
 	
r   c                       S r   r"   rO   s   r   r.   z.squeeze_or_expand_dimensions.<locals>.<lambda>   s     r   )	r7   r8   r$   r*   r;   r=   r<   r+   rS   )rH   rI   rP   y_pred_shapey_pred_ranky_true_shapey_true_rankmaybe_squeeze_dimsweights_shapeweights_rankweights_rank_tensorrZ   rW   rL   rY   rD   rM   s   ```         @@@@@r   squeeze_or_expand_dimensionsrd      s]   0 <L$K |"(#+*Ak)Q..<3Cq3H3H!=ff!M!M "'&//9IOOOOOLHQ(8(8(<==M" " " " " " "  WI&&(:L NFF v~!'M &Lqv},,l&>+%**J}rd;;MM<'1,,N=2$??Mv},, '-00#bgfoo5ICCCC
 
 
 
 
 

 
 
 
 
 
 
 G
$a(( M
 6=((r   c                 n    t          j        |           }t           j                            ||d          S )a:  Computes a safe mean of the losses.

    Args:
      losses: `Tensor` whose elements contain individual loss measurements.
      num_present: The number of measurable elements in `losses`.

    Returns:
      A scalar representing the mean of `losses`. If `num_present` is zero,
        then zero is returned.
    valuer?   )r*   
reduce_summathdivide_no_nan)lossesnum_present
total_losss      r   
_safe_meanrn      s0     v&&J7  [w GGGr   c                     t          j        d          5 }t          j        t          j        | |          | j                  cddd           S # 1 swxY w Y   dS )z3Computes the number of elements in `losses` tensor.num_elementsrg   )dtypeN)r   r4   r*   castsizerq   )rk   scopes     r   _num_elementsru     s    		N	+	+ HuwrwvE222&,GGGH H H H H H H H H H H H H H H H H Hs   /AAAc                     |t           j        k    r| }nAt          j        |           }|t           j        k    rt          |t          |                     }|S )z2Reduces the individual weighted loss measurements.)r	   r   r*   rh   r   rn   ru   )weighted_losses	reductionlosss      r   reduce_weighted_lossrz     sR     K$$$}_--777dM/$B$BCCDKr   z/keras.__internal__.losses.compute_weighted_lossc                 B   t                               |           |t           j        k    rt           j        }|d}t	          j        |pd          5  |t          j        j        	                                _
        t          | t          j        t          j        f          st          j        |           } t          |t          j        t          j        f          st          j        |          }| j        j        s| j        }t          j        | d          } d}nd}t          j        || j                  }t'          | d|          \  } }}t          j        | |          }t+          ||          }|rt          j        ||          }|cddd           S # 1 swxY w Y   dS )a  Computes the weighted loss.

    Args:
      losses: `Tensor` of shape `[batch_size, d1, ... dN]`.
      sample_weight: Optional `Tensor` whose rank is either 0, or the same rank
        as `losses`, or be broadcastable to `losses`.
      reduction: (Optional) Type of `tf.keras.losses.Reduction` to apply to
        loss. Default value is `SUM_OVER_BATCH_SIZE`.
      name: Optional name for the op.

    Raises:
      ValueError: If the shape of `sample_weight` is not compatible with
        `losses`.

    Returns:
      Weighted loss `Tensor` of the same type as `losses`. If `reduction` is
      `NONE`, this has the same shape as `losses`; otherwise, it is scalar.
    N      ?weighted_lossfloat32TF)r	   r   r   r   r   r4   r*   compatr   get_default_graph_last_loss_reduction
isinstancer   KerasTensorRaggedTensorr6   rq   is_floatingrr   rd   multiplyrz   )	rk   rP   rx   r?   input_dtypeinput_casted_rw   ry   s	            r   compute_weighted_lossr   !  s   2 ### K$$$3			D3O	4	4 $ $ AJ	&&((=&<#;R_"MNN 	2)&11FL4boF
 
 	@ 0??M |' 	! ,KWVY//FLL Lv|<< )}EE		
+fm<< $OY?? 	.74--DI$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $s   D6FFFc                 h    t           j                                        j        }|dk    r| d|z  z  } | S )zBScales and returns the given loss value by the number of replicas.r%   r|   )r*   
distributeget_strategynum_replicas_in_sync)
loss_valuenum_replicass     r   scale_loss_for_distributionr   i  s8    =--//DLacL((
r   c                     d| D ]N}|j         j        r0|j         j        j        k    r|j         n|j         hddhk    rd|j         j        r| c S Orfd| D             } | S )ar  Cast a list of losses to a common dtype.

    If any loss is floating-point, they will all be casted to the most-precise
    floating-point loss. Otherwise the losses are not casted. We also skip
    casting losses if there are any complex losses.

    Args:
      losses: A list of losses.

    Returns:
      `losses`, but they have been casted to a common dtype.
    Nbfloat16float16r~   c                 :    g | ]}t          j        |          S r"   )r*   rr   ).0ry   highest_floats     r   
<listcomp>z/cast_losses_to_common_dtype.<locals>.<listcomp>  s%    BBB4"'$..BBBr   )rq   r   rs   
is_complex)rk   ry   r   s     @r   cast_losses_to_common_dtyper   q  s     M 	 	:! 	*$
-:L(L(L $
*m,Y0GGG ):  	  	  CBBBB6BBBMr   c                 $    t          | dd          S )zReturns Keras mask from tensor._keras_maskN)getattr)y_ps    r   get_maskr     s    3t,,,r   c                     |St          j        || j                  }|5t          j        ||j                  }t          ||          \  }}}||z  }n|}|S )z2Applies any mask on predictions to sample weights.NrO   )r*   rr   rq   rd   )r   swmaskr   s       r   
apply_maskr     s`    wtSY''>TZ((B6t2NNNKD!R$JBBBIr   c                     ||t          j        || j                  }|t          j        t          j        fv rHt          j        t          j        |          | j                  }t          j        |          }|||z  z  }t          | ||          S )z;Redistribute sample weights considering only valid entries.)	r*   rr   rq   r	   r   r   rs   rh   r   )rk   r   r   rx   totalvalids         r   apply_valid_maskr     s}    wtV\**);+JKKK GBGDMM6<88EM$''EEEM!Dfb$'''r   )r   N)NN)r    tensorflow.compat.v2r   v2r*   kerasr   keras.enginer   keras.utilsr    tensorflow.python.util.tf_exportr   r	   r$   rd   rn   ru   r   rz   r   r   r   r   r   r   r"   r   r   <module>r      s    + * ! ! ! ! ! ! ! ! !       % % % % % %             : 9 9 9 9 9 &2...= = = = = = = /.=B 59C# C# C# C#LY) Y) Y) Y)xH H HH H H  +>
 
 
 
 ?BGGG -		D D D HGDN    :- - -

 
 
( ( ( ( (r   