本文介绍了使用 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'])

使用提前停止如下;

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 个 epoch 并导致 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.

我试过了使用包含 7000 多张照片的更大数据集,只有 9 个类别,准确度为 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 参数必须是训练子目录,并且仅包含包含图像的类子目录.

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 并且您的培训目录被称为 train than use

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

train_dir=r'c:mushrooms	rain'
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-13 08:45