MATLAB、R之類軟體中向量化計算是如何實現的?

例如矩陣運算等,它的底層實現是怎樣的?比如用C++實現的話,如何不用循環操作實現矩陣相乘等操作?所謂向量化操作在不使用for循環的情況下到底如何實現?
不知道我說清楚了沒?


首先說一個問題,為什麼Matlab等中要避免用for循環。其實最主要的問題在於,Matlab循環很慢,這個原因很多,包括Matlab解釋性語言的特性、以及Matlab本身設計上有很多歷史遺留問題等等。而當你做向量化運算時,你只有一行Matlab代碼,而其底層全部是用C/C++甚至彙編語言寫成的。就算底層代碼是用最簡單的C循環實現的,光Matlab和C語言之間速度差別就能使得其比用Matlab的循環實現快上可能上百倍。

而實際上Matlab、R等軟體底層使用的是一些矩陣與向量運算庫,例如Matlab使用的是Intel MKL(這個是個收費的C和Fortran語言庫,但據我所知在Intel CPU上性能最好,如果你是學生或者作為研究用途的話是可以免費申請的),此外還有OpenBlas等開源的。你可以使用MKL等庫自己寫向量化操作,完全可以輕易達到甚至超過Matlab的性能(因為你可以做到用純C來實現程序,而Matlab中雖然底層使用一樣的庫,但外層跑的還得是Matlab代碼)。

如果要更底層一點,關於這些庫是如何實現的,說白了還是要使用循環的。事實上計算機本身的循環是很快的,只不過Matlab中循環很慢而已。

其次的話,現代CPU的指令集往往都支持向量化操作,每次能夠對一個固定長度的向量(例如8個32位的整型)做運算,這樣比使用純循環一個一個來做能夠得到若干倍的提速,例如Intel CPU的SSE、AVX等指令集都提供了很多向量化的運算指令,若想大概了解這些指令可以看這兒:Introduction to Intel? Advanced Vector Extensions。

再次,現在的計算機基本都是多核,而向量化的運算一般很容易並行化,而你自己在寫for循環時很有可能不會充分利用這一點,這一點又能造成性能上很大的差異。

此外還有很多細節問題很大程度上改變向量運算的性能,比如如何有效的利用Cache(這一點我自己深有體會)。這些是在你自己寫代碼時很有可能不會太關心的,但像MKL這些高性能計算庫的作者們早就把這些細節優化到幾乎極致了。

但說白了,向量化操作的底層實現還是for循環為主,只不過充分利用硬體特性和進行代碼優化不斷加速再加速。


你可以簡單理解成就是內部幫你把循環寫了。往深說,你相當於只提供了一個向量運算的描述,運算的具體實現可能會調動更多的CPU核心以及SIMD甚至GPU,並使用你現在可能想不到的模式讓運算儘可能高效地利用硬體資源。但說到底還是拿最基本的功能寫的,只是大多數人沒辦法把代碼優化到那種程度而已。

單說介面C++里就一個valarray。想要MatLab那種級別的功能要麼用OpenCV之類的庫要麼自己擼。


推薦閱讀:

如何寫出比 MATLAB 更快的矩陣運算程序?

TAG:機器學習 | 並行計算 | C | 矩陣運算 | 數值計算 |