U
    <Afy                     @   sf   d dl Z d dlZd dlmZ d dlmZmZmZmZ d dl	m
Z
mZ d dlmZ G dd dejZdS )    N)OrderedDict)DictListTupleUnion)Tensornn)import_from_stringc                       s   e Zd Zdeeeej f ed fddZ	eee
f dddZedd	d
Zdd Zeee eeeef  f dddZedd Z  ZS )AsymT)sub_modulesallow_empty_keyc                    sn   || _ || _t }| D ]>\}}t|ts2|g}t|D ]\}}|||d t| < q:qtt	| 
| dS )a  
        This model allows to create asymmetric SentenceTransformer models, that apply different models depending on the specified input key.

        In the below example, we create two different Dense models for 'query' and 'doc'. Text that is passed as {'query': 'My query'} will
        be passed along along the first Dense model, and text that will be passed as {'doc': 'My document'} will use the other Dense model.

        Note, that when you call encode(), that only inputs of the same type can be encoded. Mixed-Types cannot be encoded.

        Example::
            word_embedding_model = models.Transformer(model_name)
            pooling_model = models.Pooling(word_embedding_model.get_word_embedding_dimension())
            asym_model = models.Asym({'query': [models.Dense(word_embedding_model.get_word_embedding_dimension(), 128)], 'doc': [models.Dense(word_embedding_model.get_word_embedding_dimension(), 128)]})
            model = SentenceTransformer(modules=[word_embedding_model, pooling_model, asym_model])

            model.encode([{'query': 'Q1'}, {'query': 'Q2'}]
            model.encode([{'doc': 'Doc1'}, {'doc': 'Doc2'}]

            #You can train it with InputExample like this. Note, that the order must always be the same:
            train_example = InputExample(texts=[{'query': 'Train query'}, {'doc': 'Document'}], label=1)

        Args:
            sub_modules: Dict in the format str -> List[models]. The
                models in the specified list will be applied for input
                marked with the respective key.
            allow_empty_key: If true, inputs without a key can be
                processed. If false, an exception will be thrown if no
                key is specified.
        -N)r   r   r   items
isinstancer   	enumeratestrsuperr
   __init__)selfr   r   Zordered_dictnamemodelsidxmodel	__class__ E/tmp/pip-unpacked-wheel-i7fohqg6/sentence_transformers/models/Asym.pyr      s    
zAsym.__init__)featuresc                 C   sP   d|kr>t |d dkr>|d d }| j| D ]}||}q.n| jsLtd|S )NZ	text_keysr   z;Input did not specify any keys and allow_empty_key is False)lenr   r   
ValueError)r   r   text_keyr   r   r   r   forward5   s    zAsym.forward)returnc                 C   s:   | j D ].}t| j | d dr| j | d    S qd S )Nr    get_sentence_embedding_dimension)r   hasattrr#   )r   r   r   r   r   r#   ?   s    
z%Asym.get_sentence_embedding_dimensionc              	   C   s   i }i }i }| j  D ]X\}}g ||< |D ]B}tt|d t|j }|||< t|j||< || | q*q| D ]2\}}tj	
|t|}	tj|	dd ||	 qxttj	
|dddd$}
tj||d| jid	|
d
d W 5 Q R X d S )N_T)exist_okconfig.jsonwutf8)encodingr   )types	structure
parameters   )indent)r   r   r   idtype__name__
__module__appendospathjoinmakedirssaveopenjsondumpr   )r   Zoutput_pathZmodel_lookupZmodel_typesmodel_structurer   r   r   model_idZ
model_pathZfOutr   r   r   r9   E   s.    z	Asym.save)textsc                 K   sh   t |d tstdd}|D ]0}tt| \}}|dkrB|}||kstq| j| d j|f|S )z-Tokenizes a text and maps tokens to token-idsr   zDAsym. model requires that texts are passed as dicts: {'key': 'text'}N)	r   dictAttributeErrornextiterr   AssertionErrorr   tokenize)r   r?   kwargsZ
module_keylookupr    textr   r   r   rE   b   s    zAsym.tokenizec              	   C   s   t tj| d}t|}W 5 Q R X i }|d  D ],\}}t|}|tj| |}|||< q8i }|d  D ],\}	}
g ||	< |
D ]}||	 ||  qqvt	|f|d }|S )Nr'   r+   r,   r-   )
r:   r5   r6   r7   r;   loadr   r	   r4   r
   )Z
input_pathZfInconfigmodulesr>   Z
model_typeZmodule_classmoduler=   Zkey_nameZmodels_listr   r   r   r   rI   q   s    
z	Asym.load)T)r2   r3   __qualname__r   r   r   r   Moduleboolr   r   r!   intr#   r9   r   r   rE   staticmethodrI   __classcell__r   r   r   r   r
      s   $)
&r
   )r;   r5   collectionsr   typingr   r   r   r   Ztorchr   r   Zsentence_transformers.utilr	   Z
Sequentialr
   r   r   r   r   <module>   s   