使用 RetinaNet 進行航空影像目標檢測

使用 RetinaNet 進行航空影像目標檢測

通過使用金字塔池化模塊(Pyramid Pooling Module),在整合基於不同區域的上下文後,PSPNet在效果上超過了FCN、DeepLab和DilatedNet等時下最佳的方法。

原標題 | Object Detection On Aerial Imagery Using RetinaNet

作者 | Kapil Varshney

使用 RetinaNet 进行航空影像目标检测

(左邊)原始圖片。(右邊) 使用RetinaNet進行車輛檢測(以綠色框註釋)

使用 RetinaNet 进行航空影像目标检测

使用RetinaNet檢測汽車和游泳池

介紹

出於稅收評估的目的,通常情況下,調查是在實地進行的。這些調查對於計算房產的真實價值非常重要。例如,擁有一個游泳池可以增加房價。同樣,附近或商店周圍的汽車數量可以表明該地區的經濟活動水平。能夠通過航空圖像和人工智能實現這一目標,可以消除低效率以及人類所需的高成本和時間來明顯改善這些過程。

為了解決這個問題,我們將嘗試用224x224像素航拍圖像的RGB芯片檢測汽車和游泳池。訓練數據集有3748個帶有邊界框註釋和PASCAL VOC格式標籤的圖像。

這個問題以及數據集由ESRI在HackerEarth上發佈,作為ESRI數據科學挑戰2019的題目。我參與並獲得了公共排行榜的第三名,其中RetinaNet模型的mAP(平均精度)為77.99,atIoU = 0.3。在下面的文章中,我將解釋我是如何嘗試這個問題的。

RetinaNet

RetinaNet是通過對現有的單目標檢測模型(如YOLO和SSD)進行兩次改進而形成的:

