Ceres SolverはGoogleが開発した非線形最適化のためのC++ライブラリ。 使い方は本家サイトにもチュートリアルがあるし、サンプルコードもある。 でも、どれも単純すぎたり、難しすぎたり中途半端なので、 データが復数ある最小二乗法のサンプルコードを載せる。
\[ y=a x^2 \]この関数をフィッティングする場合、データとして$(x_i, y_i)\ (i=0,1,\cdots,n-1)$が与えれるので、 求めるパラメータは、$a$のみ。ここのデータの誤差を \[ e_i = y_i - a*x_i^2 \] とすると、単純な最小二乗法では、 \[ E=\sum_i e_i^2 \] が最小化される。 ここでは、データ$(x_i, y_i)$として次のファイル「data.txt」が与えられるとする。
0 0 1 1.2 2 3.9 -1 0.9 -2 4.1
サンプルコード
まず、ヘッダー部分は単純にceresのヘッダをインクルードすれば良い。 namespaceはライブラリのexamplesを真似して追加した。 OpenCVのヘッダはデータ入力に使うだけなので本来必要ない。
#include "ceres/ceres.h" #include "opencv2/opencv.hpp" using ceres::AutoDiffCostFunction; using ceres::CostFunction; using ceres::Problem; using ceres::Solver; using ceres::Solve;
次に、誤差関数の定義部分。 ErrorFunctionクラスのメンバ関数として定義する必要がある。 operator()関数をテンプレート関数として ここに書くのは$e_i$の部分だけ。 パラメータ$a$も残差$e_i$も配列で定義するみたい。 汎用性を考えてType型という抽象型になっているだけで今回はdoubleと思えば良い。
class ErrorFunction{ private: //1組のデータ const double x; const double y; public: //データを1つずつ入力する際このコンストラクタが呼ばれる。 ErrorFunction(double x, double y) : x(x), y(y) {} //e_iの定義。 template <typename Type> bool operator()(const Type* const a, Type* residual) const { //e_i = y_i - a*x_i*x_i residual[0] = Type(y) - a[0]*Type(x)*Type(x); return true; } };
誤差関数が定義できれば、あとはデータを与えて最適化するだけ。 データの入力は面倒なので 「cv::Mat_をテキストファイルに保存・読み込み 」 で紹介した方法を使う。
void main(int argc, char *argv[]){ //最適化するパラメータ。初期値を入力しておく。 double a = 0.0; //データの入力 cv::Mat_<double> data; readTxt("data.txt", data); //データの入力 Problem problem; for (int i = 0; i < data.rows; ++i) { //x_i,y_iを1つずつ入力する problem.AddResidualBlock( new AutoDiffCostFunction<ErrorFunction, 1, 1> ( //ここでデータを入れている new ErrorFunction(data(i, 0), data(i, 1)) ), NULL, //Loss function &a ); //std::cout << data(i, 0) << ' ' << data(i, 1) << std::endl; } //ソルバの準備 Solver::Options options; //CXSparseをインストールしていないときはDENSE_*にしないとエラーになる。 options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; //最適化 Solver::Summary summary; Solve(options, &problem, &summary); std::cout << "Fit complete: a: " << a << "\n"; return; }
参考
- 上記プログラムのVisual Studio2010用ソースコード
https://drive.google.com/file/d/0BzP0xs1TfzCxNVdTMDI0bkFSZ0k/edit?usp=sharing - 武相荘 Ceres Solverのコンパイル方法 on Windows
http://buaiso.blogspot.jp/2013/12/ceres-solver-on-windows.html - /var/log/vbkaisetsu 「非線形最小二乗法ソルバー「ceres-solver」を使ってみる」
http://vbkaisetsu.sky-air.net/wordpress/2012/05/非線形最小二乗法ソルバー「ceres-solver」を使ってみる/ - 武相荘 OpenCV ver.2 超々々入門(C++)
http://buaiso.blogspot.jp/2012/08/opencv2-c.html - 武相荘 cv::Mat_をテキストファイルに保存・読み込み
http://buaiso.blogspot.jp/2012/07/cvmat.html