【问题标题】:Low accuracy on Convolutional Neural Network with TensorFlow and Keras [closed]使用 TensorFlow 和 Keras 的卷积神经网络精度低 [关闭]
【发布时间】:2021-04-01 16:23:26
【问题描述】:

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

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 个 epoch 后停止。

当我从测试集中预测图像时,我得到了这个荒谬的结果(我在数组中看到一个“1.”,但测试图像必须与数组的最后一个元素相对应): Random image prediction after compiling the model

不使用提前停止(我认为它是过度拟合?),完成了 2000 个 epoch 并导致 0.8 的准确度,但预测仍然是错误的。

第一个问题 准确率低的原因是什么?是因为我的数据样本少吗? 我读过 Class_num/100,所以 156/100 在我的情况下可能有很好的准确性,但是当我从测试文件中预测照片时,它永远找不到相应的蘑菇类型。

我试过了 使用一个更大的数据集,其中包含 7000 多张照片,只有 9 个类别,准确度为 0.23。 但是在测试用例中,

model.predict(my_image_arr).round(3)

无论我输入什么照片,结果如下;

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

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

【问题讨论】:

    标签: python tensorflow machine-learning keras neural-network


    【解决方案1】:

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

    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 回调。我建议的代码如下

    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 参数必须是训练子目录,并且只包含包含图像的类子目录。

    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

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

    在 model.fit 中包含 class_weight= class_weight 此外,对于每个班级,我发现每个班级至少应该有 50 张图片。如果您的数量少于该数量,那么即使像您所做的那样使用图像增强,也可能没有足够数量的样本。因此,这里的选择是为未充分代表的类获取更多图像或删除这些类。最后,这不是一项令人愉快的任务,但根据您的图像,您可能需要考虑裁剪图像,以便感兴趣区域 (ROI),即蘑菇占据图像中的大部分像素。因此,您可能希望浏览您的图像并选择不符合此标准的图像并根据需要对其进行裁剪。我已经制作了几个高质量的数据集,使用这种方法通常可以达到 98% 或更高的测试准确度。

    【讨论】:

    • 非常感谢您抽出宝贵的时间,我目前正在按照您的指示进行培训,并会及时通知您。
    • 这里的每一条建议都对我的项目有很大帮助。谢谢!
    【解决方案2】:

    与大多数 ML 问题一样,首先检查您的数据集是否以正确的方式处理,我的意思是,您的标签是否与您的图像相对应。其次,尝试将第一个Dense 层中的神经元数量从 2 增加到大于 9 的数量,因为(尽管我不是 ML 专家)我从未见过密集层在 Conv 之后增加每一层中的神经元数量层。通常你必须在 Conv 层之后减少每个 Dense 层中的神经元数量,所以在你的情况下尝试做这样的事情model.add(Dense(64, activation='relu'))

    【讨论】:

      猜你喜欢
      • 2018-07-14
      • 2017-01-02
      • 2018-07-07
      • 2019-08-18
      • 2017-07-23
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多