chen459664 commited on
Commit
9e25429
·
verified ·
1 Parent(s): 514ccae

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lm-evaluation-harness/Qwen2.5-7B_eval.log +0 -0
  2. lm-evaluation-harness/eval_base_qwen2_5_32b.log +0 -0
  3. lm-evaluation-harness/lm_eval/api/__pycache__/__init__.cpython-311.pyc +0 -0
  4. lm-evaluation-harness/lm_eval/api/__pycache__/group.cpython-310.pyc +0 -0
  5. lm-evaluation-harness/lm_eval/api/__pycache__/instance.cpython-310.pyc +0 -0
  6. lm-evaluation-harness/lm_eval/api/__pycache__/metrics.cpython-310.pyc +0 -0
  7. lm-evaluation-harness/lm_eval/api/__pycache__/model.cpython-310.pyc +0 -0
  8. lm-evaluation-harness/lm_eval/api/__pycache__/registry.cpython-311.pyc +0 -0
  9. lm-evaluation-harness/lm_eval/api/__pycache__/samplers.cpython-310.pyc +0 -0
  10. lm-evaluation-harness/lm_eval/api/__pycache__/samplers.cpython-311.pyc +0 -0
  11. lm-evaluation-harness/lm_eval/api/__pycache__/task.cpython-310.pyc +0 -0
  12. lm-evaluation-harness/lm_eval/api/model.py +493 -0
  13. lm-evaluation-harness/lm_eval/caching/__pycache__/cache.cpython-310.pyc +0 -0
  14. lm-evaluation-harness/lm_eval/caching/cache.py +59 -0
  15. lm-evaluation-harness/lm_eval/decontamination/archiver.py +174 -0
  16. lm-evaluation-harness/lm_eval/filters/__pycache__/__init__.cpython-310.pyc +0 -0
  17. lm-evaluation-harness/lm_eval/filters/__pycache__/__init__.cpython-311.pyc +0 -0
  18. lm-evaluation-harness/lm_eval/filters/__pycache__/custom.cpython-310.pyc +0 -0
  19. lm-evaluation-harness/lm_eval/filters/__pycache__/custom.cpython-311.pyc +0 -0
  20. lm-evaluation-harness/lm_eval/filters/__pycache__/extraction.cpython-310.pyc +0 -0
  21. lm-evaluation-harness/lm_eval/filters/__pycache__/extraction.cpython-311.pyc +0 -0
  22. lm-evaluation-harness/lm_eval/filters/__pycache__/selection.cpython-310.pyc +0 -0
  23. lm-evaluation-harness/lm_eval/filters/__pycache__/transformation.cpython-310.pyc +0 -0
  24. lm-evaluation-harness/lm_eval/filters/custom.py +17 -0
  25. lm-evaluation-harness/lm_eval/filters/decontamination.py +25 -0
  26. lm-evaluation-harness/lm_eval/filters/selection.py +61 -0
  27. lm-evaluation-harness/lm_eval/filters/transformation.py +122 -0
  28. lm-evaluation-harness/lm_eval/loggers/__init__.py +2 -0
  29. lm-evaluation-harness/lm_eval/loggers/__pycache__/__init__.cpython-310.pyc +0 -0
  30. lm-evaluation-harness/lm_eval/loggers/__pycache__/__init__.cpython-311.pyc +0 -0
  31. lm-evaluation-harness/lm_eval/loggers/__pycache__/evaluation_tracker.cpython-310.pyc +0 -0
  32. lm-evaluation-harness/lm_eval/loggers/__pycache__/evaluation_tracker.cpython-311.pyc +0 -0
  33. lm-evaluation-harness/lm_eval/loggers/__pycache__/utils.cpython-310.pyc +0 -0
  34. lm-evaluation-harness/lm_eval/loggers/__pycache__/utils.cpython-311.pyc +0 -0
  35. lm-evaluation-harness/lm_eval/loggers/__pycache__/wandb_logger.cpython-310.pyc +0 -0
  36. lm-evaluation-harness/lm_eval/loggers/__pycache__/wandb_logger.cpython-311.pyc +0 -0
  37. lm-evaluation-harness/lm_eval/loggers/evaluation_tracker.py +537 -0
  38. lm-evaluation-harness/lm_eval/loggers/utils.py +149 -0
  39. lm-evaluation-harness/lm_eval/loggers/wandb_logger.py +358 -0
  40. lm-evaluation-harness/lm_eval/models/__init__.py +36 -0
  41. lm-evaluation-harness/lm_eval/models/__pycache__/__init__.cpython-310.pyc +0 -0
  42. lm-evaluation-harness/lm_eval/models/__pycache__/__init__.cpython-311.pyc +0 -0
  43. lm-evaluation-harness/lm_eval/models/__pycache__/anthropic_llms.cpython-310.pyc +0 -0
  44. lm-evaluation-harness/lm_eval/models/__pycache__/anthropic_llms.cpython-311.pyc +0 -0
  45. lm-evaluation-harness/lm_eval/models/__pycache__/api_models.cpython-310.pyc +0 -0
  46. lm-evaluation-harness/lm_eval/models/__pycache__/api_models.cpython-311.pyc +0 -0
  47. lm-evaluation-harness/lm_eval/models/__pycache__/dummy.cpython-310.pyc +0 -0
  48. lm-evaluation-harness/lm_eval/models/__pycache__/dummy.cpython-311.pyc +0 -0
  49. lm-evaluation-harness/lm_eval/models/__pycache__/gguf.cpython-310.pyc +0 -0
  50. lm-evaluation-harness/lm_eval/models/__pycache__/gguf.cpython-311.pyc +0 -0
lm-evaluation-harness/Qwen2.5-7B_eval.log ADDED
The diff for this file is too large to render. See raw diff
 
lm-evaluation-harness/eval_base_qwen2_5_32b.log ADDED
The diff for this file is too large to render. See raw diff
 
