gguf.py 4.92 KB
Newer Older
Matt Hoffner's avatar
Matt Hoffner committed
1
import requests
2
import logging
Matt Hoffner's avatar
Matt Hoffner committed
3
import time
Matt Hoffner's avatar
Matt Hoffner committed
4
5
from tqdm import tqdm
from requests.exceptions import RequestException
6
import transformers
Matt Hoffner's avatar
Matt Hoffner committed
7
8
9
from lm_eval.utils import Reorderer
from lm_eval.base import BaseLM

10
11
logger = logging.getLogger(__name__)

Matt Hoffner's avatar
Matt Hoffner committed
12

13
def get_result(logprobs, context_length):
Lorenzo's avatar
Lorenzo committed
14
15
16
17
18
19
    is_greedy = True
    offsets = logprobs['text_offset']
    tokens = logprobs['tokens']
    tokens_logprobs = logprobs['token_logprobs']

    idx = 0
20
    while offsets[idx] < context_length:
Lorenzo's avatar
Lorenzo committed
21
22
23
24
25
26
27
28
29
30
31
32
33
        idx += 1
    continuation_logprobs = sum(tokens_logprobs[idx:-1])
    for i in range(idx, len(tokens)):
        token = tokens[i]
        top_tokens = logprobs["top_logprobs"][i]
        top_token = max(top_tokens.keys(), key=lambda x: top_tokens[x])
        if top_token != token:
            is_greedy = False
            break

    return continuation_logprobs, is_greedy


34
class GGUFLM(BaseLM):
35
    def __init__(self, base_url, max_length=2048):
Matt Hoffner's avatar
Matt Hoffner committed
36
37
        super().__init__()
        self.base_url = base_url
38
        self.logprobs = 10
Lorenzo's avatar
Lorenzo committed
39
        self.temperature = 0.0
40
        self.max_length = max_length
41

42
    def gguf_completion(self, context, continuation=None, stop=None, retries=3, delay=5, **kwargs):
43
44
45
        for _ in range(retries):
            try:
                prompt = context
46
                request = {'prompt': prompt, 'logprobs': self.logprobs,
Lorenzo's avatar
Lorenzo committed
47
                           'temperature': self.temperature}
48
49
                if continuation:
                    prompt += continuation
Lorenzo's avatar
Lorenzo committed
50
                    request.update({'prompt': prompt, 'max_tokens': 1, 'echo': True})
51
52
                if stop is not None:
                    request['stop'] = stop
53
                response = requests.post(f"{self.base_url}/v1/completions", json=request)
54
55
56
57
58
59
                response.raise_for_status()
                return response.json()
            except RequestException as e:
                logger.error(f"RequestException: {e}")
                time.sleep(delay)  # wait before retrying
        else:
60
            raise Exception(f"Failed to get a valid response after {retries} retries.")
61

Matt Hoffner's avatar
Matt Hoffner committed
62
    def loglikelihood(self, requests):
63
64
        if not requests:
            return []
Matt Hoffner's avatar
Matt Hoffner committed
65
66
        res = []
        for context, continuation in tqdm(requests):
67
            response = self.gguf_completion(context=context, continuation=continuation)
68
69
70
            if response and "choices" in response and response["choices"]:
                choice = response["choices"][0]
                logprobs = choice.get("logprobs")
71
                if logprobs and "token_logprobs" in logprobs and logprobs["token_logprobs"]:
Lorenzo's avatar
Lorenzo committed
72
                    logprob, is_greedy = get_result(logprobs, len(context))
73
74
75
                    res.append((logprob, is_greedy))
                else:
                    logger.warning("Invalid logprobs data. Expected 'logprobs' to contain 'token_logprobs' list.")
Matt Hoffner's avatar
Matt Hoffner committed
76
            else:
77
                logger.error(f"Invalid response for loglikelihood. Response: {response}")
Matt Hoffner's avatar
Matt Hoffner committed
78
                assert False
79
        return res
Matt Hoffner's avatar
Matt Hoffner committed
80
81
82
83
84
85
86
87
88
89

    def greedy_until(self, requests):
        if not requests:
            return []

        res = []
        for request in tqdm(requests):
            inp = request[0]
            request_args = request[1]
            until = request_args["until"]
90
            response = self.gguf_completion(context=inp, stop=until)
Matt Hoffner's avatar
Matt Hoffner committed
91
92
93
94
95
96
97
98
            if response and "choices" in response and response["choices"]:
                choice = response["choices"][0]
                if "text" in choice:
                    generated_text = choice["text"].strip()
                    res.append(generated_text)
                else:
                    logger.error(f"Invalid response for greedy_until. Response: {response}")
                    res.append(None)  # Add default value in case of error
Matt Hoffner's avatar
Matt Hoffner committed
99
            else:
100
                logger.error(f"Invalid response for greedy_until. Response: {response}")
Matt Hoffner's avatar
Matt Hoffner committed
101
                res.append(None)  # Add default value in case of error
102
        return res
Matt Hoffner's avatar
Matt Hoffner committed
103

Matt Hoffner's avatar
Matt Hoffner committed
104
    def loglikelihood_rolling(self, requests):
105
        raise NotImplementedError("loglikelihood_rolling not yet supported for GGUF models")
Matt Hoffner's avatar
Matt Hoffner committed
106

107
108
109
110
111
112
113
114
    def _model_call(self, inps):
        # Placeholder implementation
        raise NotImplementedError()

    def _model_generate(self, context, max_length, eos_token_id):
        # Placeholder implementation
        raise NotImplementedError()

115
    def tok_encode(self, string: str):
116
        raise NotImplementedError()
117
118

    def tok_decode(self, tokens):
119
        raise NotImplementedError()
Lorenzo's avatar
Lorenzo committed
120

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    @property
    def batch_size(self):
        # Placeholder implementation
        raise NotImplementedError()

    @property
    def device(self):
        # Placeholder implementation
        raise NotImplementedError()

    @property
    def eot_token_id(self):
        # Placeholder implementation
        raise NotImplementedError()

Lorenzo's avatar
Lorenzo committed
136
    def max_length(self):
137
        return self.max_length
138
139
140
141

    @property
    def max_gen_toks(self):
        # Placeholder implementation
Lorenzo's avatar
Lorenzo committed
142
        raise NotImplementedError()