簡體   English   中英

如何使用Keras構建多類卷積神經網絡

[英]How to build a multi-class convolutional neural network with Keras

我正在嘗試使用帶有Keras和Tensorflow后端的U-Net來實現圖像分割任務。 我將大小為(128,96)的圖像與大小為(12288,6)的蒙版圖像一起輸入到網絡中,因為它們被展平了。 我有6個不同的類(0-5),它們給出了蒙版圖像形狀的第二部分。 使用to_categorical()函數將它們編碼為一鍵式標簽。 目前,我只使用一張輸入圖像,也使用同一張圖像作為驗證和測試數據。

我希望U-Net進行圖像分割,其中0類對應於背景。 現在,當我僅在幾個時期(1-10)內訓練U-Net時,所得的預測蒙版圖像似乎只是為每個像素提供了隨機類別。 當我訓練網絡的時間更長(超過50個紀元)時,所有像素都被歸類為背景。 由於我使用相同的圖像進行訓練和測試,因此在加速網絡進行過度訓練時,我發現這很奇怪。 我該如何解決這個問題? 我將遮罩圖像和真實圖像提供給網絡的方式是否有問題?

我已經嘗試過手動給網絡賦權,以減少對背景的關注,並且嘗試了不同的損失組合,不同的蒙版圖像塑造方法以及許多其他事情,但是沒有任何結果能帶來良好的結果。

下面是我的網絡代碼。 它基於從此存儲庫中獲取的U-Net。 我設法在兩節課的情況下對它進行了培訓,並取得了良好的效果,但是我現在不知道如何將其擴展到更多的課。

def get_unet(self):

    inputs = Input((128, 96,1))
    #Input shape=(?,128,96,1)

    conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
      kernel_initializer = 'he_normal', input_shape=(None,128,96,6))(inputs)
    #Conv1 shape=(?,128,96,64)
    conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
          kernel_initializer = 'he_normal')(conv1)
    #Conv1 shape=(?,128,96,64)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
    #pool1 shape=(?,64,48,64)


    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(pool1)
    #Conv2 shape=(?,64,48,128)
    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(conv2)
    #Conv2 shape=(?,64,48,128)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
    #Pool2 shape=(?,32,24,128)

    conv5 = Conv2D(256, (3,3), activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(pool2)
    conv5 = Conv2D(256, (3,3), activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(conv5)

    up8 = Conv2D(128, 2, activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv5))
    merge8 = concatenate([conv2,up8], axis = 3)
    conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(merge8)
    conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(conv8)


    up9 = Conv2D(64, (2,2), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8))
    merge9 = concatenate([conv1,up9], axis = 3)
    conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(merge9)
    conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(conv9)
    conv9 = Conv2D(6, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(conv9)

    conv10 = Conv2D(6, (1,1), activation = 'sigmoid')(conv9)
    conv10 = Reshape((128*96,6))(conv10)

    model = Model(input = inputs, output = conv10)
    model.compile(optimizer = Adam(lr = 1e-5), loss = 'binary_crossentropy',
          metrics = ['accuracy'])

    return model

誰能指出我的模型出了什么問題?

謝謝@Daniel,您的建議最終幫助我使Unet正常工作。 運行500多個紀元時,我設法獲得的結果不只是將整個圖像分類為背景。 另外,代替使用kernel_initializer='he_normal'kernel_initializer='zeros'kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.07)為我工作。 我使用了'sigmoid'激活函數和loss='binary_crossentropy' 我為所有隱藏的卷積層保留了“ relu”激活。 我注意到我的網絡有時會停留在一個本地最小值范圍內,在此范圍內損耗不再改善,因此我需要重新啟動。

據我所知,我看不到您的預測層必須是密集層而不是卷積層。 也許那是你的問題。

以我的經驗,還可以使用U-net進行細分。 它傾向於這樣做:

  • 變成全黑或全白
  • 經過很多時間,損失似乎被凍結了,它發現了。

我還使用“僅訓練一張圖像”的方法來找到收斂,然后添加其他圖像即可。

但是我不得不嘗試很多次,並且它運行得非常快的唯一一次是我使用時:

  • 最終激活='Sigmoid'
  • 損失='binary_crossentropy'

但是我沒有在任何地方使用“ relu”……也許會影響收斂速度……? 考慮只有0或正數結果的“ relu”,此函數中有一個很大的區域沒有梯度。 也許有很多“ relu”激活會創建很多沒有梯度的“平坦”區域? (必須仔細考慮才能確認)

嘗試使用不同的權重初始化幾次(並耐心等待許多紀元)。

您的學習率也有可能太大。


關於to_categorical() :您是否嘗試繪制/打印蒙版? 他們真的像您期望的那樣嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM