18. 圖像分類、分割


本課程來自深度之眼deepshare.net,部分截圖來自課程視頻。

模型是如何將圖像分類的?

在這裏插入圖片描述
3-d張量>字符串過程(倒序來看)
1.類別名與標籤的轉換labelname={“ants”:0,“bees”:1}
2.取輸出向量最大值的標號,predicted=torch.max(outputs.data,1)
3.複雜運算outptus=resnet18(img_tensor)#img_tensor就是3-d張量
模型實際上就是把3-d張量映射到一個向量。
模型如何完成圖像分類?
答:圖像分類由模型與人類配合完成
模型:將數據映射到特徵
在這裏插入圖片描述
這裏的模型是指nn.Module,不是廣義上的模型。
人類:定義特徵的物理意義,解決實際問題
在這裏插入圖片描述

resnet18模型inference(推理)代碼

步驟:
1.獲取數據與標籤
2.選擇模型,損失函數,優化器
3.寫訓練代碼
4.寫inference代碼
Inference代碼基本步驟:
1.獲取數據與模型
2.數據變換,如RGB>4D-Tensor
3.前向傳播
4.輸出保存預測結果
代碼注意事項:
1.inference的時候,模型要執行eval()狀態而非training
2.使用torch.no_grad(),所有的運算不計算梯度,可以大大節省內存,提高運算速度。
3.數據預處理需保持一致,RGB or BGR?
模型將數據從圖片轉換到向量的代碼可以分爲如下幾個步驟:

# step1/4: path-->img,讀取圖片,轉換爲PIL形式
img_rgb=Image.open(path_img).convert('RGB')
# step 2/4: img-->tensor,轉換爲tensor
img_tensor=img_transform(img_rgb, inference_transform)
img_tensor.unsqueeze_(0)
img_tensor=img_tensor.to(device)#這裏注意tensor的to函數要用賦值語句,因爲它不是inplace的
# step3/4: tensor-->vector 
time_tic=time.time()
outputs=resnet18(img_tensor)
time_toc=time.time()
# step 4/4: visualization向量映射到具體的分類
_, pred_int=torch.max(outputs.data,1)
pred_str=classes[int(pred_int)]

resnet18結構分析

圖像分類經典模型

最下面那個是vgg
在這裏插入圖片描述
上面畫圈的屬於經典的CNN模型,可以看做是一組
mobilenet.py、shufflenetv2.py、squeezenet.py這三個屬於輕量化的CNN模型,可以看做一組
mnasnet.py是一種使用強化學習設計移動端模型的自動化神經架構搜索方法,最近很火,貌似最近出了第二版。

resnet18結構分析

論文:He K, Zhang X, Ren S, et al. Deep Residual Learning for Image Recognition
恆等映射,下面是resnet的一個block的圖
在這裏插入圖片描述
模型的輸入通常是224224的,經過conv1的時候,採用的stride=2,所以conv1的輸出大小是112112,然後經過一個max pooling操作,該操作的stride也是2,所以得到的是5656的輸出
在這裏插入圖片描述
然後進入conv2_x(在pytorch中可以看做一個layer,編號爲1,即layer1,下面的分別看做是layer2…)
在這裏插入圖片描述
這裏可以看到,卷積核大小是3
3,卷積核個數是64個。然後的2是代表2個block的堆疊。每個block的結構和上面的結構圖一樣,每個block都有兩個卷積層,兩個BN,兩個relu。
在進入conv3_x(layer2)前,模型將特徵圖的size進行了減半,56
56變成了2828.
依次類推,最後經過average pool,1000-d fc,softmax
resnet18中的18是根據帶參數的層來命名的,conv1是1,然後中間的在這裏插入圖片描述是2層,然後
2就有四層,
layer1~ 4就是44共16層,然後加最後的fc,一共是18,所以叫resnet18.
同理resnet34咋出來的?1+3
2+42+62+3*2+1=34,以此類推
當然,後面的在這裏插入圖片描述部分就不叫block了,ng的課裏面有講,前後小,中間大,是叫bottleneck。
下面是resnet中初始化resnet18和resnet34的代碼

return _resnet('resnet34',BasicBlock,[2,2,2,2],pretrained,progress,**kwargs)
return _resnet('resnet34',BasicBlock,[3,4,6,3],pretrained,progress,**kwargs)

