Allow overriding past_present_share_buffer in LMEvaluator ortgenai backend#2569
Merged
Conversation
…ckend
The `ortgenai` lm-eval backend always derived `past_present_share_buffer`
from the exported `genai_config.json`, with no way to override it from a
recipe config. Some models (e.g. Gemma 4) export with shared buffers
enabled but require it disabled for correct KV-cache handling during
evaluation, forcing users to write a standalone eval script instead of a
declarative Olive config.
- `LMEvalORTGenAIEvaluator` now accepts an explicit `past_present_share_buffer`
argument that takes precedence over the exported value (extracted into a
small `_resolve_past_present_share_buffer` helper for testability).
- `LMEvaluator` gains a `model_args` dict that is forwarded verbatim to the
lm-eval model backend constructor, so genai-specific options can be set
from the evaluator config. User-provided `model_args` override the
Olive-derived defaults (batch_size, max_length, ep, ...).
This lets recipes evaluate such models with a standard `LMEvaluator` config,
e.g. `"model_args": {"past_present_share_buffer": false}`.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37949b3b-0064-4033-8d7a-8127271bcf39
Contributor
There was a problem hiding this comment.
Pull request overview
This PR enhances Olive’s LMEvaluator integration with lm-eval by allowing recipe configs to pass backend-specific constructor kwargs via a new model_args dict, and by enabling an explicit override of past_present_share_buffer for the ortgenai backend to address KV-cache correctness issues for certain exported models (e.g., Gemma 4).
Changes:
- Add
model_argssupport toLMEvaluator, forwarding kwargs to the selected lm-eval backend constructor with user values overriding Olive-derived defaults. - Add a
past_present_share_bufferoverride path toLMEvalORTGenAIEvaluator, with precedence over the exportedgenai_config.jsonvalue (and defaulting toFalsewhen absent). - Add unit tests covering the new resolution helper and the forwarding behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
olive/evaluator/olive_evaluator.py |
Introduces model_args forwarding into lm-eval backend construction. |
olive/evaluator/lmeval_ort.py |
Adds past_present_share_buffer override resolution for the ortgenai backend. |
test/evaluator/test_olive_evaluator.py |
Adds a test ensuring model_args reaches the backend constructor. |
test/evaluator/test_lmeval_ort.py |
Adds tests for _resolve_past_present_share_buffer precedence/default behavior. |
jiafatom
added a commit
to microsoft/olive-recipes
that referenced
this pull request
Jul 14, 2026
Add eval/mmlu_cpu.json and eval/mmlu_cuda.json that evaluate the exported
mixed ONNX model on leaderboard_mmlu_pro via Olive's LMEvaluator (ortgenai
backend). Gemma 4 exports with past_present_share_buffer enabled but the
decoder needs it disabled during eval, so the configs pass
"model_args": {"past_present_share_buffer": false} (requires microsoft/Olive#2569).
Document the new configs in eval/README.md and the top-level README.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37949b3b-0064-4033-8d7a-8127271bcf39
- Validate that model_args is a dict, failing early with a clear error instead of a confusing unpacking error later. - Use the effective batch size (after model_args overrides) for the lm-eval simple_evaluate call so backend batching and lm-eval batching stay consistent. - Assert simple_evaluate receives the overridden batch size, and add a test that a non-dict model_args is rejected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 37949b3b-0064-4033-8d7a-8127271bcf39
Contributor
Author
|
Thanks for the review! Addressed all three in 02d7818:
|
When sample_log_num > 0, LMEvaluator now enables lm-eval log_samples and writes the first N per-task predictions (question, options, resolved prediction, target, acc) to <task>_samples.jsonl, mirroring the accuracy evaluators' sample logging. This makes it possible to inspect why a task scores low. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 37949b3b-0064-4033-8d7a-8127271bcf39
Add # pylint: disable=protected-access to the tests that call the _extract_prediction / _save_lmeval_samples helpers directly, matching the existing pattern in this file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 37949b3b-0064-4033-8d7a-8127271bcf39
- Remove redundant function-local `import json` in test_olive_evaluator.py
(json is imported at module scope), fixing pylint W0621/W0404 that failed
the Python format lint job.
- Relax the dynamic-shapes tuning assertion to match torch.ones' message
across torch versions ("ones() received an invalid combination..." vs
"ones(): argument 'size' ... must be tuple of ints"), fixing the Linux/
Windows unit test failure.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 770571fd-fbfe-46d2-8c21-67c2941eede4
Decouple OliveEvaluator.save_sample_log to take (name, sample_log_dir) instead of a Metric, so LMEvaluator can reuse it. Replace _save_lmeval_samples with _lmeval_samples_to_output, which maps lm-eval sample records into an OliveModelOutput (question/options/prediction_index/acc carried via extras) fed to the shared writer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 770571fd-fbfe-46d2-8c21-67c2941eede4
Forward apply_chat_template, system_instruction, fewshot_as_multiturn and num_fewshot from the evaluator config to lm-eval's simple_evaluate. Instruction- tuned models (e.g. Gemma) score near-random on multiple-choice tasks when evaluated 0-shot without their chat template; these options let recipes match a model card's reported protocol. Defaults preserve lm-eval's legacy behavior, so existing configs are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 770571fd-fbfe-46d2-8c21-67c2941eede4
xiaoyu-work
approved these changes
Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Describe your changes
The
ortgenailm-eval backend (LMEvalORTGenAIEvaluator) always derivedpast_present_share_bufferfrom the exportedgenai_config.json, with no way to override it from a recipe/evaluator config. Some models (e.g. Gemma 4) export with shared past/present buffers enabled but require it disabled for correct KV-cache handling during evaluation. Additionally,LMEvaluatorgave recipe authors no way to enable a model's chat template or few-shot prompting, so instruction-tuned models were evaluated 0-shot on raw prompts and scored near-random. Today these gaps force recipe authors to bypassLMEvaluatorand write a standaloneeval.pythat callslm_eval.simple_evaluatedirectly — the declarative Olive config path simply produces wrong results for these models.This PR makes these settings overridable end-to-end and adds optional sample logging:
LMEvalORTGenAIEvaluatornow accepts an explicitpast_present_share_bufferargument that takes precedence over the exported value. The resolution logic is extracted into a small_resolve_past_present_share_buffer(override, genai_config)helper (explicit override wins; otherwise fall back to the exported value, defaulting toFalse).LMEvaluatorgains amodel_argsdict that is forwarded verbatim to the lm-eval model backend constructor, so genai-specific options can be set from the evaluator config. User-providedmodel_argsoverride the Olive-derived defaults (batch_size,max_length,ep, ...). Default is{}, so existing configs are unaffected.LMEvaluatorprompting controls: newapply_chat_template,system_instruction,fewshot_as_multiturnandnum_fewshotoptions, forwarded tolm_eval.simple_evaluate. Instruction-tuned models score near-random on multiple-choice tasks when evaluated 0-shot on raw prompts; wrapping requests in the model's chat template and matching the card's few-shot protocol fixes this. Empirically, on a Gemma-4 E2B export a German MMMLU subset went from ~0.16–0.24 (0-shot, no template) to ~0.52–0.68 (5-shot + chat template). Defaults preserve lm-eval's legacy behavior (no chat template, no system prompt, task-default few-shot), so existing configs are unaffected.LMEvaluatorsample logging: a newsample_log_num(and optionalsample_log_dir) option. Whensample_log_num > 0, lm-eval'slog_samplesis enabled and the first N per-task predictions — question, options, resolved prediction (argmax of choice loglikelihoods to letter + text, or the raw generation), target, andacc— are written to<task>_samples.jsonl. Rather than duplicating the writer,OliveEvaluator.save_sample_logis decoupled to take a(name, sample_log_dir)pair instead of aMetric, soLMEvaluatorreuses the exact same JSONL writer as the accuracy evaluators; a small_lmeval_samples_to_outputhelper maps lm-eval sample records into anOliveModelOutput(carrying question/options/prediction_index/acc viaextras). This makes it possible to inspect why a task scores low (e.g. distinguishing a genuinely weak/quantized model from a broken eval). Default is0, so existing configs are unaffected.With this, such models can be evaluated with a standard
LMEvaluatorconfig instead of a bespoke script:{ "evaluators": { "mmlu": { "type": "LMEvaluator", "tasks": ["mmlu"], "model_class": "ortgenai", "num_fewshot": 5, "apply_chat_template": true, "fewshot_as_multiturn": true, "sample_log_num": 100, "model_args": { "past_present_share_buffer": false } } } }Checklist before requesting a review
lintrunner -aRelease note:
LMEvaluatornow accepts amodel_argsdict forwarded to the lm-eval model backend;apply_chat_template,system_instruction,fewshot_as_multiturnandnum_fewshotprompting options forwarded tolm_eval.simple_evaluate(so instruction-tuned models can be evaluated with their chat template and the card's few-shot protocol); and asample_log_num/sample_log_diroption to log the first N per-task predictions vs. targets to a JSONL file for debugging (reusing the accuracy evaluators'save_sample_logwriter). Theortgenaibackend accepts an explicitpast_present_share_bufferoverride (previously only read fromgenai_config.json).(Optional) Issue link