Гарантируются ли реализации BLAS одинаковыми результатами?


17

Учитывая две разные реализации BLAS, можем ли мы ожидать, что они будут делать одни и те же вычисления с плавающей запятой и возвращать одинаковые результаты? Или может случиться, например, что скалярное произведение вычисляется как а один - как ( x 1 y 1 + x 2 y 2 ) + ( х 3 у 3 + х 4

((Икс1Y1+Икс2Y2)+Икс3Y3)+Икс4Y4
поэтому, возможно, дать другой результат в арифметике IEEE с плавающей запятой?
(Икс1Y1+Икс2Y2)+(Икс3Y3+Икс4Y4),

1
В этой теме есть некоторые претензии к качеству BLAS , поищите CBLAS на странице. Это говорит о том, что они не только не дают одинакового результата, но не все они достаточно точны для любой задачи ...
Сабольч

Ответы:


15

Нет, это не гарантировано. Если вы используете NETLIB BLAS без каких-либо оптимизаций, в большинстве случаев верно, что результаты совпадают. Но для любого практического использования BLAS и LAPACK используется высокооптимизированный параллельный BLAS. Распараллеливание приводит к тому, что, даже если оно работает только параллельно внутри векторных регистров ЦП, меняется порядок вычисления отдельных членов и изменяется порядок суммирования. Теперь из отсутствующего ассоциативного свойства в стандарте IEEE следует, что результаты не совпадают. Так что именно то, что вы упомянули, может произойти.

В NETLIB BLAS скалярное произведение является только циклом for, развернутым в 5 раз:

DO I = MP1,N,5
          DTEMP = DTEMP + DX(I)*DY(I) + DX(I+1)*DY(I+1) +
     $            DX(I+2)*DY(I+2) + DX(I+3)*DY(I+3) + DX(I+4)*DY(I+4)
END DO

и это зависит от компилятора, если каждое умножение добавляется в DTEMP немедленно или если все 5 компонентов суммируются первыми и затем добавляются в DTEMP. В OpenBLAS ядро ​​зависит от архитектуры:

 __asm__  __volatile__
    (
    "vxorpd     %%ymm4, %%ymm4, %%ymm4               \n\t"
    "vxorpd     %%ymm5, %%ymm5, %%ymm5               \n\t"
    "vxorpd     %%ymm6, %%ymm6, %%ymm6               \n\t"
    "vxorpd     %%ymm7, %%ymm7, %%ymm7               \n\t"

    ".align 16                           \n\t"
    "1:                          \n\t"
        "vmovups                  (%2,%0,8), %%ymm12         \n\t"  // 2 * x
        "vmovups                32(%2,%0,8), %%ymm13         \n\t"  // 2 * x
        "vmovups                64(%2,%0,8), %%ymm14         \n\t"  // 2 * x
        "vmovups                96(%2,%0,8), %%ymm15         \n\t"  // 2 * x

    "vmulpd      (%3,%0,8), %%ymm12, %%ymm12 \n\t"  // 2 * y
    "vmulpd    32(%3,%0,8), %%ymm13, %%ymm13 \n\t"  // 2 * y
    "vmulpd    64(%3,%0,8), %%ymm14, %%ymm14 \n\t"  // 2 * y
    "vmulpd    96(%3,%0,8), %%ymm15, %%ymm15 \n\t"  // 2 * y

    "vaddpd      %%ymm4 , %%ymm12, %%ymm4 \n\t"  // 2 * y
    "vaddpd      %%ymm5 , %%ymm13, %%ymm5 \n\t"  // 2 * y
    "vaddpd      %%ymm6 , %%ymm14, %%ymm6 \n\t"  // 2 * y
    "vaddpd      %%ymm7 , %%ymm15, %%ymm7 \n\t"  // 2 * y

    "addq       $16 , %0	  	     \n\t"
	"subq	        $16 , %1            \n\t"      
    "jnz        1b                   \n\t"
...

который разбивает скалярное произведение на маленькие скалярные произведения длины 4 и суммирует их.

При использовании других типичных реализаций BLAS, таких как ATLAS, MKL, ESSL, ... эта проблема остается той же, поскольку каждая реализация BLAS использует различные оптимизации для получения быстрого кода. Но, насколько я знаю, нужен искусственный пример, чтобы вызвать действительно ошибочные результаты.

Если необходимо, чтобы библиотека BLAS возвращала для тех же результатов (побитовых и одинаковых), необходимо использовать воспроизводимую библиотеку BLAS, такую ​​как:


8

Краткий ответ

Если две реализации BLAS написаны для выполнения операций в одном и том же порядке, а библиотеки были скомпилированы с использованием одних и тех же флагов компилятора и с одинаковым компилятором, то они дадут вам один и тот же результат. Арифметика с плавающей запятой не случайна, поэтому две идентичные реализации дадут одинаковые результаты.

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

Более длинный ответ

IEEE также определяет порядок, в котором эти операции выполняются, в дополнение к тому, как должна вести себя каждая операция. Однако, если вы компилируете свою реализацию BLAS с такими опциями, как «-ffast-math», компилятор может выполнять преобразования, которые были бы истинными в точной арифметике, но не «правильными» в плавающей точке IEEE. Канонический пример - неассоциативность сложения с плавающей запятой, как вы указали. При более агрессивных настройках оптимизации будет предполагаться ассоциативность, и процессор будет делать как можно больше параллельно, переупорядочивая операции.

a+б*с


3
«Арифметика с плавающей точкой не случайна» . Грустно, что это должно быть прямо заявлено, но кажется, что слишком многие люди думают, что это ...
труба

Что ж, непредсказуемый и случайный вид очень похожи, и многие вводные классы программирования говорят «никогда не сравнивайте числа с плавающей точкой на равенство», что создает впечатление, что на точное значение нельзя полагаться так же, как на целые числа.
Тайлер Олсен

@TylerOlsen Это не имеет отношения к вопросу, и не потому, что эти классы говорят такие вещи, но IIRC, раньше был класс ошибок компилятора, где нельзя полагаться на равенство. Например, иногда if (x == 0) assert(x == 0) может произойти сбой, который с определенной точки зрения так же хорош, как и случайный.
Кирилл

@Kirill Извините, я просто пытался подчеркнуть, что многие люди никогда не узнают, как работает плавающая точка. Что касается исторического момента, это немного ужасно, но, должно быть, оно было решено до того, как я попал в игру.
Тайлер Олсен

@TylerOlsen Ой, мой пример неверен. Так и должно быть if (x != 0) assert(x != 0)из-за арифметики с повышенной точностью.
Кирилл

4

В общем нет. Оставляя в стороне ассоциативность, выбор флагов компилятора (например, включение инструкций SIMD, использование сложного умножения и т. Д.) Или аппаратного обеспечения (например, используется ли расширенная точность ) может привести к различным результатам.

Есть некоторые попытки получить воспроизводимые реализации BLAS. См. ReproBLAS и ExBLAS для получения дополнительной информации.


1
См. Также функцию условной числовой воспроизводимости (CNR) в последних версиях Intel MKL BLAS. Поймите, что получение такого уровня воспроизводимости, как правило, замедляет ваши вычисления и может сильно их замедлять!
Брайан Борхерс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.