Semantic Segmentation -- (DeepLabv3)Rethinking Atrous Convolution for Semantic Image Segmentation論文解


轉載:Semantic Segmentation -- (DeepLabv3)Rethinking Atrous Convolution for Semantic Image Segmentation論文解

Rethinking Atrous Convolution for Semantic Image Segmentation

原文地址:DeepLabv3

代碼: TensorFlow


Abstract

DeepLabv3進一步探討空洞卷積,這是一個在語義分割任務中:可以調整濾波器視野、控制卷積神經網絡計算的特征響應分辨率的強大工具。為了解決多尺度下的目標分割問題,我們設計了空洞卷積級聯或不同采樣率空洞卷積並行架構。此外,我們強調了ASPP(Atrous Spatial Pyramid Pooling)模塊,該模塊可以在獲取多個尺度上卷積特征,進一步提升性能。同時,我們分享了實施細節和訓練方法,此次提出的DeepLabv3相比先前的版本有顯著的效果提升,在PASCAL VOC 2012上獲得了先進的性能。


Introduction

對於語義分割任務,在應用深度卷積神經網絡中的有兩個挑戰:

  • 第一個挑戰:連續池化和下采樣,讓高層特征具有局部圖像變換的內在不變性,這允許DCNN學習越來越抽象的特征表示。但同時引起的特征分辨率下降,會妨礙密集的定位預測任務,因為這需要詳細的空間信息。DeepLabv3系列解決這一問題的辦法是使用空洞卷積(前兩個版本會使用CRF細化分割結果),這允許我們可以保持參數量和計算量的同時提升計算特征響應的分辨率,從而獲得更多的上下文。

  • 第二個挑戰:多尺度目標的存在。現有多種處理多尺度目標的方法,我們主要考慮4種,如下圖:
    mark

    • a. Image Pyramid: 將輸入圖片放縮成不同比例,分別應用在DCNN上,將預測結果融合得到最終輸出
    • b. Encoder-Decoder: 利用Encoder階段的多尺度特征,運用到Decoder階段上恢復空間分辨率(代表工作有FCN、SegNet、PSPNet等工作)
    • c. Deeper w. Atrous Convolution: 在原始模型的頂端增加額外的模塊,例如DenseCRF,捕捉像素間長距離信息
    • d. Spatial Pyramid Pooling: 空間金字塔池化具有不同采樣率和多種視野的卷積核,能夠以多尺度捕捉對象

DeepLabv3的主要貢獻在於:

  • 本文重新討論了空洞卷積的使用,這讓我們在級聯模塊和空間金字塔池化的框架下,能夠獲取更大的感受野從而獲取多尺度信息。

  • 改進了ASPP模塊:由不同采樣率的空洞卷積和BN層組成,我們嘗試以級聯或並行的方式布局模塊。

  • 討論了一個重要問題:使用大采樣率的3×3

  • 的空洞卷積,因為圖像邊界響應無法捕捉遠距離信息,會退化為1×1的卷積, 我們建議將圖像級特征融合到ASPP模塊中。

  • 闡述了訓練細節並分享了訓練經驗,論文提出的”DeepLabv3”改進了以前的工作,獲得了很好的結果


現有多個工作表明全局特征或上下文之間的互相作用有助於做語義分割,我們討論四種不同類型利用上下文信息做語義分割的全卷積網絡。

  • 圖像金字塔(Image pyramid): 通常使用共享權重的模型,適用於多尺度的輸入。小尺度的輸入響應控制語義,大尺寸的輸入響應控制細節。通過拉布拉斯金字塔對輸入變換成多尺度,傳入DCNN,融合輸出。這類的缺點是:因為GPU存儲器的限制,對於更大/更深的模型不方便擴展。通常應用於推斷階段

  • 編碼器-解碼器(Encoder-decoder): 編碼器的高層次的特征容易捕獲更長的距離信息,在解碼器階段使用編碼器階段的信息幫助恢復目標的細節和空間維度。例如SegNet利用下采樣的池化索引作為上采樣的指導;U-Net增加了編碼器部分的特征跳躍連接到解碼器;RefineNet等證明了Encoder-Decoder結構的有效性。

  • 上下文模塊(Context module):包含了額外的模塊用於級聯編碼長距離的上下文。一種有效的方法是DenseCRF並入DCNN中,共同訓練DCNN和CRF。

  • 空間金字塔池化(Spatial pyramid pooling):采用空間金字塔池化可以捕捉多個層次的上下文。在ParseNet中從不同圖像等級的特征中獲取上下文信息;DeepLabv2提出ASPP,以不同采樣率的並行空洞卷積捕捉多尺度信息。最近PSPNet在不同網格尺度上執行空間池化,並在多個數據集上獲得優異的表現。還有其他基於LSTM方法聚合全局信息。

