使用RetinaNet構建的人臉口罩探測器

做者|GUEST
編譯|VK
來源|Analytics Vidhyapython

介紹

目標檢測是計算機視覺中一個很是重要的領域,對於自動駕駛、視頻監控、醫療應用和許多其餘領域都是必要的。git

咱們正在與一場規模空前的傳染病做鬥爭。全世界的研究人員都在試圖開發一種疫苗或治療COVID-19的方法,而醫生們卻在努力阻止這場傳染病席捲全世界。另外一方面,許多國家發現了社會距離的疏遠,使用口罩和手套能夠稍微遏制這種局面。github

我最近有一個想法,用個人深度學習知識來幫助目前的狀況。在這篇文章中,我將向你介紹RetinaNet的實現,背景知識很少。bash

咱們將使用RetinaNet創建一個「口罩探測器」來幫助咱們應對這場持續的傳染病。你能夠推斷出一樣的想法來爲你的智能家居構建一個支持人工智能的解決方案。這我的工智能的解決方案只對戴着口罩和手套的人敞開大門。網絡

隨着無人機的成本隨着時間的推移而下降,咱們看到空中數據的生成出現了一個大的峯值。所以,你可使用這個RetinaNet模型在航空圖像甚至衛星圖像中檢測不一樣的對象,如汽車(自行車、汽車等)或行人,以解決不一樣的業務問題。架構

因此,你看目標檢測模型的應用是無窮無盡的。app

目錄

  1. 什麼是RetinaNet
  2. RetinaNet的需求
  3. RetinaNet的架構框架

    1. 骨幹網
    2. 對象分類子網
    3. 對象迴歸子網
  4. Focal Loss
  5. 利用RetinaNet模型創建口罩檢測器dom

    1. 收集數據
    2. 建立數據集
    3. 模特訓練
    4. 模型測試
  6. 最後說明

什麼是RetinaNet

RetinaNet是一種最好的單目標檢測模型,已被證實能很好地處理密集和小尺度的物體。因爲這個緣由,它已經成爲一個流行的目標檢測模型。機器學習

RetinaNet的需求

RetinaNet是由Facebook人工智能研究所(Facebook-AI-Research)引入的,旨在解決密集檢測問題。在處理極端前景-背景類時,須要彌補YOLO和SSD等單步目標檢測器的不平衡和不一致。

RetinaNet的架構

從本質上講,RetinaNet是一個複合網絡,由如下部分組成:

  1. 主幹網絡(自底向上的路徑和具備橫向鏈接的自上而下的路徑)
  2. 目標分類子網
  3. 目標迴歸子網

爲了更好地理解,讓咱們分別瞭解架構的每一個組件

1.主幹網絡

  1. 自底向上路徑:自底向上路徑(例如,ResNet)用於特徵提取。所以,它計算不一樣比例的特徵圖,而不考慮輸入圖像的大小。
  2. 具備橫向鏈接的自上而下的路徑:在自上而下的路徑上,從更高的金字塔級別對空間上較粗糙的特徵圖進行上採樣,橫向鏈接將具備相同空間大小的自頂向下和自底向上的層合併在一塊兒。較高層次的特徵圖每每具備較小的分辨率,但語義上更強。所以,更適合於檢測較大的物體;相反,來自較低級特徵圖的網格單元具備高分辨率,所以更擅長檢測較小的對象。所以,結合自上而下的路徑及其與自底向上的路徑的橫向鏈接,不須要太多額外的計算,所以生成的特徵圖的每一個級別在語義和空間上均可以很強。 所以,該體系結構是規模不變的,而且能夠在速度和準確性方面提供更好的性能。

2.目標分類子網

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

最後利用Sigmoid層(而不是softmax)進行目標分類。

而最後一個卷積層之因此有KA濾波器是由於,若是從最後一個卷積層獲得的特徵圖中的每一個位置都有不少錨盒候選區域,那麼每一個錨盒都有可能被分類爲K個類。因此輸出的特徵圖大小將是KA通道或過濾器。

3.目標迴歸子網

迴歸子網與分類子網並行附着在FPN的每一個特徵圖上。迴歸子網的設計與分類子網相同,只是最後一個卷積層大小爲3*3,有4個filter,輸出的特徵圖大小爲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. 當示例分類錯誤且pt小時,調製因子接近1而且不影響損失。
  2. 當pt→1時,因子變爲0,而且能夠很好地權衡分類良好的示例的損失。
  3. Focal loss γ平滑地調整了簡單示例的權重。 隨着γ的增長,調製因子的做用也一樣增長。 (通過大量實驗和試驗,研究人員發現γ= 2最有效)

:何時γ=0,FL至關於CE。圖中所示爲藍色曲線

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

如今讓咱們看看用Python實現RetinaNet來構建口罩檢測器。

利用RetinaNet模型創建口罩檢測器

