o
    5ti[                     @   s   d dl Z d dlZd dlZ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 d dlmZ er@d dlmZ d dlmZ eeZedd	d
ZG dd	 d	e jZdedee	 defddZG dd dZG dd dZG dd deZdS )    N)Iterable)TYPE_CHECKINGAnyOptionalTypeVar)tqdm)utils
SqliteDict)InstanceTLM)boundc                
   @   s,  e Zd Zd%ddZejdeeee	f  fddZ
ejdee fddZejdee fd	d
Z	d&deeeef  defddZe	d'dee dededB defddZe	d'dee dededB defddZedd Zedd ZedefddZd(de	eB dedB fdd Zd)d#d$ZdS )*r   returnNc                 C   s   d| _ d| _td| _dS )zDefines the interface that should be implemented by all LM subclasses.
        LMs are assumed to take text (strings) as input and yield strings as output
        (inputs/outputs should be tokenization-agnostic.)

        r      N)_rank_world_size	CacheHook
cache_hookself r   E/home/ubuntu/.local/lib/python3.10/site-packages/lm_eval/api/model.py__init__   s   zLM.__init__c                 C      dS )a  Compute log-likelihood of generating a continuation from a context.
        Downstream tasks should attempt to use loglikelihood instead of other
        LM calls whenever possible.

        :param requests: list[Instance]
            A list of Instance objects, with property `args` which returns a tuple (context, continuation).
            `context: str`
                Context string. Implementations of LM must be able to handle an
                empty context string.
            `continuation: str`
                The continuation over which log likelihood will be calculated. If
                there is a word boundary, the space should be in the continuation.
                For example, context="hello" continuation=" world" is correct.

        :return: list[tuple[float, bool]]
            A list of pairs (logprob, isgreedy)
            `logprob: float`
                The log probability of `continuation`.
            `isgreedy`:
                Whether `continuation` would be generated by greedy sampling from `context`.
        Nr   r   requestsr   r   r   loglikelihood%   s   zLM.loglikelihoodc                 C   r   )a  Compute full log-likelihood of a string, with no truncation, for perplexity computation
        - We will use the full max context length of the model.
        - For inputs that exceed the max context length, we divide the tokenized string into chunks of up to
        the max context length.
        - IMPORTANT: Each document's loglikelihood/perplexity is computed *separately*, unlike other implementations
          which may simply concatenate multiple documents together.
        - IMPORTANT: We maximize the amount of context for each prediction. Specifically, for inputs that we break into
          multiple chunks, the last input will still a full-sized context.

        Example:
            Input tokens: [ 0 1 2 3 4 5 6 7 8 9 ]
            Prefix: BOS/EOS
            Max context length: 4
            Resulting input/prediction pairs:

                INPUT:  BOS   0   1   2
                PRED:     0   1   2   3

                INPUT:    3   4   5   6
                PRED:     4   5   6   7

                INPUT:    5   6   7   8
                PRED:             8   9

          Observe that:
            1. Each token is predicted exactly once
            2. For the last pair, we provide the full context, but only score the last two tokens

        :param requests: list[Instance]
            A list of Instance objects with property `args` which returns a tuple (context,).
            string: str
                String for which we are computing overall loglikelihood
        :return: list[tuple[float]]
            A list of tuples (logprob,)
            logprob: float
                The log probability of `context` conditioned on the BOS/EOS token.
                Can also be overridden for custom cases by `prefix_token_id`.
        Nr   r   r   r   r   loglikelihood_rolling>   s   (zLM.loglikelihood_rollingc                 C   r   )a"  Generate greedily until a stopping sequence

        :param requests: list[Instance]
            A list of Instance objects with property `args` which returns a tuple (context, gen_kwargs).
            context: str
                Context string
            gen_kwargs: dict
                A dictionary of keyword arguments to pass to the generation function e.g. top_k, until, etc.
        :return: list[str]
            A list of model generated continuations.
            continuation: str
                The generated continuation.
        Nr   r   r   r   r   generate_untili   s   zLM.generate_untilTchat_historyc                 C      t d)a  
        Defines how to transform few-shot examples provided as chat history into a format that can be used as input to the LM.

        :param chat_history: list[dict[str, str]]
            A list of dictionaries with keys 'role' and 'content'.
            Values are strings representing the role name and the content of the message, respectively.
        :param add_generation_prompt: bool
            Whether to append an assistant gen prefix (for e.g. <|assistant|>) to the assistant messages in the chat history. False if prefilling an assistant message.
        :return: str
            A string representing the chat history in a format that can be used as input to the LM.
        zmTo use this model with chat templates, please implement the 'apply_chat_template' method for your model type.NotImplementedError)r   r    add_generation_promptr   r   r   apply_chat_templatez   s   zLM.apply_chat_templatecls