我們的工作主要探討空洞卷積作為上下文模塊和一個空間金字塔池化的工具,這適用於任何網絡。具體來說,我們取ResNet最后一個block,復制多個級聯起來,送入到ASPP模塊后。我們通過實驗發現使用BN層有利於訓練過程,為了進一步捕獲全局上下文,我們建議在ASPP上融入圖像級特征.


Method

空洞卷積應用於密集的特征提取

這在DeepLabv1和DeepLabv2都已經講過,這里不詳解了~

深層次的空洞卷積

我們首先探討將空洞卷積應用在級聯模塊。具體來說,我們取ResNet中最后一個block,在下圖中為block4,並在其后面增加級聯模塊。

mark

  • 上圖(a)所示,整體圖片的信息總結到后面非常小的特征映射上,但實驗證明這是不利於語義分割的。如下圖:
    mark
    使用步幅越長的特征映射,得到的結果反倒會差,結果最好的out_stride = 8 需要占用較多的存儲空間。因為連續的下采樣會降低特征映射的分辨率,細節信息被抽取,這對語義分割是有害的。

  • 上圖(b)所示,可使用不同采樣率的空洞卷積保持輸出步幅的為out_stride = 16.這樣不增加參數量和計算量同時有效的縮小了步幅。

 Atrous Spatial Pyramid Pooling

對於在DeepLabv2中提出的ASPP模塊,其在特征頂部映射圖並行使用了四種不同采樣率的空洞卷積。這表明以不同尺度采樣是有效的,我們在DeepLabv3中向ASPP中添加了BN層。不同采樣率的空洞卷積可以有效的捕獲多尺度信息,但是,我們發現隨着采樣率的增加,濾波器的有效權重(權重有效的應用在特征區域,而不是填充0)逐漸變小。如下圖所示:

mark

當我們不同采樣率的3×3

卷積核應用在65×65的特征映射上,當采樣率接近特征映射大小時,3×3的濾波器不是捕捉全圖像的上下文,而是退化為簡單的1×1

濾波器,只有濾波器中心點的權重起了作用。

為了克服這個問題,我們考慮使用圖片級特征。具體來說,我們在模型最后的特征映射上應用全局平均,將結果經過1×1

的卷積,再雙線性上采樣得到所需的空間維度。最終,我們改進的ASPP包括:

  • 一個1×1

卷積和三個3×3的采樣率為rates={6,12,18}

  • 的空洞卷積,濾波器數量為256,包含BN層。針對output_stride=16的情況。如下圖(a)部分Atrous Spatial Pyramid Pooling
  • 圖像級特征,即將特征做全局平均池化,經過卷積,再融合。如下圖(b)部分Image Pooling.

改進后的ASPP模塊如下圖所示:
mark

注意當output_stride=8時,加倍了采樣率。所有的特征通過1×1

級聯到一起,生成最終的分數.


Experiment

采用的是預訓練的ResNet為基礎層,並配合使用了空洞卷積控制輸出步幅。因為輸出步幅output_stride(定義為輸入圖像的分辨率與最終輸出分辨率的比值)。當我們輸出步幅為8時,原ResNet的最后兩個block包含的空洞卷積的采樣率為r=2

r=4

模型的訓練設置:

部分 設置
數據集 PASCAL VOC 2012
工具 TensorFlow
裁剪尺寸 采樣513大小的裁剪尺寸
學習率策略 采用poly策略, 在初始學習率基礎上,乘以(1itermax_iter)power

,其中power=0.9

 
BN層策略 當output_stride=16時,我們采用batchsize=16,同時BN層的參數做參數衰減0.9997。
在增強的數據集上,以初始學習率0.007訓練30K后,凍結BN層參數。
采用output_stride=8時,再使用初始學習率0.001訓練30K。
訓練output_stride=16比output_stride=8要快很多,因為中間的特征映射在空間上小的四倍。但因為output_stride=16在特征映射上粗糙是犧牲了精度。
上采樣策略 在先前的工作上,
我們是將最終的輸出與GroundTruth下采樣8倍做比較
現在我們發現保持GroundTruth更重要,故我們是將最終的輸出上采樣8倍與完整的GroundTruth比較。

Going Deeper with Atrous Convolution實驗

我們首先試試級聯使用多個帶空洞卷積的block模塊。

  • ResNet50:如下圖,我們探究輸出步幅的影響,當輸出步幅為256時,由於嚴重的信號抽取,性能大大的下降了。
    mark
    而當我們使用不同采樣率的空洞卷積,結果大大的上升了,這表現在語義分割中使用空洞卷積的必要性。

  • ResNet50 vs. ResNet101: 用更深的模型,並改變級聯模塊的數量。如下圖,當block增加性能也隨之增加。
    mark

  • Multi-grid: 我們使用的變體殘差模塊,采用Multi-gird策略,即主分支的三個卷積都使用空洞卷積,采樣率設置Multi-gird策略。按照如下圖:
    mark

    • 應用不同策略通常比單倍數(r1,r2,r3)=(1,1,1)
  • 效果要好
  • 簡單的提升倍數是無效的(r1,r2,r3)=(2,2,2)
  • 最好的隨着網絡的深入提升性能.即block7下(r1,r2,r3)=(1,2,1)
  • Inference strategy on val set
    推斷期間使用output_stride = 8,有着更豐富的細節內容:
    mark

