Backend akselerator

Menjelaskan penghitungan Tensor cukup mudah, tetapi kapan dan bagaimana penghitungan tersebut dilakukan akan bergantung pada backend mana yang digunakan untuk Tensor dan kapan hasilnya diperlukan pada CPU host.

Di balik layar, operasi pada Tensor dikirim ke akselerator seperti GPU atau TPU , atau dijalankan di CPU saat tidak ada akselerator yang tersedia. Hal ini terjadi secara otomatis untuk Anda, dan memudahkan Anda melakukan penghitungan paralel yang rumit menggunakan antarmuka tingkat tinggi. Namun, akan berguna untuk memahami bagaimana pengiriman ini terjadi dan dapat menyesuaikannya untuk performa optimal.

Swift untuk TensorFlow memiliki dua backend untuk melakukan komputasi yang dipercepat: mode bersemangat TensorFlow dan X10. Backend defaultnya adalah mode bersemangat TensorFlow, tetapi itu bisa diganti. Tersedia tutorial interaktif yang memandu Anda dalam menggunakan berbagai backend ini.

Mode bersemangat TensorFlow

Backend mode bersemangat TensorFlow memanfaatkan TensorFlow C API untuk mengirim setiap operasi Tensor ke GPU atau CPU saat ditemui. Hasil operasi tersebut kemudian diambil dan diteruskan ke operasi berikutnya.

Pengiriman operasi demi operasi ini mudah dipahami dan tidak memerlukan konfigurasi eksplisit dalam kode Anda. Namun, dalam banyak kasus, hal ini tidak menghasilkan kinerja yang optimal karena overhead akibat mengirimkan banyak operasi kecil, ditambah dengan kurangnya fusi operasi dan optimalisasi yang dapat terjadi ketika terdapat grafik operasi. Terakhir, mode bersemangat TensorFlow tidak kompatibel dengan TPU, dan hanya dapat digunakan dengan CPU dan GPU.

X10 (pelacakan berbasis XLA)

X10 adalah nama backend Swift untuk TensorFlow yang menggunakan penelusuran tensor lambat dan kompiler pengoptimal XLA untuk dalam banyak kasus meningkatkan kinerja secara signifikan dibandingkan pengiriman operasi demi operasi. Selain itu, ia menambahkan kompatibilitas untuk TPU , akselerator yang secara khusus dioptimalkan untuk jenis penghitungan yang ditemukan dalam model pembelajaran mesin.

Penggunaan X10 untuk penghitungan Tensor bukanlah default, jadi Anda harus ikut serta dalam backend ini. Hal ini dilakukan dengan menentukan bahwa Tensor ditempatkan pada perangkat XLA:

let tensor1 = Tensor<Float>([0.0, 1.0, 2.0], on: Device.defaultXLA)
let tensor2 = Tensor<Float>([1.5, 2.5, 3.5], on: Device.defaultXLA)

Setelah itu, deskripsi penghitungan sama persis dengan mode bersemangat TensorFlow:

let tensor3 = tensor1 + tensor2

Detail lebih lanjut dapat diberikan saat membuat Tensor , seperti jenis akselerator yang akan digunakan dan bahkan akselerator yang mana, jika tersedia beberapa. Misalnya, Tensor dapat dibuat pada perangkat TPU kedua (dengan asumsi Tensor terlihat oleh host tempat program dijalankan) menggunakan yang berikut ini:

let tpuTensor = Tensor<Float>([0.0, 1.0, 2.0], on: Device(kind: .TPU, ordinal: 1, backend: .XLA))

Tidak ada pergerakan implisit Tensor antar perangkat yang dilakukan, jadi jika dua Tensor pada perangkat berbeda digunakan dalam operasi bersama-sama, error runtime akan terjadi. Untuk menyalin konten Tensor secara manual ke perangkat baru, Anda dapat menggunakan penginisialisasi Tensor(copying:to:) . Beberapa struktur berskala lebih besar yang berisi Tensor di dalamnya, seperti model dan pengoptimal, memiliki fungsi pembantu untuk memindahkan semua Tensor interiornya ke perangkat baru dalam satu langkah.

Tidak seperti mode bersemangat TensorFlow, operasi yang menggunakan backend X10 tidak dikirim satu per satu seperti yang ditemui. Sebaliknya, pengiriman ke akselerator hanya dipicu dengan membacakan nilai terhitung kembali ke host atau dengan menempatkan penghalang eksplisit. Cara kerjanya adalah runtime dimulai dari nilai yang dibaca ke host (atau penghitungan terakhir sebelum penghalang manual) dan menelusuri grafik penghitungan yang menghasilkan nilai tersebut.

Grafik yang ditelusuri ini kemudian diubah menjadi representasi perantara XLA HLO dan diteruskan ke kompiler XLA untuk dioptimalkan dan dikompilasi untuk dieksekusi pada akselerator. Dari sana, seluruh perhitungan dikirim ke akselerator dan hasil akhir diperoleh.

Penghitungan adalah proses yang memakan waktu, jadi X10 paling baik digunakan dengan penghitungan paralel besar-besaran yang dinyatakan melalui grafik dan dilakukan berkali-kali. Nilai hash dan caching digunakan sehingga grafik identik hanya dikompilasi satu kali untuk setiap konfigurasi unik.

Untuk model pembelajaran mesin, proses pelatihan sering kali melibatkan perulangan di mana model tersebut menjalani serangkaian penghitungan yang sama berulang kali. Anda ingin setiap lintasan ini dilihat sebagai pengulangan jejak yang sama, bukan satu grafik panjang dengan unit berulang di dalamnya. Hal ini diaktifkan dengan penyisipan manual panggilan ke fungsi LazyTensorBarrier() di lokasi dalam kode tempat Anda ingin pelacakan diakhiri.

Dukungan presisi campuran di X10

Pelatihan dengan presisi campuran melalui X10 didukung dan API tingkat rendah dan tingkat tinggi disediakan untuk mengendalikannya. API tingkat rendah menawarkan dua properti terhitung: toReducedPrecision dan toFullPrecision yang mengonversi antara presisi penuh dan tereduksi, serta isReducedPrecision untuk mengkueri presisi. Selain Tensor , model dan pengoptimal dapat dikonversi antara presisi penuh dan presisi rendah menggunakan API ini.

Perhatikan bahwa konversi ke pengurangan presisi tidak mengubah tipe logika Tensor . Jika t adalah Tensor<Float> , t.toReducedPrecision juga merupakan Tensor<Float> dengan representasi dasar dengan presisi rendah.

Seperti halnya perangkat, operasi antara tensor dengan presisi berbeda tidak diperbolehkan. Hal ini untuk menghindari promosi diam-diam dan tidak diinginkan ke float 32-bit, yang akan sulit dideteksi oleh pengguna.