Sparse Bayes - #1748
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1748 +/- ##
==========================================
+ Coverage 58.99% 61.37% +2.38%
==========================================
Files 282 291 +9
Lines 50466 51224 +758
==========================================
+ Hits 29773 31440 +1667
+ Misses 20693 19784 -909
🚀 New features to boost your workflow:
|
…isession and dense/sparse bayes in that settings)
…se for that case)
matlabbe
marked this pull request as ready for review
August 22, 2026 20:43
Member
Author
|
I compared with https://github.com/introlab/rtabmap/wiki/Benchmark#udes-1hz dataset using With this PR and Bayes/SparsePrediction = false (dense like original) With this PR and Bayes/SparsePrediction = true (new default) |
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.



TODO
Rtabmap/MemoryThr = 300(with optimized map regenerated afterwards with full graph and more loop closures). Another thing is to compare the expected loop closure hypotheses ID and value taken from the statistics recorded in the database, so that it is another way to know for sure that the new dense refactor didn't break the old approach.Bayes/SparsePredictionbenchmarkBayesFilter::computePosterior()with the prediction kept as a dense matrix (as before)against kept sparse, measured by
bin/test_bayesfilter_perfover synthetic graphs and overthe graphs of two real maps.
The sparse form is not only a different multiplication: the matrix is never allocated, it is
carried over to appended locations instead of being rebuilt, and the posterior is kept as
vectors rather than walked as a map.
How to read it
-O3 -DNDEBUG, GCC 9.4.0, OpenCV 4.2.0ctest -L performance, orbin/test_bayesfilter_perfcomputePosterior()call, not just the multiplicationBayesFilter::getMemoryUsed(): prediction, posterior, neighbourhoodsAbsolute times on this laptop move with the processor's sustained clock — the 4000 node
cases were seen to swing 2x between runs — so every figure below is the best of three runs,
and the ratios are steadier than the milliseconds.
Real maps, localization mode
The graph is fixed, so the prediction is generated once and every iteration after reuses it.
Both graphs are exports of real sessions, read with their link types.
Generating the prediction, paid once at the start of a session:
The reduced graph is the denser of the two despite having fewer closures per location: its
merged neighbour links carry a margin further per step. Which links the traversal follows
without spending a margin is what decides the fill, and so everything else.
Real map, incremental mapping
A location added, then an iteration, repeated: the case the prediction cannot be reused in.
Replayed over the last 15 locations of the session so the cost is measured at the size the
map actually reaches. 9032 locations.
x29 per added location, and the 311 MB matrix is never allocated. The 57.7 MB is mostly
the neighbourhood cache the incremental update needs, which localization does not keep.
Synthetic graphs, by size
Localization mode, default model, a loop closure every 100 locations.
The dense cost grows with the square of the number of locations while the sparse one grows
with the values the graph puts in the prediction, so the ratio grows with the map.
Synthetic graphs, by what decides the fill
4 000 locations. The model's length is the depth of the graph search
(
getNeighborsId(id, _predictionLC.size()-1, …)), and a closure costs no margin, so each onewidens what a column holds.
The dense column barely moves across all six: it reads every value of the matrix whether or
not there is anything in it.
Synthetic graph, mapping mode over a graph that stopped growing
4 000 locations. The prediction outlasts an iteration here, so the sparse form is reused;
DenseVsSparsePredictionWhileMappingARealSessionabove is the same mode with the graphstill growing.
Where the time goes now
One steady state iteration on the reduced graph, 18 values, from the filter's own log:
The iteration is the multiplication, at roughly 1 ns per stored value. The only lever left is
storing fewer values, which is the prediction model: 3.88% filled costs 8.75 ms, 0.46% costs
1.48 ms.
Correctness
The posteriors of the two modes differ by 1e-7 to 1e-4 relative to the largest probability,
which is the rounding of sums of a few thousand floats taken in a different order, compounded
over the iterations of a recursive filter. That the two put the same probabilities in the same
places is asserted separately, and exactly: with a posterior that is 1 on one location and 0
elsewhere every value of the prior is a single product, and the dense and sparse results are
then required to be equal float for float, for every column, in both localization and mapping.