Struttura di un'operazione XLA
Considera un esempio di HLO:
add.936 = bf16[8,1,1280,16384]{3,2,0,1:T(8,128)(2,1)}
add(exponential.183, broadcast.3115)
È costituito dai seguenti componenti:
- Nome operazione:
add.936- Il nome univoco dell'operazione.
- Forma:
bf16[8,1,1280,16384]- Questa è la forma di output dell'operazione. Qui il dtype è
bf16 e
la forma è
[8,1,1280,16384].
- Questa è la forma di output dell'operazione. Qui il dtype è
bf16 e
la forma è
- Layout (con affiancamento):
3,2,0,1:T(8,128)(2,1)- Descrive come l'array viene memorizzato in memoria.
3,2,0,1indica l'ordine degli assi in memoria (ad es. colonna principale, riga principale e così via) eT(8,128)(2,1)indica il tiling e il padding utilizzati. - Il layout è facoltativo. Se non specificato, non è presente alcun tiling e si presume che le dimensioni siano ordinate dalla più importante alla meno importante.
- Descrive come l'array viene memorizzato in memoria.
- Operazione:
add- L'operazione in corso. In questo caso, è Add, che viene menzionato anche nel nome dell'operazione.
- Argomenti:
exponential.183,broadcast.3115- Questa operazione accetta due argomenti, specificati con i rispettivi nomi univoci.
Vediamo un altro esempio, un'operazione di fusione:
%fusion.3 = bf16[32,32,4096]{2,1,0:T(8,128)(2,1)S(1)}
fusion(bf16[32,32,8192]{2,1,0:T(8,128)(2,1)S(1)} %fusion.32),
kind=kCustom, calls=%all-reduce-scatter.3
Oltre ai componenti descritti in precedenza, è costituito da:
- Attributi:
kindecalls- Questi forniscono maggiori informazioni sull'operazione eseguita, in questo caso: fusione.
- Posizione in memoria (identificatore dello spazio di memoria):
S(1)- Indica lo spazio/la posizione di memoria in cui è archiviato l'array.
S(1)qui indica che questo array si trova in VMEM (su una TPU).
- Indica lo spazio/la posizione di memoria in cui è archiviato l'array.
- Dettagli su forma e layout per l'argomento di input
%fusion.32
Le sezioni seguenti descrivono le forme, il layout e gli identificatori dello spazio di memoria. Puoi scoprire di più sull'affiancamento in Layout affiancato.
Forme
Il proto XLA ShapeProto
(xla_data.proto)
descrive il numero di dimensioni, la dimensione e il tipo di dati di un array
N-dimensionale (array in breve).
Terminologia, notazione e convenzioni
Il numero effettivo di dimensioni di un array è il numero di dimensioni con una dimensione maggiore di 1.
Le dimensioni sono numerate da
0fino aN-1per un array dimensionaleN. La dimensione di una dimensione è un numero intero non negativo. In particolare, la dimensione 0 è valida. I numeri delle dimensioni sono etichette arbitrarie per comodità. L'ordine di questi numeri di dimensione non implica un ordine particolare minore/maggiore nel layout della forma. Il layout è determinato dal protoLayoutProto.Per convenzione, le dimensioni sono elencate in ordine crescente in base al numero della dimensione. Ad esempio, per una matrice tridimensionale di dimensioni
[A x B x C], la dimensione 0 ha dimensioneA, la dimensione 1 ha dimensioneBe la dimensione 2 ha dimensioneC.Alcune utilità in XLA supportano anche l'indicizzazione negativa in stile Python: Dimension -1 è l'ultima dimensione (equivalente a
N-1per un array di dimensioniN). Ad esempio, per l'array tridimensionale descritto sopra, la dimensione -1 ha dimensioneC, la dimensione -2 ha dimensioneBe così via.Gli array bidimensionali, tridimensionali e quadridimensionali spesso hanno lettere specifiche associate alle dimensioni. Ad esempio, per un array 2D:
- dimensione 0:
y - dimensione 1:
x
Per un array 3D:
- dimensione 0:
z - dimensione 1:
y - dimensione 2:
x
Per un array 4D:
- dimensione 0:
p - dimensione 1:
z - dimensione 2:
y - Dimensione 3:
x
- dimensione 0:
Le funzioni nell'API XLA che accettano dimensioni lo fanno in ordine crescente di numero di dimensione. Corrisponde all'ordinamento utilizzato quando si passano le dimensioni come
initializer_list, ad es.ShapeUtil::MakeShape(F32, {A, B, C, D})creerà una forma il cui array di dimensioni è costituito dalla sequenza
[A, B, C, D].
Layout
Il proto LayoutProto descrive come viene rappresentato un array in memoria. Include i seguenti campi:
message LayoutProto {
repeated int64 minor_to_major;
int64 tail_padding_alignment_in_elements;
...
}
Ordinamento delle dimensioni da minore a maggiore
L'unico campo obbligatorio è minor_to_major. Questo campo descrive l'ordine
dalla dimensione secondaria a quella principale all'interno di una forma. I valori in
minor_to_major sono un ordinamento delle dimensioni dell'array (da 0 a N-1
per un array di dimensioni N), con il primo valore che è la dimensione meno importante
fino all'ultimo valore, che è la dimensione più importante. La dimensione meno
importante è quella che cambia più rapidamente quando si scorrono gli
elementi dell'array disposti nella memoria lineare.
Ad esempio, considera la seguente matrice bidimensionale di dimensioni [2 x 3]:
a b c
d e f
Qui la dimensione 0 è la taglia 2 e la dimensione 1 è la taglia 3. Se il campo
minor_to_major nel layout è [0, 1], la dimensione 0 è la
dimensione meno importante e la dimensione 1 è la dimensione più importante. Questo
corrisponde al seguente layout nella memoria lineare:
a d b e c f
Questo ordine delle dimensioni da minore a maggiore, da 0 a N-1, è simile all'ordine column-major
(per le dimensioni bidimensionali). Supponendo un ordinamento monotono delle dimensioni, un altro modo
in cui potremmo fare riferimento a questo layout nel codice è semplicemente "dim 0 is minor".
D'altra parte, se il campo minor_to_major nel layout è [1, 0], il layout nella memoria lineare è:
a b c d e f
Un ordine delle dimensioni da minore a maggiore, da N-1 a 0 per un array
N dimensionale, è simile a row-major (per array bidimensionali). Supponendo un ordinamento
monotonico delle dimensioni, un altro modo in cui potremmo fare riferimento a questo layout nel codice è
semplicemente "dim 0 è principale".
Ordinamento predefinito dal minore al maggiore
Il layout predefinito per le forme appena create è "L'ordine delle dimensioni è
da maggiore a minore" (ovvero [N-1, ..., 0]).
Spaziatura interna
Il campo tail_padding_alignment_in_elements definisce l'allineamento dell'array
affiancato in termini di numero di elementi. Dopo
l'applicazione dell'affiancamento, gli elementi con spaziatura interna verranno aggiunti alla fine del layout finché
il numero totale di elementi non sarà un multiplo di questo valore.
Indicizzazione negli array
La classe IndexUtil in
index_util.h
fornisce utilità per la conversione tra indici multidimensionali e indici lineari
dato una forma e un layout. Gli indici multidimensionali includono un indice int64
per ogni dimensione. Gli indici lineari sono un singolo valore int64 che
viene utilizzato per indicizzare il buffer contenente l'array. Consulta shape_util.h e
layout_util.h nella stessa directory per le utilità che semplificano la creazione e
la manipolazione di forme e layout.
Identificatori dello spazio di memoria
In HLO, ogni array può essere annotato con un identificatore di spazio di memoria, scritto come S(n).
S(0)(spesso omesso) indica la memoria ad alta larghezza di banda (HBM) del dispositivo.S(1)rappresenta la memoria virtuale (VMEM) sul dispositivo.S(2),S(3)e così via corrispondono a spazi di memoria aggiuntivi specifici per il dispositivo.S(5)indica la memoria dell'host.