簡體   English   中英

Keras fit_generator() 沒有正確訓練

[英]Keras fit_generator() doesn't train properly

我正在嘗試使用 Keras 和 TensorFlow 2.0.0 后端創建圖像分類器。

我在我的本地機器上訓練這個 model 的自定義數據集,其中包含總共 17~ 千張圖像。 這些圖像大小不一,位於三個不同的文件夾(訓練、驗證和測試)中,每個文件夾包含兩個子文件夾(每個類別一個)。 我嘗試了一個類似於 VGG16 的架構,過去在這個數據集上產生了非常好的結果。 請注意,數據中存在輕微的 class 不平衡 (52:48)

當我調用fit_generator()時,model 訓練不好; 盡管在第一個 epoch 中訓練損失略有下降,但之后變化不大。 使用這種具有更高規則的架構,我在過去 55~ epochs 后達到了 85% 的准確率。

導入和超參數

import tensorflow as tf
from tensorflow import keras
from keras import backend as k
from keras.layers import Dense, Dropout, Conv2D, MaxPooling2D, Flatten, Input, UpSampling2D
from keras.models import Sequential, Model, load_model
from keras.utils import to_categorical
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ModelCheckpoint

TRAIN_PATH = 'data/train/'
VALID_PATH = 'data/validation/'
TEST_PATH = 'data/test/'
TARGET_SIZE = (256, 256)
RESCALE = 1.0 / 255
COLOR_MODE = 'grayscale'
EPOCHS = 2
BATCH_SIZE = 16
CLASSES = ['Damselflies', 'Dragonflies']
CLASS_MODE = 'categorical'
CHECKPOINT = "checkpoints/weights.hdf5"

Model

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu',
                 input_shape=(256, 256, 1), padding='same'))

model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.1))

model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.1))

model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.1))

model.add(Flatten())
model.add(Dense(516, activation='relu'))
model.add(Dropout(0.1))

model.add(Dense(128, activation='relu'))
model.add(Dropout(0.1))

model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='Adam', metrics=['accuracy'])

過去,我創建了一個自定義管道來對圖像進行整形、灰度、翻轉和標准化; 然后,我使用我的 CPU 在批量處理的圖像上訓練了 model。

我嘗試使用 ImageDataGenerator、flow_from_directory 和 GPU 支持重復該過程。

# randomly flip images, and scale pixel values
trainGenerator = ImageDataGenerator(rescale=RESCALE, 
                                    horizontal_flip=True,  
                                    vertical_flip=True)

# only scale the pixel values validation images
validatioinGenerator = ImageDataGenerator(rescale=RESCALE)

# only scale the pixel values test images
testGenerator = ImageDataGenerator(rescale=RESCALE)

# instanciate train flow
trainFlow = trainGenerator.flow_from_directory(
    TRAIN_PATH,
    target_size = TARGET_SIZE,
    batch_size = BATCH_SIZE,
    classes = CLASSES,
    color_mode = COLOR_MODE,
    class_mode = CLASS_MODE,
    shuffle=True
) 

# instanciate validation flow
validationFlow = validatioinGenerator.flow_from_directory(
    VALID_PATH,
    target_size = TARGET_SIZE,
    batch_size = BATCH_SIZE,
    classes = CLASSES,
    color_mode = COLOR_MODE,
    class_mode= CLASS_MODE,
    shuffle=True
)

然后,使用 fit_generator 擬合 model。

