首页 文章

如何使用Keras在CNN中处理可变大小的图像?

提问于
浏览
4

我目前正在CNN上使用keras进行特征提取的图像 . 所有图像均为276行,x列和3种颜色尺寸(RGB) . 列数等于它应生成的输出特征向量的长度 .

输入数据表示 - 编辑:

The input data given to the image consist of columnwise slices of the image. which means the actual input to the image is (276,3) and number of of columns is equal to the feature length it should generate.

我最初的模型是这样的:

print "Model Definition"
    model = Sequential()

    model.add(Convolution2D(64,row,1,input_shape=(row,None,3)))
    print model.output_shape
    model.add(MaxPooling2D(pool_size=(1,64)))
    print model.output_shape
    model.add(Dense(1,activation='relu'))

我之间的打印打印 output.shape ,我似乎对输出有点困惑 .

Model Definition
(None, 1, None, 64)
(None, 1, None, 64)

为什么3D数据会变成4d?并且在maxpoolling2d层之后继续保持这种状态?

我的密集层/完全连接层给我一些尺寸问题:

Traceback (most recent call last):
  File "keras_convolutional_feature_extraction.py", line 466, in <module>
    model(0,train_input_data,output_data_train,test_input_data,output_data_test)
  File "keras_convolutional_feature_extraction.py", line 440, in model
    model.add(Dense(1,activation='relu'))
  File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 324, in add
    output_tensor = layer(self.outputs[0])
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 474, in __call__
    self.assert_input_compatibility(x)
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/topology.py", line 415, in assert_input_compatibility
    str(K.ndim(x)))
Exception: Input 0 is incompatible with layer dense_1: expected ndim=2, found ndim=4

那么为什么我无法将数据从3D图像下降到单个值 . ?

1 回答

  • 2

    您正在使用64个卷积滤波器操作 276 x None x 3 图像,每个滤波器的大小为 276 x 1 (假设 rows = 276 ) . 一个卷积滤波器将输出大小为 1 x None 的矩阵 . 如果您不知道卷积滤波器的工作原理,请详细阅读this . 因此对于64个过滤器(在Theano后端),您将得到一个大小为 64 x 1 x None 的矩阵 . 在Tensorflow后端,我认为它将是 1 x None x 64 . 现在,Keras-Theano的第一个维度始终是样本 . 所以,你的最终输出形状将是 None x 64 x 1 x None . 对于Tensorflow,它将是 None x 1 x None x 64 . 有关Keras中不同后端的更多信息,请阅读this .

    要删除密集层错误,我认为您需要在添加 Dense 图层之前引入以下行来展平输出 .

    model.add(Flatten())
    

    但是,我真的不明白这里使用的是密集层 . 您必须知道,密集层只接受固定的输入大小并提供固定大小的输出 . 因此,如果您希望网络在不丢失错误的情况下运行,那么您的 None 维度将基本上限制为单个值 . 如果要输出形状为 1 x None 的输出,则不应包含密集层,并在末尾使用 average pooling将响应折叠为 1 x 1 x None 输出 .

    Edit :如果您的图像大小为 276 x n x 3 ,其中列数可变,并且您希望输出大小为 1 x n ,则可以执行以下操作:

    model = Sequential()
    model.add(Convolution2D(64,row,1,input_shape=(row,None,3)))
    model.add(Convolution2D(1,1,1))
    print model.output_shape  # this should print `None x 1 x None x 1`
    model.add(flatten())
    

    现在,我怀疑这个网络将表现得非常好,因为它只有一层64个过滤器 . 感受野也太大(例如276-图像的高度) . 你可以做两件事:

    • 减少感受野,即不是一次卷积图像的整个列,而是一次只能对一列的3个像素进行卷积 .

    • 有多个卷积层 .

    在下文中,我将假设图像高度为50.然后您可以按如下方式编写网络:

    model = Sequential()
    model.add(Convolution2D(32,3,1,activation='relu',
              init='he_normal',input_shape=(row,None,3)))  # row = 50
    model.add(Convolution2D(32,3,1,activation='relu',init='he_normal'))
    model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool1'))
    model.add(Convolution2D(64,3,1,activation='relu',init='he_normal'))
    model.add(Convolution2D(64,3,1,activation='relu',init='he_normal'))
    model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool2'))
    model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
    model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
    model.add(Convolution2D(128,3,1,activation='relu',init='he_normal'))
    model.add(MaxPooling2D(pool_size=(2,1), strides=(2,1), name='pool3'))
    model.add(Convolution2D(1,1,1), name='squash_channels')
    print model.output_shape  # this should print `None x 1 x None x 1`
    model.add(flatten(), name='flatten_input')
    

    您应该验证所有这些卷积和最大池化层在最后一个最大池之后将输入高度从50减少到1 .

    How to handle variable-sized images

    一种方法是首先确定数据集的通用大小,例如224.然后构建如上所示的 224 x n 图像网络(可能更深一些) . 现在让我们说你得到一个不同大小的图像,比如 p x n' ,其中 p > 224n' != n . 您可以拍摄大小为 224 x n' 的中心裁剪图像并将其传递过图像 . 你有你的特征向量 .

    如果您认为大多数信息不是集中在中心周围,那么您可以采取多种作物,然后平均(或最大池)获得的多个特征向量 . 使用这些方法,我认为您应该能够处理可变大小的输入 .

    Edit:

    查看我使用 3 x 3 convolutions定义的CNN . 假设输入的大小为 50 x n x 3 . 假设我们通过卷积层传递大小为 p x q x r 的输入,该层具有 f 个滤波器,每个滤波器的大小为 3 x 3 ,步长为1.输入没有填充 . 然后卷积层的输出大小为 (p-2) x (q-2) x f ,即输出高度和宽度将小于输入的两个 . 我们的池层大小为 (2,1) ,步幅为 (2,1) . 它们将在y方向上将输入减半(或将图像高度减半) . 记住这一点,下面的内容很简单(观察我在CNN中给出的图层名称,下面引用它们) .

    CNN输入: None x 50 x n x 3

    输入 pool1 图层: None x 46 x n x 32
    输出 pool1 图层: None x 23 x n x 32

    输入 pool2 图层: None x 19 x n x 64
    pool2 图层的输出: None x 9 x n x 64 (我认为Keras汇集到底,即地板(19/2)= 9)

    输入 pool3 图层: None x 3 x n x 128
    输出 pool3 图层: None x 1 x n x 128

    输入 squash_channels 图层: None x 1 x n x 128
    输出 squash_channels 图层: None x 1 x n x 1

    输入 flatten_input 图层: None x 1 x n x 1
    输出 flatten_input 图层: None x n

    我想这就是你想要的 . 我希望它现在清楚 .

相关问题