Поскольку у нас нет доступа к примеру, который на самом деле компилируется (что было бы неплохо), я на самом деле не пытался скомпилировать пример ниже. Тем не менее, некоторые незначительные опечатки (возможно) в стороне, общая идея должна быть ясной.
Задача состоит в том, чтобы найти наибольшее значение подобия и соответствующую метку, для этого мы действительно можем использовать reduction
, но, поскольку нам нужно найти максимум одно значение и затем сохранить соответствующую метку, мы используйте пару для хранения обоих значений одновременно, чтобы реализовать это как reduction
в OpenMP.
Я немного переписал ваш код, возможно, немного затруднил чтение с оригинальным именованием (temp
) переменной. По сути, мы выполняем поиск параллельно, поэтому каждый поток находит оптимальное значение, затем мы просим OpenMP найти оптимальное решение между потоками (reduction
), и все готово.
//Reduce by finding the maximum and also storing the corresponding label, this is why we use a std::pair.
void reduce_custom (std::pair<float, unsigned int>& output, std::pair<float, unsigned int>& input) {
if (input.first > output.first) output = input;
}
//Declare an OpenMP reduction with our pair and our custom reduction function.
#pragma omp declare reduction(custom_reduction : \
std::pair<float, unsigned int>: \
reduce_custom(omp_out, omp_in)) \
initializer(omp_priv(omp_orig))
bool identify(const float* data, unsigned int length, unsigned int& label, float& similarity) {
std::pair<float, unsigned int> temp(0.0, label); //Stores thread local similarity and corresponding best label.
#pragma omp parallel for reduction(custom_reduction:temp)
for (size_t i = 0; i < collection.size(); ++i) {
const float* candidateTemplate = collection[i].first.data();
float consinSimilarity = getSimilarity(data, candidateTemplate, length);
if (consinSimilarity > temp.first) {
temp.first = consinSimilarity;
temp.second = collection[i].second;
}
}
if (temp.first > 0.f) {
similarity = temp.first;
label = temp.second;
return true;
}
return false;
}
Что касается вашей озабоченности по поводу ограниченного количества регистров SIMD, их количество зависит от используемого вами c ЦП. Насколько я понимаю, каждое ядро имеет установленное количество доступных векторных регистров, так что, пока вы не использовали больше, чем было доступно, прежде чем все должно быть в порядке, к тому же AVX512, например, предоставляет 32 векторных регистра и 2 arithemti c единиц для векторных операций на ядро, поэтому нехватка вычислительных ресурсов не тривиальна, вы, скорее всего, пострадаете из-за плохой локализации памяти (особенно в вашем случае, когда векторы сохраняются повсеместно). Конечно, я могу ошибаться, если да, пожалуйста, не стесняйтесь поправлять меня в комментариях.