2017-03-10 76 views
4

我目前正在CNN上使用keras進行特徵提取。所有圖像爲276行,x列和3種顏色尺寸(RGB)。 列數等於它應該生成的輸出特徵向量的長度。如何使用Keras在CNN中使用可變大小的圖像?

輸入數據表示 - 編輯:

給予圖像輸入數據包括所述圖像的縱列切片。這意味着圖像的實際輸入是(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圖像的1個單價值。 ?

+0

看我的編輯。此外,我改變了你的問題標題,以更好地反映問題。如果您不同意,請隨時將其改回。 –

回答

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池合併來收回對1 x 1 x None輸出的響應。

編輯:如果你有大小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-圖像的高度)。你可以做兩件事:

  1. 減少接受領域,即不是一次卷積整個圖像的列,而是一次只能卷積3個像素的列。
  2. 有多個卷積層。

在下文中,我會認爲像高爲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 > 224n' != 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) 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
的輸出圖層:None x n

我認爲這是你想要的。我希望現在清楚。

+0

密集的層是我重新創建一個完全連接層的方式.. – user7654132

+0

我給了輸入形狀'276 x無x 3',因爲圖像有不同數量的列,這將是唯一我能想到的,代表列數 – user7654132

+0

我從來沒有嘗試給過'無',但我認爲它應該沒問題。主要問題將是'密集'層。當你有一個密集的圖層時,你不能給出可變大小的輸入。順便說一句,密集層是完全連接的層(即它們是同義詞)。所以我沒有得到你的第一個評論。 –

相關問題