§
    +�’j%  ã                  ó°   — d dl mZ d dlmZ d dlZd dlmZ d dlmc mZ	 d dl
mZ d dlmZ dd
„Z G d„ dej        ¦  «        Z G d„ dej        ¦  «        ZdS )é    )Úannotations)ÚIterableN)Ú"SparseMultipleNegativesRankingLoss)ÚSparseEncoderÚreconstructionútorch.TensorÚoriginal_inputÚreturnc                óÌ   — |                      d¬¦  «        }t          j        | |¦  «        t          j        |ddd…f                              |j        ¦  «        |¦  «        z  }|S )zâ
    :param reconstruction: output of Autoencoder.decode (shape: [batch, n_inputs])
    :param original_input: input of Autoencoder.encode (shape: [batch, n_inputs])
    :return: normalized mean squared error (shape: [1])
    r   )ÚdimN)ÚmeanÚFÚmse_lossÚbroadcast_toÚshape)r   r	   Úoriginal_input_meanÚlosss       ú]C:\Projects\DSCons\.venv\Lib\site-packages\sentence_transformers\sparse_encoder\losses\csr.pyÚnormalized_mean_squared_errorr      si   € ð )×-Ò-°!Ð-Ñ4Ô4ÐÝŒ:�n nÑ5Ô5½¼
Ø˜D ! ! !˜GÔ$×1Ò1°.Ô2FÑGÔGÈñ9ô 9ñ €Dð €Kó    c                  ó8   ‡ — e Zd Zddˆ fd„Zdd„Zdd„Zd„ Zˆ xZS )ÚCSRReconstructionLossç      ð?Úmodelr   ÚbetaÚfloatr
   ÚNonec                ód   •— t          ¦   «                              ¦   «          || _        || _        dS )a³  
        CSRReconstructionLoss implements the reconstruction loss component for Contrastive Sparse Representation (CSR) models.

        This loss ensures that the sparse encoding can accurately reconstruct the original model embeddings through
        three components:

        1. A primary reconstruction loss (L_k) that measures the error between the original embedding and its
           reconstruction using the top-k sparse components.
        2. A secondary reconstruction loss (L_4k) that measures the error using the top-4k sparse components.
        3. An auxiliary loss (L_aux) that helps to learn residual information.

        Args:
            model: SparseEncoder model with autoencoder components
            beta: Weight for the auxiliary loss component (L_aux)

        References:
            - For more details, see the paper "Beyond Matryoshka: Revisiting Sparse Coding for Adaptive Representation"
              https://huggingface.co/papers/2503.01776

        Requirements:
            1. The model must be configured to output the necessary reconstruction components
            2. Used with SparseEncoder models that implement compositional sparse autoencoding

        Relations:
            - Used as a component within :class:`CSRLoss` combined with a contrastive loss

        Example:
            - This loss is never used standalone, but instead used within the :class:`CSRLoss` class. See that loss for more details.
        N)ÚsuperÚ__init__r   r   )Úselfr   r   Ú	__class__s      €r   r    zCSRReconstructionLoss.__init__   s-   ø€ õ< 	‰Œ×ÒÑÔÐØˆŒ
ØˆŒ	ˆ	ˆ	r   Úsentence_featuresú!Iterable[dict[str, torch.Tensor]]údict[str, torch.Tensor]c                ó    — t          d¦  «        ‚)Nz[CSRReconstructionLoss is not intended to be used standalone. Use it within CSRLoss instead.)ÚNotImplementedError)r!   r#   s     r   ÚforwardzCSRReconstructionLoss.forward?   s   € Ý!Øiñ
ô 
ð 	
r   Úoutputsúlist[dict[str, torch.Tensor]]c                óŽ  — d}d}d}|D ]ˆ}|d         }|d         }|d         }|d         }	|d         }
t          j        ||¦  «        }t          j        ||¦  «        }t          |	||
                     ¦   «         z
  ¦  «        }||z  }||z  }||z  }Œ‰t	          |¦  «        }|dk    r||z  }||z  }||z  }||dz  | j        |z  d	œS )
a  
        Compute the CSRReconstruction loss from embeddings.

        Args:
            outputs: List of dictionaries containing embeddings and their sparse representations

        Returns:
            total_loss: The total reconstruction loss value
        g        Úsentence_embedding_backboneÚdecoded_embedding_kÚdecoded_embedding_4kÚdecoded_embedding_auxÚdecoded_embedding_k_pre_biasr   g       @)Úreconstruction_loss_kÚreconstruction_loss_4kÚreconstruction_loss_aux)r   r   r   ÚdetachÚlenr   )r!   r)   Ú	total_L_kÚ
total_L_4kÚtotal_L_auxÚfeaturesÚxÚrecons_kÚ	recons_4kÚ
recons_auxÚreconsk_pre_biasÚL_kÚL_4kÚL_auxÚnum_columnss                  r   Úcompute_loss_from_embeddingsz2CSRReconstructionLoss.compute_loss_from_embeddingsD   s!  € ð ˆ	Øˆ
Øˆð  ð 	!ð 	!ˆHØÐ6Ô7ˆAØÐ 5Ô6ˆHØ Ð!7Ô8ˆIØ!Ð"9Ô:ˆJØ'Ð(FÔGÐõ ”*˜Q Ñ)Ô)ˆCõ ”:˜a Ñ+Ô+ˆDõ 2°*¸aÐBR×BYÒBYÑB[ÔB[Ñ>[Ñ\Ô\ˆEð ˜ÑˆIØ˜$ÑˆJØ˜5Ñ ˆKˆKõ ˜'‘l”lˆØ˜Š?ˆ?Ø˜Ñ$ˆIØ˜+Ñ%ˆJØ˜;Ñ&ˆKð &/Ø&0°3Ñ&6Ø'+¤y°;Ñ'>ð
ð 
ð 	
r   c                ó   — d| j         iS )ú„
        Get the configuration dictionary.

        Returns:
            Dictionary containing the configuration parameters
        r   )r   ©r!   s    r   Úget_config_dictz%CSRReconstructionLoss.get_config_dictw   s   € ð ˜œ	Ð"Ð"r   )r   )r   r   r   r   r
   r   )r#   r$   r
   r%   )r)   r*   r
   r%   )Ú__name__Ú
__module__Ú__qualname__r    r(   rC   rG   Ú__classcell__©r"   s   @r   r   r      s{   ø€ € € € € ð ð  ð  ð  ð  ð  ð  ðD
ð 
ð 
ð 
ð
1
ð 1
ð 1
ð 1
ðf#ð #ð #ð #ð #ð #ð #r   r   c                  óL   ‡ — e Zd Zddˆ fd„Z	 ddd„Zd„ Zedd„¦   «         Zˆ xZS )ÚCSRLossNçš™™™™™¹?r   r   r   r   únn.Module | Noner   r   Úgammac                óÐ   •— t          ¦   «                              ¦   «          || _        || _        || _        t          ||¬¦  «        | _        |�|nt          |¬¦  «        | _        dS )a9	  
        CSRLoss implements a combined loss function for Contrastive Sparse Representation (CSR) models.

        This loss combines two components:

        1. A reconstruction loss :class:`CSRReconstructionLoss` that ensures the sparse representation can faithfully
           reconstruct the original embedding.
        2. A main loss, which in the paper is a :class:`SparseMultipleNegativesRankingLoss` that ensures semantically
           similar inputs have similar representations.

        The total loss is linear combination of the two losses.

        Args:
            model: SparseEncoder model
            loss: The principal loss function to use can be any of the SparseEncoder losses except flops loss and CSRReconstruction loss.
                If None, the default loss is used, which is the SparseMultipleNegativesRankingLoss.
            beta: Weight for the L_aux component in the reconstruction loss. Default is 0.1.
            gamma: Weight for the main loss component (MNRL a.k.a. InfoNCE by default). Default is 1.0.

        References:
            - For more details, see the paper "Beyond Matryoshka: Revisiting Sparse Coding for Adaptive Representation"
              https://huggingface.co/papers/2503.01776

        Requirements:
            1. Input requirements depend on the chosen loss
            2. Uses autoencoder components of the SparseEncoder model

        Relations:
            - Uses :class:`CSRReconstructionLoss` for the reconstruction component

        Example:
            ::

                from datasets import Dataset
                from sentence_transformers.sparse_encoder import SparseEncoder, SparseEncoderTrainer, losses

                model = SparseEncoder("sentence-transformers/all-MiniLM-L6-v2")
                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."],
                        "negative": ["It's quite rainy, sadly.", "She walked to the store."],
                    }
                )
                loss = losses.CSRLoss(model, beta=0.1, gamma=1.0)

                trainer = SparseEncoderTrainer(model=model, train_dataset=train_dataset, loss=loss)
                trainer.train()
        )r   r   N©r   )	r   r    r   r   rQ   r   Úreconstruction_lossr   r   )r!   r   r   r   rQ   r"   s        €r   r    zCSRLoss.__init__‚   si   ø€ õd 	‰Œ×ÒÑÔÐØˆŒ
ØˆŒ	ØˆŒ
õ $9¸uÈ4Ð#PÑ#PÔ#PˆÔ Ø Ð,�D�DÕ2TÐ[`Ð2aÑ2aÔ2aˆŒ	ˆ	ˆ	r   r#   r$   Úlabelsútorch.Tensor | Noner
   r%   c                ó:  ‡ — ˆ fd„|D ¦   «         }d„ |D ¦   «         }‰ j                              |¦  «        }‰ j                             ||¦  «        }t          |t          ¦  «        r(|                     ¦   «         D ]\  }}|‰ j        z  ||<   Œn|‰ j        z  |d<   |S )Nc                ó:   •— g | ]}‰                      |¦  «        ‘ŒS © rS   )Ú.0Úsentence_featurer!   s     €r   ú
<listcomp>z#CSRLoss.forward.<locals>.<listcomp>Á   s'   ø€ ÐZÐZÐZÐ4D�4—:’:Ð.Ñ/Ô/ÐZÐZÐZr   c                ó   — g | ]
}|d          ‘ŒS )Úsentence_embeddingrY   )rZ   Úoutputs     r   r\   z#CSRLoss.forward.<locals>.<listcomp>Â   s   € ÐQÐQÐQ¸v˜fÐ%9Ô:ÐQÐQÐQr   Ú	base_loss)rT   rC   r   Ú
isinstanceÚdictÚitemsrQ   )	r!   r#   rU   r)   r^   Úlossesr`   ÚkeyÚvalues	   `        r   r(   zCSRLoss.forward½   sÀ   ø€ ð [ÐZÐZÐZÐHYÐZÑZÔZˆØQÐQÈÐQÑQÔQÐàÔ)×FÒFÀwÑOÔOˆØ”I×:Ò:Ð;MÈvÑVÔVˆ	å�i¥Ñ&Ô&ð 	9Ø'ŸošoÑ/Ô/ð 1ð 1‘
��UØ# d¤jÑ0��s‘�ð1ð #,¨d¬jÑ"8ˆF�;Ñàˆr   c                óP   — | j         | j        t          | j        ¦  «        j        dœS )rE   )r   rQ   r   )r   rQ   Útyper   rH   rF   s    r   rG   zCSRLoss.get_config_dictÏ   s#   € ð œ	¨D¬JÅÀTÄYÁÄÔ@XÐYÐYÐYr   Ústrc                ó   — dS )NaÅ  
@misc{wen2025matryoshkarevisitingsparsecoding,
      title={Beyond Matryoshka: Revisiting Sparse Coding for Adaptive Representation},
      author={Tiansheng Wen and Yifei Wang and Zequn Zeng and Zhong Peng and Yudi Su and Xinyang Liu and Bo Chen and Hongwei Liu and Stefanie Jegelka and Chenyu You},
      year={2025},
      eprint={2503.01776},
      archivePrefix={arXiv},
      primaryClass={cs.LG},
      url={https://arxiv.org/abs/2503.01776},
}
rY   rF   s    r   ÚcitationzCSRLoss.citationØ   s   € ð
ð 
r   )NrO   r   )r   r   r   rP   r   r   rQ   r   )N)r#   r$   rU   rV   r
   r%   )r
   ri   )	rH   rI   rJ   r    r(   rG   Úpropertyrk   rK   rL   s   @r   rN   rN   �   sœ   ø€ € € € € ð9bð 9bð 9bð 9bð 9bð 9bð 9bðx cgðð ð ð ð ð$Zð Zð Zð ðð ð ñ „Xðð ð ð ð r   rN   )r   r   r	   r   r
   r   )Ú
__future__r   Úcollections.abcr   ÚtorchÚtorch.nnÚnnÚtorch.nn.functionalÚ
functionalr   ÚMsentence_transformers.sparse_encoder.losses.sparse_multiple_negatives_rankingr   Ú*sentence_transformers.sparse_encoder.modelr   r   ÚModuler   rN   rY   r   r   ú<module>rw      s  ðØ "Ð "Ð "Ð "Ð "Ð "à $Ð $Ð $Ð $Ð $Ð $à €€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ð Ð Ð ðð ð ð ð ð ð EÐ DÐ DÐ DÐ DÐ Dð
ð 
ð 
ð 
ðb#ð b#ð b#ð b#ð b#˜BœIñ b#ô b#ð b#ðJcð cð cð cð cˆbŒiñ cô cð cð cð cr   