
    rh+                        d dl mZ d dlZd dlmZ d dlmZ d dlZd dlm	c m
Z d dlmZm	Z	 d dlmZ d dlmZmZmZ ddZ G d	 d
      Z G d d      Z G d de	j,                        Zy)    )annotationsN)Iterable)Any)Tensornn)SentenceTransformer)CachedGISTEmbedLoss"CachedMultipleNegativesRankingLoss+CachedMultipleNegativesSymmetricRankingLossc                    | j                   d   }||kD  rt        d| d|       | dd |f   } t        j                  | dd      } | S )Nz
Dimension zL in matryoshka_dims cannot be greater than the model's embedding dimension: .   )pdim)shape
ValueErrorF	normalize)tensorr   
tensor_dims      ~/var/www/html/ai-insurance-compliance-backend/venv/lib/python3.12/site-packages/sentence_transformers/losses/MatryoshkaLoss.pyshrinkr      sc    b!J
Zijtiuv
 	
 C#IF[[1"-FM    c                  (    e Zd ZdZddZddZddZy)ForwardDecoratoraS  
    This decorator is used to cache the output of the Sentence Transformer's forward pass,
    so that it can be shrank and reused for multiple loss calculations. This prevents the
    model from recalculating the embeddings for each desired Matryoshka dimensionality.

    This decorator is applied to `SentenceTransformer.forward`.
    c                J    || _         d | _        g | _        d | _        d| _        y Nr   )fnr   cache	cache_dimidx)selfr   s     r   __init__zForwardDecorator.__init__'   s%    
r   c                     || _         d| _        y r   )r   r!   )r"   r   s     r   set_dimzForwardDecorator.set_dim/   s    r   c                   | j                   | j                   | j                  k(  r>| j                  |      }| j                  j	                  |       | j                  | _         n| j                  | j
                     }d|v rt        |d   | j                        |d<   t        |d   | j                        |d<   | xj
                  dz  c_        |S )Ntoken_embeddingssentence_embedding   )r    r   r   r   appendr!   r   )r"   featuresoutputs      r   __call__zForwardDecorator.__call__3   s    >>!T^^txx%?WWX&FJJf%!XXDN ZZ)F')/7I0JDHH)UF%&'-f5I.JDHH'U#$Ar   N)returnNone)r+   dict[str, Tensor]r.   r0   )__name__
__module____qualname____doc__r#   r%   r-    r   r   r   r      s    r   r   c                  2    e Zd ZdZ	 d	 	 	 	 	 	 	 ddZddZy)CachedLossDecoratora  
    This decorator is used with the Cached... losses to compute the underlying loss function
    for each Matryoshka dimensionality. This is done by shrinking the pre-computed embeddings
    to the desired dimensionality and then passing them to the underlying loss function once
    for each desired dimensionality.

    This decorator is applied to the `calculate_loss` method of the Cached... losses.
    c                <    || _         || _        || _        || _        y )N)r   matryoshka_dimsmatryoshka_weightsn_dims_per_step)r"   r   r9   r:   r;   s        r   r#   zCachedLossDecorator.__init__M   s#     ."4.r   c                   t        t        | j                              }| j                  dkD  r8| j                  t        |      k  r t	        j
                  || j                        }d}|D ]  }| j                  |   }| j                  |   }|D 	
cg c]  }	|	D 
cg c]  }
t        |
|       c}
 }}	}
t        j                         }|r<|D 	
cg c].  }	|	D 
cg c]   }
|
j                         j                         " c}
0 }}	}
n|}|| | j                  |g|i |z  z  }|st        ||      D ]7  \  }}t        ||      D ]#  \  }}|j                  ||j                  z         % 9  |S c c}
w c c}
}	w c c}
w c c}
}	w Nr   g        )rangelenr9   r;   randomsampler:   r   torchis_grad_enableddetachrequires_grad_r   zipbackwardgrad)r"   repsargskwargsdim_indiceslossr!   r   weight	minibatchr	truncatedcompute_gradientsmatryoshka_repst_minibatchd_minibatchtds                     r   r-   zCachedLossDecorator.__call__U   sv   C 4 456!#(<(<s;?O(O --T5I5IJK 	4C&&s+C,,S1FNRS)<Q&C.<SIS % 5 5 7 !en"oXa#SAAHHJ$=$=$?#S"o"o"+FWTWW_FtFvFFFD !03I0O 4,K #K = 41

6AFF?344!	4&  =S
 $T"os0   	E8E3-E8	F%E>>F3E8>FN)r   )r9   	list[int]r:   zlist[float | int]r;   intr.   r/   )rI   zlist[list[Tensor]]r.   r   )r1   r2   r3   r4   r#   r-   r5   r   r   r7   r7   C   s8     mo/#,/BS/fi/	/r   r7   c                  ^     e Zd Z	 	 d	 	 	 	 	 	 	 	 	 	 	 d fdZddZddZed	d       Z xZS )
