基于 Python 和 HuggingFace Transformers 的目標(biāo)檢測(cè)
YOLO!如果你對(duì)機(jī)器學(xué)習(xí)感興趣,這個(gè)術(shù)語(yǔ)一定不陌生。確實(shí),You Only Look Once已經(jīng)成為過(guò)去幾年中目標(biāo)檢測(cè)的默認(rèn)方法之一。受到卷積神經(jīng)網(wǎng)絡(luò)取得的進(jìn)展推動(dòng),許多版本的目標(biāo)檢測(cè)方法已經(jīng)被創(chuàng)建。然而,近年來(lái),一個(gè)競(jìng)爭(zhēng)對(duì)手出現(xiàn)在了視野中——那就是在計(jì)算機(jī)視覺(jué)中使用基于Transformer的模型。更具體地說(shuō),是使用Transformer進(jìn)行目標(biāo)檢測(cè)。
在今天的教程中,你將了解到這種類(lèi)型的Transformer模型。你還將學(xué)會(huì)使用Python、一個(gè)默認(rèn)的Transformer模型和HuggingFace Transformers庫(kù)創(chuàng)建自己的目標(biāo)檢測(cè)流程。本文將按照下列步驟講解:
- 了解目標(biāo)檢測(cè)可以用來(lái)做什么
 - 了解當(dāng)Transformer用于目標(biāo)檢測(cè)時(shí)它們是如何工作的
 - 已經(jīng)使用Python和HuggingFace Transformers實(shí)現(xiàn)了基于Transformer模型的(圖像)目標(biāo)檢測(cè)流程
 

什么是目標(biāo)檢測(cè)?
環(huán)顧四周,很可能你會(huì)看到很多東西——可能是一臺(tái)電腦顯示器、一個(gè)鍵盤(pán)和鼠標(biāo),或者當(dāng)你在移動(dòng)瀏覽器中瀏覽時(shí),是一部智能手機(jī)。這些都是物體,是特定類(lèi)別的實(shí)例。例如,在下面的圖像中,我們看到一個(gè)人類(lèi)類(lèi)別的實(shí)例。我們還看到了許多瓶子類(lèi)別的實(shí)例。雖然類(lèi)別是藍(lán)圖,但物體是真實(shí)存在的,具有許多獨(dú)特的特征,同時(shí)因?yàn)楣蚕淼奶卣鞫鴮儆陬?lèi)別的成員。
在圖片和視頻中,我們看到了許多這樣的物體。例如,當(dāng)你拍攝交通視頻時(shí),很可能會(huì)看到許多行人、汽車(chē)、自行車(chē)等實(shí)例。知道它們?cè)趫D像中存在是非常有益的。為什么呢?因?yàn)槟憧梢杂?jì)數(shù)它們,舉一個(gè)例子。這可以讓你對(duì)社區(qū)的擁擠程度有所了解。另一個(gè)例子是在繁忙地區(qū)檢測(cè)到一個(gè)停車(chē)位,讓你可以停車(chē)。

目標(biāo)檢測(cè)和Transformer
傳統(tǒng)上,目標(biāo)檢測(cè)是通過(guò)卷積神經(jīng)網(wǎng)絡(luò)來(lái)實(shí)現(xiàn)的。通常,它們的架構(gòu)是專(zhuān)門(mén)針對(duì)目標(biāo)檢測(cè)設(shè)計(jì)的,因?yàn)樗鼈儗D像作為輸入并輸出圖像的邊界框。如果你熟悉神經(jīng)網(wǎng)絡(luò),你就知道卷積網(wǎng)絡(luò)在學(xué)習(xí)圖像中的重要特征方面非常有用,并且它們是空間不變的——換句話(huà)說(shuō),學(xué)習(xí)對(duì)象在圖像中的位置或大小是無(wú)關(guān)緊要的。如果網(wǎng)絡(luò)能夠看到對(duì)象的特征,并將其與特定類(lèi)別關(guān)聯(lián)起來(lái),那么它就能識(shí)別出來(lái)。例如,許多不同的貓都可以被識(shí)別為貓類(lèi)的實(shí)例。
然而,最近,在深度學(xué)習(xí)領(lǐng)域,特別是自然語(yǔ)言處理領(lǐng)域,Transformer架構(gòu)引起了人們的極大關(guān)注。Transformer通過(guò)將輸入編碼為高維狀態(tài),然后將其解碼回所需的輸出來(lái)工作。通過(guò)聰明地使用自注意力的概念,Transformer不僅可以學(xué)習(xí)檢測(cè)特定模式,還可以學(xué)習(xí)將這些模式與其他模式關(guān)聯(lián)起來(lái)。在上面的貓的例子中,舉一個(gè)例子,Transformer可以學(xué)習(xí)將貓與其特征點(diǎn)(例如沙發(fā))關(guān)聯(lián)起來(lái)。
如果Transformer可以用于圖像分類(lèi),那么將它們用于目標(biāo)檢測(cè)只是更進(jìn)一步的一步。Carion等人(2020年)已經(jīng)表明,事實(shí)上可以使用基于Transformer的架構(gòu)來(lái)實(shí)現(xiàn)這一點(diǎn)。在他們的工作《使用Transformer進(jìn)行端到端目標(biāo)檢測(cè)》中,他們介紹了檢測(cè)Transformer或DeTr,我們將在今天創(chuàng)建我們的目標(biāo)檢測(cè)流程中使用它。
它的工作原理如下,并且甚至沒(méi)有完全放棄CNN:
- 使用卷積神經(jīng)網(wǎng)絡(luò)從輸入圖像中提取重要特征。這些特征像語(yǔ)言Transformer中一樣進(jìn)行位置編碼,以幫助神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)這些特征在圖像中的位置。
 - 將輸入展平,并使用transformer編碼器和注意力將其編碼為中間狀態(tài)。
 - 變換器解碼器的輸入是這個(gè)狀態(tài)和在訓(xùn)練過(guò)程中獲得的一組學(xué)習(xí)的對(duì)象查詢(xún)。你可以想象它們是在問(wèn):“這里是否有一個(gè)對(duì)象,因?yàn)槲乙郧霸谠S多情況下看到過(guò)?”,這將通過(guò)使用中間狀態(tài)來(lái)回答。
 - 事實(shí)上,解碼器的輸出是通過(guò)多個(gè)預(yù)測(cè)頭進(jìn)行的一組預(yù)測(cè):每個(gè)查詢(xún)一個(gè)。由于DeTr中查詢(xún)的數(shù)量默認(rèn)設(shè)置為100,因此它一次只能預(yù)測(cè)100個(gè)對(duì)象,除非你對(duì)其進(jìn)行不同的配置。
 

