機械学習を行う上で欠かせないのが行列演算ライブラリです。
pythonにnumpyがあるように、C++のデファクトスタンダードな行列計算ライブラリにEigenというものがあります。ヘッダのみのライブラリなのでプロジェクトに組み込みやすくSIMDとかも使って最適化してくれるので計算も速いです。
ここ最近でEigenを使った際に便利に感じた機能をまとめたいと思います。
Slicing and Indexing
v3.3.90から配列のSlicingとIndexingが便利に行えるようになりました。それまではblockAPIやhead/tail関数などを駆使していましたが、pythonのような要素指定が可能になりました。
以下にnumpyとEigenの要素指定方法の比較を載せました。
Eigen | numpy |
---|---|
A(seq(i,last), seqN(0,n)) |
A[i:, :n] |
A(seqN(i,m), seqN(i,n)) |
A[i:i+m, i:i+n] |
A(seq(i0,i1), seq(j0,j1)) |
A[i0:i1+1, j0:j0+1] |
A(all, seq(0,last,2)) |
A[:, ::2] |
A(last/2,all) |
A[(A.shape[0]-1)/2, :] |
v(lastN(n)) |
v[-n:] |
A(all, seq(20, 10, fix<-2>)) |
A[:, 20:9:-2] |
A(seqN(last, n, fix<-1>), all) |
A[:-n:-1, :] |
A(lastN(n).reverse(), all) |
A[:-n:-1, :] |
A(all,{4,2,5,5,3}) |
A[:, [4,2,5,5,3]] |
最近傍点を見つけるコードを1行で書く
ドキュメントにも載っているのですが、これが1行で書けるのに少し感動したので紹介します。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
Eigen::MatrixXf m(2,4);
Eigen::VectorXf v(2);
m << 1, 23, 6, 9,
3, 11, 7, 2;
v << 2,
3;
MatrixXf::Index index;
// find nearest neighbor
(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
cout << "Nearest neighbor is column " << index << ":" << endl;
cout << m.col(index) << endl;
}
該当の部分は(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
のところですが、行列m
の中からベクトルv
と最も近い列ベクトルのインデックスと距離を算出しています。
pybind11でpythonラッパにする
C++のコードのpythonラッパを作成するpybind11は標準でEigenとnumpyの変換を行ってくれます。
バインディングを行うコードでpybind11/eigen.h
をインクルードするだけで、EigenのMatrix型をnumpyのndarrayに変換してくれます。
プラグインで機能拡張
EigenのMatrixやその他の型にはユーザが新たに関数追加を行うためのプラグイン機能があります。
プラグインと言っても以下のようにMatrixBase型などの中にマクロが埋め込まれており、ユーザ側で追加機能が書かれたファイルをEIGEN_MATRIX_BASE_PLUGIN
として定義することでユーザが定義した関数や変数をクラスの中に追加することができます。
class MatrixBase {
// ...
#ifdef EIGEN_MATRIXBASE_PLUGIN
#include EIGEN_MATRIXBASE_PLUGIN
#endif
};
たとえばMatrixPlugin.h
の中身を以下のように記述します。
inline Scalar hoge() const { return this->operator()(0, 0); }
実際に使用するコードで、Eigenをインクルードする前に#define EIGEN_MATRIXBASE_PLUGIN "MatrixPlugin.h"
を記述することで、Matrixからhoge関数を呼ぶことが可能になります。
Unsupported modules
公式にEigenがサポートしていないモジュールですが、色々入ってます。
- Tensor(3次元以上の配列)の計算
- 非線形最適化
- オイラー角の計算
- 自動微分
- …
などなど。