Improve the performance of DenseQRSolver

1. Reduce amount of reallocations.

Change-Id: I91b17c781ae94ed12014d647f0162cfce4f6ed7b
This commit is contained in:
Sameer Agarwal
2012-10-05 10:06:27 -07:00
parent ba8d967f8c
commit 5bfa7e4e8f
7 changed files with 55 additions and 21 deletions
+24 -9
View File
@@ -106,11 +106,6 @@ bool CoordinateDescentMinimizer::Init(
}
}
LinearSolver::Options linear_solver_options;
linear_solver_options.type = DENSE_QR;
linear_solver_.reset(LinearSolver::Create(linear_solver_options));
CHECK_NOTNULL(linear_solver_.get());
evaluator_options_.linear_solver_type = DENSE_QR;
evaluator_options_.num_eliminate_blocks = 0;
evaluator_options_.num_threads = 1;
@@ -129,6 +124,15 @@ void CoordinateDescentMinimizer::Minimize(
parameter_block->SetConstant();
}
scoped_array<LinearSolver*> linear_solvers(new LinearSolver*[options.num_threads]);
LinearSolver::Options linear_solver_options;
linear_solver_options.type = DENSE_QR;
for (int i = 0; i < options.num_threads; ++i) {
linear_solvers[i] = LinearSolver::Create(linear_solver_options);
}
for (int i = 0; i < independent_set_offsets_.size() - 1; ++i) {
// No point paying the price for an OpemMP call if the set if of
// size zero.
@@ -142,6 +146,11 @@ void CoordinateDescentMinimizer::Minimize(
for (int j = independent_set_offsets_[i];
j < independent_set_offsets_[i + 1];
++j) {
#ifdef CERES_USE_OPENMP
int thread_id = omp_get_thread_num();
#else
int thread_id = 0;
#endif
ParameterBlock* parameter_block = parameter_blocks_[j];
const int old_index = parameter_block->index();
@@ -164,6 +173,7 @@ void CoordinateDescentMinimizer::Minimize(
// we are fine.
Solver::Summary inner_summary;
Solve(&inner_program,
linear_solvers[thread_id],
parameters + parameter_block->state_offset(),
&inner_summary);
@@ -177,10 +187,15 @@ void CoordinateDescentMinimizer::Minimize(
for (int i = 0; i < parameter_blocks_.size(); ++i) {
parameter_blocks_[i]->SetVarying();
}
for (int i = 0; i < options.num_threads; ++i) {
delete linear_solvers[i];
}
}
// Solve the optimization problem for one parameter block.
void CoordinateDescentMinimizer::Solve(Program* program,
LinearSolver* linear_solver,
double* parameter,
Solver::Summary* summary) {
*summary = Solver::Summary();
@@ -196,11 +211,11 @@ void CoordinateDescentMinimizer::Solve(Program* program,
scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
CHECK_NOTNULL(jacobian.get());
TrustRegionStrategy::Options trust_region_strategy_options;
trust_region_strategy_options.linear_solver = linear_solver_.get();
TrustRegionStrategy::Options trs_options;
trs_options.linear_solver = linear_solver;
scoped_ptr<TrustRegionStrategy>trust_region_strategy(
TrustRegionStrategy::Create(trust_region_strategy_options));
CHECK_NOTNULL(trust_region_strategy.get());
CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
Minimizer::Options minimizer_options;
minimizer_options.evaluator = evaluator.get();
@@ -65,6 +65,7 @@ class CoordinateDescentMinimizer : public Minimizer {
private:
void Solve(Program* program,
LinearSolver* linear_solver,
double* parameters,
Solver::Summary* summary);
@@ -77,7 +78,6 @@ class CoordinateDescentMinimizer : public Minimizer {
vector<int> independent_set_offsets_;
Evaluator::Options evaluator_options_;
scoped_ptr<LinearSolver> linear_solver_;
};
} // namespace internal
+4 -3
View File
@@ -62,7 +62,8 @@ class DenseJacobianWriter {
SparseMatrix* CreateJacobian() const {
return new DenseSparseMatrix(program_->NumResiduals(),
program_->NumEffectiveParameters());
program_->NumEffectiveParameters(),
true);
}
void Write(int residual_id,
@@ -87,8 +88,8 @@ class DenseJacobianWriter {
continue;
}
int parameter_block_size = parameter_block->LocalSize();
MatrixRef parameter_jacobian(jacobians[j],
const int parameter_block_size = parameter_block->LocalSize();
ConstMatrixRef parameter_jacobian(jacobians[j],
num_residuals,
parameter_block_size);
+9 -6
View File
@@ -62,17 +62,20 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
}
// rhs = [b;0] to account for the additional rows in the lhs.
Vector rhs(num_rows + ((per_solve_options.D != NULL) ? num_cols : 0));
rhs.setZero();
rhs.head(num_rows) = ConstVectorRef(b, num_rows);
const int augmented_num_rows = num_rows + ((per_solve_options.D != NULL) ? num_cols : 0);
if (rhs_.rows() != augmented_num_rows) {
rhs_.resize(augmented_num_rows);
rhs_.setZero();
}
rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
// Solve the system.
VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs);
VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs_);
VLOG(3) << "A:\n" << A->matrix();
VLOG(3) << "x:\n" << VectorRef(x, num_cols);
VLOG(3) << "b:\n" << rhs;
VLOG(3) << "error: " << (A->matrix() * VectorRef(x, num_cols) - rhs).norm();
VLOG(3) << "b:\n" << rhs_;
VLOG(3) << "error: " << (A->matrix() * VectorRef(x, num_cols) - rhs_).norm();
if (per_solve_options.D != NULL) {
+2
View File
@@ -33,6 +33,7 @@
#define CERES_INTERNAL_DENSE_QR_SOLVER_H_
#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/macros.h"
namespace ceres {
@@ -90,6 +91,7 @@ class DenseQRSolver: public DenseSparseMatrixSolver {
double* x);
const LinearSolver::Options options_;
Vector rhs_;
CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
};
+12
View File
@@ -47,6 +47,18 @@ DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
m_.setZero();
}
DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal)
: has_diagonal_appended_(false),
has_diagonal_reserved_(reserve_diagonal) {
// Allocate enough space for the diagonal.
if (reserve_diagonal) {
m_.resize(num_rows + num_cols, num_cols);
} else {
m_.resize(num_rows, num_cols);
}
m_.setZero();
}
DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m)
: m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())),
has_diagonal_appended_(false),
+1
View File
@@ -57,6 +57,7 @@ class DenseSparseMatrix : public SparseMatrix {
#endif
DenseSparseMatrix(int num_rows, int num_cols);
DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
virtual ~DenseSparseMatrix() {}