具備基本的數學和程式設計知識,你就可以學習深度學習啦
深度學習很難?對深度學習存有困惑,不知道從哪裡下手,不知道適不適合自己學習?只需瞭解基礎的數學和程式設計,如基礎的線性代數、微分和機率,以及基本的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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【筆記】動手學深度學習-預備知識筆記深度學習
- 需掌握的深度學習知識深度學習
- 動手學深度學習需要這些數學基礎知識深度學習
- ExtJs 基本知識學習JS
- Shell程式設計基礎學習之二:變數的基本認知程式設計變數
- Python學習-字串的基本知識Python字串
- 【深度學習】機率論知識複習深度學習
- Java程式設計師需要學習哪些知識?Java程式設計師
- 機器學習學習筆記——基本知識機器學習筆記
- [譯]深度學習中所需的線性代數知識深度學習
- C#程式設計學習(04):基本操作學習總結C#程式設計
- 程式設計學習MarkDown學習程式設計
- 學習程式設計前的準備程式設計
- ARM學習中的必知基本常識
- 程式設計師是否需要學習底層知識程式設計師
- 機器學習vs深度學習及其知識點機器學習深度學習
- 學習程式設計之前一定要學習數學嗎? - CACM程式設計ACM
- 作為程式設計師應具備的基本知識 (轉)程式設計師
- 深度學習(一)深度學習學習資料深度學習
- 雲端計算教程學習入門影片:雲端計算學習的必學知識
- 當知識圖譜“遇見”深度學習深度學習
- 資料庫MySQL需要學習基本知識資料庫MySql
- Java學習筆記之----------Java基本知識Java筆記
- vue學習筆記1-基本知識Vue筆記
- 程式設計師:學校教的數學知識,程式設計根本用不到!程式設計師
- web知識學習Web
- 知識學習綜合
- 學習程式設計 vs 學習電腦科學程式設計
- 程式設計學習,知識付費已是常事,知識變現更重要!程式設計
- 機械學習和深度學習的區別深度學習
- 對深度學習的認識深度學習
- 送AI專欄|深度學習必備的5大知識模組(內附知識卡片)AI深度學習
- 學習雲端計算好就業嗎?需要學習哪些知識?就業
- java程式設計學習知識點——java的異常處理Java程式設計
- 教孩子學習程式設計基礎知識的 10 個工具程式設計
- 深度學習學習框架深度學習框架
- 程式設計師都應學習程式碼編譯器知識程式設計師編譯
- 《深度學習入門:》學習基本第一章深度學習