Включение поддержки Open MP в Visual Studio 2017 замедляет кодирование - PullRequest
0 голосов
/ 14 ноября 2018

Я пытаюсь использовать OpenMP для ускорения моих кодов для вычислений нейронной сети.Поскольку я использую Visual Studio 2017, мне нужно включить поддержку OpenMP в листах свойств.Однако после того, как я это сделал, некоторая часть кода замедляется примерно в 5 раз, хотя я не включил в код #pragma omp.

Я выделил разделыи обнаружил, что именно эта функция вызывает проблему:

void foo(Eigen::Matrix<float,3,Eigen::Dynamic> inputPts)
{
    std::vector<Eigen::MatrixXf> activation;
    activation.reserve(layerNo);
    activation.push_back(inputPts);

    int inputNo = inputPts.cols();

    for (int i = 0; i < layerNo - 2; i++)
        activation.push_back(((weights[i]*activation[i]).colwise()+bias[i]).array().tanh());

    activation.push_back(((weights[layerNo - 2]*activation[layerNo - 2]).colwise()+bias[layerNo - 2]));

    val = activation[layerNo - 1]/scalingFactor;

    std::vector<Eigen::MatrixXf> delta;
    delta.reserve(layerNo);

    Eigen::Matrix<float, 1, Eigen::Dynamic> seed;
    seed.setOnes(1, inputNo);
    delta.push_back(seed);

    for (int i = layerNo - 2; i >= 1; i--)
    {
        Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic>
                d_temp = weights[i].transpose()*delta[layerNo - 2 - i],
                d_temp2 = 1 - activation[i].array().square(),
                deltaLayer = d_temp.cwiseProduct(d_temp2);

        delta.push_back(deltaLayer);
    }

    grad = weights[0].transpose()*delta[layerNo - 2];
}

Два цикла for - это те, которые значительно замедляются (от ~ 3 мс до ~ 20 мс).Как ни странно, хотя эта функция вызывается в программе много раз, это затрагивает только некоторые из них.

Я включил заголовочный файл <omp.h>.Я не уверен, происходит ли это из-за библиотеки Eigen, которая используется везде.Я попытался определить EIGEN_DONT_PARALLELIZE и позвонить на Eigen::initParallel(), как это было предложено на официальном сайте , но это не помогло.

Странно то, что я даже не включил parallel pragma ввсе, не должно быть никаких накладных расходов для обработки функций OpenMP?Почему это все еще замедляется?

1 Ответ

0 голосов
/ 14 ноября 2018

Матрично-матричные продукты Eigen по умолчанию являются многопоточными, если OpenMP включен. Проблема, скорее всего, в комбинации:

  1. Ваш ЦП гиперпоточный, например, у вас есть 4 физических ядра, способных выполнять 8 потоков.
  2. OpenMP не позволяет узнать количество физических ядер, поэтому Eigen запустит 8 потоков.
  3. Ядро матрично-матричного продукта Eigen полностью оптимизировано и использует почти 100% процессорной мощности. Следовательно, нет места для запуска двух таких потоков на одном ядре, и производительность значительно падает (загрязнение кэша).

Таким образом, решение состоит в том, чтобы ограничить количество потоков OpenMP количеством физических ядер, например, установив переменную среды OMP_NUM_THREADS. Вы также можете отключить многопоточность Eigen, определив макрос EIGEN_DONT_PARALLELIZE во время компиляции.

Больше информации в документ .

Подробнее о том, как гиперпоточность может снизить производительность: Благодаря гиперпоточности у вас есть два потока, чередующиеся на одном ядре. Они чередуют каждую инструкцию. Если ваши потоки не используют менее половины ресурсов ЦП (с точки зрения вычислений), то это победа, потому что вы будете использовать больше вычислительных единиц. Но если один поток уже использует 100% вычислительных блоков (как в случае хорошо оптимизированного матрично-матричного продукта), то вы теряете производительность из-за 1) естественных накладных расходов на управление двумя потоками и 2) из-за L1 кеш теперь разделяется двумя разными задачами. Матрично-матричные ядра разработаны с учетом точности L1. С двумя потоками ваш кэш L1 становится почти неэффективным. Это означает, что вместо того, чтобы извлекать очень быстрый кэш L1 большую часть времени, вы в конечном итоге получаете доступ к гораздо более медленному кешу L2, и, таким образом, вы получаете огромное падение производительности. В отличие от Linux и Windows, в OSX такого снижения производительности не наблюдается, скорее всего, потому, что система может отменять планирование вторых потоков, если процессор уже слишком занят.

...