Repository navigation
Some work on improving HMM engine performance - #7
Open
jeromekelleher wants to merge 2 commits into
Open
jeromekelleher wants to merge 2 commits into
jeromekelleher wants to merge 2 commits into
Conversation
Add late-stage tsinfer workloads (1000 Genomes chr20p ancestor groups 1483-1485 and sample matching) to the compression experiments, and measure the proposed delta and affine encodings on them. On these workloads a quarter to a third of the stored Viterbi entries were redundant: when edges change, nodes get explicit copies of their inherited values, and the engine stored the traceback before coalescing them away. That churn limited a delta encoding of the traceback to 1.1-1.7x. Viterbi now coalesces before storing the traceback, and no longer after. A node is removed only if its value and its recombination_required flag both equal the ones it inherits, so the traceback, in which unlisted nodes take the flag of their nearest listed ancestor, is unchanged. Nodes kept for their flag are removed at a later site. Forward and backward still coalesce after storing, on values only. What was tried: 1. Flag-aware coalescing before storing plus the old pass after: minimal lists, but two passes per site made tsls 1.36-1.48x tsinfer-hmm. 2. A single flag-aware pass before storing, with an uncached walk to the nearest listed ancestor: +2-4% instructions over the old engine. 3. As 2, with the inherited flag cached along tree paths alongside the inherited likelihood (recombination_required_cache): landed. It uses no more instructions than the old engine (callgrind: -0.2% on 20 group 1485 ancestors, -0.3% on one sample), and head-to-head wall times agree within noise. Results: the stored lists now equal the change points, Viterbi churn falls 5-8x, engine traceback entries fall 31-47%, and a delta encoding on top saves a further 5-8x. tsls still finds tsinfer's exact path on all benchmark queries. The compression experiments gain: - a tsinfer case in capture.py, with --cases and merged manifests; - churn, value change, flag change and affine residual measures in analysis.py; - an Encodings section and work plots in report.py. The README records the findings and the sequence of attempts.
tsls stores a smaller traceback than tsinfer-hmm but was still slower, because storing the traceback is under 1% of the time in both engines. Profiling both on the same 1000 Genomes chr20p queries (callgrind, limited to ancestor_matcher_find_path) showed tsls doing 1.26x (samples) to 1.49x (late ancestors) the instructions, mostly in the allele lookup and in building the first tree of each query. What was changed, and how it landed: 1. Allele lookup. tsinfer-hmm sets root 0 to the ancestral state, so its walk up the tree checks only for a set allele; tsls allows several roots and checked for the root at every step. tsls now sets every root's allele (roots are all in the likelihood list) before each site's update, and the Viterbi, forward and backward loops use get_marked_allelic_state. A first version kept an assert in the walk; because the Python module is built with asserts on, it cost as much as the check it replaced (12.71 G against 12.50 G instructions on one sample), so the walk has no assert. The traceback keeps get_allelic_state. 2. First-tree build. For Viterbi, init_sweep now builds the first tree with plain edge insertions and removals (ancestor_matcher_next_tree_topology), as tsinfer-hmm does, and no longer initialises num_below. Forward and backward, which track num_below, are unchanged. Instructions, tsinfer-hmm / tsls before / tsls after: 20 group 1485 ancestors 6.65 / 9.89 / 7.44 G; one sample 9.92 / 12.50 / 10.96 G. Paired wall times (best of 3, alternating engines per query), tsls over tsinfer-hmm: group 1485 ancestors 1.35 -> 1.10, samples 1.06 -> 1.06. Change 2 is the win; change 1 saves instructions but no time, because the walk is limited by memory access. run.py ratios proved unreliable for comparing engines, since it runs the engines in blocks and machine speed drifts; the README documents this and the paired method. Paths are unchanged: tsls still finds tsinfer's path on every query checked, and the tsls, C and benchmarking tests pass.
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.
No description provided.