
    Li7                        d dl mZ d dlZd dlZd dlZd dlmZ d dlZd dl	Z	d dl	m
Z
mZ d dlmZ d dlmZ d dlmZ  G d d	ej$                        Z G d
 dej$                        Z G d d      Zy)    )annotationsN)Iterable)Tensornn)InputExample)SentenceTransformer)cos_simc                  @     e Zd ZdZd fdZdddZedd       Z xZS )	ContrastiveTensionLossa  
    This loss expects only single sentences, without any labels. Positive and negative pairs are automatically created via random sampling,
    such that a positive pair consists of two identical sentences and a negative pair consists of two different sentences. An independent
    copy of the encoder model is created, which is used for encoding the first sentence of each pair. The original encoder model encodes the
    second sentence. The embeddings are compared and scored using the generated labels (1 if positive, 0 if negative) using the binary cross
    entropy objective.

    Generally, :class:`ContrastiveTensionLossInBatchNegatives` is recommended over this loss, as it gives a stronger training signal.

    Args:
        model: SentenceTransformer model

    References:
        * Semantic Re-Tuning with Contrastive Tension: https://openreview.net/pdf?id=Ov_sMNau-PF
        * `Unsupervised Learning > CT <../../../examples/sentence_transformer/unsupervised_learning/CT/README.html>`_

    Inputs:
        +================================+=========+
        | Texts                          | Labels  |
        +================================+=========+
        | (sentence_A, sentence_B) pairs | None    |
        +================================+=========+

    Relations:
        * :class:`ContrastiveTensionLossInBatchNegatives` uses in-batch negative sampling, which gives a stronger training signal than this loss.

    Example:

        Using a dataset with sentence pairs that sometimes are identical (positive pairs) and sometimes different (negative pairs):

        ::

            import random
            from datasets import Dataset
            from sentence_transformers import SentenceTransformer, losses
            from sentence_transformers.training_args import SentenceTransformerTrainingArguments
            from sentence_transformers.trainer import SentenceTransformerTrainer

            model = SentenceTransformer('all-MiniLM-L6-v2')
            # The dataset pairs must sometimes contain identical sentences (positive pairs) and sometimes different sentences (negative pairs).
            train_dataset = Dataset.from_dict({
                "sentence_A": [
                    "It's nice weather outside today.",
                    "He drove to work.",
                    "It's so sunny.",
                ]
                "sentence_B": [
                    "It's nice weather outside today.",
                    "He drove to work.",
                    "It's so sunny.",
                ]
            })
            train_loss = losses.ContrastiveTensionLoss(model=model)

            args = SentenceTransformerTrainingArguments(
                num_train_epochs=10,
                per_device_train_batch_size=32,
                eval_steps=0.1,
                logging_steps=0.01,
                learning_rate=5e-5,
                save_strategy="no",
                fp16=True,
            )
            trainer = SentenceTransformerTrainer(model=model, args=args, train_dataset=train_dataset, loss=train_loss)
            trainer.train()

        With a dataset with single sentence pairs:

        ::

            import random
            from datasets import Dataset
            from sentence_transformers import SentenceTransformer, losses
            from sentence_transformers.training_args import SentenceTransformerTrainingArguments
            from sentence_transformers.trainer import SentenceTransformerTrainer

            model = SentenceTransformer('all-MiniLM-L6-v2')
            train_dataset = Dataset.from_dict({
                "text1": [
                    "It's nice weather outside today.",
                    "He drove to work.",
                    "It's so sunny.",
                ]
            })
            sentences = train_dataset['text1']

            def to_ct_pairs(sample, pos_neg_ratio=8):
                pos_neg_ratio = 1 / pos_neg_ratio
                sample["text2"] = sample["text1"] if random.random() < pos_neg_ratio else random.choice(sentences)
                return sample

            pos_neg_ratio = 8  # 1 positive pair for 7 negative pairs
            train_dataset = train_dataset.map(to_ct_pairs, fn_kwargs={"pos_neg_ratio": pos_neg_ratio})

            train_loss = losses.ContrastiveTensionLoss(model=model)

            args = SentenceTransformerTrainingArguments(
                num_train_epochs=10,
                per_device_train_batch_size=32,
                eval_steps=0.1,
                logging_steps=0.01,
                learning_rate=5e-5,
                save_strategy="no",
                fp16=True,
            )
            trainer = SentenceTransformerTrainer(model=model, args=args, train_dataset=train_dataset, loss=train_loss)
            trainer.train()
    c                    t         |           || _        t        j                  |      | _        t        j                  d      | _        y )Nsum)	reduction)	super__init__model2copydeepcopymodel1r   BCEWithLogitsLoss	criterion)selfmodel	__class__s     y/var/www/html/lcp-python-backend/venv/lib/python3.12/site-packages/sentence_transformers/losses/ContrastiveTensionLoss.pyr   zContrastiveTensionLoss.__init__   s7    mmE*-->    c                   t        |      \  }}| j                  |      d   }| j                  |      d   }t        j                  |d d d f   |d d d d d f         j                  d      j                  d      }||d   }|d   }	|j                  d      }