lm-evaluation-harness/lm_eval/api/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (195 Bytes). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/group.cpython-310.pyc ADDED
Binary file (4.62 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/instance.cpython-310.pyc ADDED
Binary file (1.53 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/metrics.cpython-310.pyc ADDED
Binary file (13.4 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/model.cpython-310.pyc ADDED
Binary file (18 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/registry.cpython-311.pyc ADDED
Binary file (8.62 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/samplers.cpython-310.pyc ADDED
Binary file (5.67 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/samplers.cpython-311.pyc ADDED
Binary file (10.4 kB). View file
 
lm-evaluation-harness/lm_eval/api/__pycache__/task.cpython-310.pyc ADDED
Binary file (47.4 kB). View file
 
lm-evaluation-harness/lm_eval/api/model.py ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import abc
2
+ import hashlib
3
+ import json
4
+ import logging
5
+ import os
6
+ from typing import Dict, List, Optional, Tuple, Type, TypeVar, Union
7
+
8
+ import transformers
9
+ from sqlitedict import SqliteDict
10
+ from tqdm import tqdm
11
+
12
+ from lm_eval import utils
13
+
14
+
15
+ eval_logger = logging.getLogger(__name__)
16
+
17
+ T = TypeVar("T", bound="LM")
18
+
19
+
20
+ class LM(abc.ABC):
21
+ def __init__(self) -> None:
22
+ """Defines the interface that should be implemented by all LM subclasses.
23
+ LMs are assumed to take text (strings) as input and yield strings as output
24
+ (inputs/outputs should be tokenization-agnostic.)
25
+
26
+ """
27
+ # set rank and world size to a single process, by default.
28
+ self._rank = 0
29
+ self._world_size = 1
30
+ self.cache_hook = CacheHook(None)
31
+
32
+ @abc.abstractmethod
33
+ def loglikelihood(self, requests) -> List[Tuple[float, bool]]:
34
+ """Compute log-likelihood of generating a continuation from a context.
35
+ Downstream tasks should attempt to use loglikelihood instead of other
36
+ LM calls whenever possible.
37
+
38
+ :param requests: list[Instance]
39
+ A list of Instance objects, with property `args` which returns a tuple (context, continuation).
40
+ `context: str`
41
+ Context string. Implementations of LM must be able to handle an
42
+ empty context string.
43
+ `continuation: str`
44
+ The continuation over which log likelihood will be calculated. If
45
+ there is a word boundary, the space should be in the continuation.
46
+ For example, context="hello" continuation=" world" is correct.
47
+
48
+ :return: list[tuple[float, bool]]
49
+ A list of pairs (logprob, isgreedy)
50
+ `logprob: float`
51
+ The log probability of `continuation`.
52
+ `isgreedy`:
53
+ Whether `continuation` would be generated by greedy sampling from `context`.
54
+ """
55
+ pass
56
+
57
+ @abc.abstractmethod
58
+ def loglikelihood_rolling(self, requests) -> List[float]:
59
+ """Compute full log-likelihood of a string, with no truncation, for perplexity computation
60
+ - We will use the full max context length of the model.
61
+ - For inputs that exceed the max context length, we divide the tokenized string into chunks of up to
62
+ the max context length.
63
+ - IMPORTANT: Each document's loglikelihood/perplexity is computed *separately*, unlike other implementations
64
+ which may simply concatenate multiple documents together.
65
+ - IMPORTANT: We maximize the amount of context for each prediction. Specifically, for inputs that we break into
66
+ multiple chunks, the last input will still a full-sized context.
67
+ Example:
68
+ Input tokens: [ 0 1 2 3 4 5 6 7 8 9 ]
69
+ Prefix: BOS/EOS
70
+ Max context length: 4
71
+ Resulting input/prediction pairs:
72
+
73
+ INPUT: BOS 0 1 2
74
+ PRED: 0 1 2 3
75
+
76
+ INPUT: 3 4 5 6
77
+ PRED: 4 5 6 7
78
+
79
+ INPUT: 5 6 7 8
80
+ PRED: 8 9
81
+
82
+ Observe that:
83
+ 1. Each token is predicted exactly once
84
+ 2. For the last pair, we provide the full context, but only score the last two tokens
85
+
86
+ :param requests: list[Instance]
87
+ A list of Instance objects with property `args` which returns a tuple (context,).
88
+ string: str
89
+ String for which we are computing overall loglikelihood
90
+ :return: list[tuple[float]]
91
+ A list of tuples (logprob,)
92
+ logprob: float
93
+ The log probability of `context` conditioned on the BOS/EOS token.
94
+ Can also be overridden for custom cases by `prefix_token_id`.
95
+ """
96
+ pass
97
+
98
+ # TODO: Add an optional max length
99
+ @abc.abstractmethod
100
+ def generate_until(self, requests) -> List[str]:
101
+ """Generate greedily until a stopping sequence
102
+
103
+ :param requests: list[Instance]
104
+ A list of Instance objects with property `args` which returns a tuple (context, gen_kwargs).
105
+ context: str
106
+ Context string
107
+ gen_kwargs: dict
108
+ A dictionary of keyword arguments to pass to the generation function e.g. top_k, until, etc.
109
+ :return: list[str]
110
+ A list of model generated continuations.
111
+ continuation: str
112
+ The generated continuation.
113
+ """
114
+ pass
115
+
116
+ def apply_chat_template(
117
+ self, chat_history: List[Dict[str, str]], add_generation_prompt=True
118
+ ) -> str:
119
+ """
120
+ Defines how to transform few-shot examples provided as chat history into a format that can be used as input to the LM.
121
+
122
+ :param chat_history: list[dict[str, str]]
123
+ A list of dictionaries with keys 'role' and 'content'.
124
+ Values are strings representing the role name and the content of the message, respectively.
125
+ :param add_generation_prompt: bool
126
+ 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.
127
+ :return: str
128
+ A string representing the chat history in a format that can be used as input to the LM.
129
+ """
130
+ raise NotImplementedError(
131
+ "To use this model with chat templates, please implement the 'apply_chat_template' method for your model type."
132
+ )
133
+
134
+ @classmethod
135
+ def create_from_arg_string(
136
+ cls: Type[T], arg_string: str, additional_config: Optional[dict] = None
137
+ ) -> T:
138
+ """
139
+ Creates an instance of the LM class using the given argument string and additional config.
140
+
141
+ Parameters:
142
+ - arg_string: A string containing arguments in the format key1=value1,key2=value2.
143
+ - additional_config: Optional dictionary containing additional configuration parameters.
144
+
145
+ Returns:
146
+ - Instance of the LM class.
147
+ """
148
+ additional_config = {} if additional_config is None else additional_config
149
+ args = utils.simple_parse_args_string(arg_string)
150
+ args2 = {k: v for k, v in additional_config.items() if v is not None}
151
+ return cls(**args, **args2)
152
+
153
+ @classmethod
154
+ def create_from_arg_obj(
155
+ cls: Type[T], arg_dict: dict, additional_config: Optional[dict] = None
156
+ ) -> T:
157
+ """
158
+ Creates an instance of the LM class using the given arg_obj
159
+
160
+ Parameters:
161
+ - arg_obj: A dict containing arguments in the format key1=value1,key2=value2.
162
+ - additional_config: Optional dictionary containing additional configuration parameters.
163
+
164
+ Returns:
165
+ - Instance of the LM class.
166
+ """
167
+
168
+ additional_config = {} if additional_config is None else additional_config
169
+ additional_config = {
170
+ k: v for k, v in additional_config.items() if v is not None
171
+ }
172
+
173
+ return cls(**arg_dict, **additional_config)
174
+
175
+ @property
176
+ def rank(self):
177
+ # used in the case of parallelism. Hardcoded to
178
+ # ensure no errors arise using API models which do
179
+ # not support multi-device parallelism nor expect it.
180
+ return self._rank
181
+
182
+ @property
183
+ def world_size(self):
184
+ # used in the case of parallelism. Hardcoded to
185
+ # ensure no errors arise using API models which do
186
+ # not support multi-device parallelism nor expect it.
187
+ return self._world_size
188
+
189
+ @property
190
+ def tokenizer_name(self) -> str:
191
+ """Must be defined for LM subclasses which implement Chat Templating.
192
+ Should return the name of the tokenizer or chat template used.
193
+ Used only to properly fingerprint caches when requests are being cached with `--cache_requests`, otherwise not used.
194
+ """
195
+ raise NotImplementedError(
196
+ "To use this model with chat templates, please implement the 'tokenizer_name' property."
197
+ )
198
+
199
+ def chat_template(self, chat_template: Union[bool, str] = False) -> Optional[str]:
200
+ """Returns the chat template structure for user/assistant messages if a template is provided.
201
+ This method is intended to be overridden in a subclass to define a specific chat template format.
202
+ For models that do not support chat templates, this method returns None by default.
203
+ """
204
+
205
+ return ""
206
+
207
+ def set_cache_hook(self, cache_hook) -> None:
208
+ self.cache_hook = cache_hook
209
+
210
+
211
+ ### SQLite-based caching of LM responses
212
+ def hash_args(attr, args):
213
+ dat = json.dumps([attr] + list(args))
214
+ return hashlib.sha256(dat.encode("utf-8")).hexdigest()
215
+
216
+
217
+ class CacheHook:
218
+ def __init__(self, cachinglm) -> None:
219
+ if cachinglm is None:
220
+ self.dbdict = None
221
+ return
222
+
223
+ self.dbdict = cachinglm.dbdict
224
+
225
+ def add_partial(self, attr, req, res) -> None:
226
+ if self.dbdict is None:
227
+ return
228
+ hsh = hash_args(attr, req)
229
+ self.dbdict[hsh] = res
230
+
231
+
232
+ class CachingLM:
233
+ def __init__(self, lm, cache_db) -> None:
234
+ """LM wrapper that returns cached results if they exist, and uses the underlying LM if not.
235
+
236
+ :param lm: LM
237
+ Underlying LM
238
+ :param cache_db: str
239
+ Path to cache db
240
+ """
241
+ self.lm = lm
242
+ self.cache_db = cache_db
243
+ if os.path.dirname(cache_db):
244
+ os.makedirs(os.path.dirname(cache_db), exist_ok=True)
245
+ self.dbdict = SqliteDict(cache_db, autocommit=True)
246
+
247
+ # add hook to lm
248
+ lm.set_cache_hook(self.get_cache_hook())
249
+
250
+ def __getattr__(self, attr: str):
251
+ lm_attr = getattr(self.lm, attr)
252
+ if attr not in ["loglikelihood", "loglikelihood_rolling", "generate_until"]:
253
+ eval_logger.debug(f"Passing through attribute '{attr}' to underlying LM")
254
+ return lm_attr
255
+
256
+ def fn(requests):
257
+ res = []
258
+ remaining_reqs = []
259
+ warned = False
260
+ # figure out which ones are cached and which ones are new
261
+ eval_logger.info(
262
+ f"Loading '{attr}' responses from cache '{self.cache_db}' where possible..."
263
+ )
264
+ for req in tqdm(requests, desc="Checking cached requests"):
265
+ hsh = hash_args(attr, req.args)
266
+ if attr == "generate_until" and req.args[1].get("do_sample", False):
267
+ # when we are doing non-greedy generation, don't use the cache
268
+ # (else every "randomly sampled" generation would be identical for repeats > 1).
269
+ if not warned:
270
+ eval_logger.warning(
271
+ f"Arguments to lm.generate_until() '{req.args[1]}' include non-deterministic sampling. Caching will not be performed for such requests."
272
+ )
273
+ warned = True
274
+ res.append(None)
275
+ remaining_reqs.append(req)
276
+ elif hsh in self.dbdict:
277
+ ob = self.dbdict[hsh]
278
+
279
+ assert ob is not None
280
+
281
+ res.append(ob)
282
+ else:
283
+ res.append(None)
284
+ remaining_reqs.append(req)
285
+ eval_logger.info(
286
+ f"Cached requests: {len(requests) - len(remaining_reqs)}, Requests remaining: {len(remaining_reqs)}"
287
+ )
288
+ if remaining_reqs:
289
+ # actually run the LM on the requests that do not have cached results
290
+ rem_res = getattr(self.lm, attr)(remaining_reqs)
291
+ else:
292
+ rem_res = []
293
+
294
+ # stick the new ones back into the list and also cache any of the new ones
295
+ resptr = 0
296
+ for req, r in zip(remaining_reqs, rem_res):
297
+ while res[resptr] is not None:
298
+ resptr += 1
299
+
300
+ res[resptr] = r
301
+
302
+ # caching
303
+ hsh = hash_args(attr, req.args)
304
+ self.dbdict[hsh] = r
305
+ self.dbdict.commit()
306
+
307
+ return res
308
+
309
+ return fn
310
+
311
+ def get_cache_hook(self):
312
+ return CacheHook(self)
313
+
314
+
315
+ class TemplateLM(LM):
316
+ """
317
+ A class acting as intermediary between the LM base class
318
+ and boilerplate often included in other LM subclasses.
319
+ """
320
+
321
+ tokenizer = None
322
+
323
+ @property
324
+ @abc.abstractmethod
325
+ def eot_token_id(self):
326
+ pass
327
+
328
+ @property
329
+ def prefix_token_id(self):
330
+ # it is used as prefix for loglikelihood
331
+ return self.eot_token_id
332
+
333
+ @abc.abstractmethod
334
+ def tok_encode(self, string: str, **kwargs) -> List[int]:
335
+ """
336
+ Tokenize a string using the model's tokenizer and return a list of token IDs.
337
+ """
338
+ pass
339
+
340
+ @abc.abstractmethod
341
+ def _loglikelihood_tokens(self, requests, **kwargs) -> List[Tuple[float, bool]]:
342
+ pass
343
+
344
+ def _encode_pair(
345
+ self, context: str, continuation: str
346
+ ) -> Tuple[List[int], List[int]]:
347
+ n_spaces = len(context) - len(context.rstrip())
348
+ if n_spaces > 0:
349
+ continuation = context[-n_spaces:] + continuation
350
+ context = context[:-n_spaces]
351
+
352
+ model_class = getattr(self, "AUTO_MODEL_CLASS", None)
353
+
354
+ if model_class == transformers.AutoModelForSeq2SeqLM:
355
+ context_enc = self.tok_encode(context)
356
+ continuation_enc = self.tok_encode(continuation, add_special_tokens=False)
357
+ else:
358
+ whole_enc = self.tok_encode(context + continuation)
359
+ context_enc = self.tok_encode(context)
360
+
361
+ context_enc_len = len(context_enc)
362
+ continuation_enc = whole_enc[context_enc_len:]
363
+
364
+ return context_enc, continuation_enc
365
+
366
+ def loglikelihood(
367
+ self, requests, disable_tqdm: bool = False
368
+ ) -> List[Tuple[float, bool]]:
369
+ new_reqs = []
370
+ for context, continuation in [req.args for req in requests]:
371
+ if context == "":
372
+ # BOS or EOS as context
373
+ context_enc, continuation_enc = (
374
+ [self.prefix_token_id],
375
+ self.tok_encode(continuation),
376
+ )
377
+ else:
378
+ context_enc, continuation_enc = self._encode_pair(context, continuation)
379
+
380
+ new_reqs.append(((context, continuation), context_enc, continuation_enc))
381
+
382
+ return self._loglikelihood_tokens(new_reqs, disable_tqdm=disable_tqdm)
383
+
384
+ @abc.abstractmethod
385
+ def loglikelihood_rolling(
386
+ self, requests, disable_tqdm: bool = False
387
+ ) -> List[float]:
388
+ pass
389
+
390
+ @abc.abstractmethod
391
+ def generate_until(self, requests, disable_tqdm: bool = False) -> List[str]:
392
+ pass
393
+
394
+ def chat_template(self, chat_template: Union[bool, str] = False) -> Optional[str]:
395
+ """
396
+ Set and get the appropriate chat template for the model.
397
+ This method sets the tokenizer's chat_template and returns the template string for reproducibility.
398
+
399
+ The template selection logic is adapted from the Transformers library's `apply_chat_template`
400
+ method in the Tokenizer class. The original implementation can be found at:
401
+ https://github.com/huggingface/transformers/blob/fc35907f95459d7a6c5281dfadd680b6f7b620e3/src/transformers/tokenization_utils_base.py#L1687
402
+
403
+ This method ensures that the right template is chosen based on the following:
404
+ 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.
405
+ 1. If the model's tokenizer has multiple templates:
406
+ a. Use the specified template if it exists in the dictionary.
407
+ b. Use the default template from the list if no specific template is provided.
408
+ c. Raise an error if no default template exists and no specific template is provided.
409
+ 2. If the model's tokenizer has a single template or no template:
410
+ a. Use the tokenizer's chat template if available.
411
+ b. Fall back to the default chat template if no tokenizer chat template exists.
412
+
413
+ Args:
414
+ chat_template (Union[bool, str]): Specifies the chat template to use.
415
+ - If False or None, no template is applied.
416
+ - If True, the default or only available template is used.
417
+ - If a string, the template with the matching name is used.
418
+
419
+ Returns:
420
+ Optional[str]: The selected chat template, or None if no template is applied.
421
+ """
422
+ if self.tokenizer is None:
423
+ return ""
424
+
425
+ if chat_template is False or chat_template is None:
426
+ eval_logger.warning(
427
+ "model.chat_template was called with the chat_template set to False or None. "
428
+ "Therefore no chat template will be applied. Make sure this is an intended behavior."
429
+ )
430
+ return None
431
+
432
+ # Convert boolean chat_template to None to ensure compatibility with the adapted logic
433
+ if isinstance(chat_template, bool):
434
+ chat_template = None
435
+ using_default_template = False
436
+
437
+ # First, handle the cases when the model has a dict of multiple templates
438
+ try:
439
+ template = (
440
+ self.tokenizer.chat_template or self.tokenizer.default_chat_template
441
+ )
442
+ except AttributeError:
443
+ return None
444
+
445
+ if isinstance(template, dict):
446
+ using_default_dict = self.tokenizer.chat_template is None
447
+
448
+ if chat_template is not None:
449
+ if chat_template in template:
450
+ selected_template = template[chat_template]
451
+ if using_default_dict:
452
+ using_default_template = True
453
+ else:
454
+ raise ValueError(
455
+ f"The specified chat template '{chat_template}' is not available. "
456
+ f"Available template names are {sorted(template.keys())}."
457
+ )
458
+ else:
459
+ # If user didn't pass a chat template, use the default template from the dict
460
+ if "default" in template:
461
+ selected_template = template["default"]
462
+ using_default_template = True
463
+ else:
464
+ raise ValueError(
465
+ "This model has multiple chat templates with no default specified! Please either pass a chat "
466
+ "template or the name of the template you wish to use to the `chat_template` argument. Available "
467
+ f"template names are {sorted(template.keys())}."
468
+ )
469
+
470
+ # Cases when the model has a single template or no template
471
+ else:
472
+ # priority: `chat_template` argument > `tokenizer.chat_template` > `tokenizer.default_chat_template
473
+ if isinstance(chat_template, str):
474
+ eval_logger.warning(
475
+ "Chat template name provided, but the tokenizer's chat template is not a dictionary. "
476
+ "Using the tokenizer's chat template or the default template instead."
477
+ )
478
+ if self.tokenizer.chat_template is not None:
479
+ selected_template = self.tokenizer.chat_template
480
+ else:
481
+ selected_template = self.tokenizer.default_chat_template
482
+ using_default_template = True
483
+
484
+ if using_default_template:
485
+ eval_logger.warning(
486
+ "No chat template is set for this tokenizer, falling back to a default class-level template. This is "
487
+ "very error-prone, because models are often trained with templates different from the class default! "
488
+ "Default chat templates are a legacy feature and will be removed in Transformers v4.43, at which "
489
+ "point any code depending on them will stop working. We recommend setting a valid chat template before "
490
+ "then to ensure that this model continues working without issues."
491
+ )
492
+
493
+ return selected_template
lm-evaluation-harness/lm_eval/caching/__pycache__/cache.cpython-310.pyc ADDED
Binary file (1.69 kB). View file
 
lm-evaluation-harness/lm_eval/caching/cache.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import logging
3
+ import os
4
+
5
+ import dill
6
+
7
+
8
+ eval_logger = logging.getLogger(__name__)
9
+
10
+
11
+ MODULE_DIR = os.path.dirname(os.path.realpath(__file__))
12
+
13
+ OVERRIDE_PATH = os.getenv("LM_HARNESS_CACHE_PATH")
14
+
15
+
16
+ PATH = OVERRIDE_PATH if OVERRIDE_PATH else f"{MODULE_DIR}/.cache"
17
+
18
+ # This should be sufficient for uniqueness
19
+ HASH_INPUT = "EleutherAI-lm-evaluation-harness"
20
+
21
+ HASH_PREFIX = hashlib.sha256(HASH_INPUT.encode("utf-8")).hexdigest()
22
+
23
+ FILE_SUFFIX = f".{HASH_PREFIX}.pickle"
24
+
25
+
26
+ def load_from_cache(file_name: str, cache: bool = False):
27
+ if not cache:
28
+ return
29
+ try:
30
+ path = f"{PATH}/{file_name}{FILE_SUFFIX}"
31
+
32
+ with open(path, "rb") as file:
33
+ cached_task_dict = dill.loads(file.read())
34
+ return cached_task_dict
35
+
36
+ except Exception:
37
+ eval_logger.debug(f"{file_name} is not cached, generating...")
38
+ pass
39
+
40
+
41
+ def save_to_cache(file_name, obj):
42
+ if not os.path.exists(PATH):
43
+ os.mkdir(PATH)
44
+
45
+ file_path = f"{PATH}/{file_name}{FILE_SUFFIX}"
46
+
47
+ eval_logger.debug(f"Saving {file_path} to cache...")
48
+ with open(file_path, "wb") as file:
49
+ file.write(dill.dumps(obj))
50
+
51
+
52
+ # NOTE the "key" param is to allow for flexibility
53
+ def delete_cache(key: str = ""):
54
+ files = os.listdir(PATH)
55
+
56
+ for file in files:
57
+ if file.startswith(key) and file.endswith(FILE_SUFFIX):
58
+ file_path = f"{PATH}/{file}"
59
+ os.unlink(file_path)
lm-evaluation-harness/lm_eval/decontamination/archiver.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import io
3
+ import json
4
+ import mmap
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import jsonlines
10
+ import tqdm
11
+ import zstandard
12
+
13
+
14
+ def json_serial(obj: Any) -> str:
15
+ """JSON serializer for objects not serializable by default json code"""
16
+
17
+ if isinstance(obj, (datetime.datetime,)):
18
+ return obj.isoformat()
19
+ raise TypeError("Type %s not serializable" % type(obj))
20
+
21
+
22
+ # Modified version of lm_dataformat Archive for single file.
23
+ class Archive:
24
+ def __init__(self, file_path: str, compression_level: int = 3) -> None:
25
+ self.file_path = file_path
26
+ dir_name = os.path.dirname(file_path)
27
+ if dir_name:
28
+ os.makedirs(dir_name, exist_ok=True)
29
+ self.fh = open(self.file_path, "wb")
30
+ self.cctx = zstandard.ZstdCompressor(level=compression_level)
31
+ self.compressor = self.cctx.stream_writer(self.fh)
32
+
33
+ def add_data(self, data, meta=None) -> None:
34
+ if meta is None:
35
+ meta = {}
36
+ self.compressor.write(
37
+ json.dumps({"text": data, "meta": meta}, default=json_serial).encode(
38
+ "UTF-8"
39
+ )
40
+ + b"\n"
41
+ )
42
+
43
+ def commit(self) -> None:
44
+ self.compressor.flush(zstandard.FLUSH_FRAME)
45
+ self.fh.flush()
46
+ self.fh.close()
47
+
48
+
49
+ # Modified version of lm_dataformat Reader with self.fh set, allowing peeking for tqdm.
50
+ class Reader:
51
+ def __init__(self) -> None:
52
+ pass
53
+
54
+ def read(
55
+ self,
56
+ file,
57
+ get_meta: bool = False,
58
+ autojoin_paragraphs: bool = True,
59
+ para_joiner: str = "\n\n",
60
+ ):
61
+ with open(file, "rb") as fh:
62
+ self.fh = fh
63
+ cctx = zstandard.ZstdDecompressor()
64
+ reader = io.BufferedReader(cctx.stream_reader(fh))
65
+ rdr = jsonlines.Reader(reader)
66
+ for ob in rdr:
67
+ # naive jsonl where each object is just the string itself, with no meta. For legacy compatibility.
68
+ if isinstance(ob, str):
69
+ assert not get_meta
70
+ yield ob
71
+ continue
72
+
73
+ text = ob["text"]
74
+
75
+ if autojoin_paragraphs and isinstance(text, list):
76
+ text = para_joiner.join(text)
77
+
78
+ if get_meta:
79
+ yield text, (ob["meta"] if "meta" in ob else {})
80
+ else:
81
+ yield text
82
+
83
+
84
+ class TextArchive:
85
+ def __init__(self, file_path, mode: str = "rb+") -> None:
86
+ self.file_path = file_path
87
+ dir_name = os.path.dirname(file_path)
88
+ if dir_name:
89
+ os.makedirs(dir_name, exist_ok=True)
90
+
91
+ if not os.path.exists(file_path):
92
+ Path(file_path).touch()
93
+
94
+ self.fh = open(self.file_path, mode)
95
+
96
+ def add_data(self, data) -> None:
97
+ self.fh.write(data.encode("UTF-8") + b"\n")
98
+
99
+ def commit(self) -> None:
100
+ self.fh.flush()
101
+ self.fh.close()
102
+
103
+
104
+ class TextReader:
105
+ def __init__(self, file_path) -> None:
106
+ self.file_path = file_path
107
+
108
+ # Optimized mmap read with infrequent tqdm updates to maintain speed
109
+ # Tested up to 250MB/s.
110
+ def read_tqdm(self, update_frequency: int = 10000):
111
+ current_file_position = 0
112
+ line_counter = 0
113
+ with (
114
+ open(self.file_path, "r", encoding="utf-8") as fh,
115
+ tqdm.tqdm(
116
+ total=os.path.getsize(self.file_path),
117
+ dynamic_ncols=True,
118
+ unit="byte",
119
+ unit_scale=1,
120
+ ) as progress,
121
+ ):
122
+ with mmap.mmap(fh.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_obj:
123
+ for line in iter(mmap_obj.readline, b""):
124
+ line = line.decode("utf-8")
125
+ line_counter += 1
126
+ if line_counter == update_frequency:
127
+ new_file_pos = mmap_obj.tell()
128
+ bytes_read = new_file_pos - current_file_position
129
+ current_file_position = new_file_pos
130
+ progress.update(bytes_read)
131
+ line_counter = 0
132
+ yield line[:-1]
133
+
134
+ def read_and_tell(self):
135
+ current_file_position = 0
136
+ with open(self.file_path, "r", encoding="utf8") as fh:
137
+ with mmap.mmap(fh.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_obj:
138
+ for line in iter(mmap_obj.readline, b""):
139
+ line = line.decode("utf-8")
140
+ new_file_pos = mmap_obj.tell()
141
+ raw_bytes_read = new_file_pos - current_file_position
142
+ current_file_position = new_file_pos
143
+ yield line[:-1], raw_bytes_read
144
+
145
+ def read(self):
146
+ with open(self.file_path, "r", encoding="utf8") as fh:
147
+ with mmap.mmap(fh.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_obj:
148
+ for line in iter(mmap_obj.readline, b""):
149
+ line = line.decode("utf-8")
150
+ yield line[:-1]
151
+
152
+ def read_slow(self):
153
+ with open(self.file_path, "r", encoding="utf8") as fh:
154
+ while True:
155
+ line = fh.readline()
156
+ if line == -1 or line == "":
157
+ break
158
+ else:
159
+ yield line[:-1]
160
+
161
+
162
+ # Optimized for speed. Decompresses the archive in shell before
163
+ # using the mmap'd TextReader.
164
+ class ZStdTextReader:
165
+ def __init__(self, file) -> None:
166
+ self.file = file
167
+
168
+ def read_tqdm(self):
169
+ decompressed_file = self.file[:-4]
170
+ print("Decompressing file, please wait...")
171
+ os.system(f"zstd -d {self.file}") # linux decompress is faster
172
+ reader = TextReader(decompressed_file)
173
+ yield from reader.read_tqdm()
174
+ os.remove(decompressed_file)
lm-evaluation-harness/lm_eval/filters/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (851 Bytes). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.2 kB). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/custom.cpython-310.pyc ADDED
Binary file (966 Bytes). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/custom.cpython-311.pyc ADDED
Binary file (1.38 kB). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/extraction.cpython-310.pyc ADDED
Binary file (8.14 kB). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/extraction.cpython-311.pyc ADDED
Binary file (12.8 kB). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/selection.cpython-310.pyc ADDED
Binary file (2.92 kB). View file
 
lm-evaluation-harness/lm_eval/filters/__pycache__/transformation.cpython-310.pyc ADDED
Binary file (5.77 kB). View file
 
lm-evaluation-harness/lm_eval/filters/custom.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from lm_eval.api.filter import Filter
2
+ from lm_eval.api.registry import register_filter
3
+
4
+
5
+ @register_filter("custom")
6
+ class CustomFilter(Filter):
7
+ """
8
+ Custom filter that applies a custom, user-defined function to the model responses.
9
+ """
10
+
11
+ def __init__(self, **kwargs) -> None:
12
+ self.filter_fn = kwargs.pop("filter_fn")
13
+
14
+ super().__init__(**kwargs)
15
+
16
+ def apply(self, resps, docs):
17
+ return self.filter_fn(resps, docs)
lm-evaluation-harness/lm_eval/filters/decontamination.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from lm_eval.api.filter import Filter
2
+ from lm_eval.api.registry import register_filter
3
+
4
+
5
+ @register_filter("decontaminate")
6
+ class DecontaminationFilter(Filter):
7
+ """
8
+ A filter which evaluates
9
+ """
10
+
11
+ name = "track_decontamination"
12
+
13
+ def __init__(self, path) -> None:
14
+ """
15
+
16
+ TODO: make sure only ever run one time on the train set (should this be cached as a class var? keyed by value for "path").
17
+ should further cache result on a given (task_name, doc_id)
18
+ """
19
+ self._decontam_results = None
20
+
21
+ def apply(self, resps, docs) -> None:
22
+ """
23
+ Return {"no_contamination", "only_contamination"} keys for the 2 different subsets
24
+ """
25
+ pass
lm-evaluation-harness/lm_eval/filters/selection.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import Counter
2
+
3
+ from lm_eval.api.filter import Filter
4
+ from lm_eval.api.registry import register_filter
5
+
6
+
7
+ # TODO: implement "arg_max" filter. either it should take in an arbitrary "scoring"/reward function
8
+ # that takes an input and returns a scalar and then should select the max reward,
9
+ # or should implement different filters for different ways of handling a reward model's inference.
10
+
11
+
12
+ @register_filter("take_first")
13
+ class TakeFirstFilter(Filter):
14
+ def __init__(self) -> None:
15
+ """
16
+ Can define custom behavior here, if an individual instantiation of a Filter class should have state.
17
+ """
18
+
19
+ def apply(self, resps, docs):
20
+ """
21
+ Assuming each entry of `resps` is a list of model responses, we discard all but the first response.
22
+ """
23
+ return map(lambda r: r[0], resps)
24
+
25
+
26
+ @register_filter("take_first_k")
27
+ class TakeKFilter(Filter):
28
+ def __init__(self, **kwargs) -> None:
29
+ self.k = kwargs.pop("k")
30
+
31
+ super().__init__(**kwargs)
32
+
33
+ def apply(self, resps, docs):
34
+ # need resp to be subscriptable to check below
35
+ resps = list(resps)
36
+ # check we have at least k responses per doc, else we can't take the first k
37
+ assert len(resps[0]) >= self.k, (
38
+ f"Need at least {self.k} responses per doc to take first {self.k}, but got {len(resps[0])} only! Please increase TaskConfig.repeats ."
39
+ )
40
+ return map(lambda r: r[: self.k], resps)
41
+
42
+
43
+ @register_filter("majority_vote")
44
+ class MajorityVoteFilter(Filter):
45
+ def __init__(self) -> None:
46
+ """
47
+ Can define custom behavior here, if an individual instantiation of a Filter class should have state.
48
+ """
49
+
50
+ def apply(self, resps, docs):
51
+ """
52
+ Each entry of `resps` is a list of model responses.
53
+ We select the response that occurs most frequently in each entry of `resps`.
54
+ """
55
+
56
+ def select_majority(resp):
57
+ counts = Counter(resp)
58
+ vote = counts.most_common(1)[0][0]
59
+ return vote
60
+
61
+ return map(lambda r: [select_majority(r)], resps)
lm-evaluation-harness/lm_eval/filters/transformation.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ from lm_eval.api.filter import Filter
4
+ from lm_eval.api.registry import register_filter
5
+
6
+
7
+ @register_filter("lowercase")
8
+ class LowercaseFilter(Filter):
9
+ def __init__(self) -> None:
10
+ pass
11
+
12
+ def apply(self, resps, docs):
13
+ def filter_set(inst):
14
+ return [resp.lower() for resp in inst]
15
+
16
+ return [filter_set(resp) for resp in resps]
17
+
18
+
19
+ @register_filter("uppercase")
20
+ class UppercaseFilter(Filter):
21
+ def __init__(self) -> None:
22
+ pass
23
+
24
+ def apply(self, resps, docs):
25
+ def filter_set(inst):
26
+ return [resp.upper() for resp in inst]
27
+
28
+ return [filter_set(resp) for resp in resps]
29
+
30
+
31
+ @register_filter("map")
32
+ class MapFilter(Filter):
33
+ def __init__(self, mapping_dict: dict = None, default_value=None) -> None:
34
+ """
35
+ Initializes the MapFilter with a given mapping dictionary and default value.
36
+
37
+ Args:
38
+ - mapping_dict (dict): A dictionary containing the key-value mappings.
39
+ Default is an empty dictionary.
40
+ - default_value (Any): The value to be returned when a key is not found in the mapping_dict.
41
+ Default is None.
42
+
43
+ Example:
44
+ mapper = MapFilter({'A': 1, 'B': 2}, default_value=0)
45
+ """
46
+ if mapping_dict is None:
47
+ mapping_dict = {}
48
+ assert isinstance(mapping_dict, dict), (
49
+ "Provided mapping_dict is not a dictionary"
50
+ )
51
+ self.mapping_dict = mapping_dict
52
+ self.default_value = default_value
53
+
54
+ def apply(self, resps, docs):
55
+ def filter_set(inst):
56
+ return [self.mapping_dict.get(resp, self.default_value) for resp in inst]
57
+
58
+ return [filter_set(resp) for resp in resps]
59
+
60
+
61
+ @register_filter("format_span")
62
+ class SPANFilter(Filter):
63
+ def __init__(self) -> None:
64
+ pass
65
+
66
+ def apply(self, resps, docs):
67
+ def format_ner_text(text):
68
+ label_dict = {
69
+ "person": "PER",
70
+ "location": "LOC",
71
+ "organization": "ORG",
72
+ "counties": "LOC",
73
+ "places": "LOC",
74
+ "people": "PER",
75
+ "persons": "PER",
76
+ "company": "ORG",
77
+ "country": "LOC",
78
+ "continent": "LOC",
79
+ "time": "DATE",
80
+ "date": "DATE",
81
+ "per": "PER",
82
+ "loc": "LOC",
83
+ "org": "ORG",
84
+ }
85
+ text = text.lower()
86
+ for key, value in label_dict.items():
87
+ text = text.replace(key, value)
88
+
89
+ text = "$".join(i for i in text.split("$$"))
90
+ return text.rstrip("$$")
91
+
92
+ def format_named_entities(text):
93
+ """
94
+ Extract named entities from text and format them as 'label: value $$ label: value'.
95
+ Handles grouped entities (e.g., LOC: kenya, uganda) and excludes 'none' values.
96
+ """
97
+ # Regular expression to match label: entities pattern
98
+ pattern = r"\b(PER|LOC|ORG|DATE):\s*([^$]+)"
99
+ # Normalize newline characters
100
+ text = text.replace("\n", "$").strip()
101
+ matches = re.findall(pattern, text)
102
+
103
+ formatted_entities = []
104
+
105
+ for label, values in matches:
106
+ # Split multiple entities separated by commas and strip whitespace
107
+ entities = [value.strip() for value in values.split(",")]
108
+
109
+ # Exclude 'none' entities
110
+ for entity in entities:
111
+ if entity.lower() != "none":
112
+ formatted_entities.append(f"{label.lower()}: {entity}")
113
+
114
+ # Join entities with the desired separator
115
+ return " $ ".join(formatted_entities)
116
+
117
+ def filter_set(inst):
118
+ return [
119
+ format_named_entities(format_ner_text(resp.lower())) for resp in inst
120
+ ]
121
+
122
+ return [filter_set(resp) for resp in resps]
lm-evaluation-harness/lm_eval/loggers/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .evaluation_tracker import EvaluationTracker
2
+ from .wandb_logger import WandbLogger
lm-evaluation-harness/lm_eval/loggers/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (291 Bytes). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (337 Bytes). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/evaluation_tracker.cpython-310.pyc ADDED
Binary file (15.8 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/evaluation_tracker.cpython-311.pyc ADDED
Binary file (26.4 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/utils.cpython-310.pyc ADDED
Binary file (4.43 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/utils.cpython-311.pyc ADDED
Binary file (7.57 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/wandb_logger.cpython-310.pyc ADDED
Binary file (11.9 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/__pycache__/wandb_logger.cpython-311.pyc ADDED
Binary file (23.4 kB). View file
 
lm-evaluation-harness/lm_eval/loggers/evaluation_tracker.py ADDED
@@ -0,0 +1,537 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import logging
3
+ import os
4
+ import re
5
+ import time
6
+ from collections import defaultdict
7
+ from dataclasses import asdict, dataclass
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+
11
+ from datasets import load_dataset
12
+ from datasets.utils.metadata import MetadataConfigs
13
+ from huggingface_hub import (
14
+ DatasetCard,
15
+ DatasetCardData,
16
+ HfApi,
17
+ hf_hub_url,
18
+ )
19
+ from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
20
+
21
+ from lm_eval.utils import (
22
+ get_file_datetime,
23
+ get_file_task_name,
24
+ get_results_filenames,
25
+ get_sample_results_filenames,
26
+ handle_non_serializable,
27
+ hash_string,
28
+ sanitize_list,
29
+ sanitize_model_name,
30
+ sanitize_task_name,
31
+ )
32
+
33
+
34
+ eval_logger = logging.getLogger(__name__)
35
+
36
+
37
+ @dataclass(init=False)
38
+ class GeneralConfigTracker:
39
+ """
40
+ Tracker for the evaluation parameters.
41
+
42
+ Attributes:
43
+ model_source (str): Source of the model (e.g. Hugging Face, GGUF, etc.)
44
+ model_name (str): Name of the model.
45
+ model_name_sanitized (str): Sanitized model name for directory creation.
46
+ start_time (float): Start time of the experiment. Logged at class init.
47
+ end_time (float): Start time of the experiment. Logged when calling [`GeneralConfigTracker.log_end_time`]
48
+ total_evaluation_time_seconds (str): Inferred total evaluation time in seconds (from the start and end times).
49
+ """
50
+
51
+ model_source: str = None
52
+ model_name: str = None
53
+ model_name_sanitized: str = None
54
+ system_instruction: str = None
55
+ system_instruction_sha: str = None
56
+ fewshot_as_multiturn: bool = None
57
+ chat_template: str = None
58
+ chat_template_sha: str = None
59
+ start_time: float = None
60
+ end_time: float = None
61
+ total_evaluation_time_seconds: str = None
62
+
63
+ def __init__(self) -> None:
64
+ """Starts the evaluation timer."""
65
+ self.start_time = time.perf_counter()
66
+
67
+ @staticmethod
68
+ def _get_model_name(model_args: str) -> str:
69
+ """Extracts the model name from the model arguments."""
70
+
71
+ def extract_model_name(model_args: str, key: str) -> str:
72
+ """Extracts the model name from the model arguments using a key."""
73
+ args_after_key = model_args.split(key)[1]
74
+ return args_after_key.split(",")[0]
75
+
76
+ # order does matter, e.g. peft and delta are provided together with pretrained
77
+ prefixes = ["peft=", "delta=", "pretrained=", "model=", "path=", "engine="]
78
+ for prefix in prefixes:
79
+ if prefix in model_args:
80
+ return extract_model_name(model_args, prefix)
81
+ return ""
82
+
83
+ def log_experiment_args(
84
+ self,
85
+ model_source: str,
86
+ model_args: str,
87
+ system_instruction: str,
88
+ chat_template: str,
89
+ fewshot_as_multiturn: bool,
90
+ ) -> None:
91
+ """Logs model parameters and job ID."""
92
+ self.model_source = model_source
93
+ self.model_name = GeneralConfigTracker._get_model_name(model_args)
94
+ self.model_name_sanitized = sanitize_model_name(self.model_name)
95
+ self.system_instruction = system_instruction
96
+ self.system_instruction_sha = (
97
+ hash_string(system_instruction) if system_instruction else None
98
+ )
99
+ self.chat_template = chat_template
100
+ self.chat_template_sha = hash_string(chat_template) if chat_template else None
101
+ self.fewshot_as_multiturn = fewshot_as_multiturn
102
+
103
+ def log_end_time(self) -> None:
104
+ """Logs the end time of the evaluation and calculates the total evaluation time."""
105
+ self.end_time = time.perf_counter()
106
+ self.total_evaluation_time_seconds = str(self.end_time - self.start_time)
107
+
108
+
109
+ class EvaluationTracker:
110
+ """
111
+ Keeps track and saves relevant information of the evaluation process.
112
+ Compiles the data from trackers and writes it to files, which can be published to the Hugging Face hub if requested.
113
+ """
114
+
115
+ def __init__(
116
+ self,
117
+ output_path: str = None,
118
+ hub_results_org: str = "",
119
+ hub_repo_name: str = "",
120
+ details_repo_name: str = "",
121
+ results_repo_name: str = "",
122
+ push_results_to_hub: bool = False,
123
+ push_samples_to_hub: bool = False,
124
+ public_repo: bool = False,
125
+ token: str = "",
126
+ leaderboard_url: str = "",
127
+ point_of_contact: str = "",
128
+ gated: bool = False,
129
+ ) -> None:
130
+ """
131
+ Creates all the necessary loggers for evaluation tracking.
132
+
133
+ Args:
134
+ output_path (str): Path to save the results. If not provided, the results won't be saved.
135
+ hub_results_org (str): The Hugging Face organization to push the results to. If not provided, the results will be pushed to the owner of the Hugging Face token.
136
+ hub_repo_name (str): The name of the Hugging Face repository to push the results to. If not provided, the results will be pushed to `lm-eval-results`.
137
+ details_repo_name (str): The name of the Hugging Face repository to push the details to. If not provided, the results will be pushed to `lm-eval-results`.
138
+ result_repo_name (str): The name of the Hugging Face repository to push the results to. If not provided, the results will not be pushed and will be found in the details_hub_repo.
139
+ push_results_to_hub (bool): Whether to push the results to the Hugging Face hub.
140
+ push_samples_to_hub (bool): Whether to push the samples to the Hugging Face hub.
141
+ public_repo (bool): Whether to push the results to a public or private repository.
142
+ token (str): Token to use when pushing to the Hugging Face hub. This token should have write access to `hub_results_org`.
143
+ leaderboard_url (str): URL to the leaderboard on the Hugging Face hub on the dataset card.
144
+ point_of_contact (str): Contact information on the Hugging Face hub dataset card.
145
+ gated (bool): Whether to gate the repository.
146
+ """
147
+ self.general_config_tracker = GeneralConfigTracker()
148
+
149
+ self.output_path = output_path
150
+ self.push_results_to_hub = push_results_to_hub
151
+ self.push_samples_to_hub = push_samples_to_hub
152
+ self.public_repo = public_repo
153
+ self.leaderboard_url = leaderboard_url
154
+ self.point_of_contact = point_of_contact
155
+ self.api = HfApi(token=token) if token else None
156
+ self.gated_repo = gated
157
+
158
+ if not self.api and (push_results_to_hub or push_samples_to_hub):
159
+ raise ValueError(
160
+ "Hugging Face token is not defined, but 'push_results_to_hub' or 'push_samples_to_hub' is set to True. "
161
+ "Please provide a valid Hugging Face token by setting the HF_TOKEN environment variable."
162
+ )
163
+
164
+ if (
165
+ self.api
166
+ and hub_results_org == ""
167
+ and (push_results_to_hub or push_samples_to_hub)
168
+ ):
169
+ hub_results_org = self.api.whoami()["name"]
170
+ eval_logger.warning(
171
+ f"hub_results_org was not specified. Results will be pushed to '{hub_results_org}'."
172
+ )
173
+
174
+ if hub_repo_name == "":
175
+ details_repo_name = (
176
+ details_repo_name if details_repo_name != "" else "lm-eval-results"
177
+ )
178
+ results_repo_name = (
179
+ results_repo_name if results_repo_name != "" else details_repo_name
180
+ )
181
+ else:
182
+ details_repo_name = hub_repo_name
183
+ results_repo_name = hub_repo_name
184
+ eval_logger.warning(
185
+ "hub_repo_name was specified. Both details and results will be pushed to the same repository. Using hub_repo_name is no longer recommended, details_repo_name and results_repo_name should be used instead."
186
+ )
187
+
188
+ self.details_repo = f"{hub_results_org}/{details_repo_name}"
189
+ self.details_repo_private = f"{hub_results_org}/{details_repo_name}-private"
190
+ self.results_repo = f"{hub_results_org}/{results_repo_name}"
191
+ self.results_repo_private = f"{hub_results_org}/{results_repo_name}-private"
192
+
193
+ def save_results_aggregated(
194
+ self,
195
+ results: dict,
196
+ samples: dict,
197
+ ) -> None:
198
+ """
199
+ Saves the aggregated results and samples to the output path and pushes them to the Hugging Face hub if requested.
200
+
201
+ Args:
202
+ results (dict): The aggregated results to save.
203
+ samples (dict): The samples results to save.
204
+ """
205
+ self.general_config_tracker.log_end_time()
206
+
207
+ if self.output_path:
208
+ try:
209
+ eval_logger.info("Saving results aggregated")
210
+
211
+ # calculate cumulative hash for each task - only if samples are provided
212
+ task_hashes = {}
213
+ if samples:
214
+ for task_name, task_samples in samples.items():
215
+ sample_hashes = [
216
+ s["doc_hash"] + s["prompt_hash"] + s["target_hash"]
217
+ for s in task_samples
218
+ ]
219
+ task_hashes[task_name] = hash_string("".join(sample_hashes))
220
+
221
+ # update initial results dict
222
+ results.update({"task_hashes": task_hashes})
223
+ results.update(asdict(self.general_config_tracker))
224
+ dumped = json.dumps(
225
+ results,
226
+ indent=2,
227
+ default=handle_non_serializable,
228
+ ensure_ascii=False,
229
+ )
230
+
231
+ path = Path(self.output_path if self.output_path else Path.cwd())
232
+ self.date_id = datetime.now().isoformat().replace(":", "-")
233
+ if path.suffix == ".json":
234
+ path.parent.mkdir(parents=True, exist_ok=True)
235
+ file_results_aggregated = path.with_name(
236
+ f"{path.stem}_{self.date_id}.json"
237
+ )
238
+ else:
239
+ path = path.joinpath(
240
+ self.general_config_tracker.model_name_sanitized
241
+ )
242
+ path.mkdir(parents=True, exist_ok=True)
243
+ file_results_aggregated = path.joinpath(
244
+ f"results_{self.date_id}.json"
245
+ )
246
+
247
+ file_results_aggregated.open("w", encoding="utf-8").write(dumped)
248
+
249
+ if self.api and self.push_results_to_hub:
250
+ repo_id = (
251
+ self.results_repo
252
+ if self.public_repo
253
+ else self.results_repo_private
254
+ )
255
+ self.api.create_repo(
256
+ repo_id=repo_id,
257
+ repo_type="dataset",
258
+ private=not self.public_repo,
259
+ exist_ok=True,
260
+ )
261
+ self.api.upload_file(
262
+ repo_id=repo_id,
263
+ path_or_fileobj=str(file_results_aggregated),
264
+ path_in_repo=os.path.join(
265
+ self.general_config_tracker.model_name,
266
+ file_results_aggregated.name,
267
+ ),
268
+ repo_type="dataset",
269
+ commit_message=f"Adding aggregated results for {self.general_config_tracker.model_name}",
270
+ )
271
+ eval_logger.info(
272
+ "Successfully pushed aggregated results to the Hugging Face Hub. "
273
+ f"You can find them at: {repo_id}"
274
+ )
275
+
276
+ except Exception as e:
277
+ eval_logger.warning("Could not save results aggregated")
278
+ eval_logger.info(repr(e))
279
+ else:
280
+ eval_logger.info(
281
+ "Output path not provided, skipping saving results aggregated"
282
+ )
283
+
284
+ def save_results_samples(
285
+ self,
286
+ task_name: str,
287
+ samples: dict,
288
+ ) -> None:
289
+ """
290
+ Saves the samples results to the output path and pushes them to the Hugging Face hub if requested.
291
+
292
+ Args:
293
+ task_name (str): The task name to save the samples for.
294
+ samples (dict): The samples results to save.
295
+ """
296
+ if self.output_path:
297
+ try:
298
+ eval_logger.info(f"Saving per-sample results for: {task_name}")
299
+
300
+ path = Path(self.output_path if self.output_path else Path.cwd())
301
+ if path.suffix == ".json":
302
+ path = path.parent
303
+ else:
304
+ path = path.joinpath(
305
+ self.general_config_tracker.model_name_sanitized
306
+ )
307
+ path.mkdir(parents=True, exist_ok=True)
308
+
309
+ file_results_samples = path.joinpath(
310
+ f"samples_{task_name}_{self.date_id}.jsonl"
311
+ )
312
+
313
+ for sample in samples:
314
+ # we first need to sanitize arguments and resps
315
+ # otherwise we won't be able to load the dataset
316
+ # using the datasets library
317
+ arguments = {}
318
+ for i, arg in enumerate(sample["arguments"]):
319
+ arguments[f"gen_args_{i}"] = {}
320
+ for j, tmp in enumerate(arg):
321
+ arguments[f"gen_args_{i}"][f"arg_{j}"] = tmp
322
+
323
+ sample["resps"] = sanitize_list(sample["resps"])
324
+ sample["filtered_resps"] = sanitize_list(sample["filtered_resps"])
325
+ sample["arguments"] = arguments
326
+ sample["target"] = str(sample["target"])
327
+
328
+ sample_dump = (
329
+ json.dumps(
330
+ sample,
331
+ default=handle_non_serializable,
332
+ ensure_ascii=False,
333
+ )
334
+ + "\n"
335
+ )
336
+
337
+ with open(file_results_samples, "a", encoding="utf-8") as f:
338
+ f.write(sample_dump)
339
+
340
+ if self.api and self.push_samples_to_hub:
341
+ repo_id = (
342
+ self.details_repo
343
+ if self.public_repo
344
+ else self.details_repo_private
345
+ )
346
+ self.api.create_repo(
347
+ repo_id=repo_id,
348
+ repo_type="dataset",
349
+ private=not self.public_repo,
350
+ exist_ok=True,
351
+ )
352
+ try:
353
+ if self.gated_repo:
354
+ headers = build_hf_headers()
355
+ r = get_session().put(
356
+ url=f"https://huggingface.co/api/datasets/{repo_id}/settings",
357
+ headers=headers,
358
+ json={"gated": "auto"},
359
+ )
360
+ hf_raise_for_status(r)
361
+ except Exception as e:
362
+ eval_logger.warning("Could not gate the repository")
363
+ eval_logger.info(repr(e))
364
+ self.api.upload_folder(
365
+ repo_id=repo_id,
366
+ folder_path=str(path),
367
+ path_in_repo=self.general_config_tracker.model_name_sanitized,
368
+ repo_type="dataset",
369
+ commit_message=f"Adding samples results for {task_name} to {self.general_config_tracker.model_name}",
370
+ )
371
+ eval_logger.info(
372
+ f"Successfully pushed sample results for task: {task_name} to the Hugging Face Hub. "
373
+ f"You can find them at: {repo_id}"
374
+ )
375
+
376
+ except Exception as e:
377
+ eval_logger.warning("Could not save sample results")
378
+ eval_logger.info(repr(e))
379
+ else:
380
+ eval_logger.info("Output path not provided, skipping saving sample results")
381
+
382
+ def recreate_metadata_card(self) -> None:
383
+ """
384
+ Creates a metadata card for the evaluation results dataset and pushes it to the Hugging Face hub.
385
+ """
386
+
387
+ eval_logger.info("Recreating metadata card")
388
+ repo_id = self.details_repo if self.public_repo else self.details_repo_private
389
+
390
+ files_in_repo = self.api.list_repo_files(repo_id=repo_id, repo_type="dataset")
391
+ results_files = get_results_filenames(files_in_repo)
392
+ sample_files = get_sample_results_filenames(files_in_repo)
393
+
394
+ # Build a dictionary to store the latest evaluation datetime for:
395
+ # - Each tested model and its aggregated results
396
+ # - Each task and sample results, if existing
397
+ # i.e. {
398
+ # "org__model_name__gsm8k": "2021-09-01T12:00:00",
399
+ # "org__model_name__ifeval": "2021-09-01T12:00:00",
400
+ # "org__model_name__results": "2021-09-01T12:00:00"
401
+ # }
402
+ latest_task_results_datetime = defaultdict(lambda: datetime.min.isoformat())
403
+
404
+ for file_path in sample_files:
405
+ file_path = Path(file_path)
406
+ filename = file_path.name
407
+ model_name = file_path.parent
408
+ task_name = get_file_task_name(filename)
409
+ results_datetime = get_file_datetime(filename)
410
+ task_name_sanitized = sanitize_task_name(task_name)
411
+ # Results and sample results for the same model and task will have the same datetime
412
+ samples_key = f"{model_name}__{task_name_sanitized}"
413
+ results_key = f"{model_name}__results"
414
+ latest_datetime = max(
415
+ latest_task_results_datetime[samples_key],
416
+ results_datetime,
417
+ )
418
+ latest_task_results_datetime[samples_key] = latest_datetime
419
+ latest_task_results_datetime[results_key] = max(
420
+ latest_task_results_datetime[results_key],
421
+ latest_datetime,
422
+ )
423
+
424
+ # Create metadata card
425
+ card_metadata = MetadataConfigs()
426
+
427
+ # Add the latest aggregated results to the metadata card for easy access
428
+ for file_path in results_files:
429
+ file_path = Path(file_path)
430
+ results_filename = file_path.name
431
+ model_name = file_path.parent
432
+ eval_date = get_file_datetime(results_filename)
433
+ eval_date_sanitized = re.sub(r"[^\w\.]", "_", eval_date)
434
+ results_filename = Path("**") / Path(results_filename).name
435
+ config_name = f"{model_name}__results"
436
+ sanitized_last_eval_date_results = re.sub(
437
+ r"[^\w\.]", "_", latest_task_results_datetime[config_name]
438
+ )
439
+
440
+ if eval_date_sanitized == sanitized_last_eval_date_results:
441
+ # Ensure that all results files are listed in the metadata card
442
+ current_results = card_metadata.get(config_name, {"data_files": []})
443
+ current_results["data_files"].append(
444
+ {"split": eval_date_sanitized, "path": [str(results_filename)]}
445
+ )
446
+ card_metadata[config_name] = current_results
447
+ # If the results file is the newest, update the "latest" field in the metadata card
448
+ card_metadata[config_name]["data_files"].append(
449
+ {"split": "latest", "path": [str(results_filename)]}
450
+ )
451
+
452
+ # Add the tasks details configs
453
+ for file_path in sample_files:
454
+ file_path = Path(file_path)
455
+ filename = file_path.name
456
+ model_name = file_path.parent
457
+ task_name = get_file_task_name(filename)
458
+ eval_date = get_file_datetime(filename)
459
+ task_name_sanitized = sanitize_task_name(task_name)
460
+ eval_date_sanitized = re.sub(r"[^\w\.]", "_", eval_date)
461
+ results_filename = Path("**") / Path(filename).name
462
+ config_name = f"{model_name}__{task_name_sanitized}"
463
+ sanitized_last_eval_date_results = re.sub(
464
+ r"[^\w\.]", "_", latest_task_results_datetime[config_name]
465
+ )
466
+ if eval_date_sanitized == sanitized_last_eval_date_results:
467
+ # Ensure that all sample results files are listed in the metadata card
468
+ current_details_for_task = card_metadata.get(
469
+ config_name, {"data_files": []}
470
+ )
471
+ current_details_for_task["data_files"].append(
472
+ {"split": eval_date_sanitized, "path": [str(results_filename)]}
473
+ )
474
+ card_metadata[config_name] = current_details_for_task
475
+ # If the samples results file is the newest, update the "latest" field in the metadata card
476
+ card_metadata[config_name]["data_files"].append(
477
+ {"split": "latest", "path": [str(results_filename)]}
478
+ )
479
+
480
+ # Get latest results and extract info to update metadata card examples
481
+ latest_datetime = max(latest_task_results_datetime.values())
482
+ latest_model_name = max(
483
+ latest_task_results_datetime, key=lambda k: latest_task_results_datetime[k]
484
+ )
485
+ last_results_file = [
486
+ f for f in results_files if latest_datetime.replace(":", "-") in f
487
+ ][0]
488
+ last_results_file_path = hf_hub_url(
489
+ repo_id=repo_id, filename=last_results_file, repo_type="dataset"
490
+ )
491
+ latest_results_file = load_dataset(
492
+ "json", data_files=last_results_file_path, split="train"
493
+ )
494
+ results_dict = latest_results_file["results"][0]
495
+ new_dictionary = {"all": results_dict}
496
+ new_dictionary.update(results_dict)
497
+ results_string = json.dumps(new_dictionary, indent=4)
498
+
499
+ dataset_summary = (
500
+ "Dataset automatically created during the evaluation run of model "
501
+ )
502
+ if self.general_config_tracker.model_source == "hf":
503
+ dataset_summary += f"[{self.general_config_tracker.model_name}](https://huggingface.co/{self.general_config_tracker.model_name})\n"
504
+ else:
505
+ dataset_summary += f"{self.general_config_tracker.model_name}\n"
506
+ dataset_summary += (
507
+ f"The dataset is composed of {len(card_metadata) - 1} configuration(s), each one corresponding to one of the evaluated task.\n\n"
508
+ f"The dataset has been created from {len(results_files)} run(s). Each run can be found as a specific split in each "
509
+ 'configuration, the split being named using the timestamp of the run.The "train" split is always pointing to the latest results.\n\n'
510
+ 'An additional configuration "results" store all the aggregated results of the run.\n\n'
511
+ "To load the details from a run, you can for instance do the following:\n"
512
+ )
513
+ if self.general_config_tracker.model_source == "hf":
514
+ dataset_summary += (
515
+ "```python\nfrom datasets import load_dataset\n"
516
+ f'data = load_dataset(\n\t"{repo_id}",\n\tname="{latest_model_name}",\n\tsplit="latest"\n)\n```\n\n'
517
+ )
518
+ dataset_summary += (
519
+ "## Latest results\n\n"
520
+ f"These are the [latest results from run {latest_datetime}]({last_results_file_path.replace('/resolve/', '/blob/')}) "
521
+ "(note that there might be results for other tasks in the repos if successive evals didn't cover the same tasks. "
522
+ 'You find each in the results and the "latest" split for each eval):\n\n'
523
+ f"```python\n{results_string}\n```"
524
+ )
525
+ card_data = DatasetCardData(
526
+ dataset_summary=dataset_summary,
527
+ repo_url=f"https://huggingface.co/{self.general_config_tracker.model_name}",
528
+ pretty_name=f"Evaluation run of {self.general_config_tracker.model_name}",
529
+ leaderboard_url=self.leaderboard_url,
530
+ point_of_contact=self.point_of_contact,
531
+ )
532
+ card_metadata.to_dataset_card_data(card_data)
533
+ card = DatasetCard.from_template(
534
+ card_data,
535
+ pretty_name=card_data.pretty_name,
536
+ )
537
+ card.push_to_hub(repo_id, repo_type="dataset")
lm-evaluation-harness/lm_eval/loggers/utils.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ import re
4
+ import subprocess
5
+ from importlib.metadata import version
6
+ from pathlib import Path
7
+ from typing import Any, Dict, Optional, Tuple, Union
8
+
9
+ import numpy as np
10
+ from torch.utils.collect_env import get_pretty_env_info
11
+ from transformers import __version__ as trans_version
12
+
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def remove_none_pattern(input_string: str) -> Tuple[str, bool]:
18
+ """Remove the ',none' substring from the input_string if it exists at the end.
19
+
20
+ Args:
21
+ input_string (str): The input string from which to remove the ',none' substring.
22
+
23
+ Returns:
24
+ Tuple[str, bool]: A tuple containing the modified input_string with the ',none' substring removed
25
+ and a boolean indicating whether the modification was made (True) or not (False).
26
+ """
27
+ # Define the pattern to match ',none' at the end of the string
28
+ pattern = re.compile(r",none$")
29
+
30
+ # Use sub() to replace ',none' with an empty string
31
+ result = re.sub(pattern, "", input_string)
32
+
33
+ # check if the input_string changed
34
+ removed = result != input_string
35
+
36
+ return result, removed
37
+
38
+
39
+ def _handle_non_serializable(o: Any) -> Union[int, str, list]:
40
+ """Handle non-serializable objects by converting them to serializable types.
41
+
42
+ Args:
43
+ o (Any): The object to be handled.
44
+
45
+ Returns:
46
+ Union[int, str, list]: The converted object. If the object is of type np.int64 or np.int32,
47
+ it will be converted to int. If the object is of type set, it will be converted
48
+ to a list. Otherwise, it will be converted to str.
49
+ """
50
+ if isinstance(o, np.int64) or isinstance(o, np.int32):
51
+ return int(o)
52
+ elif isinstance(o, set):
53
+ return list(o)
54
+ else:
55
+ return str(o)
56
+
57
+
58
+ def get_commit_from_path(repo_path: Union[Path, str]) -> Optional[str]:
59
+ try:
60
+ git_folder = Path(repo_path, ".git")
61
+ if git_folder.is_file():
62
+ git_folder = Path(
63
+ git_folder.parent,
64
+ git_folder.read_text(encoding="utf-8").split("\n")[0].split(" ")[-1],
65
+ )
66
+ if Path(git_folder, "HEAD").exists():
67
+ head_name = (
68
+ Path(git_folder, "HEAD")
69
+ .read_text(encoding="utf-8")
70
+ .split("\n")[0]
71
+ .split(" ")[-1]
72
+ )
73
+ head_ref = Path(git_folder, head_name)
74
+ git_hash = head_ref.read_text(encoding="utf-8").replace("\n", "")
75
+ else:
76
+ git_hash = None
77
+ except Exception as err:
78
+ logger.debug(
79
+ f"Failed to retrieve a Git commit hash from path: {str(repo_path)}. Error: {err}"
80
+ )
81
+ return None
82
+ return git_hash
83
+
84
+
85
+ def get_git_commit_hash():
86
+ """
87
+ Gets the git commit hash of your current repo (if it exists).
88
+ Source: https://github.com/EleutherAI/gpt-neox/blob/b608043be541602170bfcfb8ec9bf85e8a0799e0/megatron/neox_arguments/neox_args.py#L42
89
+ """
90
+ try:
91
+ git_hash = subprocess.check_output(["git", "describe", "--always"]).strip()
92
+ git_hash = git_hash.decode()
93
+ except (subprocess.CalledProcessError, FileNotFoundError):
94
+ # FileNotFoundError occurs when git not installed on system
95
+ git_hash = get_commit_from_path(os.getcwd()) # git hash of repo if exists
96
+ return git_hash
97
+
98
+
99
+ def add_env_info(storage: Dict[str, Any]):
100
+ try:
101
+ pretty_env_info = get_pretty_env_info()
102
+ except Exception as err:
103
+ pretty_env_info = str(err)
104
+ try:
105
+ lm_eval_version = version("lm_eval")
106
+ except Exception as err:
107
+ lm_eval_version = str(err)
108
+ transformers_version = trans_version
109
+ upper_dir_commit = get_commit_from_path(
110
+ Path(os.getcwd(), "..")
111
+ ) # git hash of upper repo if exists
112
+ added_info = {
113
+ "pretty_env_info": pretty_env_info,
114
+ "transformers_version": transformers_version,
115
+ "lm_eval_version": lm_eval_version,
116
+ "upper_git_hash": upper_dir_commit, # in case this repo is submodule
117
+ }
118
+ storage.update(added_info)
119
+
120
+
121
+ def add_tokenizer_info(storage: Dict[str, Any], lm):
122
+ if getattr(lm, "tokenizer", False):
123
+ try:
124
+ tokenizer_info = {
125
+ "tokenizer_pad_token": [
126
+ lm.tokenizer.pad_token,
127
+ str(lm.tokenizer.pad_token_id),
128
+ ],
129
+ "tokenizer_eos_token": [
130
+ lm.tokenizer.eos_token,
131
+ str(lm.tokenizer.eos_token_id),
132
+ ],
133
+ "tokenizer_bos_token": [
134
+ lm.tokenizer.bos_token,
135
+ str(lm.tokenizer.bos_token_id),
136
+ ],
137
+ "eot_token_id": getattr(lm, "eot_token_id", None),
138
+ "max_length": getattr(lm, "max_length", None),
139
+ }
140
+ storage.update(tokenizer_info)
141
+ except Exception as err:
142
+ logger.debug(
143
+ f"Logging detailed tokenizer info failed with {err}, skipping..."
144
+ )
145
+ # seems gguf and textsynth do not have tokenizer
146
+ else:
147
+ logger.debug(
148
+ "LM does not have a 'tokenizer' attribute, not logging tokenizer metadata to results."
149
+ )
lm-evaluation-harness/lm_eval/loggers/wandb_logger.py ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import json
3
+ import logging
4
+ from typing import Any, Dict, List, Literal, Tuple
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ from packaging.version import Version
9
+
10
+ from lm_eval.loggers.utils import _handle_non_serializable, remove_none_pattern
11
+
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def get_wandb_printer() -> Literal["Printer"]:
17
+ """Returns a wandb printer instance for pretty stdout."""
18
+ from wandb.sdk.lib.printer import new_printer
19
+
20
+ printer = new_printer()
21
+ return printer
22
+
23
+
24
+ class WandbLogger:
25
+ def __init__(self, init_args=None, config_args=None) -> None:
26
+ """Attaches to wandb logger if already initialized. Otherwise, passes init_args to wandb.init() and config_args to wandb.config.update()
27
+
28
+ Args:
29
+ init_args Optional[Dict]: Arguments for init configuration.
30
+ config_args Optional[Dict]: Arguments for config
31
+
32
+ Parse and log the results returned from evaluator.simple_evaluate() with:
33
+ wandb_logger.post_init(results)
34
+ wandb_logger.log_eval_result()
35
+ wandb_logger.log_eval_samples(results["samples"])
36
+ """
37
+ try:
38
+ import wandb
39
+
40
+ assert Version(wandb.__version__) >= Version("0.13.6")
41
+ if Version(wandb.__version__) < Version("0.13.6"):
42
+ wandb.require("report-editing:v0")
43
+ except Exception as e:
44
+ logger.warning(
45
+ "To use the wandb reporting functionality please install wandb>=0.13.6.\n"
46
+ "To install the latest version of wandb run `pip install wandb --upgrade`\n"
47
+ f"{e}"
48
+ )
49
+
50
+ self.wandb_args: Dict[str, Any] = init_args or {}
51
+ self.wandb_config_args: Dict[str, Any] = config_args or {}
52
+
53
+ # pop the step key from the args to save for all logging calls
54
+ self.step = self.wandb_args.pop("step", None)
55
+
56
+ # initialize a W&B run
57
+ if wandb.run is None:
58
+ self.run = wandb.init(**self.wandb_args)
59
+ if self.wandb_config_args:
60
+ self.run.config.update(self.wandb_config_args)
61
+ else:
62
+ self.run = wandb.run
63
+
64
+ self.printer = get_wandb_printer()
65
+
66
+ def post_init(self, results: Dict[str, Any]) -> None:
67
+ self.results: Dict[str, Any] = copy.deepcopy(results)
68
+ self.task_names: List[str] = list(results.get("results", {}).keys())
69
+ self.group_names: List[str] = list(results.get("groups", {}).keys())
70
+
71
+ def _get_config(self) -> Dict[str, Any]:
72
+ """Get configuration parameters."""
73
+ self.task_configs = self.results.get("configs", {})
74
+ cli_configs = self.results.get("config", {})
75
+ configs = {
76
+ "task_configs": self.task_configs,
77
+ "cli_configs": cli_configs,
78
+ }
79
+
80
+ return configs
81
+
82
+ def _sanitize_results_dict(self) -> Tuple[Dict[str, str], Dict[str, Any]]:
83
+ """Sanitize the results dictionary."""
84
+ _results = copy.deepcopy(self.results.get("results", dict()))
85
+
86
+ # Remove None from the metric string name
87
+ tmp_results = copy.deepcopy(_results)
88
+ for task_name in self.task_names:
89
+ task_result = tmp_results.get(task_name, dict())
90
+ for metric_name, metric_value in task_result.items():
91
+ _metric_name, removed = remove_none_pattern(metric_name)
92
+ if removed:
93
+ _results[task_name][_metric_name] = metric_value
94
+ _results[task_name].pop(metric_name)
95
+
96
+ # remove string valued keys from the results dict
97
+ wandb_summary = {}
98
+ for task in self.task_names:
99
+ task_result = _results.get(task, dict())
100
+ for metric_name, metric_value in task_result.items():
101
+ if isinstance(metric_value, str):
102
+ wandb_summary[f"{task}/{metric_name}"] = metric_value
103
+
104
+ for summary_metric, summary_value in wandb_summary.items():
105
+ _task, _summary_metric = summary_metric.split("/")
106
+ _results[_task].pop(_summary_metric)
107
+
108
+ tmp_results = copy.deepcopy(_results)
109
+ for task_name, task_results in tmp_results.items():
110
+ for metric_name, metric_value in task_results.items():
111
+ _results[f"{task_name}/{metric_name}"] = metric_value
112
+ _results[task_name].pop(metric_name)
113
+ for task in self.task_names:
114
+ _results.pop(task)
115
+
116
+ return wandb_summary, _results
117
+
118
+ def _log_results_as_table(self) -> None:
119
+ """Generate and log evaluation results as a table to W&B."""
120
+ columns = [
121
+ "Version",
122
+ "Filter",
123
+ "num_fewshot",
124
+ "Metric",
125
+ "Value",
126
+ "Stderr",
127
+ ]
128
+
129
+ def make_table(columns: List[str], key: str = "results"):
130
+ import wandb
131
+
132
+ table = wandb.Table(columns=columns)
133
+ results = copy.deepcopy(self.results)
134
+
135
+ for k, dic in results.get(key).items():
136
+ if k in self.group_names and not key == "groups":
137
+ continue
138
+ version = results.get("versions").get(k)
139
+ if version == "N/A":
140
+ version = None
141
+ n = results.get("n-shot").get(k)
142
+
143
+ for (mf), v in dic.items():
144
+ m, _, f = mf.partition(",")
145
+ if m.endswith("_stderr"):
146
+ continue
147
+ if m == "alias":
148
+ continue
149
+
150
+ if m + "_stderr" + "," + f in dic:
151
+ se = dic[m + "_stderr" + "," + f]
152
+ if se != "N/A":
153
+ se = "%.4f" % se
154
+ table.add_data(*[k, version, f, n, m, str(v), str(se)])
155
+ else:
156
+ table.add_data(*[k, version, f, n, m, str(v), ""])
157
+
158
+ return table
159
+
160
+ # log the complete eval result to W&B Table
161
+ table = make_table(["Tasks"] + columns, "results")
162
+ self.run.log({"evaluation/eval_results": table}, step=self.step)
163
+
164
+ if "groups" in self.results.keys():
165
+ table = make_table(["Groups"] + columns, "groups")
166
+ self.run.log({"evaluation/group_eval_results": table}, step=self.step)
167
+
168
+ def _log_results_as_artifact(self) -> None:
169
+ """Log results as JSON artifact to W&B."""
170
+ import wandb
171
+
172
+ dumped = json.dumps(
173
+ self.results, indent=2, default=_handle_non_serializable, ensure_ascii=False
174
+ )
175
+ artifact = wandb.Artifact("results", type="eval_results")
176
+ with artifact.new_file("results.json", mode="w", encoding="utf-8") as f:
177
+ f.write(dumped)
178
+ self.run.log_artifact(artifact)
179
+
180
+ def log_eval_result(self) -> None:
181
+ """Log evaluation results to W&B."""
182
+ # Log configs to wandb
183
+ configs = self._get_config()
184
+ self.run.config.update(configs, allow_val_change=self.step is not None)
185
+
186
+ wandb_summary, self.wandb_results = self._sanitize_results_dict()
187
+ # update wandb.run.summary with items that were removed
188
+ self.run.summary.update(wandb_summary)
189
+ # Log the evaluation metrics to wandb
190
+ self.run.log(self.wandb_results, step=self.step)
191
+ # Log the evaluation metrics as W&B Table
192
+ self._log_results_as_table()
193
+ # Log the results dict as json to W&B Artifacts
194
+ self._log_results_as_artifact()
195
+
196
+ def _generate_dataset(
197
+ self, data: List[Dict[str, Any]], config: Dict[str, Any]
198
+ ) -> pd.DataFrame:
199
+ """Generate a dataset from evaluation data.
200
+
201
+ Args:
202
+ data (List[Dict[str, Any]]): The data to generate a dataset for.
203
+ config (Dict[str, Any]): The configuration of the task.
204
+
205
+ Returns:
206
+ pd.DataFrame: A dataframe that is ready to be uploaded to W&B.
207
+ """
208
+ ids = [x["doc_id"] for x in data]
209
+ labels = [x["target"] for x in data]
210
+ instance = [""] * len(ids)
211
+ resps = [""] * len(ids)
212
+ filtered_resps = [""] * len(ids)
213
+ model_outputs = {}
214
+
215
+ metrics_list = config["metric_list"]
216
+ metrics = {}
217
+ for metric in metrics_list:
218
+ metric = metric.get("metric")
219
+ if metric in ["word_perplexity", "byte_perplexity", "bits_per_byte"]:
220
+ metrics[f"{metric}_loglikelihood"] = [x[metric][0] for x in data]
221
+ if metric in ["byte_perplexity", "bits_per_byte"]:
222
+ metrics[f"{metric}_bytes"] = [x[metric][1] for x in data]
223
+ else:
224
+ metrics[f"{metric}_words"] = [x[metric][1] for x in data]
225
+ else:
226
+ metrics[metric] = [x[metric] for x in data]
227
+
228
+ if config["output_type"] == "loglikelihood":
229
+ instance = [x["arguments"][0][0] for x in data]
230
+ labels = [x["arguments"][0][1] for x in data]
231
+ resps = [
232
+ f"log probability of continuation is {x['resps'][0][0][0]} "
233
+ + "\n\n"
234
+ + "continuation will {} generated with greedy sampling".format(
235
+ "not be" if not x["resps"][0][0][1] else "be"
236
+ )
237
+ for x in data
238
+ ]
239
+ filtered_resps = [
240
+ f"log probability of continuation is {x['filtered_resps'][0][0]} "
241
+ + "\n\n"
242
+ + "continuation will {} generated with greedy sampling".format(
243
+ "not be" if not x["filtered_resps"][0][1] else "be"
244
+ )
245
+ for x in data
246
+ ]
247
+ elif config["output_type"] == "multiple_choice":
248
+ instance = [x["arguments"][0][0] for x in data]
249
+ choices = [
250
+ "\n".join([f"{idx}. {y[1]}" for idx, y in enumerate(x["arguments"])])
251
+ for x in data
252
+ ]
253
+ resps = [np.argmax([n[0][0] for n in x["resps"]]) for x in data]
254
+ filtered_resps = [
255
+ np.argmax([n[0] for n in x["filtered_resps"]]) for x in data
256
+ ]
257
+ elif config["output_type"] == "loglikelihood_rolling":
258
+ instance = [x["arguments"][0][0] for x in data]
259
+ resps = [x["resps"][0][0] for x in data]
260
+ filtered_resps = [x["filtered_resps"][0] for x in data]
261
+ elif config["output_type"] == "generate_until":
262
+ instance = [x["arguments"][0][0] for x in data]
263
+ resps = [x["resps"][0][0] for x in data]
264
+ filtered_resps = [x["filtered_resps"][0] for x in data]
265
+
266
+ model_outputs["raw_predictions"] = resps
267
+ model_outputs["filtered_predictions"] = filtered_resps
268
+
269
+ df_data = {
270
+ "id": ids,
271
+ "data": instance,
272
+ }
273
+ if config["output_type"] == "multiple_choice":
274
+ df_data["choices"] = choices
275
+
276
+ tmp_data = {
277
+ "input_len": [len(x) for x in instance],
278
+ "labels": labels,
279
+ "output_type": config["output_type"],
280
+ }
281
+ df_data.update(tmp_data)
282
+ df_data.update(model_outputs)
283
+ df_data.update(metrics)
284
+
285
+ return pd.DataFrame(df_data)
286
+
287
+ def _log_samples_as_artifact(
288
+ self, data: List[Dict[str, Any]], task_name: str
289
+ ) -> None:
290
+ import wandb
291
+
292
+ # log the samples as an artifact
293
+ dumped = json.dumps(
294
+ data,
295
+ indent=2,
296
+ default=_handle_non_serializable,
297
+ ensure_ascii=False,
298
+ )
299
+ artifact = wandb.Artifact(f"{task_name}", type="samples_by_task")
300
+ with artifact.new_file(
301
+ f"{task_name}_eval_samples.json", mode="w", encoding="utf-8"
302
+ ) as f:
303
+ f.write(dumped)
304
+ self.run.log_artifact(artifact)
305
+ # artifact.wait()
306
+
307
+ def log_eval_samples(self, samples: Dict[str, List[Dict[str, Any]]]) -> None:
308
+ """Log evaluation samples to W&B.
309
+
310
+ Args:
311
+ samples (Dict[str, List[Dict[str, Any]]]): Evaluation samples for each task.
312
+ """
313
+ task_names: List[str] = [
314
+ x for x in self.task_names if x not in self.group_names
315
+ ]
316
+
317
+ ungrouped_tasks = []
318
+ tasks_by_groups = {}
319
+
320
+ for task_name in task_names:
321
+ group_names = self.task_configs[task_name].get("group", None)
322
+ if group_names:
323
+ if isinstance(group_names, str):
324
+ group_names = [group_names]
325
+
326
+ for group_name in group_names:
327
+ if not tasks_by_groups.get(group_name):
328
+ tasks_by_groups[group_name] = [task_name]
329
+ else:
330
+ tasks_by_groups[group_name].append(task_name)
331
+ else:
332
+ ungrouped_tasks.append(task_name)
333
+
334
+ for task_name in ungrouped_tasks:
335
+ eval_preds = samples[task_name]
336
+
337
+ # log the samples as a W&B Table
338
+ df = self._generate_dataset(eval_preds, self.task_configs.get(task_name))
339
+ self.run.log({f"{task_name}_eval_results": df}, step=self.step)
340
+
341
+ # log the samples as a json file as W&B Artifact
342
+ self._log_samples_as_artifact(eval_preds, task_name)
343
+
344
+ for group, grouped_tasks in tasks_by_groups.items():
345
+ grouped_df = pd.DataFrame()
346
+ for task_name in grouped_tasks:
347
+ eval_preds = samples[task_name]
348
+ df = self._generate_dataset(
349
+ eval_preds, self.task_configs.get(task_name)
350
+ )
351
+ df["group"] = group
352
+ df["task"] = task_name
353
+ grouped_df = pd.concat([grouped_df, df], ignore_index=True)
354
+
355
+ # log the samples as a json file as W&B Artifact
356
+ self._log_samples_as_artifact(eval_preds, task_name)
357
+
358
+ self.run.log({f"{group}_eval_results": grouped_df}, step=self.step)
lm-evaluation-harness/lm_eval/models/__init__.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from . import (
2
+ anthropic_llms,
3
+ api_models,
4
+ dummy,
5
+ gguf,
6
+ hf_audiolm,
7
+ hf_steered,
8
+ hf_vlms,
9
+ huggingface,
10
+ ibm_watsonx_ai,
11
+ mamba_lm,
12
+ nemo_lm,
13
+ neuralmagic,
14
+ neuron_optimum,
15
+ openai_completions,
16
+ optimum_ipex,
17
+ optimum_lm,
18
+ sglang_causallms,
19
+ sglang_generate_API,
20
+ textsynth,
21
+ vllm_causallms,
22
+ vllm_vlms,
23
+ )
24
+
25
+
26
+ # TODO: implement __all__
27
+
28
+
29
+ try:
30
+ # enable hf hub transfer if available
31
+ import hf_transfer # type: ignore # noqa
32
+ import huggingface_hub.constants # type: ignore
33
+
34
+ huggingface_hub.constants.HF_HUB_ENABLE_HF_TRANSFER = True
35
+ except ImportError:
36
+ pass
lm-evaluation-harness/lm_eval/models/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (835 Bytes). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (1.17 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/anthropic_llms.cpython-310.pyc ADDED
Binary file (11.2 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/anthropic_llms.cpython-311.pyc ADDED
Binary file (16.8 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/api_models.cpython-310.pyc ADDED
Binary file (20.3 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/api_models.cpython-311.pyc ADDED
Binary file (37.8 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/dummy.cpython-310.pyc ADDED
Binary file (1.62 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/dummy.cpython-311.pyc ADDED
Binary file (2.59 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/gguf.cpython-310.pyc ADDED
Binary file (4.13 kB). View file
 
lm-evaluation-harness/lm_eval/models/__pycache__/gguf.cpython-311.pyc ADDED
Binary file (7.13 kB). View file