TensorFlow和Keras入門(mén)必讀教程
導(dǎo)讀:本文對(duì)TensorFlow的框架和基本示例進(jìn)行簡(jiǎn)要介紹。

01 TensorFlow
TensorFlow最初由Google開(kāi)發(fā),旨在讓研究人員和開(kāi)發(fā)人員進(jìn)行機(jī)器學(xué)習(xí)研究。它最初被定義為描述機(jī)器學(xué)習(xí)算法的接口,以及執(zhí)行該算法的實(shí)現(xiàn)。
TensorFlow的主要預(yù)期目標(biāo)是簡(jiǎn)化機(jī)器學(xué)習(xí)解決方案在各種平臺(tái)上的部署,如計(jì)算機(jī)CPU、計(jì)算機(jī)GPU、移動(dòng)設(shè)備以及最近的瀏覽器中的部署。最重要的是,TensorFlow提供了許多有用的功能來(lái)創(chuàng)建機(jī)器學(xué)習(xí)模型并大規(guī)模運(yùn)行它們。TensorFlow 2于2019年發(fā)布,它專(zhuān)注于易用性,并能保持良好的性能。
這個(gè)庫(kù)于2015年11月開(kāi)源。從那時(shí)起,它已被世界各地的用戶改進(jìn)和使用。它被認(rèn)為是開(kāi)展研究的首選平臺(tái)之一。就GitHub活躍度而言,它也是最活躍的深度學(xué)習(xí)框架之一。
TensorFlow既可供初學(xué)者使用,也可供專(zhuān)家使用。TensorFlow API具有不同級(jí)別的復(fù)雜度,從而使初學(xué)者可以從簡(jiǎn)單的API開(kāi)始,同時(shí)也可以讓專(zhuān)家創(chuàng)建非常復(fù)雜的模型。我們來(lái)探索一下這些不同級(jí)別的模型。
1. TensorFlow主要架構(gòu)
TensorFlow架構(gòu)(見(jiàn)圖2-1)具有多個(gè)抽象層級(jí)。我們首先介紹底層,然后逐漸通往最上層。

▲圖2-1 TensorFlow架構(gòu)圖
大多數(shù)深度學(xué)習(xí)計(jì)算都是用C++編碼的。為了在GPU上進(jìn)行運(yùn)算,TensorFlow使用了由NVIDIA開(kāi)發(fā)的庫(kù)CUDA。這就是如果想要利用GPU功能就需要安裝CUDA,以及不能使用其他硬件制造商GPU的原因。
然后,Python底層API(low-level API)封裝了C++源代碼。當(dāng)調(diào)用TensorFlow的Python方法時(shí),通常會(huì)在后臺(tái)調(diào)用C++代碼。這個(gè)封裝層使用戶可以更快地工作,因?yàn)镻ython被認(rèn)為更易于使用并且不需要編譯。該P(yáng)ython封裝器可以創(chuàng)建非?;镜倪\(yùn)算,例如矩陣乘法和加法。
最上層是高級(jí)API(high-level API),由Keras和評(píng)估器API(estimator API)兩個(gè)組件組成。Keras是TensorFlow的一個(gè)用戶友好型、模塊化且可擴(kuò)展的封裝器,評(píng)估器API包含多個(gè)預(yù)制組件,可讓你輕松地構(gòu)建機(jī)器學(xué)習(xí)模型。你可以將它們視為構(gòu)建塊或模板。
tip:在深度學(xué)習(xí)中,模型通常是指經(jīng)過(guò)數(shù)據(jù)訓(xùn)練的神經(jīng)網(wǎng)絡(luò)。模型由架構(gòu)、矩陣權(quán)重和參數(shù)組成。
2. Keras介紹
Keras于2015年首次發(fā)布,它被設(shè)計(jì)為一種接口,可用于使用神經(jīng)網(wǎng)絡(luò)進(jìn)行快速實(shí)驗(yàn)。因此,它依賴(lài)TensorFlow或Theano(另一個(gè)深度學(xué)習(xí)框架,現(xiàn)已棄用)來(lái)運(yùn)行深度學(xué)習(xí)操作。Keras以其用戶友好性著稱(chēng),是初學(xué)者的首選庫(kù)。
自2017年以來(lái),TensorFlow完全集成了Keras,這意味著無(wú)須安裝TensorFlow以外的任何庫(kù)就可使用它。我們將依賴(lài)tf.keras而不是Keras的獨(dú)立版本。這兩個(gè)版本之間有一些細(xì)微的差異,例如與TensorFlow的其他模塊的兼容性以及模型的保存方式。因此,讀者必須確保使用正確的版本,具體方法如下:
在代碼中,導(dǎo)入tf.keras而不是keras。
瀏覽TensorFlow網(wǎng)站上的tf.keras文檔,而不是keras.io文檔。
在使用外部Keras庫(kù)時(shí),請(qǐng)確保它們與tf.keras兼容。
某些保存的模型在Keras版本之間可能不兼容。
這兩個(gè)版本在可預(yù)見(jiàn)的未來(lái)將繼續(xù)共存,而tf.keras與TensorFlow集成將越來(lái)越密切。為了說(shuō)明Keras的強(qiáng)大功能和簡(jiǎn)單性,我們將使用該庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)。
02 基于Keras的簡(jiǎn)單計(jì)算機(jī)視覺(jué)模型
在深入探討TensorFlow的核心概念之前,我們先從一個(gè)計(jì)算機(jī)視覺(jué)的經(jīng)典示例開(kāi)始,它使用數(shù)據(jù)集MNIST進(jìn)行數(shù)字識(shí)別。
1. 準(zhǔn)備數(shù)據(jù)
首先,導(dǎo)入數(shù)據(jù)。它由用于訓(xùn)練集的60 000幅圖像和用于測(cè)試集的10 000幅圖像組成:
import tensorflow as tf
num_classes = 10
img_rows, img_cols = 28, 28
num_channels = 1
input_shape = (img_rows, img_cols, num_channels)
(x_train, y_train),(x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
tip:常見(jiàn)的做法是使用別名tf來(lái)導(dǎo)入TensorFlow,從而加快讀取和鍵入速度。通常用x表示輸入數(shù)據(jù),用y表示標(biāo)簽。
tf.keras.datasets模塊提供快速訪問(wèn),以下載和實(shí)例化一些經(jīng)典數(shù)據(jù)集。使用load_data導(dǎo)入數(shù)據(jù)后,請(qǐng)注意,我們將數(shù)組除以255.0,得到的數(shù)字范圍為[0, 1]而不是[0, 255]。將數(shù)據(jù)歸一化在[0, 1]范圍或[-1, 1]范圍是一種常見(jiàn)的做法。
2. 構(gòu)建模型
現(xiàn)在,我們可以繼續(xù)構(gòu)建實(shí)際模型。我們將使用一個(gè)非常簡(jiǎn)單的架構(gòu),該架構(gòu)由兩個(gè)全連接層(也稱(chēng)為稠密層)組成。在詳細(xì)介紹架構(gòu)之前,我們來(lái)看一下代碼??梢钥吹?,Keras代碼非常簡(jiǎn)潔:
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dense(num_classes, activation='softmax'))
由于模型是層的線性堆棧,因此我們首先調(diào)用Sequential函數(shù)。然后,依次添加每一層。模型由兩個(gè)全連接層組成。我們逐層構(gòu)建:
展平層(Flatten):它將接受表示圖像像素的二維矩陣,并將其轉(zhuǎn)換為一維數(shù)組。我們需要在添加全連接層之前執(zhí)行此操作。28×28的圖像被轉(zhuǎn)換為大小為784的向量。
大小為128的稠密層(Dense):它使用大小為128×784的權(quán)重矩陣和大小為128的偏置矩陣,將784個(gè)像素值轉(zhuǎn)換為128個(gè)激活值。這意味著有100 480個(gè)參數(shù)。
大小為10的稠密層(Dense):它將把128個(gè)激活值轉(zhuǎn)變?yōu)樽罱K預(yù)測(cè)。注意,因?yàn)楦怕士偤蜑?,所以我們將使用softmax激活函數(shù)。
tip:softmax函數(shù)獲取某層的輸出,并返回總和為1的概率。它是分類(lèi)模型最后一層的選擇的激活函數(shù)。
請(qǐng)注意,使用model.summary()可以獲得有關(guān)模型、輸出及其權(quán)重的描述。下面是輸出:

設(shè)置好架構(gòu)并初始化權(quán)重后,模型現(xiàn)在就可以針對(duì)所選任務(wù)進(jìn)行訓(xùn)練了。
3. 訓(xùn)練模型
Keras讓訓(xùn)練變得非常簡(jiǎn)單:
model.compile(optimizer='sgd',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
callbacks = [tf.keras.callbacks.TensorBoard('./keras')]
model.fit(x_train, y_train, epochs=25, verbose=1, validation_data=(x_test, y_test), callbacks=callbacks)
在剛剛創(chuàng)建的模型上調(diào)用.compile()是一個(gè)必需的步驟。必須指定幾個(gè)參數(shù):
優(yōu)化器(optimizer):運(yùn)行梯度下降的組件。
損失(loss):優(yōu)化的指標(biāo)。在本例中,選擇交叉熵,就像上一章一樣。
評(píng)估指標(biāo)(metrics):在訓(xùn)練過(guò)程進(jìn)行評(píng)估的附加評(píng)估函數(shù),以進(jìn)一步查看有關(guān)模型性能(與損失不同,它們不在優(yōu)化過(guò)程中使用)。
名為sparse_categorical_crossentropy的Keras損失執(zhí)行與categorical_crossentropy相同的交叉熵運(yùn)算,但是前者直接將真值標(biāo)簽作為輸入,而后者則要求真值標(biāo)簽先變成獨(dú)熱(one-hot)編碼。因此,使用sparse_...損失可以免于手動(dòng)轉(zhuǎn)換標(biāo)簽的麻煩。
tip:將'sgd'傳遞給Keras等同于傳遞tf.keras.optimizers.SGD()。前一個(gè)選項(xiàng)更易于閱讀,而后一個(gè)選項(xiàng)則可以指定參數(shù),如自定義學(xué)習(xí)率。傳遞給Keras方法的損失、評(píng)估指標(biāo)和大多數(shù)參數(shù)也是如此。
然后,我們調(diào)用.fit()方法。它與另一個(gè)流行的機(jī)器學(xué)習(xí)庫(kù)scikit-learn中所使用的接口非常相似。我們將訓(xùn)練5輪,這意味著將對(duì)整個(gè)訓(xùn)練數(shù)據(jù)集進(jìn)行5次迭代。
請(qǐng)注意,我們將verbose設(shè)置為1。這將讓我們獲得一個(gè)進(jìn)度條,其中包含先前選擇的指標(biāo)、損失和預(yù)計(jì)完成時(shí)間(Estimated Time of Arrival,ETA)。ETA是對(duì)輪次結(jié)束之前剩余時(shí)間的估計(jì)。進(jìn)度條如圖2-2所示。

▲圖2-2 Keras在詳細(xì)模式下顯示的進(jìn)度條屏幕截圖
4. 模型性能
如第1章中所述,你會(huì)注意到模型是過(guò)擬合的——即訓(xùn)練準(zhǔn)確率大于測(cè)試準(zhǔn)確率。如果對(duì)模型訓(xùn)練5輪,則最終在測(cè)試集上的準(zhǔn)確率為97%。這比上一章(95%)高了約2個(gè)百分點(diǎn)。最先進(jìn)的算法可達(dá)到99.79%的準(zhǔn)確率。
我們遵循了三個(gè)主要步驟:
加載數(shù)據(jù):在本例中,數(shù)據(jù)集已經(jīng)可用。在未來(lái)的項(xiàng)目中,你可能需要其他的步驟來(lái)收集和清理數(shù)據(jù)。
創(chuàng)建模型:使用Keras可以讓這一步驟變得容易——按順序添加層即可定義模型的架構(gòu)。然后,選擇損失、優(yōu)化器和評(píng)估指標(biāo)進(jìn)行監(jiān)控。
訓(xùn)練模型:模型第一次運(yùn)行效果很好。在更復(fù)雜的數(shù)據(jù)集上,通常需要在訓(xùn)練過(guò)程中微調(diào)參數(shù)。
借助TensorFlow的高級(jí)API——Keras,整個(gè)過(guò)程非常簡(jiǎn)單。在這個(gè)簡(jiǎn)單API的背后,該庫(kù)隱藏了很多復(fù)雜操作。


干貨直達(dá)??
