Skip to content

Commit da8466b

Browse files
cpcdoyNathanHB
andauthored
Fix TGI (Text Generation Inference) Endpoint Inference and TGI JSON Grammar Generation (#502)
* fix: Lighteval communication with TGI * fix: JSON grammar constrained generation * fix: unit tests + add: dep in extra * fix: request var => doc var after refactor * fix: update test to support the new grammar field * fix: TGI endpoint with the new refactor * update: TGI model config in examples with the latest parameters * add: example custom task on a classification dataset to demonstrate the usage of constrained grammar generation using TGI * add: format example task * fix: unit test * add: adapt the in the yaml config to use similarly to the other endpoints * clean: moved new task to community_tasks * fix: format * clean: delete unused grammar field * del: grammar * add: copyright at the top * del: langcodes dep isn't needed anymore * add: use load from file directly in the main endpoint * del: newlines * add: mock HTTP request for info to TGI server --------- Co-authored-by: Nathan Habib <30601243+NathanHB@users.noreply.github.com>
1 parent 52d3d33 commit da8466b

10 files changed

Lines changed: 515 additions & 20 deletions

File tree

community_tasks/custom_task_classification_grammar_task.py

Lines changed: 456 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
model_parameters:
2-
inference_server_address: ""
2+
inference_server_address: "http://localhost:8080" # Replace with your actual TGI server address
33
inference_server_auth: null
44
model_name: null # Optional, only required if the TGI container was launched with model_id pointing to a local directory
5+
generation_parameters:
6+
temperature: 0.1

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ dependencies = [
8585
]
8686

8787
[project.optional-dependencies]
88-
litellm = ["litellm", "diskcache"]
89-
tgi = ["text-generation>=0.6.0"]
88+
litellm = ["litellm[caching]", "diskcache"]
89+
tgi = ["text-generation>=0.7.0"]
9090
optimum = ["optimum==1.12.0"]
9191
quantization = ["bitsandbytes>=0.41.0", "auto-gptq>=0.4.2"]
9292
adapters = ["peft==0.3.0"]

src/lighteval/main_endpoint.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,8 @@ def tgi(
249249
"""
250250
Evaluate models using TGI as backend.
251251
"""
252-
import yaml
253-
254252
from lighteval.logging.evaluation_tracker import EvaluationTracker
255253
from lighteval.models.endpoints.tgi_model import TGIModelConfig
256-
from lighteval.models.model_input import GenerationParameters
257254
from lighteval.pipeline import ParallelismManager, Pipeline, PipelineParameters
258255

259256
evaluation_tracker = EvaluationTracker(
@@ -269,11 +266,7 @@ def tgi(
269266

270267
parallelism_manager = ParallelismManager.TGI
271268

272-
with open(model_config_path, "r") as f:
273-
config = yaml.safe_load(f)
274-
275-
generation_parameters = GenerationParameters(**config.get("generation", {}))
276-
model_config = TGIModelConfig(**config["model"], generation_parameters=generation_parameters)
269+
model_config = TGIModelConfig.from_path(model_config_path)
277270

278271
pipeline_params = PipelineParameters(
279272
launcher_type=parallelism_manager,

src/lighteval/models/endpoints/endpoint_model.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ async def _async_process_batch_logprob(self, docs: list[Doc], rolling: bool = Fa
527527
context=context if rolling else context + doc.choices[0],
528528
stop_tokens=[],
529529
max_tokens=1,
530+
grammar=doc.generation_grammar,
530531
)
531532
for context, doc in zip(contexts, docs)
532533
]
@@ -539,6 +540,7 @@ def _process_batch_logprob(self, docs: list[Doc], rolling: bool = False) -> list
539540
context=context if rolling else context + doc.choices[0],
540541
stop_tokens=[],
541542
max_tokens=1,
543+
grammar=doc.generation_grammar,
542544
)
543545
for context, doc in zip(contexts, docs)
544546
]

src/lighteval/models/endpoints/tgi_model.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
from lighteval.models.abstract_model import ModelConfig
3232
from lighteval.models.endpoints.endpoint_model import InferenceEndpointModel
33+
from lighteval.tasks.prompt_manager import PromptManager
34+
from lighteval.utils.cache_management import SampleCache
3335
from lighteval.utils.imports import NO_TGI_ERROR_MSG, is_tgi_available
3436

3537

@@ -87,6 +89,7 @@ class TGIModelConfig(ModelConfig):
8789
inference_server_auth: str | None = None
8890
model_name: str | None
8991
model_info: dict | None = None
92+
batch_size: int = 1
9093

9194

9295
# inherit from InferenceEndpointModel instead of LightevalModel since they both use the same interface, and only overwrite
@@ -110,12 +113,23 @@ def __init__(self, config: TGIModelConfig) -> None:
110113
raise ValueError("Error occurred when fetching info: " + str(self.model_info))
111114
if config.model_name:
112115
self.model_info["model_id"] = config.model_name
116+
else:
117+
# Set the model_name in config to the actual model_id from server for caching
118+
config.model_name = self.model_info["model_id"]
113119
self.config = config
114120
self._tokenizer = AutoTokenizer.from_pretrained(self.model_info["model_id"])
115121
self._add_special_tokens = True
116122
self.use_async = True
117123
self.config.model_info = self.model_info
118124

125+
# Initialize prompt manager (required by parent class)
126+
self.prompt_manager = PromptManager(
127+
use_chat_template=True, tokenizer=self.tokenizer, system_prompt=config.system_prompt
128+
)
129+
130+
# Initialize cache for tokenization and predictions
131+
self._cache = SampleCache(config)
132+
119133
def _async_process_request(
120134
self,
121135
context: str,
@@ -134,7 +148,24 @@ def _async_process_request(
134148
grammar=grammar,
135149
)
136150

137-
generated_text = self.client.generate(prompt=context, generation_config=generation_config)
151+
generated_text = self.client.generate(
152+
prompt=context,
153+
do_sample=generation_config.do_sample or False,
154+
max_new_tokens=generation_config.max_new_tokens,
155+
best_of=generation_config.best_of,
156+
repetition_penalty=generation_config.repetition_penalty,
157+
return_full_text=generation_config.return_full_text or False,
158+
seed=generation_config.seed,
159+
stop_sequences=generation_config.stop,
160+
temperature=generation_config.temperature,
161+
top_k=generation_config.top_k,
162+
top_p=generation_config.top_p,
163+
truncate=generation_config.truncate,
164+
typical_p=generation_config.typical_p,
165+
watermark=generation_config.watermark or False,
166+
decoder_input_details=generation_config.decoder_input_details,
167+
grammar=generation_config.grammar,
168+
)
138169

139170
return generated_text
140171

src/lighteval/models/model_loader.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,7 @@ def load_model_with_tgi(config: TGIModelConfig):
109109
raise ImportError(NO_TGI_ERROR_MSG)
110110

111111
logger.info(f"Load model from inference server: {config.inference_server_address}")
112-
model = ModelClient(
113-
address=config.inference_server_address, auth_token=config.inference_server_auth, model_id=config.model_id
114-
)
112+
model = ModelClient(config=config)
115113
return model
116114

117115

src/lighteval/tasks/lighteval_task.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ def _get_docs_from_split(self, splits: list[str], few_shots=False) -> list[Doc]:
251251
item["__index"] = ix
252252
doc = self.formatter(item, self.name)
253253
doc.id = str(ix)
254+
255+
# Transfer task-level generation parameters to the document
256+
doc.generation_grammar = self.generation_grammar
257+
doc.generation_size = self.generation_size
258+
doc.stop_sequences = self.stop_sequence
259+
254260
docs.append(doc)
255261

256262
return docs

tests/models/endpoints/test_tgi_model.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ class TestTGIModelConfig:
3333
(
3434
"examples/model_configs/tgi_model.yaml",
3535
{
36-
"inference_server_address": "",
36+
"inference_server_address": "http://localhost:8080",
3737
"inference_server_auth": None,
3838
"model_name": None,
3939
"model_info": None,
4040
"system_prompt": None,
41+
"batch_size": 1,
4142
"generation_parameters": {
4243
"block_size": None,
4344
"num_blocks": None,
@@ -52,7 +53,7 @@ class TestTGIModelConfig:
5253
"repetition_penalty": None,
5354
"seed": None,
5455
"stop_tokens": None,
55-
"temperature": 0,
56+
"temperature": 0.1,
5657
"top_k": None,
5758
"top_p": None,
5859
"truncate_prompt": None,

tests/utils/test_caching.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,21 +219,27 @@ def test_cache_vllm(self, mock_create_model, mock_greedy_until, mock_loglikeliho
219219

220220
self._test_cache(model)
221221

222+
@patch("requests.get")
222223
@patch("lighteval.models.endpoints.tgi_model.ModelClient._greedy_until")
223224
@patch("lighteval.models.endpoints.tgi_model.ModelClient._loglikelihood")
224-
def test_cache_tgi(self, mock_greedy_until, mock_loglikelihood):
225+
def test_cache_tgi(self, mock_loglikelihood, mock_greedy_until, mock_requests_get):
225226
from lighteval.models.endpoints.tgi_model import ModelClient, TGIModelConfig
226227
from lighteval.utils.imports import is_tgi_available
227228

228229
if not is_tgi_available():
229230
pytest.skip("Skipping because missing the imports")
230231

231232
# Mock TGI requests
232-
mock_greedy_until.return_value = self.model_responses
233233
mock_loglikelihood.return_value = self.model_responses
234+
mock_greedy_until.return_value = self.model_responses
235+
236+
# Mock HTTP info request
237+
mock_requests_get.return_value.json.return_value = {"model_id": "Qwen/Qwen3-0.6B"}
234238

235239
with tempfile.TemporaryDirectory() as temp_dir:
236-
config = TGIModelConfig(model_name="Qwen/Qwen3-0.6B", cache_dir=temp_dir)
240+
config = TGIModelConfig(
241+
model_name="Qwen/Qwen3-0.6B", cache_dir=temp_dir, inference_server_address="http://localhost:8080"
242+
)
237243
model = ModelClient(config)
238244

239245
self._test_cache(model)

0 commit comments

Comments
 (0)