TensorFlow 基礎學習 - 4 (重點是調參)

準備數據

!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip \
    -O /tmp/horse-or-human.zip

該目錄下又分別包含horseshumans子目錄。

簡而言之:訓練集就是用來告訴神經網絡模型"這就是馬的樣子"、"這就是人的樣子"等數據。

這裏需要注意的是,我們並沒有明確地將圖像標註爲馬或人。如果還記得之前的手寫數字例子,它的訓練數據已經標註了"這是一個1","這是一個7"等等。 稍後,我們使用一個叫做ImageGenerator的類--用它從子目錄中讀取圖像,並根據子目錄的名稱自動給圖像貼上標籤。所以,會有一個"訓練"目錄,其中包含一個"馬匹"目錄和一個"人類"目錄。ImageGenerator將爲你適當地標註圖片,從而減少一個編碼步驟。(不僅編程上更方便,而且可以避免一次性把所有訓練數據載入內存,而導致內存不夠等問題。)

讓我們分別定義這些目錄。

# Directory with our training horse pictures
train_horse_dir = os.path.join('/tmp/horse-or-human/horses')

# Directory with our training human pictures
train_human_dir = os.path.join('/tmp/horse-or-human/humans')

建模

像前面的例子一樣添加捲積層CNN,並將最終結果扁平化,以輸送到全連接的層去。

最後我們添加全連接層。

需要注意的是,由於我們面對的是一個兩類分類問題,即二類分類問題,所以我們會用sigmoid激活函數作爲模型的最後一層,這樣我們網絡的輸出將是一個介於0和1之間的有理數,即當前圖像是1類(而不是0類)的概率。

BTW, 如果是是多個分類,比如前面提到的0~9個分類用的softmax激活函數。

import tensorflow as tf

model = tf.keras.models.Sequential([
        tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150,3)),
        tf.keras.layers.MaxPooling2D(2,2),

        tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
        tf.keras.layers.MaxPooling2D(2,2),
        tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
        tf.keras.layers.MaxPooling2D(2,2),

        tf.keras.layers.Flatten(),
        tf.keras.layers.Dense(512, activation='relu'),
        tf.keras.layers.Dense(1, activation='sigmoid')

])

調用model.summary()方法打印出神經元網絡模型的結構信息

接下來,我們將配置模型訓練的參數。我們將用 "binary_crossentropy(二元交叉熵)"衡量損失,因爲這是一個二元分類問題,最終的激活函數是一個sigmoid。關於損失度量的複習,請參見機器學習速成班。我們將使用rmsprop作爲優化器,學習率爲0.001。在訓練過程中,我們將希望監控分類精度。

NOTE.我們將使用學習率爲0.001rmsprop優化器。在這種情況下,使用RMSprop優化算法隨機梯度下降(SGD)更可取,因爲RMSprop可以爲我們自動調整學習率。(其他優化器,如AdamAdagrad,也會在訓練過程中自動調整學習率,在這裏也同樣有效。)

from tensorflow.keras.optimizers import RMSprop
model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
              optimizer=tf.keras.optimizers.RMSprop(lr=0.001),
              metrics=['acc'])

數據預處理

讓我們設置訓練數據生成器(ImageDataGenerator),它將讀取源文件夾中的圖片,將它們轉換爲float32多維數組,並將圖像數據(連同它們的標籤)反饋給神經元網絡。總共需要兩個生成器,有用於產生訓練圖像,一個用於產生驗證圖像。生成器將產生一批大小爲300x300的圖像及其標籤(0或1)。

前面的課中我們已經知道如何對訓練數據做歸一化,進入神經網絡的數據通常應該以某種方式進行歸一化,以使其更容易被網絡處理。在這個例子中,我們將通過將像素值歸一化到[0, 1]範圍內(最初所有的值都在[0, 255]範圍內)來對圖像進行預處理。

在Keras中,可以通過keras.preprocessing.image.ImageDataGenerator類使用rescale參數來實現歸一化。通過ImageDataGenerator類的.flow(data, labels)或.flow_from_directory(directory),可以創建生成器。然後,這些生成器可以作爲輸入Keras方法的參數,如fit_generator、evaluate_generator和predict_generator都可接收生成器實例爲參數。

from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory(
    '/tmp/horse-or-human/',
    target_size=(150, 150),
    batch_size=32,
    class_mode='binary'
)

訓練

history = model.fit(
    train_generator,
    steps_per_epoch=10,
    epochs=10,
    verbose=1
)

調參

構造神經元網絡模型時,

  • 一定會考慮需要幾個卷積層
  • 過濾器應該幾個
  • 全連接層需要幾個神經元

最先想到的肯定是手動修改那些參數,然後觀察訓練的效果(損失和準確度),從而判斷參數的設置是否合理。但是那樣很繁瑣,因爲參數組合會有很多,訓練時間很長。再進一步,可以手動編寫一些循環,通過遍歷來搜索合適的參數。但是最好利用專門的框架來搜索參數,不太容易出錯,效果也比前兩種方法更好。

Kerastuner就是一個可以自動搜索模型訓練參數的庫。它的基本思路是在需要調整參數的地方插入一個特殊的對象(可指定參數範圍),然後調用類似訓練那樣的search方法即可。

接下來首先準備訓練數據和需要加載的庫。

如果沒有這個庫先安裝pip3 install -U keras-tuner,不然會提示錯誤。ModuleNotFoundError: No module named 'kerastuner

import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import RMSprop
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)
train_generator = train_datagen.flow_from_directory('/tmp/horse-or-human/',  
        target_size=(150, 150),batch_size=32,class_mode='binary')
# validation_generator = validation_datagen.flow_from_directory('/tmp/validation-horse-or-human/',  
#         target_size=(150, 150), batch_size=32,class_mode='binary')
from kerastuner.tuners import Hyperband
from kerastuner.engine.hyperparameters import HyperParameters
import tensorflow as tf

接着創建HyperParameters對象,然後在模型中插入Choice、Int等調參用的對象。

hp=HyperParameters()
def build_model(hp):
    model = tf.keras.models.Sequential()        
    model.add(tf.keras.layers.Conv2D(hp.Choice('num_filters_top_layer',values=[16,64],default=16), (3,3), 
                                     activation='relu', input_shape=(150, 150, 3)))
    model.add(tf.keras.layers.MaxPooling2D(2, 2))
    for i in range(hp.Int("num_conv_layers",1,3)):
        model.add(tf.keras.layers.Conv2D(hp.Choice(f'num_filters_layer{i}',values=[16,64],default=16), (3,3), activation='relu'))
        model.add(tf.keras.layers.MaxPooling2D(2,2))
    model.add(tf.keras.layers.Flatten())
    model.add(tf.keras.layers.Dense(hp.Int("hidden_units",128,512,step=32), activation='relu'))
    model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
    model.compile(loss='binary_crossentropy',optimizer=RMSprop(lr=0.001),metrics=['acc'])
    return model

  • 第一個參數Choice是CNN的過濾器,範圍是16~64,最好是32的倍數,默認是16
  • 第二個參數是Int,設置幾個CNN,13個,且每個CNN卷積神經網絡的過濾器個數爲1664,默認16
  • 第三個全連接需要幾個神經元,128~512,步長爲32。即:128、128+32....

他們的第一個參數是name,隨意命名,最好知道且表達出來即可。

然後創建Hyperband對象,這是Kerastuner支持的四種方法的其中一種,可以輕易的限定搜索空間去優化部分參數。具體資料可以到Kerastuner的網站獲取。關於其他三種tuner:RandomSearch、 BayesianOptimization 和 Sklearn

最後調用search方法。

tuner=Hyperband(
    build_model,
    objective='val_acc',
    max_epochs=10,
    directory='horse_human_params',
    hyperparameters=hp,
    project_name='my_horse_human_project'
)
tuner.search(train_generator,epochs=10,validation_data=validation_generator)

搜索到最優參數後,可以通過下面的程序,用tuner對象提取最優參數構建神經元網絡模型。並調用summary方法觀察優化後的網絡結構。

best_hps=tuner.get_best_hyperparameters(1)[0]
print(best_hps.values)
model=tuner.hypermodel.build(best_hps)
model.summary()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章