【问题标题】:C++ AMP is slowC++ AMP 很慢
【发布时间】:2016-07-24 19:03:16
【问题描述】:

我在 C++ 中有以下代码:

float Neuron::feedForward(std::vector<Neuron>& previousLayer){
float sum=0.0f;
for(int i=0;i<(int)previousLayer.size();i+=1){
    sum+=previousLayer[i].getOutput()*weigths[i];
}
output=Neuron::transferFunction(sum);
return output;

};

我转换成这个:

float Neuron::feedForward(std::vector<Neuron>& previousLayer){
float sum=0.0f;
extent<1> e((int)previousLayer.size());

std::vector<float> ops(previousLayer.size());
for (int i = 0; i<(int)previousLayer.size(); i += 1) {
    ops[i] = previousLayer[i].getOutput();
}

array_view<const float, 1>_outputs(e, ops);
array_view<const float, 1>_weigths(e, weigths);
array_view<float> _sum(e);
_sum.discard_data();


parallel_for_each(e, [=](index<1> idx) restrict(amp) {
    _sum[idx] = _outputs[idx] * _weigths[idx];

});

for (int i = 0; i < e[0]; i += 1) {
    sum += _sum[i];
}

output=Neuron::transferFunction(sum);
return output;

};

现在程序运行代码非常慢。不仅慢了几毫秒,而且实际上慢了几秒。

我还尝试在 AMP 代码中添加总和(仅更改):

array_view<float> _sum(1);
_sum.discard_data();

...

parallel_for_each(e, [=](index<1> idx) restrict(amp) {
_sum[0] += _outputs[idx] * _weigths[idx];

});

...

/*for (int i = 0; i < e[0]; i += 1) {
sum += _sum[i];
 }
 */

output=Neuron::transferFunction(_sum[0]);

但最后,代码就是这样:太慢了,我用手动计算器会更快。现在的问题是:为什么?我想如果我有一个 2000 权重的神经元,让 GPU 计算一切会很棒。我错过了什么,还是我必须学习 OpenCL 或 CUDA?

PS。慢动作真的很糟糕。就像它需要超过 100 000 倍的时间(同时我可以计算 20 000 个神经网络 10 次,我可以使用 AMP 计算 2 个完全相同的网络)。

【问题讨论】:

  • 您可以尝试在 parallel_for_each 块之后在 e 上添加同步调用。根据此处的 C++ AMP 教程msdn.microsoft.com/en-us/magazine/hh882446.aspx,应自动执行同步。但是,如果你不显式调用 synchronize(),你会丢失异常,所以也许这会出现问题?
  • 我怀疑你不知道如何很好地使用AMP。您似乎坚持将产品总和累积到标量_sum [0]中。如果我理解这一点,您将强制生成的代码将所有产品发送到持有 sum[0](“大量通信”)的特定处理器,和/或强制对该总和的所有更新以执行全局锁定(“很多锁干扰”)。这些都不是有效的。我认为您最好花一些时间阅读有关数据并行编程、技术和陷阱的信息,然后利用这些知识修改您的 AMP 程序。
  • 我不知道我是否可以在 e 上调用同步,但是在 _sum 上没有触发 std::exception。有没有可能,因为我在笔记本电脑上运行,GPU 不知何故处于睡眠模式,而 AMP 又回到了 cpu 上?尽管我的 CPU 使用率约为 10%,这意味着我计算机上的一个线程正在运行其 90% 的功能。
  • 致 Ira Baxter:当我尝试让代码使用 _sum[idx] 时会怎样?这应该有什么不同吗,因为每个 GPU 核心都有自己的 _sum 来赋予它们的价值?
  • 我测试了手动选择加速器。还是没有区别。也在不同的机器上,不同版本的视觉工作室(最初是 2015 社区,现在是 2012 终极版)。所以问题必须在代码中。我还使用相当大的计算层对整个事情进行计时:虽然 GPU 可以在大约 600-700 毫秒内完成其中一个层,但 CPU 在 0-1 毫秒内完成。

标签: c++ performance parallel-processing gpgpu c++-amp


【解决方案1】:

您使用sum[0] 的代码几乎肯定会给出不正确的结果,因为许多线程同时更新sum[0]

简单的实现应该可以工作,但效率非常低,因为将数据移入和移出 GPU 需要大量的复制开销,而且您只进行很少的计算。

但是,由于它像您说的那么慢,您似乎在 CPU 上的 WARP 加速器上运行。您可以使用以下代码查看可用的加速器。

https://ampbook.codeplex.com/SourceControl/latest#Samples/ShowAmpDevices/ShowAmpDevices.cpp

你在这里做的是减少。有很多文章介绍了如何在 GPU 上有效地做到这一点。您可以在此处找到显示几种不同实现的 C++AMP 代码:

C++ AMP: Accelerated Massive Parallelism with Microsoft Visual C++ 在 CodePlex 上。

随代码一起的书中对它们进行了全面解释。

【讨论】:

  • _sum[0] 是测试之一,我也尝试了 _sum[idx]。我知道这还不是最佳代码,但它是我学习 AMP 的一个简单块(稍后我计划将数据移动到 GPU,并在那里计算所有内容,但现在我用它来学习这个过程)。我添加了手动选择 GPU 的代码,GeForce 570。我还尝试了您链接中的代码,我的设备说:专用内存:1.2mb,有 display=true,is_debug 和 is_emulated 都是假的,它支持有限精度和双精度.我将尝试 CUDA,以防我的 AMP 出现问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 2015-11-01
  • 2018-12-31
  • 1970-01-01
相关资源
最近更新 更多