日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

unet 层_UNet解释及Python实现

發(fā)布時(shí)間:2025/3/21 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 unet 层_UNet解释及Python实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

介紹

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

圖像分割示例

正如你在上面看到的,圖像如何變成兩個(gè)部分,一個(gè)代表貓,另一個(gè)代表背景。圖像分割在從自動(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背后的直覺

卷積神經(jīng)網(wǎng)絡(luò)(CNN)背后的主要思想是學(xué)習(xí)圖像的特征映射,并利用它進(jìn)行更細(xì)致的特征映射。這在分類問題中很有效,因?yàn)閳D像被轉(zhuǎn)換成一個(gè)向量,這個(gè)向量用于進(jìn)一步的分類。但是在圖像分割中,我們不僅需要將feature map轉(zhuǎn)換成一個(gè)向量,還需要從這個(gè)向量重建圖像。這是一項(xiàng)巨大的任務(wù),因?yàn)橐獙⑾蛄哭D(zhuǎn)換成圖像比反過(guò)來(lái)更困難。UNet的整個(gè)理念都圍繞著這個(gè)問題。

在將圖像轉(zhuǎn)換為向量的過(guò)程中,我們已經(jīng)學(xué)習(xí)了圖像的特征映射,為什么不使用相同的映射將其再次轉(zhuǎn)換為圖像呢?這就是UNet背后的秘訣。用同樣的 feature maps,將其用于contraction 來(lái)將矢量擴(kuò)展成segmented image。這將保持圖像的結(jié)構(gòu)完整性,這將極大地減少失真。讓我們更簡(jiǎn)單地理解架構(gòu)。

UNet架構(gòu)

UNet架構(gòu)

該架構(gòu)看起來(lái)像一個(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ù)量相同。之后,生成的映射通過(guò)另一個(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)得非常好。

UNet實(shí)現(xiàn)的Python代碼

Python代碼如下:

import torch

from torch import nn

import torch.nn.functional as F

import torch.optim as optim

class UNet(nn.Module):

def contracting_block(self, in_channels, out_channels, kernel_size=3):

block = torch.nn.Sequential(

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=in_channels, out_channels=out_channels),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(out_channels),

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=out_channels, out_channels=out_channels),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(out_channels),

)

return block

def expansive_block(self, in_channels, mid_channel, out_channels, kernel_size=3):

block = torch.nn.Sequential(

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=in_channels, out_channels=mid_channel),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(mid_channel),

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=mid_channel, out_channels=mid_channel),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(mid_channel),

torch.nn.ConvTranspose2d(in_channels=mid_channel, out_channels=out_channels, kernel_size=3, stride=2, padding=1, output_padding=1)

)

return block

def final_block(self, in_channels, mid_channel, out_channels, kernel_size=3):

block = torch.nn.Sequential(

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=in_channels, out_channels=mid_channel),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(mid_channel),

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=mid_channel, out_channels=mid_channel),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(mid_channel),

torch.nn.Conv2d(kernel_size=kernel_size, in_channels=mid_channel, out_channels=out_channels, padding=1),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(out_channels),

)

return block

def __init__(self, in_channel, out_channel):

super(UNet, self).__init__()

#Encode

self.conv_encode1 = self.contracting_block(in_channels=in_channel, out_channels=64)

self.conv_maxpool1 = torch.nn.MaxPool2d(kernel_size=2)

self.conv_encode2 = self.contracting_block(64, 128)

self.conv_maxpool2 = torch.nn.MaxPool2d(kernel_size=2)

self.conv_encode3 = self.contracting_block(128, 256)

self.conv_maxpool3 = torch.nn.MaxPool2d(kernel_size=2)

# Bottleneck

self.bottleneck = torch.nn.Sequential(

torch.nn.Conv2d(kernel_size=3, in_channels=256, out_channels=512),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(512),

torch.nn.Conv2d(kernel_size=3, in_channels=512, out_channels=512),

torch.nn.ReLU(),

torch.nn.BatchNorm2d(512),

torch.nn.ConvTranspose2d(in_channels=512, out_channels=256, kernel_size=3, stride=2, padding=1, output_padding=1)

)

# Decode

self.conv_decode3 = self.expansive_block(512, 256, 128)

self.conv_decode2 = self.expansive_block(256, 128, 64)

self.final_layer = self.final_block(128, 64, out_channel)

def crop_and_concat(self, upsampled, bypass, crop=False):

if crop:

c = (bypass.size()[2] - upsampled.size()[2]) // 2

bypass = F.pad(bypass, (-c, -c, -c, -c))

return torch.cat((upsampled, bypass), 1)

def forward(self, x):

# Encode

encode_block1 = self.conv_encode1(x)

encode_pool1 = self.conv_maxpool1(encode_block1)

encode_block2 = self.conv_encode2(encode_pool1)

encode_pool2 = self.conv_maxpool2(encode_block2)

encode_block3 = self.conv_encode3(encode_pool2)

encode_pool3 = self.conv_maxpool3(encode_block3)

# Bottleneck

bottleneck1 = self.bottleneck(encode_pool3)

# Decode

decode_block3 = self.crop_and_concat(bottleneck1, encode_block3, crop=True)

cat_layer2 = self.conv_decode3(decode_block3)

decode_block2 = self.crop_and_concat(cat_layer2, encode_block2, crop=True)

cat_layer1 = self.conv_decode2(decode_block2)

decode_block1 = self.crop_and_concat(cat_layer1, encode_block1, crop=True)

final_layer = self.final_layer(decode_block1)

return final_layer

以上Python代碼中的UNet模塊代表了UNet的整體架構(gòu)。使用contracaction_block和expansive_block分別創(chuàng)建contraction部分和expansion部分。crop_and_concat函數(shù)的作用是將contraction層的輸出添加到新的expansion層輸入中。訓(xùn)練部分的Python代碼可以寫成

unet = Unet(in_channel=1,out_channel=2)

#out_channel represents number of segments desired

criterion = torch.nn.CrossEntropyLoss()

optimizer = torch.optim.SGD(unet.parameters(), lr = 0.01, momentum=0.99)

optimizer.zero_grad()

outputs = unet(inputs)

# permute such that number of desired segments would be on 4th dimension

outputs = outputs.permute(0, 2, 3, 1)

m = outputs.shape[0]

# Resizing the outputs and label to caculate pixel wise softmax loss

outputs = outputs.resize(m*width_out*height_out, 2)

labels = labels.resize(m*width_out*height_out)

loss = criterion(outputs, labels)

loss.backward()

optimizer.step()

結(jié)論

圖像分割是一個(gè)重要的問題,每天都有一些新的研究論文發(fā)表。UNet在這類研究中做出了重大貢獻(xiàn)。許多新架構(gòu)的靈感都來(lái)自UNet。在業(yè)界,這種體系結(jié)構(gòu)有很多變體,因此有必要理解第一個(gè)變體,以便更好地理解它們。

總結(jié)

以上是生活随笔為你收集整理的unet 层_UNet解释及Python实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。