Transformer架構(gòu)
HuggingFace Transformers及其目標(biāo)檢測(cè)流程
現(xiàn)在你已經(jīng)了解了DeTr的工作原理,是時(shí)候使用它來(lái)創(chuàng)建一個(gè)真實(shí)的目標(biāo)檢測(cè)流程了!我們將使用HuggingFace Transformers來(lái)實(shí)現(xiàn)這個(gè)目標(biāo),這是為了使NLP和計(jì)算機(jī)視覺(jué)Transformer的工作變得簡(jiǎn)單而構(gòu)建的。事實(shí)上,使用它非常簡(jiǎn)單,因?yàn)槭褂盟恍枰虞dObjectDetectionPipeline——它默認(rèn)加載了一個(gè)使用ResNet-50骨干訓(xùn)練的DeTr Transformer以生成圖像特征。
ObjectDetectionPipeline可以很容易地初始化為一個(gè)pipeline實(shí)例...換句話(huà)說(shuō),通過(guò)pipeline("object-detection")的方式,我們將在下面的示例中看到這一點(diǎn)。當(dāng)你沒(méi)有提供其他輸入時(shí),這就是根據(jù)GitHub(n.d.)初始化管道的方式:
    "object-detection": {
        "impl": ObjectDetectionPipeline,
        "tf": (),
        "pt": (AutoModelForObjectDetection,) if is_torch_available() else (),
        "default": {"model": {"pt": "facebook/detr-resnet-50"}},
        "type": "image",
    },毫不奇怪,使用了一個(gè)ObjectDetectionPipeline實(shí)例,它專(zhuān)門(mén)用于目標(biāo)檢測(cè)。在HuggingFace Transformers的PyTorch版本中,用于此目的的是AutoModelForObjectDetection。正如你所了解的,F(xiàn)acebook/detr-resnet-50模型是默認(rèn)用于獲取圖像特征的:
