具備基本的數學和程式設計知識,你就可以學習深度學習啦
深度學習很難?對深度學習存有困惑,不知道從哪裡下手,不知道適不適合自己學習?只需瞭解基礎的數學和程式設計,如基礎的線性代數、微分和機率,以及基本的Python程式設計知識,你就可以真正的去學習深度學習嘍!
從哪開始呢?從一本入手的《 動手學深度學習 》開始吧!
在瞭解這本書之前,帶你看一下主要符號表
以下圖片為學習深度學習的主要符號表,請點選大圖預覽。
動手學深度學習
目前市面上有關深度學習介紹的書籍大多可分兩類,一類側重方法介紹,另一類側重實踐和深度學習工具的介紹。本書同時覆蓋方法和實踐。本書不僅從數學的角度闡述深度學習的技術與應用,還包含可執行的程式碼,為讀者展示如何在實際中解決問題。為了給讀者提供一種互動式的學習體驗,本書不但提供免費的教學影片和討論區,而且提供可執行的Jupyter記事本檔案,充分利用Jupyter記事本能將文字、程式碼、公式和影像統一起來的優勢。這樣不僅直接將數學公式對應成實際程式碼,而且可以修改程式碼、觀察結果並及時獲取經驗,從而帶給讀者全新的、互動式的深度學習的學習體驗。
本書面向希望瞭解深度學習,特別是對實際使用深度學習感興趣的大學生、工程師和研究人員。本書不要求讀者有任何深度學習或者機器學習的背景知識,讀者只需具備基本的數學和程式設計知識,如基礎的線性代數、微分、機率及Python程式設計知識。本書的附錄中提供了書中涉及的主要數學知識,供讀者參考。
本書的英文版Dive into Deep Learning是加州大學伯克利分校2019年春學期“Introduction to Deep Learning”(深度學習導論)課程的教材。截至2019年春學期,本書中的內容已被全球15 所知名大學用於教學。本書的學習社群、免費教學資源(課件、教學影片、更多習題等),以及用於本書學習和教學的免費計算資源(僅限學生和老師)的申請方法在本書配套網站zh.d2l.ai上釋出。讀者在閱讀本書的過程中,如果對書中某節內容有疑惑,也可以掃一掃書中對應的二維碼尋求幫助。
樣章截選
在深度學習中,我們通常會頻繁地對資料進行操作。作為動手學深度學習的基礎,本節將介紹如何對記憶體中的資料進行操作。
在 MXNet 中,NDArray是一個類,也是儲存和變換資料的主要工具。為了簡潔,本書常將NDArray例項直接稱作NDArray。如果你之前用過 NumPy,你會發現 NDArray和NumPy 的多維陣列非常類似。然而,NDArray提供 GPU 計算和自動求梯度等更多功能,這些使NDArray更加適合深度學習。
2.2.1 建立NDArray
我們先介紹NDArray的最基本功能。如果對這裡用到的數學操作不是很熟悉,可以參閱附錄A。
首先從MXNet 匯入ndarray 模組 。這裡的nd是ndarray的縮寫形式。
In [1]: from mxnet import nd
然後我們用arange 函式 建立一個行向量。
In [2]: x = nd.arange(12)
x
Out[2]:
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.]
<NDArray 12 @cpu(0)>
這時返回了一個NDArray 例項,其中包含了從 0 開始的 12 個連續整數。從列印X時顯示的屬性<NDArray 12 @cpu(0)>可以看出,它是長度為 12 的一維陣列,且被建立在 CPU 使用的記憶體上。其中@cpu(0)裡的 0 沒有特別的意義,並不代表特定的核。
我們可以透過shape 屬性 來獲取NDArray例項的形狀。
In [3]: x.shape
Out[3]: (12,)
我們也能夠透過size 屬性 得到NDArray例項中 元素 (element)的總數。
In [4]: x.size
Out[4]: 12
下面使用reshape 函式 把行向量x的形狀改為(3, 4),也就是一個 3 行 4 列的矩陣,並記作X(矩陣變數常用大寫字母表示)。除了形狀改變之外,X中的元素保持不變。
In [5]: X = x.reshape((3, 4))
X
Out[5]:
[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
<NDArray 3x4 @cpu(0)>
注意,X屬性中的形狀發生了變化。上面x.reshape((3, 4))也可寫成x.reshape((-1, 4))或x.reshape((3, -1))。由於x的元素個數是已知的,這裡的-1是能夠透過元素個數和其他維度的大小推斷出來的。
接下來,我們建立一個各元素為0,形狀為( 2, 3, 4 )的張量。實際上,之前建立的向量和矩陣都是特殊的張量。
In [6]: nd.zeros((2, 3, 4))
Out[6]:
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]]
<NDArray 2x3x4 @cpu(0)>
類似地,我們可以建立各元素為 1 的張量。
In [7]: nd.ones((3, 4))
Out[7]:
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
<NDArray 3x4 @cpu(0)>
我們也可以透過 Python 的列表(list)指定需要建立的 NDArray 中每個元素的值。
In [8]: Y = nd.array([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
Y
Out[8]:
[[2. 1. 4. 3.]
[1. 2. 3. 4.]
[4. 3. 2. 1.]]
<NDArray 3x4 @cpu(0)>
有些情況下,我們需要隨機生成 NDArray 中每個元素的值。下面我們建立一個形狀為(3, 4)的NDArray。它的每個元素都隨機取樣於均值為0、標準差為1的正態分佈。
In [9]: nd.random.normal(0, 1, shape=(3, 4))
Out[9]:
[[ 2.2122064 0.7740038 1.0434405 1.1839255 ]
[ 1.8917114 -1.2347414 -1.771029 -0.45138445]
[ 0.57938355 -1.856082 -1.9768796 -0.20801921]]
<NDArray 3x4 @cpu(0)>
2.2.2 運算
NDArray支援大量的 運算子 (operator)。例如,我們可以對之前建立的兩個形狀為(3, 4)的NDArray做按元素加法。所得結果形狀不變。
In [10]: X + Y
Out[10]:
[[ 2. 2. 6. 6.]
[ 5. 7. 9. 11.]
[12. 12. 12. 12.]]
<NDArray 3x4 @cpu(0)>
按元素乘法如下:
In [11]: X * Y
Out[11]:
[[ 0. 1. 8. 9.]
[ 4. 10. 18. 28.]
[32. 27. 20. 11.]]
<NDArray 3x4 @cpu(0)>
按元素除法如下:
In [12]: X / Y
Out[12]:
[[ 0. 1. 0.5 1. ]
[ 4. 2.5 2. 1.75]
[ 2. 3. 5. 11. ]]
<NDArray 3x4 @cpu(0)>
按元素做指數運算如下:
In [13]: Y.exp()
Out[13]:
[[ 7.389056 2.7182817 54.59815 20.085537 ]
[ 2.7182817 7.389056 20.085537 54.59815 ]
[54.59815 20.085537 7.389056 2.7182817]]
<NDArray 3x4 @cpu(0)>
除了按元素計算外,我們還可以使用dot 函式 做矩陣乘法。下面將X與Y的轉置做矩陣乘法。由於X是 3 行 4 列的矩陣,Y轉置為 4 行 3 列的矩陣,因此兩個矩陣相乘得到 3 行 3 列的矩陣。
In [14]: nd.dot(X, Y.T)
Out[14]:
[[ 18. 20. 10.]
[ 58. 60. 50.]
[ 98. 100. 90.]]
<NDArray 3x3 @cpu(0)>
我們也可以將多個 NDArray 連結 (concatenate)。下面分別在行上(維度 0,即形狀中的最左邊元素)和列上(維度 1,即形狀中左起第二個元素)連結兩個矩陣。可以看到,輸出的第一個NDArray在維度0的長度(6)為兩個輸入矩陣在維度0的長度之和(3 + 3),而輸出的第二個NDArray在維度1的長度(8)為兩個輸入矩陣在維度1的長度之和(4 + 4)。
In [15]: nd.concat(X, Y, dim=0), nd.concat(X, Y, dim=1)
Out[15]: (
[[ 0. 1. 2. 3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]
[ 2. 1. 4. 3.]
[ 1. 2. 3. 4.]
[ 4. 3. 2. 1.]]
<NDArray 6x4 @cpu(0)>,
[[ 0. 1. 2. 3. 2. 1. 4. 3.]
[ 4. 5. 6. 7. 1. 2. 3. 4.]
[ 8. 9. 10. 11. 4. 3. 2. 1.]]
<NDArray 3x8 @cpu(0)>)
使用 條件判別式 可以得到元素為 0 或 1 的新的 NDArray。以X == Y為例,如果X和Y在相同位置的條件判斷為真(值相等),那麼新的 NDArray 在相同位置的值為 1;反之為 0。
In [16]: X == Y
Out[16]:
[[0. 1. 0. 1.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
<NDArray 3x4 @cpu(0)>
對NDArray中的所有元素求和得到只有一個元素的NDArray。
In [17]: X.sum()
Out[17]:
[66.]
<NDArray 1 @cpu(0)>
我們可以透過asscalar 函式 將結果變換為 Python 中的標量。下面例子中X的 L 2範數結果同上例一樣是單元素 NDArray,但最後結果變換成了 Python 中的標量。
In [18]: X.norm().asscalar()
Out[18]: 22.494442
我們也可以把Y.exp()、X.sum()、X.norm()等分別改寫為nd.exp(Y)、nd.sum(X)、nd.
norm(X)等。
2.2.3 廣播機制
前面我們看到如何對兩個形狀相同的 NDArray 做按元素運算。當對兩個形狀不同的 NDArray按元素運算時,可能會觸發 廣播 (broadcasting)機制:先適當複製元素使這兩個 NDArray形狀相同後再按元素運算。
先定義兩個NDArray。
In [19]: A = nd.arange(3).reshape((3, 1))
B = nd.arange(2).reshape((1, 2))
A, B
Out[19]: (
[[0.]
[1.]
[2.]]
<NDArray 3x1 @cpu(0)>,
[[0. 1.]]
<NDArray 1x2 @cpu(0)>)
由於A和B分別是3 行1列和1行2列的矩陣,如果要計算A + B,那麼A中第一列的3個元素被廣播(複製)到了第二列,而B中第一行的2個元素被廣播(複製)到了第二行和第三行。如此,就可以對2個 3 行 2 列的矩陣按元素相加。
In [20]: A + B
Out[20]:
[[0. 1.]
[1. 2.]
[2. 3.]]
<NDArray 3x2 @cpu(0)>
2.2.4 索引
在NDArray中, 索引 (index)代表了元素的位置。NDArray的索引從 0 開始逐一遞增。例如,一個 3 行 2 列的矩陣的行索引分別為 0、1 和 2,列索引分別為 0 和 1。
在下面的例子中,我們指定了NDArray的行索引擷取範圍[1:3]。依據左閉右開指定範圍的慣例,它擷取了矩陣X中行索引為 1 和 2 的兩行。
In [21]: X[1:3]
Out[21]:
[[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
<NDArray 2x4 @cpu(0)>
我們可以指定 NDArray中需要訪問的單個元素的位置,如矩陣中行和列的索引,併為該元素重新賦值。
In [22]: X[1, 2] = 9
X
Out[22]:
[[ 0. 1. 2. 3.]
[ 4. 5. 9. 7.]
[ 8. 9. 10. 11.]]
<NDArray 3x4 @cpu(0)>
當然,我們也可以擷取一部分元素,併為它們重新賦值。在下面的例子中,我們為行索引為 1 的每一列元素重新賦值。
In [23]: X[1:2, :] = 12
X
Out[23]:
[[ 0. 1. 2. 3.]
[12. 12. 12. 12.]
[ 8. 9. 10. 11.]]
<NDArray 3x4 @cpu(0)>
2.2.5 運算的記憶體開銷
在前面的例子裡我們對每個操作新開記憶體來儲存運算結果。舉個例子,即使像Y = X + Y這樣的運算,我們也會新開記憶體,然後將Y指向新記憶體。為了演示這一點,我們可以使用 Python 自帶的id函式:如果兩個例項的 ID 一致,那麼它們所對應的記憶體地址相同;反之則不同。
In [24]: before = id(Y)
Y = Y + X
id(Y) == before
Out[24]: False
如果想指定結果到特定記憶體,我們可以使用前面介紹的索引來進行替換操作。在下面的例子中,我們先透過zeros_like建立和Y形狀相同且元素為 0 的 NDArray,記為Z。接下來,我們把X + Y的結果透過[:]寫進Z對應的記憶體中。
In [25]: Z = Y.zeros_like()
before = id(Z)
Z[:] = X + Y
id(Z) == before
Out[25]: True
實際上,上例中我們還是為X + Y開了臨時記憶體來儲存計算結果,再複製到Z對應的記憶體。如果想避免這個臨時記憶體開銷,我們可以使用運算子全名函式中的out引數。
In [26]: nd.elemwise_add(X, Y, out=Z)
id(Z) == before
Out[26]: True
如果X的值在之後的程式中不會複用,我們也可以用 X[:] = X + Y 或者 X += Y 來減少運算的記憶體開銷。
In [27]: before = id(X)
X += Y
id(X) == before
Out[27]: True
2.2.6 NDArray和NumPy相互變換
我們可以透過array 函式 和asnumpy 函式 令資料在NDArray和NumPy格式之間相互變換。下面將NumPy例項變換成NDArray例項。
In [28]: import numpy as np
P = np.ones((2, 3))
D = nd.array(P)
D
Out[28]:
[[1. 1. 1.]
[1. 1. 1.]]
<NDArray 2x3 @cpu(0)>
再將 NDArray 例項變換成NumPy 例項。
In [29]: D.asnumpy()
Out[29]: array([[1., 1., 1.],
[1., 1., 1.]], dtype=f loat32)
小結
- NDArray 是 MXNet 中儲存和變換資料的主要工具。
- 可以輕鬆地對 NDArray 建立、運算、指定索引,並與NumPy 之間相互變換。
練習
(1)執行本節中的程式碼。將本節中條件判別式X == Y改為X < Y或X > Y,看看能夠得到什麼樣的 NDArray。
(2)將廣播機制中按元素運算的兩個NDArray替換成其他形狀,結果是否和預期一樣?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29829936/viewspace-2653976/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【筆記】動手學深度學習-預備知識筆記深度學習
- 機器學習學習筆記——基本知識機器學習筆記
- Python學習-字串的基本知識Python字串
- 需掌握的深度學習知識深度學習
- 動手學深度學習需要這些數學基礎知識深度學習
- Java程式設計師需要學習哪些知識?Java程式設計師
- 學習程式設計前的準備程式設計
- 【深度學習】機率論知識複習深度學習
- C#程式設計學習(04):基本操作學習總結C#程式設計
- 程式設計學習MarkDown學習程式設計
- [譯]深度學習中所需的線性代數知識深度學習
- 學習程式設計之前一定要學習數學嗎? - CACM程式設計ACM
- 機器學習數學知識積累之數理統計機器學習
- 讀這一篇,對於AI、機器學習、深度學習你都會有基本的認知AI機器學習深度學習
- 程式設計師:學校教的數學知識,程式設計根本用不到!程式設計師
- 程式設計學習,知識付費已是常事,知識變現更重要!程式設計
- 0801-深度學習程式架構設計深度學習架構
- Java學習筆記之----------Java基本知識Java筆記
- 資料庫MySQL需要學習基本知識資料庫MySql
- 機器學習及深度學習的知識點及面試題總結機器學習深度學習面試題
- web知識學習Web
- 機械學習和深度學習的區別深度學習
- 機器學習和深度學習的區別機器學習深度學習
- 對深度學習的認識深度學習
- 機器學習之必備知識篇機器學習
- 送AI專欄|深度學習必備的5大知識模組(內附知識卡片)AI深度學習
- 機器學習數學知識積累總結機器學習
- 深度學習機器學習基礎-基本原理深度學習機器學習
- 《深度學習入門:》學習基本第一章深度學習
- 學習Python的幾個必要條件,你具備嗎?Python
- Java入門基礎學習,成為一個Java程式設計師的必備知識Java程式設計師
- Linux學習/TCP程式設計學習筆記LinuxTCP程式設計筆記
- 雲端計算教程學習入門影片:雲端計算學習的必學知識
- 深度學習學習框架深度學習框架
- 學習雲端計算好就業嗎?需要學習哪些知識?就業
- 機器學習中那些必要又困惑的數學知識機器學習
- 學習的學習之七—如何應用元知識
- 深度學習+深度強化學習+遷移學習【研修】深度學習強化學習遷移學習