arg_stringadditional_configc                 C   s>   |du ri n|}t |}dd | D }| di ||S )as  
        Creates an instance of the LM class using the given argument string and additional config.

        Parameters:
        - arg_string: A string containing arguments in the format key1=value1,key2=value2.
        - additional_config: Optional dictionary containing additional configuration parameters.

        Returns:
        - Instance of the LM class.
        Nc                 S      i | ]\}}|d ur||qS Nr   .0kvr   r   r   
<dictcomp>       z-LM.create_from_arg_string.<locals>.<dictcomp>r   )r   simple_parse_args_stringitems)r&   r'   r(   argsargs2r   r   r   create_from_arg_string   s   
zLM.create_from_arg_stringarg_dictc                 C   s0   |du ri ndd |  D }| di ||S )aO  
        Creates an instance of the LM class using the given arg_obj

        Parameters:
        - arg_obj: A dict containing arguments in the format key1=value1,key2=value2.
        - additional_config: Optional dictionary containing additional configuration parameters.

        Returns:
        - Instance of the LM class.
        Nc                 S   r)   r*   r   r+   r   r   r   r/      r0   z*LM.create_from_arg_obj.<locals>.<dictcomp>r   )r2   )r&   r6   r(   r   r   r   create_from_arg_obj   s
   zLM.create_from_arg_objc                 C      | j S r*   )r   r   r   r   r   rank      zLM.rankc                 C   r8   r*   )r   r   r   r   r   
world_size   r:   zLM.world_sizec                 C   r!   )a  Must be defined for LM subclasses which implement Chat Templating.
        Should return the name of the tokenizer or chat template used.
        Used only to properly fingerprint caches when requests are being cached with `--cache_requests`, otherwise not used.
        zVTo use this model with chat templates, please implement the 'tokenizer_name' property.r"   r   r   r   r   tokenizer_name   s   zLM.tokenizer_nameFchat_templatec                 C   r   )a)  Returns the chat template structure for user/assistant messages if a template is provided.
        This method is intended to be overridden in a subclass to define a specific chat template format.
        For models that do not support chat templates, this method returns None by default.
         r   )r   r=   r   r   r   r=      s   zLM.chat_templater   r   c                 C   s
   || _ d S r*   )r   )r   r   r   r   r   set_cache_hook   s   
zLM.set_cache_hook)r   N)Tr*   F)r   r   r   N)__name__
__module____qualname__r   abcabstractmethodlisttuplefloatboolr   r   strr   dictr%   classmethodtyper   r5   r7   propertyr9   r;   r<   r=   r?   r   r   r   r   r      sX    
*


	attrr3   r   c                 C   s(   t | gt| }t|d S )Nzutf-8)jsondumpsrF   hashlibsha256encode	hexdigest)rO   r3   datr   r   r   	hash_args   s   rW   c                   @   s@   e Zd Zded ddfddZdedee d	eddfd
dZdS )r   	cachinglm	CachingLMr   Nc                 C   s   |d u r	d | _ d S |j | _ d S r*   )dbdict)r   rX   r   r   r   r      s   zCacheHook.__init__rO   reqresc                 C   s&   | j d u rd S t||}|| j |< d S r*   )rZ   rW   )r   rO   r[   r\   hshr   r   r   add_partial   s   

zCacheHook.add_partial)	rA   rB   rC   r   r   rJ   r   r   r^   r   r   r   r   r      s    "r   c                   @   s>   e Zd ZdededdfddZdedefdd	ZdddZdS )rY   lmcache_dbr   Nc                 C   sZ   ddl m} || _|| _tj|rtjtj|dd ||dd| _|	| 
  dS )zLM wrapper that returns cached results if they exist, and uses the underlying LM if not.

        :param lm: LM
            Underlying LM
        :param cache_db: str
            Path to cache db
        r   r	   T)exist_ok)
autocommitN)
sqlitedictr
   r_   r`   ospathdirnamemakedirsrZ   r?   get_cache_hook)r   r_   r`   r
   r   r   r   r      s   zCachingLM.__init__rO   c                    sN   t j } dvrtd  d |S dtd dtd f fdd}|S )	N)r   r   r   zPassing through attribute 'z' to underlying LMr   r   r   c           
         sz  g }g }d}t d  dj d t| ddD ]P}t |j} dkrI|jd d	drI|s>t d
|jd  d d}|d  || q|j	v r_j	| }|d usYJ || q|d  || qt dt
| t
|  dt
|  |rtj |ng }d}t||ddD ]#\}}	|| d ur|d7 }|| d us|	||< t |j}|	j	|< qj	  |S )NFz	Loading 'z' responses from cache 'z' where possible...zChecking cached requests)descr   r   	do_samplez"Arguments to lm.generate_until() 'zV' include non-deterministic sampling. Caching will not be performed for such requests.TzCached requests: z, Requests remaining: r   )strict)eval_loggerinfor`   r   rW   r3   getwarningappendrZ   lengetattrr_   zipcommit)
r   r\   remaining_reqswarnedr[   r]   obrem_resresptrrrO   r   r   r   _fn	  sH   




z"CachingLM.__getattr__.<locals>._fn)rr   r_   rl   debugrF   )r   rO   lm_attrr|   r   r{   r   __getattr__  s    2zCachingLM.__getattr__r   c                 C   s   t | S r*   )r   r   r   r   r   rh   =  s   zCachingLM.get_cache_hook)r   r   )	rA   rB   rC   r   rJ   r   r   r   rh   r   r   r   r   rY      s    :rY   c                
   @   sP  e Zd ZdZdZdZeejde	fddZ
edd Zej	d d	ed
edB dee	 fddZejdeeeeef ee	 ee	 f  deeeef  fddZdededeee	 ee	 f fddZ	d!ded dedeeeef  fddZej	d!dedee fddZejd!dedee fddZd!deeB dedB fddZdS )"
TemplateLMz}
    A class acting as intermediary between the LM base class
    and boilerplate often included in other LM subclasses.
    Ncausalr   c                 C      d S r*   r   r   r   r   r   eot_token_idJ  s   zTemplateLM.eot_token_idc                 C   r8   r*   )r   r   r   r   r   prefix_token_idO  s   zTemplateLM.prefix_token_idstringadd_special_tokensc                 K   r   )a  
        Tokenize a string using the model's tokenizer and return a list of token IDs.
        NOTE: This method is expected to handle strings which already contain the BOS token (when add_special_tokens=None).
        Otherwise, will use add_special_tokens if specified.
        Nr   )r   r   r   kwargsr   r   r   
tok_encodeT  s   	zTemplateLM.tok_encoder   c                 K   r   r*   r   )r   r   r   r   r   r   _loglikelihood_tokens_     z TemplateLM._loglikelihood_tokenscontextcontinuationc                 C   s   |sJ dt |t |  }|dkr$|| d | }|d|  }| jdkrC| || }| |}t |}||d }||fS | |}| j|dd}||fS )a  
        Encode a context-continuation pair into separate token ID lists.

        This method handles the tokenization of context and continuation strings while
        preserving proper boundary handling. Trailing spaces in the context are moved
        to the beginning of the continuation to ensure correct tokenization at the
        word boundary.

        For Seq2Seq models (encoder-decoder), context and continuation are encoded
        separately. For other model types (decoder-only), the full sequence is encoded
        together to ensure proper tokenization, then split at the context boundary.

        :param context: str
            The context string. Can be empty (will be handled by the caller).
        :param continuation: str
            The continuation string to be scored.

        :return: tuple[list[int], list[int]]
            A tuple of (context_enc, continuation_enc) where:
            - context_enc: Token IDs for the context
            - continuation_enc: Token IDs for the continuation

        Note:
            This method does NOT handle empty context. The caller should
            handle empty context (see loglikelihood method).
        zContext cannot be empty!r   Nr   Fr   )rq   rstripbackendr   )r   r   r   n_spaces	whole_enccontext_enccontext_enc_lencontinuation_encr   r   r   _encode_paire  s   


zTemplateLM._encode_pairFr   disable_tqdmc                 C   s   g }dd |D D ]=\}}|dkr4| j |dd}| j|d kr%| jg|fn|dd |dd f\}}n| ||\}}|||f||f q	| j||d	S )
a  
        Compute log-likelihood of generating continuations from contexts.

        This is the concrete implementation for TemplateLM and its subclasses.
        It tokenizes context-continuation pairs and delegates scoring to
        _loglikelihood_tokens.

        **IMPORTANT**: This method is expected to handle empty context strings.
        When context is empty (""), it uses the model's prefix_token_id (typically
        BOS or EOS token) as context. If the continuation already starts with the
        prefix token, it reuses that token as context instead of duplicating it.

        :param requests: list[Instance]
            List of Instance objects with property `args` returning (context, continuation) tuples.
        :param disable_tqdm: bool
            Whether to disable the progress bar in _loglikelihood_tokens.

        :return: list[tuple[float, bool]]
            List of (log_prob, is_greedy) tuples for each request.

        Implementation details:
            - Empty context: Uses prefix_token_id (BOS/EOS) as context
            - Non-empty context: Uses _encode_pair for proper tokenization
            - Avoids token duplication when continuation starts with prefix_token_id
        c                 S   s   g | ]}|j qS r   )r3   )r,   r[   r   r   r   
<listcomp>  s    z,TemplateLM.loglikelihood.<locals>.<listcomp>r>   Fr   r   Nr   )r   )r   r   r   rp   r   )r   r   r   new_reqsr   r   r   r   r   r   r   r     s   zTemplateLM.loglikelihoodc                 C   r   r*   r   r   r   r   r   r   r   r     r   z TemplateLM.loglikelihood_rollingc                 C   r   r*   r   r   r   r   r   r     s   zTemplateLM.generate_untilr=   c                 C   s4  | j du rdS |du s|du rtd dS t|trd}d}z
| j jp'| j j}W n
 ty3   Y dS w t|trv| j jdu }|dur_||v rP|| }|rOd}nAt	d| dt
|  dd	|v rj|d	 }d}n't	d
t
|  dt|trtd | j jdur| j j}n| j j}d}|rtd |S )a  
        Set and get the appropriate chat template for the model.
        This method sets the tokenizer's chat_template and returns the template string for reproducibility.

        The template selection logic is adapted from the Transformers library's `apply_chat_template`
        method in the Tokenizer class. The original implementation can be found at:
        https://github.com/huggingface/transformers/blob/fc35907f95459d7a6c5281dfadd680b6f7b620e3/src/transformers/tokenization_utils_base.py#L1687

        This method ensures that the right template is chosen based on the following:
        0. If the model has no 'tokenizer' attribute: assumes that there is only a single possible chat template, handled on the model provider side internally. Returns the empty string.
        1. If the model's tokenizer has multiple templates:
            a. Use the specified template if it exists in the dictionary.
            b. Use the default template from the list if no specific template is provided.
            c. Raise an error if no default template exists and no specific template is provided.
        2. If the model's tokenizer has a single template or no template:
            a. Use the tokenizer's chat template if available.
            b. Fall back to the default chat template if no tokenizer chat template exists.

        Args:
            chat_template (Union[bool, str]): Specifies the chat template to use.
                - If False or None, no template is applied.
                - If True, the default or only available template is used.
                - If a string, the template with the matching name is used.

        Returns:
            Optional[str]: The selected chat template, or None if no template is applied.
        Nr>   Fzmodel.chat_template was called with the chat_template set to False or None. Therefore no chat template will be applied. Make sure this is an intended behavior.TzThe specified chat template 'z1' is not available. Available template names are .defaultzThis model has multiple chat templates with no default specified! Please either pass a chat template or the name of the template you wish to use to the `chat_template` argument. Available template names are zChat template name provided, but the tokenizer's chat template is not a dictionary. Using the tokenizer's chat template or the default template instead.a  No chat template is set for this tokenizer, falling back to a default class-level template. This is very error-prone, because models are often trained with templates different from the class default! Default chat templates are a legacy feature and will be removed in Transformers v4.43, at which point any code depending on them will stop working. We recommend setting a valid chat template before then to ensure that this model continues working without issues.)	tokenizerrl   ro   
isinstancerI   r=   default_chat_templateAttributeErrorrK   
ValueErrorsortedkeysrJ   )r   r=   using_default_templatetemplateusing_default_dictselected_templater   r   r   r=     sd   





	
zTemplateLM.chat_templater*   r@   )rA   rB   rC   __doc__r   r   rN   rD   rE   intr   r   rJ   rI   rF   r   rG   rH   r   r   r   r   r   r=   r   r   r   r   r   A  sb    

 
2
0 r   )rD   rR   rP   loggingrd   collections.abcr   typingr   r   r   r   r   lm_evalr   rc   r
   lm_eval.api.instancer   	getLoggerrA   rl   r   ABCr   rJ   rW   r   rY   r   r   r   r   r   <module>   s(    
 CR