Исправить арифметическую ошибку в распределенной версии

Я инвертирую матрицу с помощью факторизации Холецкого, в распределенной среде, как это обсуждалось Вот. Мой код работает нормально, но чтобы проверить, что мой распределенный проект дает правильные результаты, мне пришлось сравнить его с серийной версией. Результаты не совсем такие же!

Например, последние пять ячеек матрицы результата:

serial gives:
-250207683.634793 -1353198687.861288 2816966067.598196 -144344843844.616425 323890119928.788757
distributed gives:
-250207683.634692 -1353198687.861386 2816966067.598891 -144344843844.617096 323890119928.788757

У меня был пост в Форум Intel об этом, но ответ, который я получил, заключался в том, чтобы получить одинаковые результаты во всех исполнениях, которые я сделаю с распределенной версией, что я уже имел. Кажется, они (в другой ветке) не могут ответить на это:

Как получить одинаковые результаты между последовательным и распределенным исполнением? Это возможно? Это приведет к исправлению арифметической ошибки.

Я попытался установить это: mkl_cbwr_set(MKL_CBWR_AVX); и используя mkl_malloc(), чтобы выровнять память, но ничего не изменилось. Я получу те же результаты, только в том случае, если я создам один процесс для распределенной версии (что сделает его почти последовательным)!

Распределенные процедуры, которые я называю: pdpotrf () а также pdpotri ().

Последовательные процедуры, которые я называю: dpotrf () а также dpotri ().

2

Решение

Ваши различия, кажется, появляются примерно на 12-й день. Поскольку арифметика с плавающей точкой не является действительно ассоциативной (то есть арифметика f-p не гарантирует, что a+(b+c) == (a+b)+c), и поскольку параллельное выполнение, как правило, не дает детерминированного порядка применения операций, эти небольшие различия типичны для распараллеленных числовых кодов по сравнению с их последовательными эквивалентами. Действительно, вы можете наблюдать тот же порядок различий при работе на другом количестве процессоров, скажем, 4 против 8.

К сожалению, простой способ получить детерминированные результаты — придерживаться последовательного выполнения. Чтобы получить детерминированные результаты от параллельного выполнения, необходимо приложить значительные усилия, чтобы быть очень точным в отношении порядка выполнения операций вплоть до последнего + или же * что почти наверняка исключает использование большинства числовых библиотек и приводит к тщательному ручному кодированию больших числовых подпрограмм.

В большинстве случаев, с которыми я столкнулся с точностью входных данных, часто получаемых с датчиков, не стоит беспокоиться о 12-й или более поздней версии s.f. Я не знаю, что означают ваши цифры, но для многих ученых и инженеров равенство с 4-й или 5-й СФ достаточно для всех практических целей. Другое дело для математиков …

4

Другие решения

Поскольку в другом ответе упоминается, что получение одинаковых результатов между последовательным и распределенным не гарантируется. Одним из распространенных методов работы с HPC / распределенными рабочими нагрузками является проверка решения. Существует ряд методов, от вычисления процентной ошибки до более сложных схем проверки, таких как используется HPL. Вот простая функция C ++, которая вычисляет процентную ошибку. Как отмечает @HighPerformanceMark в своем посте, анализ такого рода числовых ошибок невероятно сложен; Это очень простой метод, и в Интернете доступно много информации по этой теме.

#include <iostream>
#include <cmath>

double calc_error(double a,double x)
{
return std::abs(x-a)/std::abs(a);
}
int main(void)
{
double sans[]={-250207683.634793,-1353198687.861288,2816966067.598196,-144344843844.616425, 323890119928.788757};
double pans[]={-250207683.634692, -1353198687.861386, 2816966067.598891, -144344843844.617096, 323890119928.788757};
double err[5];
std::cout<<"Serial Answer,Distributed Answer, Error"<<std::endl;
for (int it=0; it<5; it++) {
err[it]=calc_error(sans[it], pans[it]);
std::cout<<sans[it]<<","<<pans[it]<<","<<err[it]<<"\n";
}
return 0;
}

Который производит этот вывод:

Serial Answer,Distributed Answer, Error
-2.50208e+08,-2.50208e+08,4.03665e-13
-1.3532e+09,-1.3532e+09,7.24136e-14
2.81697e+09,2.81697e+09,2.46631e-13
-1.44345e+11,-1.44345e+11,4.65127e-15
3.2389e+11,3.2389e+11,0

Как вы можете видеть, порядок величины ошибки в каждом случае составляет порядка 10 ^ -13 или меньше, а в одном случае не существует. В зависимости от проблемы, которую вы пытаетесь решить, ошибка такого порядка может считаться приемлемой. Надеемся, что это поможет проиллюстрировать один способ проверки распределенного решения по сравнению с последовательным или, по крайней мере, даст один способ показать, насколько далеко друг от друга параллельный и последовательный алгоритмы.

При проверке ответов на большие проблемы и параллельных алгоритмов также может быть полезным выполнить несколько прогонов параллельного алгоритма, сохранив результаты каждого прогона. Затем вы можете посмотреть, изменяется ли результат и / или ошибка при запуске параллельного алгоритма или он устанавливается со временем.

Показ того, что параллельный алгоритм выдает ошибку в допустимых пороговых значениях за 1000 прогонов (просто пример, чем больше данных, тем лучше для такого рода вещей) для задач различного масштаба, является одним из способов оценки достоверности результата.

В прошлом, когда я проводил тестирование производительности, я замечал дико меняющееся поведение для первых нескольких запусков, пока серверы не «прогрелись». В то время я не удосужился проверить, стабилизировалась ли ошибка результата с течением времени так же, как производительность, но было бы интересно посмотреть.

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector