Applications模块解析(一)
文章目錄
- 說明
- 官方模型
- 使用與下載
- 存儲文件與位置
- 預(yù)測
- 完整代碼
- 構(gòu)建新網(wǎng)絡(luò)
- 特征提取
- 提取任意中間層特征
- 微調(diào)神經(jīng)網(wǎng)絡(luò)
- 自動輸入張量
- 其他推薦
前言
閱讀該文檔需要二十分鐘,完成后你將會學(xué)會使用applications模塊的核心功能,并能夠使用該模塊中與訓(xùn)練模型進(jìn)行預(yù)測,或在對該模塊提供的神經(jīng)網(wǎng)絡(luò)進(jìn)行微調(diào),提取任意中間層特征。以下為類庫版本: 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中的一個(gè)特殊模塊,其為我們提供了已經(jīng)構(gòu)建好的多種經(jīng)典神經(jīng)網(wǎng)絡(luò)以及在特定數(shù)據(jù)集上訓(xùn)練好的模型。同時(shí)借助該模塊,我們也可以抽取其中的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),直接用于或者調(diào)整后用于訓(xùn)練自己的模型。以下是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這些代碼直接告訴了我們當(dāng)前版本可以使用的神經(jīng)網(wǎng)絡(luò)。
官方模型
使用與下載
上面的代碼告訴了我們Applications模塊中神經(jīng)網(wǎng)絡(luò)的引用格式。引用后的函數(shù)則可以通過參數(shù)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
存儲文件與位置
模型下載后的默認(rèn)存儲位置是當(dāng)前賬戶下的隱藏文件夾,路徑為~/.keras/models,絕對路徑(以本人為例)/home/fonttian/.keras/models。我們也可以直接下載模型然后存在該位置。不過除了模型之外,還會有其他文件存在,比如imagenet_class_index.json。字如其名,該文件是所使用的數(shù)據(jù)集的class_index.json,該文件中一共有一千類,與函數(shù)ResNet50中的參數(shù)classes=1000也是對應(yīng)的。
預(yù)測
首先展示代碼,這里使用的是官方例子。
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) # 將結(jié)果解碼為元組列表 (class, description, probability) # (一個(gè)列表代表批次中的一個(gè)樣本) 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)]上面的代碼中可以分為兩個(gè)模塊來看,首先是加載數(shù)據(jù)并處理,這里加載數(shù)據(jù)的函數(shù)image.load_img是官方提供的函數(shù),size參數(shù)的作用是對圖片進(jìn)行尺寸的調(diào)整。加載后的圖片繼續(xù)使用numpy進(jìn)行調(diào)整。而第二個(gè)模塊則是預(yù)測模塊,使用model.predict進(jìn)行預(yù)測,預(yù)測后則使用官方自帶的解碼函數(shù)decode_predictions將其轉(zhuǎn)化為元組列表(class, description, probability)進(jìn)行輸出,同時(shí)借助參數(shù)top選擇要輸出的項(xiàng)多少個(gè)。
完整代碼
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) # 將結(jié)果解碼為元組列表 (class, description, probability) # (一個(gè)列表代表批次中的一個(gè)樣本) 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模塊本質(zhì)返回的是一個(gè)model對象,所以具體怎么操作這個(gè)model其實(shí)應(yīng)該是很靈活的。下邊就是一些更加靈活使用該model對象的內(nèi)容。同時(shí),很顯然這些代碼也可以移植到我們自己創(chuàng)建的model對象上。
構(gòu)建新網(wǎng)絡(luò)
特征提取
Keras自帶的神經(jīng)網(wǎng)絡(luò)都是已經(jīng)構(gòu)建的經(jīng)典神經(jīng)網(wǎng)絡(luò),比如VGG16,這是一個(gè)經(jīng)典的分類神經(jīng)網(wǎng)絡(luò)。而特征提取需要的則是沒有分類器的神經(jīng)網(wǎng)絡(luò),這點(diǎn)我們可以通過參數(shù)include_top來控制。keras中對該參數(shù)的解釋為:
include_top: whether to include the ? fully-connectedlayers at the top of the network.由于不同的神經(jīng)網(wǎng)絡(luò)使用的分類器不同,有時(shí)候會有個(gè)數(shù)字表示全連接神經(jīng)網(wǎng)絡(luò)的層數(shù),所以我在這用一個(gè)問號代替。
官方給的例子有多個(gè),首先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)此時(shí)出書的例子就變?yōu)榱颂卣?#xff0c;本質(zhì)是矩陣。而非之前的類別。
提取任意中間層特征
除此之外,本質(zhì)上來說所有applications中的神經(jīng)網(wǎng)絡(luò)返回的都是定義好的keras中的神經(jīng)網(wǎng)絡(luò)。因此我們也可以按照一般神經(jīng)網(wǎng)絡(luò)那樣獲取任意的中間層特征。具體方法如下,這里使用的是官方給的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)這個(gè)很容易看懂,就是借助了Model參數(shù)對原來的完整的model進(jìn)行了處理,關(guān)鍵參數(shù)是outputs,
這里真真的個(gè)問題在于如何獲取核心參數(shù),也就是函數(shù)get_layer的參數(shù)name(另外get_layer還有一個(gè)參數(shù)為index)這里確實(shí)沒有很好地方法,而直接最有效的方法肯定還是直接查看keras的源碼,該部分代碼位于keras_applications中,如果在Pycharm中可以直接ctrl點(diǎn)擊進(jìn)去查看,或者前往github下載源碼,這里是keras-applications的github地址。
微調(diào)神經(jīng)網(wǎng)絡(luò)
通過剛剛的代碼我們已經(jīng)非常接近applications模塊的本質(zhì)了,我們可以在其上做更多更加純粹的事情,比如只使用該模塊提供的神經(jīng)網(wǎng)絡(luò)的一部分,而其他重要部分則由我們自行構(gòu)建。具體方法則剛剛所做一致。首先借用include_top參數(shù)去除分類器,然后借助Model函數(shù)獲取我們想要的輸出,比如上一部分的提取任意中間層的特征,其實(shí)說到底就是把截取并運(yùn)行了一個(gè)正常的神經(jīng)網(wǎng)絡(luò)一部分。之后再進(jìn)行微調(diào),獲取我們需要的模型。
下面是keras的例子-微調(diào) InceptionV3 ,我們以此為講解:
(1)構(gòu)建神經(jīng)網(wǎng)絡(luò)
# 構(gòu)建不帶分類器的預(yù)訓(xùn)練模型 base_model = InceptionV3(weights='imagenet', include_top=False)# 添加全局平均池化層 x = base_model.output x = GlobalAveragePooling2D()(x)# 添加一個(gè)全連接層 x = Dense(1024, activation='relu')(x)# 添加一個(gè)分類器,假設(shè)我們有200個(gè)類 predictions = Dense(200, activation='softmax')(x)# 構(gòu)建我們需要訓(xùn)練的完整模型 model = Model(inputs=base_model.input, outputs=predictions)這一步前半部分與之前的一致,都是先獲取不帶分類的神經(jīng)網(wǎng)絡(luò)。之后我們則自己來添加一個(gè)分類器,此處是先添加全劇平均池化層,然后添加一個(gè)兩層神經(jīng)網(wǎng)絡(luò)作為分類器(200類)。之后再使用Model構(gòu)建完整的模型。
(2)鎖層,訓(xùn)練新分類器
這里我們使用了預(yù)訓(xùn)練的模型,之后我們則需要使用鎖層。鎖層的方法是設(shè)置.trainable=False,該屬性是keras中Network的固有屬性,其繼承于keras.engine.base_layer中的layer。這是我們非常常用的keras中的類。我們通過該方法可以將v3的所有卷積層都鎖定,然后訓(xùn)練未鎖定的層。
# 首先,我們只訓(xùn)練頂部的幾層(隨機(jī)初始化的層) # 鎖住所有 InceptionV3 的卷積層 for layer in base_model.layers:layer.trainable = False# 編譯模型(一定要在鎖層以后操作) model.compile(optimizer='rmsprop', loss='categorical_crossentropy')# 在新的數(shù)據(jù)集上訓(xùn)練幾代 model.fit_generator(...)# 現(xiàn)在頂層應(yīng)該訓(xùn)練好了,讓我們開始微調(diào) Inception V3 的卷積層。(3)訓(xùn)練頂層
通過剛剛的操作我們就訓(xùn)練好了我們的頂層(top layers),現(xiàn)在我們則可以逐漸放開,并訓(xùn)練后邊的神經(jīng)元了。具體代碼如下:
# 現(xiàn)在頂層應(yīng)該訓(xùn)練好了,讓我們開始微調(diào) Inception V3 的卷積層。 # 我們會鎖住底下的幾層,然后訓(xùn)練其余的頂層。# 讓我們看看每一層的名字和層號,看看我們應(yīng)該鎖多少層呢: for i, layer in enumerate(base_model.layers):print(i, layer.name)# 我們選擇訓(xùn)練最上面的兩個(gè) Inception block # 也就是說鎖住前面249層,然后放開之后的層。 for layer in model.layers[:249]:layer.trainable = False for layer in model.layers[249:]:layer.trainable = True# 我們需要重新編譯模型,才能使上面的修改生效 # 讓我們設(shè)置一個(gè)很低的學(xué)習(xí)率,使用 SGD 來微調(diào) from keras.optimizers import SGD model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')# 我們繼續(xù)訓(xùn)練模型,這次我們訓(xùn)練最后兩個(gè) Inception block # 和兩個(gè)全連接層 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# 構(gòu)建不帶分類器的預(yù)訓(xùn)練模型 base_model = InceptionV3(weights='imagenet', include_top=False)# 添加全局平均池化層 x = base_model.output x = GlobalAveragePooling2D()(x)# 添加一個(gè)全連接層 x = Dense(1024, activation='relu')(x)# 添加一個(gè)分類器,假設(shè)我們有200個(gè)類 predictions = Dense(200, activation='softmax')(x)# 構(gòu)建我們需要訓(xùn)練的完整模型 model = Model(inputs=base_model.input, outputs=predictions)# 首先,我們只訓(xùn)練頂部的幾層(隨機(jī)初始化的層) # 鎖住所有 InceptionV3 的卷積層 for layer in base_model.layers:layer.trainable = False# 編譯模型(一定要在鎖層以后操作) model.compile(optimizer='rmsprop', loss='categorical_crossentropy')# 在新的數(shù)據(jù)集上訓(xùn)練幾代 model.fit_generator(...)# 現(xiàn)在頂層應(yīng)該訓(xùn)練好了,讓我們開始微調(diào) Inception V3 的卷積層。 # 我們會鎖住底下的幾層,然后訓(xùn)練其余的頂層。# 讓我們看看每一層的名字和層號,看看我們應(yīng)該鎖多少層呢: for i, layer in enumerate(base_model.layers):print(i, layer.name)# 我們選擇訓(xùn)練最上面的兩個(gè) Inception block # 也就是說鎖住前面249層,然后放開之后的層。 for layer in model.layers[:249]:layer.trainable = False for layer in model.layers[249:]:layer.trainable = True# 我們需要重新編譯模型,才能使上面的修改生效 # 讓我們設(shè)置一個(gè)很低的學(xué)習(xí)率,使用 SGD 來微調(diào) from keras.optimizers import SGD model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')# 我們繼續(xù)訓(xùn)練模型,這次我們訓(xùn)練最后兩個(gè) Inception block # 和兩個(gè)全連接層 model.fit_generator(...)自動輸入張量
from keras.applications.inception_v3 import InceptionV3 from keras.layers import Input# 這也可能是不同的 Keras 模型或?qū)拥妮敵?/span> input_tensor = Input(shape=(224, 224, 3)) # 假定 K.image_data_format() == 'channels_last'model = InceptionV3(input_tensor=input_tensor, weights='imagenet', include_top=True)其他推薦
總結(jié)
以上是生活随笔為你收集整理的Applications模块解析(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 角点检测——发现图像的特征
- 下一篇: 利用多项式特征生成与递归特征消除解决特征