Dokumen ini menjelaskan semantik penyiaran XLA.
Apa itu penyiaran?
Penyiaran adalah proses membuat array dengan bentuk yang berbeda memiliki bentuk yang kompatibel untuk operasi aritmatika. Terminologi ini dipinjam dari penyiaran NumPy.
Penyiaran mungkin diperlukan untuk operasi antara array multidimensi dengan peringkat yang berbeda, atau antara array multidimensi dengan bentuk yang berbeda tetapi kompatibel. Pertimbangkan penambahan X+v dengan X adalah matriks (array dengan 2 dimensi) dan v adalah vektor (array dengan 1 dimensi). Untuk melakukan penambahan per elemen, XLA perlu "menyiarkan" vektor v ke jumlah dimensi yang sama dengan matriks X, dengan mereplikasi v beberapa kali. Panjang vektor harus cocok dengan setidaknya salah satu dimensi matriks.
Contoh:
|1 2 3| + |7 8 9|
|4 5 6|
Dimensi matriks adalah (2,3), dan dimensi vektor adalah (3). Vektor disiarkan dengan mereplikasinya di seluruh baris untuk mendapatkan:
|1 2 3| + |7 8 9| = |8 10 12|
|4 5 6| |7 8 9| |11 13 15|
Di NumPy, hal ini disebut penyiaran.
Prinsip
Bahasa XLA seketat dan sejelas mungkin, menghindari fitur "ajaib" yang implisit. Fitur tersebut mungkin membuat beberapa komputasi sedikit lebih mudah ditentukan, tetapi dengan mengorbankan lebih banyak asumsi yang dimasukkan ke dalam kode pengguna yang akan sulit diubah dalam jangka panjang. Jika perlu, fitur ajaib implisit dapat ditambahkan dalam wrapper tingkat klien.
Terkait penyiaran, XLA memerlukan spesifikasi penyiaran eksplisit pada operasi antar-array dengan peringkat yang berbeda. Hal ini berbeda dengan NumPy, yang menyimpulkan spesifikasi jika memungkinkan.
Menyiarkan array berdimensi lebih rendah ke array berdimensi lebih tinggi
Skalar selalu dapat disiarkan melalui array tanpa spesifikasi eksplisit dimensi siaran. Operasi biner per elemen antara skalar dan array berarti menerapkan operasi dengan skalar ke setiap elemen dalam array. Misalnya, menambahkan skalar ke matriks berarti menghasilkan matriks yang setiap elemennya adalah jumlah skalar dan elemen yang sesuai dari matriks input.
|1 2 3| + 7 = |8 9 10|
|4 5 6| |11 12 13|
Sebagian besar kebutuhan penyiaran dapat ditangkap dengan menggunakan tuple dimensi pada operasi biner. Jika input ke operasi memiliki peringkat yang berbeda, tuple penyiaran ini menentukan dimensi dalam array berdimensi lebih tinggi yang akan dicocokkan dengan array berdimensi lebih rendah.
Pertimbangkan contoh sebelumnya. Daripada menambahkan skalar ke matriks (2,3), tambahkan vektor dimensi (3) ke matriks dimensi (2,3). Tanpa menentukan siaran, operasi ini tidak valid. Untuk meminta penambahan matriks-vektor dengan benar, tentukan dimensi penyiaran menjadi (1), yang berarti dimensi vektor cocok dengan dimensi 1 matriks. Dalam 2D, jika dimensi 0 mewakili baris dan dimensi 1 mewakili kolom, artinya setiap elemen vektor menjadi kolom berukuran yang cocok dengan jumlah baris dalam matriks:
|7 8 9| ==> |7 8 9|
|7 8 9|
Sebagai contoh yang lebih kompleks, pertimbangkan untuk menambahkan vektor 3 elemen (dimensi (3)) ke matriks 3x3 (dimensi (3,3)). Ada dua cara penyiaran dapat terjadi untuk contoh ini:
(1) Dimensi siaran 1 dapat digunakan. Setiap elemen vektor menjadi kolom dan vektor diduplikasi untuk setiap baris dalam matriks.
|7 8 9| ==> |7 8 9|
|7 8 9|
|7 8 9|
(2) Dimensi penyiaran 0 dapat digunakan. Setiap elemen vektor menjadi baris dan vektor diduplikasi untuk setiap kolom dalam matriks.
|7| ==> |7 7 7|
|8| |8 8 8|
|9| |9 9 9|
Dimensi penyiaran dapat berupa tuple yang menjelaskan cara bentuk berdimensi lebih kecil disiarkan ke bentuk berdimensi lebih besar. Misalnya, jika ada kuboid 2x3x4 dan matriks 3x4, tuple penyiaran (1,2) berarti mencocokkan matriks dengan dimensi 1 dan 2 kuboid.
Siaran jenis ini digunakan dalam operasi biner di XlaBuilder, jika argumen
broadcast_dimensions diberikan. Misalnya, lihat
XlaBuilder::Add.
Dalam kode sumber XLA, jenis penyiaran ini terkadang disebut penyiaran "InDim".
Definisi formal
Atribut penyiaran memungkinkan mencocokkan array berdimensi lebih rendah dengan array berdimensi lebih tinggi dengan menentukan dimensi array berdimensi lebih tinggi yang akan dicocokkan. Misalnya, untuk array dengan dimensi MxNxPxQ, vektor dengan dimensi T dapat dicocokkan sebagai berikut:
MxNxPxQ
dim 3: T
dim 2: T
dim 1: T
dim 0: T
Dalam setiap kasus, T harus sama dengan dimensi yang cocok dari array berdimensi lebih tinggi. Nilai vektor kemudian disiarkan dari dimensi yang cocok ke semua dimensi lainnya.
Untuk mencocokkan matriks TxV ke array MxNxPxQ, sepasang dimensi penyiaran digunakan:
MxNxPxQ
dim 2,3: T V
dim 1,2: T V
dim 0,3: T V
etc...
Urutan dimensi dalam tuple penyiaran harus berupa urutan yang diharapkan untuk mencocokkan dimensi array berdimensi lebih rendah dengan dimensi array berdimensi lebih tinggi. Elemen pertama dalam tuple menentukan dimensi dalam array berdimensi lebih tinggi yang harus cocok dengan dimensi 0 dalam array berdimensi lebih rendah. Elemen kedua dalam tuple menentukan dimensi dalam array berdimensi lebih tinggi yang harus cocok dengan dimensi 1 dalam array berdimensi lebih rendah, dan seterusnya. Urutan dimensi siaran harus meningkat secara ketat. Misalnya, dalam contoh sebelumnya, mencocokkan V dengan N dan T dengan P adalah ilegal; mencocokkan V dengan P dan N juga ilegal.
Menyiarkan array berdimensi serupa dengan dimensi degenerasi
Masalah terkait adalah menyiarkan dua array yang memiliki jumlah dimensi yang sama, tetapi ukuran dimensi yang berbeda. Seperti NumPy, hal ini hanya dapat dilakukan jika array kompatibel. Dua array kompatibel jika semua dimensinya kompatibel. Dua dimensi kompatibel jika:
- Keduanya sama, atau
- Salah satunya adalah 1 (dimensi "degenerate")
Saat dua array yang kompatibel ditemukan, bentuk hasilnya memiliki nilai maksimum dari dua input di setiap indeks dimensi.
Contoh:
- (2,1) dan (2,3) menyiarkan ke (2,3).
- (1,2,5) dan (7,2,5) disiarkan ke (7,2,5).
- (7,2,5) dan (7,1,5) disiarkan ke (7,2,5).
- (7,2,5) dan (7,2,6) tidak kompatibel dan tidak dapat disiarkan.
Kasus khusus muncul, dan juga didukung, di mana setiap array input memiliki dimensi degeneratif pada indeks yang berbeda. Dalam hal ini, hasilnya adalah "operasi luar": (2,1) dan (1,3) disiarkan ke (2,3). Untuk contoh lainnya, lihat dokumentasi NumPy tentang penyiaran.
Komposisi siaran
Penyiaran array berdimensi lebih rendah ke array berdimensi lebih tinggi dan penyiaran menggunakan dimensi degeneratif dapat dilakukan dalam operasi biner yang sama. Misalnya, vektor berukuran 4 dan matriks berukuran 1x2 dapat ditambahkan bersama menggunakan dimensi siaran nilai (0):
|1 2 3 4| + [5 6] // [5 6] is a 1x2 matrix, not a vector.
Pertama, vektor disiarkan hingga 2 dimensi (matriks) menggunakan dimensi siaran. Satu nilai (0) dalam dimensi siaran menunjukkan bahwa dimensi nol vektor cocok dengan dimensi nol matriks. Hal ini menghasilkan matriks berukuran 4xM dengan nilai M dipilih agar sesuai dengan ukuran dimensi yang sesuai dalam array 1x2. Oleh karena itu, matriks 4x2 dihasilkan:
|1 1| + [5 6]
|2 2|
|3 3|
|4 4|
Kemudian, "degenerate dimension broadcasting" menyiarkan dimensi nol matriks 1x2 agar sesuai dengan ukuran dimensi yang sesuai di sisi kanan:
|1 1| + |5 6| |6 7|
|2 2| + |5 6| = |7 8|
|3 3| + |5 6| |8 9|
|4 4| + |5 6| |9 10|
Contoh yang lebih rumit adalah matriks berukuran 1x2 yang ditambahkan ke array berukuran 4x3x1 menggunakan dimensi siaran (1, 2). Pertama, matriks 1x2 disiarkan hingga 3 dimensi menggunakan dimensi siaran untuk menghasilkan array Mx1x2 perantara dengan ukuran dimensi M ditentukan oleh ukuran operand yang lebih besar (array 4x3x1) yang menghasilkan array perantara 4x1x2. M berada di dimensi 0 (dimensi paling kiri) karena dimensi 1 dan 2 dipetakan ke dimensi matriks 1x2 asli sebagai dimensi siaran (1, 2). Array perantara ini dapat ditambahkan ke matriks 4x3x1 menggunakan penyiaran dimensi degeneratif untuk menghasilkan hasil array 4x3x2.