初識深度學習:從原理淺析到MXNet初體驗
來自專欄網路安全大事件4 人贊了文章
0x00 前言
最近看了一些文章,介紹了深度學習演算法在安全領域的應用。可以極大的提高安全產品的檢測效率。決定還是要投入精力在這塊知識的學習上,昨天剛好看到大佬分享了一份深度學習的教程,在跟進教程的過程中,我順手記了點東西,於是便有了本篇筆記。
由於我也是剛開始接觸這塊內容,行文中存在謬誤在所難免,還望各位看官多多指正。
0x01 初識深度學習
在筆記的開始,首先要了解3個問題:
什麼是人工智慧?
什麼是機器學習?
什麼是深度學習?
先來說說對人工智慧的定義吧,人工智慧,用於實現模擬人的思考行為,通俗來講是通過一些演算法去解決一些模糊定義的問題。
那機器學習呢?機器學習是人工智慧的一個分支,主要是利用一些統計學方法,對數據進行壓縮、訓練,得到一個精簡的模型,利用訓練好的模型對未知內容進行處理。
深度學習是機器學習的一個子集,可以追溯到從神經網路發展過來,相比神經網路,深度學習可以把模型做的更深、更複雜。數據量也會更大,同時配合更為強大的計算資源,可以做到更好的訓練效果。
0x02 深度學習的應用場景
深度學習技術廣泛應用於各個領域,這裡介紹幾個大家都了解的,且應用深度學習技術的場景:
1、AlphaGo
AlphaGo採用了增強學習的演算法,通過大量的模擬、學習、計算,最終可以在圍棋競賽上打贏人類。
2、物體識別
無人駕駛,汽車的攝像頭可以識別出前方的人、物體等。對應的是技術是計算機視覺領域的物體識別。
3、語音識別
這塊接觸的比較多,像各類手機的語音助手、各家IoT廠商推出的智能音箱等。
4、機器翻譯
基於深度學習演算法,可以提高機器翻譯的準確率。
5、推薦系統
比較多的是電商網站根據用戶平時的瀏覽、搜索習慣等,結合深度學習演算法,推薦給用戶可能想買的商品。
6、點擊預測
搜索引擎根據用戶平時的瀏覽、搜索習慣等,結合深度學習演算法,推薦廣告,增加廣告的點擊率、轉化率等。
0x03 深度學習入門
教程的作者提到,其在後續的課程中講解的「內容和工業界應用相比,主要只是數據規模和模型複雜度的區別」。在這系列的教程中會結合實踐講解工業界常用的深度學習演算法,那不出意外,我的筆記也會一直跟著更新,期待的搓手手:)
常見的深度學習框架
不得不說A廠推廣自己的深度學習框架也是用心良苦了,哈哈。
MXNet/Gluon的安裝
根據官方文檔,先來安裝Miniconda,相應的下載地址:https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh。
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上的安裝