1.Feature Pyramid Networks for Object Detection(https://arxiv.org/abs/1612.03144

2.Focal Loss for Dense Object Detection(https://arxiv.org/abs/1708.02002)

特徵金字塔網絡

金字塔網絡通常被用來識別不同規模的物體。特徵金字塔網絡(FPN)利用深度卷積神經網絡中固有的多尺度金字塔層次來生成特徵金字塔。

使用 RetinaNet 进行航空影像目标检测

one-stage RetinaNet網絡結構在前饋ResNet結構(a)的基礎上使用特徵金字塔網絡(FPN)來生成豐富的多尺度卷積特徵金字塔(b)。在這個主幹網上有兩個子網絡,一個用於分類錨盒(C),另一個用於從錨盒迴歸到真實的對象盒(d)。我們的網絡設計的十分簡單,這使得這項工作能夠專注於一種新的focal loss函數,從而消除了我們的one-stage檢測器與最先進的two-stage檢測器之間的精度差距,比如Faster R-CNN與FPN同時以更快的速度運行。

Focal Loss

Focal Loss是對交叉熵損失的改進,有助於減小分類良好的實例的相對損失,並將更多的注意力集中在錯誤分類的實例上。

在存在大量簡單的背景示例的情況下,focal loss能夠訓練高度精確的密集目標檢測器。

使用 RetinaNet 进行航空影像目标检测

Focal Loss損失函數

如果你對模型的細節更感興趣,我建議你閱讀原始論文和這個非常有用、描述性很強的博客 'The intuition behind RetinaNet'(https://medium.com/@14prakash/the-intuition-behind-retinanet-eb636755607d)。

現在,讓我們開始實現並編寫代碼。以下是您可以遵循的Github存儲庫:

kapil-varshney/esri_retinanet Contribute to kapil-varshney/esri_retinanet development by creating an account on GitHub

(https://github.com/kapil-varshney/esri_retinanet)

配置 Retinanet

我們將使用 Fizyr實現 Keras implementation of RetinaNet。如果你有深度學習的服務器,你可以運行上面的代碼,如果你沒有可以運行深度學習的服務器,你可以使用這裡的代碼 here。此外,我建議使用虛擬環境。下面的腳本將安裝RetinaNet和其他必需的包。

使用 RetinaNet 进行航空影像目标检测

或者,你可以在AWS上運行GPU實例(p2.xlarge)與AMI的“deep-learning-for-computer-vision-with-python”。這個AMI預裝了keras-retinanet和其他必需的包。你可以在使用 workon retinanet 命令激活RetinaNet的虛擬環境之後開始使用該模型。

注意:Retinanet的計算量很大。當計算批量大小為4的圖像(224x224)塊時,它將要求至少7-8GBs的GPU內存。

一旦安裝了RetinaNet,為該項目創建以下目錄結構。

使用 RetinaNet 进行航空影像目标检测

我將詳細解釋其中的每一個,但這裡只是一個概述:

  • build_dataset.py—用於創建訓練/測試數據集的Python腳本。

  • config/esri_retinanet_config.py —構建腳本使用的配置文件。

  • dataset/annotations —保存所有圖像註釋的目錄

  • dataset/images —保存所有圖像的目錄

  • dataset/submission_test_data_images —Esri Data Science 挑戰提交的測試目錄。如果您正在處理自己的數據集和其他項目,那麼可以忽略這一點。

  • snapshots —每次迭代後保存所有訓練記錄的目錄。

  • models —保存用於評估和測試記錄的目錄。

  • tensorboard —保存訓練日誌以供tensorboard使用的目錄。

  • predict.py —對提交測試文件進行預測的腳本。

創建數據集

首先,我們需要編寫一個配置文件,該文件將保存圖像、註釋、輸出CSVs——訓練,測試和種類的路徑,以及test-train split值。有了這樣一個配置文件,代碼就可以用於不同的數據集。

使用 RetinaNet 进行航空影像目标检测

在這個配置文件中,TRAIN_TEST_SPLIT=0.75。標準做法是在訓練數據集和測試數據集之間從原始數據集中分離出75-25或70-30,在某些情況下甚至是80-20。但是對於這次比賽,我沒有製作測試數據集,而是使用完整的數據集進行訓練。這是因為僅僅提供了3748圖像數據集。此外,提供了2703個圖像的測試數據集(沒有註釋),通過在線提交預測可以測試模型。

接下來,讓我們編寫一個python代碼,它將讀取所有圖像路徑和註釋,並輸出在訓練和評估模型期間所需的三個CSVs:

  • train.csv — 此文件將以下列格式保存用於訓練的所有註釋<path>,<xmin>,<ymin>,<xmax>,<ymax>,<label>,每一行將表示一個邊界框,因此,根據圖像中註釋對象的數量,可以在多個行中顯示一個圖像。 /<label>/<ymax>/<xmax>/<ymin>/<xmin>/<path>

  • test.csv — 類似於train.csv的格式,該文件將保存用於測試模型的所有註釋。

  • classes.csv —一個具有索引分配數據集中所有唯一類標籤的文件 (從0開始,忽略background)

使用 RetinaNet 进行航空影像目标检测

讓我們首先創建一個builddatet.py文件並導入所需的包。注意,我們導入了在config目錄中創建的 esri_retinanet_config.py 文件,並給出了它的alias配置。

使用 RetinaNet 进行航空影像目标检测

在上面的代碼中,我們創建了一個參數解析器,可以選擇接收圖像和註釋路徑、輸出 CSV 的路徑以及train-test split。雖然我們已經在配置文件中定義了這些參數。但是,我也意識到,有時我想要為實驗創建圖像的子樣本,或者有不同的train-test split等。當時,在不更改配置文件的情況下,在執行腳本時可以選擇更快地傳遞這些參數。可以看到的是,我為配置文件本身的每個參數提供了默認值。因此,除非您想提供這些參數,否則不需要提供這些參數。解析完參數後,為每個參數分配簡單的變量名。

使用 RetinaNet 进行航空影像目标检测

在前面的代碼中,我們將圖像路徑讀取到一個列表中,對列表進行隨機化,將其拆分為訓練集和測試集,並以格式(<dataset>, <list>, <outpucsv>)將它們存儲在另一個列表數據集中。我們還將初始CLASS集,以保存數據集中的所有唯一類標籤。 /<outpucsv>/<list>/<dataset>

使用 RetinaNet 进行航空影像目标检测

接下來,我們循環遍歷每個數據集(訓練和測試),並打開要寫入的輸出CSV文件。對於每個數據集,我們循環遍歷每個圖像路徑。對於每一張圖像,提取文件名並構建相應的註釋路徑。這是因為,通常情況下,圖像和註釋文件具有相同的名稱,但擴展名不同。例如dataset/images/0000001.jpg

在 dataset/annotations/0000001.xml 中有它的註釋。如果數據集遵循不同的命名約定,請修改本節。使用 BeautifulSoup 解析註釋文件(XML)。然後,我們可以從解析的XML中找到“width”、“height”和“object(s)”。

使用 RetinaNet 进行航空影像目标检测

對於每個圖像,請查找所有對象並遍歷其中的每一個對象。然後,在註釋中查找每個對象的邊界框(xmin, ymin, xmax, ymax)和類標籤(名稱)。並通過截斷超出圖像邊界的任何邊界框座標來進行清理。另外做一次正確的檢查,如果程序出錯,那麼任何最小值都大於最大值,反之亦然。如果我們找到這樣的值,我們將忽略這些對象並繼續到下一個對象。

現在,我們有了所有的信息,我們可以繼續寫到輸出CSV,一次一行。另外,繼續將標籤添加到 CLASSES 集中。這最終會有所有唯一的類標籤。

使用 RetinaNet 进行航空影像目标检测

以所需的格式構建數據集的最後一件事是將類標籤及其各自的索引寫入CSV。在ESRI數據集中,只有兩個類 —— cars(label:'1',index:1)和swimming pool(label:'2',index:0)。classes.csv 就是這樣查找Esri數據集的。

使用 RetinaNet 进行航空影像目标检测

模型的訓練與評估

至此,數據集和RetinaNet項目代碼及所需環境已經準備完成,讓我們繼續在該數據集上訓練RetinaNet模型吧。

<code># For a list of all arguments/<code><code>$ retinanet-train --help/<code>

我使用以下命令訓練模型:

<code>$ retinanet-train --weights resnet50_coco_best_v2.1.0.h5 \\/<code><code>--batch-size 4 --steps 4001 --epochs 20 \\/<code><code>--snapshot-path snapshots --tensorboard-dir tensorboard \\/<code><code>csv dataset/train.csv dataset/classes.csv/<code>

建議下載一個預訓練模型或者權重文件替代隨機初始化權重這樣可以加速訓練過程(損失會較早收斂)。我使用在COCO數據集上得到的ResNet50 作為預訓練模型初始化權重。可以使用下面的鏈接下載ResNet50模型:

<code>https://github.com/fizyr/keras-retinanet/releases/download/0.5.0/resnet50_coco_best_v2.1.0.h5/<code>

batch-size 和 steps 的值依賴於你的系統配置(主要是GPU存儲空間)和數據集大小。通常在初始時我會將batch-size 設置為8,然後依據啟動訓練的成功與否將batch-size擴大或縮小為原來的2倍。如當訓練正常啟動時,就中斷訓練過程(使用CTR+C),然後使用一個較大batch-size再次訓練。

一旦你確定了batch-size 的大小,就可以計算每次遍歷整個數據集所需的steps了。如下的命令可以告訴你train.csv中的行數也即樣本數,train.csv之前已經創建在dataset目錄中。

<code>wc -l datatset/train.csv/<code>

計算step的大小非常簡單: steps = 樣本數/batch-size。接著,設置迭代次數epochs。根據我的經驗,RetinaNet收斂的很快,不出意外的話一個小的epochs就可以了。如果不行,你可以使用最後一次迭代的結果繼續訓練你的模型。因此,我們將提供一個快照路徑(snapshot-path)來保存你每次迭代之後的模型。

我們同樣提供一個tensorflow-dir目錄將所有的日誌存放到這裡,並且可以使用tensorboard來可視化訓練過程。在確定你的tensorboard已經裝好後,就可以打開一個新的終端界面並使用以下命令可以啟動tensorboard。

<code># To launch tensorboard/<code><code>$ tensorboard --logdir <path>/<code>

最後, 提供訓練數據集和類別標籤的csv 文件並執行訓練命令。訓練期間你可以看個鋼鐵俠電影、小睡片刻、做一些其他事情等。使用亞馬遜平臺的AWS p2.xlarge instance GPU為 tesla K80, 在一個3748(224X224)張圖片的數據集上的一次迭代會超過2個小時。

一旦模型被訓練到你滿意的程度,就可以將模型轉換為可以用來驗證和預測的格式。

<code># To convert the model/<code><code>$ retinanet-convert-model <path> <path>/<path>/<code>
<code># To evaluate the model/<code><code>$ retinanet-evaluate <path> csv <path> <path>/<path>/<path>/<code>
<code># Sample evaluation/<code><code>95 instances of class 2 with average precision: 0.8874/<code><code>494 instances of class 1 with average precision: 0.7200/<code><code>mAP: 0.8037/<code>

上面這個示例使用375張圖片的數據集迭代18次,並在一個125張圖片的測試集中進行驗證,平均正確率能夠達到80.37%。在這麼小的數據集上這個結果算是不錯啦。

預測

我們創建一個腳本predict.py,使用已訓練的模型在最終提交結果的數據集上做預測並將結果寫入磁盤中。

使用 RetinaNet 进行航空影像目标检测

在預測之前需要用一些方法對圖像進行預處理,這些方法包含在keras_retinanet工具中。並且,導入我們前面創建的配置文件,以加載一些路徑。

使用 RetinaNet 进行航空影像目标检测使用 RetinaNet 进行航空影像目标检测
使用 RetinaNet 进行航空影像目标检测

遍歷數據集中的每一張圖片,對每一張圖片進行預測。上面代碼中的6-9行從圖像路徑中提取圖片名稱,並創建一個txt格式的輸出文件,圖片的預測結果將會放到該文件中。11-15行,我們加載圖片,在將其送入模型之前,進行圖像的預處理、調整大小、擴展維度。在第18行,我們將預處理過的圖片送進模型中,返回預測的邊框座標,以及每個邊框屬於每個標籤的概率值。在上述代碼的最後一行,根據原始圖像的大小重新調整邊框的座標。

使用 RetinaNet 进行航空影像目标检测

接著,遍歷模型輸出的每個檢測結果。拋棄那些得分小於置信度閾值的結果。然而,如果你想計算平均正確率,就要保留所有的預測結果,可通過將confidence參數設置為0實現。邊框的座標值為float類型,需要轉換成int類型的。將每一個預測的結果構造成需要的格式: <ymin> <xmin> <ymax> <xmax> 並將其寫入到文件中。一張圖片的所有預測信息都被寫入相應的文件後,就要關閉文件。/<xmax>/<ymax>/<xmin>/<ymin>

<code>$ python predict.py --model models/output.h5 --input dataset/submission_test_data_images --confidence 0.0/<code>

運行上述命令運行predict.py腳本。可以根據你自己的數據集和項目適當的修改參數。

實驗及結果

最初,我使用的訓練數據僅為數據集的十分之一(375張圖片),迭代18次後得到模型。當置信度的閾值為0.5時,這個模型在測試集上的平均正確率為0.71。我在整個數據集上(3748張圖片)恢復模型的訓練,繼續迭代10次後平均值正確率增加為0.74。我決定對模型的anchor boxes進行一些更改。因為數據集中僅僅有正方形的邊框,所以我將邊框的長寬比的取值範圍由[0.5,1.2]更改為[1]。這似乎是一個不錯的嘗試,但我很快意識到,anchor的長寬比不會隨著數據補充而發生變換。隨著網絡大小的降低,在整個數據集上網絡的訓練速度就會增加。預測的正確率也會小幅提升,但隨後開始下降。我決定使用第二次的測試結果,其中將confidence 的值設置為0,使其包含所有的預測結果。這使得平均正確率達到了77.99%確保了我第三名的成績。我也嘗試了一些其他的實驗,包括使用FPN得到圖像的多尺度特徵、數據擴充增強等但都不成功,最終還是提交了之前的實驗結果。

使用 RetinaNet 進行航空影像目標檢測

總結

在這篇文章中,我們討論了RetinaNet模型,以及我如何在Esri 2019數據科學挑戰賽中使用它在224x224的航空圖像中檢測汽車和游泳池的。我們從構建項目目錄開始。接下來,我們構建了徐那聯模型所必須的訓練/測試數據集。用適當的參數對模型進行訓練,然後將訓練後的模型轉換為評價和預測模型。我們創建了另一個腳本,在要提交的測試集進行檢測並將結果保存到磁盤中。最後,簡要描述了我所做的實驗和取得的結果。

參考文獻

Focal Loss for Dense Object Detection(基於兩階段的R-CNN擴展的高精度目標檢測器):https://arxiv.org/abs/1708.02002

Feature Pyramid Networks for Object Detection(使用特徵金字塔在不同的尺度中檢測目標):https://arxiv.org/abs/1612.03144

Deep Learning for Computer Vision with Python: Master Deep Learning Using My New Book(一本介紹計算機視覺的書):https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/

非常感謝,你能看到這裡。希望能夠對你有所幫助。請留下你的意見和建議。你也可以通過LinkedIn聯繫我(https://www.linkedin.com/in/kapilvarshney14/)。代碼放在github中:

kapil-varshney/esri_retinanet Contribute to kapil-varshney/esri_retinanet development by creating an account on GitHub.(https://github.com/kapil-varshney/esri_retinanet)

via https://towardsdatascience.com/object-detection-on-aerial-imagery-using-retinanet-626130ba2203

封面圖來源:https://commons.wikimedia.org/wiki/File:Quebec_city-satellite_image.jpg

使用 RetinaNet 进行航空影像目标检测

本 期 譯 者

使用 RetinaNet 进行航空影像目标检测

Ryan

From 西安理工大學

使用 RetinaNet 进行航空影像目标检测

diddo

此人太懶,啥也沒填

使用 RetinaNet 进行航空影像目标检测

FH_H

From 吉林大學

使用 RetinaNet 进行航空影像目标检测


分享到:


相關文章: