《python深度學習》筆記---5.3-2、貓狗分類(使用預訓練網絡-實戰)
一、總結
一句話總結:
【卷積就是特征提取】:從預訓練網絡訓練貓狗分類,可以更加方便的理解卷積層就是特征提取
【使用預訓練網絡效果非常好】:我們的驗證精度達到了約90%,比上一節從頭開始訓練的小型模型效果要好得多。但從圖 中也可以看出,雖然 dropout 比率相當大,但模型幾乎從一開始就過擬合。這是因為本方法沒有 使用數據增強,而數據增強對防止小型圖像數據集的過擬合非常重要。
1、引入vgg16已經訓練好的模型?
from tensorflow.keras.applications import VGG16
conv_base = VGG16(weights='imagenet',include_top=False,input_shape=(150, 150, 3))
# 把vgg模型弄過來 conv_base = VGG16(weights='imagenet', # include_top=False表示不包含dense層 include_top=False, input_shape=(150, 150, 3)) 這里向構造函數中傳入了三個參數。 weights 指定模型初始化的權重檢查點。 include_top 指定模型最后是否包含密集連接分類器。默認情況下,這個密集連接分類器對應於ImageNet 的 1000 個類別。因為我們打算使用自己的密集連接分類器(只有 兩個類別:cat 和 dog),所以不需要包含它。 input_shape 是輸入到網絡中的圖像張量的形狀。這個參數完全是可選的,如果不傳 入這個參數,那么網絡能夠處理任意形狀的輸入。
2、利用預訓練好的VGG16抽取訓練集、驗證集和測試集的特征?
【主要就是VGG16的predict方法】:features_batch = conv_base.predict(inputs_batch)
''' directory:目錄 sample_count:樣本數 ''' def extract_features(directory, sample_count): # 初始化 features features = np.zeros(shape=(sample_count, 4, 4, 512)) # 初始化 labels 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: # 調用 conv_base 模型的 predict 方法來從這些圖像中提取特征。 features_batch = conv_base.predict(inputs_batch) # 切片依次找到features和labels 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)
3、預訓練好的VGG16后面接dense層實例?
其實就是把vgg16提取好的特征放到作為輸入數據放到dense網絡里面就好
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')) model.compile(optimizer=optimizers.RMSprop(lr=2e-5), loss='binary_crossentropy', metrics=['acc']) history = model.fit(train_features, train_labels, epochs=30, batch_size=20, validation_data=(validation_features, validation_labels))
二、5.3-2、貓狗分類(使用預訓練網絡-實戰)
博客對應課程的視頻位置:
import pandas as pd import numpy as np import tensorflow as tf import matplotlib.pyplot as plt
In [3]:
from tensorflow.keras.applications import VGG16 # 把vgg模型弄過來 conv_base = VGG16(weights='imagenet', # include_top=False表示不包含dense層 include_top=False, input_shape=(150, 150, 3)) # C:\Users\Fan Renyi\.keras\models\vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
這里向構造函數中傳入了三個參數。
weights 指定模型初始化的權重檢查點。
include_top 指定模型最后是否包含密集連接分類器。默認情況下,這個密集連接分類器對應於ImageNet 的 1000 個類別。因為我們打算使用自己的密集連接分類器(只有 兩個類別:cat 和 dog),所以不需要包含它。
input_shape 是輸入到網絡中的圖像張量的形狀。這個參數完全是可選的,如果不傳 入這個參數,那么網絡能夠處理任意形狀的輸入。
1、 不使用數據增強的快速特征提取
首先,運行 ImageDataGenerator 實例,將圖像及其標簽提取為Numpy 數組。我們需要 調用 conv_base 模型的 predict 方法來從這些圖像中提取特征。
In [1]:
import os from tensorflow.keras.preprocessing.image import ImageDataGenerator
In [4]:
base_dir = 'E:\\78_recorded_lesson\\001_course_github\\AI_dataSet\\dogs-vs-cats\\cats_and_dogs_small' train_dir = os.path.join(base_dir, 'train') validation_dir = os.path.join(base_dir, 'validation') test_dir = os.path.join(base_dir, 'test')
In [5]:
datagen = ImageDataGenerator(rescale=1./255) batch_size = 20
In [12]:
'''
directory:目錄 sample_count:樣本數 ''' def extract_features(directory, sample_count): # 初始化 features features = np.zeros(shape=(sample_count, 4, 4, 512)) # 初始化 labels 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: # 調用 conv_base 模型的 predict 方法來從這些圖像中提取特征。 features_batch = conv_base.predict(inputs_batch) # 切片依次找到features和labels 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
In [15]:
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)
In [17]:
print(train_features.shape) print(train_labels.shape)
目前,提取的特征形狀為 (samples, 4, 4, 512)。我們要將其輸入到密集連接分類器中, 所以首先必須將其形狀展平為 (samples, 8192)。
In [18]:
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))
In [19]:
print(train_features.shape)
現在你可以定義你的密集連接分類器(注意要使用dropout 正則化),並在剛剛保存的數據 和標簽上訓練這個分類器。
In [20]:
from tensorflow.keras import models from tensorflow.keras import layers from tensorflow.keras import optimizers
In [21]:
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'))
In [22]:
model.compile(optimizer=optimizers.RMSprop(lr=2e-5), loss='binary_crossentropy', metrics=['acc'])
In [23]:
history = model.fit(train_features, train_labels, epochs=30, batch_size=20, validation_data=(validation_features, validation_labels))
訓練速度非常快,因為你只需處理兩個 Dense 層。即使在CPU 上運行,每輪的時間也不 到一秒鍾。
訓練期間的損失曲線和精度曲線
In [26]:
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, 'b--', label='Training acc') plt.plot(epochs, val_acc, 'r-', label='Validation acc') plt.title('Training and validation accuracy') plt.legend() plt.figure() plt.plot(epochs, loss, 'b--', label='Training loss') plt.plot(epochs, val_loss, 'r-', label='Validation loss') plt.title('Training and validation loss') plt.legend() plt.show()
我們的驗證精度達到了約90%,比上一節從頭開始訓練的小型模型效果要好得多。但從圖 中也可以看出,雖然 dropout 比率相當大,但模型幾乎從一開始就過擬合。這是因為本方法沒有 使用數據增強,而數據增強對防止小型圖像數據集的過擬合非常重要。
根本原因的話其實就是 因為預訓練的vgg16中訓練了很多數據,而這些數據使准確率提供很正常
In [ ]: