從系統和代碼實現角度解析TensorFlow的內部實現原理 | 深度

2020-12-24 雷鋒網

雷鋒網(公眾號:雷鋒網)按:本文作者姚健,畢業於中科院計算所網絡數據實驗室,曾就職於360天眼實驗室,主要從事深度學習和增強學習相關研究工作。目前就職於騰訊MIG事業部,從事神經機器翻譯工作。

摘要

2015年11月9日,Google發布深度學習框架TensorFlow並宣布開源,並迅速得到廣泛關注,在圖形分類、音頻處理、推薦系統和自然語言處理等場景下都被大面積推廣。TensorFlow系統更新快速,官方文檔教程齊全,上手快速且簡單易用,支持Python和C++接口。本文依據對Tensorflow(簡稱TF)白皮書[1]、TF Github[2]和TF官方教程[3]的理解,從系統和代碼實現角度講解TF的內部實現原理。以Tensorflow r0.8.0為基礎,本文由淺入深的闡述Tensor和Flow的概念。先介紹了TensorFlow的核心概念和基本概述,然後剖析了OpKernels模塊、Graph模塊、Session模塊。

1. TF系統架構

1.1 TF依賴視圖

TF的依賴視圖如圖1所示[4],描述了TF的上下遊關係鏈。

圖 1 TensorFlow依賴視圖

TF託管在github平臺,有google groups和contributors共同維護。

TF提供了豐富的深度學習相關的API,支持Python和C/C++接口。

TF提供了可視化分析工具Tensorboard,方便分析和調整模型。

TF支持Linux平臺,Windows平臺,Mac平臺,甚至手機行動裝置等各種平臺。

1.2 TF系統架構

圖2是TF的系統架構,從底向上分為設備管理和通信層、數據操作層、圖計算層、API接口層、應用層。其中設備管理和通信層、數據操作層、圖計算層是TF的核心層。

圖2 TF系統架構

底層設備通信層負責網絡通信和設備管理。設備管理可以實現TF設備異構的特性,支持CPU、GPU、Mobile等不同設備。網絡通信依賴gRPC通信協議實現不同設備間的數據傳輸和更新。

第二層是Tensor的OpKernels實現。這些OpKernels以Tensor為處理對象,依賴網絡通信和設備內存分配,實現了各種Tensor操作或計算。Opkernels不僅包含MatMul等計算操作,還包含Queue等非計算操作,這些將在第5章Kernels模塊詳細介紹。

第三層是圖計算層(Graph),包含本地計算流圖和分布式計算流圖的實現。Graph模塊包含Graph的創建、編譯、優化和執行等部分,Graph中每個節點都是OpKernels類型表示。關於圖計算將在第6章Graph模塊詳細介紹。

第四層是API接口層。Tensor C API是對TF功能模塊的接口封裝,便於其他語言平臺調用。

第四層以上是應用層。不同程式語言在應用層通過API接口層調用TF核心功能實現相關實驗和應用。

1.3 TF代碼目錄組織

圖3是TF的代碼結構視圖,下面將簡單介紹TF的目錄組織結構。

圖3 TF代碼目錄組織結構

Tensorflow/core目錄包含了TF核心模塊代碼。

  • public: API接口頭文件目錄,用於外部接口調用的API定義,主要是session.h 和tensor_c_api.h。

  • client: API接口實現文件目錄。

  • platform: OS系統相關接口文件,如file system, env等。

  • protobuf: 均為.proto文件,用於數據傳輸時的結構序列化.

  • common_runtime: 公共運行庫,包含session, executor, threadpool, rendezvous, memory管理, 設備分配算法等。

  • distributed_runtime: 分布式執行模塊,如rpc session, rpc master, rpc worker, graph manager。

  • framework: 包含基礎功能模塊,如log, memory, tensor

  • graph: 計算流圖相關操作,如construct, partition, optimize, execute等

  • kernels: 核心Op,如matmul, conv2d, argmax, batch_norm等

  • lib: 公共基礎庫,如gif、gtl(google模板庫)、hash、histogram等。

  • ops: 基本ops運算,ops梯度運算,io相關的ops,控制流和數據流操作

  • Tensorflow/stream_executor目錄是並行計算框架,由google stream executor團隊開發。

  •  Tensorflow/contrib目錄是contributor開發目錄。

  • Tensroflow/python目錄是python API客戶端腳本。

  • Tensorflow/tensorboard目錄是可視化分析工具,不僅可以模型可視化,還可以監控模型參數變化。

  • third_party目錄是TF第三方依賴庫。

  • eigen3: eigen矩陣運算庫,TF基礎ops調用

  • gpus: 封裝了cuda/cudnn編程庫