checkpoints = ModelCheckpoint(CHECKPOINT, monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')

with tf.device('/GPU:0'):
    model.fit_generator(
        trainFlow,
        validation_data=validationFlow, 
        callbacks=[checkpoints],
        epochs=EPOCHS
    )

我嘗試訓練它 40 個 epoch。 分類器在第一個 epoch 后達到 52%,並且隨着時間的推移沒有提高。

測試分類器

testFlow = testGenerator.flow_from_directory(
    TEST_PATH,
    target_size = TARGET_SIZE,
    batch_size = BATCH_SIZE,
    classes = CLASSES,
    color_mode = COLOR_MODE,
    class_mode= CLASS_MODE,
)

ans = model.predict_generator(testFlow)

當我查看預測時,model 將所有測試圖像預測為大多數 class 具有相同的置信度[0.48498476, 0.51501524]

我確定數據是正確的嗎?

是的。 我測試了生成器是否正確生成處理后的圖像及其相應的標簽。

我是否嘗試過更改損失 function、激活 function 和優化器?

是的。 我嘗試將 class 模式更改為二進制,將損失更改為 binary_crossentropy,並更改最后一層以生成具有 sigmoid 激活的單個 output。 不,我沒有更改優化器。 但是,我確實嘗試提高學習率。

我是否嘗試過更改模型的架構?

是的。 我嘗試增加和減少 model 復雜性。 具有較少正則化的更多層和具有更多正則化的更少層都產生了相似的結果。

這些層是可訓練的嗎?

是的。

GPU 支持是否正確實施?

但願如此。

print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU')))

可用 GPU 數量:1

a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a') 
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b') 
c = tf.matmul(a, b)

config = tf.compat.v1.ConfigProto(log_device_placement=True) 
config.gpu_options.allow_growth = True 
sess = tf.compat.v1.Session(config=config)
print(sess) 

設備映射:/job:localhost/replica:0/task:0/device:GPU:0 -> 設備:0,名稱:NVIDIA GeForce GTX 1050 with Max-Q Design,pci 總線 ID:0000:03:00.0,計算能力:6.1

<tensorflow.python.client.session.Session object at 0x000001F9443E2CC0>

我是否嘗試過遷移學習?

還沒有。

我從 2017 年的 keras-doesnt-train-using-fit-generator中發現了一個類似的未回答問題。

想法?

問題出在您的 model 上。 我復制了你的代碼並在我以前使用過的數據集上運行它(它得到了很高的准確性),得到的結果與你的相似。 然后我替換了下面的簡單 model

model = tf.keras.Sequential([
    Conv2D(16, 3, padding='same', activation='relu', input_shape=(256 , 256,1)),
    MaxPooling2D(),
    Conv2D(32, 3, padding='same', activation='relu' ),
    MaxPooling2D(),
    Conv2D(64, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(128, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(256, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Flatten(),
    Dense(128, activation='relu'),
    Dropout(.3),
    Dense(64, activation='relu'),
    Dropout(.3),
    Dense(2, activation='softmax')
])
model.compile(loss='categorical_crossentropy',
              optimizer='Adam', metrics=['accuracy'])

model 訓練得當。 順便說一句 model.fit_generator 已折舊。 您現在可以只使用 model.fit 現在可以處理生成器。 然后我拿走了你的 model 並刪除了除最后一層之外的所有輟學層,並且你的 model 訓練有素。 代碼是:

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu',
                 input_shape=(256, 256, 1), padding='same'))

model.add(Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
#model.add(Dropout(0.1))

model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
#model.add(Dropout(0.1))

model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
#model.add(Dropout(0.1))

model.add(Flatten())
model.add(Dense(516, activation='relu'))
#model.add(Dropout(0.1))

model.add(Dense(128, activation='relu'))
model.add(Dropout(0.1))

model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy',
              optimizer='Adam', metrics=['accuracy'])

@格里P,

偶然,我發現了導致錯誤的原因。 from Keras import backend as k中移除解決了模型無法學習的問題。

那不是全部。 我還發現您定義的 model、未調用 ModelCheckpoint 和未自定義 class 名稱影響了擬合過程。

model = Sequential([
    Conv2D(16, 3, padding='same', activation='relu', input_shape=(256 , 256, 1)),
    MaxPooling2D(),
    Conv2D(32, 3, padding='same', activation='relu' ),
    MaxPooling2D(),
    Conv2D(64, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(128, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(256, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Flatten(),
    Dense(128, activation='relu'),
    Dropout(.3),
    Dense(64, activation='relu'),
    Dropout(.3),
    Dense(2, activation='softmax')
])

我評論了導入以嘗試解決在我復制粘貼您的順序 model 時發生的錯誤。 然后,我在測試漂亮或平均數據集時忘記取消注釋它。 在第三個 epoch 之后,我達到了 80% 以上的准確率。 然后,我恢復了更改並在我的數據集上進行了嘗試,但它再次失敗了。 作為獎勵,不導入 Keras 的后端減少了訓練模型所需的時間!

最近,我不得不重新安裝 Keras 和 TensorFlow 因為他們再也檢測不到我的 GPU。 我可能犯了一個錯誤,安裝了不兼容的 Keras 版本。

CUDA==10.0
tensorflow-gpu==2.0.0
keras==2.3.1

請注意,它仍然不是 100% 的解決方案,而且問題經常出現。

編輯:

每當它不起作用時,簡化 model。 更改批量大小並停止學習? 簡化 model。 進一步增強圖像並停止學習? 簡化 model。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM