Pertanyaan saya: Saya telah memperhatikan bahwa banyak jawaban bagus untuk pertanyaan Matlab di SO sering menggunakan fungsi tersebut bsxfun
. Mengapa?
Motivasi: Dalam dokumentasi Matlab untuk bsxfun
, contoh berikut diberikan:
A = magic(5);
A = bsxfun(@minus, A, mean(A))
Tentu saja kami dapat melakukan operasi yang sama dengan menggunakan:
A = A - (ones(size(A, 1), 1) * mean(A));
Dan faktanya, uji kecepatan sederhana menunjukkan bahwa metode kedua lebih cepat 20%. Jadi mengapa menggunakan metode pertama? Saya menduga ada beberapa keadaan di mana penggunaan bsxfun
akan jauh lebih cepat daripada pendekatan "manual". Saya akan sangat tertarik untuk melihat contoh dari situasi seperti itu dan penjelasan mengapa lebih cepat.
Juga, satu elemen terakhir untuk pertanyaan ini, lagi-lagi dari dokumentasi Matlab untuk bsxfun
: "C = bsxfun (fun, A, B) menerapkan operasi biner elemen demi elemen yang ditentukan oleh fungsi handle fun ke array A dan B, dengan singleton ekspansi diaktifkan. ". Apa arti frasa "dengan perluasan tunggal diaktifkan"?
tic...toc
sekitar baris, kecepatan kode akan bergantung pada keharusan membaca fungsi ke dalam memori.timeit
fungsi di tautan yang Anda / angainor / Dan sediakan.Jawaban:
Ada tiga alasan saya menggunakan
bsxfun
( dokumentasi , link blog )bsxfun
lebih cepat darirepmat
(lihat di bawah)bsxfun
membutuhkan lebih sedikit mengetikbsxfun
, seperti menggunakanaccumarray
, membuat saya merasa nyaman dengan pemahaman saya tentang Matlab.bsxfun
akan mereplikasi larik masukan sepanjang "dimensi tunggal" mereka, yaitu dimensi dengan ukuran larik adalah 1, sehingga cocok dengan ukuran dimensi yang sesuai dari larik lainnya. Inilah yang disebut "ekspasi tunggal". Selain itu, dimensi singleton adalah salah satu yang akan dihapus jika Anda meneleponsqueeze
.Ada kemungkinan bahwa untuk masalah yang sangat kecil,
repmat
pendekatannya lebih cepat - tetapi pada ukuran larik itu, kedua operasi tersebut sangat cepat sehingga kemungkinan besar tidak akan membuat perbedaan apa pun dalam hal kinerja secara keseluruhan. Ada dua alasan penting untukbsxfun
lebih cepat: (1) kalkulasi terjadi dalam kode yang dikompilasi, yang berarti replikasi larik yang sebenarnya tidak pernah terjadi, dan (2)bsxfun
adalah salah satu fungsi Matlab multithread.Saya telah menjalankan perbandingan kecepatan antara
repmat
danbsxfun
dengan R2012b pada laptop saya yang cukup cepat.Bagi saya,
bsxfun
ini sekitar 3 kali lebih cepat darirepmat
. Perbedaannya menjadi lebih jelas jika larik menjadi lebih besarLompatan dalam runtime
repmat
terjadi di sekitar ukuran array 1Mb, yang mungkin ada hubungannya dengan ukuran cache prosesor saya -bsxfun
tidak seburuk lompatan, karena hanya perlu mengalokasikan array output.Di bawah ini Anda menemukan kode yang saya gunakan untuk pengaturan waktu:
n = 300; k=1; %# k=100 for the second graph a = ones(10,1); rr = zeros(n,1); bb=zeros(n,1); ntt=100; tt=zeros(ntt,1); for i=1:n; r = rand(1,i*k); for it=1:ntt; tic, x=bsxfun(@plus,a,r); tt(it)=toc; end; bb(i)=median(tt); for it=1:ntt; tic, y=repmat(a,1,i*k)+repmat(r,10,1); tt(it)=toc; end; rr(i)=median(tt); end
sumber
Dalam kasus saya, saya menggunakan
bsxfun
karena menghindari saya untuk memikirkan masalah kolom atau baris.Untuk menulis contoh Anda:
A = A - (ones(size(A, 1), 1) * mean(A));
Saya harus menyelesaikan beberapa masalah:
1)
size(A,1)
atausize(A,2)
2)
ones(sizes(A,1),1)
atauones(1,sizes(A,1))
3)
ones(size(A, 1), 1) * mean(A)
ataumean(A)*ones(size(A, 1), 1)
4)
mean(A)
ataumean(A,2)
Saat saya menggunakan
bsxfun
, saya hanya perlu menyelesaikan yang terakhir:a)
mean(A)
ataumean(A,2)
Anda mungkin berpikir itu malas atau semacamnya, tetapi ketika saya menggunakan
bsxfun
, saya memiliki lebih sedikit bug dan saya memprogram lebih cepat .Selain itu, lebih pendek, yang meningkatkan kecepatan mengetik dan keterbacaan .
sumber
Pertanyaan yang sangat menarik! Saya baru-baru ini tersandung pada situasi yang persis seperti itu saat menjawab pertanyaan ini . Pertimbangkan kode berikut yang menghitung indeks dari jendela geser ukuran 3 melalui vektor
a
:a = rand(1e7,1); tic; idx = bsxfun(@plus, [0:2]', 1:numel(a)-2); toc % equivalent code from im2col function in MATLAB tic; idx0 = repmat([0:2]', 1, numel(a)-2); idx1 = repmat(1:numel(a)-2, 3, 1); idx2 = idx0+idx1; toc; isequal(idx, idx2) Elapsed time is 0.297987 seconds. Elapsed time is 0.501047 seconds. ans = 1
Dalam hal
bsxfun
ini hampir dua kali lebih cepat! Ini berguna dan cepat karena menghindari alokasi memori secara eksplisit untuk matriksidx0
danidx1
, menyimpannya ke memori, lalu membacanya lagi hanya untuk menambahkannya. Karena bandwidth memori adalah aset berharga dan seringkali menjadi hambatan pada arsitektur saat ini, Anda ingin menggunakannya dengan bijak dan mengurangi persyaratan memori kode Anda untuk meningkatkan kinerja.bsxfun
memungkinkan Anda melakukan hal itu: membuat matriks berdasarkan penerapan operator arbitrer ke semua pasangan elemen dua vektor, alih-alih beroperasi secara eksplisit pada dua matriks yang diperoleh dengan mereplikasi vektor. Itu adalah ekspansi tunggal . Anda juga bisa menganggapnya sebagai produk luar dari BLAS:v1=[0:2]'; v2 = 1:numel(a)-2; tic; vout = v1*v2; toc Elapsed time is 0.309763 seconds.
Anda mengalikan dua vektor untuk mendapatkan matriks. Hanya saja hasil perkalian luarnya hanya melakukan perkalian, dan
bsxfun
bisa menerapkan operator sembarang. Sebagai catatan tambahan, sangat menarik untuk dilihat,bsxfun
secepat produk luar BLAS. Dan BLAS biasanya dianggap untuk memberikan yang kinerja ..Sunting Berkat komentar Dan, berikut adalah artikel bagus dari Loren yang membahas hal itu.
sumber
bsxfun
dengan contoh yang baik.Mulai R2016b, Matlab mendukung Ekspansi Implisit untuk berbagai macam operator, jadi dalam banyak kasus, tidak perlu lagi menggunakan
bsxfun
:Ada diskusi rinci dari Ekspansi Implisit dan kinerjanya di blog Loren ini. Untuk mengutip Steve Eddins dari MathWorks:
sumber
Hal-hal tidak selalu konsisten dengan 3 metode umum
repmat
:, expension by ones indexing, danbsxfun
. Ini menjadi lebih menarik ketika Anda meningkatkan ukuran vektor lebih jauh. Lihat plot:bsxfun
sebenarnya menjadi sedikit lebih lambat dari dua lainnya di beberapa titik, tetapi yang mengejutkan saya adalah jika Anda meningkatkan ukuran vektor lebih banyak lagi (> elemen keluaran 13E6), bsxfun tiba-tiba menjadi lebih cepat lagi sekitar 3x. Kecepatan mereka tampaknya melompat-lompat dan urutannya tidak selalu konsisten. Dugaan saya adalah mungkin saja tergantung pada ukuran prosesor / memori, tetapi secara umum saya pikir saya akan tetap menggunakannyabsxfun
jika memungkinkan.sumber