Automatically optimize transformer loglikelihood scoring - #142
Conversation
Qubitium
left a comment
There was a problem hiding this comment.
Reviewed together with QVQ #83. The ownership split is correct: Evalution should own the scorer/cache lifecycle and QVQ should only forward overrides. The one-token scoring math also looks exact for causal models: score each candidate from the final context-token logits and keep the divergent suffix path on a copied prefix cache.
I have two issues I would fix before merging because this is now default-on for transformer loglikelihood:
-
BLOCKER — batched prewarm row selection is not safe for sharded/device-mapped KV caches.
_select_loglikelihood_cache_row()createsindicesonself.input_deviceand passes that single tensor tocache.batch_select_indices(indices)(and uses it for legacyindex_select). HFCache.batch_select_indices()delegates the same index tensor to every cache layer. Withdevice_map/model sharding/offload, KV layers can live on cuda:0, cuda:1, CPU, etc., so an index tensor pinned to the input device is not valid for every cache tensor. The first multi-prefix prewarm can therefore raise on a large multi-GPU model and then disable the optimization for the session. The H200 single-GPU validation cannot exercise this. Please make row selection device-agnostic/per-layer (or fall back to unbatched prewarm when the cache is distributed) and add a unit test that exercises a cache whose rows are not all oninput_device. -
BLOCKER — do not treat every
RuntimeErroras a cache compatibility failure. Both_score_one_token_choice_prefix_cache()and_prewarm_loglikelihood_prefix_cache_for_batch()catchRuntimeError, disable the cache, and fall back. That also catchestorch.OutOfMemoryError, CUDA illegal-access/runtime failures, and unrelated model bugs. With a default-on optimization this can hide the real failure and immediately retry a larger uncached/full-context forward after an OOM. Restrict fallback to known cache-API incompatibilities (TypeError/AttributeError/NotImplementedError, or narrowly identified runtime compatibility errors) and re-raise OOM/CUDA/fatal runtime errors.
Non-blocking performance note: if one scoring batch has more eligible prefixes than loglikelihood_prefix_cache_max_entries, _prewarm_loglikelihood_prefix_cache_for_batch() prewarms all chunks before scoring; later chunks can evict earlier warm entries before they are consumed. Consider capping prewarm to retained capacity or interleaving prewarm+score by capacity-sized groups.
Otherwise the generic loglikelihood / loglikelihood_continuous finally cleanup and MMLU subject-contiguous lifecycle are the right direction.
|
Review follow-up complete.
Validation: |
Summary
Adds scorer-side prefix KV reuse for repeated one-token multiple-choice loglikelihood workloads (MMLU), while preserving the existing exact A/B/C/D grouping.
The scorer now:
Prefix caching and prewarming are enabled by default for transformer loglikelihood sessions; callers can still opt out with
loglikelihood_prefix_cache=Falseor--no-loglikelihood-prefix-cache-prewarm.H200 validation
Llama 3.2 1B QVQ checkpoint, MMLU humanities, 32 rows, batch size 128,
paged|sdpa:d966beeThis is 5.63x faster in the scoring phase with identical accuracy. The current run recorded one compulsory warmup miss followed by 1/1 steady-state scoring hits (100%).
The new H200 128-row lifecycle run (
0c74736) records 51.308 s of scoring and 89.916 s total, versus 51.416 s and 91.541 s for the same-head no-prewarm control. It achieved 5/5 steady-state hits, used 2 batched warmup forwards for 5 prefixes, and finished with 0 cache entries after 2 release calls (accuracy 0.2812).Commit
bd8ba27moves lifecycle release into the generic transformerloglikelihoodandloglikelihood_continuouspaths, so non-MMLU loglikelihood suites receive the same bounded cache and end-of-call cleanup automatically. MMLU retains subject-contiguous submission to release each subject's entries promptly.Review follow-ups
d13c302and3219460make batched cache-row extraction device-local per layer for sharded/offloaded caches, fall back to independent prefill for unknown cache wrappers, cap prewarm work to LRU capacity, remove dead helper code, and propagate OOM/illegal-access/fatal CUDA errors instead of hiding them behind an uncached retry.Tests
0.0.17, exactly one patch above the latest PyPI release (0.0.16); subsequent commits do not bump it.