Neural network 为什么我的CIFAR 100 CNN模型主要预测两类?

Neural network 为什么我的CIFAR 100 CNN模型主要预测两类?,neural-network,computer-vision,keras,Neural Network,Computer Vision,Keras,我目前正试图在CIFAR 100上获得Keras的良好分数(>40%的准确率)。然而,我正在经历一个CNN模型的奇怪行为:它倾向于预测某些类(2-5)比其他类更频繁: 位置(i,j)处的像素包含来自类i的验证集的元素预测为类j的计数。因此,对角线包含正确的分类,其他一切都是错误的。两条竖线表明该模型通常预测这些类别,尽管事实并非如此 CIFAR 100完全平衡:所有100个课程都有500个训练样本 为什么该模型倾向于预测某些类别比其他类别更频繁?如何解决这个问题 代码 运行这个需要一段时间 #

我目前正试图在CIFAR 100上获得Keras的良好分数(>40%的准确率)。然而,我正在经历一个CNN模型的奇怪行为:它倾向于预测某些类(2-5)比其他类更频繁:

位置(i,j)处的像素包含来自类i的验证集的元素预测为类j的计数。因此,对角线包含正确的分类,其他一切都是错误的。两条竖线表明该模型通常预测这些类别,尽管事实并非如此

CIFAR 100完全平衡:所有100个课程都有500个训练样本

为什么该模型倾向于预测某些类别比其他类别更频繁?如何解决这个问题

代码 运行这个需要一段时间

#!/usr/bin/env python

from __future__ import print_function
from keras.datasets import cifar100
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
from sklearn.model_selection import train_test_split
import numpy as np

batch_size = 32
nb_classes = 100
nb_epoch = 50
data_augmentation = True

# input image dimensions
img_rows, img_cols = 32, 32
# The CIFAR10 images are RGB.
img_channels = 3

# The data, shuffled and split between train and test sets:
(X, y), (X_test, y_test) = cifar100.load_data()
X_train, X_val, y_train, y_val = train_test_split(X, y,
                                                  test_size=0.20,
                                                  random_state=42)

# Shuffle training data
perm = np.arange(len(X_train))
np.random.shuffle(perm)
X_train = X_train[perm]
y_train = y_train[perm]

print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_val.shape[0], 'validation samples')
print(X_test.shape[0], 'test samples')

# Convert class vectors to binary class matrices.
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
Y_val = np_utils.to_categorical(y_val, nb_classes)

model = Sequential()

model.add(Convolution2D(32, 3, 3, border_mode='same',
                        input_shape=X_train.shape[1:]))
model.add(Activation('relu'))
model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('tanh'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))

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

X_train = X_train.astype('float32')
X_val = X_val.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_val /= 255
X_test /= 255

if not data_augmentation:
    print('Not using data augmentation.')
    model.fit(X_train, Y_train,
              batch_size=batch_size,
              nb_epoch=nb_epoch,
              validation_data=(X_val, y_val),
              shuffle=True)
else:
    print('Using real-time data augmentation.')
    # This will do preprocessing and realtime data augmentation:
    datagen = ImageDataGenerator(
        featurewise_center=False,  # set input mean to 0 over the dataset
        samplewise_center=False,  # set each sample mean to 0
        featurewise_std_normalization=False,  # divide inputs by std of the dataset
        samplewise_std_normalization=False,  # divide each input by its std
        zca_whitening=False,  # apply ZCA whitening
        rotation_range=0,  # randomly rotate images in the range (degrees, 0 to 180)
        width_shift_range=0.1,  # randomly shift images horizontally (fraction of total width)
        height_shift_range=0.1,  # randomly shift images vertically (fraction of total height)
        horizontal_flip=True,  # randomly flip images
        vertical_flip=False)  # randomly flip images

    # Compute quantities required for featurewise normalization
    # (std, mean, and principal components if ZCA whitening is applied).
    datagen.fit(X_train)

    # Fit the model on the batches generated by datagen.flow().
    model.fit_generator(datagen.flow(X_train, Y_train,
                                     batch_size=batch_size),
                        samples_per_epoch=X_train.shape[0],
                        nb_epoch=nb_epoch,
                        validation_data=(X_val, Y_val))
    model.save('cifar100.h5')
可视化代码 红鲱鱼 谭 我已将
tanh
替换为
relu
。外观正常,但可视化存在相同的问题:

还请注意,此处的验证准确率仅为3.44%

辍学+正切+边界模式 删除辍学,用relu替换tanh,将边界模式设置为处处相同:

可视化代码的准确率(这次为8.50%)仍然比keras训练代码低得多

