ann flann alglibB最近邻方法时效性探索


FLANN-use

为什么用flann

在点集X中存储了大量点,给定一个点y并需要在X中寻找距离点y最近的一个点或者多个点时,通常采用硬查找或者近似最近邻的方式进行查找。而点数越多、维度越高,硬查找的方法将会消耗大量的时间,但是找到的结果精度是较高的。为了提升效率我们可以通过近似最近邻的方法查找最近点。
关于这方面的库主要由ANN(2010),flann(2013),之前一直使用的是ANN,但是觉得效率方面并不是很理想。因此现在对flann进行调研与使用,flann与ann相比方法更加完备,使用起来可选择的方法更多,并且可以调用OPENMP、CUDA等对搜索进行加速,号称比ANN的速度快一个数量级,但用起来稍微麻烦一点。

怎么用flann

在flann的官网中可以下载其源码,可以绑定到C++、C、MATLAB、python,但是自己是使用C++写的。我主要是结合说明手册以及自己在C++中的使用方法与效率对比进行一个测试和使用记录。

多thread支持

可以选择多内核进行搜索,选择的方式是使用参数SearchParams,默认是单核计算的,可以通过设置这个参数的数值来使用内核数,也可以将参数设置为0,表示使用尽可能多的核来计算。

flann使用

我主要是看的C++使用,关于matlab C python的使用可以通过说明书再细看。

头文件

flann.hpp

3.1.1 flann::Index

FLANN的最近邻搜索类,这个类用于适应于不同类型的最近邻索引。这个点用于计算距离函数。

flann::Index::Index 构造函数

参数features,是包含用于构建索引的特征的矩阵;
参数params,是包含索引参数的结构,这个参数选择了搜索的方式,主要包括一下几种:

  • LinearIndexParams 线性的、暴力(brute-force)的搜索。
  • KDTreeIndexParams kd树构成(randomized kd-trees),它可以平行地进行搜索。
struct KDTreeIndexParams : public IndexParams
{
    KDTreeIndexParams( int trees = 4 );
};
  • KMeansIndexParams 层次k均值树
struct KMeansIndexParams : public IndexParams
{
    KMeansIndexParams(
        int branching = 32,//The branching factor to use for the hierarchical k-means tree
        int iterations = 11,//If a value of -1,should be iterated
until convergence
        flann_centers_init_t centers_init = CENTERS_RANDOM,
        float cb_index = 0.2 );
};
  • CompositeIndexParams 随机kd树与层次k均值树相结合
  • KDTreeSingleIndexParams 仅仅是一个k-d树为低维度的搜索(如3D点云数据)
  • KDTreeCuda3dIndexParams 运用CUDA的k-d树搜索,这最好用在有大量搜索和查询点的时候
  • HierarchicalClusteringIndexParams hierarchical clustering index
  • LshIndexParams 该结构使用multi-probe LSH方法创建索引
  • AutotunedIndexParams 自动选择最好的以上结构
  • SavedIndexParams 从文件中读取索引
centers init

这个参数用来选择在搜索时,选择初始中心的方法。可能之有:
CENTERS RANDOM:随即产生
CENTERS GONZALES:使用Gonzales’的算法
CENTERS KMEANSPP:D. Arthur and S. Vassilvitskii. k-means++中提到的方法。

3.1.2 flann::Index::buildIndex

创建最近邻索引可以使用两种方式:一个是传入点进去,一种是使用构造函数时传入的点。也就是这个借口可以选择不传参数。

void buildIndex();
void buildIndex(const Matrix<ElementType>& points);
3.1.3 flann::Index::addPoints/removePoint

在索引已经建立之后也可以增加和减少点。为了避免索引失衡,addPoints提供了在新增大量数据后的重建索引,参数rebuild threshold=2表示点云增加为size的两倍。removePoint一般不改变索引结构

3.1.5 flann::Index::getPoint

ElementType* getPoint(size_t point_id);不知道这里的point_id指的是什么?

3.1.6 flann::Index::knnSearch

是一个K邻域搜索,可以选择输出类型为matrix或者vector。用vector的话就不需要先限定数组的大小,能够自己扩展。

int Index::knnSearch(const Matrix<ElementType>& queries,//查询点。点数×维度
                     Matrix<int>& indices,//返回的最近点数据 num queries × knn
                     Matrix<DistanceType>& dists, //返回最近点的距离 num_queries×knn
                     size_t knn,//最近邻的个数
                     const SearchParams& params);//搜索参数
                     
int Index::knnSearch(const Matrix<ElementType>& queries,
                    std::vector< std::vector<int> >& indices,
                    std::vector<std::vector<DistanceType> >& dists,
                    size_t knn,
                    const SearchParams& params);
                    
struct SearchParams
{
                    SearchParams(int checks = 32,
                    float eps = 0,
                    bool sorted = true);
                
                int checks;//检测点 CHECKS UNLIMITED CHECKS AUTOTUNED
                float eps;//KD tree
                bool sorted;//Used only by radius search, specifies if the neighbors returned should be sorted by distance.
                int max_neighbors;//Used only by radius search, 最多返回的点数
                tri_type use_heap;//
                int cores; //内核数 0表示自动选择
                bool matrices_in_gpu_ram;//
};
3.1.7 flann::Index::radiusSearch

与knn基本相同,只是最近的点数变为了半径大小

3.1.8 flann::Index::save

把索引表存入文件中,
void Index::save(std::string filename);

3.1.9 flann::hierarchicalClustering

使用多层次k均值树

3.1.10 flann::KdTreeCuda3dIndex

提供了CUDA为提升建立和查询速度的三维点云数据。首先需要在安装时候选择上CUDA选项才可以。

时间测试:

LinearIndexParams(): 0.460
KDTreeIndexParams(4): 0.58
KMeansIndexParams(): 0.290
CompositeIndexParams(): 0.280
KDTreeSingleIndexParams(): 0.20
LshIndexParams():error
HierarchicalClusteringIndexParams(): 0.500
AutotunedIndexParams(): 0.850??
搜索时候的配置都是全核: 二维坐标点 点数共有360个,搜索大概1200*180次

flann::SearchParams mypapra(16,0.1,false);
        mypapra.cores = 0;
//        mypapra.checks=flann::CHECKS AUTOTUNED;
        index_->knnSearch(*query_, *indics_, *dists_, 1, mypapra);

EX:

        flann::Matrix<float> *dataset_;
        flann::Matrix<float> *query_;
        flann::Matrix<int> *indics_;
        flann::Matrix<float> *dists_;
        flann::Index<flann::L2<float> > *index_;
        void cleanFLANN();
  dataset_ = new flann::Matrix<float>(new float[maxPts*dim], maxPts, dim);
  for(int i=0; i<nsites; ++i)
  {
    (*dataset_)[i][0]=points[i].x();
    (*dataset_)[i][1]=points[i].y();
  }
query_ = new flann::Matrix<float>(new float[k*dim], k, dim);
  dists_ = new flann::Matrix<float>(new float[k*dim], k, dim);
  indics_ = new flann::Matrix<int>(new int[k*dim], k, dim);
  index_ = new flann::Index<flann::L2<float> >(*dataset_,flann::KDTreeSingleIndexParams());
  index_->buildIndex();
        
void VoronoiDiagramGenerator::cleanFLANN()
{
  if(dataset_)
  {
    delete[] dataset_->ptr();
    delete[] dataset_;
    dataset_ = NULL;
  }
  //TODO:QY 下面这三个可以不清除内存的,反正每次都是寻找一个最近点。
  if(query_)
  {
    delete[] query_->ptr();
    delete[] query_;
    query_ = NULL;
  }
  if(indics_)
  {
    delete[] indics_->ptr();
    delete[] indics_;
    indics_ = NULL;
  }
  if(dists_)
  {
    delete[] dists_->ptr();
    delete[] dists_;
    dists_ = NULL;
  }
}

//search
 *query_[0][0] = x;
 *query_[0][1] = x;
  flann::SearchParams mypapra(16,0.1,false);
  mypapra.cores = 0;
  index_->knnSearch(*query_, *indics_, *dists_, 1, mypapra);
  return sqrt(*dists_[0][0]);

insall FLANN with CUDA

FLANN支持GPU并行计算,但是在安装时就需要选择并行。
1.刚开始在flann的发行版上进行安装未成功,因为后期CUDA版本更新,作者对flann进行了修改,但是没有把修改后的发行。因此1.8.4的发行版对cuda8.0不支持。因此我在github上下载了最新的flann-master原文件进行安装。
一直出现如下错误:
flann-with-cuda-error.png

2.在cmake后打开CMakeCache.txt,选择CUDA-LIB,并把我不需要的Matlab的勾取消。
flann-CUDA.png
3.make
4.sudo make install

ALGLIB use

直接在官网下载源码,将源码放在项目中并进行了测试。
搜索条件:二维坐标点 点数共有360个,搜索大概1200*180次
时间为0.160s,与flann的最快搜索时间基本相同。

ANN-USE

搜索条件:二维坐标点 点数共有360个,搜索大概1200*180次
ANN_KD_STD = 0, // the optimized kd-splitting rule ERROR
ANN_KD_MIDPT = 1, // midpoint split 搜索时间为0.07s
ANN_KD_FAIR = 2, // fair split 搜索时间为0.08s
ANN_KD_SL_MIDPT = 3, // sliding midpoint splitting method 搜索时间为0.08s
ANN_KD_SL_FAIR = 4, // sliding fair split method //搜索时间为0.06s
ANN_KD_SUGGEST= 5}; // the authors’ suggestion for best 搜索时间为0.06ms
ANN_KD_SUGGEST对应下的搜索方式的时间开销:

  • annkPriSearch:0.15s
  • annkSearch: 0.06s
  • annkFRSearch: 按照半径2.5m进行搜索,时间为0.055s !! 这种求最短距离的早该想到在固定半径内查找最近点!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值