本文介绍了使用TensorFlow和Keras的卷积神经网络精度低的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正计划创建一个CNN以预测蘑菇的类型,并从互联网上收集了2500多张照片.数据集有156个类别(不同类型的蘑菇).我在Tensorflow 2和Keras上使用ImageDataGenerator对其进行了培训.这是图像生成器:

I am planning to create a CNN to predict mushroom types and collected over 2500 photos from the internet. Dataset has 156 classes(different types of mushrooms). I trained it using ImageDataGenerator on Tensorflow 2 and Keras.Here is the Image Generator:

image_gen = ImageDataGenerator(rotation_range = 20,
                           width_shift_range=0.12,
                           height_shift_range=0.12,
                           shear_range=0.1,
                           zoom_range = 0.06,
                           horizontal_flip=True,
                           fill_mode='nearest',
                           rescale=1./255)

这是模型;

model = Sequential()
model.add(Conv2D(filters=32,kernel_size=(3,3),input_shape=image_shape,activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Conv2D(filters=64,kernel_size=(3,3),input_shape=image_shape,activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Conv2D(filters=64,kernel_size=(3,3),input_shape=image_shape,activation='relu'))
model.add(MaxPool2D(pool_size=(2,2)))

model.add(Flatten())

model.add(Dense(2,activation='relu'))
model.add(Dropout(0.5))

model.add(Dense(156,activation='softmax'))

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

使用如下的提前停止;

with using early stopping as follows;

early_stop = EarlyStopping(monitor='val_loss',patience=2)

该模型以acc = 0.006开始,并在acc = 0.2附近20个历时后停止.

The model starts with acc=0.006 and stops after 20 epochs around acc=0.2.

当我从测试集中预测图像时,在这里我得到了这个荒谬的结果(我在数组中看到"1",但是测试图像必须对应于数组的最后一个元素):编译模型后的随机图像预测

When I predict an image from test set, here i get this absurd results(i see a '1.' in the array but test image must correspound to the last element of the array):Random image prediction after compiling the model

不使用提早停止(我认为这是过度拟合吗?),完成了2000个纪元并获得了0.8的准确度,但是预测仍然是错误的.

without using early stopping(i think it is overfitting?), 2000 epochs done and resulted in 0.8 accuracy, but the predictions are still wrong.

第一个问题准确性低的原因是什么?是因为我的数据样本少吗?我已经读过Class_num/100,因此就我而言,156/100可能会达到较高的准确性,但是当我从测试文件中预测照片时,它永远找不到对应的蘑菇类型.

First QuestionWhat is the reason behind the low accuracy? Is it because I have low samples of data?I have read that Class_num/100, so 156/100 might good accuracy in my case but when I predict a photo from the test files, it never finds the corresponding mushroom type.

我尝试了使用只有9个类别的7000多张照片的较大数据集,准确性为0.23.但是在测试案例中,

I triedUsing a larger dataset with 7000+ photos with only 9 classes, and accuracy resulted in 0.23.But in the test case,

model.predict(my_image_arr).round(3)

对于我喂的任何照片,结果如下:

resulted as follows, for whatever photo I feed in;

array([[0.063, 0.11 , 0.153, 0.123, 0.064, 0.059, 0.208, 0.162, 0.059]],
      dtype=float32)

如果有人可以帮助我解决我做错的事情,我将不胜感激.

I would be very grateful if anyone can help me with what I am doing wrong.

推荐答案

针对具有大量类的分类问题,我认为您的模型不够复杂.至少将2个神经元的密集单位更改为256个神经元.坦率地说,我建议您考虑使用迁移学习.下面是为此目的使用MobilenetV2模型的代码.

for a classification problem with a large number of classes I do not think your model is sufficiently complex. As a minimum change the dense unit with 2 neurons to something 256 neurons. Frankly I recommend that you consider using transfer learning. Below is the code to use the MobilenetV2 model for that purpose.

height=224
width=224
img_shape=(height, width, 3)
dropout=.3
lr=.001
class_count=156 # number of classes
img_shape=(height, width, 3)
base_model=tf.keras.applications.MobileNetV2( include_top=False, input_shape=img_shape, pooling='max', weights='imagenet')
x=base_model.output
x=keras.layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001 )(x)
x = Dense(512, kernel_regularizer = regularizers.l2(l = 0.016),activity_regularizer=regularizers.l1(0.006),
                bias_regularizer=regularizers.l1(0.006) ,activation='relu', kernel_initializer= tf.keras.initializers.GlorotUniform(seed=123))(x)
x=Dropout(rate=dropout, seed=123)(x)
output=Dense(class_count, activation='softmax',kernel_initializer=tf.keras.initializers.GlorotUniform(seed=123))(x)
model=Model(inputs=base_model.input, outputs=output)
model.compile(Adamax(lr=lr), loss='categorical_crossentropy', metrics=['accuracy'])

如果使用可调学习,则无论使用哪种模型,结果都将得到改善.因此,除了提早停止的回调外,还要添加ReduceLROnPlateau回调.我建议的代码如下

No matter which model you use results will improve if you use an adjustable learning. So in addition to the early stopping callback add the ReduceLROnPlateau callback. My suggested code for that is below

rlronp=tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=1, verbose=1, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)
callbacks=[rlronp, your early stopping callack]

