Saya ingin menulis program yang memanfaatkan fungsi aljabar linier BLAS dan LAPACK secara ekstensif. Karena kinerja adalah masalah, saya melakukan beberapa pembandingan dan ingin tahu, apakah pendekatan yang saya ambil itu sah.
Bisa dibilang, saya memiliki tiga kontestan dan ingin menguji kinerja mereka dengan perkalian matriks-matriks sederhana. Para kontestannya adalah:
- Numpy, hanya memanfaatkan fungsionalitas
dot
. - Python, memanggil fungsionalitas BLAS melalui objek bersama.
- C ++, memanggil fungsionalitas BLAS melalui objek bersama.
Skenario
Saya menerapkan perkalian matriks-matriks untuk dimensi yang berbeda i
. i
berjalan dari 5 hingga 500 dengan kenaikan 5 dan matriks m1
dan m2
diatur seperti ini:
m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)
1. Numpy
Kode yang digunakan terlihat seperti ini:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python, memanggil BLAS melalui objek bersama
Dengan fungsinya
_blaslib = ctypes.cdll.LoadLibrary("libblas.so")
def Mul(m1, m2, i, r):
no_trans = c_char("n")
n = c_int(i)
one = c_float(1.0)
zero = c_float(0.0)
_blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref(n), byref(n),
byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n),
m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero),
r.ctypes.data_as(ctypes.c_void_p), byref(n))
kode tes terlihat seperti ini:
r = numpy.zeros((i,i), numpy.float32)
tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul")
rBlas.append((i, tBlas.repeat(20, 1)))
3. c ++, memanggil BLAS melalui objek bersama
Sekarang kode c ++ secara alami sedikit lebih lama jadi saya mengurangi informasinya seminimal mungkin.
Saya memuat fungsi dengan
void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");
Saya mengukur waktu dengan gettimeofday
seperti ini:
gettimeofday(&start, NULL);
f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim);
gettimeofday(&end, NULL);
dTimes[j] = CalcTime(start, end);
dimana j
loop berjalan 20 kali. Saya menghitung waktu berlalu dengan
double CalcTime(timeval start, timeval end)
{
double factor = 1000000;
return (((double)end.tv_sec) * factor + ((double)end.tv_usec) - (((double)start.tv_sec) * factor + ((double)start.tv_usec))) / factor;
}
Hasil
Hasilnya ditunjukkan pada plot di bawah ini:
Pertanyaan
- Apakah menurut Anda pendekatan saya adil, atau adakah biaya tambahan yang tidak perlu yang dapat saya hindari?
- Apakah Anda berharap bahwa hasilnya akan menunjukkan perbedaan yang sangat besar antara pendekatan c ++ dan python? Keduanya menggunakan objek bersama untuk penghitungannya.
- Karena saya lebih suka menggunakan python untuk program saya, apa yang dapat saya lakukan untuk meningkatkan kinerja saat memanggil rutinitas BLAS atau LAPACK?
Unduh
Benchmark lengkapnya bisa diunduh disini . (JF Sebastian memungkinkan tautan itu ^^)
r
matriks tidak adil. Saya sedang menyelesaikan "masalah" sekarang dan memposting hasil baru.np.ascontiguousarray()
(pertimbangkan urutan C vs. Fortran). 2. pastikan bahwanp.dot()
menggunakan samalibblas.so
.m1
danm2
memilikiascontiguousarray
flag sebagaiTrue
. Dan numpy menggunakan objek bersama yang sama seperti C. Adapun urutan larik: Saat ini saya tidak tertarik dengan hasil penghitungan sehingga urutannya tidak relevan.Jawaban:
Saya telah menjalankan patokan Anda . Tidak ada perbedaan antara C ++ dan numpy di mesin saya:
Sepertinya adil karena tidak ada perbedaan hasil.
Tidak.
Pastikan numpy menggunakan versi perpustakaan BLAS / LAPACK yang dioptimalkan di sistem Anda.
sumber
UPDATE (30.07.2014):
Saya menjalankan kembali benchmark pada HPC baru kami. Baik perangkat keras maupun tumpukan perangkat lunak berubah dari pengaturan dalam jawaban asli.
Hasil saya taruh di google spreadsheet (berisi juga hasil dari jawaban aslinya).
Perangkat keras
HPC kami memiliki dua node berbeda, satu dengan CPU Intel Sandy Bridge dan satu lagi dengan CPU Ivy Bridge yang lebih baru:
Sandy (MKL, OpenBLAS, ATLAS):
Ivy (MKL, OpenBLAS, ATLAS):
Perangkat lunak
Tumpukan perangkat lunak untuk kedua node yang sama. Alih-alih GotoBLAS2 , OpenBLAS digunakan dan ada juga ATLAS BLAS multi-utas yang disetel ke 8 utas (hardcode).
Tolok Ukur Produk Titik
Benchmark-code sama seperti di bawah ini. Namun untuk mesin baru saya juga menjalankan benchmark untuk ukuran matriks 5000 dan 8000 .
Tabel di bawah ini mencakup hasil benchmark dari jawaban asli (berganti nama: MKL -> Nehalem MKL, Netlib Blas -> Nehalem Netlib BLAS, dll)
Kinerja ulir tunggal:
Kinerja multi utas (8 utas):
Benang vs ukuran Matriks (Ivy Bridge MKL) :
Suite Benchmark
Kinerja ulir tunggal:
Kinerja multi utas (8 utas):
Kesimpulan
Hasil benchmark baru mirip dengan yang ada di jawaban asli. OpenBLAS dan MKL bekerja pada level yang sama, kecuali tes nilai Eigen . The Eigenvalue melaksanakan uji hanya cukup baik pada OpenBLAS di modus threaded tunggal . Dalam mode multi-utas, kinerjanya lebih buruk.
The "Matrix ukuran vs benang bagan" juga menunjukkan bahwa meskipun MKL serta OpenBLAS umumnya baik skala dengan jumlah core / benang, itu tergantung pada ukuran matriks. Untuk matriks kecil menambahkan lebih banyak inti tidak akan banyak meningkatkan kinerja.
Ada juga peningkatan kinerja sekitar 30% dari Sandy Bridge ke Ivy Bridge yang mungkin disebabkan oleh clock rate yang lebih tinggi (+ 0.8 Ghz) dan / atau arsitektur yang lebih baik.
Jawaban Asli (04.10.2011):
Beberapa waktu yang lalu saya harus mengoptimalkan beberapa perhitungan / algoritma aljabar linier yang ditulis dengan python menggunakan numpy dan BLAS jadi saya melakukan benchmark / uji konfigurasi numpy / BLAS yang berbeda.
Secara khusus saya menguji:
Saya menjalankan dua tolok ukur yang berbeda:
Ini hasil saya:
Mesin
Linux (MKL, ATLAS, No-MKL, GotoBlas2):
Mac Book Pro (Accelerate Framework):
Mac Server (Accelerate Framework):
Tolok ukur produk titik
Kode :
Hasil :
Suite Benchmark
Kode :
Untuk informasi tambahan tentang rangkaian benchmark, lihat di sini .
Hasil :
Instalasi
Instalasi MKL termasuk menginstal Intel Compiler Suite lengkap yang cukup mudah. Namun karena beberapa bug / masalah, konfigurasi dan kompilasi numpy dengan dukungan MKL agak merepotkan.
GotoBlas2 adalah paket kecil yang dapat dengan mudah dikompilasi sebagai perpustakaan bersama. Namun karena bug Anda harus membuat ulang pustaka bersama setelah membuatnya untuk menggunakannya dengan numpy.
Selain bangunan ini, untuk beberapa bentuk pelat target tidak berfungsi karena alasan tertentu. Jadi saya harus membuat file .so untuk setiap platform yang saya ingin file libgoto2.so dioptimalkan .
Jika Anda menginstal numpy dari repositori Ubuntu, maka secara otomatis akan menginstal dan mengkonfigurasi numpy untuk menggunakan ATLAS . Menginstal ATLAS dari sumber dapat memakan waktu lama dan memerlukan beberapa langkah tambahan (fortran, dll).
Jika Anda menginstal numpy pada mesin Mac OS X dengan Fink atau Mac Ports , numpy akan dikonfigurasi untuk menggunakan ATLAS atau Kerangka Accelerate Apple . Anda dapat memeriksa dengan menjalankan ldd pada file numpy.core._dotblas atau memanggil numpy.show_config () .
Kesimpulan
MKL berkinerja terbaik diikuti oleh GotoBlas2 .
Dalam tes nilai eigen, kinerja GotoBlas2 ternyata lebih buruk dari yang diharapkan. Tidak yakin mengapa ini terjadi.
Kerangka Accelerate Apple bekerja sangat baik terutama dalam mode single threaded (dibandingkan dengan implementasi BLAS lainnya).
Baik GotoBlas2 dan MKL berskala sangat baik dengan jumlah utas. Jadi jika Anda harus berurusan dengan matriks besar yang menjalankannya di banyak utas akan sangat membantu.
Bagaimanapun, jangan gunakan implementasi netlib blas default karena terlalu lambat untuk pekerjaan komputasi yang serius.
Di cluster kami, saya juga menginstal ACML AMD dan kinerjanya mirip dengan MKL dan GotoBlas2 . Saya tidak memiliki angka yang sulit.
Saya pribadi akan merekomendasikan untuk menggunakan GotoBlas2 karena lebih mudah untuk menginstal dan gratis.
Jika Anda ingin membuat kode dalam C ++ / C juga periksa Eigen3 yang seharusnya mengungguli MKL / GotoBlas2 dalam beberapa kasus dan juga cukup mudah digunakan.
sumber
Ini patokan lain (di Linux, cukup ketik
make
): http://dl.dropbox.com/u/5453551/blas_call_benchmark.ziphttp://dl.dropbox.com/u/5453551/blas_call_benchmark.png
Saya pada dasarnya tidak melihat perbedaan apa pun antara metode yang berbeda untuk matriks besar, antara Numpy, Ctypes dan Fortran. (Fortran bukannya C ++ --- dan jika ini penting, tolok ukur Anda mungkin rusak.)
Mungkin benchmark Anda juga memiliki bug lain, misalnya, membandingkan antara perpustakaan BLAS yang berbeda, atau pengaturan BLAS yang berbeda seperti jumlah utas, atau antara waktu nyata dan waktu CPU?CalcTime
Fungsi Anda di C ++ sepertinya mengalami kesalahan tanda.... + ((double)start.tv_usec))
seharusnya sebagai gantinya... - ((double)start.tv_usec))
.EDIT : gagal menghitung tanda kurung dalam
CalcTime
fungsi - tidak apa-apa.Sebagai pedoman: jika Anda melakukan benchmark, harap selalu memposting semua kode di suatu tempat. Mengomentari benchmark, terutama jika mengejutkan, tanpa kode lengkap biasanya tidak produktif.
Untuk mengetahui BLAS Numpy mana yang ditautkan, lakukan:
UPDATE : Jika Anda tidak dapat mengimpor numpy.core._dotblas, Numpy Anda menggunakan salinan cadangan internal BLAS, yang lebih lambat, dan tidak dimaksudkan untuk digunakan dalam komputasi kinerja! Balasan dari @Woltan di bawah ini menunjukkan bahwa ini adalah penjelasan untuk perbedaan yang dia lihat di Numpy vs. Ctypes + BLAS.
Untuk memperbaiki situasi ini, Anda memerlukan ATLAS atau MKL --- periksa petunjuk ini: http://scipy.org/Installing_SciPy/Linux Sebagian besar distribusi Linux disertakan dengan ATLAS, jadi opsi terbaik adalah menginstal
libatlas-dev
paket mereka (nama mungkin berbeda) .sumber
import numpy.core._dotblas
. Apa masalahnya di sini? Saya akan mencoba membersihkan benchmark saya dan menulis makefile agar orang lain dapat mengujinya.otool -L
selainldd
di LinuxMengingat ketelitian yang Anda tunjukkan dengan analisis Anda, saya terkejut dengan hasilnya sejauh ini. Saya menempatkan ini sebagai 'jawaban' tetapi hanya karena terlalu panjang untuk komentar dan memberikan kemungkinan (meskipun saya berharap Anda telah mempertimbangkannya).
Saya akan mengira pendekatan numpy / python tidak akan menambah banyak overhead untuk matriks dengan kompleksitas yang wajar, karena ketika kompleksitas meningkat, proporsi yang diikuti python harus kecil. Saya lebih tertarik dengan hasil di sisi kanan grafik, tetapi perbedaan urutan besaran yang ditunjukkan di sana akan mengganggu.
Saya ingin tahu apakah Anda menggunakan algoritme terbaik yang dapat dimanfaatkan numpy. Dari panduan kompilasi untuk linux:
"Build FFTW (3.1.2): Versi SciPy> = 0.7 dan Numpy> = 1.2: Karena masalah lisensi, konfigurasi, dan pemeliharaan, dukungan untuk FFTW telah dihapus dalam versi SciPy> = 0.7 dan NumPy> = 1.2. Sebagai gantinya sekarang menggunakan versi built-in dari fftpack. Ada beberapa cara untuk memanfaatkan kecepatan FFTW jika perlu untuk analisis Anda. Turunkan ke versi Numpy / Scipy yang menyertakan dukungan. Instal atau buat pembungkus FFTW Anda sendiri. Lihat http: //developer.berlios.de/projects/pyfftw/ sebagai contoh yang tidak didukung. "
Apakah Anda mengkompilasi numpy dengan mkl? ( http://software.intel.com/en-us/articles/intel-mkl/ ). Jika Anda menjalankan linux, petunjuk untuk mengompilasi numpy dengan mkl ada di sini: http://www.scipy.org/Installing_SciPy/Linux#head-7ce43956a69ec51c6f2cedd894a4715d5bfff974 (terlepas dari url). Bagian kuncinya adalah:
Jika Anda menggunakan windows, Anda bisa mendapatkan biner terkompilasi dengan mkl, (dan juga mendapatkan pyfftw, dan banyak algoritma terkait lainnya) di: http://www.lfd.uci.edu/~gohlke/pythonlibs/ , dengan hutang terima kasih kepada Christoph Gohlke di Laboratory for Fluorescence Dynamics, UC Irvine.
Peringatan, dalam kedua kasus, ada banyak masalah perizinan dan sebagainya yang harus diperhatikan, tetapi halaman intel menjelaskannya. Sekali lagi, saya membayangkan Anda telah mempertimbangkan ini, tetapi jika Anda memenuhi persyaratan perizinan (yang di linux sangat mudah dilakukan), ini akan mempercepat bagian numpy relatif untuk menggunakan build otomatis sederhana, bahkan tanpa FFTW. Saya akan tertarik untuk mengikuti utas ini dan melihat apa yang dipikirkan orang lain. Terlepas dari itu, ketelitian yang sangat baik dan pertanyaan yang sangat baik. Terima kasih telah mempostingnya.
sumber