问答 以下是评论的摘要:

  • 数据均匀地分布在各个类上。因此,这两个班没有“过度训练”
  • 使用了数据扩充,但如果没有数据扩充,问题仍然存在
  • 可视化不是问题所在

    • 我对这部分代码感觉不好:

      model.add(Dense(1024))
      model.add(Activation('tanh'))
      model.add(Dropout(0.5))
      model.add(Dense(nb_classes))
      model.add(Activation('softmax'))
      
      剩下的模型充满了
      relus
      ,但这里有一个
      tanh

      tanh
      有时会消失或爆炸(饱和为-1和1),这可能会导致你的2级课程过于重要


      基本上使用相同的体系结构(密集层大小可能不同),但也在那里使用
      relu
      (根本没有tanh)。这同样适用于。

      我对这部分代码感觉不好:

      model.add(Dense(1024))
      model.add(Activation('tanh'))
      model.add(Dropout(0.5))
      model.add(Dense(nb_classes))
      model.add(Activation('softmax'))
      
      剩下的模型充满了
      relus
      ,但这里有一个
      tanh

      tanh
      有时会消失或爆炸(饱和为-1和1),这可能会导致你的2级课程过于重要

      基本上使用相同的体系结构(密集层大小可能不同),但也在那里使用
      relu
      (根本没有tanh)。同样的情况也会发生

    • 即使在datagen中,我也看不出你在做什么。我怀疑这是主要原因。要使用
      ImageDataGenerator
      进行居中,请将
      featurewise\u center=1
      。另一种方法是从每个RGB像素中减去ImageNet平均值。要减去的平均向量是
      [103.939116.779123.68]

    • 进行所有激活
      relu
      s,除非您有特定的理由使用单个
      tanh

    • 删除两个0.25的辍学,看看会发生什么。如果要将退出应用于卷积层,最好使用
      SpatialDropout2D
      。它以某种方式从Keras在线文档中删除,但您可以在中找到它

    • 您有两个
      conv
      层具有
      same
      和两个
      valid
      。这并没有什么错,但更简单的方法是保持所有
      conv
      层的
      相同
      ,并根据最大池数控制大小

    • 即使在datagen中,我也看不出你在做什么。我怀疑这是主要原因。要使用
      ImageDataGenerator
      进行居中,请将
      featurewise\u center=1
      。另一种方法是从每个RGB像素中减去ImageNet平均值。要减去的平均向量是
      [103.939116.779123.68]

    • 进行所有激活
      relu
      s,除非您有特定的理由使用单个
      tanh

    • 删除两个0.25的辍学,看看会发生什么。如果要将退出应用于卷积层,最好使用
      SpatialDropout2D
      。它以某种方式从Keras在线文档中删除,但您可以在中找到它

    • 您有两个
      conv
      层具有
      same
      和两个
      valid
      。这并没有什么错,但更简单的方法是保持所有
      conv
      层的
      相同
      ,并根据最大池数控制大小


    • 问题的一个重要部分是我的
      ~/.keras/keras.json

      {
          "image_dim_ordering": "th",
          "epsilon": 1e-07,
          "floatx": "float32",
          "backend": "tensorflow"
      }
      
      因此,我不得不将
      image\u dim\u排序
      更改为
      tf
      。这导致了


      准确率为12.73%。显然,仍然存在一个问题,因为我的
      ~/.keras/keras.json
      给出了45.1%的准确率

      {
          "image_dim_ordering": "th",
          "epsilon": 1e-07,
          "floatx": "float32",
          "backend": "tensorflow"
      }
      
      因此,我不得不将
      image\u dim\u排序
      更改为
      tf
      。这导致了


      准确率为12.73%。显然,仍然存在一个问题,因为数据集的准确率为45.1%。

      如果您在培训和验证期间获得了很好的准确率,但在测试时没有,请确保在这两种情况下对数据集执行完全相同的预处理。 这是您在培训时获得的:

      X_train /= 255
      X_val /= 255
      X_test /= 255
      
      但在预测混淆矩阵时,没有这样的代码。添加到测试中:

      X_val /=  255.
      
      给出了以下美观的混淆矩阵:


      如果您在培训和验证过程中获得了很好的准确性,但在测试时没有,请确保在这两种情况下对数据集执行完全相同的预处理。 这是您在培训时获得的:

      X_train /= 255
      X_val /= 255
      X_test /= 255
      
      但在预测混淆矩阵时,没有这样的代码。添加到测试中:

      X_val /=  255.
      
      给出了以下美观的混淆矩阵:


      这是一个红色的赫林。Tanh不是问题所在。至少不是tanh一个人。查看我的更新答案。这是一个红色的hering。Tanh不是问题所在。至少没有晒黑