MatryoshkaLossc                   t         |           || _        || _        |dgt	        |      z  }t        ||      }t        t        |d d       \  | _        | _        || _	        t        t        t        f| _        t        || j                        r1t        |j                   | j                  | j                        |_        yy)a  
        The MatryoshkaLoss can be seen as a loss *modifier* that allows you to use other loss functions at various
        different embedding dimensions. This is useful for when you want to train a model where users have the option
        to lower the embedding dimension to improve their embedding comparison speed and costs.

        This loss is also compatible with the Cached... losses, which are in-batch negative losses that allow for
        higher batch sizes. The higher batch sizes allow for more negatives, and often result in a stronger model.

        Args:
            model: SentenceTransformer model
            loss: The loss function to be used, e.g.
                :class:`MultipleNegativesRankingLoss`,
                :class:`CoSENTLoss`, etc.
            matryoshka_dims: A list of embedding dimensions to be used
                for the loss function, e.g. [768, 512, 256, 128, 64].
            matryoshka_weights: A list of weights to be used for the
                loss function, e.g. [1, 1, 1, 1, 1]. If None, then the
                weights will be set to 1 for all dimensions.
            n_dims_per_step: The number of dimensions to use per step.
                If -1, then all dimensions are used. If > 0, then a
                random sample of n_dims_per_step dimensions are used per
                step. The default value is -1.

        References:
            - The concept was introduced in this paper: https://arxiv.org/abs/2205.13147
            - `Matryoshka Embeddings <../../../examples/sentence_transformer/training/matryoshka/README.html>`_

        Inputs:
            +---------------------------------------+--------+
            | Texts                                 | Labels |
            +=======================================+========+
            | any                                   | any    |
            +---------------------------------------+--------+

        Relations:
            - :class:`Matryoshka2dLoss` uses this loss in combination with :class:`AdaptiveLayerLoss` which allows for
                layer reduction for faster inference.

        Example:
            ::

                from sentence_transformers import SentenceTransformer, SentenceTransformerTrainer, losses
                from datasets import Dataset

                model = SentenceTransformer("microsoft/mpnet-base")
                train_dataset = Dataset.from_dict({
                    "anchor": ["It's nice weather outside today.", "He drove to work."],
                    "positive": ["It's so sunny.", "He took the car to the office."],
                })
                loss = losses.MultipleNegativesRankingLoss(model)
                loss = losses.MatryoshkaLoss(model, loss, [768, 512, 256, 128, 64])

                trainer = SentenceTransformerTrainer(
                    model=model,
                    train_dataset=train_dataset,
                    loss=loss,
                )
                trainer.train()
        Nr)   c                    | d   S r   r5   )xs    r   <lambda>z)MatryoshkaLoss.__init__.<locals>.<lambda>   s    `abc`d r   T)keyreverse)superr#   modelrM   r?   rF   sortedr9   r:   r;   r
   r	   r   cached_losses
isinstancer7   calculate_loss)r"   rc   rM   r9   r:   r;   dims_weights	__class__s          r   r#   zMatryoshkaLoss.__init__r   s    F 	
	%"#s?';!;?,>?8;VLVdnr=s8t5d5. /7

 dD../"5##T%9%94;R;R#D 0r   c                   t        | j                  | j                        r| j                  ||      S | j                  j                  }	 t        |      }|| j                  _        t        t        | j                              }| j                  dkD  rH| j                  t        |      k  r0t        j                  || j                        }|j                          d}|D ]I  }| j                  |   }| j                  |   }	|j                  |       ||	| j                  ||      z  z  }K 	 || j                  _        |S # || j                  _        w xY wr=   )rf   rM   re   rc   forwardr   r>   r?   r9   r;   r@   rA   sortr:   r%   )
r"   sentence_featureslabelsoriginal_forwarddecorated_forwardrL   rM   r!   r   rN   s
             r   rk   zMatryoshkaLoss.forward   s2    dii!3!3499.77  ::--	2 01A B!2DJJD$8$8 9:K##a'D,@,@3{CS,S$mmK9M9MN  "D" F**3/005!))#.+<f!EEE	F "2DJJ "2DJJs   
C!D? ?Ec                    | j                   j                  j                  | j                  | j                  | j
                  dS )N)rM   r9   r:   r;   )rM   ri   r1   r9   r:   r;   r"   s    r   get_config_dictzMatryoshkaLoss.get_config_dict   s:    II''00#33"&"9"9#33	
 	
r   c                     y)Na  
@misc{kusupati2024matryoshka,
    title={Matryoshka Representation Learning},
    author={Aditya Kusupati and Gantavya Bhatt and Aniket Rege and Matthew Wallingford and Aditya Sinha and Vivek Ramanujan and William Howard-Snyder and Kaifeng Chen and Sham Kakade and Prateek Jain and Ali Farhadi},
    year={2024},
    eprint={2205.13147},
    archivePrefix={arXiv},
    primaryClass={cs.LG}
}
r5   rr   s    r   citationzMatryoshkaLoss.citation   s    	r   )Nr   )rc   r   rM   z	nn.Moduler9   rX   r:   zlist[float | int] | Noner;   rY   r.   r/   )rm   zIterable[dict[str, Tensor]]rn   r   r.   r   )r.   zdict[str, Any])r.   str)	r1   r2   r3   r#   rk   rs   propertyru   __classcell__)ri   s   @r   r[   r[   q   sp     8<!Y"Y Y #	Y
 5Y Y 
Yv8
 
 
r   r[   )r   r   r   rY   r.   r   )
__future__r   r@   collections.abcr   typingr   rB   torch.nn.functionalr   
functionalr   r   sentence_transformersr   sentence_transformers.lossesr	   r
   r   r   r   r7   Moduler[   r5   r   r   <module>r      sW    "  $      5 " "J+ +\KRYY Kr   