天天看點

php 圖像紋理特征提取,CNN基礎二:使用預訓練網絡提取圖像特征

上一節中,我們采用了一個自定義的網絡結構,從頭開始訓練貓狗大戰分類器,最終在使用圖像增強的方式下得到了82%的驗證準确率。但是,想要将深度學習應用于小型圖像資料集,通常不會貿然采用複雜網絡并且從頭開始訓練(training from scratch),因為訓練代價高,且很難避免過拟合問題。相對的,通常會采用一種更高效的方法——使用預訓練網絡。

預訓練網絡的使用通常有兩種方式,一種是利用預訓練網絡簡單提取圖像的特征,之後可能會利用這些特征進行其他操作(比如和文本資訊結合以用于image caption,或者簡單的進行分類);另一種是對預訓練的網絡進行裁剪和微調,以适應自己的任務。

第一種方式訓練代價極低,因為它就是簡單提取個特征,不涉及訓練;缺點是儲存提取出來的特征需要占用一定空間,且無法使用圖像增強(而圖像增強對于防止小型資料集的過拟合非常重要)。第二種方式可以使用圖像增強,但訓練代價也會大幅增加。(當然相對于從頭訓練來說,使用預訓練網絡的訓練代價肯定要低得多。)

這一節中我們以VGG16提取圖像特征為例,展示第一種使用方式。該案例接着上一個例子,使用同樣的資料集,利用keras中自帶的VGG16模型提取圖像特征,然後以這些圖像特征為輸入,訓練一個小型分類器。

import numpy as np

from keras.applications.vgg16 import VGG16

#執行個體化一個VGG16卷積基

#輸入次元根據需要自行指定,這裡仍然采用上一個例子的次元,卷積基的輸出是(None,4,4,512)

conv_base = VGG16(include_top=False, input_shape=(150,150,3))

#conv_base.summary()

###############單純用VGG16卷積基直接提取特征,不使用圖像增強####################

import os

from keras.preprocessing.image import ImageDataGenerator

#定義提取圖像特征的函數

datagen = ImageDataGenerator(rescale=1./255)

batch_size = 20

def extract_features(directory, sample_count):

#輸入:檔案路徑,樣本個數

#傳回:指定個數的樣本特征,以及對應的标簽

features = np.zeros(shape=(sample_count, 4, 4, 512))

labels = np.zeros(shape=(sample_count))

generator = datagen.flow_from_directory(

directory,

target_size=(150,150),

batch_size=batch_size,

class_mode='binary')

i = 0

for inputs_batch, labels_batch in generator: #分别為(20,150,150,3) (20,)

features_batch = conv_base.predict(inputs_batch) #(20,4,4,512)

features[i * batch_size : (i + 1) * batch_size] = features_batch

labels[i * batch_size : (i + 1) * batch_size] = labels_batch

i += 1

if i * batch_size >= sample_count: #讀取了指定樣本個數後即退出

break

return features, labels

#分别提取訓練集、驗證集、測試集的圖像特征

train_dir = r'D:\KaggleDatasets\MyDatasets\dogs-vs-cats-small\train'

validation_dir = r'D:\KaggleDatasets\MyDatasets\dogs-vs-cats-small\validation'

test_dir = r'D:\KaggleDatasets\MyDatasets\dogs-vs-cats-small\test'

train_features, train_labels = extract_features(train_dir, 2000)

validation_features, validation_labels = extract_features(validation_dir, 1000)

test_features, test_labels = extract_features(test_dir, 1000)

#将各自的圖像特征展平,作為後續Dense層的輸入

assert train_features.shape == (2000, 4, 4, 512)

assert validation_features.shape == (1000, 4, 4, 512)

assert test_features.shape == (1000, 4, 4, 512)

train_features = train_features.reshape(2000, 4*4*512)

validation_features = validation_features.reshape(1000, 4*4*512)

test_features = test_features.reshape(1000, 4*4*512)

###################定義并訓練一個小型分類器#########################

from keras.models import Model

from keras.layers import Input, Dense, Dropout

input = Input(shape=(4*4*512,))

X = Dense(256, activation='relu')(input)

X = Dropout(0.5)(X)

X = Dense(1, activation='sigmoid')(X)

model = Model(inputs=input, outputs=X)

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

H = model.fit(train_features, train_labels,

validation_data=(validation_features, validation_labels),

epochs=30, batch_size=64, verbose=1)

#######################訓練結果可視化############################

import matplotlib.pyplot as plt

acc = H.history['acc']

val_acc = H.history['val_acc']

loss = H.history['loss']

val_loss = H.history['val_loss']

epoch = range(1, len(loss) + 1)

fig, ax = plt.subplots(1, 2, figsize=(10,4))

fig.subplots_adjust(wspace=0.2)

ax[0].plot(epoch, loss, label='Train loss') #注意不要寫成labels

ax[0].plot(epoch, val_loss, label='Validation loss')

ax[0].set_xlabel('Epoch')

ax[0].set_ylabel('Loss')

ax[0].legend()

ax[1].plot(epoch, acc, label='Train acc')

ax[1].plot(epoch, val_acc, label='Validation acc')

ax[1].set_xlabel('Epoch')

ax[1].set_ylabel('Accuracy')

ax[1].legend()

plt.show()

訓練結果如下所示。可以看出,相對于上一個從頭開始訓練的貓狗分類任務,很輕松的就把驗證集準确率由82%提高到90%左右,更重要的是,現在還沒有使用重量級武器——圖像增強。下一節,我們會使用第二種更常用更高效的方式——模型微調。

php 圖像紋理特征提取,CNN基礎二:使用預訓練網絡提取圖像特征