Skip to content

Commit aaa8bbf

Browse files
hynky1999NathanHBHynek Kydlicek
authored
Standalone nanotron config (#285)
What does this implement/fix? Explain your changes. --------------------------------------------------- This PR moves the lighteval config to lighteval codebase. - Enforces the lighteval_config_path as the only way to read the lighteval config. The nanotron part is ignore, this way the breaking changes won't be as breaking. - Some typing corrections --------- Co-authored-by: Nathan Habib <[email protected]> Co-authored-by: Nathan Habib <[email protected]> Co-authored-by: Hynek Kydlicek <[email protected]>
1 parent 21934d5 commit aaa8bbf

File tree

11 files changed

+163
-76
lines changed

11 files changed

+163
-76
lines changed

examples/nanotron/lighteval_config_override_template.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
batch_size: 16
2-
checkpoints_path: null
1+
# As of right now auto batch size doesn't work, so we use some default
2+
batch_size: 8
33
generation: null
44
logging:
5-
hub_repo_details: null
6-
hub_repo_results: null
7-
hub_repo_tensorboard: null
8-
local_output_path: ./output_dir
9-
push_details_to_hub: false
5+
output_dir: "outputs"
6+
save_details: false
107
push_results_to_hub: false
11-
push_results_to_tensorboard: true
12-
tensorboard_metric_prefix: e
8+
push_details_to_hub: false
9+
push_results_to_tensorboard: false
10+
public_run: false
11+
results_org: null
12+
tensorboard_metric_prefix: "eval"
1313
parallelism:
1414
dp: 1
1515
pp: 1

src/lighteval/__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def cli_evaluate():
6060
elif args.subcommand == "nanotron":
6161
from lighteval.main_nanotron import main as main_nanotron
6262

63-
main_nanotron(args.checkpoint_config_path, args.lighteval_override, args.cache_dir)
63+
main_nanotron(args.checkpoint_config_path, args.lighteval_config_path, args.cache_dir)
6464

6565
elif args.subcommand == "tasks":
6666
if args.list:
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# MIT License
2+
3+
# Copyright (c) 2024 The HuggingFace Team
4+
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
from dataclasses import dataclass
24+
from typing import Dict, Optional, Union
25+
26+
from nanotron.config import Config
27+
from nanotron.config.parallelism_config import ParallelismArgs
28+
from nanotron.generation.sampler import SamplerType
29+
from nanotron.logging import get_logger
30+
31+
32+
logger = get_logger(__name__)
33+
34+
DEFAULT_GENERATION_SEED = 42
35+
36+
37+
@dataclass
38+
class GenerationArgs:
39+
sampler: Optional[Union[str, SamplerType]] = None
40+
temperature: Optional[float] = None
41+
top_k: Optional[int] = None
42+
top_p: Optional[float] = None
43+
n_samples: Optional[int] = None
44+
eos: Optional[str] = None
45+
seed: Optional[int] = None
46+
use_cache: Optional[bool] = False
47+
48+
def __post_init__(self):
49+
if isinstance(self.sampler, str):
50+
self.sampler = SamplerType[self.sampler.upper()]
51+
if self.seed is None:
52+
self.seed = DEFAULT_GENERATION_SEED
53+
54+
55+
@dataclass
56+
class LightEvalLoggingArgs:
57+
"""Arguments related to logging for LightEval"""
58+
59+
output_dir: str
60+
save_details: bool = True
61+
push_results_to_hub: bool = False
62+
push_details_to_hub: bool = False
63+
push_results_to_tensorboard: bool = False
64+
public_run: bool = False
65+
results_org: str | None = None
66+
tensorboard_metric_prefix: str = "eval"
67+
68+
69+
@dataclass
70+
class LightEvalTasksArgs:
71+
"""Arguments related to tasks for LightEval"""
72+
73+
tasks: str
74+
custom_tasks: Optional[str] = None
75+
max_samples: Optional[int] = None
76+
num_fewshot_seeds: Optional[int] = None
77+
78+
dataset_loading_processes: int = 8
79+
multichoice_continuations_start_space: Optional[bool] = None
80+
81+
82+
@dataclass
83+
class LightEvalConfig:
84+
"""Arguments related to running LightEval on checkpoints.
85+
86+
All is optional because you can also use this class to later supply arguments to override
87+
the saved config when running LightEval after training.
88+
"""
89+
90+
logging: LightEvalLoggingArgs
91+
tasks: LightEvalTasksArgs
92+
parallelism: ParallelismArgs
93+
batch_size: int = 0
94+
generation: Optional[Union[GenerationArgs, Dict[str, GenerationArgs]]] = None
95+
96+
97+
@dataclass
98+
class FullNanotronConfig:
99+
lighteval_config: LightEvalConfig
100+
nanotron_config: Config

src/lighteval/logging/evaluation_tracker.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ class EvaluationTracker:
9494

9595
def __init__(
9696
self,
97-
output_dir: str = None,
98-
hub_results_org: str = "",
97+
output_dir: str,
98+
hub_results_org: str | None = None,
9999
push_results_to_hub: bool = False,
100100
push_details_to_hub: bool = False,
101101
push_results_to_tensorboard: bool = False,
@@ -133,14 +133,13 @@ def __init__(
133133

134134
self.output_dir = output_dir
135135

136-
self.hub_results_org = hub_results_org # will also contain tensorboard results
137-
if hub_results_org in ["", None] and any(
138-
[push_details_to_hub, push_results_to_hub, push_results_to_tensorboard]
139-
):
136+
if hub_results_org in [None] and any([push_details_to_hub, push_results_to_hub, push_results_to_tensorboard]):
140137
raise Exception(
141138
"You need to select which org to push to, using `--results_org`, if you want to save information to the hub."
142139
)
143140

141+
self.hub_results_org = hub_results_org # will also contain tensorboard results
142+
144143
self.hub_results_repo = f"{hub_results_org}/results"
145144
self.hub_private_results_repo = f"{hub_results_org}/private-results"
146145
self.push_results_to_hub = push_results_to_hub

src/lighteval/main_nanotron.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import os
2525
from typing import Optional
2626

27+
from lighteval.config.lighteval_config import FullNanotronConfig, LightEvalConfig
2728
from lighteval.logging.evaluation_tracker import EvaluationTracker
2829
from lighteval.logging.hierarchical_logger import htrack, htrack_block
2930
from lighteval.pipeline import ParallelismManager, Pipeline, PipelineParameters
@@ -34,7 +35,7 @@
3435
if not is_nanotron_available():
3536
raise ImportError(NO_NANOTRON_ERROR_MSG)
3637

37-
from nanotron.config import Config, LightEvalConfig, get_config_from_file
38+
from nanotron.config import Config, get_config_from_file
3839

3940

4041
SEED = 1234
@@ -60,28 +61,26 @@ def main(
6061
skip_unused_config_keys=True,
6162
skip_null_keys=True,
6263
)
63-
if lighteval_config_path:
64-
lighteval_config = get_config_from_file(lighteval_config_path, config_class=LightEvalConfig)
65-
model_config.lighteval = lighteval_config
66-
else:
67-
lighteval_config = model_config.lighteval
64+
65+
# We are getting an type error, because the get_config_from_file is not correctly typed,
66+
lighteval_config: LightEvalConfig = get_config_from_file(lighteval_config_path, config_class=LightEvalConfig) # type: ignore
67+
nanotron_config = FullNanotronConfig(lighteval_config, model_config)
6868

6969
evaluation_tracker = EvaluationTracker(
70-
token=os.getenv("HF_TOKEN"),
71-
output_dir=lighteval_config.logging.local_output_path,
72-
hub_results_org=lighteval_config.logging.hub_repo_tensorboard,
70+
output_dir=lighteval_config.logging.output_dir,
71+
hub_results_org=lighteval_config.logging.results_org,
7372
tensorboard_metric_prefix=lighteval_config.logging.tensorboard_metric_prefix,
74-
nanotron_run_info=model_config.general,
73+
nanotron_run_info=nanotron_config.nanotron_config.general,
7574
)
7675

7776
pipeline_parameters = PipelineParameters(
7877
launcher_type=ParallelismManager.NANOTRON,
7978
env_config=env_config,
80-
job_id=os.environ.get("SLURM_JOB_ID", None),
79+
job_id=os.environ.get("SLURM_JOB_ID", 0),
8180
nanotron_checkpoint_path=checkpoint_config_path,
8281
dataset_loading_processes=lighteval_config.tasks.dataset_loading_processes,
8382
custom_tasks_directory=lighteval_config.tasks.custom_tasks,
84-
override_batch_size=None,
83+
override_batch_size=lighteval_config.batch_size,
8584
num_fewshot_seeds=1,
8685
max_samples=lighteval_config.tasks.max_samples,
8786
use_chat_template=False,
@@ -92,7 +91,7 @@ def main(
9291
tasks=lighteval_config.tasks.tasks,
9392
pipeline_parameters=pipeline_parameters,
9493
evaluation_tracker=evaluation_tracker,
95-
model_config=model_config,
94+
model_config=nanotron_config,
9695
)
9796

9897
pipeline.evaluate()

src/lighteval/models/base_model.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ def __init__(
7373
"""Initializes a HuggingFace `AutoModel` and `AutoTokenizer` for evaluation."""
7474
self._config = config.init_configs(env_config)
7575
self.accelerator = config.accelerator
76-
self._batch_size = config.batch_size
7776
self._max_length = self._init_max_length(config.max_length)
7877
self.use_chat_template = config.use_chat_template
7978

@@ -285,12 +284,6 @@ def _init_max_length(self, max_length) -> int:
285284
# or no max length config setting is found in the model or tokenizer.
286285
return 2048
287286

288-
@property
289-
def batch_size(self) -> int:
290-
if self._batch_size >= 0:
291-
self._batch_size = self._get_batch_size(max_input_length=self.max_length)
292-
return self._batch_size # * gpus
293-
294287
@property
295288
def device(self) -> Union[int, str, torch.device]:
296289
return self._device

src/lighteval/models/nanotron_model.py

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from tqdm import tqdm
3535
from transformers import AutoTokenizer, BatchEncoding
3636

37+
from lighteval.config.lighteval_config import FullNanotronConfig
3738
from lighteval.data import (
3839
GenDistributedSampler,
3940
GenerativeTaskDatasetNanotron,
@@ -55,18 +56,16 @@
5556
)
5657
from lighteval.utils.imports import is_nanotron_available
5758
from lighteval.utils.parallelism import find_executable_batch_size
58-
from lighteval.utils.utils import EnvConfig, as_list, boolstring_to_bool
59+
from lighteval.utils.utils import EnvConfig, as_list
5960

6061

6162
os.environ["TOKENIZERS_PARALLELISM"] = "false"
6263

6364
TokenSequence = Union[List[int], torch.LongTensor, torch.Tensor, BatchEncoding]
6465

6566
if is_nanotron_available():
66-
import nanotron
6767
from nanotron import distributed as dist
6868
from nanotron import logging
69-
from nanotron.config import LightEvalConfig, ModelArgs, TokenizerArgs
7069
from nanotron.generation.decode import decode_tokenized
7170
from nanotron.logging import human_format, log_rank
7271
from nanotron.models import build_model
@@ -90,7 +89,7 @@ class NanotronLightevalModel(LightevalModel):
9089
def __init__(
9190
self,
9291
checkpoint_path: str,
93-
nanotron_config: nanotron.config.Config,
92+
nanotron_config: FullNanotronConfig,
9493
parallel_context: ParallelContext,
9594
max_gen_toks: Optional[int] = 256,
9695
max_length: Optional[int] = None,
@@ -104,12 +103,11 @@ def __init__(
104103
"""Initializes a nanotron model for evaluation.
105104
Args:
106105
"""
107-
model_args: ModelArgs = nanotron_config.model
108-
tokenizer: TokenizerArgs = nanotron_config.tokenizer
109-
lighteval_config: LightEvalConfig = nanotron_config.lighteval
110-
parallel_config: ParallelContext = nanotron_config.lighteval.parallelism
106+
model_args = nanotron_config.nanotron_config.model
107+
tokenizer = nanotron_config.nanotron_config.tokenizer
108+
lighteval_config = nanotron_config.lighteval_config
109+
parallel_config = nanotron_config.lighteval_config.parallelism
111110

112-
self._batch_size = lighteval_config.batch_size
113111
self._max_gen_toks = max_gen_toks
114112
self._max_length = max_length
115113
self.parallel_config = parallel_config
@@ -120,9 +118,7 @@ def __init__(
120118
raise ValueError("PP parallelism is not supported yet")
121119

122120
# multichoice_continuations_start_space can be True (forcing space), False (forcing no space) or None (no forcing)
123-
multichoice_continuations_start_space = boolstring_to_bool(
124-
lighteval_config.tasks.multichoice_continuations_start_space
125-
)
121+
multichoice_continuations_start_space = lighteval_config.tasks.multichoice_continuations_start_space
126122

127123
self.generation_config = lighteval_config.generation
128124
if isinstance(self.generation_config, dict):
@@ -217,7 +213,9 @@ def __init__(
217213

218214
self.multichoice_continuations_start_space = multichoice_continuations_start_space
219215

220-
self.model_info = ModelInfo(model_name=f"{nanotron_config.general.run}/{nanotron_config.general.step}")
216+
self.model_info = ModelInfo(
217+
model_name=f"{nanotron_config.nanotron_config.general.run}/{nanotron_config.nanotron_config.general.step}"
218+
)
221219

222220
@property
223221
def tokenizer(self):
@@ -299,12 +297,6 @@ def max_length(self) -> int:
299297
return self.tokenizer.model_max_length
300298
return self._DEFAULT_MAX_LENGTH
301299

302-
@property
303-
def batch_size(self) -> int:
304-
if self._batch_size >= 0:
305-
self._batch_size = self._get_batch_size(max_input_length=self.max_length)
306-
return self._batch_size # * gpus
307-
308300
@property
309301
def device(self) -> Union[int, str, torch.device]:
310302
return "cuda"
@@ -415,7 +407,7 @@ def _check_continuations_start_space(self, continuation: str) -> str:
415407
return continuation
416408

417409
def loglikelihood_single_token(
418-
self, requests: List[Tuple[str, dict]], override_bs=None
410+
self, requests: List[Tuple[str, dict]], override_bs=0
419411
) -> List[LoglikelihoodSingleTokenResponse]:
420412
"""Tokenize the context and continuation and compute the log likelihood of those
421413
tokenized sequences.
@@ -475,7 +467,7 @@ def loglikelihood(self, requests: List[LoglikelihoodRequest], override_bs=None)
475467
)
476468

477469
def loglikelihood_rolling(
478-
self, requests: List[LoglikelihoodRollingRequest], override_bs=None
470+
self, requests: List[LoglikelihoodRollingRequest], override_bs: int = 0
479471
) -> List[LoglikelihoodResponse]:
480472
"""This function is used to compute the log likelihood of the context for perplexity metrics."""
481473
for request in tqdm(
@@ -652,7 +644,7 @@ def _get_subsets(self, dataset, num_dataset_splits):
652644

653645
@torch.inference_mode()
654646
def _loglikelihood_single_token(
655-
self, requests, disable_tqdm: bool = False, override_bs: int = -1, num_dataset_splits: int = 1
647+
self, requests, disable_tqdm: bool = False, override_bs: int = 0, num_dataset_splits: int = 1
656648
) -> List[LoglikelihoodSingleTokenResponse]:
657649
dataset = LoglikelihoodSingleTokenDataset(requests=requests)
658650
res = []
@@ -1115,7 +1107,7 @@ def greedy_until(
11151107
self,
11161108
requests: List[GreedyUntilRequest],
11171109
disable_tqdm: bool = False,
1118-
override_bs=None,
1110+
override_bs: int = -1,
11191111
num_dataset_splits: int = 1,
11201112
) -> List[GenerativeResponse]:
11211113
"""Greedy generation until a stop token is generated."""
@@ -1155,7 +1147,7 @@ def greedy_until(
11551147
max_input_length = min(len(context_enc) + max_gen, self.max_length)
11561148

11571149
batch_size = self._get_batch_size(
1158-
override_bs=self._batch_size,
1150+
override_bs=override_bs,
11591151
max_input_length=max_input_length,
11601152
starting_batch_size=starting_batch_size,
11611153
)

0 commit comments

Comments
 (0)