|j                  d      }|
|t        j                  t        ||
j                         |	|j                               D cg c]#  \  }}}}t        j                  ||   ||         % c}}}}|j                  |j                        }n#||	k(  j                  d      j                         }| j                  ||j!                  |            }|S c c}}}}w )Nsentence_embedding	input_idsattention_mask)devicedtype   )dim)tupler   r   torchmatmulsqueezeget	as_tensorzipboolequalr!   r"   allfloatr   type_as)r   sentence_featureslabelssentence_features1sentence_features2reps_1reps_2
sim_scores
input_ids1
input_ids2attention_mask1attention_mask2inputs1mask1inputs2mask2losss                    r   forwardzContrastiveTensionLoss.forward   s   167H1I../01EF/01EF LL4&At*<=EEbIQQRTU 	 >+K8J+K8J0445EFO0445EFO*/J ?B&(<(<(>
OL`L`Lb? :GUGU GENGENC &,,$**	 %
277A7>DDF~~j&..*DEs   ,(E<c                     yNar  
@inproceedings{carlsson2021semantic,
    title={Semantic Re-tuning with Contrastive Tension},
    author={Fredrik Carlsson and Amaru Cuba Gyllensten and Evangelia Gogoulou and Erik Ylip{"a}{"a} Hellqvist and Magnus Sahlgren},
    booktitle={International Conference on Learning Representations},
    year={2021},
    url={https://openreview.net/forum?id=Ov_sMNau-PF}
}
 r   s    r   citationzContrastiveTensionLoss.citation       r   )r   r   returnNone)N)r1   Iterable[dict[str, Tensor]]r2   zTensor | NonerH   r   rH   str)	__name__
__module____qualname____doc__r   rA   propertyrF   __classcell__r   s   @r   r   r      s)    kZ? D 	 	r   r   c                  @     e Zd Zdefd fdZddZedd       Z xZS )&ContrastiveTensionLossInBatchNegativesg      4@c                *   t         |           || _        t        j                  |      | _        || _        t        j                         | _	        t        j                  t        j                  g       t        j                  |      z        | _        y)a  
        This loss expects only single sentences, without any labels. Positive and negative pairs are automatically created via random sampling,
        such that a positive pair consists of two identical sentences and a negative pair consists of two different sentences. An independent
        copy of the encoder model is created, which is used for encoding the first sentence of each pair. The original encoder model encodes the
        second sentence. Unlike :class:`ContrastiveTensionLoss`, this loss uses the batch negative sampling strategy, i.e. the negative pairs
        are sampled from the batch. Using in-batch negative sampling gives a stronger training signal than the original :class:`ContrastiveTensionLoss`.
        The performance usually increases with increasing batch sizes.

        The training :class:`datasets.Dataset` must contain one text column.

        Args:
            model: SentenceTransformer model
            scale: Output of similarity function is multiplied by scale value
            similarity_fct: similarity function between sentence embeddings. By default, cos_sim. Can also be set to dot
                product (and then set scale to 1)

        References:
            - Semantic Re-Tuning with Contrastive Tension: https://openreview.net/pdf?id=Ov_sMNau-PF
            - `Unsupervised Learning > CT (In-Batch Negatives) <../../../examples/sentence_transformer/unsupervised_learning/CT_In-Batch_Negatives/README.html>`_

        Relations:
            * :class:`ContrastiveTensionLoss` does not select negative pairs in-batch, resulting in a weaker training signal than this loss.

        Inputs:
            +------------------+--------+
            | Texts            | Labels |
            +==================+========+
            | single sentences | none   |
            +------------------+--------+

        Example:
            ::

                from sentence_transformers import SentenceTransformer, losses
                from datasets import Dataset

                model = SentenceTransformer('all-MiniLM-L6-v2')

                train_dataset = Dataset.from_dict({
                    "sentence": [
                       "It's nice weather outside today.",
                       "He drove to work.",
                       "It's so sunny.",
                    ]
                })

                train_loss = losses.ContrastiveTensionLossInBatchNegatives(model=model)

                args = SentenceTransformerTrainingArguments(
                    num_train_epochs=10,
                    per_device_train_batch_size=32,
                    eval_steps=0.1,
                    logging_steps=0.01,
                    learning_rate=5e-5,
                    save_strategy="no",
                    fp16=True,
                )

                trainer = SentenceTransformerTrainer(
                    model=model,
                    args=args,
                    train_dataset=train_dataset,
                    loss=train_loss,
                )
                trainer.train()
        N)r   r   r   r   r   r   similarity_fctr   CrossEntropyLosscross_entropy_loss	Parameterr&   onesnploglogit_scale)r   r   scalerW   r   s       r   r   z/ContrastiveTensionLossInBatchNegatives.__init__   sg    F 	mmE*,"$"5"5"7<<

2(FGr   c                   |d   }| j                  |      d   }| j                  |      d   }| j                  ||      | j                  j	                         z  }t        j                  t        |      t
        j                  |j                        }| j                  ||      | j                  |j                         |      z   dz  S )Nr   r   )r"   r!      )r   r   rW   r^   expr&   arangelenlongr!   rY   t)r   r1   r2   embeddings_aembeddings_bscoress         r   rA   z.ContrastiveTensionLossInBatchNegatives.forward   s    -a0{{#456JK{{#456JK$$\<@4CSCSCWCWCYYc&kFMMR''7$:Q:QRXRZRZR\^d:eeijjjr   c                     yrC   rD   rE   s    r   rF   z/ContrastiveTensionLossInBatchNegatives.citation  rG   r   )r   r   r_   r/   rH   rI   )r1   rJ   r2   r   rH   r   rK   )	rM   rN   rO   r	   r   rA   rQ   rF   rR   rS   s   @r   rU   rU      s+    BFW^ HHTk 	 	r   rU   c                       e Zd ZddZd Zd Zy)ContrastiveTensionDataLoaderc                    || _         || _        || _        d | _        | j                  | j                  z  dk7  rt	        d| d| d      y )Nr   z@ContrastiveTensionDataLoader was loaded with a pos_neg_ratio of z and a batch size of z7. The batch size must be divisible by the pos_neg_ratio)	sentences
batch_sizepos_neg_ratio
collate_fn
ValueError)r   rn   ro   rp   s       r   r   z%ContrastiveTensionDataLoader.__init__  so    "$*??T///14RS`Raav  xB  wC  Cz  {  5r   c              #  "  K   t        j                  | j                         d}g }|dz   t        | j                        k  r| j                  |   }t        |      | j                  z  dkD  r|dz  }| j                  |   }d}n| j                  |   }d}|dz  }|j                  t        ||g|             t        |      | j                  k\  r#| j                  | j                  |      n| g }|dz   t        | j                        k  ry y w)Nr   r#   )textslabel)	randomshufflern   rd   rp   appendr   ro   rq   )r   sentence_idxbatchs1s2ru   s         r   __iter__z%ContrastiveTensionDataLoader.__iter__'  s     t~~&QT^^!44-B5zD...2!^^L1^^L1ALLLRHEBC5zT__,040Kdooe,QVV QT^^!44s   D
DDc                r    t        j                  t        | j                        d| j                  z  z        S )Nra   )mathfloorrd   rn   ro   rE   s    r   __len__z$ContrastiveTensionDataLoader.__len__=  s(    zz#dnn-T__1DEFFr   N)   )rM   rN   rO   r   r}   r   rD   r   r   rl   rl     s    	,Gr   rl   )
__future__r   r   r   rv   collections.abcr   numpyr\   r&   r   r   sentence_transformers.readersr   )sentence_transformers.SentenceTransformerr   sentence_transformers.utilr	   Moduler   rU   rl   rD   r   r   <module>r      sX    "    $    6 I .`RYY `F^RYY ^N#G #Gr   