本篇文章是我們學(xué)習(xí) Python 及其在機(jī)器學(xué)習(xí)(ML)和 人工智能(AI) 中的應(yīng)用系列的第七個(gè)模塊。在上一模塊中,我們討論了使用 NLTK 進(jìn)行文本分析。接下來(lái),我們將要討論的是Keras,一個(gè)用于處理神經(jīng)網(wǎng)絡(luò)的高級(jí) Python 庫(kù)。在本模塊中,將演示如何使用 Keras 解決圖像分類問(wèn)題。
安裝
使用Anaconda的conda install就可以安裝Keras庫(kù):
conda install keras
該命令也會(huì)立即幫你安裝好相關(guān)依賴。
后端配置
Keras 可以使用多個(gè)可用庫(kù)之一作為其后端,這是處理低級(jí)操作(例如張量)的部分。我們將使用 TensorFlow,這是默認(rèn)設(shè)置。
首先,我們將稍微調(diào)整 TensorFlow 的配置。具體來(lái)說(shuō),我們將allow_growth選項(xiàng)設(shè)置為 true,這允許 TensorFlow 動(dòng)態(tài)增加使用的 GPU 內(nèi)存,而不是預(yù)先分配所有內(nèi)容。如果我們不這樣做,TensorFlow 可能會(huì)嘗試分配太多內(nèi)存,導(dǎo)致你的 GPU 會(huì)立即耗盡內(nèi)存(對(duì)我來(lái)說(shuō)確實(shí)如此)。為此,請(qǐng)把以下代碼放在文件的開(kāi)頭:
如果您的后端是 TensorFlow 1.x:
from keras.backend.tensorflow_backend import set_session
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
set_session(tf.Session(config=config))
對(duì)于 TensorFlow 2.x,你必須set_memory_growth
設(shè)置為你的 GPU調(diào)用該函數(shù)。你可以在tf.config.experimental.set_memory_growth文檔中閱讀更多關(guān)于這背后的細(xì)節(jié)。
怎么查看你所擁有的版本?可以通過(guò)conda list
來(lái)查看您的 TensorFlow 版本。即便使用相同的 Anaconda 安裝命令,例如我在一臺(tái)計(jì)算機(jī)上安裝了 1.13.1,在另一臺(tái)上安裝了 2.1.0。
如果你想強(qiáng)制 Keras 使用你的 CPU 而不是你的 GPU,請(qǐng)?jiān)诘谝淮?Keras import 之前添加:
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
雖然這樣一來(lái)比在 GPU 上慢很多,但如果你沒(méi)有足夠的多 GPU 內(nèi)存,你還真得考慮一下這樣做。
使用 Keras 進(jìn)行圖像分類
我們將使用英特爾圖像分類數(shù)據(jù)集演示用于圖像分類的 Keras 。該數(shù)據(jù)集包含六個(gè)類別的圖像,分為六個(gè)不同的目錄,這非常方便,因?yàn)?Keras 提供了處理該格式數(shù)據(jù)的內(nèi)置功能。
雖然你不用過(guò)多擔(dān)心神經(jīng)網(wǎng)絡(luò)背后的數(shù)學(xué)問(wèn)題,但你還需要對(duì)此有足夠的理解,因?yàn)槟悴拍軠?zhǔn)確指定你的模型由哪些層組成。
Keras 提供的模型之一是順序模型,即一堆層。創(chuàng)建順序模型和添加層非常簡(jiǎn)單:
from keras.models import Sequential
model = Sequential()
model.add(layer_one)
model.add(layer_two)
# ...
以下是我們的模型用于圖像分類的樣子:
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Dropout, Flatten, Dense
from keras.layers.normalization import BatchNormalization
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(150, 150, 3))) # our images are 150*150
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Conv2D(64, kernel_size=(3, 3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Conv2D(128, kernel_size=(3, 3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(128, activation="relu"))
model.add(Dropout(0.15))
model.add(Dense(64, activation="relu"))
model.add(Dense(6, activation="softmax"))
神經(jīng)網(wǎng)絡(luò)模型的構(gòu)建超出了本模塊的范圍,但簡(jiǎn)而言之:卷積層的重復(fù)模式(由于模式變得更復(fù)雜,過(guò)濾器數(shù)量越來(lái)越多)、最大池化層和批處理歸一化通常用作圖像分類問(wèn)題的第一步。該步驟的輸出是多維的,我們將其展平為具有展平層的一維向量。我們以幾個(gè)密集連接的層結(jié)束,中間有一個(gè) dropout 層,以幫助對(duì)抗過(guò)度擬合。最后一層必須輸出一個(gè)包含六個(gè)元素的向量,因?yàn)槲覀冇辛鶄€(gè)類別。
接下來(lái),我們編譯模型,這意味著我們對(duì)其進(jìn)行配置以進(jìn)行訓(xùn)練:
model.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
我們的損失函數(shù)sparse_categorical_crossentropy
非常適合分類問(wèn)題,而類別之間沒(méi)有重疊。有關(guān)損失函數(shù)的完整討論,請(qǐng)參閱Keras 文檔。我們正在使用 Adam 優(yōu)化器??梢栽谙嚓P(guān)文檔中找到優(yōu)化器的完整列表。并metrics
指定模型在訓(xùn)練和測(cè)試期間評(píng)估的內(nèi)容。
擬合模型
現(xiàn)在我們有了模型的結(jié)構(gòu),我們可以將它擬合到我們的數(shù)據(jù)集。
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(validation_split=0.2)
train_generator =
datagen.flow_from_directory("intel-images/seg_train/seg_train",
batch_size=32, target_size=(150,150), class_mode="sparse",
subset="training")
validation_generator =
datagen.flow_from_directory("intel-images/seg_train/seg_train",
batch_size=32, target_size=(150, 150), class_mode="sparse",
subset="validation")
model.fit_generator(train_generator, epochs=40,
validation_data=validation_generator)
(如果你想要以較低的準(zhǔn)確度更快地完成該過(guò)程,請(qǐng)自定義減少 epoch 的數(shù)量,尤其是在你使用 CPU 的情況下。40 個(gè) epoch 需要相當(dāng)長(zhǎng)的時(shí)間。)
根據(jù) Keras 文檔,這就是 an 的ImageDataGenerator
作用:
使用實(shí)時(shí)數(shù)據(jù)增強(qiáng)生成批量張量圖像數(shù)據(jù)。數(shù)據(jù)將被循環(huán)(分批)。
我們的例子沒(méi)有做任何數(shù)據(jù)增強(qiáng)。稍后我們將介紹該功能。
在前面的代碼中,validation_split=0.2
意味著我們將使用 20% 的訓(xùn)練集進(jìn)行驗(yàn)證。由于數(shù)據(jù)集只有一個(gè)訓(xùn)練集和一個(gè)測(cè)試集,我們必須使用訓(xùn)練集的一個(gè)子集作為驗(yàn)證集。
flow_from_directory
是一個(gè)簡(jiǎn)潔的內(nèi)置函數(shù),非常適合像我們這樣的數(shù)據(jù)集結(jié)構(gòu):每個(gè)類別的子目錄。
class_mode="sparse"
意味著我們正在處理一維整數(shù)標(biāo)簽。
fit_generator
ImageDataGenerator
在我們指定的多個(gè)時(shí)期中將模型擬合到。
測(cè)試模型
訓(xùn)練完成后,我們可以用evaluate_generator
函數(shù)測(cè)試模型。就像fit_generator
,它需要一個(gè)生成器作為參數(shù)。我們可以為我們的測(cè)試數(shù)據(jù)創(chuàng)建一個(gè),類似于我們?yōu)橛?xùn)練數(shù)據(jù)所做的:
test_datagen = ImageDataGenerator()
test_generator =
datagen.flow_from_directory(
"intel-images/seg_test/seg_test",
target_size=(150,150), class_mode="sparse")
print(model.evaluate_generator(test_generator))
這將為我們的示例返回一個(gè)包含兩個(gè)值的數(shù)組:損失和準(zhǔn)確性。(你還可以通過(guò)查看model.metrics_names值來(lái)檢查。)
我的準(zhǔn)確率為 81.7%,這對(duì)于非平凡數(shù)據(jù)集上的相對(duì)簡(jiǎn)單模型來(lái)說(shuō)還不錯(cuò)。
生成預(yù)測(cè)
你現(xiàn)在可以使用該model.predict方法對(duì)任何圖像生成預(yù)測(cè)。此方法將 NumPy 圖像數(shù)組作為輸入,其中圖像也是形狀為 (150, 150, 3) 的 NumPy 數(shù)組。要對(duì)一張圖像進(jìn)行預(yù)測(cè),你可以執(zhí)行以下操作:
import skimage.io import numpy as np model.predict(np.expand_dims(skimage.io.imread("file.jpg"), axis=0))
skimage.io.imread將讀取圖像expand_dims并將另一個(gè)維度添加到數(shù)組。輸出是一個(gè)預(yù)測(cè)數(shù)組,其中每個(gè)預(yù)測(cè)是一個(gè)值數(shù)組,指示每個(gè)類別的概率。
數(shù)據(jù)增強(qiáng)
數(shù)據(jù)增強(qiáng)是指根據(jù)現(xiàn)有訓(xùn)練集生成新的訓(xùn)練數(shù)據(jù),以提高準(zhǔn)確性和泛化性并減少過(guò)度擬合。
對(duì)于圖像,數(shù)據(jù)增強(qiáng)可以通過(guò)對(duì)圖像進(jìn)行多種變換來(lái)完成:旋轉(zhuǎn)、翻轉(zhuǎn)、縮放、移位、剪切等。
ImageDataGenerator使這變得容易。要將數(shù)據(jù)增強(qiáng)應(yīng)用于我們的模型,只需更改兩行代碼。
首先,ImageDataGenerator使用更多參數(shù)實(shí)例化,指定我們想要的轉(zhuǎn)換:
Python復(fù)制代碼
datagen = ImageDataGenerator(rotation_range=30,
horizontal_flip=True,
zoom_range=0.2,
shear_range=0.2)
還有更多的可能性——請(qǐng)參閱圖像預(yù)處理文檔以獲取完整的參數(shù)列表。
第二行是fit_generator電話。這個(gè)函數(shù)有可選steps_per_epoch和validation_steps參數(shù),我們可以離開(kāi)了前面,因?yàn)槲覀冇杏?xùn)練樣本的固定數(shù)量。通過(guò)數(shù)據(jù)增強(qiáng),我們可能有更多的訓(xùn)練樣本,因此我們必須指定要使用的數(shù)量。如果我們不這樣做,該函數(shù)將只使用我們固定大小的樣本集。一個(gè)步驟對(duì)應(yīng)于一批給定的batch_size。
model.fit_generator(train_generator, epochs=40,
validation_data=validation_generator,
steps_per_epoch=1600, validation_steps=32)
同樣,如果您希望該過(guò)程更快,請(qǐng)隨時(shí)減少 epoch 數(shù)或步驟數(shù)。經(jīng)過(guò) 2-3 小時(shí)的訓(xùn)練,我的準(zhǔn)確率為 85.5%。
保存和恢復(fù)模型
Keras 允許你以 HDF5 格式保存經(jīng)過(guò)訓(xùn)練的模型:
model.save("images_model.h5")
恢復(fù)模型也是一行:
import keras.models
model = keras.models.load_model("images_model.h5")
這需要h5py軟件包,如果你使用的是conda install. 如果沒(méi)有,請(qǐng)?jiān)?Jupyter Notebook 單元中運(yùn)行此 pip 命令:
Python復(fù)制代碼
!pip install --upgrade h5py
結(jié)論
在本模塊中,我們演練了 Keras 在圖像分類問(wèn)題中的使用。Keras 的可用層比我們?cè)谶@里使用的層多得多。如果您想深入了解,可以使用Keras 文檔作為起點(diǎn)。它還提供了大量常見(jiàn)深度學(xué)習(xí)問(wèn)題的示例。