Neural network 为什么我的CIFAR 100 CNN模型主要预测两类?
我目前正试图在CIFAR 100上获得Keras的良好分数(>40%的准确率)。然而,我正在经历一个CNN模型的奇怪行为:它倾向于预测某些类(2-5)比其他类更频繁: 位置(i,j)处的像素包含来自类i的验证集的元素预测为类j的计数。因此,对角线包含正确的分类,其他一切都是错误的。两条竖线表明该模型通常预测这些类别,尽管事实并非如此 CIFAR 100完全平衡:所有100个课程都有500个训练样本 为什么该模型倾向于预测某些类别比其他类别更频繁?如何解决这个问题 代码 运行这个需要一段时间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个训练样本 为什么该模型倾向于预测某些类别比其他类别更频繁?如何解决这个问题 代码 运行这个需要一段时间 #
#!/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)。同样的情况也会发生
ImageDataGenerator
进行居中,请将featurewise\u center=1
。另一种方法是从每个RGB像素中减去ImageNet平均值。要减去的平均向量是[103.939116.779123.68]
relu
s,除非您有特定的理由使用单个tanh
SpatialDropout2D
。它以某种方式从Keras在线文档中删除,但您可以在中找到它conv
层具有same
和两个valid
。这并没有什么错,但更简单的方法是保持所有conv
层的相同
,并根据最大池数控制大小ImageDataGenerator
进行居中,请将featurewise\u center=1
。另一种方法是从每个RGB像素中减去ImageNet平均值。要减去的平均向量是[103.939116.779123.68]
relu
s,除非您有特定的理由使用单个tanh
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不是问题所在。至少没有晒黑