mlpack是一个C++机器学习库,侧重于可扩展性、速度和易用性。它的目的是经过一个简单的、先后一致的API让新用户使用机器学习成为可能,同时利用C++语言特征为专家用户提供最好的性能和最大的灵活性。这些经过提供一系列命令行执行程序完成,就像使用一个黑箱,并且专家用户和研究者能够容易的更改一个模块化的C++ API的内部算法。html
这种方法的结果就是mlpack的性能大幅度超过其余竞争的机器学习库;在the BigLearning workshop paper 和the benchmarks for details查看细节。node
mlpack由全世界的贡献者开发。基于伯克利发行软件许可的第三个条款免费发行。(比1.0.12更老的版本基于GNU通用公共受权规定发行:LGPL,第3版。)算法
mlpack存储在许多Linux的发行版本中,因此在你的系统中使用程序包管理器可能更容易一些。例如:在Ubuntu上,你可使用下面的命令安装mlpack。windows
C++dom
1机器学习 |
$ sudo apt-get install libmlpack-devide |
若是mlpack不能在你的系统的程序包管理器中使用,那么你能够按照下面的步骤编译和安装mlpack源文件。模块化
Mlpack使用CMake做为生成系统,容许几个灵活的生成配置选项。你能够查询大量的CMake教程获得更多的文件,可是这个教程应该足够让你在大多数Linux和类UNIX系统中(包括OS X)成功生成和安装mlpack。若是你想在Windows操做系统中生成mlpack,请看这里。svn
首先下载mlpack。函数
当mlpack的源文件完成解压,你能够建立一个生成目录。
C++
1 2 |
$ cd mlpack-2.2.5 $ mkdir build |
这个目录能够是任何名字,不只仅是“build”,可是“build”足够了。
mlpack依赖下面的库,它们须要被安装在系统中并有一些头文件出现。
在Ununtu和Debian中,你能够经过apt得到全部这些依赖项:
C++
1 2 |
# apt-get install libboost-math-dev libboost-program-options-dev libboost-test-dev libboost-serialization-dev libarmadillo-dev binutils-dev |
在Fedora、Red Hat或CentOS上,这些相同的依赖项能够经过dnf得到:
C++
1 2 |
# dnf install boost-devel boost-test boost-program-options boost-math armadillo-devel binutils-devel |
运行CMake至关于使用autotools运行./configure。
若是你工做中使用mlpack的svn trunk版本,且不带任何选项运行CMake,它将配置这个生成项目带有调试符号和分析信息:若是你工做中使用发行版本的mlpack,不带任何选项运行CMake,它将配置这个生成项目不带调试符号和分析信息(为了速度)。
C++
1 2 |
$ cd build $ cmake ../ |
你能够手动指定选项去编译或不编译调试信息和分析信息(也就是说尽量快):
C++
1 2 |
$ cd build $ cmake -D DEBUG=OFF -D PROFILE=OFF ../ |
Mlpack容许的所有选项为:
每一个选项均可以被指定给带有‘-D’标记的CMake。其余工具也能够用于配置CMake,可是它们没有被记录在这里。
一旦CMake配置好,生成库就像打出‘make’同样简单。这将生成全部库组件和‘mlpack_test’。
C++
1 2 3 4 5 |
$ make Scanning dependencies of target mlpack [ 1%] Building CXX object src/mlpack/CMakeFiles/mlpack.dir/core/optimizers/aug_lagrangian/aug_lagrangian_test_functions.cpp.o <...> |
若是你不想生成每个库,能够指定你想生成的单个组件。
C++
1 |
$ make mlpack_pca mlpack_knn mlpack_kfn |
一个有趣的特殊组件是mlpack_test,它是运行mlpack的测试组件。你可使用这个命令生成这个组件:
C++
1 |
$ make mlpack_test |
而后运行全部的测试组件或单个的测试组件:
C++
1 2 |
$ bin/mlpack_test $ bin/mlpack_test -t KNNTest |
若是生成失败,而你不能找到为何失败,在Github上注册一个帐户,提交这个问题,mlpack的开发人员将会尽快帮你解决,
或者在irc.freenode.netm上的mlpack的IRC中也能够找到mlpack的帮助。
若是你想将mlpack安装在/usr/include/mlpack/、/usr/lib/和/usr/bin/中,当它生成后,确保你有root权限(或向那两个目录的写入许可),而后简单的打出:
C++
1 |
# make install |
如今你能够经过名字运行可执行程序;你可使用-lmlpack连接到mlpack,mlpack的头文件能够在目录/usr/include/mlpack/中找到。
最近邻搜索是一个常见的机器学习任务。在这个背景下 ,咱们有一个查询数据集和一个参考数据集。对于在查询数据集中的每一个点,咱们但愿知道参考数据集中距离给定查询点最近的k个点。
或者,若是查询和参考数据集是相同的,问题能够更简单的说明:对于每一个数据集中的点,咱们但愿知道距离那个点最近的k个点。
Mlpack提供:
在mlpack中完成最近邻搜索最简单的方式是使用mlpack_knn程序包。这个程序将完成最近邻搜索,并将获得的邻近点放入一个文件,同时将对应的距离放入另外一个文件。输出文件被整理为第一行对应第一个被查询点的最近邻点,第一列对应最近的点,以此类推。
下面是几个简单用法的例子(和输出结果)。因为使用了选项‘-v’,所以输出是给定的。更多关于每一个选项的文档能够经过下面这个语句找到。
C++
1 |
$ mlpack_knn –help |
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ mlpack_knn -r dataset.csv -n neighbors_out.csv -d distances_out.csv -k 5 -v [INFO ] Loading 'dataset.csv' as CSV data. Size is 3 x 1000. [INFO ] Loaded reference data from 'dataset.csv' (3 x 1000). [INFO ] Building reference tree... [INFO ] Tree built. [INFO ] Searching for 5 nearest neighbors with dual-tree kd-tree search... [INFO ] 18412 node combinations were scored. [INFO ] 54543 base cases were calculated. [INFO ] Search complete. [INFO ] Saving CSV data to 'neighbors_out.csv'. [INFO ] Saving CSV data to 'distances_out.csv'. [INFO ] [INFO ] Execution parameters: [INFO ] distances_file: distances_out.csv [INFO ] help: false [INFO ] info: "" [INFO ] input_model_file: "" [INFO ] k: 5 [INFO ] leaf_size: 20 [INFO ] naive: false [INFO ] neighbors_file: neighbors_out.csv [INFO ] output_model_file: "" [INFO ] query_file: "" [INFO ] random_basis: false [INFO ] reference_file: dataset.csv [INFO ] seed: 0 [INFO ] single_mode: false [INFO ] tree_type: kd [INFO ] verbose: true [INFO ] version: false [INFO ] [INFO ] Program timers: [INFO ] computing_neighbors: 0.108968s [INFO ] loading_data: 0.006495s [INFO ] saving_data: 0.003843s [INFO ] total_time: 0.126036s [INFO ] tree_building: 0.003442s |
在输出底部为每一个不一样的计算部分加入方便的程序计时器,同时也加入和仿真一块儿运行的参数。如今,若是咱们看看结果文件:
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ head neighbors_out.csv 862,344,224,43,885 703,499,805,639,450 867,472,972,380,601 397,319,277,443,323 840,827,865,38,438 732,876,751,492,616 563,222,569,985,940 361,97,928,437,79 547,695,419,961,716 982,113,689,843,634
$ head distances_out.csv 5.986076164057e-02,7.664920518084e-02,1.116050961847e-01,1.155595474371e-01,1.169810085522e-01 7.532635022982e-02,1.012564715841e-01,1.127846944644e-01,1.209584396720e-01,1.216543647014e-01 7.659571546879e-02,1.014588981948e-01,1.025114621511e-01,1.128082429187e-01,1.131659758673e-01 2.079405647909e-02,4.710724516732e-02,7.597622408419e-02,9.171977778898e-02,1.037033340864e-01 7.082206779700e-02,9.002355499742e-02,1.044181406406e-01,1.093149568834e-01,1.139700558608e-01 5.688056488896e-02,9.478072514474e-02,1.085637706630e-01,1.114177921451e-01,1.139370265105e-01 7.882260880455e-02,9.454474078041e-02,9.724494179950e-02,1.023829575445e-01,1.066927013814e-01 7.005321598247e-02,9.131417221561e-02,9.498248889074e-02,9.897964162308e-02,1.121202216165e-01 5.295654132754e-02,5.509877761894e-02,8.108227366619e-02,9.785461174861e-02,1.043968140367e-01 3.992859920333e-02,4.471418646159e-02,7.346053904990e-02,9.181982339584e-02,9.843075910782e-02 |
因此对于第0点的最近邻点是第862点,距离是5.986076164057e-02。第二近邻点是第344点,距离是7.664920518084e-02。第5点的第三近邻点是第751点,距离是1.085637706630e-01。
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
$ mlpack_knn -q query_dataset.csv -r reference_dataset.csv \ > -n neighbors_out.csv -d distances_out.csv -k 10 -v [INFO ] Loading 'reference_dataset.csv' as CSV data. Size is 3 x 1000. [INFO ] Loaded reference data from 'reference_dataset.csv' (3 x 1000). [INFO ] Building reference tree... [INFO ] Tree built. [INFO ] Loading 'query_dataset.csv' as CSV data. Size is 3 x 50. [INFO ] Loaded query data from 'query_dataset.csv' (3x50). [INFO ] Searching for 10 nearest neighbors with dual-tree kd-tree search... [INFO ] Building query tree... [INFO ] Tree built. [INFO ] Search complete. [INFO ] Saving CSV data to 'neighbors_out.csv'. [INFO ] Saving CSV data to 'distances_out.csv'. [INFO ] [INFO ] Execution parameters: [INFO ] distances_file: distances_out.csv [INFO ] help: false [INFO ] info: "" [INFO ] input_model_file: "" [INFO ] k: 10 [INFO ] leaf_size: 20 [INFO ] naive: false [INFO ] neighbors_file: neighbors_out.csv [INFO ] output_model_file: "" [INFO ] query_file: query_dataset.csv [INFO ] random_basis: false [INFO ] reference_file: reference_dataset.csv [INFO ] seed: 0 [INFO ] single_mode: false [INFO ] tree_type: kd [INFO ] verbose: true [INFO ] version: false [INFO ] [INFO ] Program timers: [INFO ] computing_neighbors: 0.022589s [INFO ] loading_data: 0.003572s [INFO ] saving_data: 0.000755s [INFO ] total_time: 0.032197s [INFO ] tree_building: 0.002590s |
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ mlpack_knn -r dataset.csv -n neighbors_out.csv -d distances_out.csv -k 3 -l 15 -v [INFO ] Loading 'dataset.csv' as CSV data. Size is 3 x 1000. [INFO ] Loaded reference data from 'dataset.csv' (3 x 1000). [INFO ] Building reference tree... [INFO ] Tree built. [INFO ] Searching for 3 nearest neighbors with dual-tree kd-tree search... [INFO ] 19692 node combinations were scored. [INFO ] 36263 base cases were calculated. [INFO ] Search complete. [INFO ] Saving CSV data to 'neighbors_out.csv'. [INFO ] Saving CSV data to 'distances_out.csv'. [INFO ] [INFO ] Execution parameters: [INFO ] distances_file: distances_out.csv [INFO ] help: false [INFO ] info: "" [INFO ] input_model_file: "" [INFO ] k: 3 [INFO ] leaf_size: 15 [INFO ] naive: false [INFO ] neighbors_file: neighbors_out.csv [INFO ] output_model_file: "" [INFO ] query_file: "" [INFO ] random_basis: false [INFO ] reference_file: dataset.csv [INFO ] seed: 0 [INFO ] single_mode: false [INFO ] tree_type: kd [INFO ] verbose: true [INFO ] version: false [INFO ] [INFO ] Program timers: [INFO ] computing_neighbors: 0.059020s [INFO ] loading_data: 0.002791s [INFO ] saving_data: 0.002369s [INFO ] total_time: 0.069277s [INFO ] tree_building: 0.002713s |
更多关于选项的文档可使用‘-help’选项找到。
具体来讲,‘KNN’类是一个更扩展的邻域搜索类的类型定义,使用欧氏距离查询最近邻点。
C++
1 2 |
typedef NeighborSearch<NearestNeighborSort, metric::EuclideanDistance> KNN; |
使用KNN类至关简单。首先,目标对象必须被构建并指定一个数据集。而后,运行方法,返回两个矩阵:一个是最近邻点的序号,一个是最近邻点的距离。以相同的结构输出–neighbors_file和–distances_file到命令行接口。下面给出几个KNN使用的几个例子。
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
using namespace mlpack::neighbor;
// Our dataset matrix, which is column-major. extern arma::mat data;
KNN a(data);
// The matrices we will store output in. arma::Mat<size_t> resultingNeighbors; arma::mat resultingDistances;
a.Search(5, resultingNeighbors, resultingDistances); |
搜索的输出存储在resultingNeighbors和resultingDistances里面。
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
using namespace mlpack::neighbor;
// Our dataset matrices, which are column-major. extern arma::mat queryData, referenceData;
KNN a(referenceData);
// The matrices we will store output in. arma::Mat<size_t> resultingNeighbors; arma::mat resultingDistances;
a.Search(queryData, 10, resultingNeighbors, resultingDistances); |
这个例子使用时间度O(n^2)的天然搜索(不是树搜索)。、
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
using namespace mlpack::neighbor;
// Our dataset matrix, which is column-major. extern arma::mat dataset;
KNN a(dataset, true);
// The matrices we will store output in. arma::Mat<size_t> resultingNeighbors; arma::mat resultingDistances;
a.Search(6, resultingNeighbors, resultingDistances); |
不用说,天然搜索很慢。
NeighborSearch类是可扩展的,带有下列模板参数:
C++
1 2 3 4 5 6 7 8 9 10 11 12 |
template< typename SortPolicy = NearestNeighborSort, typename MetricType = mlpack::metric::EuclideanDistance, typename MatType = arma::mat, template<typename TreeMetricType, typename TreeStatType, typename TreeMatType> class TreeType = tree::KDTree, template<typename RuleType> class TraversalType = TreeType<MetricType, NeighborSearchStat<SortPolicy>, MatType>::template DualTreeTraverser> > class NeighborSearch; |
经过为每一个模板类选择不一样的内容,能够建立任意的邻域搜索对象。注意,这些模板的每一个参数都有默认值,因此不须要为每一个参数赋值。
SortPolicy模板参数容许指定NeighborSearch对象将怎样肯定被搜索的每一个点。mlpack::neighbor::NearestNeighborSort类是一个被清楚记录的示例。一个定制的SortPolicy类必须完成和NearestNeighborSort类相同的方法。
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
static size_t SortDistance(const arma::vec& list, double newDistance);
static bool IsBetter(const double value, const double ref);
template<typename TreeType> static double BestNodeToNodeDistance(const TreeType* queryNode, const TreeType* referenceNode);
template<typename TreeType> static double BestPointToNodeDistance(const arma::vec& queryPoint, const TreeType* referenceNode);
static const double WorstDistance();
static const double BestDistance(); |
mlpack::neighbor::FurthestNeighborSort类是用于建立‘KFN’类型定义类的另外一个方法,和寻找最近邻点相反,它寻找最远邻点。
MetricType策略类容许邻域搜索发生在任意度量空间。mlpack::metric::LMetric是一个很好的示例实现。一个MetricType类必须提供下列功能:
C++
1 2 3 4 5 6 |
// Empty constructor is required. MetricType();
// Compute the distance between two points. template<typename VecType> double Evaluate(const VecType& a, const VecType& b); |
在内部,NeighborSearch类保存一个MetricType类的实例(它能够在构造函数中给定)。这对于像马氏距离这样必须存储状态(协方差矩阵)的度量是有用的(mlpack::metric::MahalanobisDistance)。所以,你能够写一个非静态MetricType类,无缝的使用它和NeighborSearch。
MatType模板参数指定数据类型使用矩阵。这个类型必须实现和Armadillo矩阵相同的操做,标准选择是arma::mat和arma::sp_mat。
邻域搜索NeighborSearch类在用于搜索的树类型的选择上有很好的扩展。这个类型必须遵循典型的mlpack TreeType策略。
典型的选择可能包含mlpack::tree::KDTree,mlpack::tree::BallTree,mlpack::tree::StandardCoverTree,mlpack::tree::RTree或mlpack::tree::RStarTree。制做你本身的树类型用来使用NeighborSearch是很容易的。更多细节请点击这里。
下面给出一个使用带有球树的NeighborSearch类的例子。
C++
1 2 3 4 5 6 7 |
// Construct a NeighborSearch object with ball bounds. NeighborSearch< NearestNeighborSort, metric::EuclideanDistance, arma::mat, tree::BallTree > neighborSearch(dataset); |
邻域搜索NeighborSearch类提供的最后一个模板参数是TraverserType类。它具备的策略是在单一树或者双树搜索模式下遍历树。默认状况下,它被设置为使用指定TreeType(成员TreeType::DualTreeTraverser)的默认遍历器。
这个类必须实现下面两种方法:
C++
1 2 3 4 5 |
// Instantiate with a given RuleType. TraverserType(RuleType& rule);
// Traverse with two trees. void Traverse(TreeType& queryNode, TreeType& referenceNode); |
RuleType类用在遍历器中时提供下面的功能:
C++
1 2 3 4 5 6 |
// Evaluate the base case between two points. double BaseCase(const size_t queryIndex, const size_t referenceIndex);
// Score the two nodes to see if they can be pruned, returning DBL_MAX if they // can be pruned. double Score(TreeType& queryNode, TreeType& referenceNode); |
注意任何指定的遍历器必须知足修剪双树遍历的定义,其在文章”Tree-independent dual-tree algorithms”中指定。