CNN中的模型精度和损失没有提高

问题描述 投票:0回答:1

我正在使用下面的LeNet架构来训练我的图像分类模型,我注意到每次迭代的训练,val的准确性都没有提高。任何一个在这方面的专业知识,可以解释什么可能已经出了问题?

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

#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

python tensorflow keras deep-learning cnn
1个回答
1
投票

最重要的是,你正在使用 loss = 'categorical_crossentropy',将其改为 loss = 'binary_crossentropy' 因为你只有2个班。而且还改变 class_mode='categorical'class_mode='binary'flow_from_directory.

正如@desertnaut正确地提到的。categorical_crossentropy 并驾齐驱 softmax 最后一层的激活,如果你把损失改为 binary_crossentropy 最后一次激活也应改为 sigmoid.

其他改进。

  1. 你的数据非常有限(160张图片),你用了近50%的数据作为验证数据。
  2. 由于你正在建立图像分类模型,你只有两个Conv2D层和4个密集层。密集层增加了大量的权重需要学习。增加几个conv2d层,减少密集层。
  3. 设置batch_size = 1并删除step_per_epoch。因为你的输入非常少,所以让每个epoch的步数与输入记录相同。
  4. 使用默认的 glorot_uniform kernel initializer。
  5. 为了进一步调整你的模型,使用多个Conv2D层建立模型,然后是GlobalAveragePooling2D层和FC层,最后是softmax层。
  6. 使用数据增强技术,如 horizontal_flip, vertical_flip, shear_range,ImageDataGenerator的zoom_range来增加训练和验证图像的数量。

按照 @desertnaut 的建议,将评论移到答案区 -------------------------。

问题 - 谢谢! 是的,我想的问题是数据少。有一个额外的问题--为什么增加更多的致密层会对模型产生负面影响,当我们决定使用多少个致密层和密集层时,有什么规则可以遵循吗?- Arun_Ramji_Shanmugam 2天前

回答 - 回答你问题的第一部分,Conv2D层保持了图像的空间信息,需要学习的权重取决于层中提到的内核大小和步长,而密集层需要将Conv2D的输出进行扁平化处理并进一步使用,因此失去了空间信息。此外,密集层还增加了更多的权重,例如2个512的密集层会给模型增加(512*512)=262144个参数或权重(必须由模型学习).这意味着你必须训练更多的纪元数,并以良好的炒作参数设置来学习这些权重。- Tensorflow战士 2天前

回答 - 回答你问题的第二部分,使用系统化的实验来发现什么是最适合你的特定数据集的。另外,这也取决于你所拥有的处理能力。请记住,更深的网络总是更好的,代价是更多的数据和增加学习的复杂性。 传统的方法是寻找类似的问题和已经被证明有效的深度学习架构。同时我们还可以灵活地利用预训练的模型,如resnet、vgg等,通过冻结部分层和在剩余层上训练来使用这些模型。- Tensorflow战士 2天前

问题 - 谢谢你的详细回答! 如果你不嫌麻烦的话,还有一个问题--当我们使用已经训练好的模型(可能是一些层)时,是不是需要在相同的输入数据上进行训练,作为我们要工作的模型?- Arun_Ramji_Shanmugam yesterday

答案 - 图像分类的转移学习背后的直觉是,如果在一个足够大和通用的数据集上训练一个模型,这个模型将有效地作为视觉世界的通用模型。 你可以在这里找到转移学习的例子与解释 - tensorflow.orgtutorialsimagestransfer_learning 。


3
投票

移除 kernel_initializer='uniform' 的参数;不要在这里指定任何东西,你的 默认 初始化器 glorot_uniform 是极力推荐的一款(和 uniform 是一个特别糟糕的设置)。)

一般来说,请记住,这种相当高级的设置的默认值是为了方便你,它们是隐含的推荐值,你最好不要乱用它们,除非你有特殊的原因,而且你知道你在做什么。

对于 kernel_initializer 特别是争论,我已经开始相信它给人们带来了很多不必要的痛苦(参见:1. 此处 为最新的例子)。)

另外,默认情况下不应该使用 dropout,特别是在像这里这样的情况下,模型似乎在努力学习任何东西;开始时不要使用任何 dropout(注释出相应的层),只有当你看到过度拟合的迹象时才将其添加回来。

© www.soinside.com 2019 - 2024. All rights reserved.