我必须将预先存在的“仅主机”反向传播实现移植到 CUDA。我认为算法的性质在这里并不重要,所以我不会对它的工作方式做太多解释。不过,我认为重要的是它使用 3 维数组,其所有三个维度都是动态分配的。我使用带有 CUDA 5.0 的 VS2010。我的设备是2.1。原始主机代码可以在这里下载 → http://files.getwebb.org/view-cre62u4d.html
代码要点:
- 使用“pattern.h”中的数据结构将成人数据中的模式加载到内存中。
- 分配了几个多维数组
- 该算法使用之前分配的数组在模式上运行。
如果您想尝试运行代码,请不要忘记修改 kernel.cu 开头的 PATH 常量。我还建议你使用“2”层、“5”个神经元和“0.00001”的学习率。如您所见,这非常有效。“MSE”正在改善。对于那些不知道这个算法是做什么的人,我们简单地说它学习如何根据模式中存在的 14 个变量来预测目标值。“MSE”减少,意味着算法在每个“epoch”之后犯的错误更少。
我花了很长时间尝试在设备上运行此代码。而我仍然没有成功。最后一次尝试是通过简单地复制初始化数组的代码并将算法运行到一个大内核中来完成的。又失败了。该代码可以在那里下载 → http://files.getwebb.org/view-cre62u4c.html
准确地说,以下是与原始仅主机代码的区别:
- 算法使用的 f() 和 fder() 成为设备 函数。
- 参数是硬编码的:2 层,5 个神经元,学习率为 0.00001
- “w” 数组使用固定值 (0.5) 进行初始化,不再是 rand()
- a 数据结构在设备内存中分配,数据从host内存中的adult.data加载后发送到设备内存
我认为我做了使代码在内核中运行所需的最少修改。“kernel_check_learningData”内核,显示了有关加载到设备内存中的模式的一些信息,证明了以下代码,将模式从主机发送到设备,确实有效:
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”数组时,它显然在前向阶段开始时失败。我找不到任何解释。
我看到两种可能性:
- 将模式发送到设备内存中的代码存在错误,尽管它似乎可以正常工作,并且在开始前进阶段时会进一步引发错误。
- CUDA API 的行为不像它应该的那样!
我拼命寻找我的错误很长一段时间。所以我想知道社区是否可以为我提供一些帮助。
谢谢。