Keras模型评估准确性不变,并且设计模型

时间:2019-09-12 07:25:42

标签: python tensorflow keras deep-learning multiclass-classification

我正在尝试在Keras中设计CNN,以将表情符号的小图像分类为其他图像。下面是13个类之一的示例。所有图片的大小相同,所有表情符号的大小也相同。我认为分类时应该很容易就能达到非常高精度,因为来自一类的表情符号是完全一样的!我的直觉告诉我,如果表情符号为50x50,则可以创建相同大小的卷积层以匹配一种表情符号。我的上司认为这不可行。无论如何,我的问题是,无论我如何设计模型,我总是对每个纪元获得相同的验证精度,相当于1/13(或者只是猜测每个表情符号属于同一类)。

我的模型如下:

model = Sequential()
model.add(Conv2D(16, kernel_size=3, activation="relu", input_shape=IMG_SIZE))
model.add(Dropout(0.5))
model.add(Conv2D(32, kernel_size=3, activation="relu"))
model.add(Conv2D(64, kernel_size=3, activation="relu"))
model.add(Conv2D(128, kernel_size=3, activation="relu"))
#model.add(Conv2D(256, kernel_size=3, activation="relu"))
model.add(Dropout(0.5))
model.add(Flatten()) 
#model.add(Dense(256, activation="relu"))
model.add(Dense(128, activation="relu"))
model.add(Dense(64, activation="relu"))
model.add(Dense(NUM_CLASSES, activation='softmax', name="Output")) 

我像这样训练它:

# ------------------ Compile and train ---------------
sgd = optimizers.SGD(lr=0.001, decay=1e-6, momentum=0.9, nesterov=True)
rms = optimizers.RMSprop(lr=0.004, rho=0.9, epsilon=None, decay=0.0)

model.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=["accuracy"])  # TODO Read more about this
train_hist = model.fit_generator(
    train_generator,
    steps_per_epoch=train_generator.n // BATCH_SIZE,
    validation_steps=validation_generator.n // BATCH_SIZE,  # TODO que?
    epochs=EPOCHS,
    validation_data=validation_generator,
    #callbacks=[EarlyStopping(patience=3, restore_best_weights=True)]
)

即使使用具有超过2亿个参数的模型,每个时期的验证准确度也仅为0.0773:

Epoch 1/10
56/56 [==============================] - 21s 379ms/step - loss: 14.9091 - acc: 0.0737 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 2/10
56/56 [==============================] - 6s 108ms/step - loss: 14.9308 - acc: 0.0737 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 3/10
56/56 [==============================] - 6s 108ms/step - loss: 14.7869 - acc: 0.0826 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 4/10
56/56 [==============================] - 6s 108ms/step - loss: 14.8948 - acc: 0.0759 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 5/10
56/56 [==============================] - 6s 109ms/step - loss: 14.8897 - acc: 0.0762 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 6/10
56/56 [==============================] - 6s 109ms/step - loss: 14.8178 - acc: 0.0807 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 7/10
56/56 [==============================] - 6s 108ms/step - loss: 15.0747 - acc: 0.0647 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 8/10
56/56 [==============================] - 6s 108ms/step - loss: 14.7509 - acc: 0.0848 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 9/10
56/56 [==============================] - 6s 108ms/step - loss: 14.8948 - acc: 0.0759 - val_loss: 14.8719 - val_acc: 0.0773
Epoch 10/10
56/56 [==============================] - 6s 108ms/step - loss: 14.8228 - acc: 0.0804 - val_loss: 14.8719 - val_acc: 0.0773

因为它没有学到任何东西,所以我开始认为这不是我的模型错误,而是数据集或我如何训练它。我也尝试过使用“ adam”进行训练,但得到相同的结果。我尝试更改图像的输入大小,但结果仍然相同。以下是我的数据集中的示例。你们有什么主意吗?

Same from dataset

1 个答案:

答案 0 :(得分:0)

我认为当前的主要问题是,相对于要训练的样本数,您的模型有太多的参数。对于当今的图像分类,通常只需要具有conv层,一个Global Something Pooling层以及一个用于输出的密集层。您只需要确保转换部分的结尾处具有足够大的接受范围即可找到您需要的所有功能。

首先要考虑的是确保您具有足够大的接收场(further reading about that here)。有三种主要的实现方法:池化,步幅> = 2和/或扩张> =2。由于您只有13个要识别的“功能”,而所有这些功能始终都是像素完美的,因此我认为,扩张将是必经之路,因此该模型可以轻松地在这13个“功能”上“过度拟合”。如果我们使用4个分别具有1、2、4和8膨胀的conv层,那么最终将得到31的接收场。这应该足以轻松识别50像素的表情符号。

接下来,每层应该有几个过滤器?通常,您从几个过滤器开始,然后像在此处所做的那样随着模型的增加而增加。但是,我们想对特定功能“过度拟合”,因此我们可能应该增加早期图层中的数量。为了简单起见,让我们为所有层提供64个过滤器。

最后,我们如何将所有这些转换为单个预测?如今,人们不再使用密集的层(将使用 ton 的参数并且不会平移不变),而是使用GlobalAveragePooling或GlobalMaxPooling。 GlobalAveragePooling更常见,因为它有助于查找许多功能的组合。但是,我们只想在此处找到13个左右的确切功能,因此GlobalMaxPooling可能会更好。然后,在那之后的单个密集层将足以获得预测。因为我们使用的是 Global MaxPooling,所以不需要先对其进行展平-全局池已经为我们做到了。

结果模型:

Conv2D(64, kernel_size=3, activation="relu", input_shape=IMG_SIZE)
Conv2D(64, kernel_size=3, dilation_rate=2, activation="relu")
Conv2D(64, kernel_size=3, dilation_rate=4, activation="relu")
Conv2D(64, kernel_size=3, dilation_rate=8, activation="relu")
GlobalMaxPooling()
Dense(NUM_CLASSES, activation='softmax', name="Output")

尝试一下。您可能还希望在除最后一层以外的所有层之后在其中添加BatchNormalization层。一旦获得了不错的培训准确性,请检查它是否过拟合。如果可能(请尝试),请尝试以下步骤:

  • 如果没有的话可以批量
  • 所有转化层和致密层的重量衰减
  • 转换层之后的SpatialDropout2D和池化层之后的常规Dropout
  • 使用ImageDataGenerator增强数据

设计这样的网络几乎是一门艺术,而不是一门科学,因此,如果您认为应该做的话,请进行一些更改。最终,您将获得在任何给定情况下或多或少可能起作用的直觉。