Biorąc pod uwagę dwie różne implementacje BLAS, czy możemy oczekiwać, że wykonają dokładnie takie same obliczenia zmiennoprzecinkowe i zwrócą te same wyniki? Lub może się zdarzyć, na przykład, że oblicza się produkt skalarny jako i jeden jako co może dać inny wynik w zmiennoprzecinkowym IEEE arytmetyka?
floating-point
blas
Federico Poloni
źródło
źródło
Odpowiedzi:
Nie, to nie jest gwarantowane. Jeśli używasz NETLIB BLAS bez żadnych optymalizacji, to w większości przypadków prawdą jest, że wyniki są takie same. Ale do każdego praktycznego zastosowania BLAS i LAPACK stosuje się wysoce zoptymalizowany równoległy BLAS. Równoległość powoduje, nawet jeśli działa ona równolegle tylko w rejestrach wektorowych CPU, że zmienia się kolejność, w jakiej oceniane są poszczególne warunki, a także zmienia się kolejność sumowania. Teraz z brakującej właściwości asocjacyjnej w standardzie IEEE wynika, że wyniki nie są takie same. Może się zdarzyć dokładnie to, o czym wspomniałeś.
W NETLIB BLAS iloczyn skalarny jest tylko pętlą for rozwiniętą 5-krotnie:
i to od kompilatora zależy, czy każde zwielokrotnienie zostanie dodane do DTEMP natychmiast, czy wszystkie 5 składników zostanie najpierw zsumowane, a następnie dodane do DTEMP. W OpenBLAS jest zależne od architektury bardziej skomplikowane jądro:
który dzieli iloczyn skalarny na małe iloczyny skalarne o długości 4 i sumuje je.
Używając innych typowych implementacji BLAS, takich jak ATLAS, MKL, ESSL, ... ten problem pozostaje ten sam, ponieważ każda implementacja BLAS korzysta z różnych optymalizacji w celu uzyskania szybkiego kodu. Ale o ile mi wiadomo, potrzebny jest sztuczny przykład, aby spowodować naprawdę błędne wyniki.
Jeśli konieczne jest, aby biblioteka BLAS zwróciła te same wyniki (pod względem bitów to samo), należy użyć odtwarzalnej biblioteki BLAS, takiej jak:
źródło
Krótka odpowiedź
Jeśli dwie implementacje BLAS zostały napisane w celu przeprowadzenia operacji w dokładnie tej samej kolejności, a biblioteki zostały skompilowane przy użyciu tych samych flag kompilatora i przy użyciu tego samego kompilatora, to dają ten sam wynik. Arytmetyka zmiennoprzecinkowa nie jest przypadkowa, więc dwie identyczne implementacje dadzą identyczne wyniki.
Istnieje jednak wiele rzeczy, które mogą złamać to zachowanie ze względu na wydajność ...
Dłuższa odpowiedź
IEEE określa także kolejność wykonywania tych operacji, oprócz tego, jak powinna się zachowywać każda operacja. Jeśli jednak skompilujesz swoją implementację BLAS z opcjami takimi jak „-ffast-matematyka”, kompilator może wykonać transformacje, które byłyby prawdziwe w dokładnej arytmetyce, ale nie byłyby „poprawne” w zmiennoprzecinkowym IEEE. Jak zauważyłeś, kanonicznym przykładem jest brak asocjatywności dodawania zmiennoprzecinkowego. Przy bardziej agresywnych ustawieniach optymalizacji założona zostanie asocjatywność, a procesor wykona tyle czynności równolegle, jak to możliwe, poprzez ponowne uporządkowanie operacji.
źródło
if (x == 0) assert(x == 0)
może czasami zawieść, co z pewnego punktu widzenia jest tak dobre, jak losowe.if (x != 0) assert(x != 0)
powodu arytmetyki o rozszerzonej precyzji.Ogólnie nie. Pomijając skojarzenia, wybór flag kompilatora (na przykład włączenie instrukcji SIMD, użycie stopionego dodawania wielokrotnego itd.) Lub sprzętu (np. Czy używana jest zwiększona precyzja ) może dawać różne wyniki.
Istnieją pewne wysiłki, aby uzyskać odtwarzalne implementacje BLAS. Aby uzyskać więcej informacji, zobacz ReproBLAS i ExBLAS .
źródło