深入解析NumPy中的Broadcasting廣播機制

前言

在吳恩達老師的深度學習專項課程中,老師有提到NumPy中的廣播機制,同時那一周的測驗也有涉及到廣播機制的題目。那麼,到底什麼是NumPy中的廣播機制?

官方文檔

接下來到瞭看官方文檔的時間。

Array Broadcasting in Numpy

廣播機制概述

讓我們探索numpy中一個更高級的概念,這個概念被稱為廣播。 廣播展現瞭NumPy在算術運算期間是如何處理具有不同形狀的數組的。 受到某些約束,較小的陣列將在較大的陣列上“廣播”,以使它們具有相同形狀。 廣播提供瞭一種數組矢量化操作,從而使得循環在C而不是Python中發生。 它無需復制不必要的數據即可完成,並且通常算法的效率還挺高。 當然在某些情況下,廣播並不是一個好辦法,因為它會導致內存使用效率低,從而減慢計算速度。 本文通過示例,對廣播進行瞭詳盡的介紹。 它還提供何時使用廣播的提示。

numpy操作通常是逐個元素完成的,這就需要兩個數組具有完全相同的形狀

Example 1

>>> from numpy import array
>>> a = array([1.0, 2.0, 3.0])
>>> b = array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

當數組的形狀滿足某些條件時,numpy的廣播規則將放寬這種數組限制。 將數組和標量值在一起運算時,會出現最簡單的廣播示例

Example 2

>>> from numpy import array
>>> a = array([1.0,2.0,3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

盡管隻有一個變量是數組,但是結果和之前的一個代碼例子是一樣的。 我們可以認為其中的標量在算術運算中被拓展成與數組a變量形狀相同的數組。 例如下圖中顯示的中拓展的新元素隻是原始標量的副本。這種拓展隻是概念上的。 numpy的明智之處在於使用原始標量值而不必要創建副本,從而使廣播操作盡可能地節省內存提高計算效率。 由於上面的代碼例子中,乘法過程中標量移動的內存較少,所以在具有一百萬個元素數組的Windows 2000上,廣播機制與之前的兩個數組相加相比大概快10%。

Vector-Scalar multiplication

在最簡單的廣播示例中,標量b被拉伸為與a相同形狀的數組,使得這些形狀適用於逐元素乘法。

下面的規則決定瞭兩個具有兼容形狀的數組是否可以在單個代碼段中進行廣播。

廣播機制規則

廣播規則

為瞭廣播,操作中兩個陣列的尾軸的大小必須相同,或者其中一個必須是一個。

問題來瞭,尾軸是什麼?

為此我找到瞭python – numpy broadcasting – explanation of trailing axes – Stack Overflow這篇解答。

If you have two arrays with different dimensions number, say one 1x2x3 and other 2×3, then you compare only the trailing common dimensions, in this case 2×3. But if both your arrays are two-dimensional, then their corresponding sizes have to be either equal or one of them has to be 1.

In your case you have a 2×2 and 4×2 and 4 != 2 and neither 4 or 2 equals 1, so this doesn’t work.

假設你有兩個不同維度的數組。一個是1x2x3,另一個是2×3,那麼隻需要比較後面的公共尺寸,在這種情況下為2×3。 但是,**如果兩個數組都是二維的,則它們的對應大小必須相等或其中之一必須為1 **。

在兩個二維數組中2×2和4×2,4!= 2,並且4或2都不等於1,所以廣播行不通的。

這個解釋應該比較清楚瞭。

如果不滿足此條件,則會引發異常,提示數組的形狀不兼容。 廣播操作創建的結果數組的大小是兩個數組中每個維度的最大大小。 請註意,該規則並未說明需要具有相同維數的兩個數組。 如果有一個256 x 256 x 3的RGB值數組,想要按不同的值縮放圖像中的每種顏色,則可以將圖像乘以具有3個值的一維數組。

Image (3d array) 256 x 256 x 3
Scale (1d array) 3
Result (3d array) 256 x 256 x 3

在下面的示例中,兩個數組都具有長度為1的軸,這些軸在廣播操作中被擴展為更大的大小。

A (4d array) 8 x 1 x 6 x 1
B (3d array) 7 x 1 x 5
Result (4d array) 8 x 7 x 6 x 5

下面,是幾個代碼例子和圖形表示,有助於使廣播規則直觀明瞭。例3將一個一維數組添加到一個二維數組。

Example 3

>>> from numpy import array
>>> a = array([[ 0.0,  0.0,  0.0],
...            [10.0, 10.0, 10.0],
...            [20.0, 20.0, 20.0],
...            [30.0, 30.0, 30.0]])
>>> b = array([1.0, 2.0, 3.0])
>>> a + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

如下圖2所示,b將拓展維度大小和a一樣。在圖3中,當b的列維度大於a的時,由於形狀不兼容而引發異常。

Matrix-Vector

如果一維數組元素的數量與二維數組列的數量匹配,則將二維數組乘以一維數組將導致廣播。

當數組的尾部不相等時,廣播將失敗,因為無法將第一個數組的行中的值與第二個數組的元素對齊進行逐元素加法。

廣播提供瞭一種獲取兩個數組的外部乘積(或任何其他外部操作)的便捷方法。 下面的示例顯示兩個1維數組的外部加法運算,其結果與示例3相同。

Example 4

>>> from numpy import array, newaxis
>>> a = array([0.0, 10.0, 20.0, 30.0])
>>> b = array([1.0, 2.0, 3.0])
>>> a[:,newaxis] + b
array([[  1.,   2.,   3.],
       [ 11.,  12.,  13.],
       [ 21.,  22.,  23.],
       [ 31.,  32.,  33.]])

在這裡,newaxis索引運算符將一個新軸插入,使其成為二維4×1數組。 圖4說明瞭兩個陣列的拉伸以產生所需的4×3輸出陣列。

在這裡例子裡是b = array([1.0, 2.0, 3.0]),但是下圖中是0,1,2,emmmm…尊重原文吧!

vector-vector with newaxis

在某些情況下,廣播會拉伸兩個陣列以形成一個比任何一個初始陣列都大的輸出陣列。

總結

以上是對官方文檔的翻譯,總的來說廣播機制主要是以下幾點:

  • 效率較快,性能較好
  • 廣播時,操作中兩個數組的尾軸的大小必須相同,或者其中之一必須是1
  • 如果兩個數組都是二維的,則它們的對應大小必須相等或其中之一必須為1

通過這篇文章,你是否瞭解瞭NumPy的廣播機制呢?更多相關NumPy Broadcasting廣播機制內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: