[英]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進行細分。 它傾向於這樣做:
我還使用“僅訓練一張圖像”的方法來找到收斂,然后添加其他圖像即可。
但是我不得不嘗試很多次,並且它運行得非常快的唯一一次是我使用時:
但是我沒有在任何地方使用“ relu”……也許會影響收斂速度……? 考慮只有0或正數結果的“ relu”,此函數中有一個很大的區域沒有梯度。 也許有很多“ relu”激活會創建很多沒有梯度的“平坦”區域? (必須仔細考慮才能確認)
嘗試使用不同的權重初始化幾次(並耐心等待許多紀元)。
您的學習率也有可能太大。
關於to_categorical()
:您是否嘗試繪制/打印蒙版? 他們真的像您期望的那樣嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.