Le implementazioni BLAS garantiscono lo stesso esatto risultato?


17

Date due diverse implementazioni BLAS, possiamo aspettarci che eseguano esattamente gli stessi calcoli in virgola mobile e restituiscano gli stessi risultati? O può succedere, ad esempio, che uno calcoli un prodotto scalare come e uno come ( x 1 y 1 + x 2 y 2 ) + ( x 3 y 3 + x 4

((X1y1+X2y2)+X3y3)+X4y4
quindi forse dando risultati diversi nell'aritmetica IEEE in virgola mobile?
(X1y1+X2y2)+(X3y3+X4y4),

1
Ci sono alcuni reclami sulla qualità BLAS in questo thread , cerca CBLAS nella pagina. Ciò suggerirebbe che non solo non danno lo stesso risultato, ma non tutti sono abbastanza precisi per qualsiasi compito ...
Szabolcs,

Risposte:


15

No, questo non è garantito. Se si utilizza un BLAS NETLIB senza ottimizzazioni, è quasi vero che i risultati sono gli stessi. Ma per qualsiasi uso pratico di BLAS e LAPACK si usa un BLAS altamente ottimizzato e parallelo. La parallelizzazione provoca, anche se funziona solo in parallelo all'interno dei registri vettoriali di una CPU, che cambia l'ordine di valutazione dei singoli termini e cambia anche l'ordine della somma. Ora segue la proprietà associativa mancante nello standard IEEE che i risultati non sono gli stessi. Quindi può succedere esattamente ciò che hai menzionato.

Nel NETAS BLAS il prodotto scalare è solo un ciclo for srotolato da un fattore 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

e spetta al compilatore se ogni moltiplicazione viene aggiunta immediatamente a DTEMP o se tutti e 5 i componenti vengono sommati per primi e poi aggiunti a DTEMP. In OpenBLAS dipende dall'architettura un kernel più complicato:

 __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"
...

che divide il prodotto scalare in piccoli prodotti scalari di lunghezza 4 e li riassume.

Utilizzando le altre implementazioni BLAS tipiche come ATLAS, MKL, ESSL, ... questo problema rimane lo stesso perché ogni implementazione BLAS utilizza ottimizzazioni diverse per ottenere codice veloce. Ma per quanto ne so uno ha bisogno di un esempio artificiale per causare risultati davvero errati.

Se è necessario che la libreria BLAS ritorni per gli stessi risultati (per quanto riguarda gli stessi bit), è necessario utilizzare una libreria BLAS riproducibile come:


8

La risposta breve

Se le due implementazioni BLAS sono scritte per eseguire le operazioni nello stesso identico ordine e le librerie sono state compilate utilizzando gli stessi flag del compilatore e con lo stesso compilatore, ti daranno lo stesso risultato. L'aritmetica in virgola mobile non è casuale, quindi due implementazioni identiche daranno risultati identici.

Tuttavia, ci sono una varietà di cose che possono interrompere questo comportamento per motivi di prestazioni ...

La risposta più lunga

IEEE specifica anche l' ordine in cui queste operazioni vengono eseguite, oltre a come ciascuna operazione dovrebbe comportarsi. Tuttavia, se si compila l'implementazione BLAS con opzioni come "-ffast-math", il compilatore può eseguire trasformazioni che sarebbero vere nell'aritmetica esatta ma non "corrette" in virgola mobile IEEE. L'esempio canonico è la non associatività dell'aggiunta in virgola mobile, come hai sottolineato. Con le impostazioni di ottimizzazione più aggressive, verrà assunta l'associatività e il processore eseguirà il più possibile in parallelo, riordinando le operazioni.

un'+B*c


3
"L'aritmetica in virgola mobile non è casuale" . È triste che questo debba essere esplicitamente dichiarato, ma sembra che troppe persone pensano che sia ...
pipe

Bene, imprevedibile e casuale sembrano abbastanza simili, e molte classi di programmazione introduttiva dicono "non confrontare mai i float per l'uguaglianza", il che dà l'impressione che il valore esatto non possa essere invocato allo stesso modo degli interi.
Tyler Olsen,

@TylerOlsen Questo non è rilevante per la domanda, e non è per questo che quelle classi dicono cose del genere, ma IIRC, c'era una classe di bug del compilatore in cui l'uguaglianza non poteva essere invocata. Ad esempio, a volte if (x == 0) assert(x == 0) potrebbe fallire, che da un certo punto di vista è buono come casuale.
Kirill

@Kirill Spiacente, stavo semplicemente cercando di sottolineare che molte persone non imparano mai veramente come funziona il virgola mobile. Per quanto riguarda il punto storico, è un po 'terrificante, ma deve essere stato risolto prima di entrare nel gioco.
Tyler Olsen,

@TylerOlsen Oops, il mio esempio è sbagliato. Dovrebbe essere if (x != 0) assert(x != 0), a causa dell'aritmetica di precisione estesa.
Kirill

4

In generale, no. Lasciando da parte l'associatività, la scelta dei flag del compilatore (ad esempio, abilitazione delle istruzioni SIMD, utilizzo dell'aggiunta multipla fusa , ecc.) O dell'hardware (ad es. Se si utilizza la precisione estesa ) può produrre risultati diversi.

Ci sono alcuni sforzi per ottenere implementazioni BLAS riproducibili. Vedere ReproBLAS ed ExBLAS per ulteriori informazioni.


1
Vedi anche la funzionalità di riproducibilità numerica condizionale (CNR) nelle recenti versioni di Intel MKL BLAS. Comprendi che ottenere questo livello di riproducibilità in genere rallenta i tuoi calcoli e può rallentarli molto!
Brian Borchers,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.