深度學習 - Kaggle - Dog & Cat - 使用預訓練的卷積神經網絡
在cat & dog 的學習過程,我們只使用了較少的數據集,所以得到的精度不比在大型數據庫訓練的精準度。然而在處理較小型數據問題時,使用預先訓練好的模型,其在大規模數據學習到的特徵在不同問題之間的可移植性,是深度學習與許多早期淺層學習方法相比的重要優勢,它使得深度學習對小數據問題也非常有效。
使用預訓練網絡有兩種方法:特徵提取(feature extraction)和微調模型(fine-tuning)
特徵提取(feature extraction)
對於卷積神經網絡而言,特徵提取就是取出之前訓練好的網絡的卷積基(trained convolution base),在上面運行新數據,然後在輸出上面訓練一個新的分類器(new classifier)。
簡而言之,就是將輸出層刪掉,保留卷積層,當作特徵提取機,將經過卷積基後提取的特徵再訓練分類成我們要處理的問題。
我們練習使用VGG16預訓練模型的卷積基
from keras.applications import VGG16
conv_base = VGG16(weights='imagenet',
include_top=False,
input_shape=(150, 150, 3))
weights指定模型初始化的權重檢查點。
include_top 指定模型最後是否包含密集連接分類器。默認情況下,這個密集連接分類器對應於ImageNet 的1000 個類別。因為我們打算使用自己的密集連接分類器(只有兩個類別:cat 和dog),所以不需要包含它。
可以看看True & False 的差異 :
include_top=True 會包含最後三個密集連接層(黃色框內),其最後會將訓練結果做1000個分類,在這邊,我們只需要分類貓&狗,所以不需要使用到1000個分類,這是相當浪費計算資源的。
接著,我們要將訓練資料透過 conv_base 的 predict 方法來提取特徵。
目的: 將train, validation, test 的資料都用conv_base 過濾出特徵,輸出形狀為(4,4,512) 的array。
因為會使用到3次,將其寫成函數
#使用ImageDataGenerator 將圖片rescale import numpy as np from keras.preprocessing.image import ImageDataGenerator datagen = ImageDataGenerator(rescale=1./255) batch_size = 20
def extract_features(directory, sample_count): #建立兩個zero array 存放特徵 features = np.zeros(shape=(sample_count, 4, 4, 512)) labels = np.zeros(shape=(sample_count)) #利用 Keras 內建的 generator 將生成數據輸入至 conv_base generator = datagen.flow_from_directory(directory, target_size=(150, 150), batch_size=batch_size, class_mode='binary') #跑個for 迴圈,批次將 conv_base 的輸出存進 features,labels array。 i = 0 for inputs_batch, labels_batch in generator: features_batch = conv_base.predict(inputs_batch) 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_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)
#將數據reshape ,才能連結至我們自訂的密集連接層作訓練。 train_features = np.reshape(train_features, (2000, 4 * 4 * 512)) validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512)) test_features = np.reshape(test_features, (1000, 4 * 4 * 512))
#建立模型網絡 from keras import layers from keras import models model = models.Sequential() model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512)) model.add(layers.Dropout(0.5)) model.add(layers.Dense(1, activation='sigmoid'))
#選擇優化器RMSprop、損失函數binary_crossentropy、指標acc from keras import optimizers model.compile(optimizer=optimizers.RMSprop(lr=2e-5), loss='binary_crossentropy', metrics=['acc'])
#將訓練&驗證資料丟進fit_generator訓練 history = model.fit(train_features, train_labels, epochs=30, batch_size=20, validation_data=(validation_features, validation_labels)) scores = model.evaluate(test_features,test_labels, steps=50) print(scores)
#將訓練過程畫出來 import matplotlib.pyplot as plt acc = history.history['acc'] val_acc = history.history['val_acc'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(1, len(acc) + 1) plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.legend() plt.figure() plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.legend() plt.show()
在測試數據上的[loss,acc]
[0.26085495948791504, 0.8880000114440918]
利用預訓練模型特徵提取,連接至自定義的全連接層訓練後,提高精度到達了88%
後續再練習微調模型(fine-tuning)
沒有留言:
張貼留言