使用Thrust从单个数组构造多个直方图

时间:2015-03-30 16:52:57

标签: cuda thrust

我们假设我有一个存储多个事件时间戳的数组。例如,T1_e1,T2_e1,......,T1_e2,T2_e2,T3_e2,...... T1_eN,T2,eN,..

我知道Thrust提供了一个计算相邻差异的函数,但在这里我需要为多个事件做这件事。基本上,从单个输入数组构造多个直方图。

因此输出将有N个不同的直方图(每个事件一个),如下所示: e1的直方图区间,e2的直方图区间,e3的直方图区间,eN的直方图区间。

Input1 (timestamps): 100, 101, 104, 105, 101,104, 106, 111, 90, 91, 93,  94,95
Input2 (events):    4123,4123,4123,4123,2129,2129,2129,2129,300,300,300,300,300

output: 4123:(1,2),(2,0),(3,1),(4,0),(5,0)
        2129:(1,0),(2,1),(3,1),(4,0),(5,1)
        300: (1,2),(2,1),(3,0),(4,),(5,0)  

箱数将固定,即每个直方图5个箱。 关于元组:(x,y) - > x是属于同一事件的两个连续时间戳之间的差异。 y是计数。

如果我们考虑事件4123,第一个元组是(1,2),因为101和100之间的差是1,而105和104是1.所以有两个时间戳差异属于这个bin,因此(1,2)。

有人可以建议最有效的方法来做到这一点。到目前为止,我似乎必须编写自己的代码。但如果有现有的解决方案,我想先试试。

1 个答案:

答案 0 :(得分:2)

这是计算稀疏直方图的一种可能方法(即仅限非零二进制位)。使用推力散射将稀疏直方图转换为密集直方图(包括零和非零箱)应该不难。

  1. 使用thrust::adjacent_difference和特殊仿函数(my_adj_diff)计算时间戳差异,该仿函数仅为类似事件计算相邻差异。

  2. 使用thrust::remove_if删除每个事件序列开头的零值(每个事件一个)(由步骤1中的仿函数创建)。

  3. 使用thrust::transform将事件和时间戳差异组合成一个整数,以进行直方图编码。这只是在我的示例中将事件乘以100,并添加时间戳差异(假设是一组小于100最大bin的箱子)。

  4. 使用推力histogram example code中的稀疏直方图方法。

  5. 这是一个功能齐全的例子。数据与预期输出不完全匹配(仅限非零值),因为预期输出中存在错误。

    $ cat t678.cu
    #include <thrust/adjacent_difference.h>
    #include <thrust/iterator/zip_iterator.h>
    #include <thrust/iterator/constant_iterator.h>
    #include <thrust/device_vector.h>
    #include <thrust/host_vector.h>
    #include <thrust/copy.h>
    #include <thrust/remove.h>
    #include <thrust/sort.h>
    #include <thrust/inner_product.h>
    #include <thrust/reduce.h>
    #include <thrust/functional.h>
    
    
    #include <iostream>
    
    #define ZIP(X,Y) thrust::make_zip_iterator(thrust::make_tuple(X,Y))
    #define SCALE 100
    
    struct my_adj_diff
    {
      template <typename T>
      __host__ __device__
      T operator()(T &d2, T &d1) const
        {
          if (thrust::get<1>(d1) == thrust::get<1>(d2)) {
            thrust::get<0>(d2) -= thrust::get<0>(d1);}
          else {
            thrust::get<0>(d2) = 0;}
          return d2;
        }
    };
    
    struct my_is_zero
    {
      template <typename T>
      __host__ __device__
      bool operator()(const T &d1) const
        {
          return (thrust::get<0>(d1) == 0);
        }
    };
    
    struct my_combine
    {
      template <typename T>
      __host__ __device__
      T operator()(const T &d1, const T &d2) const
        {
          return (d1*SCALE)+d2;
        }
    };
    
    // sparse histogram using reduce_by_key
    // modified from: https://github.com/thrust/thrust/blob/master/examples/histogram.cu
    template <typename Vector1,
              typename Vector2,
              typename Vector3>
    void sparse_histogram(const Vector1& input,
                                Vector2& histogram_values,
                                Vector3& histogram_counts)
    {
      typedef typename Vector1::value_type ValueType; // input value type
      typedef typename Vector3::value_type IndexType; // histogram index type
      thrust::device_vector<ValueType> data(input);
    
      // sort data to bring equal elements together
      thrust::sort(data.begin(), data.end());
    
      // number of histogram bins is equal to number of unique values (assumes data.size() > 0)
      IndexType num_bins = thrust::inner_product(data.begin(), data.end() - 1,
                                                 data.begin() + 1,
                                                 IndexType(1),
                                                 thrust::plus<IndexType>(),
                                                 thrust::not_equal_to<ValueType>());
    
      // resize histogram storage
      histogram_values.resize(num_bins);
      histogram_counts.resize(num_bins);
    
      // compact find the end of each bin of values
      thrust::reduce_by_key(data.begin(), data.end(),
                            thrust::constant_iterator<IndexType>(1),
                            histogram_values.begin(),
                            histogram_counts.begin());
    
    }
    
    
    int main(){
    
      int tstamps[] = { 100, 101, 104, 105, 101,104, 106, 111, 90, 91, 93,  94,95 };
      int mevents[] = {4123,4123,4123,4123,2129,2129,2129,2129,300,300,300,300,300};
      int dsize = sizeof(tstamps)/sizeof(int);
    
      thrust::host_vector<int>   h_stamps(tstamps, tstamps+dsize);
      thrust::host_vector<int>   h_events(mevents, mevents+dsize);
      thrust::device_vector<int> d_stamps = h_stamps;
      thrust::device_vector<int> d_events = h_events;
      thrust::device_vector<int> diffs(dsize);
      // compute timestamp differences by event
      thrust::adjacent_difference(ZIP(d_stamps.begin(), d_events.begin()), ZIP(d_stamps.end(), d_events.end()), ZIP(d_stamps.begin(), d_events.begin()), my_adj_diff());
      d_stamps[0] = 0;  // fix up first event for adjacent_difference
      int sz1 = thrust::remove_if(ZIP(d_stamps.begin(), d_events.begin()), ZIP(d_stamps.end(), d_events.end()), my_is_zero()) - ZIP(d_stamps.begin(), d_events.begin());
      d_stamps.resize(sz1);
      d_events.resize(sz1);
      // pack events and timestamps into a single vector - assumes max bin (time difference) is less than SCALE
      thrust::device_vector<int> d_data(sz1);
      thrust::transform(d_events.begin(), d_events.end(), d_stamps.begin(), d_data.begin(), my_combine());
      // compute histogram
      thrust::device_vector<int> histogram_values;
      thrust::device_vector<int> histogram_counts;
      sparse_histogram(d_data, histogram_values, histogram_counts);
      thrust::copy(histogram_values.begin(), histogram_values.end(), std::ostream_iterator<int>(std::cout, ","));
      std::cout << std::endl;
      thrust::copy(histogram_counts.begin(), histogram_counts.end(), std::ostream_iterator<int>(std::cout, ","));
      std::cout << std::endl;
    }
    $ nvcc t678.cu -o t678
    $ ./t678
    30001,30002,212902,212903,212905,412301,412303,
    3,1,1,1,1,2,1,
    $
    

    请注意,您需要使用CUDA 7.0(不是CUDA 7.0 RC或任何早期版本的CUDA),否则请下载最新的推力主分支from github,因为较旧版本的推力有issue尝试使用带有thrust::adjacent_difference的zip迭代器时。