Broadcasting adalah aturan yang digunakan PyTorch untuk menjalankan operasi element-wise, yaitu operasi per elemen, pada dua tensor yang bentuknya tidak sama, dengan cara melebarkan dimensi yang ukurannya satu seolah-olah data disalin. Mekanisme ini diwarisi langsung dari NumPy dan menjadi alasan penjumlahan tensor (3, 1) dengan (1, 4) dapat menghasilkan (3, 4) tanpa satu byte penyalinan pun. Topik ini membahas aturan bentuknya, cara menghitung bentuk hasil, perilaku saat aturan dilanggar, dan jebakan operasi in-place yang menyertainya.
Aturan broadcasting#
Aturan broadcasting bekerja dengan menyelaraskan kedua bentuk dari kanan, lalu membandingkan dimensi berpasangan satu per satu. Dua dimensi dinyatakan cocok apabila ukurannya sama, atau salah satunya berukuran 1, atau salah satu bentuk sudah kehabisan dimensi sehingga dianggap berukuran 1. Ukuran hasil setiap dimensi adalah ukuran yang lebih besar di antara keduanya. Contoh berikut disimpan sebagai file broadcasting_dasar.py.
import torch
a = torch.tensor([[1.0], [2.0], [3.0]]) # (3, 1)
b = torch.tensor([[10.0, 20.0, 30.0, 40.0]]) # (1, 4)
c = a + b # (3, 1) + (1, 4) -> (3, 4)
print(c)
print(c.shape)
d = a + 5.0 # (3, 1) + skalar -> (3, 1)
print(d)
print(d.shape)tensor([[11., 21., 31., 41.],
[12., 22., 32., 42.],
[13., 23., 33., 43.]])
torch.Size([3, 4])
tensor([[6.],
[7.],
[8.]])
torch.Size([3, 1])Pada penjumlahan pertama, dimensi kanan mempertemukan 1 dengan 4 sehingga a melebar menjadi empat kolom, sedangkan dimensi kiri mempertemukan 3 dengan 1 sehingga b melebar menjadi tiga baris. Hasilnya (3, 4) berisi penjumlahan setiap baris a dengan setiap kolom b. Pada penjumlahan kedua, skalar 5.0 dianggap berbentuk (), melebar ke seluruh elemen, dan hasilnya tetap (3, 1). Tabel berikut merangkum beberapa kasus yang telah diverifikasi.
| Bentuk A | Bentuk B | Hasil | Alasan |
|---|---|---|---|
(3, 1) | (1, 4) | (3, 4) | setiap dimensi cocok karena salah satunya berukuran 1 |
(2, 3) | (3,) | (2, 3) | dimensi yang kurang dilengkapi angka 1 di sisi kiri |
(2, 3) | () | (2, 3) | skalar melebar ke seluruh elemen |
(3, 4) | (2, 4) | error | dimensi 0 mempertemukan 3 dengan 4, tidak ada yang berukuran 1 |
Demo: menghitung bentuk hasil#
Aturan di atas cukup pendek untuk dihitung manual, tetapi kecepatan menghitung bentuk hasil menentukan kelancaran membaca error bentuk. Jalankan demo berikut, pilih beberapa pasang bentuk yang ada di tabel, kemudian bandingkan keputusan demo dengan tabel tersebut, lalu coba pasangan seperti (3, 1) dengan (4, 1) untuk melihat kegagalannya.
Demo tersebut mengikuti alur yang sama dengan PyTorch: dimensi diselaraskan dari kanan, dimensi yang kurang dilengkapi angka 1, lalu setiap pasangan dimensi dievaluasi menurut aturan cocok, melebar, atau gagal.
Ketika broadcasting gagal#
Broadcasting ditolak apabila ada pasangan dimensi yang ukurannya berbeda dan tidak satu pun berukuran 1. PyTorch menolak operasi tersebut dengan RuntimeError yang menyebut ukuran kedua tensor dan posisi dimensi yang bermasalah, sehingga penyebabnya biasanya terbaca langsung dari pesan error.
import torch
try:
torch.ones(3, 4) + torch.ones(2, 4) # (3, 4) + (2, 4) -> error
except RuntimeError as e:
print("RuntimeError:", e)RuntimeError: The size of tensor a (3) must match the size of tensor b (2) at non-singleton dimension 0Pesan error tersebut menyebut dimensi 0 sebagai lokasi bentrokan dan istilah non-singleton, yakni dimensi yang ukurannya bukan satu, karena hanya dimensi berukuran satu yang boleh dibedakan. Bentrokan terjadi pada dimensi paling kiri, yaitu 3 melawan 4, sementara dimensi kanannya cocok karena sama-sama 4. Pembacaan pesan dari kanan ke kiri mengikuti arah penyelarasan aturan, sehingga kebiasaan ini membantu menemukan pasangan dimensi yang bermasalah dengan cepat.
Jebakan operasi in-place#
Operasi in-place adalah operasi yang menulis hasilnya langsung ke memori tensor asalnya, ditandai akhiran garis bawah seperti add_ atau ditulis sebagai penugasan gabungan seperti +=. Operasi semacam ini menghemat memori, tetapi mengubah tensor asalnya secara permanen, dan perubahannya mudah terlewat bila tensor yang sama digunakan di tempat lain.
import torch
a = torch.zeros(2, 3) # (2, 3)
b = torch.ones(2, 3) # (2, 3)
a += b # in-place: hasil ditulis ke memori a
print(a) # a tidak lagi berisi noltensor([[1., 1., 1.],
[1., 1., 1.]])Nilai a berubah dari nol menjadi satu karena a += b menulis langsung ke memori a, berbeda dengan a = a + b yang membuat tensor baru dan membiarkan a lama utuh. Konsekuensinya makin serius di modul autograd: tensor yang dilacak untuk perhitungan gradien tidak boleh diubah secara in-place, karena nilai lamanya masih dibutuhkan saat gradien dihitung mundur, dan PyTorch menegakkan aturan itu dengan error.
import torch
w = torch.ones(3, requires_grad=True) # (3,), dilacak autograd
try:
w += 1.0 # (3,) += skalar, in-place -> error
except RuntimeError as e:
print("RuntimeError:", e)
hasil = w + 1.0 # (3,), aman: tensor baru, w tetap utuh
print(hasil)RuntimeError: a leaf Variable that requires grad is being used in an in-place operation.
tensor([2., 2., 2.], grad_fn=<AddBackward0>)Ada satu keanehan lain yang patut dicatat: penugasan in-place dengan hasil yang bentuknya membesar ditolak PyTorch, misalnya x += y untuk x berbentuk (3, 1) dan y berbentuk (1, 4) memicu pesan output with shape [3, 1] doesn't match the broadcast shape [3, 4], karena memori x tidak mungkin menampung hasil yang lebih besar. Kebiasaan aman yang dianjurkan adalah menulis ulang bentuk non-in-place seperti x = x + y kecuali ada alasan memori yang kuat, terutama pada kode yang nanti disentuh modul autograd.
Ringkasan#
- Broadcasting menyelaraskan bentuk dari kanan, dan pasangan dimensi cocok bila ukurannya sama atau salah satunya berukuran 1 atau hilang.
- Ukuran hasil tiap dimensi adalah ukuran terbesar dari pasangannya, sehingga
(3, 1) + (1, 4)menghasilkan(3, 4). - Bentrokan dimensi yang tidak kompatibel memicu RuntimeError yang menyebut ukuran kedua tensor dan posisi dimensinya.
- Operasi in-place seperti
x += ymengubah tensor asalnya, ditolak bila hasilnya membesar, dan memicu error pada tensor yang dilacak autograd, sehingga bentukx = x + yadalah kebiasaan yang aman.
Referensi#
- PyTorch documentation — PyTorch — Rujukan API untuk semantik broadcasting dan operasi element-wise tensor.
- Learn the Basics — PyTorch — Tutorial resmi yang bagian Tensors memperkenalkan broadcasting ala NumPy.