I have noticed posts on the forum regarding obtaining covariance values for solutions computed through Ceres. I'm also in this basket as I need to obtain marginal distributions of parameters solved by Ceres.
Unfortunately, obtaining the full covariance matrix will require inversion of the Hessian approximation JTJ. Some recent posts have inquired about obtaining the Jacobian at the solution, presumably in order to undertake the JTJ inversion operation outside Ceres. The new Evaluation feature (introduced in 1.5 I believe) is very useful in this regard, but it hits the auto-diff pipeline a second time after the solve, which can be undesirable at times. Furthermore, inverting JTJ for large problems might simply be too costly.
I have been looking into this issue and it seems there is an elegant solution to obtaining a subset of the covariance matrix without needing to calculate it in its entirety [1][2]. It seems to be only applicable to factored approaches, which are the Cholesky and QR solvers in Ceres. In both cases, a factor matrix R is internally calculated during the solve process.
____________________________Some analysis ahead, if you'd like to see the proposed implementation feel free to skip this sectionIn short, a particular column of the covariance matrix C, can be calculated by solving the following(1) RTR * C_i = e_iWhere R is the Cholesky or QR factor matrix, C_i is the covariance column of interest, and e_i is the i_th column of the identity matrix. This relation holds due since JTJ * C = I and RTR = JTJ.(1) can be solved using forward/backward substitution as in choldmod_solve(), and will produce the ith column of C. This can be useful for state estimation applications where we are only interested in the covariance columns of the latest state X. If X has a dimension of n, we require n solves to obtain the n covariance columns containing the variances of X along with the covariances with all other parameters. Note that X is not the solution state vector, but a small subset of it, corresponding to the parameters for which we are interested in obtaining covariances.If we are only interested in the variance of X, we can further optimize the calculation. In this case, we only need the nxn submatrix of C that contains the variances on its diagonal. If we place the parameters of X at the end of the state vector, due to the triangularity of R, there will only need to be n substitutions per column of covariance. This will require a total of n^2 substitutions to obtain the variances of X, which is a massive saving over inverting a potentially enormous JTJ, or solving for n full columns of C. The chomod_solve2() function already supports solving for a subset of the state vector, all that is needed for efficiency, is that this subset be at the end.
Implementation details:The proposed implementation would be to allow the user to "select" a particular parameter block for covariance extraction. Ceres would then place this parameter block at the end of the state vector when calculating the factors.
If presented as a feature, I believe this would greatly streamline the use of Ceres in state estimation and filtering applications, and would also obviate the need to calculate and manually manipulate the Jacobian/Hessian. However, my exposure to the Ceres codebase is limited as of yet, so I may have missed some major roadblocks to implementation.
--
--
----------------------------------------
Ceres Solver Google Group
http://groups.google.com/group/ceres-solver?hl=en?hl=en
---
You received this message because you are subscribed to the Google Groups "Ceres Solver" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceres-solver...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
Are you primarily interested in the block diagonals of the covariance matrix? or the off diagonal entries too?
How big if your jacobian? and how much time are you spending on evaluating it? If the jacobian evaluation is a performance bottleneck, I am quite curious to hear about it.
As for inverting all of J'J is not feasible, but I do not think you need to do that.is one way to only evaluate the entries that you need once you have the cholesky factorization. Part of the trick here would be to cache the symbolic factorization and re-use it across subsequent calls to the cholesky factorization routines.
This won't quite work. Since different linear solvers have differing ordering requirements. e.g., the schur complement based solvers which are used in slam as well as bundle adjustment
Before we go down the road of including this functionality in the main solver instead of a post processing as our plan is now, I would like to understand the performance bottleneck a bit better. Is it the Jacobian evaluation, the cholesky factorization or the inversion?
Could you tell us a bit more about your work load? size of problem, which part of the covariance matrix you are interested in etc.
I had not seen chomod-extra before. From what I gather, this still calculates the entire inverse, but exploits the sparsity structure that it finds in the factor. As you pointed out, it would be feasible to cache the factor matrix and re-use it later for specific solvers. I will look into how fast this runs. However, I don't see where I can specify the exact submatrix coordinates in chomod-extra. It seems to return the full inverse? However, the recursive algorithm in the reference can calculate any particular member of the inverse. I'm not sure whether this is faster than the substitution method or not.
Before we go down the road of including this functionality in the main solver instead of a post processing as our plan is now, I would like to understand the performance bottleneck a bit better. Is it the Jacobian evaluation, the cholesky factorization or the inversion?
I this this might change from application to application. For simple problems with large numbers of parameters, the inversion might dominate, in which case using the already-computed factor in the solver makes sense. In our application, due to the large number of parameters, I would guess that the factorization is the bottleneck in the optimization, as the Jacobians are relatively simple. However, due to the large number of parameters I would still be averse to re-evaluate the Jacobians in each iteration in order to computer variances.
Could you tell us a bit more about your work load? size of problem, which part of the covariance matrix you are interested in etc.The application is for a real time SLAM system. The parameter count varies depending on the number of landmarks tracked, but is more than 1000 parameters. The requirement is to obtain the variances for the current pose, which would be a 6x6 submatrix in the covariance matrix.
I might have a deeper look into chomod-extra in order to compare its performance to substitution-based methods. I think for our needs, both of these solutions would work quite well.
Thanks,Nima
I agree that it might not be worth caching the factorization matrix between solves. Just curious, which method are you going to use to get the covariance using colmod_solve2? Would you calculate it during the solve and pass it back via the problem structure? Or would it be calculated after the solve.
You expressed an interest in designating the covariance calculation to be outside the main solver. Do you think it would be possible to get access to the factor matrix for selected solvers? That way the user could opt to use it as they wish, or they could use potential Ceres functions which would use the factor to calculate sections of the covariance matrix. I'm not sure if this would work with all solvers in Ceres though.
What is the size/structure of your jacobian?What version of suitesparse are you using? If you are using something older than 4.2.0 can you upgrade and report back?
My suspicion is that its not the factorization but rather the inversion which is taking time. There are two ways of accelerating the inversion computation. One by doing a sparse solve, the other by threading. I now know how to do the latter, the former will require some indexing gymnastics that I need to figure out. But both of them are on my radar.
Is it possible for you to share an example problem/code that I can run and benchmark? Also when you say the solve time has doubled, how much actual wall time are we talking about?
What is the size/structure of your jacobian?What version of suitesparse are you using? If you are using something older than 4.2.0 can you upgrade and report back?We are at about 600 parameters and 5000 residuals. The structure is that of simple bundle adjustment problem with 3D poses and landmarks. It turns out I was using SuiteSparse 4 (as it is the version on macports) I will upgrade and report back
My suspicion is that its not the factorization but rather the inversion which is taking time. There are two ways of accelerating the inversion computation. One by doing a sparse solve, the other by threading. I now know how to do the latter, the former will require some indexing gymnastics that I need to figure out. But both of them are on my radar.By inversion do you mean the calls to cholmod_solve and cholmod_solve2 in cvariance_impl.cc? As I understand it, these should only be performing forward/backward substitution (which are order n^2), whereas the call to cholmod_factorize which produces the factor is order n^3.
Is it possible for you to share an example problem/code that I can run and benchmark? Also when you say the solve time has doubled, how much actual wall time are we talking about?I'll ask and see if it would be possible to share the code, although it's very tightly linked into a much larger project.I realized that I had made a mistake in my time calculation. The actual time for the solve (without covariance) is averaging at 17ms whereas the solve+covariance is averaging at 27ms. So the increased cost is a little less than what I previously mentioned. Sorry about that.