DEtection TRansformer(DETR)模型在COCO 2017目標(biāo)檢測(cè)(118張帶標(biāo)注圖像)上進(jìn)行了端到端訓(xùn)練。它是由Carrion等人在論文《使用Transformer進(jìn)行端到端目標(biāo)檢測(cè)》中介紹的。
HuggingFace (n.d.)
COCO數(shù)據(jù)集(上下文中的常見(jiàn)對(duì)象)是用于目標(biāo)檢測(cè)模型的標(biāo)準(zhǔn)數(shù)據(jù)集之一,并且已用于訓(xùn)練此模型。不用擔(dān)心,你顯然也可以訓(xùn)練自己基于DeTr的模型!要使用ObjectDetectionPipeline,安裝包含PyTorch圖像模型的timm包是很重要的。確保在尚未安裝時(shí)運(yùn)行以下命令:
pip install timm使用Python實(shí)現(xiàn)簡(jiǎn)單的目標(biāo)檢測(cè)流程
現(xiàn)在讓我們來(lái)看看如何使用Python實(shí)現(xiàn)簡(jiǎn)單的目標(biāo)檢測(cè)解決方案?;叵胍幌?,我們使用的是HuggingFace Transformers,如果你還沒(méi)有安裝它,請(qǐng)運(yùn)行:
pip install transformers我們還假設(shè)PyTorch,這是當(dāng)今領(lǐng)先的深度學(xué)習(xí)庫(kù)之一,已經(jīng)安裝。回想一下上面介紹的ObjectDetectionPipeline將在調(diào)用pipeline("object-detection")時(shí)在底層加載,它沒(méi)有TensorFlow的實(shí)例,因此PyTorch是必需的。這是我們將要運(yùn)行創(chuàng)建的目標(biāo)檢測(cè)流程的圖像,稍后在本文中將會(huì)用到。我們從導(dǎo)入開(kāi)始:
from transformers import pipeline
from PIL import Image, ImageDraw, ImageFont顯然,我們使用了transformers,以及它的pipeline表示。然后,我們還使用了PIL,一個(gè)用于加載、可視化和操作圖像的Python庫(kù)。具體來(lái)說(shuō),我們使用第一個(gè)導(dǎo)入——Image用于加載圖像,ImageDraw用于繪制邊界框和標(biāo)簽,后者還需要ImageFont。說(shuō)到這兩者,接下來(lái)是加載字體(我們選擇Arial)并初始化上面介紹的目標(biāo)檢測(cè)管道。
# Load font
font = ImageFont.truetype("arial.ttf", 40)
# Initialize the object detection pipeline
object_detector = pipeline("object-detection")然后,我們創(chuàng)建一個(gè)名為draw_bounding_box的函數(shù),該函數(shù)將用于繪制邊界框。它接受圖像(im)、類(lèi)別概率、邊界框的坐標(biāo)、該定義將要用于的邊界框列表中的邊界框索引以及該列表的長(zhǎng)度作為輸入。
在函數(shù)中,我們將依次執(zhí)行下面步驟:
- 首先,在圖像上繪制實(shí)際的邊界框,表示為具有紅色的rounded_rectangle bbox,并且半徑較小,以確保邊緣平滑。
 - 其次,在邊界框的上方略微繪制文本標(biāo)簽。
 - 最后,返回中間結(jié)果,這樣我們就可以在其上繼續(xù)繪制下一個(gè)邊界框和標(biāo)簽。
 
# Draw bounding box definition
def draw_bounding_box(im, score, label, xmin, ymin, xmax, ymax, index, num_boxes):
 """ Draw a bounding box. """
 print(f"Drawing bounding box {index} of {num_boxes}...")
 # Draw the actual bounding box
 im_with_rectangle = ImageDraw.Draw(im)  
 im_with_rectangle.rounded_rectangle((xmin, ymin, xmax, ymax), outline = "red", width = 5, radius = 10)
 # Draw the label
 im_with_rectangle.text((xmin+35, ymin-25), label, fill="white", stroke_fill = "red", font = font)
 # Return the intermediate result
 return im剩下的是核心部分——使用管道,然后根據(jù)其結(jié)果繪制邊界框。以下是我們步驟:
- 首先,圖像——我們將其稱(chēng)為street.jpg,并且它位于與Python腳本相同的目錄中——將被打開(kāi)并存儲(chǔ)在im PIL對(duì)象中。我們只需將其提供給初始化的object_detector——這就足夠讓模型返回邊界框了!Transformers庫(kù)會(huì)處理其余部分。
 - 然后,我們將數(shù)據(jù)分配給一些變量,并遍歷每個(gè)結(jié)果,繪制邊界框。
 - 最后,我們將圖像保存到street_bboxes.jpg中。
 
# Open the image
with Image.open("street.jpg") as im:
 # Perform object detection
 bounding_boxes = object_detector(im)
 # Iteration elements
 num_boxes = len(bounding_boxes)
 index = 0
 # Draw bounding box for each result
 for bounding_box in bounding_boxes:
  # Get actual box
  box = bounding_box["box"]
  # Draw the bounding box
  im = draw_bounding_box(im, bounding_box["score"], bounding_box["label"],\
   box["xmin"], box["ymin"], box["xmax"], box["ymax"], index, num_boxes)
  # Increase index by one
  index += 1
 # Save image
 im.save("street_bboxes.jpg")
 # Done
 print("Done!")使用不同的模型/使用自己的模型進(jìn)行目標(biāo)檢測(cè)
如果你創(chuàng)建了自己的模型,或者想要使用不同的模型,那么很容易使用它來(lái)代替基于ResNet-50的DeTr Transformer。這將需要你添加以下導(dǎo)入:
from transformers import DetrFeatureExtractor, DetrForObjectDetection然后,你可以初始化特征提取器和模型,并使用它們初始化object_detector,而不是默認(rèn)的一個(gè)。例如,如果你想將ResNet-101用作你的骨干,那么你可以這樣做:
# Initialize another model and feature extractor
feature_extractor = DetrFeatureExtractor.from_pretrained('facebook/detr-resnet-101')
model = DetrForObjectDetection.from_pretrained('facebook/detr-resnet-101')
# Initialize the object detection pipeline
object_detector = pipeline("object-detection", model = model, feature_extractor = feature_extractor)結(jié)果
以下是我們?cè)谳斎雸D像上運(yùn)行目標(biāo)檢測(cè)流程后得到的結(jié)果:

當(dāng)放大時(shí):
















 
 
 



















 
 
 
 