
    rhC$                    v    d dl mZ d dlmZ d dlZd dlmZmZ d dlmZ d dl	m
Z
  G d dej                        Zy)	    )annotations)	GeneratorN)Tensornn)CrossEncoder)fullnamec                       e Zd Zdd ej                         f	 	 	 	 	 	 	 	 	 d
 fdZddZddZ	 	 	 	 	 	 ddZddZ	ddZ
dd	Z xZS )MultipleNegativesRankingLoss   g      $@c                   t         |           || _        || _        || _        || _        t        j                         | _        t        | j                  t              s8t        | j                  j                   dt        | j                         d      | j                  j                  dk7  r9t        | j                  j                   d| j                  j                   d      y)ax  
        Given a list of (anchor, positive) pairs or (anchor, positive, negative) triplets, this loss optimizes the following:

        * Given an anchor (e.g. a question), assign the highest similarity to the corresponding positive (i.e. answer)
          out of every single positive and negative (e.g. all answers) in the batch.

        If you provide the optional negatives, they will all be used as extra options from which the model must pick the
        correct positive. Within reason, the harder this "picking" is, the stronger the model will become. Because of
        this, a higher batch size results in more in-batch negatives, which then increases performance (to a point).

        This loss function works great to train embeddings for retrieval setups where you have positive pairs
        (e.g. (query, answer)) as it will sample in each batch ``n-1`` negative docs randomly.

        This loss is also known as InfoNCE loss, SimCSE loss, Cross-Entropy Loss with in-batch negatives, or simply
        in-batch negatives loss.

        Args:
            model (:class:`~sentence_transformers.cross_encoder.CrossEncoder`): A CrossEncoder model to be trained.
            num_negatives (int, optional): Number of in-batch negatives to sample for each anchor. Defaults to 4.
            scale (int, optional): Output of similarity function is multiplied by scale value. Defaults to 10.0.
            activation_fn (:class:`~torch.nn.Module`): Activation function applied to the logits before computing the loss. Defaults to :class:`~torch.nn.Sigmoid`.

        .. note::

            The current default values are subject to change in the future. Experimentation is encouraged.

        References:
            - Efficient Natural Language Response Suggestion for Smart Reply, Section 4.4: https://arxiv.org/pdf/1705.00652.pdf

        Requirements:
            1. Your model must be initialized with `num_labels = 1` (a.k.a. the default) to predict one class.

        Inputs:
            +-------------------------------------------------+--------+-------------------------------+
            | Texts                                           | Labels | Number of Model Output Labels |
            +=================================================+========+===============================+
            | (anchor, positive) pairs                        | none   | 1                             |
            +-------------------------------------------------+--------+-------------------------------+
            | (anchor, positive, negative) triplets           | none   | 1                             |
            +-------------------------------------------------+--------+-------------------------------+
            | (anchor, positive, negative_1, ..., negative_n) | none   | 1                             |
            +-------------------------------------------------+--------+-------------------------------+

        Recommendations:
            - Use ``BatchSamplers.NO_DUPLICATES`` (:class:`docs <sentence_transformers.training_args.BatchSamplers>`) to
              ensure that no in-batch negatives are duplicates of the anchor or positive samples.
            - Use :class:`~sentence_transformers.util.mine_hard_negatives` with ``output_format="n-tuple"`` or
              ``output_format="triplet"`` to convert question-answer pairs to triplets with hard negatives.

        Relations:
            - :class:`CachedMultipleNegativesRankingLoss` is equivalent to this loss, but it uses caching that allows for
              much higher batch sizes (and thus better performance) without extra memory usage. However, it is slightly
              slower.

        Example:
            ::

                from sentence_transformers.cross_encoder import CrossEncoder, CrossEncoderTrainer, losses
                from datasets import Dataset

                model = CrossEncoder("microsoft/mpnet-base")
                train_dataset = Dataset.from_dict({
                    "query": ["What are pandas?", "What is the capital of France?"],
                    "answer": ["Pandas are a kind of bear.", "The capital of France is Paris."],
                })
                loss = losses.MultipleNegativesRankingLoss(model)

                trainer = CrossEncoderTrainer(
                    model=model,
                    train_dataset=train_dataset,
                    loss=loss,
                )
                trainer.train()
        z? expects a model of type CrossEncoder, but got a model of type .   z; expects a model with 1 output label, but got a model with z output labels.N)super__init__modelnum_negativesscaleactivation_fnr   CrossEntropyLosscross_entropy_loss
isinstancer   
ValueError	__class____name__type
num_labels)selfr   r   r   r   r   s        /var/www/html/ai-insurance-compliance-backend/venv/lib/python3.12/site-packages/sentence_transformers/cross_encoder/losses/MultipleNegativesRankingLoss.pyr   z%MultipleNegativesRankingLoss.__init__   s    b 	
*
*"$"5"5"7$**l3>>**+ ,++/

+;*<A? 
 ::  A%>>**+ ,((,

(=(='>oO  &    c                N    t        t        ||            }| j                  |      S )N)listzipcall_model_with_pairs)r   anchors
candidatespairss       r   call_model_with_columnsz4MultipleNegativesRankingLoss.call_model_with_columnsr   s$    S*-.))%00r   c                    | j                   j                  |ddd      }|j                  | j                   j                          | j                   di |d   }|j	                  d      S )NTpt)padding
truncationreturn_tensorsr   r    )r   	tokenizertodevicesqueeze)r   r&   tokenslogitss       r   r#   z2MultipleNegativesRankingLoss.call_model_with_pairsv   sf    %%	 & 
 			$**##$%f%a(~~a  r   c              #  V  K   t        |      }t        |      }|D cg c]  }|D ]  }|  }}}t        j                  |t        j                        j	                  d|       }| j
                  G| j
                  t        |      k  r/t        j                  |j                         | j
                        }	n=t        j                  |      j	                  ||z  d      }
|
|   j                  |d      }	|	j                  D ]  }|D cg c]  }||   	 c}  y c c}}w c c}w w)N)dtyper   )lentorcheyeboolrepeatr   multinomialfloatarangereshapeT)r   r$   r%   
batch_sizenum_columnssublist	candidatecandidates_flattenedmasknegative_indicesall_indicesnegative_indices_rownegative_idxs                r   get_in_batch_negativesz3MultipleNegativesRankingLoss.get_in_batch_negatives   s     \
*o :D]gU\]		]	]] 		*EJJ7>>q+NN)d.@.@3G[C\.\$00t?Q?QR  ,,z299*{:RTUVK*4088RH$4$6$6 	` J^_,'5__	`  ^ `s   D)DCD)
D$D)c                \   t        j                  |d      j                  d|      j                  }| j                  r| j	                  |      }| j
                  r|| j
                  z  }t        j                  ||j                  t         j                        }| j                  ||      }|S )Nr   )dimr6   )r0   r5   )
r8   catr?   r@   r   r   zerosr0   longr   )r   r3   rA   labelslosss        r   calculate_lossz+MultipleNegativesRankingLoss.calculate_loss   s    6q)11"jACC ''/F::djj(F ZUZZP&&vv6r   c                B   |d   }|d   }t        |      }| j                  ||      g}| j                  ||dd        D ]#  }|j                  | j                  ||             % |dd  D ]#  }|j                  | j                  ||             % | j	                  ||      S )Nr   r      )r7   r'   rK   appendrS   )r   inputsrQ   r$   	positivesrA   scores	negativess           r   forwardz$MultipleNegativesRankingLoss.forward   s    )1I	\
..w	BC 44WfQRjI 	LIMM$66w	JK	L   	LIMM$66w	JK	L ""6:66r   c                \    | j                   | j                  t        | j                        dS )N)r   r   r   )r   r   r   r   )r   s    r   get_config_dictz,MultipleNegativesRankingLoss.get_config_dict   s*    ZZ!//%d&8&89
 	
r   )
r   r   r   z
int | Noner   intr   znn.Module | NonereturnNone)r$   	list[str]r%   ra   r_   r   )r&   list[list[str]]r_   r   )r$   ra   r%   rb   r_   z Generator[list[str], None, None])r3   r   rA   r^   r_   r   )rW   rb   rQ   r   r_   r   )r_   zdict[str, float])r   
__module____qualname__r   Sigmoidr   r'   r#   rK   rS   r[   r]   __classcell__)r   s   @r   r
   r
      s     %&*4"**,cc "c 	c
 (c 
cJ1	!` `.=`	)`0 7"
r   r
   )
__future__r   collections.abcr   r8   r   r   0sentence_transformers.cross_encoder.CrossEncoderr   sentence_transformers.utilr   Moduler
   r-   r   r   <module>rl      s)    " %   I /s
299 s
r   