2. TF核心概念

TF的核心是圍繞Graph展開的,簡而言之,就是Tensor沿著Graph傳遞閉包完成Flow的過程。所以在介紹Graph之前需要講述一下符號編程、計算流圖、梯度計算、控制流的概念。

2.1 Tensor

在數學上,Matrix表示二維線性映射,Tensor表示多維線性映射,Tensor是對Matrix的泛化,可以表示1-dim、2-dim、N-dim的高維空間。圖4對比了矩陣乘法(Matrix Product)和張量積(Tensor Contract),可以看出Tensor的泛化能力,其中張量積運算在TF的MatMul和Conv2D運算中都有用到。

圖4 Tensor contract

Tensor在高維空間數學運算比Matrix計算複雜,計算量也非常大,加速張量並行運算是TF優先考慮的問題,如add, contract, slice, reshape, reduce, shuffle等運算。

TF中Tensor的維數描述為階,數值是0階,向量是1階,矩陣是2階,以此類推,可以表示n階高維數據。

TF中Tensor支持的數據類型有很多,如tf.float16, tf.float32, tf.float64, tf.uint8, tf.int8, tf.int16, tf.int32, tf.int64, tf.string, tf.bool, tf.complex64等,所有Tensor運算都使用泛化的數據類型表示。

TF的Tensor定義和運算主要是調用Eigen矩陣計算庫完成的。TF中Tensor的UML定義如圖4。其中TensorBuffer指針指向Eigen::Tensor類型。其中,Eigen::Tensor[5][6]不屬於Eigen官方維護的程序,由貢獻者提供文檔和維護,所以Tensor定義在Eigen unsupported模塊中。

圖5 Tensor數據結構定義

圖5中,Tensor主要包含兩個變量m_data和m_dimension,m_data保存了Tensor的數據塊,T是泛化的數據類型,m_dimensions保存了Tensor的維度信息。

Eigen:Tensor的成員變量很簡單,卻支持非常多的基本運算,再藉助Eigen的加速機制實現快速計算,參考章節3.2。Eigen::Tensor主要包含了

  • 一元運算(Unary),如sqrt、square、exp、abs等。

  • 二元運算(Binary),如add,sub,mul,div等

  • 選擇運算(Selection),即if / else條件運算

  • 歸納運算(Reduce),如reduce_sum, reduce_mean等

  • 幾何運算(Geometry),如reshape,slice,shuffle,chip,reverse,pad,concatenate,extract_patches,extract_image_patches等

  • 張量積(Contract)和卷積運算(Convolve)是重點運算,後續會詳細講解。

2.2 符號編程

編程模式通常分為命令式編程(imperative style programs)和符號式編程(symbolic style programs)。

命令式編程容易理解和調試,命令語句基本沒有優化,按原有邏輯執行。符號式編程涉及較多的嵌入和優化,不容易理解和調試,但運行速度有同比提升。

這兩種編程模式在實際中都有應用,Torch是典型的命令式風格,caffe、theano、mxnet和Tensorflow都使用了符號式編程。其中caffe、mxnet採用了兩種編程模式混合的方法,而Tensorflow是完全採用了符號式編程,Theano和Tensorflow的編程模式更相近。

命令式編程是常見的編程模式,程式語言如python/C++都採用命令式編程。命令式編程明確輸入變量,並根據程序邏輯逐步運算,這種模式非常在調試程序時進行單步跟蹤,分析中間變量。舉例來說,設A=10, B=10,計算邏輯:

第一步計算得出C=100,第二步計算得出D=101,輸出結果D=101。

符號式編程將計算過程抽象為計算圖,計算流圖可以方便的描述計算過程,所有輸入節點、運算節點、輸出節點均符號化處理。計算圖通過建立輸入節點到輸出節點的傳遞閉包,從輸入節點出發,沿著傳遞閉包完成數值計算和數據流動,直到達到輸出節點。這個過程經過計算圖優化,以數據(計算)流方式完成,節省內存空間使用,計算速度快,但不適合程序調試,通常不用於程式語言中。舉上面的例子,先根據計算邏輯編寫符號式程序並生成計算圖

