【问题标题】:Generating random numbers with uniform distribution using Thrust使用 Thrust 生成均匀分布的随机数
【发布时间】:2012-09-18 19:30:44
【问题描述】:

我需要使用Thrust 生成一个具有0.01.0 之间随机数的向量。我能找到的唯一记录示例会产生非常大的随机数 (thrust::generate(myvector.begin(), myvector.end(), rand)。 我确信答案很简单,但如果有任何建议,我将不胜感激。

【问题讨论】:

    标签: c++ cuda thrust


    【解决方案1】:

    这个问题已经有了令人满意的答案。特别是,OP 和 Robert Crovella 处理了thrust::generate,而 talonmies 建议使用thrust::transform

    我认为还有另一种可能性,即使用thrust::for_each,所以我发布了一个使用这种原语的完整示例,仅供记录。

    我也在为不同的解决方案计时。

    代码

    #include <iostream>
    
    #include <thrust\host_vector.h>
    #include <thrust\generate.h>
    #include <thrust\for_each.h>
    #include <thrust\execution_policy.h>
    #include <thrust\random.h>
    
    #include "TimingCPU.h"
    
    /**************************************************/
    /* RANDOM NUMBERS GENERATION STRUCTS AND FUNCTION */
    /**************************************************/
    template<typename T>
    struct rand_01 {
        __host__ T operator()(T& VecElem) const { return (T)rand() / RAND_MAX; }
    };
    
    template<typename T>
    struct rand_01_for_each {
        __host__ void operator()(T& VecElem) const { VecElem = (T)rand() / RAND_MAX; }
    };
    
    template<typename T>
    __host__ T rand_01_fcn() { return ((T)rand() / RAND_MAX); }
    
    struct prg
    {
        float a, b;
    
        __host__ __device__
            prg(float _a = 0.f, float _b = 1.f) : a(_a), b(_b) {};
    
        __host__ __device__
            float operator()(const unsigned int n) const
        {
            thrust::default_random_engine rng;
            thrust::uniform_real_distribution<float> dist(a, b);
            rng.discard(n);
    
            return dist(rng);
        }
    };
    
    /********/
    /* MAIN */
    /********/
    int main() {
    
        TimingCPU timerCPU;
    
        const int N = 2 << 18;          
        //const int N = 64;
    
        const int numIters = 50;
    
        thrust::host_vector<double>     h_v1(N);
        thrust::host_vector<double>     h_v2(N);
        thrust::host_vector<double>     h_v3(N);
        thrust::host_vector<double>     h_v4(N);
    
        printf("N = %d\n", N);
    
        double timing = 0.;
        for (int k = 0; k < numIters; k++) {
            timerCPU.StartCounter();
            thrust::transform(thrust::host, h_v1.begin(), h_v1.end(), h_v1.begin(), rand_01<double>());
            timing = timing + timerCPU.GetCounter();
        }
        printf("Timing using transform = %f\n", timing / numIters);
    
        timing = 0.;
        for (int k = 0; k < numIters; k++) {
            timerCPU.StartCounter();
            thrust::counting_iterator<unsigned int> index_sequence_begin(0);
            thrust::transform(index_sequence_begin,
                index_sequence_begin + N,
                h_v2.begin(),
                prg(0.f, 1.f));
            timing = timing + timerCPU.GetCounter();
        }
        printf("Timing using transform and internal Thrust random generator = %f\n", timing / numIters);
    
        timing = 0.;
        for (int k = 0; k < numIters; k++) {
            timerCPU.StartCounter();
            thrust::for_each(h_v3.begin(), h_v3.end(), rand_01_for_each<double>());
            timing = timing + timerCPU.GetCounter();
        }
        timerCPU.StartCounter();
        printf("Timing using for_each = %f\n", timing / numIters);
    
        //std::cout << "Values generated: " << std::endl;
        //for (int k = 0; k < N; k++)
        //  std::cout << h_v3[k] << " : ";
        //std::cout << std::endl;
    
        timing = 0.;
        for (int k = 0; k < numIters; k++) {
            timerCPU.StartCounter();
            thrust::generate(h_v4.begin(), h_v4.end(), rand_01_fcn<double>);
            timing = timing + timerCPU.GetCounter();
        }
        timerCPU.StartCounter();
        printf("Timing using generate = %f\n", timing / numIters);
    
        //std::cout << "Values generated: " << std::endl;
        //for (int k = 0; k < N; k++)
        //  std::cout << h_v4[k] << " : ";
        //std::cout << std::endl;
    
        //std::cout << "Values generated: " << std::endl;
        //for (int k = 0; k < N * 2; k++)
        //  std::cout << h_v[k] << " : ";
        //std::cout << std::endl;
    
        return 0;
    }
    

    在笔记本电脑Core i5 平台上,我有以下时间

    N = 2097152
    Timing using transform = 33.202298
    Timing using transform and internal Thrust random generator = 264.508662
    Timing using for_each = 33.155237
    Timing using generate = 35.309399 
    

    除了第二个使用Thrust的内部随机数生成器而不是rand()之外,其他时间是相同的。

    请注意,与其他解决方案不同,thrust::generate刚性,因为用于生成随机数的函数不能有输入参数。因此,例如,不可能通过常数缩放输入参数。

    【讨论】:

    • 我认为你的包含有 / 倒置
    • @zardilior 这是由于linux和windows中文件路径的约定不同。
    【解决方案2】:

    这可能不是您问题的直接答案,但是 cuRand 库在这个概念上非常强大。您可以同时在 GPU 和 CPU 上生成随机数,并且它包含许多分布函数(正态分布等)。

    在此链接上搜索标题:“一个 NVIDIA CURAND 实现”:http://adnanboz.wordpress.com/tag/nvidia-curand/

    //Create a new generator
    curandCreateGenerator(&m_prng, CURAND_RNG_PSEUDO_DEFAULT);
    //Set the generator options
    curandSetPseudoRandomGeneratorSeed(m_prng, (unsigned long) mainSeed);
    //Generate random numbers
    curandGenerateUniform(m_prng, d_randomData, dataCount);
    

    需要注意的是,不要一次又一次地生成生成器,它会进行一些预先计算。调用 curandGenerateUniform 非常快,并且生成的值介于 0.0 和 1.0 之间。

    【讨论】:

      【解决方案3】:

      @talonmies 建议的方法具有许多有用的特征。这是模仿您引用的示例的另一种方法:

      #include <thrust/host_vector.h>
      #include <thrust/generate.h>
      #include <iostream>
      #define DSIZE 5
      
      
      __host__ static __inline__ float rand_01()
      {
          return ((float)rand()/RAND_MAX);
      }
      
      int main(){
        thrust::host_vector<float> h_1(DSIZE);
      
        thrust::generate(h_1.begin(), h_1.end(), rand_01);
        std::cout<< "Values generated: " << std::endl;
        for (unsigned i=0; i<DSIZE; i++)
          std::cout<< h_1[i] << " : ";
        std::cout<<std::endl;
      return 0;
      }
      

      与您引用的示例类似,它使用 rand(),因此只能用于生成宿主向量。同样,除非您适当地重新播种 rand(),否则它每次都会产生相同的序列。

      【讨论】:

        【解决方案4】:

        Thrust 具有随机生成器,可用于生成随机数序列。要将它们与设备向量一起使用,您需要创建一个函子,该函子返回随机生成器序列的不同元素。最直接的方法是使用计数迭代器的转换。一个非常简单的完整示例(在本例中生成介于 1.0 和 2.0 之间的随机单精度数)可能如下所示:

        #include <thrust/random.h>
        #include <thrust/device_vector.h>
        #include <thrust/transform.h>
        #include <thrust/iterator/counting_iterator.h>
        #include <iostream>
        
        struct prg
        {
            float a, b;
        
            __host__ __device__
            prg(float _a=0.f, float _b=1.f) : a(_a), b(_b) {};
        
            __host__ __device__
                float operator()(const unsigned int n) const
                {
                    thrust::default_random_engine rng;
                    thrust::uniform_real_distribution<float> dist(a, b);
                    rng.discard(n);
        
                    return dist(rng);
                }
        };
        
        
        int main(void)
        {
            const int N = 20;
        
            thrust::device_vector<float> numbers(N);
            thrust::counting_iterator<unsigned int> index_sequence_begin(0);
        
            thrust::transform(index_sequence_begin,
                    index_sequence_begin + N,
                    numbers.begin(),
                    prg(1.f,2.f));
        
            for(int i = 0; i < N; i++)
            {
                std::cout << numbers[i] << std::endl;
            }
        
            return 0;
        }
        

        在此示例中,仿函数 prg 将随机数的下限和上限作为参数,(0.f,1.f) 作为默认值。请注意,为了每次调用变换操作时都有不同的向量,您应该使用初始化为不同起始值的计数迭代器。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-12-09
          • 2013-07-22
          • 1970-01-01
          • 1970-01-01
          • 2018-10-04
          • 1970-01-01
          • 2017-07-16
          • 1970-01-01
          相关资源
          最近更新 更多