Skip to content

Commit 3a08856

Browse files
Use the programmatic interface using an already in memory loaded model (#390)
--------- Co-authored-by: Nathan Habib <[email protected]>
1 parent 89215f1 commit 3a08856

File tree

4 files changed

+121
-12
lines changed

4 files changed

+121
-12
lines changed

src/lighteval/logging/hierarchical_logger.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@
3434

3535
logger = get_logger(__name__, log_level="INFO")
3636
elif is_accelerate_available():
37+
from accelerate import Accelerator, InitProcessGroupKwargs
3738
from accelerate.logging import get_logger
3839

40+
# We must init the accelerator before using the logger
41+
accelerator = Accelerator(kwargs_handlers=[InitProcessGroupKwargs(timeout=timedelta(seconds=3000))])
3942
logger = get_logger(__name__, log_level="INFO")
4043
else:
4144
logger = Logger(__name__, level="INFO")

src/lighteval/models/adapter_model.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ class AdapterModel(BaseModel):
4141
def _create_auto_tokenizer(self, config: AdapterModelConfig, env_config: EnvConfig) -> PreTrainedTokenizer:
4242
# By default, we look at the model config for the model stored in `base_model`
4343
# (= the parent model, not the model of interest)
44-
return self._create_auto_tokenizer_with_name(config.base_model, config=config, env_config=env_config)
44+
return self._create_auto_tokenizer_with_name(
45+
model_name=config.base_model,
46+
revision=config.revision,
47+
env_config=env_config,
48+
tokenizer_name=config.tokenizer,
49+
subfolder=config.subfolder,
50+
trust_remote_code=config.trust_remote_code,
51+
)
4552

4653
def _create_auto_model(self, config: AdapterModelConfig, env_config: EnvConfig) -> AutoModelForCausalLM:
4754
"""Returns a PeftModel from a base model and a version fined tuned using PEFT."""

src/lighteval/models/base_model.py

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from torch.utils.data import DataLoader
3131
from tqdm import tqdm
3232
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
33+
from transformers.models.auto.modeling_auto import MODEL_FOR_CAUSAL_LM_MAPPING_NAMES
3334

3435
from lighteval.data import GenerativeTaskDataset, LoglikelihoodDataset, LoglikelihoodSingleTokenDataset
3536
from lighteval.logging.hierarchical_logger import hlog, hlog_err, hlog_warn
@@ -57,6 +58,7 @@
5758

5859

5960
if is_accelerate_available():
61+
from accelerate import Accelerator
6062
from accelerate.utils import calculate_maximum_sizes, convert_bytes, get_max_memory
6163

6264
os.environ["TOKENIZERS_PARALLELISM"] = "false"
@@ -67,8 +69,8 @@
6769
class BaseModel(LightevalModel):
6870
def __init__(
6971
self,
70-
config: BaseModelConfig,
7172
env_config: EnvConfig,
73+
config: BaseModelConfig,
7274
):
7375
"""Initializes a HuggingFace `AutoModel` and `AutoTokenizer` for evaluation."""
7476
self._config = config.init_configs(env_config)
@@ -114,6 +116,72 @@ def __init__(
114116

115117
self.pairwise_tokenization = config.pairwise_tokenization
116118

119+
@classmethod
120+
def from_model(
121+
cls,
122+
model: Union[AutoModelForCausalLM, LightevalModel],
123+
env_config: EnvConfig,
124+
accelerator: "Accelerator" = None,
125+
tokenizer_name: str = None, # custom tokenizer
126+
trust_remote_code: bool = False,
127+
use_chat_template: bool = False,
128+
add_special_tokens: bool = True,
129+
pairwise_tokenization: bool = False,
130+
multichoice_continuations_start_space: bool = None,
131+
):
132+
# Slightly hackish way to test if the model is a AutoModelForCausalLM, since the instances don't
133+
# derive from this class explicitely
134+
assert isinstance(model, LightevalModel) or type(model).__name__ in MODEL_FOR_CAUSAL_LM_MAPPING_NAMES.values()
135+
136+
if isinstance(model, LightevalModel):
137+
return model
138+
139+
# Instanciate the object without using __init__
140+
self = cls.__new__(cls)
141+
self._config = model.config
142+
self._max_length = self._init_max_length(max_length=model.config.max_length)
143+
self._tokenizer = self._create_auto_tokenizer_with_name(
144+
model_name=model.name_or_path,
145+
revision=model.config._commit_hash,
146+
env_config=env_config,
147+
trust_remote_code=trust_remote_code,
148+
tokenizer_name=tokenizer_name,
149+
)
150+
self.model_name = _simplify_name(model.name_or_path)
151+
self.model_sha = model.config._commit_hash
152+
153+
# If model_parallel is not set we compare the number of processes with the number of GPUs
154+
self.model = model
155+
self.model.eval()
156+
torch.set_grad_enabled(False)
157+
158+
self.accelerator = accelerator
159+
if accelerator is not None:
160+
self._device = accelerator.device
161+
self.model = self.accelerator.prepare(self.model.to(accelerator.device))
162+
else:
163+
self._device = "cpu"
164+
165+
self.use_chat_template = use_chat_template
166+
self._add_special_tokens = add_special_tokens if add_special_tokens is not None else False
167+
self.pairwise_tokenization = pairwise_tokenization
168+
self.multichoice_continuations_start_space = multichoice_continuations_start_space
169+
170+
self.precision = _get_dtype(model.dtype, config=self._config)
171+
172+
if is_accelerate_available():
173+
model_size, _ = calculate_maximum_sizes(self.model)
174+
model_size = convert_bytes(model_size)
175+
else:
176+
model_size = -1
177+
self.model_info = ModelInfo(
178+
model_name=self.model_name,
179+
model_sha=self.model_sha,
180+
model_dtype=self.precision,
181+
model_size=model_size,
182+
)
183+
return self
184+
117185
@property
118186
def tokenizer(self):
119187
return self._tokenizer
@@ -207,10 +275,23 @@ def _create_auto_model(self, config: BaseModelConfig, env_config: EnvConfig) ->
207275
def _create_auto_tokenizer(
208276
self, config: BaseModelConfig, env_config: EnvConfig
209277
) -> transformers.PreTrainedTokenizer:
210-
return self._create_auto_tokenizer_with_name(config.pretrained, config=config, env_config=env_config)
278+
return self._create_auto_tokenizer_with_name(
279+
model_name=config.pretrained,
280+
revision=config.revision,
281+
env_config=env_config,
282+
tokenizer_name=config.tokenizer,
283+
subfolder=config.subfolder,
284+
trust_remote_code=config.trust_remote_code,
285+
)
211286

212287
def _create_auto_tokenizer_with_name(
213-
self, model_name: str, config: BaseModelConfig, env_config: EnvConfig
288+
self,
289+
model_name: str,
290+
revision: str,
291+
env_config: EnvConfig,
292+
tokenizer_name: str = None,
293+
subfolder: str = None,
294+
trust_remote_code: bool = False,
214295
) -> transformers.PreTrainedTokenizer:
215296
"""
216297
Create a Hugging Face AutoTokenizer for language model.
@@ -231,25 +312,35 @@ def _create_auto_tokenizer_with_name(
231312
"""
232313
try:
233314
tokenizer = AutoTokenizer.from_pretrained(
234-
model_name if config.tokenizer is None else config.tokenizer,
235-
revision=config.revision + (f"/{config.subfolder}" if config.subfolder is not None else ""),
315+
model_name if tokenizer_name is None else tokenizer_name,
316+
revision=revision + (f"/{subfolder}" if subfolder is not None else ""),
236317
cache_dir=env_config.cache_dir,
237318
token=env_config.token,
238-
trust_remote_code=config.trust_remote_code,
319+
trust_remote_code=trust_remote_code,
239320
padding_side="left",
240321
truncation_side="left",
241322
)
242323
except RecursionError:
243324
tokenizer = AutoTokenizer.from_pretrained(
244-
model_name if config.tokenizer is None else config.tokenizer,
245-
revision=config.revision + (f"/{config.subfolder}" if config.subfolder is not None else ""),
325+
model_name if tokenizer_name is None else tokenizer_name,
326+
revision=revision + (f"/{subfolder}" if subfolder is not None else ""),
246327
cache_dir=env_config.cache_dir,
247328
token=env_config.token,
248-
trust_remote_code=config.trust_remote_code,
329+
trust_remote_code=trust_remote_code,
249330
unk_token="<unk>",
250331
padding_side="left",
251332
truncation_side="left",
252333
)
334+
except FileNotFoundError:
335+
hlog_warn("Problem when loading the tokenizer in the cache - discarding the provided cache path value.")
336+
tokenizer = AutoTokenizer.from_pretrained(
337+
model_name if tokenizer_name is None else tokenizer_name,
338+
revision=revision + (f"/{subfolder}" if subfolder is not None else ""),
339+
token=env_config.token,
340+
trust_remote_code=trust_remote_code,
341+
padding_side="left",
342+
truncation_side="left",
343+
)
253344
tokenizer.pad_token = tokenizer.eos_token
254345
tokenizer.model_max_length = self.max_length
255346
hlog("Tokenizer truncation and padding size set to the left side.")

src/lighteval/pipeline.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from lighteval.logging.evaluation_tracker import EvaluationTracker
3535
from lighteval.logging.hierarchical_logger import hlog, htrack_block
3636
from lighteval.metrics.utils.metric_utils import MetricCategory
37-
from lighteval.models.model_loader import load_model
37+
from lighteval.models.model_loader import BaseModel, load_model
3838
from lighteval.models.model_output import ModelResponse
3939
from lighteval.tasks.lighteval_task import LightevalTask, create_requests_from_tasks
4040
from lighteval.tasks.registry import Registry, taskinfo_selector
@@ -164,7 +164,15 @@ def _init_model(self, model_config, model):
164164
)
165165
else:
166166
return load_model(config=model_config, env_config=self.pipeline_parameters.env_config)
167-
return model
167+
if isinstance(model, BaseModel):
168+
return model
169+
else:
170+
return BaseModel.from_model(
171+
model=model,
172+
use_chat_template=self.pipeline_parameters.use_chat_template,
173+
env_config=self.pipeline_parameters.env_config,
174+
accelerator=self.accelerator,
175+
)
168176

169177
def _init_tasks_and_requests(self, tasks: str):
170178
with htrack_block("Tasks loading"):

0 commit comments

Comments
 (0)