2016-07-24 71 views
2

我具有以下在C++代码:C++ AMP是慢

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。缓慢是非常糟糕的。就像它花费的时间超过10万次(同时我可以计算20 000个神经网络10次,使用AMP我可以计算2个完全相同的网络)。

+0

您可以尝试在parallel_for_each块之后的e上添加同步调用。根据此处的C++ AMP教程https://msdn.microsoft.com/en-us/magazine/hh882446.aspx,应该自动执行同步。但是,如果你不明确地调用synchronize(),你将失去异常,所以这可能会导致一些事情发生。 – hacoo

+0

我怀疑你不知道如何使用AMP。看起来你坚持要将一定数量的产品积累到一个标量_sum [0]中。如果我理解了这个权利,那么您就迫使生成的代码将所有产品发送到持有sum [0](“多次通信”)的特定处理器,并且/或者强制执行全局锁定的所有更新(“大量的锁干扰“)。这些都不是有效的。我认为你会花点时间阅读数据并行编程,技术和陷阱,然后利用这些知识修改AMP的程序。 –

+0

我不知道我是否可以在e上调用同步,但在_sum上没有触发std :: exception。是否有可能,因为我在笔记本电脑上运行,GPU以某种方式处于睡眠模式,并且AMP退回到CPU?尽管我的CPU使用率约为10%,这意味着我的电脑上的一个线程正在运行其90%的功能。 – Nyxeria

回答

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++ on CodePlex。

他们在随代码一起的书中有充分的解释。

+0

_sum [0]是其中一个测试,我也尝试过_sum [idx]。我知道这还不是最优的代码,但它对我来说是一个学习AMP的简单方块(稍后我计划将数据移动到GPU,并计算所有内容,但现在我用它来学习该过程)。 我添加了手动选择GPU的代码,GeForce 570.我也试过了你链接的代码,我的设备说:专用内存:1.2mb,有display = true,is_debug和is_emulated都是假的,它支持有限的双精度。我要去尝试CUDA,以防AMP的问题。 – Nyxeria