Ceres solver ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ

์ด ๊ธ€์€ ์ž„ํ˜•ํƒœ๋‹˜์˜ helloceres git ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค


Ceres solver๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ์ผ์ด ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์„œ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ •๋ฆฌํ•˜๋ฉด์„œ ํฌ์ŠคํŒ…์ค‘์ด๋‹ค

Ceres๋Š” ์–ด๋–ค ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š”๊ฐ€?

๊ธฐ๋ณธ์ ์œผ๋กœ ๊ตฌ์† ์กฐ๊ฑด์ด ์žˆ๋Š” non-linear least square ๋ฌธ์ œ๋ฅผ ํ’€ ์ˆ˜ ์žˆ๋‹ค
ceres solver์— ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ณธ ์‹์˜ ๋ผˆ๋Œ€๋Š” ์•„๋ž˜ ์‚ฌ์ง„๊ณผ ๊ฐ™๋‹ค


Example code

// A simple example of using the Ceres minimizer.
//
// Minimize 0.5 (10 - x)^2 using jacobian matrix computed using
// automatic differentiation.

#include "ceres/ceres.h"
#include "glog/logging.h"

using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solver;
using ceres::Solve;

// A templated cost functor that implements the residual r = 10 -
// x. The method operator() is templated so that we can then use an
// automatic differentiation wrapper around it to generate its
// derivatives.
struct CostFunctor {
    template<typename T>
    bool operator()(const T *const x, T *residual) const {
        residual[0] = 10.0 - x[0];
        return true;
    }
};

int main(int argc, char** argv) {
  google::InitGoogleLogging(argv[0]);

  // The variable to solve for with its initial value.
  double initial_x = 5.0;
  double x = initial_x;

  // Build the problem.
  Problem problem;

  // Set up the only cost function (also known as residual). This uses
  // auto-differentiation to obtain the derivative (jacobian).
  CostFunction* cost_function =
      new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
  problem.AddResidualBlock(cost_function, nullptr, &x);

  // Run the solver!
  Solver::Options options;
  options.linear_solver_type = ceres::DENSE_QR;
  options.minimizer_progress_to_stdout = true;
  Solver::Summary summary;
  Solve(options, &problem, &summary);

  std::cout << summary.BriefReport() << "\n";
  std::cout << "x : " << initial_x
            << " -> " << x << "\n";
  return 0;
}

Break the code

CostFunctor

CostFunctor ๊ตฌ์กฐ์ฒด ์•ˆ์— residual์ด ์„ ์–ธ๋˜์–ด ์žˆ๋‹ค

struct CostFunctor {
    template<typename T>
    bool operator()(const T *const x, T *residual) const {
        residual[0] = 10.0 - x[0];
        return true;
    }
};

์ด๋ผ๊ณ  ์„ ์–ธํ•˜๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์ตœ์†Œํ™” ํ•ด์•ผํ•˜๋Š” ํ•จ์ˆ˜๋Š”
\(\frac{1}{2} *(10 \, - \, x)^2\) ์ธ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค

CostFunction/AutoDiffCostFunction

CostFunction* cost_function =
    new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
problem.AddResidualBlock(cost_function, nullptr, &x);

์œ„์˜ ์‹์—์„œ \(f\)์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค
cost function์„ ์–ด๋–ค ํ•จ์ˆ˜๋กœ ๊ฐ€์ ธ๊ฐˆ ์ง€ ์„ ์–ธํ•ด์ค€๋‹ค
์ด๋ฒˆ ์˜ˆ์ œ๋กœ๋Š” \(f=(10-x)^2\) ์ด ๋˜๊ฒ ๋‹ค

