Merge pull request #337 from borglab/feature/fast_hessian
Switched to in-place update of the diagonal Hessianrelease/4.3a0
commit
75ce6d60ef
|
@ -42,6 +42,9 @@
|
||||||
// Whether we are using TBB (if TBB was found and GTSAM_WITH_TBB is enabled in CMake)
|
// Whether we are using TBB (if TBB was found and GTSAM_WITH_TBB is enabled in CMake)
|
||||||
#cmakedefine GTSAM_USE_TBB
|
#cmakedefine GTSAM_USE_TBB
|
||||||
|
|
||||||
|
// Whether we are using a TBB version higher than 2020
|
||||||
|
#cmakedefine TBB_GREATER_EQUAL_2020
|
||||||
|
|
||||||
// Whether we are using system-Eigen or our own patched version
|
// Whether we are using system-Eigen or our own patched version
|
||||||
#cmakedefine GTSAM_USE_SYSTEM_EIGEN
|
#cmakedefine GTSAM_USE_SYSTEM_EIGEN
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
||||||
|
* Atlanta, Georgia 30332-0415
|
||||||
|
* All Rights Reserved
|
||||||
|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
||||||
|
|
||||||
|
* See LICENSE for the license information
|
||||||
|
|
||||||
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file GaussianFactor.cpp
|
||||||
|
* @brief A factor with a quadratic error function - a Gaussian
|
||||||
|
* @brief GaussianFactor
|
||||||
|
* @author Fan Jiang
|
||||||
|
*/
|
||||||
|
|
||||||
|
// \callgraph
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtsam/linear/GaussianFactor.h>
|
||||||
|
#include <gtsam/linear/VectorValues.h>
|
||||||
|
|
||||||
|
namespace gtsam {
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
VectorValues GaussianFactor::hessianDiagonal() const {
|
||||||
|
VectorValues d;
|
||||||
|
hessianDiagonalAdd(d);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -100,7 +100,10 @@ namespace gtsam {
|
||||||
virtual Matrix information() const = 0;
|
virtual Matrix information() const = 0;
|
||||||
|
|
||||||
/// Return the diagonal of the Hessian for this factor
|
/// Return the diagonal of the Hessian for this factor
|
||||||
virtual VectorValues hessianDiagonal() const = 0;
|
VectorValues hessianDiagonal() const;
|
||||||
|
|
||||||
|
/// Add the current diagonal to a VectorValues instance
|
||||||
|
virtual void hessianDiagonalAdd(VectorValues& d) const = 0;
|
||||||
|
|
||||||
/// Raw memory access version of hessianDiagonal
|
/// Raw memory access version of hessianDiagonal
|
||||||
virtual void hessianDiagonal(double* d) const = 0;
|
virtual void hessianDiagonal(double* d) const = 0;
|
||||||
|
|
|
@ -255,8 +255,7 @@ namespace gtsam {
|
||||||
VectorValues d;
|
VectorValues d;
|
||||||
for (const sharedFactor& factor : *this) {
|
for (const sharedFactor& factor : *this) {
|
||||||
if(factor){
|
if(factor){
|
||||||
VectorValues di = factor->hessianDiagonal();
|
factor->hessianDiagonalAdd(d);
|
||||||
d.addInPlace_(di);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
|
|
|
@ -302,12 +302,14 @@ Matrix HessianFactor::information() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
VectorValues HessianFactor::hessianDiagonal() const {
|
void HessianFactor::hessianDiagonalAdd(VectorValues &d) const {
|
||||||
VectorValues d;
|
|
||||||
for (DenseIndex j = 0; j < (DenseIndex)size(); ++j) {
|
for (DenseIndex j = 0; j < (DenseIndex)size(); ++j) {
|
||||||
d.emplace(keys_[j], info_.diagonal(j));
|
auto result = d.emplace(keys_[j], info_.diagonal(j));
|
||||||
|
if(!result.second) {
|
||||||
|
// if emplace fails, it returns an iterator to the existing element, which we add to:
|
||||||
|
result.first->second += info_.diagonal(j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
@ -293,8 +293,11 @@ namespace gtsam {
|
||||||
*/
|
*/
|
||||||
Matrix information() const override;
|
Matrix information() const override;
|
||||||
|
|
||||||
/// Return the diagonal of the Hessian for this factor
|
/// Add the current diagonal to a VectorValues instance
|
||||||
VectorValues hessianDiagonal() const override;
|
void hessianDiagonalAdd(VectorValues& d) const override;
|
||||||
|
|
||||||
|
/// Using the base method
|
||||||
|
using Base::hessianDiagonal;
|
||||||
|
|
||||||
/// Raw memory access version of hessianDiagonal
|
/// Raw memory access version of hessianDiagonal
|
||||||
void hessianDiagonal(double* d) const override;
|
void hessianDiagonal(double* d) const override;
|
||||||
|
|
|
@ -542,21 +542,31 @@ Matrix JacobianFactor::information() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
VectorValues JacobianFactor::hessianDiagonal() const {
|
void JacobianFactor::hessianDiagonalAdd(VectorValues& d) const {
|
||||||
VectorValues d;
|
|
||||||
for (size_t pos = 0; pos < size(); ++pos) {
|
for (size_t pos = 0; pos < size(); ++pos) {
|
||||||
Key j = keys_[pos];
|
Key j = keys_[pos];
|
||||||
size_t nj = Ab_(pos).cols();
|
size_t nj = Ab_(pos).cols();
|
||||||
Vector dj(nj);
|
auto result = d.emplace(j, nj);
|
||||||
|
|
||||||
|
Vector& dj = result.first->second;
|
||||||
|
|
||||||
for (size_t k = 0; k < nj; ++k) {
|
for (size_t k = 0; k < nj; ++k) {
|
||||||
Vector column_k = Ab_(pos).col(k);
|
Eigen::Ref<const Vector> column_k = Ab_(pos).col(k);
|
||||||
if (model_)
|
if (model_) {
|
||||||
model_->whitenInPlace(column_k);
|
Vector column_k_copy = column_k;
|
||||||
dj(k) = dot(column_k, column_k);
|
model_->whitenInPlace(column_k_copy);
|
||||||
|
if(!result.second)
|
||||||
|
dj(k) += dot(column_k_copy, column_k_copy);
|
||||||
|
else
|
||||||
|
dj(k) = dot(column_k_copy, column_k_copy);
|
||||||
|
} else {
|
||||||
|
if (!result.second)
|
||||||
|
dj(k) += dot(column_k, column_k);
|
||||||
|
else
|
||||||
|
dj(k) = dot(column_k, column_k);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d.emplace(j, dj);
|
|
||||||
}
|
}
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
|
@ -215,8 +215,11 @@ namespace gtsam {
|
||||||
*/
|
*/
|
||||||
Matrix information() const override;
|
Matrix information() const override;
|
||||||
|
|
||||||
/// Return the diagonal of the Hessian for this factor
|
/// Using the base method
|
||||||
VectorValues hessianDiagonal() const override;
|
using Base::hessianDiagonal;
|
||||||
|
|
||||||
|
/// Add the current diagonal to a VectorValues instance
|
||||||
|
void hessianDiagonalAdd(VectorValues& d) const override;
|
||||||
|
|
||||||
/// Raw memory access version of hessianDiagonal
|
/// Raw memory access version of hessianDiagonal
|
||||||
void hessianDiagonal(double* d) const override;
|
void hessianDiagonal(double* d) const override;
|
||||||
|
|
|
@ -102,10 +102,8 @@ public:
|
||||||
DMap(y + D * keys_[pos]) += Ab_(pos).transpose() * Ax;
|
DMap(y + D * keys_[pos]) += Ab_(pos).transpose() * Ax;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expose base class hessianDiagonal
|
/// Using the base method
|
||||||
virtual VectorValues hessianDiagonal() const {
|
using GaussianFactor::hessianDiagonal;
|
||||||
return JacobianFactor::hessianDiagonal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Raw memory access version of hessianDiagonal
|
/// Raw memory access version of hessianDiagonal
|
||||||
void hessianDiagonal(double* d) const {
|
void hessianDiagonal(double* d) const {
|
||||||
|
|
|
@ -96,20 +96,6 @@ namespace gtsam {
|
||||||
return result.first;
|
return result.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
|
||||||
VectorValues::iterator VectorValues::emplace(Key j, const Vector& value) {
|
|
||||||
#ifdef TBB_GREATER_EQUAL_2020
|
|
||||||
std::pair<iterator, bool> result = values_.emplace(j, value);
|
|
||||||
#else
|
|
||||||
std::pair<iterator, bool> result = values_.insert(std::make_pair(j, value));
|
|
||||||
#endif
|
|
||||||
if(!result.second)
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Requested to emplace variable '" + DefaultKeyFormatter(j)
|
|
||||||
+ "' already in this VectorValues.");
|
|
||||||
return result.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
void VectorValues::update(const VectorValues& values)
|
void VectorValues::update(const VectorValues& values)
|
||||||
{
|
{
|
||||||
|
|
|
@ -179,7 +179,14 @@ namespace gtsam {
|
||||||
* j is already used.
|
* j is already used.
|
||||||
* @param value The vector to be inserted.
|
* @param value The vector to be inserted.
|
||||||
* @param j The index with which the value will be associated. */
|
* @param j The index with which the value will be associated. */
|
||||||
iterator emplace(Key j, const Vector& value);
|
template<class... Args>
|
||||||
|
inline std::pair<VectorValues::iterator, bool> emplace(Key j, Args&&... args) {
|
||||||
|
#if ! defined(GTSAM_USE_TBB) || defined (TBB_GREATER_EQUAL_2020)
|
||||||
|
return values_.emplace(std::piecewise_construct, std::forward_as_tuple(j), std::forward_as_tuple(args...));
|
||||||
|
#else
|
||||||
|
return values_.insert(std::make_pair(j, Vector(std::forward<Args>(args)...)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c
|
/** Insert a vector \c value with key \c j. Throws an invalid_argument exception if the key \c
|
||||||
* j is already used.
|
* j is already used.
|
||||||
|
@ -197,7 +204,7 @@ namespace gtsam {
|
||||||
* and an iterator to the existing value is returned, along with 'false'. If the value did not
|
* and an iterator to the existing value is returned, along with 'false'. If the value did not
|
||||||
* exist, it is inserted and an iterator pointing to the new element, along with 'true', is
|
* exist, it is inserted and an iterator pointing to the new element, along with 'true', is
|
||||||
* returned. */
|
* returned. */
|
||||||
std::pair<iterator, bool> tryInsert(Key j, const Vector& value) {
|
inline std::pair<iterator, bool> tryInsert(Key j, const Vector& value) {
|
||||||
#ifdef TBB_GREATER_EQUAL_2020
|
#ifdef TBB_GREATER_EQUAL_2020
|
||||||
return values_.emplace(j, value);
|
return values_.emplace(j, value);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -98,8 +98,13 @@ namespace gtsam
|
||||||
// Insert solution into a VectorValues
|
// Insert solution into a VectorValues
|
||||||
DenseIndex vectorPosition = 0;
|
DenseIndex vectorPosition = 0;
|
||||||
for(GaussianConditional::const_iterator frontal = c.beginFrontals(); frontal != c.endFrontals(); ++frontal) {
|
for(GaussianConditional::const_iterator frontal = c.beginFrontals(); frontal != c.endFrontals(); ++frontal) {
|
||||||
VectorValues::const_iterator r =
|
auto result = collectedResult.emplace(*frontal, solution.segment(vectorPosition, c.getDim(frontal)));
|
||||||
collectedResult.emplace(*frontal, solution.segment(vectorPosition, c.getDim(frontal)));
|
if(!result.second)
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Internal error while optimizing clique. Trying to insert key '" + DefaultKeyFormatter(*frontal)
|
||||||
|
+ "' that exists.");
|
||||||
|
|
||||||
|
VectorValues::const_iterator r = result.first;
|
||||||
myData.cliqueResults.emplace(r->first, r);
|
myData.cliqueResults.emplace(r->first, r);
|
||||||
vectorPosition += c.getDim(frontal);
|
vectorPosition += c.getDim(frontal);
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,11 +141,12 @@ public:
|
||||||
return augmented.block(0, 0, M, M);
|
return augmented.block(0, 0, M, M);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the diagonal of the Hessian for this factor
|
/// Using the base method
|
||||||
virtual VectorValues hessianDiagonal() const {
|
using GaussianFactor::hessianDiagonal;
|
||||||
// diag(Hessian) = diag(F' * (I - E * PointCov * E') * F);
|
|
||||||
VectorValues d;
|
|
||||||
|
|
||||||
|
/// Add the diagonal of the Hessian for this factor to existing VectorValues
|
||||||
|
virtual void hessianDiagonalAdd(VectorValues &d) const override {
|
||||||
|
// diag(Hessian) = diag(F' * (I - E * PointCov * E') * F);
|
||||||
for (size_t k = 0; k < size(); ++k) { // for each camera
|
for (size_t k = 0; k < size(); ++k) { // for each camera
|
||||||
Key j = keys_[k];
|
Key j = keys_[k];
|
||||||
|
|
||||||
|
@ -153,7 +154,7 @@ public:
|
||||||
// D x 3 = (D x ZDim) * (ZDim x 3)
|
// D x 3 = (D x ZDim) * (ZDim x 3)
|
||||||
const MatrixZD& Fj = FBlocks_[k];
|
const MatrixZD& Fj = FBlocks_[k];
|
||||||
Eigen::Matrix<double, D, 3> FtE = Fj.transpose()
|
Eigen::Matrix<double, D, 3> FtE = Fj.transpose()
|
||||||
* E_.block<ZDim, 3>(ZDim * k, 0);
|
* E_.block<ZDim, 3>(ZDim * k, 0);
|
||||||
|
|
||||||
Eigen::Matrix<double, D, 1> dj;
|
Eigen::Matrix<double, D, 1> dj;
|
||||||
for (int k = 0; k < D; ++k) { // for each diagonal element of the camera hessian
|
for (int k = 0; k < D; ++k) { // for each diagonal element of the camera hessian
|
||||||
|
@ -163,9 +164,12 @@ public:
|
||||||
// (1 x 1) = (1 x 3) * (3 * 3) * (3 x 1)
|
// (1 x 1) = (1 x 3) * (3 * 3) * (3 x 1)
|
||||||
dj(k) -= FtE.row(k) * PointCovariance_ * FtE.row(k).transpose();
|
dj(k) -= FtE.row(k) * PointCovariance_ * FtE.row(k).transpose();
|
||||||
}
|
}
|
||||||
d.insert(j, dj);
|
|
||||||
|
auto result = d.emplace(j, dj);
|
||||||
|
if(!result.second) {
|
||||||
|
result.first->second += dj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue