Keras TensorFlow教程:如何從零開發(fā)一個(gè)復(fù)雜深度學(xué)習(xí)模型
Keras 是提供一些高可用的 Python API ,能幫助你快速的構(gòu)建和訓(xùn)練自己的深度學(xué)習(xí)模型,它的后端是 TensorFlow 或者 Theano 。本文假設(shè)你已經(jīng)熟悉了 TensorFlow 和卷積神經(jīng)網(wǎng)絡(luò),如果,你還沒有熟悉,那么可以先看看這個(gè)10分鐘入門 TensorFlow 教程和卷積神經(jīng)網(wǎng)絡(luò)教程,然后再回來閱讀這個(gè)文章。
在這個(gè)教程中,我們將學(xué)習(xí)以下幾個(gè)方面:
1.為什么選擇 Keras?為什么 Keras 被認(rèn)為是深度學(xué)習(xí)的未來?
2.在Ubuntu上面一步一步安裝Keras。
3.Keras TensorFlow教程:Keras基礎(chǔ)知識(shí)。
4.了解 Keras 序列模型
4.1 實(shí)際例子講解線性回歸問題
5.使用 Keras 保存和回復(fù)預(yù)訓(xùn)練的模型
6.Keras API
6.1 使用Keras API開發(fā)VGG卷積神經(jīng)網(wǎng)絡(luò)
6.2 使用Keras API構(gòu)建并運(yùn)行SqueezeNet卷積神經(jīng)網(wǎng)絡(luò)
1. 為什么選擇Keras?
Keras 是 Google 的一位工程師 François Chollet 開發(fā)的一個(gè)框架,可以幫助你在 Theano 上面進(jìn)行快速原型開發(fā)。后來,這被擴(kuò)展為 TensorFlow 也可以作為后端。并且最近,TensorFlow決定將其作為 contrib 文件中的一部分進(jìn)行提供。
Keras 被認(rèn)為是構(gòu)建神經(jīng)網(wǎng)絡(luò)的未來,以下是一些它流行的原因:
- 輕量級(jí)和快速開發(fā):Keras 的目的是在消除樣板代碼。幾行 Keras 代碼就能比原生的 TensorFlow 代碼實(shí)現(xiàn)更多的功能。你也可以很輕松的實(shí)現(xiàn) CNN 和 RNN,并且讓它們運(yùn)行在 CPU 或者 GPU 上面。
- 框架的“贏者”:Keras 是一個(gè)API,運(yùn)行在別的深度學(xué)習(xí)框架上面。這個(gè)框架可以是 TensorFlow 或者 Theano。Microsoft 也計(jì)劃讓 CNTK 作為 Keras 的一個(gè)后端。目前,神經(jīng)網(wǎng)絡(luò)框架世界是非常分散的,并且發(fā)展非常快。具體,你可以看看 Karpathy 的這個(gè)推文:
想象一下,我們每年都要去學(xué)習(xí)一個(gè)新的框架,這是多么的痛苦。到目前為止,TensorFlow 似乎成為了一種潮流,并且越來越多的框架開始為 Keras 提供支持,它可能會(huì)成為一種標(biāo)準(zhǔn)。
目前,Keras 是成長最快的一種深度學(xué)習(xí)框架。因?yàn)榭梢允褂貌煌纳疃葘W(xué)習(xí)框架作為后端,這也使得它成為了流行的一個(gè)很大的原因。你可以設(shè)想這樣一個(gè)場景,如果你閱讀到了一篇很有趣的論文,并且你想在你自己的數(shù)據(jù)集上面測試這個(gè)模型。讓我們?cè)俅渭僭O(shè),你對(duì)TensorFlow 非常熟悉,但是對(duì)Theano了解的非常少。那么,你必須使用TensorFlow 對(duì)這個(gè)論文進(jìn)行復(fù)現(xiàn),但是這個(gè)周期是非常長的。但是,如果現(xiàn)在代碼是采用Keras寫的,那么你只要將后端修改為TensorFlow就可以使用代碼了。這將是對(duì)社區(qū)發(fā)展的一個(gè)巨大的推動(dòng)作用。
2. 怎么安裝Keras,并且把TensorFlow作為后端
a) 依賴安裝
安裝 h5py,用于模型的保存和載入:
- pip install h5py
還有一些依賴包也要安裝。
- pip install numpy scipy
- pip install pillow
如果你還沒有安裝TensorFlow,那么你可以按照這個(gè)教程先去安裝TensorFlow。一旦,你安裝完成了 TensorFlow,你只需要使用 pip 很容易的安裝 Keras。
- sudo pip install keras
使用以下命令來查看 Keras 版本。
- >>> import keras
- Using TensorFlow backend.
- >>> keras.__version__
- '2.0.4'
一旦,Keras 被安裝完成,你需要去修改后端文件,也就是去確定,你需要 TensorFlow 作為后端,還是 Theano 作為后端,修改的配置文件位于 ~/.keras/keras.json 。具體配置如下:
- {
- "floatx": "float32",
- "epsilon": 1e-07,
- "backend": "tensorflow",
- "image_data_format": "channels_last"
- }
請(qǐng)注意,參數(shù) image_data_format 是 channels_last ,也就是說這個(gè)后端是 TensorFlow。因?yàn)?,在TensorFlow中圖像的存儲(chǔ)方式是[height, width, channels],但是在Theano中是完全不同的,也就是 [channels, height, width]。因此,如果你沒有正確的設(shè)置這個(gè)參數(shù),那么你模型的中間結(jié)果將是非常奇怪的。對(duì)于Theano來說,這個(gè)參數(shù)就是channels_first。
那么,至此你已經(jīng)準(zhǔn)備好了,使用Keras來構(gòu)建模型,并且把TensorFlow作為后端。
3. Keras基礎(chǔ)知識(shí)
在Keras中主要的數(shù)據(jù)結(jié)構(gòu)是 model ,該結(jié)構(gòu)定義了一個(gè)完整的圖。你可以向已經(jīng)存在的圖中加入任何的網(wǎng)絡(luò)結(jié)構(gòu)。
- import keras
Keras 有兩種不同的建模方式:
- Sequential models:這種方法用于實(shí)現(xiàn)一些簡單的模型。你只需要向一些存在的模型中添加層就行了。
- Functional API:Keras的API是非常強(qiáng)大的,你可以利用這些API來構(gòu)造更加復(fù)雜的模型,比如多輸出模型,有向無環(huán)圖等等。
在本文的下一節(jié)中,我們將學(xué)習(xí)Keras的Sequential models 和 Functional API的理論和實(shí)例。
4. Keras Sequential models
在這一部分中,我將來介紹Keras Sequential models的理論。我將快速的解釋它是如何工作的,還會(huì)利用具體代碼來解釋。之后,我們將解決一個(gè)簡單的線性回歸問題,你可以在閱讀的同時(shí)運(yùn)行代碼,來加深印象。
以下代碼是如何開始導(dǎo)入和構(gòu)建序列模型。
- from keras.models import Sequential
- models = Sequential()
接下來我們可以向模型中添加 Dense(full connected layer),Activation,Conv2D,MaxPooling2D函數(shù)。
- from keras.layers import Dense, Activation, Conv2D, MaxPooling2D, Flatten, Dropout
- model.add(Conv2D(64, (3,3), activation='relu', input_shape = (100,100,32)))
- # This ads a Convolutional layer with 64 filters of size 3 * 3 to the graph
以下是如何將一些***的圖層添加到網(wǎng)絡(luò)中。我已經(jīng)在卷積神經(jīng)網(wǎng)絡(luò)教程中寫了很多關(guān)于圖層的描述。
1). 卷積層
這里我們使用一個(gè)卷積層,64個(gè)卷積核,維度是33的,之后采用 relu 激活函數(shù)進(jìn)行激活,輸入數(shù)據(jù)的維度是 `100100*32`。注意,如果是***個(gè)卷積層,那么必須加上輸入數(shù)據(jù)的維度,后面幾個(gè)這個(gè)參數(shù)可以省略。
- model.add(Conv2D(64, (3,3), activation='relu', input_shape = (100,100,32)))
2). MaxPooling 層
指定圖層的類型,并且指定赤的大小,然后自動(dòng)完成赤化操作,酷斃了!
- model.add(MaxPooling2D(pool_size=(2,2)))
3). 全連接層
這個(gè)層在 Keras 中稱為被稱之為 Dense 層,我們只需要設(shè)置輸出層的維度,然后Keras就會(huì)幫助我們自動(dòng)完成了。
- model.add(Dense(256, activation='relu'))
4). Dropout
- model.add(Dropout(0.5))
5). 扁平層
- model.add(Flatten())
數(shù)據(jù)輸入
網(wǎng)絡(luò)的***層需要讀入訓(xùn)練數(shù)據(jù)。因此我們需要去制定輸入數(shù)據(jù)的維度。因此,input_shape參數(shù)被用于制定輸入數(shù)據(jù)的維度大小。
- model.add(Conv2D(32, (3,3), activation='relu', input_shape=(224, 224, 3)))
在這個(gè)例子中,數(shù)據(jù)輸入的***層是一個(gè)卷積層,輸入數(shù)據(jù)的大小是 224*224*3 。
以上操作就幫助你利用序列模型構(gòu)建了一個(gè)模型。接下來,讓我們學(xué)習(xí)最重要的一個(gè)部分。一旦你指定了一個(gè)網(wǎng)絡(luò)架構(gòu),你還需要指定優(yōu)化器和損失函數(shù)。我們?cè)贙eras中使用compile函數(shù)來達(dá)到這個(gè)功能。比如,在下面的代碼中,我們使用 rmsprop 來作為優(yōu)化器,binary_crossentropy 來作為損失函數(shù)值。
- model.compile(loss='binary_crossentropy', optimizer='rmsprop')
如果你想要使用隨機(jī)梯度下降,那么你需要選擇合適的初始值和超參數(shù):
- from keras.optimizers import SGD
- sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
- model.compile(loss='categorical_crossentropy', optimizer=sgd)
現(xiàn)在,我們已經(jīng)構(gòu)建完了模型。接下來,讓我們向模型中輸入數(shù)據(jù),在Keras中是通過 fit 函數(shù)來實(shí)現(xiàn)的。你也可以在該函數(shù)中指定 batch_size 和 epochs 來訓(xùn)練。
- model.fit(x_train, y_train, batch_size = 32, epochs = 10, validation_data(x_val, y_val))
***,我們使用 evaluate 函數(shù)來測試模型的性能。
- score = model.evaluate(x_test, y_test, batch_size = 32)
這些就是使用序列模型在Keras中構(gòu)建神經(jīng)網(wǎng)絡(luò)的具體操作步驟?,F(xiàn)在,我們來構(gòu)建一個(gè)簡單的線性回歸模型。
4.1 實(shí)際例子講解線性回歸問題
問題陳述
在線性回歸問題中,你可以得到很多的數(shù)據(jù)點(diǎn),然后你需要使用一條直線去擬合這些離散點(diǎn)。在這個(gè)例子中,我們創(chuàng)建了100個(gè)離散點(diǎn),然后用一條直線去擬合它們。
a) 創(chuàng)建訓(xùn)練數(shù)據(jù)
TrainX 的數(shù)據(jù)范圍是 -1 到 1,TrainY 與 TrainX 的關(guān)系是3倍,并且我們加入了一些噪聲點(diǎn)。
- import keras
- from keras.models import Sequential
- from keras.layers import Dense
- import numpy as np
- trX = np.linspace(-1, 1, 101)
- trY = 3 * trX + np.random.randn(*trX.shape) * 0.33
b) 構(gòu)建模型
首先我們需要構(gòu)建一個(gè)序列模型。我們需要的只是一個(gè)簡單的鏈接,因此我們只需要使用一個(gè) Dense 層就夠了,然后用線性函數(shù)進(jìn)行激活。
- model = Sequential()
- model.add(Dense(input_dim=1, output_dim=1, init='uniform', activation='linear'))
下面的代碼將設(shè)置輸入數(shù)據(jù) x,權(quán)重 w 和偏置項(xiàng) b。然我們來看看具體的初始化工作。如下:
- weights = model.layers[0].get_weights()
- w_init = weights[0][0][0]
- b_init = weights[1][0]
- print('Linear regression model is initialized with weights w: %.2f, b: %.2f' % (w_init, b_init))
- ## Linear regression model is initialized with weight w: -0.03, b: 0.00
現(xiàn)在,我們可以l利用自己構(gòu)造的數(shù)據(jù) trX 和 trY 來訓(xùn)練這個(gè)線性模型,其中 trY 是 trX 的3倍。因此,權(quán)重 w 的值應(yīng)該是 3。
我們使用簡單的梯度下降來作為優(yōu)化器,均方誤差(MSE)作為損失值。如下:
- model.compile(optimizer='sgd', loss='mse')
***,我們使用 fit 函數(shù)來輸入數(shù)據(jù)。
- model.fit(trX, trY, nb_epoch=200, verbose=1)
在經(jīng)過訓(xùn)練之后,我們?cè)俅未蛴?quán)重:
- weights = model.layers[0].get_weights()
- w_final = weights[0][0][0]
- b_final = weights[1][0]
- print('Linear regression model is trained to have weight w: %.2f, b: %.2f' % (w_final, b_final))
- ##Linear regression model is trained to have weight w: 2.94, b: 0.08
正如你所看到的,在運(yùn)行 200 輪之后,現(xiàn)在權(quán)重非常接近于 3。你可以將運(yùn)行的輪數(shù)修改為區(qū)間 [100, 300] 之間,然后觀察輸出結(jié)構(gòu)有什么變化?,F(xiàn)在,你已經(jīng)學(xué)會(huì)了利用很少的代碼來構(gòu)建一個(gè)線性回歸模型,如果要構(gòu)建一個(gè)相同的模型,在 TensorFlow 中需要用到更多的代碼。
5. 使用 Keras 保存和回復(fù)預(yù)訓(xùn)練的模型
HDF5 二進(jìn)制格式
一旦你利用Keras完成了訓(xùn)練,你可以將你的網(wǎng)絡(luò)保存在HDF5里面。當(dāng)然,你需要先安裝 h5py。HDF5 格式非常適合存儲(chǔ)大量的數(shù)字收,并從 numpy 處理這些數(shù)據(jù)。比如,我們可以輕松的將存儲(chǔ)在磁盤上的多TB數(shù)據(jù)集進(jìn)行切片,就好像他們是真正的 numpy 數(shù)組一樣。你還可以將多個(gè)數(shù)據(jù)集存儲(chǔ)在單個(gè)文件中,遍歷他們或者查看 .shape 和 .dtype 屬性。
如果你需要信心,那么告訴你,NASA也在使用 HDF5 進(jìn)行數(shù)據(jù)存儲(chǔ)。h5py 是python對(duì)HDF5 C API 的封裝。幾乎你可以用C在HDF5上面進(jìn)行的任何操作都可以用python在h5py上面操作。
保存權(quán)重
如果你要保存訓(xùn)練好的權(quán)重,那么你可以直接使用 save_weights 函數(shù)。
- model.save_weights("my_model.h5")
載入預(yù)訓(xùn)練權(quán)重
如果你想要載入以前訓(xùn)練好的模型,那么你可以使用 load_weights 函數(shù)。
- model.load_weights('my_model_weights.h5')
6. Keras API
如果對(duì)于簡單的模型和問題,那么序列模型是非常好的方式。但是如果你要構(gòu)建一個(gè)現(xiàn)實(shí)世界中復(fù)雜的網(wǎng)絡(luò),那么你就需要知道一些功能性的API,在很多流行的神經(jīng)網(wǎng)絡(luò)中,我們都有一個(gè)最小的網(wǎng)絡(luò)結(jié)構(gòu),完整的模型是根據(jù)這些最小的模型進(jìn)行疊加完成的。這些基礎(chǔ)的API可以讓你一層一層的構(gòu)建模型。因此,你只需要很少的代碼就可以來構(gòu)建一個(gè)完整的復(fù)雜神經(jīng)網(wǎng)絡(luò)。
讓我們來看看它是如何工作的。首先,你需要導(dǎo)入一些包。
- from keras.models import Model
現(xiàn)在,你需要去指定輸入數(shù)據(jù),而不是在順序模型中,在***的 fit 函數(shù)中輸入數(shù)據(jù)。這是序列模型和這些功能性的API之間最顯著的區(qū)別之一。我們使用 input() 函數(shù)來申明一個(gè) 1*28*28 的張量。
- from keras.layers import Input
- ## First, define the vision modules
- digit_input = Input(shape=(1, 28, 28))
現(xiàn)在,讓我們來利用API設(shè)計(jì)一個(gè)卷積層,我們需要指定要在在哪個(gè)層使用卷積網(wǎng)絡(luò),具體代碼這樣操作:
- x = Conv2D(64, (3, 3))(digit_input)
- x = Conv2D(64, (3, 3))(x)
- x = MaxPooling2D((2, 2))(x)
- out = Flatten()(x)
***,我們對(duì)于指定的輸入和輸出數(shù)據(jù)來構(gòu)建一個(gè)模型。
- vision_model = Model(digit_input, out)
當(dāng)然,我們還需要指定損失函數(shù),優(yōu)化器等等。但這些和我們?cè)谛蛄心P椭械牟僮饕粯?,你可以使?fit 函數(shù)和 compile 函數(shù)來進(jìn)行操作。
接下來,讓我們來構(gòu)建一個(gè)vgg-16模型,這是一個(gè)很大很“老”的模型,但是由于它的簡潔性,它是一個(gè)很好的學(xué)習(xí)模型。
6.1 使用Keras API開發(fā)VGG卷積神經(jīng)網(wǎng)絡(luò)
VGG:
VGG卷積神經(jīng)網(wǎng)絡(luò)是牛津大學(xué)在2014年提出來的模型。當(dāng)這個(gè)模型被提出時(shí),由于它的簡潔性和實(shí)用性,馬上成為了當(dāng)時(shí)***的卷積神經(jīng)網(wǎng)絡(luò)模型。它在圖像分類和目標(biāo)檢測任務(wù)中都表現(xiàn)出非常好的結(jié)果。在2014年的ILSVRC比賽中,VGG 在Top-5中取得了92.3%的正確率。 該模型有一些變種,其中***的當(dāng)然是 vgg-16,這是一個(gè)擁有16層的模型。你可以看到它需要維度是 224*224*3 的輸入數(shù)據(jù)。
Vgg 16 architecture
讓我們來寫一個(gè)獨(dú)立的函數(shù)來完整實(shí)現(xiàn)這個(gè)模型。
- img_input = Input(shape=input_shape)
- # Block 1
- x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)
- x = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
- x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
- # Block 2
- x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
- x = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
- x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
- # Block 3
- x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
- x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
- x = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
- x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
- # Block 4
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
- x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
- # Block 5
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
- x = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
- x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
- x = Flatten(name='flatten')(x)
- x = Dense(4096, activation='relu', name='fc1')(x)
- x = Dense(4096, activation='relu', name='fc2')(x)
- x = Dense(classes, activation='softmax', name='predictions')(x)
我們可以將這個(gè)完整的模型,命名為 vgg16.py。
在這個(gè)例子中,我們來運(yùn)行 imageNet 數(shù)據(jù)集中的某一些數(shù)據(jù)來進(jìn)行測試。具體代碼如下:
- model = applications.VGG16(weights='imagenet')
- img = image.load_img('cat.jpeg', target_size=(224, 224))
- x = image.img_to_array(img)
- x = np.expand_dims(x, axis=0)
- x = preprocess_input(x)
- preds = model.predict(x)
- for results in decode_predictions(preds):
- for result in results:
- print('Probability %0.2f%% => [%s]' % (100*result[2], result[1]))
正如你在圖中看到的,模型會(huì)對(duì)圖片中的物體進(jìn)行一個(gè)識(shí)別預(yù)測。
我們通過API構(gòu)建了一個(gè)VGG模型,但是由于VGG是一個(gè)很簡單的模型,所以并沒有完全將API的能力開發(fā)出來。接下來,我們通過構(gòu)建一個(gè) SqueezeNet模型,來展示API的真正能力。
6.2 使用Keras API構(gòu)建并運(yùn)行SqueezeNet卷積神經(jīng)網(wǎng)絡(luò)
SequeezeNet 是一個(gè)非常了不起的網(wǎng)絡(luò)架構(gòu),它的顯著點(diǎn)不在于對(duì)正確性有多少的提高,而是減少了計(jì)算量。當(dāng)SequeezeNet的正確性和AlexNet接近時(shí),但是ImageNet上面的預(yù)訓(xùn)練模型的存儲(chǔ)量小于5 MB,這對(duì)于在現(xiàn)實(shí)世界中使用CNN是非常有利的。SqueezeNet模型引入了一個(gè) Fire模型,它由交替的 Squeeze 和 Expand 模塊組成。
SqueezeNet fire module
現(xiàn)在,我們對(duì) fire 模型進(jìn)行多次復(fù)制,從而來構(gòu)建完整的網(wǎng)絡(luò)模型,具體如下:
為了去構(gòu)建這個(gè)網(wǎng)絡(luò),我們將利用API的功能首先來構(gòu)建一個(gè)單獨(dú)的 fire 模塊。
- # Squeeze part of fire module with 1 * 1 convolutions, followed by Relu
- x = Convolution2D(squeeze, (1, 1), padding='valid', name='fire2/squeeze1x1')(x)
- x = Activation('relu', name='fire2/relu_squeeze1x1')(x)
- #Expand part has two portions, left uses 1 * 1 convolutions and is called expand1x1
- left = Convolution2D(expand, (1, 1), padding='valid', name='fire2/expand1x1')(x)
- left = Activation('relu', name='fire2/relu_expand1x1')(left)
- #Right part uses 3 * 3 convolutions and is called expand3x3, both of these are follow#ed by Relu layer, Note that both receive x as input as designed.
- right = Convolution2D(expand, (3, 3), padding='same', name='fire2/expand3x3')(x)
- right = Activation('relu', name='fire2/relu_expand3x3')(right)
- # Final output of Fire Module is concatenation of left and right.
- x = concatenate([left, right], axis=3, name='fire2/concat')
為了重用這些代碼,我們可以將它們轉(zhuǎn)換成一個(gè)函數(shù):
- sq1x1 = "squeeze1x1"
- exp1x1 = "expand1x1"
- exp3x3 = "expand3x3"
- relu = "relu_"
- WEIGHTS_PATH = "https://github.com/rcmalli/keras-squeezenet/releases/download/v1.0/squeezenet_weights_tf_dim_ordering_tf_kernels.h5"
模塊化處理
- sq1x1 = "squeeze1x1"
- exp1x1 = "expand1x1"
- exp3x3 = "expand3x3"
- relu = "relu_"
- def fire_module(x, fire_id, squeeze=16, expand=64):
- s_id = 'fire' + str(fire_id) + '/'
- x = Convolution2D(squeeze, (1, 1), padding='valid', name=s_id + sq1x1)(x)
- x = Activation('relu', name=s_id + relu + sq1x1)(x)
- left = Convolution2D(expand, (1, 1), padding='valid', name=s_id + exp1x1)(x)
- left = Activation('relu', name=s_id + relu + exp1x1)(left)
- right = Convolution2D(expand, (3, 3), padding='same', name=s_id + exp3x3)(x)
- right = Activation('relu', name=s_id + relu + exp3x3)(right)
- x = concatenate([left, right], axis=3, name=s_id + 'concat')
現(xiàn)在,我們可以利用我們構(gòu)建好的單獨(dú)的 fire 模塊,來構(gòu)建完整的模型。
- x = Convolution2D(64, (3, 3), strides=(2, 2), padding='valid', name='conv1')(img_input)
- x = Activation('relu', name='relu_conv1')(x)
- x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool1')(x)
- x = fire_module(x, fire_id=2, squeeze=16, expand=64)
- x = fire_module(x, fire_id=3, squeeze=16, expand=64)
- x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool3')(x)
- x = fire_module(x, fire_id=4, squeeze=32, expand=128)
- x = fire_module(x, fire_id=5, squeeze=32, expand=128)
- x = MaxPooling2D(pool_size=(3, 3), strides=(2, 2), name='pool5')(x)
- x = fire_module(x, fire_id=6, squeeze=48, expand=192)
- x = fire_module(x, fire_id=7, squeeze=48, expand=192)
- x = fire_module(x, fire_id=8, squeeze=64, expand=256)
- x = fire_module(x, fire_id=9, squeeze=64, expand=256)
- x = Dropout(0.5, name='drop9')(x)
- x = Convolution2D(classes, (1, 1), padding='valid', name='conv10')(x)
- x = Activation('relu', name='relu_conv10')(x)
- x = GlobalAveragePooling2D()(x)
- out = Activation('softmax', name='loss')(x)
- model = Model(inputs, out, name='squeezenet')
完整的網(wǎng)絡(luò)模型我們放置在 squeezenet.py 文件里。我們應(yīng)該先下載 imageNet 預(yù)訓(xùn)練模型,然后在我們自己的數(shù)據(jù)集上面進(jìn)行訓(xùn)練和測試。下面的代碼就是實(shí)現(xiàn)了這個(gè)功能:
- import numpy as np
- from keras_squeezenet import SqueezeNet
- from keras.applications.imagenet_utils import preprocess_input, decode_predictions
- from keras.preprocessing import image
- model = SqueezeNet()
- img = image.load_img('pexels-photo-280207.jpeg', target_size=(227, 227))
- x = image.img_to_array(img)
- x = np.expand_dims(x, axis=0)
- x = preprocess_input(x)
- preds = model.predict(x)
- all_results = decode_predictions(preds)
- for results in all_results:
- for result in results:
- print('Probability %0.2f%% => [%s]' % (100*result[2], result[1]))
對(duì)于相同的一幅圖預(yù)測,我們可以得到如下的預(yù)測概率。
至此,我們的Keras TensorFlow教程就結(jié)束了。希望可以幫到你 。