其中A和B是輸入符號變量,C和D是運算符號變量,compile函數生成計算圖F,如圖6所示。

圖6 符號編程的正向計算圖

最後得到A=10, B=10時變量D的值,這裡D可以復用C的內存空間,省去了中間變量的空間存儲。

圖 6是TF中的計算流圖,C=F(Relu(Add(MatMul(W, x), b))),其中每個節點都是符號化表示的。通過session創建graph,在調用session.run執行計算。

圖7 TF符號計算圖

和目前的符號語言比起來,TF最大的特點是強化了數據流圖,引入了mutation的概念。這一點是TF和包括Theano在內的符號編程框架最大的不同。所謂mutation,就是可以在計算的過程更改一個變量的值,而這個變量在計算的過程中會被帶入到下一輪迭代裡面去。

Mutation是機器學習優化算法幾乎必須要引入的東西(雖然也可以通過immutable replacement來代替,但是會有效率的問題)。 Theano的做法是引入了update statement來處理mutation。TF選擇了純符號計算的路線,並且直接把更新引入了數據流圖中去。從目前的白皮書看還會支持條件和循環。這樣就幾乎讓TF本身成為一門獨立的語言。不過這一點會導致最後的API設計和使用需要特別小心,把mutation 引入到數據流圖中會帶來一些新的問題,比如如何處理寫與寫之間的依賴。[7]

2.3 梯度計算

梯度計算主要應用在誤差反向傳播和數據更新,是深度學習平臺要解決的核心問題。梯度計算涉及每個計算節點,每個自定義的前向計算圖都包含一個隱式的反向計算圖。從數據流向上看,正向計算圖是數據從輸入節點到輸出節點的流向過程,反向計算圖是數據從輸出節點到輸入節點的流向過程。

圖8是2.2節中圖6對應的反向計算圖。圖中,由於C=A*B,則dA=B*dC, dB=A*dC。在反向計算圖中,輸入節點dD,輸出節點dA和dB,計算表達式為dA=B*dC=B*dD, dB=A*dC=A*dD。每一個正向計算節點對應一個隱式梯度計算節點。

圖8 符號編程的反向計算圖

反向計算限制了符號編程中內存空間復用的優勢,因為在正向計算中的計算數據在反向計算中也可能要用到。從這一點上講,粗粒度的計算節點比細粒度的計算節點更有優勢,而TF大部分為細粒度操作,雖然靈活性很強,但細粒度操作涉及到更多的優化方案,在工程實現上開銷較大,不及粗粒度簡單直接。在神經網絡模型中,TF將逐步側重粗粒度運算。

2.4 控制流

TF的計算圖如同數據流一樣,數據流向表示計算過程,如圖9。數據流圖可以很好的表達計算過程,為了擴展TF的表達能力,TF中引入控制流。

圖9 Graph的數據流

在程式語言中,if…else…是最常見的邏輯控制,在TF的數據流中也可以通過這種方式控制數據流向。接口函數如下,pred為判別表達式,fn1和fn2為運算表達式。當pred為true是,執行fn1操作;當pred為false時,執行fn2操作。

TF還可以協調多個數據流,在存在依賴節點的場景下非常有用,例如節點B要讀取模型參數θ更新後的值,而節點A負責更新參數θ,則節點B必須等節點A完成後才能執行,否則讀取的參數θ為更新前的數值,這時需要一個運算控制器。接口函數如下,tf.control_dependencies函數可以控制多個數據流執行完成後才能執行接下來的操作,通常與tf.group函數結合使用。

TF支持的控制算子有Switch、Merge、Enter、Leave和NextIteration等。

TF不僅支持邏輯控制,還支持循環控制。TF使用和MIT Token-Tagged machine相似的表示系統,將循環的每次迭代標記為一個tag,迭代的執行狀態標記為一個frame,但迭代所需的數據準備好的時候,就可以開始計算,從而多個迭代可以同時執行。

未完待續……