注意看裏面的[2,2,2,2]和[3,4,6,3]對應的是模型結構分析中的豎下來的數字。
resnet50的代碼

return _resnet('resnetse',Bottleneck,[3,4,6,3],pretrained,progress,**kwargs)

注意看是Bottleneck,不是BasicBlock。
下面看BasicBlock的forward代碼對應的結構是不是一致(兩個卷積層,兩個BN,兩個relu)

def forward(self,x): 
	identity=x 
	out=self.conv1(x) #第一個卷積
	out=self.bn1(out)#第一個BN
	out=self.relu(out)#第一個relu
	
	out=self.conv2(out)#第二個卷積
	out=self.bn2(out)#第二個bn
	
	if self.downsample is not None: 
		identity=self.downsample(x)
	
	out+=identity #第二個relu前先加原始輸入(identity),進行殘差
	out=self.relu(out)#第二個relu
	
	return out

用torchsummary查看resnet18的具體結構。
在這裏插入圖片描述
接上圖:
在這裏插入圖片描述
這裏說一下,自適應池化操作,就是上面黃線部分,無論輸入的維度是多少,輸出的維度大小是1*1的,以便於接後面的linear層。

圖像分割是什麼?

圖像分割:將圖像每一個像素分類
黑色爲背景,藍色是貓咪
在這裏插入圖片描述
圖像分割分類:
1.超像素分割:少量超像素代替大量像素,常用於圖像預處理
2.語義分割:逐像素分類,無法區分個體,相同類別是一個顏色,例如人是一類,但是沒有辦法區分每一個人。
3.實例分割:對個體目標進行分割,像素級目標檢測
4.全景分割:語義分割結合實例分割
在這裏插入圖片描述

模型是如何將圖像分割的?

在這裏插入圖片描述
可以看到,分割後圖像大小不變,21是代表要預測的類別數量。

在這裏插入圖片描述
在這裏插入圖片描述
狗頭貓身識別爲狗。
在這裏插入圖片描述
模型如何完成圖像分割?
答:圖像分割由模型與人類配合完成
模型:將數映射到特徵
人類:定義特徵的物理意義,解決實際問題
結合之前的圖像分類來看,圖像分割也是分類的一種,只不過是把圖片上的每個像素做一個分類。
在這裏插入圖片描述
在這裏插入圖片描述

PyTorch-Hub

PyTorch-Hub—-PyTorch模型庫,有大量模型供開發者調用,下面是Hub常用的三個函數。
1.torch.hub.load(“pytorch/vision”,‘deeplabv3_resnet101’,pretrained=True)
model=torch.hub.load(github,model,*args,**kwargs)
功能:加載模型
主要參數:
·github:str,項目名,eg:pytorch/vision,<repo_owner/repo_name[:tag_name]>
·model:str,模型名
2.torch.hub.list(github,force_reload=False)列出當前github項目下有什麼模型供我們調用。
3.torch.hub.help(github,model,force_reload=False)列出模型的參數
更多參見:https://pytorch.org/hub

圖像分割的思考

在這裏插入圖片描述
在這裏插入圖片描述
上面例子中的圖例顏色含義爲:藍色爲小貓,綠色爲小狗
可以看出,模型進行圖像分割的依據主要是小動物的頭部。

深度學習圖像分割模型簡介

FCN

文獻:Fully Convolutional Networks for Semantic Segmentation
最主要貢獻:
利用全卷積完成pixelwise prediction
在這裏插入圖片描述

Unet

最主要貢獻:
奠定Unet系列分割模型的基本結構——編碼器與解碼器的特徵融合
網友對Unet及改進做了合集:https://github.com/shawnbit/unet-family
文獻:《U-Net:Convolutional Networks for Biomedical Image Segmentation》
這個模型是針對醫學圖像分類用的,其特點是可以針對醫學圖像數據量較少的特點進行訓練,由於模型(如下圖)像一個U型,所以叫Unet,中中間分開,左右兩邊分別就是編碼器與解碼器
在這裏插入圖片描述
注意看上面的模型,輸入shape是:572572,1個channel(灰度圖,只有一個channel),輸出是388388,2個channel(只做了2分類所以只有2個channel),爲什麼輸入和輸出不一樣大呢,因爲最早Unet是用來做細胞分割的,如下圖所示:
在這裏插入圖片描述
其中,藍色框是輸入,黃色框是輸出。注意看左圖中,對黃框的邊界一圈是做了鏡像的padding。同時這個模型也說明了,做圖像分割,輸入和輸出是可以不一樣大的。

