Próbuję użyć OpenMP, aby przyspieszyć moje kody do obliczeń sieci neuronowej. Ponieważ używam programu Visual Studio 2017, muszę włączyć obsługę OpenMP w arkuszach właściwości. Jednak po tym, jak to zrobiłem, pewna część kodu spowalnia około 5 razy, mimo że nie zawarłem w kodzie żadnego #pragma omp.

Wyizolowałem sekcje i dowiedziałem się, że ta konkretna funkcja powoduje problem:

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];
}

Dwie pętle for to te, które znacznie spowalniają (od ~3ms do ~20ms). O dziwo, chociaż ta funkcja jest wielokrotnie wywoływana w programie, dotyczy to tylko niektórych z nich.

Dołączyłem plik nagłówkowy <omp.h>. Nie jestem pewien, czy to zasługa biblioteki Eigen, która jest używana wszędzie. Próbowałem zdefiniować EIGEN_DONT_PARALLELIZE i zadzwonić Eigen::initParallel() zgodnie z sugestią na oficjalnej stronie< /a> ale to nie pomaga.

Dziwne jest to, że w ogóle nie zawarłem żadnego parallel pragma, nie powinno być żadnych dodatkowych kosztów związanych z obsługą funkcji OpenMP? Dlaczego nadal zwalnia?

0
mjfoo21 14 listopad 2018, 15:04

1 odpowiedź

Najlepsza odpowiedź

Produkty matrix-matrix Eigen są domyślnie wielowątkowe, jeśli OpenMP jest włączony. Problemem jest prawdopodobnie połączenie:

  1. Twój procesor jest hiperwątkowy, np. masz 4 rdzenie fizyczne zdolne do uruchomienia 8 wątków.
  2. OpenMP nie pozwala poznać liczby fizycznych rdzeni, dlatego Eigen uruchomi 8 wątków.
  3. Jądro produktu Matrix-Matrix firmy Eigen jest w pełni zoptymalizowane i wykorzystuje prawie 100% mocy procesora. W konsekwencji nie ma miejsca na uruchomienie dwóch takich wątków na jednym rdzeniu, a wydajność znacznie spada (zanieczyszczenie pamięci podręcznej).

Rozwiązaniem jest więc ograniczenie liczby wątków OpenMP do liczby fizycznych rdzeni, na przykład poprzez ustawienie zmiennej środowiskowej OMP_NUM_THREADS. Możesz także wyłączyć wielowątkowość Eigen, definiując makro EIGEN_DONT_PARALLELIZE w czasie kompilacji.

Więcej informacji znajdziesz w dokumentacji.

Więcej informacji o tym, jak hiperwątkowość może obniżyć wydajność: Dzięki hiperwątkowości masz dwa wątki działające z przeplotem na jednym rdzeniu. Zmieniają każdą instrukcję. Jeśli twoje wątki nie zużywają mniej niż połowy zasobów procesora (pod względem obliczeń), to wygrana, ponieważ wykorzystasz więcej jednostek obliczeniowych. Ale jeśli pojedynczy wątek używa już 100% jednostek obliczeniowych (jak w przypadku dobrze zoptymalizowanego produktu macierzowo-macierzowego), tracisz wydajność z powodu 1) naturalnego obciążenia związanego z zarządzaniem dwoma wątkami i 2) z powodu L1 pamięć podręczna jest teraz współdzielona przez dwa różne zadania. Jądra Matrix-Matrix zostały zaprojektowane z myślą o dokładnej pojemności L1. W przypadku dwóch wątków pamięć podręczna L1 staje się prawie nieefektywna. Oznacza to, że zamiast pobierać przez większość czasu bardzo szybką pamięć podręczną L1, uzyskujesz dostęp do znacznie wolniejszej pamięci podręcznej L2, a tym samym uzyskujesz ogromny spadek wydajności. W przeciwieństwie do Linuksa i Windowsa, na OSX nie obserwuję takiego spadku wydajności, najprawdopodobniej dlatego, że system jest w stanie rozplanować drugie wątki, jeśli procesor jest już zbyt zajęty.

1
ggael 15 listopad 2018, 15:53