CNN中的模型准确性和损失未改善

时间:2020-04-29 09:18:36

标签: python tensorflow keras deep-learning conv-neural-network

我正在使用下面的LeNet架构训练我的图像分类模型,我注意到这两个训练的val精度都没有提高。该领域的任何一位专家都可以解释可能出了什么问题吗?

训练样本-属于2类的110张图像。 验证-属于2类的50张图像。

#LeNet

import keras 
from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense

#import dropout class if needed
from keras.layers import Dropout

from keras import regularizers

model = Sequential()
#Layer 1
#Conv Layer 1
model.add(Conv2D(filters = 6, 
                 kernel_size = 5, 
                 strides = 1, 
                 activation = 'relu', 
                 input_shape = (32,32,3)))
#Pooling layer 1
model.add(MaxPooling2D(pool_size = 2, strides = 2))
#Layer 2
#Conv Layer 2
model.add(Conv2D(filters = 16, 
                 kernel_size = 5,
                 strides = 1,
                 activation = 'relu',
                 input_shape = (14,14,6)))
#Pooling Layer 2
model.add(MaxPooling2D(pool_size = 2, strides = 2))
#Flatten
model.add(Flatten())
#Layer 3
#Fully connected layer 1
model.add(Dense(units=128,activation='relu',kernel_initializer='uniform'
                     ,kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(rate=0.2))
#Layer 4
#Fully connected layer 2
model.add(Dense(units=64,activation='relu',kernel_initializer='uniform'
                     ,kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(rate=0.2))

#layer 5
#Fully connected layer 3
model.add(Dense(units=64,activation='relu',kernel_initializer='uniform'
                     ,kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(rate=0.2))

#layer 6
#Fully connected layer 4
model.add(Dense(units=64,activation='relu',kernel_initializer='uniform'
                     ,kernel_regularizer=regularizers.l2(0.01)))
model.add(Dropout(rate=0.2))

#Layer 7
#Output Layer
model.add(Dense(units = 2, activation = 'softmax'))
model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])

from keras.preprocessing.image import ImageDataGenerator

#Image Augmentation
train_datagen = ImageDataGenerator(
        rescale=1./255, #rescaling pixel value bw 0 and 1
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)

#Just Feature scaling
test_datagen = ImageDataGenerator(rescale=1./255)

training_set = train_datagen.flow_from_directory(
       '/Dataset/Skin_cancer/training',
        target_size=(32, 32),
        batch_size=32,
        class_mode='categorical')

test_set = test_datagen.flow_from_directory(
        '/Dataset/Skin_cancer/testing',
        target_size=(32, 32),
        batch_size=32,
        class_mode='categorical')

model.fit_generator(
        training_set,
        steps_per_epoch=50,   #number of input (image)
        epochs=25,
        validation_data=test_set,
        validation_steps=10)          # number of training sample

Epoch 1/25
50/50 [==============================] - 52s 1s/step - loss: 0.8568 - accuracy: 0.4963 - val_loss: 0.7004 - val_accuracy: 0.5000
Epoch 2/25
50/50 [==============================] - 50s 1s/step - loss: 0.6940 - accuracy: 0.5000 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 3/25
50/50 [==============================] - 48s 967ms/step - loss: 0.6932 - accuracy: 0.5065 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 4/25
50/50 [==============================] - 50s 1s/step - loss: 0.6932 - accuracy: 0.4824 - val_loss: 0.6933 - val_accuracy: 0.5000
Epoch 5/25
50/50 [==============================] - 49s 974ms/step - loss: 0.6932 - accuracy: 0.4949 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 6/25
50/50 [==============================] - 51s 1s/step - loss: 0.6932 - accuracy: 0.4854 - val_loss: 0.6931 - val_accuracy: 0.5000
Epoch 7/25
50/50 [==============================] - 49s 976ms/step - loss: 0.6931 - accuracy: 0.5015 - val_loss: 0.6918 - val_accuracy: 0.5000
Epoch 8/25
50/50 [==============================] - 51s 1s/step - loss: 0.6932 - accuracy: 0.4986 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 9/25
50/50 [==============================] - 49s 973ms/step - loss: 0.6932 - accuracy: 0.5000 - val_loss: 0.6929 - val_accuracy: 0.5000
Epoch 10/25
50/50 [==============================] - 50s 1s/step - loss: 0.6931 - accuracy: 0.5044 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 11/25
50/50 [==============================] - 49s 976ms/step - loss: 0.6931 - accuracy: 0.5022 - val_loss: 0.6932 - val_accuracy: 0.5000
Epoch 12/25

Accuracy on each iteration

loss for each iteration

2 个答案:

答案 0 :(得分:3)

从图层中删除所有 kernel_initializer='uniform'个参数;不要在此处指定任何内容,强烈建议使用default初始化程序glorot_uniform(而uniform是特别糟糕的初始化程序)。

作为一般规则,请记住,为方便起见,有一些此类高级设置的默认值,建议隐式使用,除非您有特定的理由并且知道,否则最好不要搞乱它们。正是你在做什么。

特别是对于kernel_initializer争论,我开始认为它给人们带来了很多不必要的痛苦(有​​关最新示例,请参见here)。

此外,默认情况下不应该使用辍学,尤其是在这种情况下,模型似乎很难学习任何东西。开始时没有任何缺失(注释掉各个图层),只有在看到过度拟合的迹象时才将其重新添加。

答案 1 :(得分:2)

最重要的是您正在使用loss = 'categorical_crossentropy',因为只有2个类,所以将其更改为loss = 'binary_crossentropy'。并且还将class_mode='categorical'中的class_mode='binary'更改为flow_from_directory

正如@desertnaut正确提到的,categorical_crossentropy与最后一层的softmax激活紧密相关,如果将损失更改为binary_crossentropy,则最后一个激活也应更改为sigmoid

其他改进:

  1. 您的数据非常有限(160张图像),并且几乎使用了50%的数据作为验证数据。
  2. 在构建图像分类模型时,您只有两个Conv2D层和4个密集层。密集层增加了大量的权重需要学习。添加更多的conv2d层并减少Dense层。
  3. 设置batch_size = 1并删除steps_per_epoch。由于您的输入量非常少,因此每个纪元都具有与输入记录相同的步数。
  4. 使用默认的glorot_uniform内核初始化程序。
  5. 要进一步调整模型,请使用多个Conv2D层,随后是GlobalAveragePooling2D层,FC层和最终的softmax层来构建模型。
  6. 使用数据增强技术(例如horizontal_flipvertical_flipshear_range,ImageDataGenerator的zoom_range)来增加训练和验证图像的数量。

按照@desertnaut的建议移动评论以回答问题-

问题-谢谢!是的,我想的是更少的数据。再加一个 问题-为什么添加比conv层更密集的层 对模型有负面影响,当我们 决定我们要使用多少个conv和致密层? – 2天前Arun_Ramji_Shanmugam

答案-为回答问题的第一部分,Conv2D层保留了 图像的空间信息和要学习的权重取决于 层中提到的内核大小和步幅,如密集 层需要将Conv2D的输出展平并进一步使用 因此会丢失空间信息。同样致密的层增加了更多 权重数量,例如2个512的密集层相加 (512 * 512)= 262144模型的参数或权重(必须由 该模型)。这意味着您需要训练更多的纪元, 具有良好的炒作参数设置以学习这些权重。 – Tensorflow Warriors 2天前

答案-要回答问题的第二部分,请使用系统的实验 找出最适合您的特定数据集的方法。还取决于 您拥有的处理能力。请记住,更深层次的网络永远 更好,但需要更多数据并增加学习的复杂性。 常规方法是寻找类似的问题并深入研究 学习架构已经被证明是可行的。还有我们 可以灵活地使用预训练的模型,例如resnet,vgg 等等,通过冻结层的一部分并进行训练来使用这些模型 在其余层上。 – 2天前的Tensorflow Warriors

问题-谢谢您的详细回答!如果您不打扰另一个问题 -因此,当我们使用已经训练好的模型(可能是一些层)时,是否需要在与我们要输入的模型相同的输入数据上进行训练 工作? –昨天Arun_Ramji_Shanmugam

答案-传递学习用于图像分类的直觉是 如果模型是在足够大和足够通用的数据集上训练的,则这 模型将有效地充当视觉世界的通用模型。 您可以在此处找到带有说明的转学示例- tensorflow.org/tutorials/images/transfer_learning。 – Tensorflow 昨天的勇士们