1. 程式人生 > >機器學習系統或者SysML&DL筆記(一)

機器學習系統或者SysML&DL筆記(一)

# 前言 在使用過TVM、TensorRT等優秀的機器學習編譯優化系統以及Pytorch、Keras等深度學習框架後,總覺得有必要從**理論上**對這些系統進行一些分析,雖然說在實踐中學習是最快最直接的(指哪兒打哪兒、不會哪兒查哪兒),但惡補一些關於系統設計的一些知識還是非常有用了,權當是鞏固一些基礎了。 因此,有必要學習瞭解一下機器學習系統的設計和思想。如果不是很瞭解機器學習系統的設計,可以看下知乎上關於這個問題的回答:[相比AI演算法研究,計算機系統研究沒落了嗎?](https://www.zhihu.com/question/322296599/answer/673561614) 以下是本系列文章的筆記來源: - [CSE 599W: Systems for ML](http://dlsys.cs.washington.edu/schedule) - [AI-Sys Spring 2019](https://ucbrise.github.io/cs294-ai-sys-sp19/) 注意,這一系列文章並不是傳統的深度學習或者機器學習講解,關於這部分的講解可以看CS231n或者吳恩達的入門課,該系列文章適合在深度學習方面有經驗有了解的童鞋。 附一張**CSE 599W**這門課(偶像tqchen主講)一開始的講解說明: ![TIM截圖20190509181944](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225925131-2115046796.jpg) 這門課主要的重點不在深度學習理論演算法,而是與深度學習有關,機器學習系統方面的講解。 ## 什麼是深度學習 簡單說下深度學習。 ![TIM截圖20190509182437](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225925333-1625727562.jpg) 由上圖可知,深度學習所包含的基本內容,也就是以下四大部分: - 模型的設計(最核心的地方,不同的任務設計的模型不同,使用的具體演算法也不同) - 目標函式,訓練策略(用於訓練模型權重引數的目標函式,也就是損失函式,以及一些訓練的方法) - 正則化和初始化(與訓練過程中的模型權重資訊有關係,加快訓練的收斂速度,屬於訓練部分) - 足夠多的資料(機器學習亦或深度學習都是由資料驅動著了,沒有資料的話就什麼都不是) 我們在學習深度學習的過程中,難免會有一些實踐,於是我們就利用以下這些優秀的深度學習庫去實現我們自己設計的模型,並且設計好損失函式,一些正則化策略,最終利用這些庫去讀入我們需要新聯的資料,然後執行等待即可。 ![TIM截圖20190509190226](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225925552-559838367.jpg) 這些優秀的深度學習庫(caffe、Mxnet、TF、Pytorch)我們應該都耳熟能詳了,那麼這些深度學習庫的大概結構都是什麼呢? 大部分的深度學習庫都是由以下三個部分組成 - 使用者API - 系統元件 - 底層架構 大多數的我們其實並不需要接觸除了使用者API以外的其他兩個部分,而使用者API也是深度學習庫最頂層的部分。 ![TIM截圖20190509191530](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225925770-1950190088.jpg) ## Logistic Regression 拿個例子簡單說一下使用者的API,首先我們有一個邏輯迴歸的任務,就拿最熟悉的MNIST資料集來進行演示,我們通過輸入每個數字的向量化資料,然後通過全連線層去計算這些向量並且利用softmax函式進行預測。整個網路模型很簡單已有一層全連線層。 ![TIM截圖20190509191558](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225925939-671779181.jpg) 接下來我們看一下使用numpy和[tinyflow](https://github.com/tqchen/tinyflow)(這是一個迷你的深度學習系統庫,麻雀雖小五臟俱全,值得我們去學習)去訓練一個簡單的神經網路識別MNIST手寫資料庫的例子:
上述程式碼中**最重要**的也就是三個部分(在上圖右側已經列了出來): - 前向計算:因為只有一個全連線層,所以我們的計算也很簡單$h_{k}=w_{k}^{T} x_{i}$,其中$ x_{i}$為輸入的資料,$w_{k}^{T}$為權重,$h_{k}$為權重向量和資料向量點乘的結果。計算出來結果後我們使用softmax函式對其進行分類計算得到對應十個數字的概率向量(最後輸出的向量包含10個元素,分別為每個數字的可能性) - 反向求導:我們求出權重W關於極大似然損失的導數,這裡我們人工寫了出來,在右圖第二部分 - 梯度更新:我們簡單對權重W進行更新,更新值為學習率乘以W的梯度,即$w \leftarrow w-\eta \nabla_{w} L(w)$,也就是我們經常用的SGD 整個深度學習庫中最重要的也就是上述三個部分,大部分的深度學習庫已經幫我們實現了上述的程式碼,我們不需要重複造輪子,直接使用即可。 ### 嘗試使用TensorFlow like API 接下來,我們使用類似於TensorFlow的API來對上述描述的程式碼進行重構,使用TensorFlow的API格式來實現上述程式碼實現的訓練過程。 那麼,為什麼要使用TensorFlow型別的API進行演示而不是採用Pytorch呢?其實TensorFlow與Pytorch構建的圖型別很不一樣,雖然在最近一段時間TensorFlow已經出現了`eager mode`,但經典的TensorFlow是採用靜態圖來構建整個訓練過程的。 也就是說,在TF中構建的是靜態圖,而在Pytorch中構建的是動態圖: ![Computation_model](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225926116-2134116451.jpg) 其實關於靜態圖和動態圖對於這個話題已經經過了很多的討論,動態圖靈活多變,而靜態圖雖然沒有動態圖靈活,但是因為提前都確定好了輸入引數,計算方式等等過程,系統可以針對這些特點來對計算進行規劃,所以在計算過程中的效能比動態圖是要高一些的。 首先我們確定要進行的前向資料以及操作運算元: - 輸入x為float32型別的向量,[None,784]中None表示當前輸入的batch-size未知 - W為權重資訊,維度為[784,10] - y為前向計算函式,利用運算元函式巢狀定義了整個計算過程。 ![tinyflow-1](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225926341-1386151911.jpg) 接下來設定了損失函式,可以看到 ```python cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1])) ``` 這句中聲明瞭一個損失函式,使用的是分類任務中最常用的交叉熵損失,注意`y_`代表存放麼一個數據的分類label,每一個數據的分類標籤是一個元素數量為10的向量,用於與預測出來的值進行比對。具體的公式在下圖右側。 ![tinyflow-2](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225926594-256045464.jpg) 接下來設定了自動求導的過程,這一步中我們要求的是權重向量對損失值(也就是交叉熵損失後計算出來的值)的梯度,這裡我們只是聲明瞭一個函式,但是其中的計算過程是比較複雜的(也就是我們常說的自動求導的過程),這個之後會進行講解,自動求導是我們必須要掌握的,直接手擼是必須的。 ![tinyflow-3](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225926798-1576280155.jpg) 設定好了損失函式,接下來我們就要拿計算出來的梯度值來更新網路的權重資訊了,在這個例子中使用SGD隨機梯度下降的方式進行權重更新,我們只需要設定學習率這個超引數就可以。 ![tinyflow-4](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225926957-2144725936.jpg) 因為在TF中,所有的宣告式都僅僅是對要計算的流程進行宣告,實際上並沒有計算(這裡可以稱為一個懶計算的方法),也就是所謂的靜態圖方式定義好了整個網路以及訓練的步驟,只是沒有開始運作而已。 在執行完`sess.run`一句後,整個網路才開始正式執行起來。 ![tinyflow-5](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225927223-604007920.jpg) 這幾張ppt的內容講述了一個典型的神經網路庫的執行流程(TF型別的,如果是Pytorch的話略有不同),通過這個我們可以知道一個深度學習框架的基本作用。接下來要說的就是上述過程中最為重要的自動求導過程。 ### 計算圖(Computation Graph) 計算圖是實現自動求導的基礎,也是每個深度學習框架必須實現的部分,接下來我們簡單說說計算圖是什麼? 要說起計算圖首先簡單提一下宣告式程式設計,正如下圖中所展示的,計算圖本質上是一種宣告式語言,怎麼說比較合適,這種語言不同於我們平時所說的python和C++,它是一種DSL(領域語言)或者一種迷你語言,這種語言深入嵌入到Python和C++中,也就是我們使用Python去操作,使用C++去具體實現。 是宣告式程式設計不是簡單地一條接一條地執行我們的指令,而是根據我們給出的所有指令建立一個計算圖(computing graph)。這個圖被內部優化和編譯成可執行的 C++ 程式碼。這樣我們就能同時利用上兩個世界的最優之處:Python 帶來的開發速度和 C++ 帶來的執行速度。 最終形態就是我們提前設定好了計算邏輯,其他的交給系統就行了,具體怎麼優化就不用我們去操心。 下圖中就是一個簡單的例子,我們定義計算的邏輯`a*b+3`這個邏輯,其中node表示計算內容,箭頭表示依賴關係。 ![computation_graph1](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225927387-1900761264.jpg) 下圖中我們就利用TF-like API去實現一個簡單的$t=softmax(W*x)$的過程,這個過程需要的資料(x、W)和運算元(matmult、softmax)都已經提前定義好了。 ![computation_graph2](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225927545-374502030.jpg) 接下來是設定損失函式的計算部分: ![computation_graph3](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225927708-83888148.jpg) 然後設定與自動求導相關的梯度下降部分: ![computation_graph4](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225927869-1757903361.jpg) 接下來是設定梯度更新的方式: ![computation_graph5](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225928022-579411421.jpg) 在設定玩所有的計算邏輯後,這裡正式開始計算的過程,只有執行完`sess.run`這句後,整個計算圖才開始真正的進行計算了。 ![computation_graph6](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225928209-1909347159.jpg) 上面關於自動求導的具體過程並沒有展示,這個過程將在下一節中進行講解,不過關於自動求導的具體流程也可以在CS231n這門課中見到,具體在**Backpropagation and Neutal Networks**這一節中。 ### numpy 與 TF-program 的比較 之前我們使用了numpy與TF-like API的方式模擬了一個簡單的Logistic Regression的過程,也就是實現利用一個簡單的全連線網路去識別手寫數字集MNIST的過程,這個過程中我們使用了兩種不同的方式去構建,用計算圖來說就是**動態圖(numpy)與靜態圖(TF)**,而用語言型別來說就是**指令式程式設計(numpy)和宣告式程式設計(TF)**。 其實上述的numpy的例子也可以使用Pytorch做演示,因為Pytorch是一個類numpy的深度學習庫,其操作的運算元邏輯和numpy幾乎一致,可以說是一個利用動態圖結構的領域語言。 也就是說關於numpy與 TF-program 的比較,可以等同於關於動態圖和靜態圖的比較,兩者各有優缺點,但是如果追求效能和開發效率的話,靜態圖更勝一籌,但是如果追求靈活性和可拓展性,那麼動態圖的優勢就展現出來了。 ![discuss_numpy_and_tf](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225928485-2094602401.jpg) ## 未完待續 這節課的末尾提出了一些後續要講的內容,首當其衝的就是計算圖的優化。 計算圖優化在TVM中這個深度學習編譯器中佔了很大的篇幅,正如下面所說,我們建立了計算圖,因為這個計算圖是靜態的,所以我們可以在底層對其進行儘可能地優化,從而加快神經網路執行的速度,那麼如何去優化呢?這可就是一個大學問,總之就是我們可優化的空間很大,而關於優化的具體細節放在之後進行描述。 ![TIM截圖20190512165609](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225928641-850902926.jpg) 另外一點,資料並行也是重點解決的問題之一,畢竟現在的資料越來越多,顯示卡計算能力雖然每年提升,但是記憶體(具體點就是視訊記憶體)的提升有限。那麼如何更高效更快地訓練大量的資料,直接的途徑就是並行分散式訓練,如何處理並行期間出現的問題也是一個重點的方向。 ![parallel_scheduling](https://img2020.cnblogs.com/other/2304365/202103/2304365-20210303225928806-1840103032.jpg) # 相關參考 http://dlsys.cs.washington.edu/schedule https://ucbrise.github.io/cs294-ai-sys-sp19/ https://blog.csdn.net/tealex/article/details/75333222 # 撩我吧 - 如果你與我志同道合於此,老潘很願意與你交流; - 如果你喜歡老潘的內容,歡迎關注和支援。 - 如果你喜歡我的文章,希望點贊