mlpack: 一个C++机器学习库

简介

mlpack是一个C++机器学习库,侧重于可扩展性、速度和易用性。它的目的是通过一个简单的、前后一致的API让新用户使用机器学习成为可能,同时利用C++语言特征为专家用户提供最好的性能和最大的灵活性。这些通过提供一系列命令行执行程序完成,就像使用一个黑箱,而且专家用户和研究者可以容易的更改一个模块化的C++ API的内部算法。

mlpack

这种方法的结果就是mlpack的性能大幅度超过其他竞争的机器学习库;在the BigLearning workshop paper 和the benchmarks for details查看细节。

mlpack由全世界的贡献者开发。基于伯克利发行软件许可的第三个条款免费发行。(比1.0.12更老的版本基于GNU通用公共授权规定发行:LGPL,第3版。)

安装

mlpack存储在许多Linux的发行版本中,所以在你的系统中使用程序包管理器可能更容易一些。例如:在Ubuntu上,你可以使用下面的命令安装mlpack。

C++

 

1

$ sudo apt-get install libmlpack-dev

如果mlpack不能在你的系统的程序包管理器中使用,那么你可以按照下面的步骤编译和安装mlpack源文件。

Mlpack使用CMake作为生成系统,允许几个灵活的生成配置选项。你可以查询大量的CMake教程得到更多的文件,但是这个教程应该足够让你在大多数Linux和类UNIX系统中(包括OS X)成功生成和安装mlpack。如果你想在Windows操作系统中生成mlpack,请看这里

首先下载mlpack。

当mlpack的源文件完成解压,你可以创建一个生成目录。

C++

 

1

2

$ cd mlpack-2.2.5

$ mkdir build

这个目录可以是任何名字,不仅仅是“build”,但是“build”足够了。

mlpack依赖项

mlpack依赖下面的库,它们需要被安装在系统中并有一些头文件出现。

  • Armadillo >=4.200.0(支持LAPACK(线性代数程序包))
  • Boost(math_c99, program_options, serialization, unit_test_framework, heap, spirit)>=1.49

在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

运行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允许的全部选项为:

  • DEBUG=(ON/OFF): compile with debugging symbols (default ON in svn trunk, OFF in releases)
  • PROFILE=(ON/OFF): compile with profiling symbols (default ON in svn trunk, OFF in releases)
  • ARMA_EXTRA_DEBUG=(ON/OFF): compile with extra Armadillo debugging symbols (default OFF)
  • BUILD_TESTS=(ON/OFF): compile the mlpack_test program (default ON)
  • BUILD_CLI_EXECUTABLES=(ON/OFF): compile the mlpack command-line executables (i.e. mlpack_knn, mlpack_kfn, mlpack_logistic_regression, etc.) (default ON)
  • TEST_VERBOSE=(ON/OFF): run test cases in mlpack_test with verbose output (default OFF)

每个选项都可以被指定给带有‘-D’标记的CMake。其他工具也可以用于配置CMake,但是它们没有被记录在这里。

生成mlpack

一旦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

如果你想将mlpack安装在/usr/include/mlpack/、/usr/lib/和/usr/bin/中,当它生成后,确保你有root权限(或向那两个目录的写入许可),然后简单的打出:

C++

 

1

# make install

现在你可以通过名字运行可执行程序;你可以使用-lmlpack链接到mlpack,mlpack的头文件可以在目录/usr/include/mlpack/中找到。

示例

最近邻搜索是一个常见的机器学习任务。在这个背景下 ,我们有一个查询数据集和一个参考数据集。对于在查询数据集中的每个点,我们希望知道参考数据集中距离给定查询点最近的k个点。

或者,如果查询和参考数据集是相同的,问题可以更简单的说明:对于每个数据集中的点,我们希望知道距离那个点最近的k个点。

Mlpack提供:

  • 一个简单的命令行程序包运行最近邻搜索(和最远邻搜索)。
  • 一个简单的C++接口用于完成最近邻搜索(和最远邻搜索)。
  • 一个通用的、可扩展的和强大的C++类(邻域搜索)用于复杂算法。

命令行‘mlpack_knn’

在mlpack中完成最近邻搜索最简单的方式是使用mlpack_knn程序包。这个程序将完成最近邻搜索,并将得到的邻近点放入一个文件,同时将对应的距离放入另一个文件。输出文件被整理为第一行对应第一个被查询点的最近邻点,第一列对应最近的点,以此类推。

下面是几个简单用法的例子(和输出结果)。由于使用了选项‘-v’,因此输出是给定的。更多关于每个选项的文档可以通过下面这个语句找到。

C++

 

1

$ mlpack_knn –help

 

一个数据集,5个最近邻点

 

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。

查询和参考数据集,10个最近邻点

 

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

 

一个数据集,3个最近邻点,15个点的大小

 

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’类

具体来说,‘KNN’类是一个更扩展的邻域搜索类的类型定义,使用欧氏距离查询最近邻点。

C++

 

1

2

typedef NeighborSearch<NearestNeighborSort, metric::EuclideanDistance>

    KNN;

使用KNN类相当简单。首先,目标对象必须被构建并指定一个数据集。然后,运行方法,返回两个矩阵:一个是最近邻点的序号,一个是最近邻点的距离。以相同的结构输出–neighbors_file和–distances_file到命令行接口。下面给出几个KNN使用的几个例子。

单一数据集上的5个最近邻点

 

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里面。

查询和参考数据集上的10个最近邻点

 

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);

 

在数据集上自然(穷举)搜索6个最近邻点

这个例子使用时间度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’类

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策略类

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策略类

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策略类

MatType模板参数指定数据类型使用矩阵。这个类型必须实现和Armadillo矩阵相同的操作,标准选择是arma::mat和arma::sp_mat。

TreeType策略类

邻域搜索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);

 

TraverserType策略类

邻域搜索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”中指定。

资源链接

命令行程序参考:http://mlpack.org/docs/mlpack-2.2.5/man.html

 

转载于:https://my.oschina.net/u/4000302/blog/3047185

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值