雷鋒網特約稿件,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • 揭秘框架的本源:開源中文書「TensorFlow內核剖析」
    本書將通過剖析 TensorFlow 原始碼的方式,揭示 TensorFlow 的系統架構、領域模型、工作原理、及其實現模式等相關內容,以便揭示內在的知識。本書適合於渴望深入了解 TensorFlow 內核設計,期望改善 TensorFlow 系統設計和性能優化,及其探究 TensorFlow 關鍵技術的設計和實現的系統架構師、AI 算法工程師、和 AI 軟體工程師。
  • 代碼+實戰:TensorFlow Estimator of Deep CTR——DeepFM/NFM/AFM/...
    深度學習在 ctr 預估領域的應用越來越多,新的模型不斷冒出。從 ctr 預估問題看看 f(x) 設計—DNN 篇整理了各模型之間的聯繫之後,一直在琢磨這些東西如何在工業界落地。經過幾個月的調研,發現目前存在的一些問題:開源的實現基本都是學術界的人在搞,距離工業應用還有較大的鴻溝模型實現大量調用底層 API,各版本實現千差萬別,代碼臃腫難懂,遷移成本較高單機,放到工業場景下跑不動
  • TensorFlow 2.0開源工具書,30天「無痛」上手
    本書要求讀者具備一定的機器學習和深度學習理論基礎,同時使用過 Keras、Tensorflow1.0 或者 PyTorch 搭建訓練過模型。如果沒有任何基礎怎麼辦?你可以在學習本教程的同時參考深度學習大牛、Keras 之父 Francois Chollet 所著的《Python 深度學習》一書。
  • TensorFlow 2.4來了:上線對分布式訓練和混合精度的新功能支持
    優化器本次更新包括重構 tf.keras.optimizers.Optimizer 類,讓 model.fit 的用戶和自定義訓練循環的用戶能夠編寫可與任何優化器一起使用的訓練代碼。該模塊可以運行由 TensorFlow 加速的 NumPy 代碼,由於這一 API 是基於 TensorFlow 構建的,因此可與 TensorFlow 無縫銜接,允許訪問所有 TensorFlow API 並通過編譯和自動矢量化提供優化後的運行。
  • TensorFlow和Caffe、MXNet、Keras等其他深度學習框架的對比
    Julia: http://github.com/malmaud/TensorFlow.jlNode.js: http://github.com/node-tensorflow/node-tensorflowR: http://github.com/rstudio/tensorflowTensorFlow 也有內置的 TF.Learn 和 TF.Slim
  • 谷歌TensorFlow成為最受歡迎Python項目
    TensorFlow眾所周知,最初是2015年11月由谷歌開源的人工智慧系統,屬於谷歌大腦第二代機器學習系統。TensorFlow是一個開源軟體庫,用於各種感知和語言理解人物的機器學習,在谷歌的語音識別、Gmail、谷歌相冊和搜索等多款產品中都有應用。
  • 能看破並說破一切的TensorFlow
    目標檢測是深度學習和計算機視覺領域最有趣的概念之一,構建一個能瀏覽圖片並告知圖片中有什麼對象的模型,多麼奇妙的感覺!好消息是,開發目標檢測應用程式比以往更加容易了。如今的方法專注於端到端管道,極大地提高了性能,有助於開發實時用例。
  • 谷歌開放GNMT教程:如何使用TensorFlow構建自己的神經機器翻譯系統
    由於其可以使用深度神經網絡獲取句義,該模型成為谷歌翻譯等多數商業翻譯系統事實上的標準模型。但是,儘管有關 OpenNMT 或 tf-seq2seq 等 seq2seq 模型的資料已經非常豐富,但能夠指導人們快速構建高質量翻譯系統的知識和技能仍然略顯不足。
  • 雅虎開源 TensorFlowOnSpark,TensorFlow 結合 Spark
    Yahoo 在博客上表示,深度學習(DL)近年來發展迅速,為了從大量的數據中挖掘價值,需要部署分布式深度學習。現有的深度學習框架,往往需要設立單獨的深度學習數據組。這強迫我們為同一個機器學習流水線創建多個程序(見下圖)。維護多個獨立的數據組,要求我們在它們之間傳輸海量數據集——這導致不必要的系統複雜性和端到端的學習延遲。
  • mnist tensorflow 預測專題及常見問題 - CSDN
    實驗大致步驟如下,加載MNIST數據集,同時初始化網絡超參; 建立計算圖; 建立Session會話,執行計算圖進行AlexNet模型訓練和結果預測(訓練模型和評估模型)。實現代碼如下, 1 #coding=utf-8 2 from __future__ import print_function 3 4 from tensorflow.examples.tutorials.mnist import input_data 5 mnist = input_data.read_data_sets("/
  • TensorFlow 2入門指南,初學者必備!
    它是世界上最著名的深度學習框架之一,被行業專家和研究人員廣泛使用。請記住,這不是有關深度學習的文章,所以我希望您了解深度學習的術語及其背後的基本思想。我們將使用非常著名的數據集IRIS數據集探索深度學習的世界。廢話不多說,我們直接看看代碼。
  • 這裡有一份TensorFlow2.0中文教程
    /tensorflow2_tutorials_chinese該教程是 NLP 愛好者 Doit 在知乎上開的一個專欄,由作者從 TensorFlow2.0 官方教程的個人學習復現筆記整理而來。Keras 快速入門Keras 是一個用於構建和訓練深度學習模型的高階 API。它可用於快速設計原型、高級研究和生產。keras 的 3 個優點: 方便用戶使用、模塊化和可組合、易於擴展1.
  • 程式設計師實戰,生成式對抗網絡(GAN)下篇,tensorflow實現
    一、程序代碼程序主要實現上篇文章中所提到的隨機噪聲擬合高斯分布的過程,話不多說,直接上代碼:#引入必要的包import argparseimport numpy as npfrom scipy.stats import normimport tensorflow as tfimport matplotlib.pyplot as pltimport
  • 從星際2深度學習環境到神經機器翻譯,上手機器學習這些開源項目必...
    tensorflow/magentaGitHub 地址:https://github.com/tensorflow/magenta機器智能音樂與藝術生成器。一些庫和工具:scikit-learn / scikit-learnGitHub 地址:https://github.com/scikit-learn/scikit-learn用 Python 實現機器學習。t
  • 如何利用 TVM 優化深度學習GPU op?教你用幾十行Python代碼實現2-3...
    歡迎對於深度學習,編譯原理,高性能計算,硬體加速有興趣的同學一起加入 dmlc 推動領導開源項目社區 。」據雷鋒網(公眾號:雷鋒網)AI科技評論了解,大多數現有系統針對窄範圍的伺服器級 GPU 進行優化,且需要在包括手機、IOT 設備及專用加速器上部署大量工作。而 TVM 是一種將深度學習工作負載部署到硬體的端到端 IR(中間表示)堆棧。
  • 國產軟體半年實現Matlab70%功能?看了代碼後,網友:別幻想了!
    最近在知乎上,有一家國產軟體公司聯高軟體(legalsoft)表示,已經在開發替代Matlab的軟體——Truffer,在文章中說:「半年內實現 MATLAB 科學計算與圖形顯示的 70%;1 年內 100% 全部實現;3 年內完全實現 Simulink;100% 自主版權原始碼;無需 #openG 等組件支持的三維
  • 算法系列 | 如何在 S32V 中實現危險駕駛行為檢測
    在上一篇文章中,我們已經提到,疲勞預警系統(DMS)是基於駕駛員生理及其他非生理信號的基礎設施進行採集、分析和處理,判斷駕駛員狀態是否處於疲勞、睡眠狀態。 基於處理圖像的疲勞駕駛系統主要由 3 個模塊組成:圖像採集模塊、圖像處理模塊、警示提示模塊。
  • 淺談酒店房價代碼管理及動態變價原理的實現
    酒店朋友們大家好,今天我為大家分享一個關於酒店PMS系統當中非常基礎也非常重要的話題——酒店PMS系統價格計劃設置與動態變價原理,內容主要分為四個部分:房價代碼——酒店房型售賣價格的代碼表示房價日曆——讓酒店房價能夠平面化展示父子價格——價格聯動的基礎高級按天存儲的價格代碼:自動變價原理的精髓
  • 通過css和js實現水流效果,附效果圖和原理解析
    css和js實現水流效果最終實現的效果圖效果圖實現的原理原理圖通過1 和2實現三角形(當然最終也可以製作成圓形或者其他形狀),水波的原理在於3,主要是通過動畫的transform:rotate()旋轉360deg和border-radius
  • 不用寫代碼就能實現深度學習?手把手教你用英偉達 DIGITS 解決圖像...
    英偉達想必大家都有所耳聞,但對英偉達開發的深度學習訓練系統(NVIDIA Deep Learning GPU Training System, DIGITS) 知之甚少,今天我們介紹如何使用DIGITS,實現基於深度神經網絡的圖像分類,包括數據集創建、模型創建、模型訓練、模型測試等等。