基于 Python 和 HuggingFace Transformers 的目標(biāo)檢測
YOLO!如果你對機(jī)器學(xué)習(xí)感興趣,這個(gè)術(shù)語一定不陌生。確實(shí),You Only Look Once已經(jīng)成為過去幾年中目標(biāo)檢測的默認(rèn)方法之一。受到卷積神經(jīng)網(wǎng)絡(luò)取得的進(jìn)展推動(dòng),許多版本的目標(biāo)檢測方法已經(jīng)被創(chuàng)建。然而,近年來,一個(gè)競爭對手出現(xiàn)在了視野中——那就是在計(jì)算機(jī)視覺中使用基于Transformer的模型。更具體地說,是使用Transformer進(jìn)行目標(biāo)檢測。
在今天的教程中,你將了解到這種類型的Transformer模型。你還將學(xué)會使用Python、一個(gè)默認(rèn)的Transformer模型和HuggingFace Transformers庫創(chuàng)建自己的目標(biāo)檢測流程。本文將按照下列步驟講解:
- 了解目標(biāo)檢測可以用來做什么
- 了解當(dāng)Transformer用于目標(biāo)檢測時(shí)它們是如何工作的
- 已經(jīng)使用Python和HuggingFace Transformers實(shí)現(xiàn)了基于Transformer模型的(圖像)目標(biāo)檢測流程
什么是目標(biāo)檢測?
環(huán)顧四周,很可能你會看到很多東西——可能是一臺電腦顯示器、一個(gè)鍵盤和鼠標(biāo),或者當(dāng)你在移動(dòng)瀏覽器中瀏覽時(shí),是一部智能手機(jī)。這些都是物體,是特定類別的實(shí)例。例如,在下面的圖像中,我們看到一個(gè)人類類別的實(shí)例。我們還看到了許多瓶子類別的實(shí)例。雖然類別是藍(lán)圖,但物體是真實(shí)存在的,具有許多獨(dú)特的特征,同時(shí)因?yàn)楣蚕淼奶卣鞫鴮儆陬悇e的成員。
在圖片和視頻中,我們看到了許多這樣的物體。例如,當(dāng)你拍攝交通視頻時(shí),很可能會看到許多行人、汽車、自行車等實(shí)例。知道它們在圖像中存在是非常有益的。為什么呢?因?yàn)槟憧梢杂?jì)數(shù)它們,舉一個(gè)例子。這可以讓你對社區(qū)的擁擠程度有所了解。另一個(gè)例子是在繁忙地區(qū)檢測到一個(gè)停車位,讓你可以停車。
目標(biāo)檢測和Transformer
傳統(tǒng)上,目標(biāo)檢測是通過卷積神經(jīng)網(wǎng)絡(luò)來實(shí)現(xiàn)的。通常,它們的架構(gòu)是專門針對目標(biāo)檢測設(shè)計(jì)的,因?yàn)樗鼈儗D像作為輸入并輸出圖像的邊界框。如果你熟悉神經(jīng)網(wǎng)絡(luò),你就知道卷積網(wǎng)絡(luò)在學(xué)習(xí)圖像中的重要特征方面非常有用,并且它們是空間不變的——換句話說,學(xué)習(xí)對象在圖像中的位置或大小是無關(guān)緊要的。如果網(wǎng)絡(luò)能夠看到對象的特征,并將其與特定類別關(guān)聯(lián)起來,那么它就能識別出來。例如,許多不同的貓都可以被識別為貓類的實(shí)例。
然而,最近,在深度學(xué)習(xí)領(lǐng)域,特別是自然語言處理領(lǐng)域,Transformer架構(gòu)引起了人們的極大關(guān)注。Transformer通過將輸入編碼為高維狀態(tài),然后將其解碼回所需的輸出來工作。通過聰明地使用自注意力的概念,Transformer不僅可以學(xué)習(xí)檢測特定模式,還可以學(xué)習(xí)將這些模式與其他模式關(guān)聯(lián)起來。在上面的貓的例子中,舉一個(gè)例子,Transformer可以學(xué)習(xí)將貓與其特征點(diǎn)(例如沙發(fā))關(guān)聯(lián)起來。
如果Transformer可以用于圖像分類,那么將它們用于目標(biāo)檢測只是更進(jìn)一步的一步。Carion等人(2020年)已經(jīng)表明,事實(shí)上可以使用基于Transformer的架構(gòu)來實(shí)現(xiàn)這一點(diǎn)。在他們的工作《使用Transformer進(jìn)行端到端目標(biāo)檢測》中,他們介紹了檢測Transformer或DeTr,我們將在今天創(chuàng)建我們的目標(biāo)檢測流程中使用它。
它的工作原理如下,并且甚至沒有完全放棄CNN:
- 使用卷積神經(jīng)網(wǎng)絡(luò)從輸入圖像中提取重要特征。這些特征像語言Transformer中一樣進(jìn)行位置編碼,以幫助神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)這些特征在圖像中的位置。
- 將輸入展平,并使用transformer編碼器和注意力將其編碼為中間狀態(tài)。
- 變換器解碼器的輸入是這個(gè)狀態(tài)和在訓(xùn)練過程中獲得的一組學(xué)習(xí)的對象查詢。你可以想象它們是在問:“這里是否有一個(gè)對象,因?yàn)槲乙郧霸谠S多情況下看到過?”,這將通過使用中間狀態(tài)來回答。
- 事實(shí)上,解碼器的輸出是通過多個(gè)預(yù)測頭進(jìn)行的一組預(yù)測:每個(gè)查詢一個(gè)。由于DeTr中查詢的數(shù)量默認(rèn)設(shè)置為100,因此它一次只能預(yù)測100個(gè)對象,除非你對其進(jìn)行不同的配置。
Transformer架構(gòu)
HuggingFace Transformers及其目標(biāo)檢測流程
現(xiàn)在你已經(jīng)了解了DeTr的工作原理,是時(shí)候使用它來創(chuàng)建一個(gè)真實(shí)的目標(biāo)檢測流程了!我們將使用HuggingFace Transformers來實(shí)現(xiàn)這個(gè)目標(biāo),這是為了使NLP和計(jì)算機(jī)視覺Transformer的工作變得簡單而構(gòu)建的。事實(shí)上,使用它非常簡單,因?yàn)槭褂盟恍枰虞dObjectDetectionPipeline——它默認(rèn)加載了一個(gè)使用ResNet-50骨干訓(xùn)練的DeTr Transformer以生成圖像特征。
ObjectDetectionPipeline可以很容易地初始化為一個(gè)pipeline實(shí)例...換句話說,通過pipeline("object-detection")的方式,我們將在下面的示例中看到這一點(diǎn)。當(dāng)你沒有提供其他輸入時(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í)例,它專門用于目標(biāo)檢測。在HuggingFace Transformers的PyTorch版本中,用于此目的的是AutoModelForObjectDetection。正如你所了解的,F(xiàn)acebook/detr-resnet-50模型是默認(rèn)用于獲取圖像特征的:
DEtection TRansformer(DETR)模型在COCO 2017目標(biāo)檢測(118張帶標(biāo)注圖像)上進(jìn)行了端到端訓(xùn)練。它是由Carrion等人在論文《使用Transformer進(jìn)行端到端目標(biāo)檢測》中介紹的。
HuggingFace (n.d.)
COCO數(shù)據(jù)集(上下文中的常見對象)是用于目標(biāo)檢測模型的標(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)簡單的目標(biāo)檢測流程
現(xiàn)在讓我們來看看如何使用Python實(shí)現(xiàn)簡單的目標(biāo)檢測解決方案。回想一下,我們使用的是HuggingFace Transformers,如果你還沒有安裝它,請運(yùn)行:
pip install transformers
我們還假設(shè)PyTorch,這是當(dāng)今領(lǐng)先的深度學(xué)習(xí)庫之一,已經(jīng)安裝?;叵胍幌律厦娼榻B的ObjectDetectionPipeline將在調(diào)用pipeline("object-detection")時(shí)在底層加載,它沒有TensorFlow的實(shí)例,因此PyTorch是必需的。這是我們將要運(yùn)行創(chuàng)建的目標(biāo)檢測流程的圖像,稍后在本文中將會用到。我們從導(dǎo)入開始:
from transformers import pipeline
from PIL import Image, ImageDraw, ImageFont
顯然,我們使用了transformers,以及它的pipeline表示。然后,我們還使用了PIL,一個(gè)用于加載、可視化和操作圖像的Python庫。具體來說,我們使用第一個(gè)導(dǎo)入——Image用于加載圖像,ImageDraw用于繪制邊界框和標(biāo)簽,后者還需要ImageFont。說到這兩者,接下來是加載字體(我們選擇Arial)并初始化上面介紹的目標(biāo)檢測管道。
# 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)、類別概率、邊界框的坐標(biāo)、該定義將要用于的邊界框列表中的邊界框索引以及該列表的長度作為輸入。
在函數(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é)果繪制邊界框。以下是我們步驟:
- 首先,圖像——我們將其稱為street.jpg,并且它位于與Python腳本相同的目錄中——將被打開并存儲在im PIL對象中。我們只需將其提供給初始化的object_detector——這就足夠讓模型返回邊界框了!Transformers庫會處理其余部分。
- 然后,我們將數(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)檢測
如果你創(chuàng)建了自己的模型,或者想要使用不同的模型,那么很容易使用它來代替基于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é)果
以下是我們在輸入圖像上運(yùn)行目標(biāo)檢測流程后得到的結(jié)果:
當(dāng)放大時(shí):