Applications模块解析(一)
文章目錄
- 說明
- 官方模型
- 使用與下載
- 存儲文件與位置
- 預測
- 完整代碼
- 構建新網絡
- 特征提取
- 提取任意中間層特征
- 微調神經網絡
- 自動輸入張量
- 其他推薦
前言
閱讀該文檔需要二十分鐘,完成后你將會學會使用applications模塊的核心功能,并能夠使用該模塊中與訓練模型進行預測,或在對該模塊提供的神經網絡進行微調,提取任意中間層特征。以下為類庫版本: keras 2.3.1 keras-applications 1.0.8 keras-base 2.3.1 keras-preprocessing 1.1.0 tensorflow 2.2.0 tensorflow-base 2.2.0 tensorflow-estimator 2.2.0 tensorflow-gpu 2.2.0
說明
Application是keras中的一個特殊模塊,其為我們提供了已經構建好的多種經典神經網絡以及在特定數據集上訓練好的模型。同時借助該模塊,我們也可以抽取其中的神經網絡結構,直接用于或者調整后用于訓練自己的模型。以下是keras.applications模塊中的初始化文件(__init__.py)中的代碼。
from .vgg16 import VGG16 from .vgg19 import VGG19 from .resnet50 import ResNet50 from .inception_v3 import InceptionV3 from .inception_resnet_v2 import InceptionResNetV2 from .xception import Xception from .mobilenet import MobileNet from .mobilenet_v2 import MobileNetV2 from .densenet import DenseNet121, DenseNet169, DenseNet201 from .nasnet import NASNetMobile, NASNetLarge from .resnet import ResNet101, ResNet152 from .resnet_v2 import ResNet50V2, ResNet101V2, ResNet152V2這些代碼直接告訴了我們當前版本可以使用的神經網絡。
官方模型
使用與下載
上面的代碼告訴了我們Applications模塊中神經網絡的引用格式。引用后的函數則可以通過參數weights獲取官方模型。
from keras.applications.resnet50 import ResNet50 model = ResNet50(weights='imagenet')使用以上代碼,keras將會檢測模型是否存在,不存在則會前往github下載模型,以上代碼所需模型的下載地址為:https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels.h5
存儲文件與位置
模型下載后的默認存儲位置是當前賬戶下的隱藏文件夾,路徑為~/.keras/models,絕對路徑(以本人為例)/home/fonttian/.keras/models。我們也可以直接下載模型然后存在該位置。不過除了模型之外,還會有其他文件存在,比如imagenet_class_index.json。字如其名,該文件是所使用的數據集的class_index.json,該文件中一共有一千類,與函數ResNet50中的參數classes=1000也是對應的。
預測
首先展示代碼,這里使用的是官方例子。
img_path = '../Images/elephant.jpg' img = image.load_img(img_path, 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) # 將結果解碼為元組列表 (class, description, probability) # (一個列表代表批次中的一個樣本) print('Predicted:', decode_predictions(preds, top=3)[0]) # Predicted: [(u'n02504013', u'Indian_elephant', 0.82658225), (u'n01871265', u'tusker', 0.1122357), (u'n02504458', u'African_elephant', 0.061040461)]上面的代碼中可以分為兩個模塊來看,首先是加載數據并處理,這里加載數據的函數image.load_img是官方提供的函數,size參數的作用是對圖片進行尺寸的調整。加載后的圖片繼續使用numpy進行調整。而第二個模塊則是預測模塊,使用model.predict進行預測,預測后則使用官方自帶的解碼函數decode_predictions將其轉化為元組列表(class, description, probability)進行輸出,同時借助參數top選擇要輸出的項多少個。
完整代碼
from keras.applications.resnet50 import ResNet50 from keras.preprocessing import image from keras.applications.resnet50 import preprocess_input, decode_predictions import numpy as npmodel = ResNet50(weights='imagenet')img_path = '../Images/elephant.jpg' img = image.load_img(img_path, 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) # 將結果解碼為元組列表 (class, description, probability) # (一個列表代表批次中的一個樣本) print('Predicted:', decode_predictions(preds, top=3)[0]) # Predicted: [(u'n02504013', u'Indian_elephant', 0.82658225), (u'n01871265', u'tusker', 0.1122357), (u'n02504458', u'African_elephant', 0.061040461)]從完整代碼我們可以很清楚的看出,Applications模塊本質返回的是一個model對象,所以具體怎么操作這個model其實應該是很靈活的。下邊就是一些更加靈活使用該model對象的內容。同時,很顯然這些代碼也可以移植到我們自己創建的model對象上。
構建新網絡
特征提取
Keras自帶的神經網絡都是已經構建的經典神經網絡,比如VGG16,這是一個經典的分類神經網絡。而特征提取需要的則是沒有分類器的神經網絡,這點我們可以通過參數include_top來控制。keras中對該參數的解釋為:
include_top: whether to include the ? fully-connectedlayers at the top of the network.由于不同的神經網絡使用的分類器不同,有時候會有個數字表示全連接神經網絡的層數,所以我在這用一個問號代替。
官方給的例子有多個,首先VGG16 提取特征的例子:
from keras.applications.vgg16 import VGG16 from keras.preprocessing import image from keras.applications.vgg16 import preprocess_input import numpy as npmodel = VGG16(weights='imagenet', include_top=False)img_path = 'elephant.jpg' img = image.load_img(img_path, target_size=(224, 224)) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x)features = model.predict(x)此時出書的例子就變為了特征,本質是矩陣。而非之前的類別。
提取任意中間層特征
除此之外,本質上來說所有applications中的神經網絡返回的都是定義好的keras中的神經網絡。因此我們也可以按照一般神經網絡那樣獲取任意的中間層特征。具體方法如下,這里使用的是官方給的VGG19提取任意中間層特征的例子:
from keras.applications.vgg19 import VGG19 from keras.preprocessing import image from keras.applications.vgg19 import preprocess_input from keras.models import Model import numpy as npbase_model = VGG19(weights='imagenet') model = Model(inputs=base_model.input, outputs=base_model.get_layer('block4_pool').output)img_path = '../Images/elephant.jpg' img = image.load_img(img_path, target_size=(224, 224)) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x)block4_pool_features = model.predict(x) print(block4_pool_features)這個很容易看懂,就是借助了Model參數對原來的完整的model進行了處理,關鍵參數是outputs,
這里真真的個問題在于如何獲取核心參數,也就是函數get_layer的參數name(另外get_layer還有一個參數為index)這里確實沒有很好地方法,而直接最有效的方法肯定還是直接查看keras的源碼,該部分代碼位于keras_applications中,如果在Pycharm中可以直接ctrl點擊進去查看,或者前往github下載源碼,這里是keras-applications的github地址。
微調神經網絡
通過剛剛的代碼我們已經非常接近applications模塊的本質了,我們可以在其上做更多更加純粹的事情,比如只使用該模塊提供的神經網絡的一部分,而其他重要部分則由我們自行構建。具體方法則剛剛所做一致。首先借用include_top參數去除分類器,然后借助Model函數獲取我們想要的輸出,比如上一部分的提取任意中間層的特征,其實說到底就是把截取并運行了一個正常的神經網絡一部分。之后再進行微調,獲取我們需要的模型。
下面是keras的例子-微調 InceptionV3 ,我們以此為講解:
(1)構建神經網絡
# 構建不帶分類器的預訓練模型 base_model = InceptionV3(weights='imagenet', include_top=False)# 添加全局平均池化層 x = base_model.output x = GlobalAveragePooling2D()(x)# 添加一個全連接層 x = Dense(1024, activation='relu')(x)# 添加一個分類器,假設我們有200個類 predictions = Dense(200, activation='softmax')(x)# 構建我們需要訓練的完整模型 model = Model(inputs=base_model.input, outputs=predictions)這一步前半部分與之前的一致,都是先獲取不帶分類的神經網絡。之后我們則自己來添加一個分類器,此處是先添加全劇平均池化層,然后添加一個兩層神經網絡作為分類器(200類)。之后再使用Model構建完整的模型。
(2)鎖層,訓練新分類器
這里我們使用了預訓練的模型,之后我們則需要使用鎖層。鎖層的方法是設置.trainable=False,該屬性是keras中Network的固有屬性,其繼承于keras.engine.base_layer中的layer。這是我們非常常用的keras中的類。我們通過該方法可以將v3的所有卷積層都鎖定,然后訓練未鎖定的層。
# 首先,我們只訓練頂部的幾層(隨機初始化的層) # 鎖住所有 InceptionV3 的卷積層 for layer in base_model.layers:layer.trainable = False# 編譯模型(一定要在鎖層以后操作) model.compile(optimizer='rmsprop', loss='categorical_crossentropy')# 在新的數據集上訓練幾代 model.fit_generator(...)# 現在頂層應該訓練好了,讓我們開始微調 Inception V3 的卷積層。(3)訓練頂層
通過剛剛的操作我們就訓練好了我們的頂層(top layers),現在我們則可以逐漸放開,并訓練后邊的神經元了。具體代碼如下:
# 現在頂層應該訓練好了,讓我們開始微調 Inception V3 的卷積層。 # 我們會鎖住底下的幾層,然后訓練其余的頂層。# 讓我們看看每一層的名字和層號,看看我們應該鎖多少層呢: for i, layer in enumerate(base_model.layers):print(i, layer.name)# 我們選擇訓練最上面的兩個 Inception block # 也就是說鎖住前面249層,然后放開之后的層。 for layer in model.layers[:249]:layer.trainable = False for layer in model.layers[249:]:layer.trainable = True# 我們需要重新編譯模型,才能使上面的修改生效 # 讓我們設置一個很低的學習率,使用 SGD 來微調 from keras.optimizers import SGD model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')# 我們繼續訓練模型,這次我們訓練最后兩個 Inception block # 和兩個全連接層 model.fit_generator(...)(4)全部代碼
from keras.applications.inception_v3 import InceptionV3 from keras.preprocessing import image from keras.models import Model from keras.layers import Dense, GlobalAveragePooling2D from keras import backend as K# 構建不帶分類器的預訓練模型 base_model = InceptionV3(weights='imagenet', include_top=False)# 添加全局平均池化層 x = base_model.output x = GlobalAveragePooling2D()(x)# 添加一個全連接層 x = Dense(1024, activation='relu')(x)# 添加一個分類器,假設我們有200個類 predictions = Dense(200, activation='softmax')(x)# 構建我們需要訓練的完整模型 model = Model(inputs=base_model.input, outputs=predictions)# 首先,我們只訓練頂部的幾層(隨機初始化的層) # 鎖住所有 InceptionV3 的卷積層 for layer in base_model.layers:layer.trainable = False# 編譯模型(一定要在鎖層以后操作) model.compile(optimizer='rmsprop', loss='categorical_crossentropy')# 在新的數據集上訓練幾代 model.fit_generator(...)# 現在頂層應該訓練好了,讓我們開始微調 Inception V3 的卷積層。 # 我們會鎖住底下的幾層,然后訓練其余的頂層。# 讓我們看看每一層的名字和層號,看看我們應該鎖多少層呢: for i, layer in enumerate(base_model.layers):print(i, layer.name)# 我們選擇訓練最上面的兩個 Inception block # 也就是說鎖住前面249層,然后放開之后的層。 for layer in model.layers[:249]:layer.trainable = False for layer in model.layers[249:]:layer.trainable = True# 我們需要重新編譯模型,才能使上面的修改生效 # 讓我們設置一個很低的學習率,使用 SGD 來微調 from keras.optimizers import SGD model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')# 我們繼續訓練模型,這次我們訓練最后兩個 Inception block # 和兩個全連接層 model.fit_generator(...)自動輸入張量
from keras.applications.inception_v3 import InceptionV3 from keras.layers import Input# 這也可能是不同的 Keras 模型或層的輸出 input_tensor = Input(shape=(224, 224, 3)) # 假定 K.image_data_format() == 'channels_last'model = InceptionV3(input_tensor=input_tensor, weights='imagenet', include_top=True)其他推薦
總結
以上是生活随笔為你收集整理的Applications模块解析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 角点检测——发现图像的特征
- 下一篇: 利用多项式特征生成与递归特征消除解决特征