DeepLab系列——V1

DeepLab系列現在有4個:V1/V2/V3/V3+。這裏看V1
主要特點:
1.孔洞卷積:藉助孔洞卷積,增大感受野
2.CRF:採用CRF進行mask後處理
文獻:《DeepLabv1 Semantic image segmentation with deep convolutional nets and fully connected CRFs》
在這裏插入圖片描述

DeepLab系列——V2

主要特點:
ASPP(Atrous spatial pyramid pooling):解決多尺度問題
文獻:DeepLab-Semantic Image Segmentation with Deep Convolutional Nets,Atrous Convolution,and Fully Connected CRFs
從圖中可以看到,對於一個輸入,採用了不同尺度(金字塔pyramid )的池化,4個池化的kernel都是3*3的,但是每個池化的感受野完全不同。注意看下面的顏色和上面的顏色是一一對應的。
在這裏插入圖片描述

DeepLab系列——V3

主要特點:
1.孔洞卷積的串行
2.ASPP的並行
以上兩個特點相當於對V1和V2兩個模型中的特點進行了改進。
文獻:DeepLabv3-Rethinking Atrous Convolution for Semantic Image Segmentation
下面是四種方法,第一個是圖像金字塔;第二個是Unet;第三個是DeepLabV1的空洞卷積,第四個是DeepLabV2的金字塔池化。DeepLabV3就是針對第三個和第四個進行的優化。
在這裏插入圖片描述
下面的圖片的下半部分是孔洞卷積的串行示意圖(畫圈圈的那裏),上半部分是傳統的卷積,可以看出空洞卷積保持了輸出的分辨率。
在這裏插入圖片描述
下面是ASPP的並行示意圖,並行結果concat起來,然後經過1*1的卷積操作得到結果。
在這裏插入圖片描述

DeepLab系列——V3+

主要特點:deeplabv3基礎上加上Encoder-Decoder思想
文獻:《DeepLabv3-Rethinking Atrous Convolution for Semantic Image Segmentation》
模型結構如下圖,上下分別是編碼和解碼器。解碼器中的DCNN是V1中的空洞卷積,然後接V3中的並行ASPP,可以看到使用了不同rate的特徵(注意顏色)得到結果後concat起來,經過11的卷積,得到一個輸出的特徵圖(編碼)。
解碼器中將上面得到的綠色的東西(就是編碼特徵圖,編碼器得出的結果就叫這個)先進行4倍的上採樣。然後和前面的結果進行concat,然後經過3
3的卷積,再進行4倍的上採樣,得到最後的Prediction。
在這裏插入圖片描述

綜述

綜述文獻:Deep Semantic Segmentation of Natural and Medical Images: A Review. 2019
在這裏插入圖片描述
github圖像分割資源:
https://github.com/shawnbit/unet-family
https://github.com/yassouali/pytorch_segmentation

訓練Unet完成人像摳圖(Portrait Matting)

數據來源:https://github.com/PetroWu/AutoPortraitMatting
在這裏插入圖片描述
在這裏插入圖片描述
可以看到輸入是三通道的rgb,輸出是2通道的圖片(或者說是1通道的mask,就是<0.5是背景,>0.5是人。)
代碼中與原始Unet不一樣的是,構建模型時,初始化特徵數爲32,原始模型是64(可以看上面的Unet的模型圖),後面每一層的特徵數都是以這個初始化特徵數爲基準進行計算的。

# step 2
net = UNet(in_channels=3, out_channels=1, init_features=32)   # init_features is 64 in stander uent

用1通道的3d張量來進行圖像分割代碼,在可視化步驟中寫:

mask_pred = outputs.ge(0.5).cpu().data.numpy().astype("uint8")#0.5是閾值

模型結構,具體代碼看unet.py文件中的forward函數,這裏只給圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章