【问题标题】:Why do my models keep getting exactly 0.5 AUC?为什么我的模型总是精确地得到 0.5 AUC?
【发布时间】:2019-09-21 22:34:07
【问题描述】:

我目前正在做一个项目,我需要在一组图像中预测眼部疾病。我正在使用 Keras 内置应用程序。我在 VGG16 和 VGG19 上取得了不错的成绩,但在 Xception 架构上,我每个时期的 AUC 都保持在 0.5 左右。

我尝试了不同的优化器和学习率,但没有任何效果。我通过从 RMSProp 优化器切换到 Adam 优化器解决了与 VGG19 相同的问题,但我无法让它为 Xception 工作。

   def buildModel():
    from keras.models import Model
    from keras.layers import Dense, Flatten
    from keras.optimizers import adam

    input_model = applications.xception.Xception(
        include_top=False,
        weights='imagenet',
        input_tensor=None,
        input_shape=input_sizes["xception"],
        pooling=None,
        classes=2)

    base_model = input_model

    x = base_model.output
    x = Flatten()(x)
    predictions = Dense(2, activation='softmax')(x)

    model = Model(inputs=base_model.input, outputs=predictions)
    for layer in base_model.layers:
        layer.trainable = False

    model.compile(optimizer=adam(lr=0.01), loss='binary_crossentropy', metrics=['accuracy'])

    return model


class Histories(keras.callbacks.Callback):

    def __init__(self, val_data):
        super(Histories, self).__init__()
        self.x_batch = []
        self.y_batch = []
        for i in range(len(val_data)):
            x, y = val_data.__getitem__(i)
            self.x_batch.extend(x)
            self.y_batch.extend(np.ndarray.astype(y, int))
        self.aucs = []
        self.specificity = []
        self.sensitivity = []
        self.losses = []
        return

    def on_train_begin(self, logs={}):
        initFile("results/xception_results_adam_3.txt")
        return

    def on_train_end(self, logs={}):
        return

    def on_epoch_begin(self, epoch, logs={}):
        return

    def on_epoch_end(self, epoch, logs={}):
        self.losses.append(logs.get('loss'))
        y_pred = self.model.predict(np.asarray(self.x_batch))
        con_mat = confusion_matrix(np.asarray(self.y_batch).argmax(axis=-1), y_pred.argmax(axis=-1))
        tn, fp, fn, tp = con_mat.ravel()
        sens = tp/(tp+fn)
        spec = tn/(tn+fp)
        auc_score = roc_auc_score(np.asarray(self.y_batch).argmax(axis=-1), y_pred.argmax(axis=-1))
        print("Specificity: %f Sensitivity: %f AUC: %f"%(spec, sens, auc_score))
        print(con_mat)
        self.sensitivity.append(sens)
        self.specificity.append(spec)
        self.aucs.append(auc_score)
        writeToFile("results/xception_results_adam_3.txt", epoch, auc_score, spec, sens, self.losses[epoch])
        return


# What follows is data from the Jupyter Notebook that I actually use to evaluate
#%% Initialize data
trainDirectory =      'RetinaMasks/train'
valDirectory =        'RetinaMasks/val'
testDirectory =       'RetinaMasks/test'

train_datagen = ImageDataGenerator(rescale=1. / 255)
test_datagen = ImageDataGenerator(rescale=1. / 255)

train_generator = train_datagen.flow_from_directory(
    trainDirectory,
    target_size=(299, 299),
    batch_size=16,
    class_mode='categorical')

validation_generator = test_datagen.flow_from_directory(
    valDirectory,
    target_size=(299, 299),
    batch_size=16,
    class_mode='categorical')

test_generator = test_datagen.flow_from_directory(
    testDirectory,
    target_size=(299, 299),
    batch_size=16,
    class_mode='categorical')

#%% Create model
model = buildModel("xception")

#%% Initialize metrics
from keras.callbacks import EarlyStopping
from MetricsCallback import Histories
import keras

metrics = Histories(validation_generator)
es = EarlyStopping(monitor='val_loss', 
                   min_delta=0, 
                   patience=20,
                   verbose=0, 
                   mode='auto', 
                   baseline=None, 
                   restore_best_weights=False)

mcp = keras.callbacks.ModelCheckpoint("saved_models/xception.adam.lr0.1_{epoch:02d}.hdf5", 
                                      monitor='val_loss', 
                                      verbose=0, 
                                      save_best_only=False, 
                                      save_weights_only=False, 
                                      mode='auto',
                                      period=1)

#%% Train model
from StaticDataAugmenter import superDirectorySize

history = model.fit_generator(
    train_generator,
    steps_per_epoch=superDirectorySize(trainDirectory) // 16,
    epochs=100,
    validation_data=validation_generator,
    validation_steps=superDirectorySize(valDirectory) // 16,
    callbacks=[metrics, es, mcp],
    workers=8,
    shuffle=False
)

老实说,我不知道是什么导致了这种行为,也不知道如何防止它。提前谢谢你,对于长代码sn-p我深表歉意:)

【问题讨论】:

  • 如果回答解决了您的问题,您可以标记answer as accepted
  • 当你想训练 Xception 时,你真的使用model = load_model("saved_models/vgg16.10.hdf5") 吗?如果这样做,请删除该行。
  • @Natthapon Honcharoen 不,这是我的错误。

标签: python keras scikit-learn auc


【解决方案1】:

您的学习率太大。 尝试降低学习率。

我也遇到过类似的情况,这发生在迁移学习中。在二进制分类的情况下,多个 epoch 的扩展 AUC 为 0.5 意味着您的卷积神经网络没有学习任何东西。

使用 0.0001,0.00001,0.000001 的 learning_rates。

同时,您应该尝试解冻/使某些层可训练,因为您的整个特征提取器都被冻结了;事实上,这可能是网络无法学习任何东西的另一个原因。

如果你降低学习率,我很有信心你的问题会得到解决:)。

【讨论】:

  • 不幸的是,这根本没有帮助。
【解决方案2】:

AUC 为 0.5 意味着您的网络随机猜测输出,这意味着它没有学到任何东西。这已经讨论过了,例如here

正如 Timbus Calin 建议的那样,您可以从 0.000001 开始对学习率进行“线性搜索”,然后将学习率提高 10 倍。

我建议您直接从随机搜索开始,您不仅尝试优化学习率,还尝试优化其他超参数,例如批量大小。在paper 中阅读有关随机搜索的更多信息。

【讨论】:

    【解决方案3】:

    你没有正确计算 AUC,你目前有这个:

    auc_score = roc_auc_score(np.asarray(self.y_batch).argmax(axis=-1), y_pred.argmax(axis=-1))
    

    AUC 是根据模型产生的(概率)分数计算得出的。模型输出的 argmax 不提供分数,而是提供类标签。正确的函数调用是:

    auc_score = roc_auc_score(np.asarray(self.y_batch).argmax(axis=-1), y_pred[:, 1])
    

    请注意,计算 ROC 所需的分数是正类的概率,它是 softmax 输出的第二个元素。这就是为什么只使用预测的第二列来制作 AUC。

    【讨论】:

      【解决方案4】:

      这个怎么样?

         def buildModel():
          from keras.models import Model
          from keras.layers import Dense, Flatten
          from keras.optimizers import adam
      
          input_model = applications.xception.Xception(
              include_top=False,
              weights='imagenet',
              input_tensor=None,
              input_shape=input_sizes["xception"],
              pooling='avg',  # 1
              classes=2)
      
          base_model = input_model
      
          x = base_model.output
          # x = Flatten()(x)  # 2
          predictions = Dense(2, activation='softmax')(x)
      
          model = Model(inputs=base_model.input, outputs=predictions)
          for layer in base_model.layers:
              layer.trainable = False
      
          model.compile(optimizer=adam(lr=0.01), 
                        loss='categorical_crossentropy',  # 3
                        metrics=['accuracy'])
      
          return model
      
      
      class Histories(keras.callbacks.Callback):
      
          def __init__(self, val_data):
              super(Histories, self).__init__()
              self.x_batch = []
              self.y_batch = []
              for i in range(len(val_data)):
                  x, y = val_data.__getitem__(i)
                  self.x_batch.extend(x)
                  self.y_batch.extend(np.ndarray.astype(y, int))
              self.aucs = []
              self.specificity = []
              self.sensitivity = []
              self.losses = []
              return
      
          def on_train_begin(self, logs={}):
              initFile("results/xception_results_adam_3.txt")
              return
      
          def on_train_end(self, logs={}):
              return
      
          def on_epoch_begin(self, epoch, logs={}):
              return
      
          def on_epoch_end(self, epoch, logs={}):
              self.losses.append(logs.get('loss'))
              y_pred = self.model.predict(np.asarray(self.x_batch))
              con_mat = confusion_matrix(np.asarray(self.y_batch).argmax(axis=-1), y_pred.argmax(axis=-1))
              tn, fp, fn, tp = con_mat.ravel()
              sens = tp/(tp+fn)
              spec = tn/(tn+fp)
              auc_score = roc_auc_score(np.asarray(self.y_batch).argmax(axis=-1), y_pred.argmax(axis=-1))
              print("Specificity: %f Sensitivity: %f AUC: %f"%(spec, sens, auc_score))
              print(con_mat)
              self.sensitivity.append(sens)
              self.specificity.append(spec)
              self.aucs.append(auc_score)
              writeToFile("results/xception_results_adam_3.txt", epoch, auc_score, spec, sens, self.losses[epoch])
              return
      
      
      # What follows is data from the Jupyter Notebook that I actually use to evaluate
      #%% Initialize data
      trainDirectory =      'RetinaMasks/train'
      valDirectory =        'RetinaMasks/val'
      testDirectory =       'RetinaMasks/test'
      
      train_datagen = ImageDataGenerator(rescale=1. / 255)
      test_datagen = ImageDataGenerator(rescale=1. / 255)
      
      train_generator = train_datagen.flow_from_directory(
          trainDirectory,
          target_size=(299, 299),
          batch_size=16,
          class_mode='categorical')
      
      validation_generator = test_datagen.flow_from_directory(
          valDirectory,
          target_size=(299, 299),
          batch_size=16,
          class_mode='categorical')
      
      test_generator = test_datagen.flow_from_directory(
          testDirectory,
          target_size=(299, 299),
          batch_size=16,
          class_mode='categorical')
      
      #%% Create model
      model = buildModel("xception")
      
      #%% Initialize metrics
      from keras.callbacks import EarlyStopping
      from MetricsCallback import Histories
      import keras
      
      metrics = Histories(validation_generator)
      es = EarlyStopping(monitor='val_loss', 
                         min_delta=0, 
                         patience=20,
                         verbose=0, 
                         mode='auto', 
                         baseline=None, 
                         restore_best_weights=False)
      
      mcp = keras.callbacks.ModelCheckpoint("saved_models/xception.adam.lr0.1_{epoch:02d}.hdf5", 
                                            monitor='val_loss', 
                                            verbose=0, 
                                            save_best_only=False, 
                                            save_weights_only=False, 
                                            mode='auto',
                                            period=1)
      
      
      #%% Load saved model
      from keras.models import load_model
      # model = load_model("saved_models/vgg16.10.hdf5")  # 4
      
      #%% Train model
      from StaticDataAugmenter import superDirectorySize
      
      history = model.fit_generator(
          train_generator,
          steps_per_epoch=superDirectorySize(trainDirectory) // 16,
          epochs=100,
          validation_data=validation_generator,
          validation_steps=superDirectorySize(valDirectory) // 16,
          callbacks=[metrics, es, mcp],
          workers=8,
          shuffle=False
      )
      
      

      对于 1 和 2,我认为在 ReLU 之后不使用池化层就使用 FC 层是没有意义的,永远不要尝试,所以它可能没有任何帮助。

      对于 3,当您的生成器使用 class_mode='categorical' 时,您为什么要使用 BCE?

      对于 4,正如我在上面评论的那样,这意味着您正在加载 VGG 模型并对其进行训练,而不是使用来自 buildModel() 的 Xception。

      【讨论】:

        猜你喜欢
        • 2019-06-01
        • 2020-12-30
        • 2018-05-14
        • 2021-03-18
        • 2021-07-03
        • 1970-01-01
        • 1970-01-01
        • 2014-01-20
        • 1970-01-01
        相关资源
        最近更新 更多