zoukankan      html  css  js  c++  java
  • k Nearest Neighbor Search by CUDA

    kNN(k Nearest Neighbor)是常用的群集算法(Cluster Algorithm)用于空间搜索。目前最快的kNN方法莫过于KDTree的版本,不过基本上都是CPU的比如ANN C++ Library。对于GPU来说,实现加速结构比较复杂,因为没有栈所以无法递归,而且执行资源有限,不能像CPU一样舒舒服服的顺序执行。

    为了方便起见我直接用komrade粘合C++与CUDA,下面是测试程序的代码。 

    #include <komrade/device_vector.h>
    #include 
    <komrade/transform.h>
    #include 
    <komrade/range.h>
    #include 
    <komrade/copy.h>
    #include 
    <komrade/fill.h>
    #include 
    <komrade/sort.h>
    #include 
    <komrade/replace.h>
    #include 
    <komrade/functional.h>
    #include 
    <iostream>
    #include 
    <iterator>
    #include 
    <math.h>
    #include 
    <memory>
    #include 
    <boost/timer.hpp>

    using namespace std;

    #include 
    <ANN/ANN.h>
    #pragma comment(lib,"ANN.lib")

    struct dist
    {
        dist(
    float qx, float qy, float qz) : x(qx), y(qy), z(qz)
        {
        }
        
    float x,y,z;
        
        __host__ __device__ 
    float operator()(const float3& p) const
        {
            
    float a = p.x - x;
            
    float b = p.y - y;
            
    float c = p.z - z;
            
    return a*+ b*+ c*c;
        }
    };

    int main(int argc, char* argv[])
    {
        
    if( argc < 2 )
            
    return -1;
                
        
    int N = 0;
        sscanf(argv[
    1],"%d",&N);
        
        boost::timer Stopwatch;
        ANNpointArray ANNPh 
    = annAllocPts(N,3);
        komrade::host_vector
    <float3> Ph(N);
        komrade::device_vector
    <int> Idx(N);
        komrade::device_vector
    <float> Dist(N);
        
        
        
    for(int i=0; i<N; ++i)
        {
            
    float x = (float)rand() / (float)RAND_MAX;;
            
    float y = (float)rand() / (float)RAND_MAX;;
            
    float z = (float)rand() / (float)RAND_MAX;;
            
            Ph[i].x 
    = x;
            Ph[i].y 
    = y;
            Ph[i].z 
    = z;
            
            ANNPh[i][
    0= x;
            ANNPh[i][
    1= y;
            ANNPh[i][
    2= z;
                    
            
    if( N < 32 )
                printf(
    "<%f %f %f>\n",x,y,z);
            Idx[i] 
    = i;
        }
        cout
    <<fixed<<"Generate Data Used "<<Stopwatch.elapsed()<<endl;
        Stopwatch.restart();
            
        
    float QueryPos[3];
        QueryPos[
    0= (float)rand() / (float)RAND_MAX * 0.1f + 0.5f;
        QueryPos[
    1= (float)rand() / (float)RAND_MAX * 0.1f + 0.5f;
        QueryPos[
    2= (float)rand() / (float)RAND_MAX * 0.1f + 0.5f;
        
    if( N < 32 )
            printf(
    "[%f %f %f]\n",QueryPos[0],QueryPos[1],QueryPos[2]);
            
        komrade::device_vector
    <float3> Pd = Ph;
        cout
    <<fixed<<"Copy Data Used "<<Stopwatch.elapsed()<<endl;
        Stopwatch.restart();
        
        komrade::transform(Pd.begin(), Pd.end(), Dist.begin(), dist(QueryPos[
    0], QueryPos[1], QueryPos[2]));
        komrade::sort_by_key(Dist.begin(), Dist.end(), Idx.begin());
        cout
    <<fixed<<"Sort Data by CUDA Used "<<Stopwatch.elapsed()<<endl;
        Stopwatch.restart();
        
        ANNkd_tree ANNTree(ANNPh,N,
    3);
        ANNidx ANNIdx[
    1];
        ANNdist ANNDst[
    1];
        ANNTree.annkSearch(QueryPos,
    1,ANNIdx,ANNDst);
        cout
    <<fixed<<"Sort Data by ANN Used "<<Stopwatch.elapsed()<<endl;

        
        
    if( N < 32 )
        {
            copy(Dist.begin(), Dist.end(), ostream_iterator
    <float>(cout," "));
            cout
    <<endl;
            copy(Idx.begin(), Idx.end(), ostream_iterator
    <int>(cout," "));
        }
        
        
        
    return 0;
    }

    下面是性能分析对比,可以看到CUDA版本在大量点的情况下还是非常有优势的,不过在纯RenderFarm就用不上了,恐怕只能在装备有G80以上芯片的桌面环境或者工作站上执行。测试环境如下,

    • Intel E5200@2.9G
    • Apacer 2Gx2
    • 9800GT 512M
    • CUDA 2.2, komrade 0.9
      10 100 1000 10000 100000 1000000
    CUDA 0.003 0.003 0.00300 0.007 0.012 0.038
    ANN 0.000 0.000 0.00100 0.008 0.131 2.490

    CUDAKNN

    极其明显的,当排序数目数量级超过10e5的时候,CUDA显示出了巨大的速度优势。数目比较少的时候还是CPU的比较快速。

    启发自《Fast k Nearest Neighbor Search using GPU

  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/Jedimaster/p/1497985.html
Copyright © 2011-2022 走看看