AutoDiffCostFunction์ด๋ž€ ๊ฑฐ ๋ณด๋‹ˆ ์ž๋™์œผ๋กœ ๋ฏธ๋ถ„ํ•ด์ฃผ๋Š”? ๊ทธ๋Ÿฐ ํ•จ์ˆ˜์ธ ๊ฑฐ ๊ฐ™์€๋ฐ CostFunctor๋ฅผ ์ธ์ž๋กœ ๊ฐ€์ ธ๊ฐ€๋Š” ๊ฑธ ๋ด์„œ ์ €๊ฑธ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๊นŒ์ง€๋Š” ์ดํ•ดํ–ˆ๋Š”๋ฐ, ๊ทธ ๋’ค์— ๋“ค์–ด๊ฐ€๋Š” ์ˆซ์ž ์ธ์ž์ž์ธ <Costfunctor, 1, 1> ๋ถ€๋ถ„์€ ์ข€ ๋” ์Šคํ„ฐ๋””๊ฐ€ ํ•„์š”ํ•˜๋‹ค

AddResidualBlock

problem.AddResidualBlock(cost_function, nullptr, &x);

์ธ์ž๊ฐ€ ๋„˜์–ด๊ฐ€๋Š” ํ˜•ํƒœ๋กœ ๋ณด์•„ ์œ„์—์„œ ์ •์˜ํ–ˆ๋˜ cost_function \(f\) ๋ฅผ ์ตœ์†Œํ™” ํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ \(x\)๋ฅผ ์ฐพ์•„์•ผ ํ•˜๋‹ˆ๊นŒ ๊ทธ๋Ÿฐ residual block ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ๋‹ค๋ผ๋Š” ๋œป ์ธ ๊ฑฐ ๊ฐ™๋‹ค!

Solver

solver๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์ „์— options๋ฅผ ๋จผ์ € ์„ ์–ธํ•ด์ฃผ๊ณ , solver์˜ option๋“ค์„ ๋„ฃ์–ด์ค€๋‹ค

Solver::Options options;
  options.linear_solver_type = ceres::DENSE_QR;
  options.minimizer_progress_to_stdout = true;
  Solver::Summary summary;
  Solve(options, &problem, &summary);

๋Š” ์ตœ์†Œํ™” ํ•˜๋Š” ๊ณผ์ •์„ ์ถœ๋ ฅํ•  ์ง€ ๋ง ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ถ”์ •๋œ๋‹ค.

Solver()ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ’€์–ด์ค€๋‹ค

  • ์šฐ๋ฆฌ๊ฐ€ residual block ํ•˜๋‚˜๋ฅผ ๋„ฃ์—ˆ๋˜ problem
  • ๋ฐฉ๊ธˆ ์ •์˜ํ•œ solver์˜ option
  • ์ตœ์†Œํ™” ๊ณผ์ •์„ ์š”์•ฝํ•œ summary ์ด ์„ธ ์ธ์ž๋ฅผ ๋„˜๊ฒจ์ฃผ๊ณ  ๋ฌธ์ œ๋ฅผ ํ’€ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค

๊ฒฐ๊ณผ

\(f=(10-x)^2\) ์ด์—ˆ์œผ๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” ์†์œผ๋กœ๋„ \(x=10\)์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๊ณ ,
ceres solver ๊ฒฐ๊ณผ๋„ ๋™์ผํ•จ์„ ํ™•์ธํ–ˆ๋‹ค

iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
   0  1.250000e+01    0.00e+00    5.00e+00   0.00e+00   0.00e+00  1.00e+04        0    4.98e-05    1.13e-04
   1  1.249750e-07    1.25e+01    5.00e-04   5.00e+00   1.00e+00  3.00e+04        1    7.61e-05    3.02e-04
   2  1.388518e-16    1.25e-07    1.67e-08   5.00e-04   1.00e+00  9.00e+04        1    1.79e-05    3.43e-04
Ceres Solver Report: Iterations: 3, Initial cost: 1.250000e+01, Final cost: 1.388518e-16, Termination: CONVERGENCE
x : 5 -> 10

์ตœ์†Œ์ž์Šน๋ฒ•์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ’€๊ธฐ ๋•Œ๋ฌธ์— iteration์ด ์—ฌ๋Ÿฌ๋ฒˆ ๋“ค์–ด๊ฐ€๋Š”๋ฐ, ์ด๋ฒˆ ์˜ˆ์ œ์—์„œ๋Š” 2๋ฒˆ ๋งŒ์— \(x=10\)์œผ๋กœ ์ˆ˜๋ ดํ•˜์˜€๋‹ค

Reference

Leave a comment