random - curand_uniform 不确定?
问题描述
我想以一种确定的方式在 CUDA 设备上生成伪随机数,如果我运行该程序两次,我希望得到完全相同的结果,因为该程序使用的是硬编码的种子。按照 nvidia 提供的示例:https ://docs.nvidia.com/cuda/curand/device-api-overview.html#device-api-example 我希望完全符合所描述的行为。
但我确实得到了不同的结果,多次运行完全相同的代码。正如我所描述的,有没有办法以确定的方式获得伪随机数?
以下示例代码显示了我的问题:
#include <iostream>
#include <cuda.h>
#include <curand_kernel.h>
__global__ void setup_kernel(curandState *state)
{
auto id = threadIdx.x + blockIdx.x * blockDim.x;
curand_init(123456, id, 0, &state[id]);
}
__global__ void draw_numbers(curandState *state, float* results)
{
auto id = threadIdx.x + blockIdx.x * blockDim.x;
// Copy state
curandState localState = state[id % 1024];
// Generate random number
results[id] = curand_uniform(&localState);
// Copy back state
state[id % 1024] = localState;
}
int main(int argc, char* argv[])
{
// Setup
curandState* dStates;
cudaMalloc((void **) &dStates, sizeof(curandState) * 1024);
setup_kernel<<<1024, 1>>>(dStates);
// Random numbers
float* devResults;
cudaMalloc((void **) &devResults, sizeof(float) * 16 * 1024);
float *hostResults = (float*) calloc(16 * 1024, sizeof(float));
// Call draw random numbers
draw_numbers<<<1024, 16>>>(dStates, devResults);
// Copy results
cudaMemcpy(hostResults, devResults, 16 * 1024 * sizeof(float), cudaMemcpyDeviceToHost);
// Output number 12345
::std::cout << "12345 is: " << hostResults[12345] << ::std::endl;
return 0;
}
编译和运行代码会在我的机器上产生不同的输出:
$ nvcc -std=c++11 curand.cu && ./a.out && ./a.out && ./a.out
12345 is: 0.8059
12345 is: 0.53454
12345 is: 0.382981
正如我所说,在此示例中,我希望输出相同的三倍。
解决方案
curand_uniform
确实取决于提供它的状态。
感谢 Robert Crovella 的评论,我现在看到错误在于依赖于线程执行顺序。只是不重用状态会导致相同的“随机”数字,当 draw_numbers 内核被多次调用时,这对我来说也不是一个选项。
我的猜测是,就我而言,最好的解决方案是只启动 1024 个线程(与设置的 curandState 一样多)并在每个线程中生成多个随机数(在我的示例中为 16 个/线程)。这样,我在程序内的多次调用中收到不同的随机数,但每次程序启动时都收到相同的数字。
更新代码:
#include <iostream>
#include <cuda.h>
#include <curand_kernel.h>
__global__ void setup_kernel(curandState *state)
{
auto id = threadIdx.x + blockIdx.x * blockDim.x;
curand_init(123456, id, 0, &state[id]);
}
__global__ void draw_numbers(curandState *state, float* results, int runs)
{
auto id = threadIdx.x + blockIdx.x * blockDim.x;
// Copy state
curandState localState = state[id];
// Generate random numbers
for (int i = 0; i < runs; ++i)
{
results[id + i * 1024] = curand_uniform(&localState);
}
// Copy back state
state[id] = localState;
}
int main(int argc, char* argv[])
{
// Setup
curandState* dStates;
cudaMalloc((void **) &dStates, sizeof(curandState) * 1024);
setup_kernel<<<1024, 1>>>(dStates);
// Random numbers
float* devResults;
cudaMalloc((void **) &devResults, sizeof(float) * 16 * 1024);
float *hostResults = (float*) calloc(16 * 1024, sizeof(float));
// Call draw random numbers
draw_numbers<<<16, 64>>>(dStates, devResults, 16);
// Copy results
cudaMemcpy(hostResults, devResults, 16 * 1024 * sizeof(float), cudaMemcpyDeviceToHost);
// Output number 12345
::std::cout << "12345 is " << hostResults[12345];
// Call draw random numbers (again)
draw_numbers<<<16, 64>>>(dStates, devResults, 16);
// Copy results
cudaMemcpy(hostResults, devResults, 16 * 1024 * sizeof(float), cudaMemcpyDeviceToHost);
// Output number 12345 again
::std::cout << " and " << hostResults[12345] << ::std::endl;
return 0;
}
产生以下输出:
$ nvcc -std=c++11 curand.cu && ./a.out && ./a.out && ./a.out
12345 is 0.164181 and 0.295907
12345 is 0.164181 and 0.295907
12345 is 0.164181 and 0.295907
这正是我的用例。
推荐阅读
- android - 我们可以在 Android Network Profiler 面板中格式化 JSON 响应吗?
- sql - 如果数据库中已经存在,则从 Temp 表中删除数据
- django - 如何使用来自另一个数据库(不是默认数据库)的 auth_user?
- javascript - 烧瓶现场;为不同的元素重用 Javascript/Ajax 函数(MacOS Mojave)
- node.js - Telegram Webhook 在群聊中未触发
- node.js - 如何从 Azure 云中的 nodejs 应用程序发送 gmail?
- angular - Angular 6中泳道图表中的日期格式问题
- apache-spark - 如何在使用 Spark 2.1 部署的 YARN 集群上使用不同的 Spark 版本(Spark 2.4)?
- database - 插入和更新在 postgres 的表上被阻止
- database - 无法识别的名称:_PARTITIONTIME