亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Tensorflow 代碼解析(三)

worldligang / 2669人閱讀

摘要:所有操作都是節(jié)點(diǎn)形式表示的,包括計(jì)算節(jié)點(diǎn)和非計(jì)算節(jié)點(diǎn)。采用回合通信機(jī)制,類似生產(chǎn)者消費(fèi)者的消息信箱。解析器將協(xié)議內(nèi)存塊解析為張量,放入隊(duì)列中,其中命名和類型要與寫入的一致。目前就職于騰訊事業(yè)部,從事神經(jīng)機(jī)器翻譯工作。

4. ?TF – Kernels模塊

TF中包含大量Op算子,這些算子組成Graph的節(jié)點(diǎn)集合。這些算子對Tensor實(shí)現(xiàn)相應(yīng)的運(yùn)算操作。圖 4 1列出了TF中的Op算子的分類和舉例。

圖 4 1 TensorFlow核心庫中的部分運(yùn)算

4.1 ? OpKernels 簡介

OpKernel類(core/framework/op_kernel.h)是所有Op類的基類。繼承OpKernel還可以自定義新的Op類。用的較多的Op如(MatMul, ?Conv2D, ?SoftMax, ?AvgPooling, Argmax等)。

所有Op包含注冊(Register Op)和實(shí)現(xiàn)(正向計(jì)算、梯度定義)兩部分。

所有Op類的實(shí)現(xiàn)需要overide抽象基函數(shù) void Compute(OpKernelContext* context),實(shí)現(xiàn)自身Op功能。用戶可以根據(jù)需要自定義新的Op操作,參考[12]。

TF中所有Op操作的屬性定義和描述都在 ops/ops.pbtxt。如下Add操作,定義了輸入?yún)?shù)x、y,輸出參數(shù)z。

4.2 UnaryOp & BinaryOp

UnaryOp和BinaryOp定義了簡單的一元操作和二元操作,類定義在/core/kernels/ cwise_ops.h文件,類實(shí)現(xiàn)在/core/kernels/cwise_op_*.cc類型的文件中,如cwise_op_sin.cc文件。

一元操作全稱為Coefficient-wise unary operations,一元運(yùn)算有abs, sqrt, exp, sin, cos,conj(共軛)等。如abs的基本定義:

二元操作全稱為Coefficient-wise binary operations,二元運(yùn)算有add,sub, div, mul,mod等。如sum的基本定義:

4.3 MatMul

4.3.1 Python相關(guān)部分

在Python腳本中定義matmul運(yùn)算:

根據(jù)Ops名稱MatMul從Ops庫中找出對應(yīng)Ops類型

創(chuàng)建ops節(jié)點(diǎn)

創(chuàng)建ops節(jié)點(diǎn)并指定相關(guān)屬性和設(shè)備分配

4.3.2 C++相關(guān)部分

Python腳本通過swig調(diào)用進(jìn)入C接口API文件core/client/tensor_c_api.cc,調(diào)用TF_NewNode函數(shù)生成節(jié)點(diǎn),同時(shí)還需要指定輸入變量,TF_AddInput函數(shù)設(shè)置first輸入變量,TF_AddInputList函數(shù)設(shè)置other輸入變量。這里op_type為MatMul,first輸入變量為a,other輸入變量為b。

創(chuàng)建節(jié)點(diǎn)根據(jù)節(jié)點(diǎn)類型從注冊的Ops工廠中生成,即TF通過工廠模式把一系列Ops注冊到Ops工廠中。其中MatMul的注冊函數(shù)為如下

4.3.3 MatMul正向計(jì)算

MatMul的實(shí)現(xiàn)部分在core/kernels/matmul_op.cc文件中,類MatMulOp繼承于OpKernel,成員函數(shù)Compute完成計(jì)算操作。

MatMul的測試用例core/kernels/matmul_op_test.cc文件,要調(diào)試這個(gè)測試用例,可通過如下方式:

在TF中MatMul實(shí)現(xiàn)了CPU和GPU兩個(gè)版本,其中CPU版本使用Eigen庫,GPU版本使用cuBLAS庫。

CPU版的MatMul使用Eigen庫,調(diào)用方式如下:

簡而言之就是調(diào)用eigen的constract函數(shù)。

GPU版的MatMul使用cuBLAS庫,準(zhǔn)確而言是基于cuBLAS的stream_executor庫。Stream executor是google開發(fā)的開源并行計(jì)算庫,調(diào)用方式如下:

其中stream類似于設(shè)備句柄,可以調(diào)用stream executor中的cuda模塊完成運(yùn)算。

4.3.4 MatMul梯度計(jì)算

MatMul的梯度計(jì)算本質(zhì)上也是一種kernel ops,描述為MatMulGrad。MatMulgrad操作是定義在grad_ops工廠中,類似于ops工廠。定義方式如下:

MatmulGrad由FDH(Function Define Helper)完成定義,

其中attr_adj_x="transpose_a" ax0=false, ax1=true, attr_adj_y= "transpose_b", ay0=true, ay1=false, *g屬于FunctionDef類,包含MatMul的梯度定義。

從FDH定義中可以看出MatMulGrad本質(zhì)上還是MatMul操作。在矩陣求導(dǎo)運(yùn)算中:

MatMulGrad的測試用例core/ops/math_grad_test.cc文件,要調(diào)試這個(gè)測試用例,可通過如下方式:

4.4 Conv2d

關(guān)于conv2d的python調(diào)用部分和C++創(chuàng)建部分可參考MatMul中的描述。

4.4.1 Conv2d正向計(jì)算部分

TF中conv2d接口如下所示,簡單易用:

實(shí)現(xiàn)部分在core/kernels/conv_ops.cc文件中,類Conv2DOp繼承于抽象基類OpKernel。

Conv2DOp的測試用例core/kernels/eigen_spatial_convolutions_test.cc文件,要調(diào)試這個(gè)測試用例,可通過如下方式:

Conv2DOp的成員函數(shù)Compute完成計(jì)算操作。

為方便描述,假設(shè)tf.nn.conv2d中input參數(shù)的shape為[batch, in_rows, in_cols, in_depth],filter參數(shù)的shape為[filter_rows, filter_cols, in_depth, out_depth]。

首先,計(jì)算卷積運(yùn)算后輸出tensor的shape。

? ?若padding=VALID,output_size = (input_size - filter_size + stride) / stride;

? ?若padding=SAME,output_size = (input_size + stride - 1) / stride;

其次,根據(jù)計(jì)算結(jié)果給輸出tensor分配內(nèi)存。

然后,開始卷積計(jì)算。Conv2DOp實(shí)現(xiàn)了CPU和GPU兩種模式下的卷積運(yùn)算。同時(shí),還需要注意input tensor的輸入格式,通常有NHWC和NCHW兩種格式。在TF中,Conv2d-CPU模式下目前僅支持NHWC格式,即[Number, Height, Weight, Channel]格式。Conv2d-GPU模式下以NCHW為主,但支持將NHWC轉(zhuǎn)換為NCHW求解。C++中多維數(shù)組是row-major順序存儲的,而Eigen默認(rèn)是col-major順序的,則C++中[N, H, W, C]相當(dāng)于Eigen中的[C, W, H, N],即dimention order是相反的,需要特別注意。

Conv2d-CPU模式下調(diào)用Eigen庫函數(shù)。

Eigen庫中卷積函數(shù)的詳細(xì)代碼參見圖 4 2。

圖 4 2 Eigen卷積運(yùn)算的定義

? ?Tensor:: extract_image_patches () 為卷積或池化操作抽取與kernel size一致的image patches。該函數(shù)的定義在eigen3/unsupported/Eigen/CXX11/src/Tensor/ TensorBase.h中,參考該目錄下ReadME.md。

? ?Tensor:: extract_image_patches () 的輸出與input tensor的data layout有關(guān)。設(shè)input tensor為ColMajor格式[NHWC],則image patches輸出為[batch, filter_index, filter_rows, filter_cols, in_depth],并reshape為[batch * filter_index, filter_rows * filter_cols * in_depth],而kernels維度為[filter_rows * filter_cols * in_depth, out_depth],然后kernels矩陣乘image patches得到輸出矩陣[batch * filter_index, out_depth],并reshape為[batch, out_rows, out_cols, out_depth]。

Conv2d-GPU模式下調(diào)用基于cuDNN的stream_executor庫。若input tensor為NHWC格式的,則先轉(zhuǎn)換為NCHW格式

調(diào)用cudnn庫實(shí)現(xiàn)卷積運(yùn)算:

計(jì)算完成后再轉(zhuǎn)換成HHWC格式的

4.4.2 Conv2d梯度計(jì)算部分

Conv2D梯度計(jì)算公式,假設(shè)output=Conv2d(input, filter),則

Conv2D梯度計(jì)算的測試用例core/kernels/eigen_backward_spatial_convolutions_test.cc文件,要調(diào)試這個(gè)測試用例,可通過如下方式:

Conv2d的梯度計(jì)算函數(shù)描述為Conv2DGrad。Conv2DGrad操作定義在grad_ops工廠中。注冊方式如下:

Conv2DGrad由FDH(Function Define Helper)完成定義,參見圖 4 3。

圖 4 3 Conv2DGrad的函數(shù)定義

Conv2DGrad梯度函數(shù)定義中依賴Conv2DBackpropInput和Conv2DBackpropFilter兩種Ops,二者均定義在kernels/conv_grad_ops.cc文件中。

Conv2DBackpropInputOp和Conv2DBackpropFilterOp的實(shí)現(xiàn)分為GPU和CPU版本。

Conv2D運(yùn)算的GPU版實(shí)現(xiàn)定義在類Conv2DSlowBackpropInputOp和類Conv2DSlowBackprop FilterOp 中。

Conv2D運(yùn)算的CPU版有兩種實(shí)現(xiàn)形式,分別為custom模式和fast模式。Custom模式基于賈揚(yáng)清在caffe中的思路實(shí)現(xiàn),相關(guān)類是Conv2DCustomBackpropInputOp和Conv2DCustomBackpropFilterOp。Fast模式基于Eigen計(jì)算庫,由于在GPU下會出現(xiàn)nvcc編譯超時(shí),目前僅適用于CPU環(huán)境,相關(guān)類是Conv2DFastBackpropInputOp和Conv2DFastBackpropFilterOp。

根據(jù)Conv2DGrad的函數(shù)定義,從代碼分析Conv2D-GPU版的實(shí)現(xiàn)代碼,即分析Conv2DBackpropInput和Conv2DBackpropFilter的實(shí)現(xiàn)方式。

Conv2DSlowBackpropInputOp的成員函數(shù)Compute完成計(jì)算操作。

Compute實(shí)現(xiàn)部分調(diào)用stream executor的相關(guān)函數(shù),需要先獲取庫的stream句柄,再調(diào)用卷積梯度函數(shù)。

stream executor在卷積梯度運(yùn)算部分仍然是借助cudnn庫實(shí)現(xiàn)的。

4.4.3 MaxPooling計(jì)算部分

在很多圖像分類和識別問題中都用到了池化運(yùn)算,池化操作主要有較大池化(max pooling)和均值池化(avg pooling),本章節(jié)主要介紹較大池化的實(shí)現(xiàn)方法。調(diào)用TF接口可以很容易實(shí)現(xiàn)池化操作。

Eigen庫中較大池化的詳細(xì)描述如下:

其中較大池化運(yùn)算主要分為兩步,第一步中extract_image_patch為池化操作抽取與kernel size一致的image patches,第二步計(jì)算每個(gè)image patch的較大值。

4.5 SendOp & RecvOp

TF所有操作都是節(jié)點(diǎn)形式表示的,包括計(jì)算節(jié)點(diǎn)和非計(jì)算節(jié)點(diǎn)。在跨設(shè)備通信中,發(fā)送節(jié)點(diǎn)(SendOp)和接收節(jié)點(diǎn)(RecvOp)為不同設(shè)備的兩個(gè)相鄰節(jié)點(diǎn)完成完成數(shù)據(jù)通信操作。Send和Recv通過TCP或RDMA來傳輸數(shù)據(jù)。

TF采用Rendezvous(回合)通信機(jī)制,Rendezvous類似生產(chǎn)者/消費(fèi)者的消息信箱。引用TF描述如下:

TF的消息傳遞屬于采用“發(fā)送不阻塞/接收阻塞”機(jī)制,實(shí)現(xiàn)場景有LocalRendezvous

(本地消息傳遞)、RpcRemoteRendezvous (分布式消息傳遞)。除此之外還有IntraProcessRendezvous用于本地不同設(shè)備間通信。

TF會在不同設(shè)備的兩個(gè)相鄰節(jié)點(diǎn)之間添加Send和Recv節(jié)點(diǎn),通過Send和Recv之間進(jìn)行通信來達(dá)到op之間通信的效果,如圖 4 4右子圖所示。圖中還涉及到一個(gè)優(yōu)化問題,即a->b和a->c需要建立兩組send/recv連接的,但兩組連接是可以共用的,所以合并成一組連接。

圖 4 4 Graph跨設(shè)備通信

Send和Recv分別對應(yīng)OpKernel中的SendOp和RecvOp兩個(gè)類(kernels/sendrecv_ops.h)。

SendOp的計(jì)算函數(shù)。

SendOp作為發(fā)送方需要先獲取封裝ctx消息,然后借助Rendezvous模塊發(fā)送給接收方。

RecvOp的計(jì)算函數(shù)如下。

RecvOp作為接收方借助Rendezvous模塊獲取ctx消息。

其中parsed變量是類ParsedKey的實(shí)例。圖 5?5是Rendezvous封裝的ParsedKey消息實(shí)體示例。

4.6 ReaderOp & QueueOp

4.6.1 TF數(shù)據(jù)讀取

TF系統(tǒng)定義了三種數(shù)據(jù)讀取方式[13]:

? ?供給數(shù)據(jù)(Feeding): 在TensorFlow程序運(yùn)行的每一步, 通過feed_dict來供給數(shù)據(jù)。

? ?從文件讀取數(shù)據(jù): 在TensorFlow圖的起始, 讓一個(gè)輸入管線(piplines)從文件中讀取數(shù)據(jù)放入隊(duì)列,通過QueueRunner供給數(shù)據(jù),其中隊(duì)列可以實(shí)現(xiàn)多線程異步計(jì)算。

? ?預(yù)加載數(shù)據(jù): 在TensorFlow圖中定義常量或變量來保存所有數(shù)據(jù),如Mnist數(shù)據(jù)集(僅適用于數(shù)據(jù)量比較小的情況)。

除了以上三種數(shù)據(jù)讀取方式外,TF還支持用戶自定義數(shù)據(jù)讀取方式,即繼承ReaderOpKernel類創(chuàng)建新的輸入讀取類[14]。本章節(jié)主要講述通過piplines方式讀取數(shù)據(jù)的方法。

Piplines利用隊(duì)列實(shí)現(xiàn)異步計(jì)算

從piplines讀取數(shù)據(jù)也有兩種方式:一種是讀取所有樣本文件路徑名轉(zhuǎn)換成string tensor,使用input_producer將tensor亂序(shuffle)或slice(切片)處理放入隊(duì)列中;另一種是將數(shù)據(jù)轉(zhuǎn)化為TF標(biāo)準(zhǔn)輸入格式,即使用TFRecordWriter將樣本數(shù)據(jù)寫入tfrecords文件中,再使用TFRecordReader將tfrecords文件讀取到隊(duì)列中。

圖 4 6描述了piplines讀取數(shù)據(jù)的第一種方式,這些流程通過節(jié)點(diǎn)和邊串聯(lián)起來,成為graph數(shù)據(jù)流的一部分。

從左向右, 第一步 是載入文件列表,使用convert_to_tensor函數(shù)將文件列表轉(zhuǎn)化為tensor,如cifar10數(shù)據(jù)集中的image_files_tensor和label_tensor。

第二步是使用input_producer將image_files_tensor和label_tensor放入圖中的文件隊(duì)列中,這里的input_producer作用就是將樣本放入隊(duì)列節(jié)點(diǎn)中,有string_input_producer、range_input_producer和slice_input_producer三種,其中slice_input_producer的切片功能支持亂序,其他兩種需要借助tf.train.shuffle_batch函數(shù)作亂序處理,有關(guān)三種方式的具體描述可參考tensorflow/python/training/input.py注釋說明。

第三步是使用tf.read_file()讀取隊(duì)列中的文件數(shù)據(jù)到內(nèi)存中,使用解碼器如tf.image.decode_jpeg()解碼成[height, width, channels]格式的數(shù)據(jù)。

最后就是使用batch函數(shù)將樣本數(shù)據(jù)處理成一批批的樣本,然后使用session執(zhí)行訓(xùn)練。

圖 4 6 使用piplines讀取數(shù)據(jù)

4.6.2 TFRecords使用

TFRecords是TF支持的標(biāo)準(zhǔn)文件格式,這種格式允許將任意的數(shù)據(jù)轉(zhuǎn)換為TFRecords支持的文件格式。TFRecords方法需要兩步:第一步是使用TFRecordWriter將樣本數(shù)據(jù)寫入tfrecords文件中,第二步是使用TFRecordReader將tfrecords文件讀取到隊(duì)列中。

圖 4 7是TFRecords文件寫入的簡單示例。tf.train.Example將數(shù)據(jù)填入到Example協(xié)議內(nèi)存塊(protocol buffer),將協(xié)議內(nèi)存塊序列化為一個(gè)字符串,通過TFRecordWriter寫入到TFRecords文件,圖中定義了label和image_raw兩個(gè)feature。Example協(xié)議內(nèi)存塊的定義請參考文件core/example/example.proto。

圖 4 7 TFRecordWriter寫入數(shù)據(jù)示例

圖 4 8是TFRecords文件讀取的簡單示例。tf.parse_single_example解析器將Example協(xié)議內(nèi)存塊解析為張量,放入example隊(duì)列中,其中features命名和類型要與Example寫入的一致。

圖 4 8 TFRecrodReader讀取數(shù)據(jù)示例

4.6.3 ReaderOps分析

ReaderOpsKernel類封裝了數(shù)據(jù)讀取的入口函數(shù)Compute,通過繼承ReaderOpsKernel類可實(shí)現(xiàn)各種自定義的數(shù)據(jù)讀取方法。圖 4 9是ReaderOp相關(guān)的UML視圖。

圖 4 9 ReaderOp相關(guān)的UML視圖

ReaderOpKernel子類必須重新定義成員函數(shù)SetReaderFactory實(shí)現(xiàn)對應(yīng)的數(shù)據(jù)讀取邏輯。TFRecordReaderOp的讀取方法定義在TFRecordReader類中。

其中offset的計(jì)算方式。

作者簡介:

姚健,畢業(yè)于中科院計(jì)算所網(wǎng)絡(luò)數(shù)據(jù)實(shí)驗(yàn)室,畢業(yè)后就職于360天眼實(shí)驗(yàn)室,主要從事深度學(xué)習(xí)和增強(qiáng)學(xué)習(xí)相關(guān)研究工作。目前就職于騰訊MIG事業(yè)部,從事神經(jīng)機(jī)器翻譯工作。聯(lián)系方式: yao_62995@163.com

歡迎加入本站公開興趣群

商業(yè)智能與數(shù)據(jù)分析群

興趣范圍包括各種讓數(shù)據(jù)產(chǎn)生價(jià)值的辦法,實(shí)際應(yīng)用案例分享與討論,分析工具,ETL工具,數(shù)據(jù)倉庫,數(shù)據(jù)挖掘工具,報(bào)表系統(tǒng)等全方位知識

QQ群:81035754

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/4498.html

相關(guān)文章

  • Tensorflow代碼解析(二)

    摘要:為了進(jìn)一步了解的邏輯,圖對和進(jìn)行了展開分析。另外,在命名空間中還隱式聲明了控制依賴操作,這在章節(jié)控制流中相關(guān)說明。簡述是高效易用的開源庫,有效支持線性代數(shù),矩陣和矢量運(yùn)算,數(shù)值分析及其相關(guān)的算法。返回其中一塊給用戶,并將該內(nèi)存塊標(biāo)識為占用。 3. TF 代碼分析初步3.1 TF總體概述為了對TF有整體描述,本章節(jié)將選取TF白皮書[1]中的示例展開說明,如圖 3 1所示是一個(gè)簡單線性模型的TF...

    zhigoo 評論0 收藏0
  • TensorFlow學(xué)習(xí)筆記(10):讀取文件

    摘要:簡介讀取數(shù)據(jù)共有三種方法當(dāng)運(yùn)行每步計(jì)算的時(shí)候,從獲取數(shù)據(jù)。數(shù)據(jù)直接預(yù)加載到的中,再把傳入運(yùn)行。在中定義好文件讀取的運(yùn)算節(jié)點(diǎn),把傳入運(yùn)行時(shí),執(zhí)行讀取文件的運(yùn)算,這樣可以避免在和執(zhí)行環(huán)境之間反復(fù)傳遞數(shù)據(jù)。本文講解的代碼。 簡介 TensorFlow讀取數(shù)據(jù)共有三種方法: Feeding:當(dāng)TensorFlow運(yùn)行每步計(jì)算的時(shí)候,從Python獲取數(shù)據(jù)。在Graph的設(shè)計(jì)階段,用place...

    Neilyo 評論0 收藏0
  • TensorFlow 刪除 YAML 支持,建議 JSON 作為替補(bǔ)方案!

    摘要:據(jù)公告稱,和的包裝庫使用了不安全的函數(shù)來反序列化編碼的機(jī)器學(xué)習(xí)模型。簡單來看,序列化將對象轉(zhuǎn)換為字節(jié)流。據(jù)悉,本次漏洞影響與版本,的到版本均受影響。作為解決方案,在宣布棄用之后,團(tuán)隊(duì)建議開發(fā)者以替代序列化,或使用序列化作為替代。 ...

    BlackFlagBin 評論0 收藏0
  • 以靜制動的TensorFlow Fold動態(tài)計(jì)算圖介紹

    摘要:近日它們交鋒的戰(zhàn)場就是動態(tài)計(jì)算圖,誰能在這場戰(zhàn)爭中取得優(yōu)勢,誰就把握住了未來用戶的流向。所以動態(tài)框架對虛擬計(jì)算圖的構(gòu)建速度有較高的要求。動態(tài)計(jì)算圖問題之一的多結(jié)構(gòu)輸入問題的高效計(jì) 隨著深度學(xué)習(xí)的發(fā)展,深度學(xué)習(xí)框架之間競爭也日益激烈,新老框架紛紛各顯神通,想要在廣大DeepLearner的服務(wù)器上占據(jù)一席之地。近日它們交鋒的戰(zhàn)場就是動態(tài)計(jì)算圖,誰能在這場戰(zhàn)爭中取得優(yōu)勢,誰就把握住了未來用戶的流...

    waltr 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<