Невозможно объяснить модели поведения в трансферном обучении - PullRequest
0 голосов
/ 31 марта 2020

У меня очень маленький набор данных изображений (747 изображений для тренировок и 250 для тестирования, когда размеры изображений уменьшены до 256 x 256). Задача - классификация по нескольким меткам (между двумя инфекциями, которые возможны вместе, но в моих данных об обучении такой ситуации нет).

Поскольку мой набор данных очень мал, я решил использовать трансферное обучение с использованием VGG16. и Начало V3. Когда я тренирую VGG16, все следует теории, например, потери при обучении и потери при проверке продолжают уменьшаться и не сильно отличаются друг от друга, как показано на рисунке 1

VGG16: batch_size=32, learning_rate=0.00001

Когда я тренирую InceptionV3, кажется, что модель переоснащена, но я не уверен в этом, потому что потери при обучении составляют около 0,6, тогда как потери при проверке в 10 раз превышают потери при обучении, как показано на рисунке 2

InceptionV3: batch_size=8, learning_rate=0.00001

В обе модели были добавлены 3 плотных слоя. Я приложил код для справки. Я не смог найти объяснения, почему модель намного большего размера (VGG) не подходит для этого набора данных, а InceptionV3. Могу ли я предложить, что пошло не так с InceptionV3?

def xvgg16(self, height, width, depth, num_class, hparams):
        """
        This function defines transfer learning for vgg16

        Parameters
        ----------
        height : Integer
            Image height (pixel)
        width : Integer
            Image width (pixel)
        depth : Integer
            Image channel
        num_class : Integer
            Number of class labels
        hparams: Dictionary
            Hyperparameters

        Returns
        -------
        model : Keras model object
            The transfer model

        """
        input_tensor = Input(shape=(height, width, depth))
        pretrain = VGG16(weights="imagenet", include_top=False, input_tensor=input_tensor)

        conv1_1 = pretrain.layers[1]
        conv1_2 = pretrain.layers[2]
        pool1 = pretrain.layers[3]
        conv2_1 = pretrain.layers[4]
        conv2_2 = pretrain.layers[5]
        pool2 = pretrain.layers[6]
        conv3_1 = pretrain.layers[7]
        conv3_2 = pretrain.layers[8]
        conv3_3 = pretrain.layers[9]
        pool3 = pretrain.layers[10]
        conv4_1 = pretrain.layers[11]
        conv4_2 = pretrain.layers[12]
        conv4_3 = pretrain.layers[13]
        pool4 = pretrain.layers[14]
        conv5_1 = pretrain.layers[15]
        conv5_2 = pretrain.layers[16]
        conv5_3 = pretrain.layers[17]
        pool5 = pretrain.layers[18]

        x = BatchNormalization(axis=-1)(conv1_1.output)
        x = conv1_2(x)
        x = BatchNormalization(axis=-1)(x)
        x = pool1(x)
        x = conv2_1(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv2_2(x)
        x = BatchNormalization(axis=-1)(x)
        x = pool2(x)
        x = conv3_1(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv3_2(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv3_3(x)
        x = BatchNormalization(axis=-1)(x)
        x = pool3(x)
        x = conv4_1(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv4_2(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv4_3(x)
        x = BatchNormalization(axis=-1)(x)
        x = pool4(x)
        x = conv5_1(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv5_2(x)
        x = BatchNormalization(axis=-1)(x)
        x = conv5_3(x)
        x = BatchNormalization(axis=-1)(x)
        x = pool5(x)

        x = Flatten()(x)
        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(num_class)(x)
        x = Activation("sigmoid")(x)

        model = Model(inputs=pretrain.layers[0].input, outputs=x)

        for layer in model.layers:
            if "conv" in layer.name:
                layer.trainable = False    

        model.compile(loss="binary_crossentropy", optimizer=Adam(lr=hparams["learning_rate"]), metrics=["binary_accuracy"])

        return model

def inception3(self, height, width, depth, num_class, hparams):
        """
        This function defines transfer learning for densenet

        Parameters
        ----------
        height : Integer
            Image height (pixel)
        width : Integer
            Image width (pixel)
        depth : Integer
            Image channel
        num_class : Integer
            Number of class labels
        hparams: Dictionary
            Hyperparameters

        Returns
        -------
        model : Keras model object
            The transfer model
        """
        input_tensor = Input(shape=(height, width, depth))
        pretrain = InceptionV3(weights="imagenet", include_top=False, input_tensor=input_tensor)

        x = pretrain.output
        x = GlobalAveragePooling2D()(x)

        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(64, use_bias=False)(x)
        x = Dropout(0.25)(x)
        x = BatchNormalization(axis=-1)(x)
        x = Activation("relu")(x)

        x = Dense(num_class)(x)
        x = Activation("sigmoid")(x)

        model = Model(inputs=pretrain.input, outputs=x)

        for layer in pretrain.layers:
            layer.trainable = False

        model.compile(loss="binary_crossentropy", optimizer=Adam(lr=hparams["learning_rate"]), metrics=["binary_accuracy"])

        return model

1 Ответ

0 голосов
/ 31 марта 2020

Вы должны знать, что модели VGG и Inception в Keras проходят предварительную подготовку с использованием imagenet, но с другой функцией предварительной обработки.

В то время как VGG предварительно обрабатывает изображения, чтобы иметь значения пикселей в диапазон (0, 255), Inception_v3 предварительно обрабатывает их, чтобы иметь значения пикселей в диапазоне (-1, 1)

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

from keras.applications.vgg16 import preprocess_input
X_train = ... # read your training images
X_train = preprocess_input(X_train)
print(X_train.max(), X_train.min(), X_train.mean())

Вы увидите, что максимальное, минимальное и среднее значения пикселей находятся в диапазоне (0, 255)

Для Inception_v3 вы должны выполнить следующую процедуру:

from keras.applications.inception_v3 import preprocess_input
X_train = ... # read your training images
X_train = preprocess_input(X_train)
print(X_train.max(), X_train.min(), X_train.mean())

Здесь значения будет между -1 и 1

В вашем текущем коде VGG работает вполне нормально, потому что ваши изображения имеют пиксели в диапазоне от 0 до 255, как ожидается моделью VGG, но не работают для Inception V3 потому что он ожидает их в диапазоне -1 и 1.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...