初識深度學習:從原理淺析到MXNet初體驗

初識深度學習:從原理淺析到MXNet初體驗

來自專欄網路安全大事件4 人贊了文章

0x00 前言

最近看了一些文章,介紹了深度學習演算法在安全領域的應用。可以極大的提高安全產品的檢測效率。決定還是要投入精力在這塊知識的學習上,昨天剛好看到大佬分享了一份深度學習的教程,在跟進教程的過程中,我順手記了點東西,於是便有了本篇筆記。

由於我也是剛開始接觸這塊內容,行文中存在謬誤在所難免,還望各位看官多多指正。

0x01 初識深度學習

在筆記的開始,首先要了解3個問題:

什麼是人工智慧?

什麼是機器學習?

什麼是深度學習?

先來說說對人工智慧的定義吧,人工智慧,用於實現模擬人的思考行為,通俗來講是通過一些演算法去解決一些模糊定義的問題。

那機器學習呢?機器學習是人工智慧的一個分支,主要是利用一些統計學方法,對數據進行壓縮、訓練,得到一個精簡的模型,利用訓練好的模型對未知內容進行處理。

深度學習是機器學習的一個子集,可以追溯到從神經網路發展過來,相比神經網路,深度學習可以把模型做的更深、更複雜。數據量也會更大,同時配合更為強大的計算資源,可以做到更好的訓練效果。

0x02 深度學習的應用場景

深度學習技術廣泛應用於各個領域,這裡介紹幾個大家都了解的,且應用深度學習技術的場景:

1、AlphaGo

AlphaGo採用了增強學習的演算法,通過大量的模擬、學習、計算,最終可以在圍棋競賽上打贏人類。

2、物體識別

無人駕駛,汽車的攝像頭可以識別出前方的人、物體等。對應的是技術是計算機視覺領域的物體識別。

3、語音識別

這塊接觸的比較多,像各類手機的語音助手、各家IoT廠商推出的智能音箱等。

4、機器翻譯

基於深度學習演算法,可以提高機器翻譯的準確率。

5、推薦系統

比較多的是電商網站根據用戶平時的瀏覽、搜索習慣等,結合深度學習演算法,推薦給用戶可能想買的商品。

6、點擊預測

搜索引擎根據用戶平時的瀏覽、搜索習慣等,結合深度學習演算法,推薦廣告,增加廣告的點擊率、轉化率等。

0x03 深度學習入門

教程的作者提到,其在後續的課程中講解的「內容和工業界應用相比,主要只是數據規模和模型複雜度的區別」。在這系列的教程中會結合實踐講解工業界常用的深度學習演算法,那不出意外,我的筆記也會一直跟著更新,期待的搓手手:)

常見的深度學習框架

不得不說A廠推廣自己的深度學習框架也是用心良苦了,哈哈。

MXNet/Gluon的安裝

根據官方文檔,先來安裝Miniconda,相應的下載地址:repo.continuum.io/minic

wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.shbash Miniconda3-latest-Linux-x86_64.sh

下載相應的教程及代碼:

git clone https://github.com/mli/gluon-tutorials-zhcd gluon-tutorials-zhbashconda env create -f environment.ymlsource activate gluon

安裝完成。

可以通過如下命令實現虛擬環境的激活與退出:

source activate gluonsource deactivate

安裝notedown插件,運行Jupyter Notebook並載入插件:

pip install https://github.com/mli/notedown/tarball/masterjupyter notebook --NotebookApp.contents_manager_class=notedown.NotedownContentsManager --allow-root

最後將遠端的8888埠映射到本地,然後即可通過瀏覽器訪問

ssh -L 8888:localhost:8888 root@myserverhttp://localhost:8888/notebooks/chapter_crashcourse/introduction.md

0x04 如何使用NDArray來處理數據

關於NDArray官方文檔已經說的很詳細了,本文不做過多的介紹,我們只要知道NDArray比NumPy更強大,其提供了CPU和GPU的非同步運算,同時支持自動求導

剩下的就是跟一遍文檔了。

NDArray幾種不同的創建方法

第1條:從mxnet中導入nd

第2條:使用arange()函數創建一個長度為12的行向量

該NDArray包含12個元素(element),其值為arange(12)指定的0-11。在列印的結果中標註了屬性<NDArray 12 @cpu(0)>。其中12指的是NDArray的形狀,就是向量的長度。@cpu(0)表示默認情況下NDArray被創建在CPU上。

第3條:使用reshape()函數修改x的形狀,將x修改為一個3行4列的矩陣

第4條:創建一個各元素為0,形狀為(2,3,4)的張量。PS:矩陣和向量都是一種特殊的張量。

第5條:同理,創建一個各元素為1的張量。

第6條:通過Python的列表(list)指定NDArray中每個元素的值。

第7條:通過nd.random.normal()方法,隨機生成NDArray每個元素的值,創建一個形狀為(3,4)的NDArray。每個元素隨機採樣於均值為0方差為1的正態分布。

第8條:通過shape屬性獲取形狀,通過size屬性獲取NDArray中元素的個數。

NDArray的運算

第1條:按元素加法

第2條:按元素乘法

第3條:按元素除法

第4條:按元素指數運算,exp

第5條:對矩陣b做轉置,矩陣a、b做矩陣乘法操作,a為3行4列,b為4行3列,故其結果為一個3行3列的矩陣。dot

第6條:NDArray元素求和(結果為標量,但仍然為NDArray格式,可以通過norm().asscalar()函數轉換為Python中的數),sum()

廣播機制

上面提到的兩個NDArray之間元素級的運算都是基於兩個NDArray形狀相同,如果兩個NDArray形狀不同,在運算的過程中會觸發廣播(broadcasting)機制,即先把兩個NDArray搞成形狀相同,然後再進行運算。

廣播(broadcasting)機制簡單理解就是行與列間複製,達到不同NDArray之間形狀相同的目的。

NDArray在進行運算的過程中產生的內存開銷

第1條:每一個操作都會新開闢一塊內存空間用來存儲操作後的運算結果。

第2條:可以通過[:]將計算結果寫入之前變數創建的內存空間中。nd.zeros_like(x)方法可以創建一個形狀和x相同,但元素均為0的NDArray。

第3條:在第2條的運算中,雖然變數z在計算前後的內存地址相同,在本質上其運行原理仍然是先將x+y的值放到一個新開闢的內存空間中,然後再將結果拷貝到z的內存中。

為了避免這種計算過程中的內存開銷,可以使用運算符全名函數中的out參數解決該問題。

可以看到,前後的內存地址相同,這種開銷也得以避免。

第4條:現有NDArray的值在之後的程序中不會復用,可以直接使用如下方法來減少內存開銷。x+=y,x[:]=x+y

NDArray的索引

類比Python中列表(list)的索引,NDArray的索引可以理解為每一個元素的位置。索引的值從0開始逐漸遞加。

舉個栗子,一個3行2列的矩陣,其行索引為0,1,2,列索引為0,1。

第1條:創建一個3行3列的矩陣x,通過x[1:3],根據Python的開閉原則,可知取的值為索引為1和2行的數據。

第2條:通過x[1,2]這種形式可以取出指定的元素,可以對其重新賦值。

第3條:可以通過[1:2,1:3]這種方式取出NDArray中的多個元素,可以對這些元素進行重新賦值。

NDArray與NumPy格式的相互轉換

可以通過array()函數將numpy轉換為ndarray,通過asnumpy()函數將ndarray轉化為numpy。

小結

NDArray是MXNet中存儲和轉換數據的主要工具,可以將它理解為MXNet實現的一種數據結構。

在這一節中可以了解到如何對NDArray進行創建、運算、制定索引,同時與numpy格式進行轉換的方法。

0x05 簡述MXNet提供的自動求導功能

很多深度學習框架需要編譯計算圖進行求導,而MXNet不需要,使用自帶的autograd包即可實現自動求導功能。

下面來看兩個例子。

第一個:對簡單的數學函數進行求導

對函數y=2x^2進行求導

其中涉及的細節有一點:

1、求變數x的導數,需要先調用x.attach_grad()函數創建需要的內存空間

2、為了減少計算和內存的開銷,默認情況下,MXNet不會記錄用於求倒數的計算圖,我們需要需要調用autograd.record()函數來讓MXNet記錄有關的計算圖。

3、通過y.backward()函數求倒數,其結果為x.grad

第二個:對Python的控制流求導

對如下函數進行求導:

def f(a): b = a * 2 while b.norm().asscalar() < 1000: b = b * 2 if b.sum().asscalar() > 0: c = b else: c = 100 * b return c

函數f(a)最後的輸出值c由輸入值a決定,即c=xa,導數x=c/a。

小結

通過MXNet自動求導總共分為3步:

1、開闢存儲導數的內存空間a.attach_grad()

2、通過autograd.record()函數記錄計算圖,並實現相應的函數

3、調用c.backward()函數進行求導

0x06 如何通過ndarray和autograd實現簡單的線性回歸

插一句題外話,因為本身是個網路安全從業者,與其耗費大量的時間糾結基本的數學理論,不如先去了解通過一些成熟的深度學習框架,去實現這些演算法,應用於安全領域(比如說流量分析、惡意樣本分析、webshell查殺等等)。一來是更容易產生價值,二來也可以激發深入學習的興趣吧。

線性回歸是監督學習中的一種,是一個最簡單,也是最有用的單層神經網路。

我的理解是這樣的給定一些數據集X,根據訓練好的模型(將數據集X帶入模型中),都有一個特定的y值與其對應。訓練這個模型就是我們需要做的工作。

那線性回歸就是y=ax+b,我們要做的就是確定斜率a和位移b的值。

第1步:數據集的創建

在工業級的生產環境中,數據集往往來源於真事的業務場景(在Web日誌中挖掘攻擊行為呀,預測房價啊一類的),這裡是演示,所以暫且使用隨機生成的數據。

在第一個例子中,作者使用了一套人工生成的數據,相應的生成公式如下。

y[i] = 2*X[i][0] - 3.4*X[i][1] + 4.2 + noise

noise服從均值為0方差為0.1的正態分布。

相應的代碼如下:

>>> from mxnet import ndarray as nd>>> from mxnet import autograd>>> num_inputs = 2>>> num_examples = 1000>>> true_w = [2,-3.4]>>> true_b = 4.2>>> X = nd.random_normal(shape=(num_example,num_inputs))Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name num_example is not defined>>> X = nd.random_normal(shape=(num_examples,num_inputs))>>> y = true_w[0]*X[:,0]+true_w[1]*X[:,1]+true_b>>> y += .01*nd.random_normal(shape=y.shape)

第2步:數據讀取

當我們擁有了一定的數據集之後,我們要做的就是數據的讀取。不斷的讀取這些數據塊,進行神經網路的訓練。

相應的函數如下:

>>> def date_iter():... idx = list(range(num_examples))... random.shuffle(idx)... for i in range(0,num_examples,batch_size):... j = nd.array(idx[i:min(i+batch_size,num_examples)])... yield nd.take(X,j),nd.take(y,j)

通過yield關鍵字來構造成迭代器,依次取出不同的樣本數據(10個)。

通過for loop不斷的遍歷將迭代器中的數據取出。

>>> for date,label in adte_iter():... print(date,label)... break...

接下來將讀取到的數據,傳入我們給定的演算法中進行訓練。

第3步:定義模型

先來隨機初始化模型的參數。

創建參數的梯度:

參數初始化完成後我們就可以進行模型的定義:

>>> def net(X):... return nd.dot(X,w)+b

第4步:定義損失函數

通過損失函數衡量預測目標與真實目標之間的差距。

def square_loss(yhat,y): return (yhat - y.reshape(yhat.shape))**2

第5步:優化

使用梯度下降進行求解。

def SGD(params,lr): for param in params: param[:] = param - lr * param.grad

第6步:訓練

>>> epochs = 5>>> learning_rate = .001>>> >>> for e in range(epochs):... total_loss = 0... for data,label in adte_iter():... with autograd.record():... output = net(data)... loss = square_loss(output,label)... loss.backward()... SGD(params,learning_rate)... total_loss += nd.sum(loss).asscalar()... print("%d,loss: %f" % (e,total_loss/num_examples))... 0,loss: 0.1309111,loss: 0.0026282,loss: 0.0001503,loss: 0.0001024,loss: 0.000101

查看訓練結果(和我們的預期相同)

0x07 使用gluon的線性回歸

第1步:數據集的創建

第2步:數據讀取

第3步:定義模型

第4步:定義損失函數

第5步:優化

第6步:訓練

0x08 總結

本文主要為筆者在剛接觸深度學習時,看文檔+視頻最後整理的筆記。

通過幾天的學習了解到這塊的工作流程:

1、確認需要訓練的數據集(特徵工程)

2、將特徵工程後的數據讀取至內存中

3、定義模型同時初始化模型參數

4、定義損失函數、優化演算法

5、訓練模型及驗證結果

在訓練模型的過程中,要不斷的根據訓練結果調整模型參數,以達到理想解。

0x09 參考鏈接

NDArray API - mxnet documentation

Project Jupyter

apache/incubator-mxnet

動手學深度學習 - 動手學深度學習 0.6 文檔

瑣事閑談 & Pandas安利


推薦閱讀:

gluon源碼分析1
RefineDet 論文解析
GluonNLP 0.3.3 新功能及重現報告
mxnet訓練/導出/載入模型並預測(python和C++)
mxnet在linux上的安裝

TAG:機器學習 | MXNet | 網路安全 |