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

我目前正在CNN上使用keras进行特征提取的图像.所有图像均为276行,x列和3种颜色尺寸(RGB).

列数等于它应生成的输出特征向量的长度.

输入数据表示 – 编辑:

给予图像的输入数据由图像的列方向切片组成.这意味着图像的实际输入是(276,3),列数等于它应该生成的特征长度.

我最初的模型是这样的:

    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图像下降到单个值. ?

最佳答案 您使用64个卷积滤波器在276 x无x 3图像上操作,每个滤波器的大小为276 x 1(假设行= 276).一个卷积滤波器将输出大小为1 x无的矩阵.如果您不知道卷积滤波器的工作原理,请详细阅读
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的输出,则不应包括密集层,并在末尾使用平均池以将响应折叠为1 x 1 x无输出.

编辑:如果您有一个大小为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.

如何处理可变大小的图像

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

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

编辑:

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

CNN输入:无x 50 x n x 3

pool1层的输入:无x 46 x n x 32
pool1层的输出:无x 23 x n x 32

pool2层的输入:无x 19 x n x 64
pool2层的输出:无x 9 x n x 64(我认为Keras池占底线,即楼层(19/2)= 9)

pool3层的输入:无x 3 x n x 128
pool3层的输出:无x 1 x n x 128

squash_channels图层的输入:无x 1 x n x 128
squash_channels图层的输出:无x 1 x n x 1

flatten_input层的输入:无x 1 x n x 1
flatten_input图层的输出:无x n

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

点赞