Skip to content

Commit 6da982b

Browse files
authored
Fix input validation issues and update multiple-choice options handling (microsoft#2501)
This pull request introduces improvements to the handling of multiple-choice questions and options extraction in the data preprocessing and evaluation pipeline, as well as a minor enhancement to ONNX model input handling. The main changes include switching from numeric to letter-based multiple-choice options, extracting the selected letter during evaluation, and supporting an additional input name in ONNX graph surgeries. **Multiple-choice options handling:** * Updated `pre_process_data.py` to format multiple-choice options using letters (A, B, C, ...) instead of numbers, and added a new field `extract_option_letter` to indicate when letter extraction is needed. [[1]](diffhunk://#diff-df8a7d990b3be7d29f4b7a919903dc72b9e8ff15d13d9282639a3e281bc3f23aR481-R490) [[2]](diffhunk://#diff-df8a7d990b3be7d29f4b7a919903dc72b9e8ff15d13d9282639a3e281bc3f23aR510) * Modified `olive_evaluator.py` to extract the selected letter from model responses for multiple-choice questions, in addition to the previous digit extraction. This ensures compatibility with the new letter-based formatting. [[1]](diffhunk://#diff-816af95cf16e31610395bb20947f1d73cc1ca67355964e074a8f55375c8139a7R884) [[2]](diffhunk://#diff-816af95cf16e31610395bb20947f1d73cc1ca67355964e074a8f55375c8139a7L940-R943) [[3]](diffhunk://#diff-816af95cf16e31610395bb20947f1d73cc1ca67355964e074a8f55375c8139a7R956-R959) **ONNX model input handling:** * Enhanced the `TieWordEmbeddings` class in `graph_surgeries.py` to support both `input_embeds` and `inputs_embeds` as valid input names, improving compatibility with different model variants.
1 parent 120972c commit 6da982b

3 files changed

Lines changed: 18 additions & 7 deletions

File tree

olive/data/component/pre_process_data.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,11 +478,16 @@ def __getitem__(self, idx):
478478
# Use 1-based numbering (1, 2, 3, 4) which aligns with how VLMs are
479479
# typically prompted and avoids confusion with diagram region labels.
480480
num_choices = 0
481+
has_options = False
481482
if self.options_column and self.options_column in item:
482483
options = item[self.options_column]
483-
if isinstance(options, (list, tuple)) and len(options) > 0:
484+
if isinstance(options, (list, tuple)):
485+
has_options = True
484486
num_choices = len(options)
485-
options_text = "\n".join(f"{i + 1}. {opt}" for i, opt in enumerate(options))
487+
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
488+
options_text = "\n".join(
489+
f"{letters[i] if i < len(letters) else str(i)}. {opt}" for i, opt in enumerate(options)
490+
)
486491
question = f"{question}\n{options_text}"
487492

488493
# Handle list/tuple answers (some datasets have multiple valid answers)
@@ -502,6 +507,7 @@ def __getitem__(self, idx):
502507
"image": image,
503508
"question": question,
504509
"system_prompt": self.system_prompt,
510+
"extract_option_letter": has_options,
505511
"num_choices": num_choices,
506512
"max_length": self.max_length,
507513
}

olive/evaluator/olive_evaluator.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ def _inference_vision_genai(
881881
pil_image = item.get("image")
882882
question = item.get("question", "")
883883
sys_prompt = item.get("system_prompt", "")
884+
extract_option_letter = item.get("extract_option_letter", False)
884885
num_choices = item.get("num_choices", 0)
885886
max_length = item.get("max_length", default_max_length)
886887

@@ -937,9 +938,9 @@ def _inference_vision_genai(
937938

938939
sample_idx += 1
939940

940-
# For multiple-choice tasks, extract the answer digit from responses
941-
# like "2", "The answer is 3", or "1. D" to match the expected answer format.
942-
# Only enabled when num_choices is between 1 and 9 (single-digit options).
941+
# For multiple-choice tasks, extract the answer from responses.
942+
# First try digit extraction (for 1-based numbered options),
943+
# then fall back to letter extraction (for A/B/C/D options).
943944
if 1 <= num_choices <= 9 and pred:
944945
pattern = rf"\b([1-{num_choices}])\b"
945946
num_match = re.search(pattern, pred)
@@ -952,6 +953,10 @@ def _inference_vision_genai(
952953
if ch in valid_digits:
953954
pred = ch
954955
break
956+
elif extract_option_letter and pred:
957+
letter_match = re.search(r"\b([A-Z])\b", pred)
958+
if letter_match:
959+
pred = letter_match.group(1)
955960
all_preds.append(pred)
956961

957962
# Collect reference texts (aligned with preds including empty ones for None images)

olive/passes/onnx/graph_surgeries.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,9 +2151,9 @@ class TieWordEmbeddings(ProtoSurgeon):
21512151
def __call__(self, model: onnx.ModelProto):
21522152
dag = OnnxDAG(model)
21532153

2154-
# support both "input_ids" and "input_embeds" as input names
2154+
# support both "input_ids" and "input_embeds"/"inputs_embeds" as input names
21552155
input_name = None
2156-
for candidate in ("input_ids", "input_embeds"):
2156+
for candidate in ("input_ids", "input_embeds", "inputs_embeds"):
21572157
if candidate in dag.ios and dag.is_input(candidate):
21582158
input_name = candidate
21592159
break

0 commit comments

Comments
 (0)