2016-07-24 10 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. Сливы действительно плохие. Как и требуется более 100 000 раз дольше (в то же время я могу вычислить 20 000 нейронных сетей десять раз, я могу вычислить 2 точно такие же сети, используя AMP).

+0

Вы можете попробовать добавить вызов синхронизации по e после блока parallel_for_each. В соответствии с инструкцией C++ AMP, https://msdn.microsoft.com/en-us/magazine/hh882446.aspx, синхронизация должна выполняться автоматически. Но, если вы не вызываете synchronize() явно, вы потеряете исключения, так что, может быть, это что-то изменит? – hacoo

+0

Я подозреваю, что вы не знаете, как хорошо использовать AMP. Кажется, вы настаиваете на накоплении суммы продуктов в скалярном _sum [0]. Если я понимаю это право, вы вынуждаете сгенерированный код отправлять все продукты конкретному процессору, который содержит сумму [0] («много сообщений») и/или принуждает все обновления к этой сумме выполнять глобальную блокировку (" много помех блокировки "). Ни один из них не эффективен. Я думаю, вам будет полезно потратить некоторое время на чтение данных о параллельном программировании, методах и подводных камнях, а затем использовать эти знания для пересмотра вашей программы для AMP. –

+0

Я не знаю, могу ли я вызвать синхронизацию по e, но на _sum не было вызвано std :: exception.Возможно ли, что, поскольку я бегу на ноутбуке, графический процессор каким-то образом находится в режиме сна, а AMP падает на CPU? Хотя использование моего процессора составляет ~ 10%, что означает, что один из потоков на моем компьютере работает на 90% от его возможностей. – Nyxeria

ответ

1

Ваш код с использованием sum[0] почти наверняка даст неверные результаты, так как многие потоки обновляются одновременно sum[0].

Наивная реализация должна работать, но очень неэффективна, поскольку для перемещения данных на и с графического процессора имеется значительная накладная нагрузка, и вы делаете очень мало вычислений.

Однако, поскольку это должно быть так медленно, как вы говорите, кажется вероятным, что вы работаете на ускорителе WARP на CPU. Вы можете использовать следующий код, чтобы узнать, какие ускорители доступны.

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

Что вы здесь делаете это сокращение. Существует много статей о том, как это сделать эффективно на графическом процессоре. Вы можете найти код C++ AMP, показывающий несколько различных реализаций здесь:

C++ AMP: Accelerated Massive Parallelism with Microsoft Visual C++ на CodePlex.

Они полностью объясняются в книге, которая идет с кодом.

+0

_sum [0] был одним из тестов, я также попробовал _sum [idx]. Я знаю, что это еще не оптимальный код, но для меня это простой блок для изучения AMP (позже я планирую только переносить данные на GPU и вычислять все там, но теперь я использую это, чтобы изучить процесс). Я добавил код для выбора GPU вручную, GeForce 570. Я также пробовал код из вашей ссылки, и мое устройство говорит: выделенная память: 1.2mb, имеет display = true, is_debug и is_emulated являются ложными и поддерживает ограниченные и двойная точность. Я собираюсь попробовать CUDA, если у меня есть проблемы с моей AMP. – Nyxeria