收集數據

任何深度學習模型都須要大量的訓練數據才能在測試數據上產生良好的結果。

建立數據集

咱們開始使用LabelImg工具建立數據集和驗證。這個優秀的註釋工具可讓你快速地註釋對象的邊界框,從而訓練機器學習模型。

你能夠在anaconda命令提示符下使用下面的命令安裝它

pip install labelImg

你可使用下面的labelmg工具對每一個JPEG文件進行註釋,它將生成帶有每一個邊界框座標的XML文件。咱們將使用這些xml文件來訓練咱們的模型。

模型訓練

第1步:克隆並安裝keras-retinanet
import os
print(os.getcwd())
git clone https://github.com/fizyr/keras-retinanet.git
%cd keras-retinanet/
!pip install .
!python setup.py build_ext --inplace
第2步:導入全部必要庫
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
第3步:導入JPEG和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()
##讀全部文件
allfiles = [f for f in listdir(annotPath) if isfile(join(annotPath, f))]
#讀取全部pdf文件的圖像,而後在文本存儲在臨時文件夾
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
            #經過添加字典在空數據框架中追加行
            data = data.append({'fileName': fileName, 'xmin': xmin, 'ymin':ymin,'xmax':xmax,'ymax':ymax,'class':cls_name}, ignore_index=True)

data.shape
第4步:編寫一個函數來顯示訓練數據集上的邊界框
# 隨機選取圖像
  filepath = df.sample()['fileName'].values[0]

  # 獲取此圖像的全部行
  df2 = df[df['fileName'] == filepath]
  im = np.array(Image.open(filepath))

  # 若是有PNG的話,它會有alpha通道
  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)

#檢查少許數據記錄
data.head()

#定義標籤並將其寫入文件
classes = ['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 = 'https://github.com/fizyr/keras-retinanet/releases/download/0.5.1/resnet50_coco_best_v2.1.0.h5'
urllib.request.urlretrieve(URL_MODEL, PRETRAINED_MODEL)
第5步:訓練RetinaNet模型

注意:若是你使用google colab,你可使用下面的代碼片斷來訓練你的模型。

#把你的訓練數據路徑和文件放在訓練數據的標籤上
!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:上面的腳本生成的註釋文件
第6步:載入訓練模型
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]
模型測試:
第7步:利用訓練模型進行預測
#寫一個函數,從你的數據集中隨機選擇一個圖像,並預測使用訓練模型。
def show_image_with_predictions(df, threshold=0.6):
  # 隨機選擇一個圖像
  row = df.sample()
  filepath = row['fileName'].values[0]
  print("filepath:", filepath)
  # 獲取此圖像的全部行
  df2 = df[df['fileName'] == filepath]
  im = np.array(Image.open(filepath))
  print("im.shape:", im.shape)

  # 若是有一個PNG,它會有alpha通道
  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))

  ### 畫出預測 ###

  # 獲取預測
  imp = preprocess_image(im)
  imp, scale = resize_image(im)

  boxes, scores, labels = model.predict_on_batch(
    np.expand_dims(imp, axis=0)
  )

  # 標準化框座標
  boxes /= scale

  # 循環獲得每一個預測
  for box, score, label in zip(boxes[0], scores[0], labels[0]):
    # 分數是排序的,因此一旦咱們看到分數低於閾值,咱們就能夠退出
    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]
#能夠根據你的業務需求隨意更改閾值
label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
score, label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
score, label=show_image_with_predictions(data, threshold=0.6)

#能夠根據你的業務需求隨意更改閾值
score, label=show_image_with_predictions(data, threshold=0.6)

參考文獻

最後說明

總而言之,咱們完成了使用RetinaNet製做口罩檢測器的整個過程。 咱們建立了一個數據集,訓練了一個模型並進行了測試(這是個人Notebook和數據集的Github存儲庫):https://github.com/Praveen76/...

RetinaNet是一個功能強大的模型,使用Feature Pyramid Networks&ResNet做爲其骨幹。 我可以經過很是有限的數據集和極少的迭代(每一個迭代有500個步長,共6次迭代)得到口罩檢測器的良好結果。固然你也能夠更改閾值。

注意:

  1. 確保你訓練你的模型至少20次迭代,以得到好的結果。
  2. 一個好的想法是提交使用RetinaNet模型構建口罩檢測器的方法。 人們老是能夠根據業務需求調整模型,數據和方法。

通常來講,RetinaNet是開始目標檢測項目的一個很好的選擇,特別是若是你須要快速得到良好的結果。

原文連接:https://www.analyticsvidhya.c...

歡迎關注磐創AI博客站:
http://panchuang.net/

sklearn機器學習中文官方文檔:
http://sklearn123.com/

歡迎關注磐創博客資源彙總站:
http://docs.panchuang.net/

相關文章
相關標籤/搜索