選自easy-tensorflow 機(jī)器之心編譯 參與:張倩、劉曉坤
這一系列教程分為 6 部分,從為什么選擇 TensorFlow 到卷積神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn),介紹了初學(xué)者所需要的技能。機(jī)器之心在本文介紹了 PyTorch 和 Caffe 等深度學(xué)習(xí)框架的優(yōu)缺點(diǎn)及 TensorFlow 基礎(chǔ),包括靜態(tài)計(jì)算圖、張量、TensorBoard 可視化和模型參數(shù)的保存等。 教程地址:http://www. 機(jī)器之心此前也介紹過很多 TensorFlow 的學(xué)習(xí)資源,讀者可結(jié)合這些資源閱讀該系列教程:
為什么選擇 TensorFlow? 在本文中,我們將對(duì)比當(dāng)前最流行的深度學(xué)習(xí)框架(包括 Caffe、Theano、PyTorch、TensorFlow 和 Keras),幫助你為應(yīng)用選擇最合適的框架。 1. Caffe:第一個(gè)主流產(chǎn)品級(jí)深度學(xué)習(xí)庫,于 2014 年由 UC Berkeley 啟動(dòng)。 優(yōu)點(diǎn):
缺點(diǎn):
2. Theano:由蒙特利爾大學(xué)研究團(tuán)隊(duì)構(gòu)建。Theano 的頂層構(gòu)建了數(shù)值開源深度庫,包括 Keras、Lasagne 和 Blocks。Yoshua Bengio 在 2017 年 9 月 28 日宣布,Theano 的開發(fā)將終止。因此實(shí)際上 Theano 已死! 優(yōu)點(diǎn):
缺點(diǎn):
import numpy
3. Pytorch:2017 年 1 月,F(xiàn)acebook 將 Python 版本的 Torch 庫(用 Lua 編寫)開源。 優(yōu)點(diǎn):
缺點(diǎn):
4. TensorFlow: 由較低級(jí)別的符號(hào)計(jì)算庫(如 Theano)與較高級(jí)別的網(wǎng)絡(luò)規(guī)范庫(如 Blocks 和 Lasagne)組合而成。 優(yōu)點(diǎn):
缺點(diǎn):
5. Keras:Keras 是一個(gè)更高級(jí)、對(duì)用戶最友好的 API,具有可配置的后端,由 Google Brain 團(tuán)隊(duì)成員 Francis Chollet 編寫和維護(hù)。 優(yōu)點(diǎn):
例如:
缺點(diǎn):
TensorFlow 基礎(chǔ) TensorFlow 是一種采用數(shù)據(jù)流圖(data flow graphs),用于數(shù)值計(jì)算的開源軟件庫。其中 Tensor 代表傳遞的數(shù)據(jù)為張量(多維數(shù)組),F(xiàn)low 代表使用計(jì)算圖進(jìn)行運(yùn)算。數(shù)據(jù)流圖用「節(jié)點(diǎn)」(nodes)和「邊」(edges)組成的有向圖來描述數(shù)學(xué)運(yùn)算?!腹?jié)點(diǎn)」一般用來表示施加的數(shù)學(xué)操作,但也可以表示數(shù)據(jù)輸入的起點(diǎn)和輸出的終點(diǎn),或者是讀取/寫入持久變量(persistent variable)的終點(diǎn)。邊表示節(jié)點(diǎn)之間的輸入/輸出關(guān)系。這些數(shù)據(jù)邊可以傳送維度可動(dòng)態(tài)調(diào)整的多維數(shù)據(jù)數(shù)組,即張量(tensor)。 計(jì)算圖與會(huì)話 學(xué)習(xí) TensorFlow 的第一步是了解它的主要特色——「計(jì)算圖」方法?;旧纤械?TensorFlow 代碼都包含兩個(gè)重要部分: 1. 創(chuàng)建「計(jì)算圖」,表示計(jì)算的數(shù)據(jù)流 2. 運(yùn)行「會(huì)話」,執(zhí)行圖中的運(yùn)算 事實(shí)上,TensorFlow 將計(jì)算的定義與其執(zhí)行分開。這兩個(gè)部分將在以下各節(jié)中詳細(xì)說明。在此之前,請(qǐng)記住第一步是導(dǎo)入 TensorFlow ! import tensorflow as tf 這樣,Python 就可以訪問 TensorFlow 的所有類、方法和符號(hào)。使用此命令,TensorFlow 庫將在別名「tf」下導(dǎo)入,以便以后我們可以使用它而不必每次鍵入其全稱「TensorFlow」。 1. 計(jì)算圖 TensorFlow 的創(chuàng)意中的最大創(chuàng)意是數(shù)值計(jì)算被表達(dá)成計(jì)算圖。換種說法,任何 TensorFlow 程序的骨干都是一個(gè)計(jì)算圖。正如 TensorFlow 官網(wǎng)上提及的,「一個(gè)計(jì)算圖是被組織到圖節(jié)點(diǎn)上的一系列 TensorFlow 運(yùn)算」。 首先,什么是節(jié)點(diǎn)和運(yùn)算?最好的解釋方式是,舉個(gè)例子。假設(shè)我們?yōu)楹瘮?shù)「f(x,y)=x^2y+y+2」編寫代碼。TensorFlow 中的計(jì)算圖如下所示: 圖 2:TensorFlow 構(gòu)建的計(jì)算圖。 如上圖所示,計(jì)算圖有一系列由邊互相連接的節(jié)點(diǎn)構(gòu)成。每個(gè)節(jié)點(diǎn)稱為 op,即 operation(運(yùn)算)的縮寫。因此每個(gè)節(jié)點(diǎn)代表一個(gè)運(yùn)算,可能是張量運(yùn)算或生成張量的操作。每個(gè)節(jié)點(diǎn)以零或更多張量為輸入,并生成一個(gè)張量作為輸出。 現(xiàn)在我們來構(gòu)建一個(gè)簡(jiǎn)單的計(jì)算圖。 import tensorflow as tf 生成的計(jì)算圖和變量為: 圖 3:左:生成的圖在 Tensorboard 中可視化;右:生成的變量(在 debug 模式下運(yùn)行時(shí)從 PyCharm 調(diào)試器獲取的屏幕截圖) 為了實(shí)際評(píng)估節(jié)點(diǎn),必須在會(huì)話內(nèi)運(yùn)行計(jì)算圖。簡(jiǎn)言之,編寫的代碼只生成僅僅用來確定張量的預(yù)期大小以及對(duì)它們執(zhí)行的運(yùn)算的圖。但是,它不會(huì)為任何張量賦值。 因此,TensorFlow Graph 類似于 Python 中的函數(shù)定義。它「不會(huì)」為你執(zhí)行任何計(jì)算(就像函數(shù)定義不會(huì)有任何執(zhí)行結(jié)果一樣)。它「僅」定義計(jì)算操作。 2. 會(huì)話(Session) 在 TensorFlow 中,所有不同的變量和運(yùn)算都是儲(chǔ)存在計(jì)算圖。所以在我們構(gòu)建完模型所需要的圖之后,還需要打開一個(gè)會(huì)話(Session)來運(yùn)行整個(gè)計(jì)算圖。在會(huì)話中,我們可以將所有計(jì)算分配到可用的 CPU 和 GPU 資源中。舉個(gè)簡(jiǎn)單的例子,運(yùn)行計(jì)算圖并獲取 c 的值: sess = tf.Session() 這些代碼創(chuàng)建了一個(gè) Session() 對(duì)象(分配到 sess),然后(第二行)調(diào)用它的運(yùn)行方法來運(yùn)行足夠的計(jì)算圖以評(píng)估 c。計(jì)算完畢后需要關(guān)閉會(huì)話來幫助系統(tǒng)回收資源,不然就會(huì)出現(xiàn)資源泄漏的問題。 TensorFlow 張量 import tensorflow as tf TensorFlow 中最基本的單位是常量(Constant)、變量(Variable)和占位符(Placeholder)。常量定義后值和維度不可變,變量定義后值可變而維度不可變。在神經(jīng)網(wǎng)絡(luò)中,變量一般可作為儲(chǔ)存權(quán)重和其他信息的矩陣,而常量可作為儲(chǔ)存超參數(shù)或其他結(jié)構(gòu)信息的變量。 1. 常量 創(chuàng)建一個(gè)節(jié)點(diǎn)取常數(shù)值,它接收以下的變量: tf.constant(value, dtype=None, shape=None, name='Const', verify_shape=False) 我們來創(chuàng)建兩個(gè)常量并將它們加起來。常量張量可以通過定義一個(gè)值來簡(jiǎn)單地定義: # create graph 現(xiàn)在我們來看看創(chuàng)建的計(jì)算圖和生成的數(shù)據(jù)類型: 2. 變量 變量是狀態(tài)性的節(jié)點(diǎn),輸出的是它們當(dāng)前的值,意味著它們可以在一個(gè)計(jì)算圖的多次執(zhí)行中保留它們的值。它們有一系列的有用特征,例如: 它們可以在訓(xùn)練期間或訓(xùn)練后保存到硬盤上。這允許來自不同公司和團(tuán)隊(duì)的人們保存、恢復(fù)和發(fā)送他們的模型參數(shù)給別人。 默認(rèn)情況下,梯度更新(在所有神經(jīng)網(wǎng)絡(luò)中應(yīng)用)將應(yīng)用到計(jì)算圖中的所有變量。實(shí)際上,變量是你希望調(diào)整以最小化損失函數(shù)的東西。 為了創(chuàng)建變量,你可以按如下方式使用 tf.Variable: # Create a variable. 以下語句聲明一個(gè) 2 行 3 列的變量矩陣,該變量的值服從標(biāo)準(zhǔn)差為 1 的正態(tài)分布,并隨機(jī)生成。 w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) TensorFlow 還有 tf.truncated_normal() 函數(shù),即截?cái)嗾龖B(tài)分布隨機(jī)數(shù),它只保留 [mean-2*stddev,mean+2*stddev] 范圍內(nèi)的隨機(jī)數(shù)。 調(diào)用 tf.Variable 來創(chuàng)建一個(gè)變量是一種老方法。TensorFlow 推薦使用封裝器 tf.get_variable,它能接收命名、形狀等參數(shù): tf.get_variable(name, 變量在使用前需要初始化。為此,我們必須調(diào)用「變量初始值設(shè)定項(xiàng)操作」,并在 session 上運(yùn)行該操作。 a = tf.get_variable(name='var_1', initializer=tf.constant(2)) 3. 占位符 我們已經(jīng)創(chuàng)建了各種形式的常量和變量,但 TensorFlow 同樣還支持占位符。占位符并沒有初始值,它只會(huì)分配必要的內(nèi)存。在會(huì)話中,占位符可以使用 feed_dict 饋送數(shù)據(jù)。 feed_dict 是一個(gè)字典,在字典中需要給出每一個(gè)用到的占位符的取值。在訓(xùn)練神經(jīng)網(wǎng)絡(luò)時(shí)需要每次提供一個(gè)批量的訓(xùn)練樣本,如果每次迭代選取的數(shù)據(jù)要通過常量表示,那么 TensorFlow 的計(jì)算圖會(huì)非常大。因?yàn)槊吭黾右粋€(gè)常量,TensorFlow 都會(huì)在計(jì)算圖中增加一個(gè)節(jié)點(diǎn)。所以說擁有幾百萬次迭代的神經(jīng)網(wǎng)絡(luò)會(huì)擁有極其龐大的計(jì)算圖,而占位符卻可以解決這一點(diǎn),它只會(huì)擁有占位符這一個(gè)節(jié)點(diǎn)。 a = tf.constant([5, 5, 5], tf.float32, name='A') 它生成的計(jì)算圖與變量如下所示: 現(xiàn)在,我們已經(jīng)能創(chuàng)建一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)。如下利用隨機(jī)生成的數(shù)據(jù)創(chuàng)建了一個(gè)三層全連接網(wǎng)絡(luò): import tensorflow as tf 上面的代碼定義了一個(gè)簡(jiǎn)單的三層全連接網(wǎng)絡(luò)(輸入層、隱藏層和輸出層分別為 2、3 和 2 個(gè)神經(jīng)元),隱藏層和輸出層的激活函數(shù)使用的是 ReLU 函數(shù)。該模型訓(xùn)練的樣本總數(shù)為 512,每次迭代讀取的批量為 10。這個(gè)簡(jiǎn)單的全連接網(wǎng)絡(luò)以交叉熵為損失函數(shù),并使用 Adam 優(yōu)化算法進(jìn)行權(quán)重更新。 其中需要注意的幾個(gè)函數(shù)如 tf.nn.relu() 代表調(diào)用 ReLU 激活函數(shù),tf.matmul() 為矩陣乘法等。tf.clip_by_value(yhat,1e-10,1.0) 這一語句代表的是截?cái)?yhat 的值,因?yàn)檫@一語句是嵌套在 tf.log() 函數(shù)內(nèi)的,所以我們需要確保 yhat 的取值不會(huì)導(dǎo)致對(duì)數(shù)無窮大。 TensorBoard 基礎(chǔ) TensorBoard 是一個(gè)可視化軟件,在所有的 TensorFlow 標(biāo)準(zhǔn)安裝中都包含了 TensorBoard。按谷歌的話說:「使用 TensorFlow 執(zhí)行的計(jì)算,例如訓(xùn)練一個(gè)大規(guī)模深度神經(jīng)網(wǎng)絡(luò),可能復(fù)雜且令人困惑。為了更加容易理解、調(diào)試和優(yōu)化 TensorFlow 程序,我們內(nèi)置了一套可視化工具,即 TensorBoard?!?/span> TensorFlow 程序既能解決非常簡(jiǎn)單也能解決非常復(fù)雜的問題,它們都有兩種基本組件——運(yùn)算和張量。如前所述,你創(chuàng)建了一個(gè)由一系列運(yùn)算構(gòu)成的模型,饋送數(shù)據(jù)到模型上,張量將在運(yùn)算之間流動(dòng),直到得到了輸出張量,即你的結(jié)果。 完全配置好后,TensorBoard 窗口將呈現(xiàn)與下圖類似的畫面: TensorBoard 的創(chuàng)建是為了幫助你了解模型中張量的流動(dòng),以便調(diào)試和優(yōu)化模型。它通常用于兩項(xiàng)任務(wù): 1. 圖形可視化 2. 編寫摘要(或可視化學(xué)習(xí)) 在本教程中,我們將介紹 TensorBoard 的上述兩項(xiàng)主要用法。盡早學(xué)習(xí)使用 TensorBoard,可以讓使用 TensorFlow 的工作更有趣也更有成效。 1. 計(jì)算圖可視化 強(qiáng)大的 TensorFlow 計(jì)算圖會(huì)變得極其復(fù)雜??梢暬瘓D形有助于理解并對(duì)其進(jìn)行調(diào)試。這是一個(gè)在 TensorFlow 網(wǎng)站工作的可視化示例。 為了激活 TensorFlow 程序 TensorBoard,需要向其中添加幾行代碼。這將把 TensorFlow 運(yùn)算導(dǎo)出到一個(gè)名為「event file」(或 event log file)的文件中。TensorBoard 能夠讀取此文件并深入了解模型圖及其性能。 現(xiàn)在我們來編寫一個(gè)簡(jiǎn)單的 TensorFlow 程序,并用 TensorBoard 可視化其計(jì)算圖。先創(chuàng)建兩個(gè)常量并將其添加到一起。常數(shù)張量可以簡(jiǎn)單地通過定義它們的值來定義: import tensorflow as tf 為了用 TensorBoard 可視化程序,我們需要編寫程序的日志文件。為了編寫事件文件,我們首先需要為那些日志編寫一個(gè) writer,使用以下代碼: writer = tf.summary.FileWriter([logdir], [graph]) 其中 [logdir] 是你想要保存那些日志文件的文件夾。你可以選擇 [logdir] 作為某些有意義的東西,例如『./graphs』。第二個(gè)參數(shù) [graph] 是我們正在編寫的程序的計(jì)算圖。有兩種獲取計(jì)算圖的方法: 1. 使用 tf.get_default_graph() 調(diào)用計(jì)算圖,返回程序的默認(rèn)計(jì)算圖 2. 將計(jì)算圖設(shè)置為 sess.graph,返回會(huì)話的計(jì)算圖(注意這里需要我們已經(jīng)創(chuàng)建了會(huì)話) 我們將在以下的例子中展示兩種方法。然而,第二種方法更加常用。不管用哪種方法,確保僅當(dāng)你定義了計(jì)算圖之后才創(chuàng)建一個(gè) writer。否則,TensorBoard 中可視化的計(jì)算圖將是不完整的。讓我們添加 writer 到第一個(gè)例子中并可視化計(jì)算圖。 import tensorflow as tf 接下來轉(zhuǎn)到 Terminal,確保當(dāng)前工作目錄與運(yùn)行 Python 代碼的位置相同。例如,此處我們可以使用以下代碼切換到目錄 $ cd ~/Desktop/tensorboard 接下來運(yùn)行: $ tensorboard --logdir='./graphs' —port 6006 這將為你生成一個(gè)鏈接。ctrl+左鍵單擊該鏈接(或?qū)⑵鋸?fù)制到瀏覽器中,或只需打開瀏覽器并轉(zhuǎn)到 http://localhost:6006/)。接下來將顯示 TensorBoard 頁面,如下所示: 參數(shù)存儲(chǔ)與加載 在基礎(chǔ)部分中,最后還介紹了模型參數(shù)的保存與恢復(fù)。一般 TensorFlow 模型持久化可使用 tf.train.Saver() 完成,它會(huì)將 TensorFlow 模型保存為 .ckpt 格式的文件。一般該文件目錄下會(huì)有三個(gè)文件,第一個(gè) model.ckpt.meta 保存了 TensorFlow 計(jì)算圖的結(jié)構(gòu),第二個(gè) model.ckpt 文件保存了 TensorFlow 中每一個(gè)變量的取值,而最后一個(gè) cheekpoint 文件保存了同目錄下所有的模型文件列表。 為了保存和恢復(fù)模型變量,我們需要在構(gòu)建計(jì)算圖后調(diào)用 tf.train.Saver(),例如: # create the graph 在訓(xùn)練模式中,我們需要打開會(huì)話初始化變量和運(yùn)行計(jì)算圖,并在訓(xùn)練結(jié)束時(shí)調(diào)用 saver.save() 保存變量: # TRAIN 在測(cè)試模式中,我們需要使用 saver.restore() 恢復(fù)參數(shù): # TEST 當(dāng)然,模型持久化還有非常多的內(nèi)容,例如由 MetaGraphDef Protocol Buffer 定義的計(jì)算圖節(jié)點(diǎn)元數(shù)據(jù)。讀者可繼續(xù)閱讀完整的教程或其它書籍以了解詳細(xì)信息。 深度學(xué)習(xí)時(shí)代,傳統(tǒng) NLP 中的語言知識(shí)庫是否就不再有用了呢?在最新一期的 INTERFACE 中,清華大學(xué)劉知遠(yuǎn)副教授將為我們介紹在深度學(xué)習(xí)模型中應(yīng)用 HowNet 知識(shí)的探索和未來展望。 |
|