Cuda 在主机上完美运行的代码,放在内核中,由于神秘的原因而失败
我必须将预先存在的“仅主机”反向传播实现移植到CUDA。我认为算法的性质在这里并不重要,所以我不会对它的工作方式做太多解释。但我认为重要的是,它使用三维数组,所有三维数组都是动态分配的。 我使用VS2010和CUDA 5.0。我的设备是2.1。原始的纯主机代码可以在这里下载 → 守则的要点:Cuda 在主机上完美运行的代码,放在内核中,由于神秘的原因而失败,cuda,neural-network,backpropagation,Cuda,Neural Network,Backpropagation,我必须将预先存在的“仅主机”反向传播实现移植到CUDA。我认为算法的性质在这里并不重要,所以我不会对它的工作方式做太多解释。但我认为重要的是,它使用三维数组,所有三维数组都是动态分配的。 我使用VS2010和CUDA 5.0。我的设备是2.1。原始的纯主机代码可以在这里下载 → 守则的要点: 使用“pattern.h”中的数据结构,将成人数据中的模式加载到内存中 分配了几个多维数组 该算法使用之前分配的数组在模式上运行 如果要尝试运行代码,请不要忘记修改kernel.cu开头的PATH常量。我
- 算法使用的f()和fder()将成为设备 功能
- 参数是硬编码的:2层,5个神经元,学习率为 0.00001
- “w”数组是使用固定值(0.5)而不是rand()初始化的 再
- 在设备的内存中分配一个数据结构,并且数据 从成人数据加载后发送到设备内存中 在主人的记忆中
Data data;
Data* dev_data;
int* dev_t;
double* dev_x;
...
input_adult(PathFile, &data);
...
cudaMalloc((void**)&dev_data, sizeof(Data));
cudaMalloc((void**)&dev_t, data.N * sizeof(int));
cudaMalloc((void**)&dev_x, data.N * data.n * sizeof(double));
// Filling the device with t and x's data.
cudaMemcpy(dev_t, data.t, data.N * sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(dev_x, data.x, data.N * data.n * sizeof(double), cudaMemcpyHostToDevice);
// Updating t and x pointers into devices Data structure.
cudaMemcpy(&dev_data->t, &dev_t, sizeof(int*), cudaMemcpyHostToDevice);
cudaMemcpy(&dev_data->x, &dev_x, sizeof(double*), cudaMemcpyHostToDevice);
// Copying N and n.
cudaMemcpy(&dev_data->N, &data.N, sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(&dev_data->n, &data.n, sizeof(int), cudaMemcpyHostToDevice);
当读取“w”数组时,它显然在正向阶段开始时失败。我找不到任何解释
我认为有两种可能性:
谢谢。这是您代码中的问题,以及为什么它在64位机器模式下工作,而不是在32位机器模式下工作 在反向传播内核中的正向路径中,有一系列代码如下:
/*
* for layer = 0
*/
for (i = 0; i < N[0]; i++) { // for all neurons i of layer 0
a[0][i] = x[ data->n * pat + i]; // a[0][i] = input i
}
a[layer] = (double *)malloc( N[layer] * sizeof(double) );
假设test\u bp.exe
是可执行文件的名称。cuda memcheck可以方便地识别是否发生了越界写入,甚至可以识别发生写入的源代码行
那为什么这是不允许的呢?让我们先看一下内核代码中的代码:<代码> A[0 ][]/COD>被分配:
a[0] = (double *)malloc( N[0] * sizeof(double *) );
^ oops!!
a[0][]
用于保存double
数据,但您正在分配指针存储。
事实证明,在64位机器中,这两种类型的存储大小相同,因此它最终可以正常工作。但是在32位机器中,double
指针是4字节,而double
数据是8字节。因此,在32位机器中,当我们以8字节的数据步长对这个数组进行索引时,我们最终会从数组的末尾运行
在内核代码的其他地方,您正在为a
的其他“层”分配存储,如下所示:
/*
* for layer = 0
*/
for (i = 0; i < N[0]; i++) { // for all neurons i of layer 0
a[0][i] = x[ data->n * pat + i]; // a[0][i] = input i
}
a[layer] = (double *)malloc( N[layer] * sizeof(double) );
这是正确的。我看到原始的“仅主机”代码似乎也包含此错误。代码中也可能存在潜在的缺陷
如果要在windows wddm设备上运行,您仍然需要解决内核运行时间问题,以某种方式避免windows TDR事件。正如我已经指出的,这段代码没有试图使用机器的并行功能。这是代码中的问题,以及为什么它在64位机器模式下工作,而不是在32位机器模式下工作 在反向传播内核中的正向路径中,有一系列代码如下:
/*
* for layer = 0
*/
for (i = 0; i < N[0]; i++) { // for all neurons i of layer 0
a[0][i] = x[ data->n * pat + i]; // a[0][i] = input i
}
a[layer] = (double *)malloc( N[layer] * sizeof(double) );
假设test\u bp.exe
是可执行文件的名称。cuda memcheck可以方便地识别是否发生了越界写入,甚至可以识别发生写入的源代码行
那为什么这是不允许的呢?让我们先看一下内核代码中的代码:<代码> A[0 ][]/COD>被分配:
a[0] = (double *)malloc( N[0] * sizeof(double *) );
^ oops!!
a[0][]
用于保存double
数据,但您正在分配指针存储。
事实证明,在64位机器中,这两种类型的存储大小相同,因此它最终可以正常工作。但是在32位机器中,double
指针是4字节,而double
数据是8字节。因此,在32位机器中,当我们以8字节的数据步长对这个数组进行索引时,我们最终会从数组的末尾运行
在内核代码的其他地方,您正在为a
的其他“层”分配存储,如下所示:
/*
* for layer = 0
*/
for (i = 0; i < N[0]; i++) { // for all neurons i of layer 0
a[0][i] = x[ data->n * pat + i]; // a[0][i] = input i
}
a[layer] = (double *)malloc( N[layer] * sizeof(double) );
这是正确的。我看到原始的“仅主机”代码似乎也包含此错误。代码中也可能存在潜在的缺陷
如果希望在窗口上运行,您仍然需要解决内核运行时间问题,以某种方式避免windows TDR事件