U-Net: Convolutional Networks for Biomedical Image Segmentation

https://arxiv.org/abs/1505.04597
https://www.seoxiehui.cn/article-106308-1.html

簡(jiǎn)介:介紹在圖像分割中,機(jī)器必須將圖像分割成不同的segments,每個(gè)segment代表不同的實(shí)體。圖像分割示例正如你在上面看到的,圖像如何變成兩個(gè)部分,一個(gè)代表貓,另一個(gè)代表背景。圖像分割在從自動(dòng)駕駛汽車到衛(wèi)星的許多 ...

介紹

在圖像分割中,機(jī)器必須將圖像分割成不同的segments,每個(gè)segment代表不同的實(shí)體。


image.png

圖像分割在從自動(dòng)駕駛汽車到衛(wèi)星的許多領(lǐng)域都很有用。也許其中最重要的是醫(yī)學(xué)影像。醫(yī)學(xué)圖像的微妙之處是相當(dāng)復(fù)雜的。一臺(tái)能夠理解這些細(xì)微差別并識(shí)別出必要區(qū)域的機(jī)器,可以對(duì)醫(yī)療保健產(chǎn)生深遠(yuǎn)的影響。

卷積神經(jīng)網(wǎng)絡(luò)在簡(jiǎn)單的圖像分割問題上取得了不錯(cuò)的效果,但在復(fù)雜的圖像分割問題上卻沒有取得任何進(jìn)展。這就是UNet的作用。UNet最初是專門為醫(yī)學(xué)圖像分割而設(shè)計(jì)的。該方法取得了良好的效果,并在以后的許多領(lǐng)域得到了應(yīng)用。在本文中,我們將討論UNet工作的原因和方式

UNet架構(gòu)

image.png

該架構(gòu)看起來像一個(gè)'U'。該體系結(jié)構(gòu)由三部分組成:contraction,bottleneck和expansion 部分。contraction部分由許多contraction塊組成。每個(gè)塊接受一個(gè)輸入,應(yīng)用兩個(gè)3X3的卷積層,然后是一個(gè)2X2的最大池化。在每個(gè)塊之后,核或特征映射的數(shù)量會(huì)加倍,這樣體系結(jié)構(gòu)就可以有效地學(xué)習(xí)復(fù)雜的結(jié)構(gòu)。最底層介于contraction層和expansion 層之間。它使用兩個(gè)3X3 CNN層,然后是2X2 up convolution層。

這種架構(gòu)的核心在于expansion 部分。與contraction層類似,它也包含幾個(gè)expansion 塊。每個(gè)塊將輸入傳遞到兩個(gè)3X3 CNN層,然后是2X2上采樣層。此外,卷積層使用的每個(gè)塊的feature map數(shù)量得到一半,以保持對(duì)稱性。每次輸入也被相應(yīng)的收縮層的 feature maps所附加。這個(gè)動(dòng)作將確保在contracting 圖像時(shí)學(xué)習(xí)到的特征將被用于重建圖像。expansion 塊的數(shù)量與contraction塊的數(shù)量相同。之后,生成的映射通過另一個(gè)3X3 CNN層,feature map的數(shù)量等于所需的segment的數(shù)量。

UNet中的損失計(jì)算

UNet對(duì)每個(gè)像素使用了一種新穎的損失加權(quán)方案,使得分割對(duì)象的邊緣具有更高的權(quán)重。這種損失加權(quán)方案幫助U-Net模型以不連續(xù)的方式分割生物醫(yī)學(xué)圖像中的細(xì)胞,以便在binary segmentation map中容易識(shí)別單個(gè)細(xì)胞。

首先,在所得圖像上應(yīng)用pixel-wise softmax,然后是交叉熵?fù)p失函數(shù)。所以我們將每個(gè)像素分類為一個(gè)類。我們的想法是,即使在分割中,每個(gè)像素都必須存在于某個(gè)類別中,我們只需要確保它們可以。因此,我們只是將分段問題轉(zhuǎn)換為多類分類問題,與傳統(tǒng)的損失函數(shù)相比,它表現(xiàn)得非常好。

def unet(pretrained_weights = None,input_size = (256,256,1)):
    inputs = Input(input_size)
    conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)
    conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)
    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
    conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2)
    conv3 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv3)
    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
    conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool3)
    conv4 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4)
    drop4 = Dropout(0.5)(conv4)
    pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)

    conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4)
    conv5 = Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5)
    drop5 = Dropout(0.5)(conv5)

    up6 = Conv2D(512, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(drop5))
    merge6 = concatenate([drop4,up6], axis = 3)
    conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge6)
    conv6 = Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv6)

    up7 = Conv2D(256, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv6))
    merge7 = concatenate([conv3,up7], axis = 3)
    conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge7)
    conv7 = Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv7)

    up8 = Conv2D(128, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv7))
    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, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8))
    merge9 = concatenate([conv1,up9], axis = 3)
    conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge9)
    conv9 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)
    conv9 = Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)
    conv10 = Conv2D(1, 1, activation = 'sigmoid')(conv9)

    model = Model(input = inputs, output = conv10)

    model.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
    
    #model.summary()

    if(pretrained_weights):
        model.load_weights(pretrained_weights)

    return model

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容