PyTorch的Broadcasting 和 Element-Wise 操作 | PyTorch系列(八)

點擊上方AI算法與圖像處理”,選擇加"星標"或“置頂”

重磅乾貨,第一時間送達

文 |AI_study

歡迎回到這個關於神經網絡編程的系列。在這篇文章中,我們將通過學習 element-wise 的操作來擴展我們的知識,而不僅僅是 reshape 操作。

  • Reshaping operations

  • Element-wise operations

  • Reduction operations

  • Access operations


深度學習中Element-Wise 操作

一、Element-Wise的含義

element-wise 是神經網絡編程中非常常見的張量操作。讓我們首先定義一下 element-wise 操作。

element-wise 是兩個張量之間的操作,它在相應張量內的對應的元素進行操作。

An element-wise operation operates on corresponding elements between tensors.

如果兩個元素在張量內佔據相同位置,則稱這兩個元素是對應的。該位置由用於定位每個元素的索引確定。

假設我們有以下兩個張量:

> t1 = torch.tensor([
    [1,2],
    [3,4]
], dtype=torch.float32)


> t2 = torch.tensor([
    [9,8],
    [7,6]
], dtype=torch.float32)

這兩個張量均爲2 x 2形狀的2階張量。

這意味着我們有兩個軸,每個軸的長度均爲兩個元素。第一軸的元素是數組,第二軸的元素是數字。

# Example of the first axis
> print(t1[0])
tensor([1., 2.])


# Example of the second axis
> print(t1[0][0])
tensor(1.)

這是我們現在在本系列中經常看到的那種東西。好吧,讓我們以此爲基礎。

我們知道,如果兩個元素在張量內佔據相同位置,則認爲這兩個元素是對應的,並且該位置由用於定位每個元素的索引確定。讓我們看一個對應元素的例子。

> t1[0][0]
tensor(1.)


> t2[0][0]
tensor(9.)

這使我們看到 t1 中1的對應元素是 t2 中9的元素。

對應關係由索引定義。這很重要,因爲它揭示了element-wise 操作的重要特徵。我們可以推斷出張量必須具有相同數量的元素才能執行 element-wise 的操作。

我們將繼續進行此聲明,使其更具限制性。兩個張量必須具有相同的形狀,以便對其執行 element-wise 操作。

二、加法也是一種Element-Wise操作


讓我們看看第一個 element-wise  操作,加法。別擔心。它會變得更有趣。

> t1 + t2
tensor([[10., 10.],
        [10., 10.]])

這讓我們看到張量之間的加法是一個element-wise 操作。在相應位置的每一對元素被加在一起,產生一個新的相同形狀的張量。

加法是一種element-wise 運算,事實上,所有的算術運算,加、減、乘、除都是element-wise 運算。


算術運算是基於 Element-Wise的運算

我們通常看到的張量運算是使用標量值的算術運算。我們有兩種方法可以做到這一點:

(1) 使用這些符號運算:

> print(t + 2)
tensor([[3., 4.],
        [5., 6.]])


> print(t - 2)
tensor([[-1.,  0.],
        [ 1.,  2.]])


> print(t * 2)
tensor([[2., 4.],
        [6., 8.]])


> print(t / 2)
tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])

或者等價地,(2) 這些張量內置的方法:

> print(t1.add(2))
tensor([[3., 4.],
        [5., 6.]])


> print(t1.sub(2))
tensor([[-1.,  0.],
        [ 1.,  2.]])


> print(t1.mul(2))
tensor([[2., 4.],
        [6., 8.]])


> print(t1.div(2))
tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])

這兩個選項的作用是相同的。我們可以看到,在這兩種情況下,標量值 2 通過相應的算術運算應用於每個元素。

這裏好像有點不對勁。這些例子打破了我們建立的規則,即element-wise 作操作相同形狀的張量。

標量的值是0階張量,這意味着它們沒有形狀,而我們的張量t1是一個形狀爲2×2的2階張量。

這是怎麼回事呢?讓我們分解一下。

可能想到的第一個解釋是,這個運算只是使用單個標量值,對張量中的每個元素進行運算。

這種邏輯是可行的。然而,這有點誤導人,而且在更一般的情況下,我們注意到它使用標量。

爲了從不同的角度考慮這些操作,我們需要引入tensor broadcastingbroadcasting的概念。

一、Broadcasting Tensors

broadcasting 描述了在element-wise 操作期間如何處理不同形狀的張量。

Broadcasting is the concept whose implementation allows us to add scalars to higher dimensional tensors.

我們考慮一下t1 + 2的運算。在這裏,將標量值張量變換成t1的形狀,然後進行element-wise 運算。

我們可以看到什麼是broadcasted(廣播後)標量值看起來像使用broadcast_to()  Numpy函數:

> np.broadcast_to(2, t1.shape)
array([[2, 2],
        [2, 2]])

這意味着標量值被轉換成一個2階張量,就像t1一樣,就像那樣,形狀匹配和element-wise 方面的規則有了相同的形狀。當然,這一切都是祕密進行的。

可以這麼說,這段代碼美如畫

> t1 + 2
tensor([[3., 4.],
        [5., 6.]])

    實際上的操作

> t1 + torch.tensor(
    np.broadcast_to(2, t1.shape)
    ,dtype=torch.float32
)
tensor([[3., 4.],
        [5., 6.]])

在這一點上,您可能會認爲這似乎有些令人費解,所以讓我們看一個更棘手的示例,以解決這一問題。假設我們有以下兩個張量。

二、廣播的一個更棘手的例子

讓我們看一個更復雜的例子來理解這一點。假設我們有下面這個張量。

