《python深度學習》筆記---5.3-2、貓狗分類(使用預訓練網絡-實戰)


《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) 
Found 2000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
Found 1000 images belonging to 2 classes.
In [17]:
print(train_features.shape) print(train_labels.shape) 
(2000, 4, 4, 512)
(2000,)

目前,提取的特征形狀為 (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) 
(2000, 8192)

現在你可以定義你的密集連接分類器(注意要使用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)) 
Epoch 1/30
100/100 [==============================] - 1s 5ms/step - loss: 0.5869 - acc: 0.6830 - val_loss: 0.4461 - val_acc: 0.8280
Epoch 2/30
100/100 [==============================] - 0s 4ms/step - loss: 0.4259 - acc: 0.8145 - val_loss: 0.3650 - val_acc: 0.8550
Epoch 3/30
100/100 [==============================] - 0s 4ms/step - loss: 0.3570 - acc: 0.8530 - val_loss: 0.3341 - val_acc: 0.8670
Epoch 4/30
100/100 [==============================] - 0s 4ms/step - loss: 0.3124 - acc: 0.8780 - val_loss: 0.3015 - val_acc: 0.8750
Epoch 5/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2856 - acc: 0.8885 - val_loss: 0.2838 - val_acc: 0.8840
Epoch 6/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2666 - acc: 0.8960 - val_loss: 0.2731 - val_acc: 0.8880
Epoch 7/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2477 - acc: 0.9030 - val_loss: 0.2646 - val_acc: 0.8910
Epoch 8/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2388 - acc: 0.9080 - val_loss: 0.2625 - val_acc: 0.8920
Epoch 9/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2251 - acc: 0.9130 - val_loss: 0.2534 - val_acc: 0.8960
Epoch 10/30
100/100 [==============================] - 0s 4ms/step - loss: 0.2059 - acc: 0.9255 - val_loss: 0.2513 - val_acc: 0.8970
Epoch 11/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1988 - acc: 0.9265 - val_loss: 0.2598 - val_acc: 0.8920
Epoch 12/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1903 - acc: 0.9320 - val_loss: 0.2458 - val_acc: 0.8990
Epoch 13/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1818 - acc: 0.9335 - val_loss: 0.2417 - val_acc: 0.9050
Epoch 14/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1786 - acc: 0.9340 - val_loss: 0.2402 - val_acc: 0.9030
Epoch 15/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1706 - acc: 0.9390 - val_loss: 0.2375 - val_acc: 0.9020
Epoch 16/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1574 - acc: 0.9480 - val_loss: 0.2349 - val_acc: 0.9020
Epoch 17/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1587 - acc: 0.9455 - val_loss: 0.2346 - val_acc: 0.9060
Epoch 18/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1448 - acc: 0.9500 - val_loss: 0.2474 - val_acc: 0.9000
Epoch 19/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1411 - acc: 0.9485 - val_loss: 0.2345 - val_acc: 0.9010
Epoch 20/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1383 - acc: 0.9510 - val_loss: 0.2326 - val_acc: 0.9030
Epoch 21/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1313 - acc: 0.9570 - val_loss: 0.2412 - val_acc: 0.9010
Epoch 22/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1262 - acc: 0.9600 - val_loss: 0.2337 - val_acc: 0.9040
Epoch 23/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1213 - acc: 0.9600 - val_loss: 0.2347 - val_acc: 0.9040
Epoch 24/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1164 - acc: 0.9615 - val_loss: 0.2337 - val_acc: 0.9020
Epoch 25/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1124 - acc: 0.9630 - val_loss: 0.2342 - val_acc: 0.9040
Epoch 26/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1033 - acc: 0.9650 - val_loss: 0.2321 - val_acc: 0.9070
Epoch 27/30
100/100 [==============================] - 0s 4ms/step - loss: 0.1029 - acc: 0.9685 - val_loss: 0.2391 - val_acc: 0.9040
Epoch 28/30
100/100 [==============================] - 0s 4ms/step - loss: 0.0988 - acc: 0.9670 - val_loss: 0.2335 - val_acc: 0.9090
Epoch 29/30
100/100 [==============================] - 0s 4ms/step - loss: 0.0935 - acc: 0.9720 - val_loss: 0.2416 - val_acc: 0.9030
Epoch 30/30
100/100 [==============================] - 0s 4ms/step - loss: 0.0933 - acc: 0.9730 - val_loss: 0.2348 - val_acc: 0.9080

訓練速度非常快,因為你只需處理兩個 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 [ ]:
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM