前言 Hello,大家好,歡迎來到『自由技藝』的學習小館。在之前的文章中,我介紹了一些互聯網的知識,比如加密算法、編譯器、web 服務等,也介紹了些基本的 AI 算法,最多的還是 C++ 系列文章,內容淺顯易懂,附有能直接運行的樣例代碼,對新手還算是很友好吧~。接下來,我將開啟一個新的系列專題 - 動手學習深度學習框架。之前李沐大神有個『動手學深度學習』系列很受歡迎,對于我這個專題,不指望能成為爆款,本著交流學習的目的,希望借此讓大家了解下深度學習框架的設計思想及實現方法。本系列專題以百度 PaddlePaddle(飛槳)開源深度學習框架為例,深入淺出,學完本系列專題希望不僅能讓你了解到神經網絡的計算原理,同時也學到一些 C++ 的優秀實踐,從源碼開始讀,掌握每個小的知識點。 深度學習框架到底能干什么 首先,我們用 tensorflow、pytorch 或者 paddlepaddle 寫一段 python 代碼來組建一個神經網絡模型,然后訓練,達到一定精度后再保存模型,最后基于訓練好的模型做圖像識別、語音識別等任務。這個流程想必大家都很清楚了,那這一切都是誰來計算的呢?答案是后臺框架,你所寫的 python 代碼只不過是前端 API,真正調用的是后端 C 或 C++ 計算邏輯,而前端 python API 和 后端計算邏輯正是通過 pybind 綁定的。 深度學習框架最基本的功能就是要能提供一系列算子(俗稱『OP』,operator 的簡稱),支持前向計算和反向梯度更新。如此說來,框架應該很簡單呀。實則不然,且聽我細細道來。首先,這些 OP 數量很大,比如卷積、全連接、各種激活函數(如 Relu、Sigmoid)、各種梯度更新算法(如 Adam、RMS)等等。其次,組建神經網絡模型時,需要提供靜態圖模式(聲明式編程)和動態圖模式(函數式編程)。動態圖好理解,就是我們平時寫代碼的邏輯,do A -> do B -> do C,按流程順序執行任務,每寫完一行代碼就能得到相應的結果。而靜態圖就不大好理解了,用戶所寫的代碼僅僅是為了構建一張圖,圖構建完之后再去執行,執行完才能得到結果,而不像動態圖那樣能實時獲取結果。靜態圖這種方式有什么好處呢?答案是便于做性能優化,通過優化這張圖的結構,使得程序執行效率更高。靜態圖中的『圖』,又叫做 SSA Graph,Directed Acyclic Single Static Assignment Graph(有向無環靜態單賦值圖),那這張圖是如何構建出來的呢?如何去描述?如何把它序列化成二進制字節流在不同進程間傳遞呢?如何執行的?又是如何優化的呢? 還有,樣本數據該如何存儲呢?內存?緩存?SSD?還是哈希表,這些存儲資源該怎么管理呢?原始樣本文件又如何轉化成模型『認識』的 feed data 呢? 另外,模型如何保存呢?保存完整模型還是保存部分模型(比如只保留模型最后兩層)?模型又是如何加載呢?從頭開始訓練(冷啟動)和增量訓練(熱啟動)又有什么區別? 更重要的是,隨著模型越來越大,參數規模達到百億、千億,甚至萬億,對模型的訓練性能提出了非常高的要求,高性能的訓練框架不僅能大大縮短訓練時間,同時大大節約硬件資源,這可是實打實的真金白銀呀。另外,在推薦領域,All is Embedding,大規模稀疏參數需要大量的存儲空間,單機無法容納,需要借助分布式文件系統。于是,參數服務器(Parameter Server)這一解決方案應運而生。 考慮到不同廠家的各類 AI 芯片,如英偉達的 GPU、華為的昇騰、百度的昆侖等芯片,想要充分利用這些高性能 AI 硬件的能力,軟件必須得兼容這些硬件,而它們的編程語法, 編譯方法和英特爾的 x86 CPU 又不一樣,比如 cuda 編程等,硬件之間又涉及到通信問題,如 nccl。自然地,CPU 參數服務器進化成了異構參數服務器。參數服務器系統中又牽扯出了各式各樣的并行優化策略,如數據并行、模型并行、流水線并行、混合并行、自動并行等,數據和模型中的各個層(layer)要如何切分,才能充分利用硬件資源呢?不僅如此,分布式系統中的通信算法,如 gloo、mpi 等,不同進程間又涉及到同步問題,如 barrier 算法。 從應用層面看,還包括基于 k8s、docker、yarn 等訓練資源調度系統的搭建、實現基于 C++、Java、Go 等主流語言的線上低時延, 高吞吐推理預測服務、終端低功耗的 PaddleLite 解決方案等。一款合格的深度學習訓練框架應該是工業級的產品,具備高性能、支持各類 AI 硬件、能大規模部署、能支持所有 AI 模型,API 還必須得是用戶友好的。 希望上述這些問題,在接下來的學習中,都能一一找到答案,敬請期待。 |
|