Pertimbangkan tes kecepatan sederhana berikut untuk arrayfun
:
T = 4000;
N = 500;
x = randn(T, N);
Func1 = @(a) (3*a^2 + 2*a - 1);
tic
Soln1 = ones(T, N);
for t = 1:T
for n = 1:N
Soln1(t, n) = Func1(x(t, n));
end
end
toc
tic
Soln2 = arrayfun(Func1, x);
toc
Di komputer saya (Matlab 2011b di Linux Mint 12), output dari pengujian ini adalah:
Elapsed time is 1.020689 seconds.
Elapsed time is 9.248388 seconds.
Apa itu?!? arrayfun
, meskipun memang solusi yang tampak lebih bersih, urutan besarnya lebih lambat. Apa yang terjadi disini?
Selanjutnya, saya melakukan gaya pengujian yang serupa cellfun
dan menemukan itu menjadi sekitar 3 kali lebih lambat dari loop eksplisit. Sekali lagi, hasil ini berlawanan dengan yang saya harapkan.
Pertanyaan saya adalah: Mengapa arrayfun
dan cellfun
jauh lebih lambat? Dan mengingat ini, apakah ada alasan bagus untuk menggunakannya (selain untuk membuat kode terlihat bagus)?
Catatan: Saya berbicara tentang versi standar di arrayfun
sini, BUKAN versi GPU dari kotak alat pemrosesan paralel.
EDIT: Untuk memperjelas, saya sadar bahwa di Func1
atas dapat vektorisasi seperti yang ditunjukkan oleh Oli. Saya hanya memilihnya karena menghasilkan tes kecepatan sederhana untuk tujuan pertanyaan sebenarnya.
EDIT: Mengikuti saran grungetta, saya melakukan tes ulang dengan feature accel off
. Hasilnya adalah:
Elapsed time is 28.183422 seconds.
Elapsed time is 23.525251 seconds.
Dengan kata lain, akan terlihat bahwa sebagian besar perbedaannya adalah akselerator JIT melakukan pekerjaan yang jauh lebih baik untuk mempercepat for
loop eksplisit daripada yang dilakukannya arrayfun
. Ini tampak aneh bagi saya, karena arrayfun
sebenarnya memberikan lebih banyak informasi, yaitu, penggunaannya mengungkapkan bahwa urutan panggilan ke Func1
tidak penting. Juga, saya mencatat bahwa apakah akselerator JIT dihidupkan atau dimatikan, sistem saya hanya pernah menggunakan satu CPU ...
sumber
Jawaban:
Anda bisa mendapatkan ide dengan menjalankan versi lain dari kode Anda. Pertimbangkan untuk menulis perhitungan secara eksplisit, daripada menggunakan fungsi dalam loop Anda
Waktu untuk menghitung di komputer saya:
Sekarang, meskipun solusi 'vektorisasi' sepenuhnya jelas merupakan yang tercepat, Anda dapat melihat bahwa menentukan fungsi yang akan dipanggil untuk setiap entri x adalah biaya tambahan yang sangat besar . Hanya secara eksplisit menulis perhitungan memberi kami faktor kecepatan 5. Saya rasa ini menunjukkan bahwa MATLABs JIT compiler tidak mendukung fungsi inline . Menurut jawaban gnovice di sana, sebenarnya lebih baik menulis fungsi normal daripada yang anonim. Cobalah.
Langkah selanjutnya - hapus (vektorisasi) loop dalam:
Faktor lain 5 percepatan: ada sesuatu dalam pernyataan itu yang mengatakan Anda harus menghindari loop di MATLAB ... Atau benarkah? Lihat ini kalau begitu
Lebih dekat dengan versi vektorisasi 'sepenuhnya'. Matlab menyimpan matriks berdasarkan kolom. Anda harus selalu (jika mungkin) menyusun komputasi Anda menjadi 'kolom-bijaksana' vektor.
Kita bisa kembali ke Soln3 sekarang. Urutan loop ada 'baris-bijaksana'. Mari kita ubah
Lebih baik, tapi tetap sangat buruk. Putaran tunggal - bagus. Putaran ganda - buruk. Saya kira MATLAB melakukan beberapa pekerjaan yang layak untuk meningkatkan kinerja loop, tetapi overhead loop masih ada. Jika Anda memiliki pekerjaan yang lebih berat di dalam, Anda tidak akan menyadarinya. Tetapi karena komputasi ini dibatasi bandwidth memori, Anda akan melihat overhead loop. Dan Anda bahkan akan lebih jelas melihat overhead pemanggilan Func1 di sana.
Jadi ada apa dengan arrayfun? Tidak ada fungsi inlinig di sana, jadi banyak overhead. Tetapi mengapa jauh lebih buruk daripada loop bersarang ganda? Sebenarnya topik penggunaan cellfun / arrayfun sudah banyak dibahas berkali-kali (misalnya disini , disini , disini dan disini ). Fungsi-fungsi ini lambat sekali, Anda tidak dapat menggunakannya untuk perhitungan halus seperti itu. Anda dapat menggunakannya untuk singkatnya kode dan konversi mewah antara sel dan array. Tetapi fungsinya harus lebih berat dari yang Anda tulis:
Perhatikan bahwa Soln7 sekarang adalah sel .. terkadang itu berguna. Kinerja kode cukup baik sekarang, dan jika Anda membutuhkan sel sebagai keluaran, Anda tidak perlu mengonversi matriks Anda setelah Anda menggunakan solusi vektor penuh.
Jadi mengapa arrayfun lebih lambat dari struktur loop sederhana? Sayangnya, kami tidak dapat mengatakan dengan pasti, karena tidak ada kode sumber yang tersedia. Anda hanya dapat menebaknya karena arrayfun adalah fungsi bertujuan umum, yang menangani semua jenis struktur data dan argumen yang berbeda, tidak harus sangat cepat dalam kasus sederhana, yang dapat Anda ekspresikan secara langsung sebagai sarang loop. Dari mana datangnya biaya overhead, kita tidak bisa tahu. Bisakah overhead dihindari dengan implementasi yang lebih baik? Mungkin tidak. Tapi sayangnya satu-satunya hal yang dapat kita lakukan adalah mempelajari kinerja untuk mengidentifikasi kasus-kasus, di mana itu bekerja dengan baik, dan di mana tidak.
Perbarui Karena waktu pelaksanaan tes ini singkat, untuk mendapatkan hasil yang andal, saya menambahkan sekarang putaran di sekitar tes:
Beberapa waktu yang diberikan di bawah ini:
Anda melihat bahwa arrayfun masih buruk, tetapi setidaknya tidak tiga kali lipat lebih buruk daripada solusi vektor. Di sisi lain, satu loop dengan perhitungan berdasarkan kolom secepat versi vektor penuh ... Itu semua dilakukan pada satu CPU. Hasil untuk Soln5 dan Soln7 tidak berubah jika saya beralih ke 2 core - Dalam Soln5 saya harus menggunakan parfor untuk membuatnya diparalelkan. Lupakan tentang speedup ... Soln7 tidak berjalan secara paralel karena arrayfun tidak berjalan secara paralel. Versi vektor Olis di sisi lain:
sumber
cellfun
diimplementasikan sebagai file MEX (dengan kode sumber C tersedia di sampingnya). Sebenarnya cukup mudah. Tentu saja itu hanya mendukung penerapan salah satu dari 6 fungsi hard-coded (Anda tidak bisa melewatkan sebuah pegangan fungsi, hanya sebuah string dengan satu nama fungsi)Karena itu!!!!
bukan
gpuarray
tipe;Yang perlu Anda lakukan hanyalah
sumber
gpuarray
. Hampir pasti itulah mengapa jawaban ini tidak disukai.gpuarray
hanya didukung untuk kartu grafis nVidia. Jika mereka tidak memiliki perangkat keras seperti itu, maka saran Anda (atau kekurangan) tidak ada artinya. -1