Another very significant speed-up of reverseAD pipeline, by template specialization of the leaf case for fixed matrices. Unfortunately, while this sped up reverse AD for our SFM kernel by 300%, reverseAD was only 6%, and is now 2% of total time. So, time to look elsewhere.

Oh, and, it is clear that the Identity matrix for Leaf only expressions is completely known at compile time: Eigen::Matrix<double, T::dimension, T::dimension>::Identity(). That should nicely speed up many a PriorFactor (replacement).
release/4.3a0
dellaert 2014-10-14 23:40:21 +02:00
parent 4894dccf5b
commit 625b939b66
1 changed files with 19 additions and 15 deletions

View File

@ -74,6 +74,22 @@ struct CallRecord {
}
};
//-----------------------------------------------------------------------------
/// Handle Leaf Case: reverseAD ends here, by writing a matrix into Jacobians
template<int ROWS, int COLS>
void handleLeafCase(const Eigen::Matrix<double,ROWS,COLS>& dTdA,
JacobianMap& jacobians, Key key) {
JacobianMap::iterator it = jacobians.find(key);
it->second.block<ROWS,COLS>(0,0) += dTdA; // block makes HUGE difference
}
/// Handle Leaf Case for Dynamic Matrix type (slower)
template<>
void handleLeafCase(const Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>& dTdA,
JacobianMap& jacobians, Key key) {
JacobianMap::iterator it = jacobians.find(key);
it->second += dTdA;
}
//-----------------------------------------------------------------------------
/**
* The ExecutionTrace class records a tree-structured expression's execution
@ -127,28 +143,16 @@ public:
return p ? boost::optional<Record*>(p) : boost::none;
}
}
/// reverseAD in case of Leaf
template<class Derived>
static void handleLeafCase(const Eigen::MatrixBase<Derived>& dTdA,
JacobianMap& jacobians, Key key) {
JacobianMap::iterator it = jacobians.find(key);
if (it == jacobians.end()) {
std::cout << "No block for key " << key << std::endl;
throw std::runtime_error("Reverse AD internal error");
}
// we have pre-loaded them with zeros
Eigen::Block<Matrix>& block = it->second;
block += dTdA;
}
/**
* *** This is the main entry point for reverseAD, called from Expression ***
* Called only once, either inserts I into Jacobians (Leaf) or starts AD (Function)
*/
typedef Eigen::Matrix<double, T::dimension, T::dimension> JacobianTT;
void startReverseAD(JacobianMap& jacobians) const {
if (kind == Leaf) {
// This branch will only be called on trivial Leaf expressions, i.e. Priors
size_t n = T::Dim();
handleLeafCase(Eigen::MatrixXd::Identity(n, n), jacobians, content.key);
static const JacobianTT I = JacobianTT::Identity();
handleLeafCase(I, jacobians, content.key);
} else if (kind == Function)
// This is the more typical entry point, starting the AD pipeline
// Inside the startReverseAD that the correctly dimensioned pipeline is chosen.