§
    æ˜ºh’%  ã                   ó†   — d dl Z d dl mZmZ d dlmZmZ d dlmZ d dlm	Z	  G d„ d¦  «        Z
 G d„ d	ej        ¦  «        ZdS )
é    N)ÚnnÚTensor)ÚIterableÚDict)Úutil)ÚSentenceTransformerc                   ó@   — e Zd ZdZed„ ¦   «         Zedd„¦   «         ZdS )Ú$BatchHardTripletLossDistanceFunctionzj
    This class defines distance functions, that can be used with Batch[All/Hard/SemiHard]TripletLoss
    c                 ó2   — dt          j        | | ¦  «        z
  S )zi
        Compute the 2D matrix of cosine distances (1-cosine_similarity) between all embeddings.
        é   )r   Úpytorch_cos_sim)Ú
embeddingss    úy/var/www/html/services/rag-service/venv/lib/python3.11/site-packages/sentence_transformers/losses/BatchHardTripletLoss.pyÚcosine_distancez4BatchHardTripletLossDistanceFunction.cosine_distance   s   € ð
 •4Ô'¨
°JÑ?Ô?Ñ?Ð?ó    Fc                 ó†  — t          j        | |                      ¦   «         ¦  «        }t          j        |¦  «        }|                     d¦  «        d|z  z
  |                     d¦  «        z   }d||dk     <   |sI|                     d¦  «                             ¦   «         }||dz  z   }d|z
  t          j        |¦  «        z  }|S )a´  
        Compute the 2D matrix of eucledian distances between all the embeddings.
        Args:
            embeddings: tensor of shape (batch_size, embed_dim)
            squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
                     If false, output is the pairwise euclidean distance matrix.
        Returns:
            pairwise_distances: tensor of shape (batch_size, batch_size)
        r   g       @r   g¼‰Ø—²Òœ<ç      ð?)ÚtorchÚmatmulÚtÚdiagÚ	unsqueezeÚeqÚfloatÚsqrt)r   ÚsquaredÚdot_productÚsquare_normÚ	distancesÚmasks         r   Úeucledian_distancez7BatchHardTripletLossDistanceFunction.eucledian_distance   sÂ   € õ ”l :¨z¯|ª|©~¬~Ñ>Ô>ˆõ
 ”j Ñ-Ô-ˆð
  ×)Ò)¨!Ñ,Ô,¨s°[Ñ/@Ñ@À;×CXÒCXÐYZÑC[ÔC[Ñ[ˆ	ð $%ˆ	�)˜a’-Ñ àð 	=ð —<’< ‘?”?×(Ò(Ñ*Ô*ˆDØ! D¨5¡LÑ0ˆIà˜t™¥u¤z°)Ñ'<Ô'<Ñ<ˆIàÐr   N)F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ústaticmethodr   r!   © r   r   r
   r
      s\   € € € € € ðð ð ð@ð @ñ „\ð@ð ð"ð "ð "ñ „\ð"ð "ð "r   r
   c                   ó¾   ‡ — e Zd ZdZej        dfdedefˆ fd„Zde	e
eef                  defd„Zded	ed
efd„Zed„ ¦   «         Zed„ ¦   «         Zed„ ¦   «         Zˆ xZS )ÚBatchHardTripletLossaŸ  
    BatchHardTripletLoss takes a batch with (label, sentence) pairs and computes the loss for all possible, valid
    triplets, i.e., anchor and positive must have the same label, anchor and negative a different label. It then looks
    for the hardest positive and the hardest negatives.
    The labels must be integers, with same label indicating sentences from the same class. You train dataset
    must contain at least 2 examples per label class. The margin is computed automatically.

    Source: https://github.com/NegatioN/OnlineMiningTripletLoss/blob/master/online_triplet_loss/losses.py
    Paper: In Defense of the Triplet Loss for Person Re-Identification, https://arxiv.org/abs/1703.07737
    Blog post: https://omoindrot.github.io/triplet-loss

    :param model: SentenceTransformer model
    :param distance_metric: Function that returns a distance between two emeddings. The class SiameseDistanceMetric contains pre-defined metrices that can be used


    Example::

       from sentence_transformers import SentenceTransformer, SentencesDataset, losses
       from sentence_transformers.readers import InputExample

       model = SentenceTransformer('distilbert-base-nli-mean-tokens')
       train_examples = [InputExample(texts=['Sentence from class 0'], label=0), InputExample(texts=['Another sentence from class 0'], label=0),
           InputExample(texts=['Sentence from class 1'], label=1), InputExample(texts=['Sentence from class 2'], label=2)]
       train_dataset = SentencesDataset(train_examples, model)
       train_dataloader = DataLoader(train_dataset, shuffle=True, batch_size=train_batch_size)
       train_loss = losses.BatchHardTripletLoss(model=model)
    é   ÚmodelÚmarginc                 ó€   •— t          t          | ¦  «                             ¦   «          || _        || _        || _        d S )N)Úsuperr)   Ú__init__Úsentence_embedderÚtriplet_marginÚdistance_metric)Úselfr+   r2   r,   Ú	__class__s       €r   r/   zBatchHardTripletLoss.__init__W   s@   ø€ õ 	Õ" DÑ)Ô)×2Ò2Ñ4Ô4Ð4Ø!&ˆÔØ$ˆÔØ.ˆÔÐÐr   Úsentence_featuresÚlabelsc                 óp   — |                       |d         ¦  «        d         }|                      ||¦  «        S )Nr   Úsentence_embedding)r0   Úbatch_hard_triplet_loss)r3   r5   r6   Úreps       r   ÚforwardzBatchHardTripletLoss.forwardb   s7   € Ø×$Ò$Ð%6°qÔ%9Ñ:Ô:Ð;OÔPˆØ×+Ò+¨F°CÑ8Ô8Ð8r   r   Úreturnc                 óð  — |                       |¦  «        }t                               |¦  «                             ¦   «         }||z  }|                     dd¬¦  «        \  }}t                               |¦  «                             ¦   «         }|                     dd¬¦  «        \  }	}||	d|z
  z  z   }
|
                     dd¬¦  «        \  }}||z
  | j        z   }d||dk     <   |                     ¦   «         }|S )ab  Build the triplet loss over a batch of embeddings.
        For each anchor, we get the hardest positive and hardest negative to form a triplet.
        Args:
            labels: labels of the batch, of size (batch_size,)
            embeddings: tensor of shape (batch_size, embed_dim)
            margin: margin for triplet loss
            squared: Boolean. If true, output is the pairwise squared euclidean distance matrix.
                     If false, output is the pairwise euclidean distance matrix.
        Returns:
            Label_Sentence_Triplet: scalar tensor containing the triplet loss
        r   T)Úkeepdimr   r   )	r2   r)   Ú get_anchor_positive_triplet_maskr   ÚmaxÚ get_anchor_negative_triplet_maskÚminr1   Úmean)r3   r6   r   Úpairwise_distÚmask_anchor_positiveÚanchor_positive_distÚhardest_positive_distÚ_Úmask_anchor_negativeÚmax_anchor_negative_distÚanchor_negative_distÚhardest_negative_distÚtlÚtriplet_losss                 r   r9   z,BatchHardTripletLoss.batch_hard_triplet_lossj   s  € ð ×,Ò,¨ZÑ8Ô8ˆõ  4×TÒTÐU[Ñ\Ô\×bÒbÑdÔdÐð  4°mÑCÐð $8×#;Ò#;¸AÀtÐ#;Ñ#LÔ#LÑ Ð˜qõ  4×TÒTÐU[Ñ\Ô\×bÒbÑdÔdÐð '4×&7Ò&7¸À4Ð&7Ñ&HÔ&HÑ#Ð  !Ø,Ð/GÈ3ÐQeÑKeÑ/fÑfÐð $8×#;Ò#;¸AÀtÐ#;Ñ#LÔ#LÑ Ð˜qð #Ð%:Ñ:¸TÔ=PÑPˆØˆˆ2�Š6‰
Ø—w’w‘y”yˆàÐr   c                 óØ  — t          j        |                      d¦  «        | j        ¬¦  «                             ¦   «         }| }|                     d¦  «        }|                     d¦  «        }|                     d¦  «        }||z  |z  }|                      d¦  «        |                      d¦  «        k    }|                     d¦  «        }|                     d¦  «        }	|	 |z  }
|
|z  S )a1  Return a 3D mask where mask[a, p, n] is True iff the triplet (a, p, n) is valid.
        A triplet (i, j, k) is valid if:
            - i, j, k are distinct
            - labels[i] == labels[j] and labels[i] != labels[k]
        Args:
            labels: tf.int32 `Tensor` with shape [batch_size]
        r   ©Údeviceé   r   ©r   ÚeyeÚsizerQ   Úboolr   )r6   Úindices_equalÚindices_not_equalÚi_not_equal_jÚi_not_equal_kÚj_not_equal_kÚdistinct_indicesÚlabel_equalÚ	i_equal_jÚ	i_equal_kÚvalid_labelss              r   Úget_triplet_maskz%BatchHardTripletLoss.get_triplet_mask•   så   € õ œ	 &§+¢+¨a¡.¤.¸¼ÐGÑGÔG×LÒLÑNÔNˆØ*˜NÐØ)×3Ò3°AÑ6Ô6ˆØ)×3Ò3°AÑ6Ô6ˆØ)×3Ò3°AÑ6Ô6ˆà)¨MÑ9¸]ÑJÐà×&Ò& qÑ)Ô)¨V×-=Ò-=¸aÑ-@Ô-@Ò@ˆØ×)Ò)¨!Ñ,Ô,ˆ	Ø×)Ò)¨!Ñ,Ô,ˆ	à!�z IÑ-ˆàÐ.Ñ.Ð.r   c                 óê   — t          j        |                      d¦  «        | j        ¬¦  «                             ¦   «         }| }|                      d¦  «        |                      d¦  «        k    }||z  S )a  Return a 2D mask where mask[a, p] is True iff a and p are distinct and have same label.
        Args:
            labels: tf.int32 `Tensor` with shape [batch_size]
        Returns:
            mask: tf.bool `Tensor` with shape [batch_size, batch_size]
        r   rP   r   rS   )r6   rW   rX   Úlabels_equals       r   r?   z5BatchHardTripletLoss.get_anchor_positive_triplet_mask¯   sl   € õ œ	 &§+¢+¨a¡.¤.¸¼ÐGÑGÔG×LÒLÑNÔNˆØ*˜NÐð ×'Ò'¨Ñ*Ô*¨f×.>Ò.>¸qÑ.AÔ.AÒAˆàÐ/Ñ/Ð/r   c                 ó\   — |                       d¦  «        |                       d¦  «        k     S )zøReturn a 2D mask where mask[a, n] is True iff a and n have distinct labels.
        Args:
            labels: tf.int32 `Tensor` with shape [batch_size]
        Returns:
            mask: tf.bool `Tensor` with shape [batch_size, batch_size]
        r   r   )r   )r6   s    r   rA   z5BatchHardTripletLoss.get_anchor_negative_triplet_maskÂ   s.   € ð ×!Ò! !Ñ$Ô$¨×(8Ò(8¸Ñ(;Ô(;Ò;Ð<Ð<r   )r"   r#   r$   r%   r
   r!   r   r   r/   r   r   Ústrr   r;   r9   r&   ra   r?   rA   Ú__classcell__)r4   s   @r   r)   r)   :   s  ø€ € € € € ðð ð> =ÔOØð		/ð 	/à"ð	/ð ð		/ð 	/ð 	/ð 	/ð 	/ð 	/ð9¨°$°s¸F°{Ô2CÔ)Dð 9Èfð 9ð 9ð 9ð 9ð)¨fð )À&ð )ÈVð )ð )ð )ð )ðV ð/ð /ñ „\ð/ð2 ð0ð 0ñ „\ð0ð$ ð
=ð 
=ñ „\ð
=ð 
=ð 
=ð 
=ð 
=r   r)   )r   r   r   Útypingr   r   Úsentence_transformersr   Ú)sentence_transformers.SentenceTransformerr   r
   ÚModuler)   r'   r   r   ú<module>rk      sË   ðØ €€€Ø Ð Ð Ð Ð Ð Ð Ð Ø !Ð !Ð !Ð !Ð !Ð !Ð !Ð !Ø &Ð &Ð &Ð &Ð &Ð &Ø IÐ IÐ IÐ IÐ IÐ Ið/ð /ð /ð /ð /ñ /ô /ð /ðdS=ð S=ð S=ð S=ð S=˜2œ9ñ S=ô S=ð S=ð S=ð S=r   