ImageDataGenerator для многозадачного вывода в Keras с использованием flow_from_directory

Вопрос или проблема

Я создаю многозадачную модель CNN и у меня есть два разных свойства классификации (одно с 10 классами, второе с 5 классами), и моя структура папок выглядит следующим образом:

    -Train
       - image1.jpg
          ...
       - imageN.jpg

    -Test
       - image1.jpg
             ...
       - imageN.jpg

    -Vald
       - image1.jpg
          ...
       - imageN.jpg

И метки находятся в csv файле как propA, propB. Так, одно изображение будет иметь два класса, один из свойства A и один из свойства B.

Модель использует VGG16 :

baseModel = VGG16(weights="imagenet", include_top=False,input_tensor=Input(shape=(img_size, img_size, 3)))
flatLayer = baseModel.output
sharedLayer = Flatten(name="flatten")(flatLayer)
sharedLayer = Dense(1024,name="Shared")(sharedLayer)
sharedLayer = Dropout(0.5)(sharedLayer)
task1 = Dense(512, activation="relu")(sharedLayer)
task1 = Dense(10, activation="softmax",name="PFR")(task1)
task2 = Dense(512, activation="relu")(sharedLayer)
task2 = Dense(5, activation="softmax",name="FT")(task2)
model3 = Model(inputs=baseModel.input, outputs=[task1,task2])

Количество изображений велико, поэтому я не могу загрузить их в память и мне нужно использовать функциональность наподобие flow_from_directory. Но в моей учебной директории нет подкаталогов классов, потому что невозможно создать каталоги классов, так как в общей сложности 15 классов, и я не уверен, для какого свойства создавать подкаталоги классов. (и flow_from_directory не работает, если нет подкаталогов классов)

Метки доступны в массиве, propALab и propBLab.

Пока мне не удалось найти что-то полезное, может кто-нибудь помочь?

Вы пробовали создать собственный генератор данных для вашего случая? Структура для него приведена ниже. Вам понадобится метод __data_generation, такой что вы возвращаете y как массив из 2 элементов, с первым элементом, являющимся вашими метками для задачи 1, и вторым элементом для задачи 2.

import numpy as np
import keras

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'
    def __init__(self, list_IDs, labels, batch_size=32, dim=(32,32,32), n_channels=1,
                 n_classes=10, shuffle=True):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_classes = n_classes
        self.shuffle = shuffle
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        y = np.empty((self.batch_size), dtype=int)

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            X[i,] = np.load('data/' + ID + '.npy')

            # Store class
            y[i] = self.labels[ID]

        return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

Затем вы можете использовать свой собственный генератор с созданной моделью, как показано ниже:
training_generator = DataGenerator(partition[‘train’], labels, **params)
validation_generator = DataGenerator(partition[‘validation’], labels, **params)

# Design model
model = Sequential()
[...] # Architecture
model.compile()

# Train model on dataset
model.fit_generator(generator=training_generator,
                    validation_data=validation_generator,
                    use_multiprocessing=True,
                    workers=6)

Коды были взяты с https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly

.

Ответ или решение

Создание сложной модели с несколькими задачами в Keras, такой как многозадачная CNN с использованием VGG16, часто требует нестандартного подхода, особенно когда мы сталкиваемся с ограничениями, такими как отсутствие подкаталогов классов в директории изображений. Давайте подробно рассмотрим решение этой задачи, задействовав пользовательский генератор данных, который позволит обрабатывать изображения и соответствующие метки напрямую из основного каталога.

Теория

В Keras метод flow_from_directory удобно использовать, когда изображения организованы по подкаталогам, соответствующим классам. Однако в вашей задаче такая структура отсутствует, так как у каждого изображения две независимые классификации. Вместо этого вы можете создать пользовательский генератор данных, который решает эту проблему, извлекая изображения напрямую и соотнося их с метками из заранее подготовленных массивов меток propALab и propBLab.

Пример

Один из способов объединить задачи мультиклассовой классификации — создать наследуемый от keras.utils.Sequence пользовательский генератор данных. Этот генератор позволит загружать изображения по частям, тем самым не загружая всё в оперативную память, и одновременно подготавливать к ним массивы меток для обеих задач. Пример имплементации:

import numpy as np
import keras
from keras.preprocessing import image

class DataGenerator(keras.utils.Sequence):
    'Генератор данных для Keras'
    def __init__(self, list_IDs, labelsA, labelsB, batch_size=32, dim=(224,224), n_channels=3,
                 n_classesA=10, n_classesB=5, shuffle=True):
        self.dim = dim
        self.batch_size = batch_size
        self.labelsA = labelsA
        self.labelsB = labelsB
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_classesA = n_classesA
        self.n_classesB = n_classesB
        self.shuffle = shuffle
        self.on_epoch_end()

    def __len__(self):
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        X, yA, yB = self.__data_generation(list_IDs_temp)
        return X, [yA, yB]

    def on_epoch_end(self):
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        yA = np.empty((self.batch_size), dtype=int)
        yB = np.empty((self.batch_size), dtype=int)

        for i, ID in enumerate(list_IDs_temp):
            img = image.load_img(ID, target_size=self.dim)
            X[i,] = image.img_to_array(img) / 255.0
            yA[i] = self.labelsA[ID]
            yB[i] = self.labelsB[ID]

        return X, keras.utils.to_categorical(yA, num_classes=self.n_classesA), keras.utils.to_categorical(yB, num_classes=self.n_classesB)

Применение

После написания пользовательского генератора, его можно использовать для обучения вашей модели. Внизу представлен пример того, как можно воспользоваться этим генератором с моделью:

train_generator = DataGenerator(list_IDs=train_list, labelsA=propALab_train, labelsB=propBLab_train)
val_generator = DataGenerator(list_IDs=val_list, labelsA=propALab_val, labelsB=propBLab_val)

model3.compile(optimizer='adam', loss=['categorical_crossentropy', 'categorical_crossentropy'], metrics=['accuracy'])

model3.fit(train_generator, validation_data=val_generator, epochs=10, workers=4, use_multiprocessing=True)

Заключение

Создание пользовательского генератора данных — это мощное решение для задач, где структура данных не позволяет использовать стандартные функции Keras. Этот подход не только очищает память, обрабатывая данные партиями, но и позволяет точно настроить обработку данных в соответствии с конкретными требованиями многозадачных моделей.

Оцените материал
Добавить комментарий

Капча загружается...