Atrous Spatial Pyramid Pooling實驗

  • ASPP模塊相比以前增加了BN層,對比multi-grid策略和圖片層級特征提升實驗結果:

mark

  • Inference strategy on val set
    推斷期間使用output_stride = 8,有着更豐富的細節內容,采用多尺度輸入和翻轉,性能進一步提升了:
    mark

在PASCAL VOC 2012上表現:

mark

Cityscapes表現

多種技巧配置結果:

mark

與其他模型相比:
mark

其他參數的影響

  • 上采樣策略和裁剪大小和BN層的影響:
    mark

  • 不同batchsize的影響:
    mark

  • 不同評估步幅的影響:
    mark


Conclusion

DeepLabv3重點探討了空洞卷積的使用,同時改進了ASPP模塊,便於更好的捕捉多尺度上下文。


代碼分析

因為沒找到官方的代碼,在github上找了一個DeepLabV3-TensorFlow版本.

訓練腳本分析

先找到train_voc12.py訓練文件。

找到關鍵的main方法:

創建訓練模型 & 計算loss

def main(): """創建模型 and 准備訓練.""" h = args.input_size w = args.input_size input_size = (h, w) # 設置隨機種子 tf.set_random_seed(args.random_seed) # 創建線程隊列,准備數據 coord = tf.train.Coordinator() # 讀取數據 image_batch, label_batch = read_data(is_training=True) # 創建訓練模型 net, end_points = deeplabv3(image_batch, num_classes=args.num_classes, depth=args.num_layers, is_training=True, ) # 對於小的batchsize,保持BN layers的統計參數更佳(即凍結預訓練模型的BN參數) # If is_training=True, 統計參數在訓練期間會被更新 # 注意的是:即使is_training=False ,BN參數gamma (scale) and beta (offset) 也會更新 # 取出模型預測值 raw_output = end_points['resnet{}/logits'.format(args.num_layers)] # Which variables to load. Running means and variances are not trainable, # thus all_variables() should be restored. restore_var = [v for v in tf.global_variables() if 'fc' not in v.name or not args.not_restore_last] if args.freeze_bn: all_trainable = [v for v in tf.trainable_variables() if 'beta' not in v.name and 'gamma' not in v.name] else: all_trainable = [v for v in tf.trainable_variables()] conv_trainable = [v for v in all_trainable if 'fc' not in v.name] # 上采樣logits輸出,取代ground truth下采樣 raw_output_up = tf.image.resize_bilinear(raw_output, [h, w]) # 雙線性插值放大到原大小 # Predictions: 忽略標簽中大於或等於n_classes的值 label_proc = tf.squeeze(label_batch) # 刪除數據標簽tensor的shape中維度值為1 mask = label_proc <= args.num_classes # 忽略標簽中大於或等於n_classes的值 seg_logits = tf.boolean_mask(raw_output_up, mask) #取出預測值中感興趣的mask seg_gt = tf.boolean_mask(label_proc, mask) # 取出數據標簽中標注的mask(感興趣的mask) seg_gt = tf.cast(seg_gt, tf.int32) # 轉換一下數據類型 # 逐像素做softmax loss. loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=seg_logits, labels=seg_gt) seg_loss = tf.reduce_mean(loss) seg_loss_sum = tf.summary.scalar('loss/seg', seg_loss) # TensorBoard記錄 # 增加正則化損失 reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES) reg_loss = tf.add_n(reg_losses) reg_loss_sum = tf.summary.scalar('loss/reg', reg_loss) tot_loss = seg_loss + reg_loss tot_loss_sum = tf.summary.scalar('loss/tot', tot_loss) seg_pred = tf.argmax(seg_logits, axis=1) # 計算MIOU train_mean_iou, train_update_mean_iou = streaming_mean_iou(seg_pred, seg_gt, args.num_classes, name="train_iou") train_iou_sum = tf.summary.scalar('accuracy/train_mean_iou', train_mean_iou)

關於streaming_mean_iou方法代碼見metric_ops.py,該方法用於計算每步的平均交叉點(mIOU),即先計算每個類別的IOU,再平均到各個類上。

IOU的計算定義如下:

IOU=true_positivetrue_positive+false_positive+false_negative
該方法返回一個 update_op操作用於估計數據流上的度量,更新變量並返回 mean_iou.

上面代碼初始化了DeepLabv3模型,並取出模型輸出,計算了loss,並計算了mIOU.

訓練參數設置

這里學習率沒有使用poly策略,該github說學習率設置0.00001效果更好點~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM