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

前言

在使用過TVM、TensorRT等優秀的機器學習編譯優化系統以及Pytorch、Keras等深度學習框架後,總以爲有必要從理論上對這些系統進行一些分析,雖說在實踐中學習是最快最直接的(指哪兒打哪兒、不會哪兒查哪兒),但惡補一些關於系統設計的一些知識仍是很是有用了,權當是鞏固一些基礎了。node

所以,有必要學習瞭解一下機器學習系統的設計和思想。若是不是很瞭解機器學習系統的設計,能夠看下知乎上關於這個問題的回答:相比AI算法研究,計算機系統研究沒落了嗎?python

如下是本系列文章的筆記來源:git

注意,這一系列文章並非傳統的深度學習或者機器學習講解,關於這部分的講解能夠看CS231n或者吳恩達的入門課,該系列文章適合在深度學習方面有經驗有了解的童鞋。github

附一張CSE 599W這門課(偶像tqchen主講)一開始的講解說明:算法

TIM截圖20190509181944

這門課主要的重點不在深度學習理論算法,而是與深度學習有關,機器學習系統方面的講解。數據庫

什麼是深度學習

簡單說下深度學習。編程

TIM截圖20190509182437

由上圖可知,深度學習所包含的基本內容,也就是如下四大部分:api

  • 模型的設計(最核心的地方,不一樣的任務設計的模型不一樣,使用的具體算法也不一樣)
  • 目標函數,訓練策略(用於訓練模型權重參數的目標函數,也就是損失函數,以及一些訓練的方法)
  • 正則化和初始化(與訓練過程當中的模型權重信息有關係,加快訓練的收斂速度,屬於訓練部分)
  • 足夠多的數據(機器學習亦或深度學習都是由數據驅動着了,沒有數據的話就什麼都不是)

咱們在學習深度學習的過程當中,不免會有一些實踐,因而咱們就利用如下這些優秀的深度學習庫去實現咱們本身設計的模型,而且設計好損失函數,一些正則化策略,最終利用這些庫去讀入咱們須要新聯的數據,而後運行等待便可。網絡

TIM截圖20190509190226

這些優秀的深度學習庫(caffe、Mxnet、TF、Pytorch)咱們應該都耳熟能詳了,那麼這些深度學習庫的大概結構都是什麼呢?架構

大部分的深度學習庫都是由如下三個部分組成

  • 用戶API
  • 系統組件
  • 底層架構

大多數的咱們其實並不須要接觸除了用戶API之外的其餘兩個部分,而用戶API也是深度學習庫最頂層的部分。

TIM截圖20190509191530

Logistic Regression

拿個例子簡單說一下用戶的API,首先咱們有一個邏輯迴歸的任務,就拿最熟悉的MNIST數據集來進行演示,咱們經過輸入每一個數字的向量化數據,而後經過全鏈接層去計算這些向量而且利用softmax函數進行預測。整個網絡模型很簡單已有一層全鏈接層。

TIM截圖20190509191558

接下來咱們看一下使用numpy和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

其實關於靜態圖和動態圖對於這個話題已經通過了不少的討論,動態圖靈活多變,而靜態圖雖然沒有動態圖靈活,可是由於提早都肯定好了輸入參數,計算方式等等過程,系統能夠針對這些特色來對計算進行規劃,因此在計算過程當中的性能比動態圖是要高一些的。

首先咱們肯定要進行的前向數據以及操做算子:

  • 輸入x爲float32類型的向量,[None,784]中None表示當前輸入的batch-size未知
  • W爲權重信息,維度爲[784,10]
  • y爲前向計算函數,利用算子函數嵌套定義了整個計算過程。

tinyflow-1

接下來設定了損失函數,能夠看到

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]))

這句中聲明瞭一個損失函數,使用的是分類任務中最經常使用的交叉熵損失,注意y_表明存放麼一個數據的分類label,每個數據的分類標籤是一個元素數量爲10的向量,用於與預測出來的值進行比對。具體的公式在下圖右側。

tinyflow-2

接下來設定了自動求導的過程,這一步中咱們要求的是權重向量對損失值(也就是交叉熵損失後計算出來的值)的梯度,這裏咱們只是聲明瞭一個函數,可是其中的計算過程是比較複雜的(也就是咱們常說的自動求導的過程),這個以後會進行講解,自動求導是咱們必需要掌握的,直接手擼是必須的。

tinyflow-3

設定好了損失函數,接下來咱們就要拿計算出來的梯度值來更新網絡的權重信息了,在這個例子中使用SGD隨機梯度降低的方式進行權重更新,咱們只須要設定學習率這個超參數就能夠。

tinyflow-4

由於在TF中,全部的聲明式都僅僅是對要計算的流程進行聲明,實際上並無計算(這裏能夠稱爲一個懶計算的方法),也就是所謂的靜態圖方式定義好了整個網絡以及訓練的步驟,只是沒有開始運做而已。

在運行完sess.run一句後,整個網絡纔開始正式執行起來。

tinyflow-5

這幾張ppt的內容講述了一個典型的神經網絡庫的運行流程(TF類型的,若是是Pytorch的話略有不一樣),經過這個咱們能夠知道一個深度學習框架的基本做用。接下來要說的就是上述過程當中最爲重要的自動求導過程。

計算圖(Computation Graph)

計算圖是實現自動求導的基礎,也是每一個深度學習框架必須實現的部分,接下來咱們簡單說說計算圖是什麼?

要提及計算圖首先簡單提一下聲明式編程,正以下圖中所展現的,計算圖本質上是一種聲明式語言,怎麼說比較合適,這種語言不一樣於咱們平時所說的python和C++,它是一種DSL(領域語言)或者一種迷你語言,這種語言深刻嵌入到Python和C++中,也就是咱們使用Python去操做,使用C++去具體實現。

是聲明式編程不是簡單地一條接一條地執行咱們的指令,而是根據咱們給出的全部指令建立一個計算圖(computing graph)。這個圖被內部優化和編譯成可執行的 C++ 代碼。這樣咱們就能同時利用上兩個世界的最優之處:Python 帶來的開發速度和 C++ 帶來的執行速度。

最終形態就是咱們提早設定好了計算邏輯,其餘的交給系統就好了,具體怎麼優化就不用咱們去操心。

下圖中就是一個簡單的例子,咱們定義計算的邏輯a*b+3這個邏輯,其中node表示計算內容,箭頭表示依賴關係。

computation_graph1

下圖中咱們就利用TF-like API去實現一個簡單的$t=softmax(W*x)$的過程,這個過程須要的數據(x、W)和算子(matmult、softmax)都已經提早定義好了。

computation_graph2

接下來是設置損失函數的計算部分:

computation_graph3

而後設定與自動求導相關的梯度降低部分:

computation_graph4

接下來是設定梯度更新的方式:

computation_graph5

在設定玩全部的計算邏輯後,這裏正式開始計算的過程,只有執行完sess.run這句後,整個計算圖纔開始真正的進行計算了。

computation_graph6

上面關於自動求導的具體過程並無展現,這個過程將在下一節中進行講解,不過關於自動求導的具體流程也能夠在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

未完待續

這節課的末尾提出了一些後續要講的內容,首當其衝的就是計算圖的優化。

計算圖優化在TVM中這個深度學習編譯器中佔了很大的篇幅,正以下面所說,咱們創建了計算圖,由於這個計算圖是靜態的,因此咱們能夠在底層對其進行儘量地優化,從而加快神經網絡運行的速度,那麼如何去優化呢?這可就是一個大學問,總之就是咱們可優化的空間很大,而關於優化的具體細節放在以後進行描述。

TIM截圖20190512165609

另一點,數據並行也是重點解決的問題之一,畢竟如今的數據愈來愈多,顯卡計算能力雖然每一年提高,可是內存(具體點就是顯存)的提高有限。那麼如何更高效更快地訓練大量的數據,直接的途徑就是並行分佈式訓練,如何處理並行期間出現的問題也是一個重點的方向。

parallel_scheduling

相關參考

http://dlsys.cs.washington.edu/schedule
https://ucbrise.github.io/cs294-ai-sys-sp19/
http://www.javashuo.com/article/p-zvtrboqt-rc.html

撩我吧

  • 若是你與我志同道合於此,老潘很願意與你交流;
  • 若是你喜歡老潘的內容,歡迎關注和支持。
  • 若是你喜歡個人文章,但願點贊👍 收藏 📁 評論 💬 三連一下~

想知道老潘是如何學習踩坑的,想與我交流問題~請關注公衆號「oldpan博客」。
老潘也會整理一些本身的私藏,但願能幫助到你們,點擊神祕傳送門獲取。

相關文章
相關標籤/搜索