Хуже производительность при использовании Eigen, чем при использовании моего собственного класса - PullRequest
10 голосов
/ 01 июня 2011

Пару недель назад я задал вопрос о производительности умножения матриц.

Мне сказали, что для повышения производительности моей программы я должен использовать некоторые специализированные матричные классы, а не свой собственный класс.

Рекомендуется пользователям StackOverflow:

  • uBLAS
  • Эйген
  • BLAS

Сначала я хотел использовать uBLAS, но, прочитав документацию , оказалось, что эта библиотека не поддерживает матрично-матричное умножение.

В конце концов я решил использовать библиотеку EIGEN. Поэтому я изменил свой класс матрицы на Eigen::MatrixXd - однако оказалось, что теперь мое приложение работает даже медленнее, чем раньше. Время до использования EIGEN составляло 68 секунд, а после замены моего класса матрицы на матрицу EIGEN программа запускается в течение 87 секунд.

Части программы, которые занимают больше всего времени, выглядят так

TemplateClusterBase* TemplateClusterBase::TransformTemplateOne( vector<Eigen::MatrixXd*>& pointVector, Eigen::MatrixXd& rotation ,Eigen::MatrixXd& scale,Eigen::MatrixXd& translation )
{   
    for (int i=0;i<pointVector.size();i++ )
    {
        //Eigen::MatrixXd outcome =
        Eigen::MatrixXd outcome = (rotation*scale)* (*pointVector[i])  + translation;
        //delete  prototypePointVector[i];      // ((rotation*scale)* (*prototypePointVector[i])  + translation).ConvertToPoint();
        MatrixHelper::SetX(*prototypePointVector[i],MatrixHelper::GetX(outcome));
        MatrixHelper::SetY(*prototypePointVector[i],MatrixHelper::GetY(outcome));
        //assosiatedPointIndexVector[i]    = prototypePointVector[i]->associatedTemplateIndex = i;
    }

    return this;
}

и

Eigen::MatrixXd AlgorithmPointBased::UpdateTranslationMatrix( int clusterIndex )
{
    double membershipSum = 0,outcome = 0;
    double currentPower = 0;
    Eigen::MatrixXd outcomePoint = Eigen::MatrixXd(2,1);
    outcomePoint << 0,0;
    Eigen::MatrixXd templatePoint;
    for (int i=0;i< imageDataVector.size();i++)
    {
        currentPower =0; 
        membershipSum += currentPower = pow(membershipMatrix[clusterIndex][i],m);
        outcomePoint.noalias() +=  (*imageDataVector[i] - (prototypeVector[clusterIndex]->rotationMatrix*prototypeVector[clusterIndex]->scalingMatrix* ( *templateCluster->templatePointVector[prototypeVector[clusterIndex]->assosiatedPointIndexVector[i]]) ))*currentPower ;
    }

    outcomePoint.noalias() = outcomePoint/=membershipSum;
    return outcomePoint; //.ConvertToMatrix();
}

Как видите, эти функции выполняют множество матричных операций. Вот почему я думал, что использование Eigen ускорит мое приложение. К сожалению (как я уже говорил выше), программа работает медленнее.

Есть ли способ ускорить эти функции?

Может быть, если бы я использовал матричные операции DirectX, я бы получил лучшую производительность ?? (однако у меня есть ноутбук со встроенной графической картой).

Ответы [ 6 ]

12 голосов
/ 01 июня 2011

Если вы используете типы Eigen MatrixXd, они имеют динамический размер. Вы должны получить намного лучших результатов от использования типов фиксированного размера, например, Matrix4d, Vector4d.

Кроме того, убедитесь, что вы компилируете так, чтобы код можно было векторизовать; см. соответствующую документацию Eigen .

Подумайте об использовании библиотеки расширений Direct3D (D3DXMATRIX и т. Д.): Все в порядке (если немного старомодно) для графической геометрии (преобразования 4x4 и т. Д.), Но, безусловно, не ускоряется с помощью GPU (просто старый добрый SSE, я думаю, ). Кроме того, обратите внимание, что это только точность с плавающей запятой (вы, кажется, настроены на использование double). Лично я бы предпочел использовать Eigen, если я не кодировал приложение Direct3D.

10 голосов
/ 12 июня 2011

Убедитесь, что оптимизация компилятора включена (например, по крайней мере -O2 на gcc). Eigen сильно шаблонизирован и не будет работать очень хорошо, если вы не включите оптимизацию.

9 голосов
/ 01 июня 2011

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

for (int i=0;i<pointVector.size();i++ )
{
   Eigen::MatrixXd outcome = (rotation*scale)* (*pointVector[i])  + translation;

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

Eigen::MatrixXd tmp = rotation*scale;
for (int i=0;i<pointVector.size();i++ )
{
   Eigen::MatrixXd outcome = tmp*(*pointVector[i])  + translation;

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

8 голосов
/ 01 июня 2011

Какую версию Eigen вы используете? Недавно они выпустили 3.0.1, которая должна быть быстрее, чем 2.x. Также убедитесь, что вы немного поиграли с опциями компилятора. Например, убедитесь, что SSE используется в Visual Studio:

C / C ++ -> Генерация кода -> Включить расширенный набор команд

2 голосов
/ 19 октября 2013

Пара баллов.

  1. Почему вы умножаете масштаб вращения * внутри цикла, когда этот продукт будет иметь одинаковое значение на каждой итерации? Это много потраченных впустую усилий.

  2. Вы используете матрицы динамического размера, а не матрицы фиксированного размера. Кто-то уже упоминал об этом, и вы сказали, что сбрили 2 сек.

  3. Вы передаете аргументы как вектор указателей на матрицы. Это добавляет дополнительную косвенность указателя и разрушает любую гарантию локальности данных, что приведет к низкой производительности кэша.

  4. Надеюсь, это не оскорбительно, но вы компилируете в Release или Debug? Eigen очень медленный в сборках отладки, потому что он использует множество тривиальных шаблонных функций, которые оптимизированы вне выпуска, но остаются в отладке.

Глядя на ваш код, я не решаюсь винить Эйгена в проблемах с производительностью. Тем не менее, большинство библиотек линейной алгебры (включая Eigen) на самом деле не предназначены для вашего случая использования множества крошечных матриц. В общем, Eigen будет лучше оптимизирован для матриц размером 100x100 или более. Вам может быть лучше использовать собственный класс матрицы или математические вспомогательные классы DirectX. Математические классы DirectX полностью независимы от вашей видеокарты.

0 голосов
/ 01 июня 2011

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

...