RetinaNet模型構建面罩檢測器

  • 2020 年 9 月 3 日
  • AI

字幕組雙語原文:如何使用RetinaNet模型構建面罩檢測器

英語原文:How to build a Face Mask Detector using RetinaNet Model!

翻譯:雷鋒字幕組(李珺毅


介紹

目標檢測是電腦視覺中一個非常重要的領域,對於自動駕駛、影片監控、醫療應用和許多其他領域都是十分必要的。

我們正在努力應對一場規模空前的大流行。全球各地的研究人員都在瘋狂地嘗試開發COVID-19的疫苗或治療方法,而醫生們正努力防止這一流行病席捲整個世界。另一方面,許多國家發現了社交距離,戴口罩和手套是稍微抑制這種情況的一種方法。

最近我有了一個想法,用我的深度學習知識來幫助一下現在的情況。在本文中,我將向您介紹RetinaNet的實現,而不需要什麼背景知識和相關工作。

最重要的是什麼?我們將使用RetinaNet建立一個口罩探測器來幫助我們應對這一持續的流行病。您可以推斷相同的想法,為你的智慧家居構建一個啟用ai的解決方案。這個人工智慧解決方案將只對戴著口罩和手套的開啟大樓的大門。

隨著無人機的成本隨著時間的推移而降低,我們看到了航拍數據的激增。因此,您可以使用這個RetinaNet模型在航空影像甚至衛星影像中檢測不同的對象,如汽車(自行車、汽車等)或行人,以解決不同的業務問題。

所以,你可以看到對象檢測模型的應用是無窮無盡的。

目錄

     1.RetinaNet是什麼

     2.RetinaNet的需求

     3.RetinaNet網路結構

        -1.主幹網路

        -2.目標分類自網路

        -3.目標回歸自網路

     4.Focal loss 損失函數

     5.使用RetianNet模型建立口罩檢測器

       -1.獲取數據

       -2.建立數據集

       -3.模型訓練

       -4.模型測試

      6.備註

RetianNet是什麼:

RetinaNet是最好的單階段目標檢測模型之一,它已被證明可以很好地處理密集和小規模的物體。因此,它已成為我們在航空和衛星影像中使用的流行目標檢測模型。

RetianNet的需求:

RetinaNet是由Facebook AI研究公司引入來解決密集檢測問題的。在處理極端的前景-背景類時,需要用它來彌補YOLO和SSD等單鏡頭對象檢測器的不平衡和不一致性。

RetinaNet的網路結構:

從本質上講,RetinaNet是由以下基本分組成的:

1.主幹網路(自下而上的邊路和具有側連接的自上而下的路徑)

2.目標分類子網路

3.目標回歸子網路

為了更好地理解,讓我們分別理解架構的每個組件

1.主幹網路

1.自底向上路徑:自底向上路徑(例如,ResNet)用於特徵提取。因此,它計算不同比例的特徵地圖,而不考慮輸入影像的大小。

2.具有橫向連接的自頂向下路徑:自頂向下路徑從更高的金字塔層次上采 樣空間上較粗糙的特徵圖,橫向連接將具有相同空間大小的自頂向下和自底向上的層合併在一起。較高層次的特徵圖往往具有較小的解析度,但語義上更強。因此,更適合於檢測較大的物體; 相反,來自較低級特徵圖的網格單元具有高解析度,因此更擅長檢測較小的對象(參見圖64)。 因此,通過自上而下的路徑及其與路徑的自下而上的橫向連接的組合,這些操作不需要太多額外的計算,因此生成的特徵圖的每個級別在語義和空間上都可以很強。 因此,該體系結構是規模不變的,並且可以在速度和準確性方面提供更好的性能。

2.目標分類子網路

每個FPN層都附加一個全卷積網路(FCN)進行對象分類。如圖所示,該子網包含3*3個卷積層,256個濾波器,然後是3*3個卷積層,K*A濾波器,因此輸出的feature map大小為W*H*KA,其中W和H與輸入特徵圖的寬度和高度成比例,K和A分別為對象類和錨盒的數量。

最後採用Sigmoid層(不是softmax層)進行對象分類。

而最後一個卷積層之所以有KA濾波器是因為,如果從最後一個卷積層得到的feature map中的每個位置都有很多錨盒候選區域,那麼每個錨盒都有可能被分類為K個類。所以輸出的特徵圖大小將是KA通道或過濾器。

3.目標回歸子網路

回歸子網路與分類子網路並行附著在FPN的每個特徵圖上。回歸子網路的設計與分類子網路相同,只是最後一個卷積層大小為3*3,有4個filter,輸出的feature map大小為W*H*4A。

最後一個卷積層有4個過濾器的原因是,為了定位類對象,回歸子網路為每個錨定盒產生4個數字,這些數字預測錨定盒和真實框錨盒之間的相對偏移量(根據中心坐標、寬度和高度)。因此,回歸子網的輸出特徵圖具有4A濾波器或通道。

Focal Loss損失函數

Focal Loss(FL)是Cross-Entropy Loss(CE)的改進版本,它通過為困難的或容易錯誤分類的示例(即具有嘈雜紋理或部分對象或我們感興趣的對象的背景)分配更多權重來嘗試處理類不平衡問題 ,並簡化簡單的示例(即背景對象)。

因此,「Focal Loss」減少了簡單示例帶來的損失貢獻,並提高了糾正錯誤分類的示例的重要性。 焦點損失只是交叉熵損失函數的擴展,它將降低簡單示例的權重,並將訓練重點放在困難樣本上。

所以為了實現這些研究人員提出了-

1- pt代表交叉熵損失,可調聚焦參數≥0。 RetinaNet物體檢測方法使用焦距損失的α平衡變體,其中α= 0.25,γ= 2效果最佳。

 

所以focal loss 的定義是:

對於γ∈[0,5]的幾個值,可以看到Focal Loss,請參見圖1。我們將注意到聚焦損耗的以下特性:

1.當示例分類錯誤且pt小時,調製因子接近1並且不影響損失。

2.當pt→1時,因子變為0,並且可以很好地權衡分類良好的示例的損失。

3.Focal loss γ平滑地調整了簡單示例的權重。 隨著γ的增加,調製因子的    作用也同樣增加。 (經過大量實驗和試驗,研究人員發現γ= 2最有效)

注意:-當FL = 0時,FL等於CE。如圖藍色曲線所示

直觀地看,調製因子減小了簡單例的損耗貢獻,擴展了例的低損耗範圍。

你可以在這篇文章中讀到關於Focal loss的詳細資訊(鏈接到我的focal loss文章),在這篇文章中我討論了交叉熵演變成focal loss,focal loss的需要,focal loss和交叉熵的比較

最重要的是,我用了幾個例子來解釋為什麼focal loss比交叉熵好。

現在讓我們看看用Python實現RetinaNet來構建口罩檢測器。

使用RetianNet模型建立口罩檢測器

獲取數據

任何深度學習模型都需要大量的訓練數據才能在測試數據上得到好的結果。在這篇文章中(鏈接到我的Web文章),我談到了為您的深度學習項目收集大量影像的Web方法。

創建數據集

我們首先使用LabelImg工具為訓練和驗證數據集創建注釋。這個優秀的注釋工具允許您快速注釋對象的邊框,以訓練機器學習模型。

您可以在anaconda命令提示符中使用下面的命令來安裝它

pip install labelImg

您可以使用如下所示的labelmg工具對每個JPEG文件進行注釋,它將生成帶有每個邊框坐標的XML文件。我們將使用這些xml文件來訓練我們的模型。

模型訓練

第一步:克隆安裝keras-retinaNet程式碼倉庫

import osprint(os.getcwd())

git clone //github.com/fizyr/keras-retinanet.git%cd keras-retinanet/

!pip install .

!python setup.py build_ext –inplace

第二步:導入所需要的包

import numpy as np

import shutil

import pandas as pd

import os, sys, random

import xml.etree.ElementTree as ET

import pandas as pd

from os import listdir

from os.path import isfile, join

import matplotlib.pyplot as plt

from PIL import Image

import requests

import urllib

from keras_retinanet.utils.visualization import draw_box, draw_caption , label_color

from keras_retinanet.utils.image import preprocess_image, resize_image

第三步:導入圖片和xml文件

pngPath=’C:/Users/PraveenKumar/RetinaNet//maskDetectorJPEGImages/’

annotPath=’C:/Users/PraveenKumar/RetinaNet//maskDetectorXMLfiles/’

data=pd.DataFrame(columns=[‘fileName’,’xmin’,’ymin’,’xmax’,’ymax’,’class’])

os.getcwd()#read All filesallfiles = [f for f in listdir(annotPath) if isfile(join(annotPath, f))

#Read all pdf files in images and then in text and store that in temp folder #Read all pdf files in images and then in text and store that in temp folder

for file in allfiles:

#print(file)

if (file.split(“.”)[1]==’xml’):

 

fileName=’C:/Users/PraveenKumar/RetinaNet/maskDetectorJPEGImages/’+file.replace(“.xml”,’.jpg’)

        tree = ET.parse(annotPath+file)

        root = tree.getroot()

        for obj in root.iter(‘object’):

            cls_name = obj.find(‘name’).text

            xml_box = obj.find(‘bndbox’)

            xmin = xml_box.find(‘xmin’).text

            ymin = xml_box.find(‘ymin’).text

            xmax = xml_box.find(‘xmax’).text

            ymax = xml_box.find(‘ymax’).text

            # Append rows in Empty Dataframe by adding dictionaries

            data = data.append({‘fileName’: fileName, ‘xmin’: xmin, ‘ymin’:ymin,’xmax’:xmax,’ymax’:ymax,’class’:cls_name}, ignore_index=True)

第三步:編寫一個可以在訓練集上顯示邊界框的函數

# pick a random image  filepath = df.sample()[‘fileName’].values[0]

 

  # get all rows for this image  df2 = df[df[‘fileName’] == filepath]

  im = np.array(Image.open(filepath))

 

  # if there’s a PNG it will have alpha channel  im = im[:,:,:3]

 

  for idx, row in df2.iterrows():

    box = [

      row[‘xmin’],

      row[‘ymin’],

      row[‘xmax’],

      row[‘ymax’],

    ]

    print(box)

    draw_box(im, box, color=(255, 0, 0))

 

  plt.axis(‘off’)

  plt.imshow(im)

  plt.show()                        

 

show_image_with_boxes(data)

#Check few records of datadata.head(

#Define labels & write them in a fileclasses = [‘mask’,’noMask’]with open(‘../maskDetectorClasses.csv’, ‘w’) as f:

  for i, class_name in enumerate(classes):

    f.write(f'{class_name},{i}\n’)         

 

if not os.path.exists(‘snapshots’):

  os.mkdir(‘snapshots’)

注意:最好從一個預先訓練好的模型開始,而不是從頭開始訓練一個模型。我們將使用已經在Coco數據集上預先訓練好的ResNet50模型。

URL_MODEL = ‘//github.com/fizyr/keras-retinanet/releases/download/0.5.1/resnet50_coco_best_v2.1.0.h5’
urllib.request.urlretrieve(URL_MODEL, PRETRAINED_MODEL)

第四步:訓練RetinaNet模型

注意:如果您正在使用GoogleColab,您可以使用下面的程式碼片段來訓練您的模型。

#Put your training data path & file that has labels for your training data!keras_retinanet/bin/train.py –freeze-backbone \ –random-transform \ –weights {PRETRAINED_MODEL} \ –batch-size 8 \ –steps 500 \ –epochs 15 \ csv maskDetectorData.csv maskDetectorClasses.csv

但如果你重新訓練你的本地Jupyter Notebook或不同的IDE訓練,然後你可以從命令提示符下面的命令

python keras_retinanet/bin/train.py –freeze-backbone

            –random-transform \

            –weights {PRETRAINED_MODEL}

            –batch-size 8

            –steps 500

            –epochs 15  

            csv maskDetectorData.csv maskDetectorClasses.csv

讓我們解釋一下傳遞給腳本train.py的每個參數。

1.freeze-backbone:凍結主幹層,當我們使用小數據集時特別有用,以避免過擬合

2.random-transform:隨機變換數據集以獲得數據增強

3.weights:使用一個預先訓練好的模型(您自己的模型或者Fizyr發布的模型)初始化模型

4.batch-size:訓練批量大小,值越高,學習曲線越平滑

5.step:迭代的步數

6.epochs:迭代的次數

7.csv:上面的腳本生成的注釋文件

第五步:載入訓練好的模型

from glob import glob

model_paths = glob(‘snapshots/resnet50_csv_0*.h5’)

latest_path = sorted(model_paths)[-1]

print(“path:”, latest_path)from keras_retinanet import models

 

model = models.load_model(latest_path, backbone_name=’resnet50′)

model = models.convert_model(model)

 

label_map = {}for line in open(‘../maskDetectorClasses.csv’):

  row = line.rstrip().split(‘,’)

  label_map[int(row[1])] = row[0]

模型測試

第六步:使用模型進行預測

#Write a function to choose one image randomly from your dataset and predict using Trained model.def show_image_with_predictions(df, threshold=0.6):

  # choose a random image  row = df.sample()

  filepath = row[‘fileName’].values[0]

  print(“filepath:”, filepath)

  # get all rows for this image  df2 = df[df[‘fileName’] == filepath]

  im = np.array(Image.open(filepath))

  print(“im.shape:”, im.shape)

 

  # if there’s a PNG it will have alpha channel  im = im[:,:,:3]

 

  # plot true boxes  for idx, row in df2.iterrows():

    box = [

      row[‘xmin’],

      row[‘ymin’],

      row[‘xmax’],

      row[‘ymax’],

    ]

    print(box)

    draw_box(im, box, color=(255, 0, 0))

 

  ### plot predictions ###  # get predictions  imp = preprocess_image(im)

  imp, scale = resize_image(im)

 

  boxes, scores, labels = model.predict_on_batch(

    np.expand_dims(imp, axis=0)

  )

 

  # standardize box coordinates  boxes /= scale

 

  # loop through each prediction for the input image  for box, score, label in zip(boxes[0], scores[0], labels[0]):

    # scores are sorted so we can quit as soon    # as we see a score below threshold    if score < threshold:

      break    box = box.astype(np.int32)

    color = label_color(label)

    draw_box(im, box, color=color)

 

    class_name = label_map    caption = f”{class_name} {score:.3f}”

    draw_caption(im, box, caption)

    score, label=score, label

  plt.axis(‘off’)

  plt.imshow(im)

  plt.show()

  return score, label

plt.rcParams[‘figure.figsize’] = [20, 10]

#Feel free to change threshold as per your business requirement score,
label=show_image_with_predictions(data, threshold=0.6)

引用

//arxiv.org/abs/1605.06409.

//arxiv.org/pdf/1708.02002.pdf

//developers.arcgis.com/python/guide/how-retinanet-works/

//analyticsindiamag.com/what-is-retinanet-ssd-focal-loss/

//github.com/fizyr/keras-retinanet

//www.freecodecamp.org/news/object-detection-in-colab-with-fizyr-retinanet-efed36ac4af3/

//deeplearningcourses.com/

//blog.zenggyu.com/en/post/2018-12-05/retinanet-explained-and-demystified/

備註:

總而言之,我們完成了使用RetinaNet製作面罩檢測器的整個過程。 我們創建了一個數據集,訓練了一個模型並進行了測試(這是我的筆記型電腦和數據集的Github存儲庫)。

Retina Net是一個功能強大的模型,使用Feature Pyramid Networks&ResNet作為其骨幹。 我能夠通過非常有限的數據集和極少的迭代(每個迭代有500個步長,共6次迭代)獲得口罩檢測器的良好結果。當然你也可以更改閾值。

注意:

1.確保你訓練你的模型至少20次迭代,以獲得好的結果。

2.一個好的想法是提交使用RetinaNet模型構建口罩檢測器的方法。 人們總是可以根據業務需求調整模型,數據和方法。

一般來說,RetinaNet是開始目標檢測項目的一個很好的選擇,特別是如果您需要快速獲得良好的結果。


雷鋒字幕組是一個由 AI 愛好者組成的翻譯團隊,匯聚五百多位志願者的力量,分享最新的海外AI資訊,交流關於人工智慧技術領域的行業變革與技術創新的見解。

團隊成員有大數據專家、演算法工程師、影像處理工程師、產品經理、產品運營、IT諮詢人、在校師生;志願者們來自IBM、AVL、Adobe、阿里、百度等知名企業,北大、清華、港大、中科院、南卡羅萊納大學、早稻田大學等海內外高校研究所。

如果,你也是位熱愛分享的AI愛好者。歡迎與雷鋒字幕組一起,學習新知,分享成長。

雷鋒網雷鋒網