代码之家  ›  专栏  ›  技术社区  ›  mad

是否可以用CNN对同一物体图像的不同区域进行分类?

  •  1
  • mad  · 技术社区  · 6 年前

    我有两张打印物体的照片,第一张是2.5x2.5 cm^2的打印面积,第二张是同一个物体,但打印面积是5.0x5.0 cm^2。在将物体从背景中分离出来并均衡这两张图片的直方图之后,我试图在深度学习方法(CNN)中使用小补丁(64x64)来理解它们的模式并对它们进行分类。我尝试使用2.5x2.5cm^2打印对象中的64x64补丁来训练深度学习分类器,并使用5.0x5.0cm^2对象中的补丁测试它们。两个对象的数字图像的分辨率大致相同,这是从对象提取程序中定义的。以下是用于训练和测试CNN二进制分类器的64x64补丁的示例。


    2.5x2.5cm^2对象的64x64修补程序

    5x5cm^2对象的64x64修补程序

    我要预测的类如下:

    Negative Class

    负类(第一次打印)

    Positive Class

    正类(复印、再版)

    我发现:

    1. 2.5x2.5cm^2物体的补丁如果CNN接受相同大小(面积)物体的补丁训练,很容易分类。
    2. 如果CNN使用2.5x2.5cm^2物体的64x64补丁进行培训,并使用5x5cm^2物体的64x64补丁进行测试,则预测结果仅适用于一个等级(精度为50%)。
    3. 在这种情况下,一些多尺度和多分辨率描述符可以很好地工作,例如使用一袋视觉单词
    4. 在这种情况下,其他基线CNN也会失败,如Mobilenet、Densenet和Resnet。
    5. 我试图在我的数据扩充过程中包括缩放(就像一个答案所建议的那样)。它也不起作用:-(

    这是我到目前为止试过的角膜模型

    model = Sequential()
    
    # GROUP1
    model.add(Conv2D(filters=32, kernel_size=3, strides=1, padding='same',
                     input_shape=input_shape))
    model.add(LeakyReLU(alpha=0.2))
    
    
    # GROUP2
    model.add(Conv2D(filters=32, kernel_size=3, strides=2, padding='same'))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))
    
    # GROUP3
    model.add(Conv2D(filters=64, kernel_size=3, strides=1, padding='same'))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))
    
    # GROUP4
    model.add(Conv2D(filters=64, kernel_size=3, strides=2, padding='same'))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))
    
    # GROUP5
    model.add(Conv2D(filters=96, kernel_size=3, strides=1, padding='same'))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))
    
    # GROUP6
    model.add(Conv2D(filters=96, kernel_size=3, strides=2, padding='same'))
    model.add(LeakyReLU(alpha=0.2))
    model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))
    
    model.add(Flatten())
    model.add(Dense(1024))
    model.add(LeakyReLU(alpha=0.2))
    
    model.add(Dense(2, activation='softmax'))
    
    return model
    

    这是我正在使用的数据扩充

    datagen = ImageDataGenerator(
                width_shift_range=0.2,
                height_shift_range=0.2,
                horizontal_flip=True,
            vertical_flip=True,
            zoom_range=0.2,
                fill_mode='nearest')
    
    
        datagen.fit(x_train)
        datagen.fit(x_validation)
    
        # Fit the model on the batches generated by datagen.flow().
        model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
                            steps_per_epoch=x_train.shape[0] // batch_size,
                            validation_data=datagen.flow(x_validation, y_validation, batch_size=batch_size),
                            epochs=nb_epoch, verbose=1, max_q_size=100,
                            validation_steps=x_validation.shape[0]//batch_size,
                            callbacks=[lr_reducer, early_stopper, csv_logger, model_checkpoint])
    

    那么,对于CNN来说,在这种非常困难的情况下,有没有解决方案来提高准确性呢?我的意思是,CNN从数据中学习特性,正如你所看到的,来自同一个班级的培训和测试数据是不同的。那么,对于我来说,是否有可能执行任何数据扩充或CNN操作(我的CNN没有退学,也没有汇集,如你所见),以最小化或模拟培训数据中的测试数据?

    1 回复  |  直到 6 年前
        1
  •  1
  •   spadarian    6 年前

    如果你的目标是在多个缩放级别预测,你需要用多个缩放级别培训CNN… 我认为当前的增强正在生成的样本不是您想要的。例如,这是当zoom=1.2时可能生成的图像之一:

    augmented_image

    最简单的解决方案是在使用5x5cm^2补丁进行培训时使用这样的生成器:

    ImageDataGenerator(horizontal_flip=True,
                       vertical_flip=True,
                       zoom_range=[0.5, 1])
    

    在这种情况下,当zoom=0.5时,您将得到如下图像:

    enter image description here

    它或多或少相当于2.5x2.5cm^2图像。

    如果必须使用2.5x2.5补丁进行培训,请尝试:

    ImageDataGenerator(horizontal_flip=True,
                       vertical_flip=True,
                       zoom_range=[1, 2],
                       fill_mode='constant',
                       cval=0)
    

    它产生像这样的图像:

    enter image description here

    有了足够的样本和时代,CNN应该能够了解填充零可以被忽略。