在您的提早停止回调中,请确保耐心值至少为4.我不知道您的数据集的结构,但如果在类中最多的样本/类别中的最少样本之间的比率不大于2的情况下不平衡,那么您可能需要考虑在model.fit中使用类权重参数.这是基于每个类别中样本数量的权重字典.以下是用于遍历训练图像目录并计算班级权重字典的函数的代码.请注意,您的dir参数必须是training子目录,并且仅包含包含图像的class子目录,这很重要.

In your early stopping callback make sure patience value is at least 4.I do not know the structure of your data set but if it is not balanced where the ratio between the most samples in a class/least samples in a class >2 then you might want to consider using the class weights parameter in model.fit. This is a dictionary of weights based on the number of samples in each class. Below is the code for a function to iterate through your training images directory and calculate the class weight dictionary. Note it is essential that your dir parameter is the training sub directory and only contains class sub directories containing the images.

def get_weight_dict(dir):
    most_samples=0
    class_weight={}
    class_list=os.listdir(dir) # dir is the directory with the training samples organized by class
    for c in (class_list): # iterate through class directories, find number of samples in each class then find class with highest number of samples
        c_path=os.path.join(dir,c)
        if os.path.isdir(c_path):
            length=len(os.listdir(c_path)) # determine number of samples in the class directory
            if length>most_samples:
                most_samples=length
    for i,c in enumerate(class_list): #iterate through class directories, find number of samples in each and divide total_samples by length
        c_path=os.path.join(dir,c)
        if os.path.isdir(c_path):
            length=len(os.listdir(c_path)) # number of samples inclass directory
            class_weight[i]=most_samples/length
            #print (i,most_samples, class_weight[i])
    return class_weight

例如,如果您的主目录是c:\ mushrooms,而您的训练目录称为训练比使用"

for example if your main directory is c:\mushrooms and your training directory is called train than use

train_dir=r'c:\mushrooms\train'
class_weight=get_weight_dict(train_dir)

在model.fit中包括class_weight = class_weight另外,对于每个班级,我发现每个班级至少应有50张图像.如果您的数据不足,则即使像您那样使用图像增强,也可能没有足够的样本数量.因此,这里的选择是为表示的类获得更多图像或删除这些类.最后,这并不是一件令人愉快的任务,但是根据您的图像,您可能需要考虑裁剪图像,以使感兴趣区域(ROI)(即蘑菇占据图像中的大多数像素).因此,您可能需要浏览图像并选择不符合此条件的图像,然后根据需要裁剪它们.通过使用这种方法,我制作了一些高质量的数据集,通常可以达到98%或更高的测试精度.

in model.fit include class_weight= class_weightAdditionally for each class I find you should have a minimum of 50 images per class. If you have less than that there may not be a sufficient number of samples even using image augmentation as you have done. So the choice here is to either get more images for under represented classes or remove those classes. Finally and this is not a pleasant task but depending on your images you may want to consider cropping your images such that the region of interest (ROI) , namely the mushroom occupies the majority of pixels in the image. So you might want to go through your images and select those not meeting this criteria and crop them as needed. I have produced several high quality data sets that typically achieve a 98% or better test accuracy by using this approach.

这篇关于使用TensorFlow和Keras的卷积神经网络精度低的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 12:38