#python #tensorflow #keras #conv-neural-network #image-classification
Вопрос:
я изучаю tensorflow/keras для классификации изображений, и мне кажется, что я упускаю важную часть теории.
задача, над которой я в настоящее время работаю, связана с использованием предварительно подготовленной модели (в данном случае Resnet50) для классификации на небольшом наборе данных с ограниченным временем обучения.
набор данных составляет 1600 150 х 150 цветных фотографий фруктов, которые делятся на 12 классов. я использую генератор для изображений:
datagen = ImageDataGenerator(
validation_split=0.25,
rescale=1/255,
horizontal_flip=True,
vertical_flip=True,
width_shift_range=0.2,
height_shift_range=0.2,
rotation_range=90)
train_datagen_flow = datagen.flow_from_directory(
'/datasets/fruits_small/',
target_size=(150, 150),
batch_size=32,
class_mode='sparse',
subset='training',
seed=12345)
val_datagen_flow = datagen.flow_from_directory(
'/datasets/fruits_small/',
target_size=(150, 150),
batch_size=32,
class_mode='sparse',
subset='validation',
seed=12345)
features, target = next(train_datagen_flow)
вот слои, которые я использую:
магистраль = ResNet50(input_shape=(150, 150, 3),веса=’imagenet’, include_top=False) магистраль.обучаемый = False
model = Sequential()
optimizer = Adam(lr=0.001)
model.add(backbone)
model.add(GlobalMaxPooling2D())
model.add(Dense(2048,activation='relu'))
model.add(BatchNormalization())
model.add(Dense(512,activation = 'relu'))
model.add(BatchNormalization())
model.add(Dense(12, activation='softmax'))
model.compile(optimizer = optimizer, loss='sparse_categorical_crossentropy',metrics=['acc'])
Теперь это моя первая попытка использовать globalmax и resnet50, и я испытываю ОГРОМНОЕ переоснащение, потому что, я полагаю, небольшой набор данных.
я немного почитал на эту тему и предпринял несколько попыток нормализации с ограниченным успехом.
в разговоре с моим наставником он предложил мне более критически подумать о результатах модели resnet при выборе параметров для моих плотных слоев.
этот комментарий заставил меня понять, что я в основном произвольно выбирал фильтры для плотных слоев, но, похоже, я должен понимать что-то, связанное с выводом предыдущего слоя при создании нового, и я не уверен, что именно, но я чувствую, что упускаю что-то важное.
вот как выглядит мое текущее резюме слоя:
Model: "sequential_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
resnet50 (Model) (None, 5, 5, 2048) 23587712
_________________________________________________________________
global_max_pooling2d_3 (Glob (None, 2048) 0
_________________________________________________________________
dense_7 (Dense) (None, 2048) 4196352
_________________________________________________________________
batch_normalization_2 (Batch (None, 2048) 8192
_________________________________________________________________
dense_8 (Dense) (None, 512) 1049088
_________________________________________________________________
batch_normalization_3 (Batch (None, 512) 2048
_________________________________________________________________
dense_9 (Dense) (None, 12) 6156
=================================================================
Total params: 28,849,548
Trainable params: 5,256,716
Non-trainable params: 23,592,832
вот как выглядит мой текущий результат:
Epoch 1/3
40/40 [==============================] - 363s 9s/step - loss: 0.5553 - acc: 0.8373 - val_loss: 3.8422 - val_acc: 0.1295
Epoch 2/3
40/40 [==============================] - 354s 9s/step - loss: 0.1621 - acc: 0.9423 - val_loss: 6.3961 - val_acc: 0.1295
Epoch 3/3
40/40 [==============================] - 357s 9s/step - loss: 0.1028 - acc: 0.9716 - val_loss: 4.8895 - val_acc: 0.1295
поэтому я читал о замораживании слоев resnet для обучения, чтобы помочь с подгонкой и регуляризацией (что я пытаюсь сделать с помощью пакетной нормализации? — хотя это, кажется, многим людям кажется сомнительным..) я также пробовал использовать отсев для первого и второго плотных слоев, а также путем увеличения размера набора данных с увеличением (у меня есть ротации и тому подобное)
Любой вклад будет оценен по достоинству!
Комментарии:
1. Может быть, это имеет какое-то отношение к
class_mode='sparse',
переданномуdatagen.flow_from_directory
. Выход модели-это softmax, верно? Мне кажется, что это соответствует лучшеclass_mode='"categorical"
.2. Хорошее наблюдение, я могу это попробовать! 🙂
3. Оказывается, категоричность делает OHE, и это очень быстро выходит из-под контроля ресурсов и убивает ядро (похоже, так или иначе)
4. Да, в документах действительно написано «По умолчанию: «категорично». Определяет тип возвращаемых массивов меток: — «категориальными» будут 2D однократно закодированные метки». Поправьте меня, если я ошибаюсь, но softmax-это приближение OHE, верно? Не уверен, что вы имеете в виду, говоря о выходе из-под контроля ресурсов, но, возможно, вам захочется уменьшить свои плотные слои. Я думаю, что 5 м обучаемых параметров-это довольно много для начала. Что произойдет, если вы разрежете оба слоя пополам?
5. @GillesOttervanger ядро умирает-это то, что я имел в виду под ресурсами. для этого я использую онлайн-платформу (это курс, который я прохожу). Тем не менее, ваши предложения о разделении слоев пополам были великолепны — я неправильно понял и подумал, что мне нужно иметь нейрон для каждого вывода из сети resnet, но, перейдя с 256, затем с 64 на последний слой из 12, производительность значительно улучшилась
Ответ №1:
Итак, я обнаружил, что у меня было неправильное представление о форме вывода из слоя resnet/global average — он имел форму 2048, и я думал, что это означает, что мне нужно, чтобы мой первый плотный слой имел 2048 фильтров, что вызывало значительные проблемы с подгонкой.
в конечном счете я изменил свои плотные слои на 256, затем на 64 и, наконец, на 12 (потому что у меня есть 12 классов для классификации), и это значительно повысило производительность.