feat: standardize logits in mot#1261
Conversation
|
cc @ajbozarth as it relates to your MOT redesign work |
ajbozarth
left a comment
There was a problem hiding this comment.
a couple follow up nits to my above comment
ajbozarth
left a comment
There was a problem hiding this comment.
Some feedback from Claude:
Main ask is to land the field on GenerationMetadata rather than as a top-level attr on ModelOutputThunk — per #909 and the #793 precedent, that's the standardized home for backend-execution metadata. The implementation logic (squeeze, clone-per-batch-item, cached vs. non-cached branches) looks correct; the rest of my comments are smaller items.
ajbozarth
left a comment
There was a problem hiding this comment.
LGTM, just a couple nits
ajbozarth
left a comment
There was a problem hiding this comment.
Some feedback from Claude.
ajbozarth
left a comment
There was a problem hiding this comment.
LGTM, I confirmed all of my comments were addressed in addition to @jakelorocco comments
| want_scores = bool( | ||
| model_options.get(ModelOption.LOGITS) | ||
| or model_options.get(ModelOption.RAW_LOGITS) | ||
| ) | ||
| if model_options.get(ModelOption.LOGITS): | ||
| generate_input["output_scores"] = True | ||
| if model_options.get(ModelOption.RAW_LOGITS): | ||
| generate_input["output_logits"] = True | ||
|
|
||
| # When logits are requested, intercept the raw GenerateDecoderOnlyOutput that | ||
| # generate_with_transformers produces internally but never returns (it wraps | ||
| # everything into a ChatCompletionResponse). We proxy self._model so that | ||
| # .generate() stores the raw output in raw_hf_output_cell before returning it; | ||
| # granite_formatters_processing then writes it to mot._meta["hf_output"] for | ||
| # _surface_logits in post_processing. | ||
| raw_hf_output_cell: list[GenerateDecoderOnlyOutput | None] = [None] | ||
|
|
||
| model_arg = self._model | ||
| if want_scores: | ||
| _real_model = self._model | ||
|
|
||
| # Two load-bearing assumptions: (1) __getattr__ falls through for attributes | ||
| # accessed by generate_with_transformers (model.device, model.vocab_size, | ||
| # model.generation_config). (2) chat_completion_request_to_transformers_inputs | ||
| # always sets return_dict_in_generate=True, so .generate() always returns a | ||
| # GenerateDecoderOnlyOutput — if that ever changes, the cell stays None and | ||
| # logits silently won't be populated. | ||
| class _CapturingModelProxy: | ||
| def generate(self_proxy, *args: Any, **kwargs: Any) -> Any: | ||
| result = cast(Callable[..., Any], _real_model.generate)( | ||
| *args, **kwargs | ||
| ) | ||
| if isinstance(result, GenerateDecoderOnlyOutput): | ||
| raw_hf_output_cell[0] = result | ||
| return result | ||
|
|
||
| def __getattr__(self_proxy, name: str) -> Any: | ||
| return getattr(_real_model, name) | ||
|
|
||
| model_arg = _CapturingModelProxy() # type: ignore[assignment] |
There was a problem hiding this comment.
Can you please confirm that you manually ran the intrinsic tests (minus the openai ones) to make sure this doesn't cause issues? If it does, I think we can just say it's not supported behavior for this code path. I didn't realize that supporting this for adapter components would cause this complexity.
There was a problem hiding this comment.
Yes I had manually run the intrinsics tests, and the only failures were also the same ones I had on main.
I just double checked main against my 4 previously troubled tests, which now have 3 passing and 1 xfail on main.
test_intrinsics_formatters.py::test_canned_input[context_relevance]
test_intrinsics_formatters.py::test_run_transformers[context_relevance_alora]
test_intrinsics_formatters.py::test_run_transformers[context-attribution]
test_intrinsics_formatters.py::test_run_transformers[uncertainty_alora]
After rebasing these all seem to mirror main now (all passing, 1 xfail).
I'll run against this again as well just to double check
uv run pytest test/formatters/granite/test_intrinsics_formatters.py test/formatters/granite/test_intrinsics_canned_output.py test/backends/test_adapters/ test/stdlib/components/intrinsic/ -m "not openai and not qualitative"
There was a problem hiding this comment.
The above all pass, will run a full suite again - would not be surprised if the rebase has introduced a few other issues.
| and (hf_output.past_key_values is not None or hf_output.scores is not None) | ||
| and ( | ||
| hf_output.past_key_values is not None | ||
| or hf_output.scores is not None | ||
| or hf_output.logits is not None | ||
| ) |
There was a problem hiding this comment.
I looked at this with fresh eyes. I don't think we want to cache things here if neither the kv_cache nor the scores are not None.
Would it be possible to separate out the caching logic from the logit surfacing logic? I know the cache handles deleting references from the hf_output object, but maybe this can be extracted as well?
There was a problem hiding this comment.
I think so, will take a stab at that.
There was a problem hiding this comment.
Does logits need to be added here as well? To be explicitly deleted? I don't think so but would like to confirm?
There was a problem hiding this comment.
If my understanding is correct it's not /necessary/ but I should probably add it anyway - after del mot.eta["hf_output"] garbage collection should clean it up (but I think this is also the case for the scores and sequences?).
jakelorocco
left a comment
There was a problem hiding this comment.
small issue with the rebase I think
| allowed_types = tuple(at.value for at in action.adapter_types) | ||
| adapter = self._find_adapter(action.intrinsic_name, allowed_types) | ||
| adapter = get_adapter_for_intrinsic( | ||
| action.intrinsic_name, action.adapter_types, self._added_adapters | ||
| ) |
There was a problem hiding this comment.
I think these lines were rebased incorrectly? main shows the allowed_types... version.
There was a problem hiding this comment.
Updated, re-ran intrinsics test locally 👍
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Co-authored-by: Alex Bozarth <ajbozart@us.ibm.com> Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Co-authored-by: Alex Bozarth <ajbozart@us.ibm.com> Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
Signed-off-by: AngeloDanducci <angelo.danducci.ii@ibm.com>
8c951a8
Pull Request
Issue
Fixes #123
Description
standardize logits in MOT
Testing
Attribution
Adding a new component, requirement, sampling strategy, or tool?
If your PR adds or modifies one of the types below, check the matching box. A checklist of type-specific review items will be posted as a comment.
NOTE: Please ensure you have an issue that has been acknowledged by a core contributor and routed you to open a pull request against this repository. Otherwise, please open an issue before continuing with this pull request.