t1 = torch.tensor([
    [1,1],
    [1,1]
], dtype=torch.float32)


t2 = torch.tensor([2,4], dtype=torch.float32)

這個element-wise 加法運算的結果是什麼?對element-wise 運算的相同形狀規則是否還可行?

# t1 + t2 ???????


> t1.shape
torch.Size([2, 2])


> t2.shape
torch.Size([2])

儘管這兩個張量有不同的形狀,但element-wise操作是可能的,而 broadcasting 使得運算成爲可能。低階張量t2將通過broadcasting 進行變換,以匹配高階張量t1的形狀,element-wise 操作將照常進行。

broadcasting 的概念是理解這個運算將如何進行的關鍵。與前面一樣,我們可以使用broadcast_to() numpy函數檢查broadcast 轉換。

> np.broadcast_to(t2.numpy(), t1.shape)
array([[2., 4.],
        [2., 4.]], dtype=float32)


> t1 + t2
tensor([[3., 5.],
        [3., 5.]])

broadcasting之後,這兩個張量之間的加法運算是同一形狀張量之間的element-wise 運算。

廣播是一個比基本element-wise 操作更先進的話題,所以如果需要更長的時間來熟悉這個概念,也不要擔心。

理解element-wise 的操作和相同的形狀要求爲廣播的概念和爲什麼使用廣播提供了基礎。

我們什麼時候真正使用廣播?在預處理數據時,特別是在歸一化化過程中,我們經常需要使用廣播。

在TensorFlow.js系列中有一篇文章更詳細地介紹了廣播。這裏有一個實際的例子,並討論了確定一個特定的張量如何廣播的算法,所以檢查一下,對廣播進行更深入的討論。

不要擔心不知道TensorFlow.js。這不是必須的,我強烈推薦廣播的內容。


比較操作也是Element-Wise的運算

比較操作也是element-wise 運算。

對於給定的兩個張量之間的比較運算,返回一個形狀相同的新張量,每個元素包含一個torch.bool值爲True或Faslse。

一、PyTorch版本1.2.0中的更改

返回的比較操作從torch.uint8 變成 torch.bool.

https://github.com/pytorch/pytorch/pull/21113

1.1版本:

> torch.tensor([1, 2, 3]) < torch.tensor([3, 1, 2])
tensor([1, 0, 0], dtype=torch.uint8)

1.2版本:

> torch.tensor([1, 2, 3]) < torch.tensor([3, 1, 2])
tensor([True, False, False])

相關鏈接:

  • Release Notes: https://github.com/pytorch/pytorch/releases/tag/v1.2.0

  • Pull Request: https://github.com/pytorch/pytorch/pull/21113

下面的示例顯示了PyTorch版本1.2.0及更高版本的輸出。

二、元素比較運算的例子

假設有下面的張量

> t = torch.tensor([
    [0,5,0],
    [6,0,7],
    [0,8,0]
], dtype=torch.float32)

讓我們來看看這些比較運算

> t.eq(0)
tensor([[True, False, True],
        [False, True, False],
        [True, False, True]])




> t.ge(0)
tensor([[True, True, True],
        [True, True, True],
        [True, True, True]])




> t.gt(0)
tensor([[False, True, False],
        [True, False, True],
        [False, True, False]])




> t.lt(0)
tensor([[False, False, False],
        [False, False, False],
        [False, False, False]])


> t.le(7)
tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

從廣播的角度來思考這些操作,我們可以看到最後一個操作,t.le(7),實際上是這樣的:

> t <= torch.tensor(
    np.broadcast_to(7, t.shape)
    ,dtype=torch.float32
)


tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

等同於:

> t <= torch.tensor([
    [7,7,7],
    [7,7,7],
    [7,7,7]
], dtype=torch.float32)


tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

三、使用函數的元素操作

對於函數的元素操作,我們可以假設這個函數適用於張量的每個元素。

以下是一些例子:

> t.abs() 
tensor([[0., 5., 0.],
        [6., 0., 7.],
        [0., 8., 0.]])




> t.sqrt()
tensor([[0.0000, 2.2361, 0.0000],
        [2.4495, 0.0000, 2.6458],
        [0.0000, 2.8284, 0.0000]])


> t.neg()
tensor([[-0., -5., -0.],
        [-6., -0., -7.],
        [-0., -8., -0.]])


> t.neg().abs()
tensor([[0., 5., 0.],
        [6., 0., 7.],
        [0., 8., 0.]])

一些術語

有一些其他的方法來引用element-wise的運算,所以我只想提一下,所有這些都意味着同一件事:

  • Element-wise

  • Component-wise

  • Point-wise

如果你在其他地方遇到這些術語,請記住這一點。


總結

現在,我們應該有一個很好的理解element-wise 的操作,以及如何將它們應用到神經網絡和深度學習的張量操作。在下一篇文章中,我們將討論最後兩類張量運算:

  • Reshaping operations

  • Element-wise operations

  • Reduction operations

  • Access operations

文章中內容都是經過仔細研究的,本人水平有限,翻譯無法做到完美,但是真的是費了很大功夫,希望小夥伴能動動你性感的小手,分享朋友圈或點個“在看”,支持一下我 ^_^

英文原文鏈接是:

https://deeplizard.com/learn/video/fCVuiW9AFzY

加羣交流

歡迎小夥伴加羣交流,目前已有交流羣的方向包括:AI學習交流羣,目標檢測,秋招互助,資料下載等等;加羣可掃描並回復感興趣方向即可(註明:地區+學校/企業+研究方向+暱稱)

 我的生活不能沒有你! ????

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章