幾行代碼構(gòu)建全功能的對(duì)象檢測模型,他是如何做到的?
如今,機(jī)器學(xué)習(xí)和計(jì)算機(jī)視覺已成為一種熱潮。我們都看過關(guān)于自動(dòng)駕駛汽車和面部識(shí)別的新聞,可能會(huì)想象建立自己的計(jì)算機(jī)視覺模型有多酷。然而,進(jìn)入這個(gè)領(lǐng)域并不總是那幺容易,尤其是在沒有很強(qiáng)的數(shù)學(xué)背景的情況下。如果你只想做一些小的實(shí)驗(yàn),像PyTorch和TensorFlow這樣的庫可能會(huì)很枯燥。
在本教程中,作者提供了一種簡單的方法,任何人都可以使用幾行代碼構(gòu)建全功能的對(duì)象檢測模型。更具體地說,我們將使用Detecto,這是一個(gè)在PyTorch之上構(gòu)建的Python軟件包,可簡化該過程并向所有級(jí)別的程序員開放。
快速簡單的例子
為了演示如何簡單地使Detecto,讓我們加載一個(gè)預(yù)先訓(xùn)練的模型,并對(duì)以下圖像進(jìn)行推斷:
首先,使用pip下載Detecto軟件包:
pip3 install detecto
然后,將上面的圖像另存為“fruit.jpg”,并在與圖像相同的文件夾中創(chuàng)建一個(gè)Python文件。在Python文件中,編寫以下5行代碼:
- from detectoimport core, utils, visualize
- image = utils.read_image('fruit.jpg')
- model = core.Model()
- labels, boxes, scores = model.predict_top(image)
- visualize.show_labeled_image(image, boxes, labels)
運(yùn)行此文件后(如果你的計(jì)算機(jī)上沒有啟用CUDA的GPU,可能會(huì)花費(fèi)幾秒鐘;稍后再進(jìn)行介紹),你應(yīng)該會(huì)看到類似下面的圖:
作者僅用了5行代碼就完成了所有工作,真的是太棒了。下面是我們每步中分別做的:
1)導(dǎo)入Detecto模塊
2)讀入圖像
3)初始化預(yù)訓(xùn)練模型
4)在圖像上生成最高預(yù)測
5)為預(yù)測繪圖
繪制我們的預(yù)測
Detecto使用來自PyTorch模型動(dòng)物園中的Faster R-CNN ResNet-50 FPN,它能夠檢測大約80種不同的物體,例如動(dòng)物,車輛,廚房用具等。但是,如果你想要檢測自定義對(duì)象,例如可口可樂與百事可樂罐,斑馬與長頸鹿,該怎幺辦呢?
這時(shí)你會(huì)發(fā)現(xiàn),在自定義數(shù)據(jù)集上訓(xùn)練探測器模型同樣簡單; 同樣,你只需要5行代碼,以及現(xiàn)有的數(shù)據(jù)集或花一些時(shí)間標(biāo)記圖像。
構(gòu)建自定義數(shù)據(jù)集
在本教程中,作者將從頭開始構(gòu)建自己的數(shù)據(jù)集。建議你也這樣做,但是如果你想跳過這一步,你可以在這里下載一個(gè)示例數(shù)據(jù)集(從斯坦福的Dog數(shù)據(jù)集修改)。
對(duì)于我們的數(shù)據(jù)集,我們將訓(xùn)練我們的模型來檢測來自RoboSub競賽的水下外星人,蝙蝠和女巫,如下所示:
理想情況下,每個(gè)類至少需要100張圖像。好在每張圖像中可以有多個(gè)對(duì)象,所以理論上,如果每張圖像包含你想要檢測的每類對(duì)象,那幺你可以總共獲得100張圖像。另外,如果你有視頻素材,Detico可以輕松地將這些視頻素材分割成可用于數(shù)據(jù)集的圖像:
- from detecto.utilsimport split_video
- split_video('video.mp4','frames/', step_size=4)
上面的代碼在“video.mp4”中每第4幀拍攝一次,并將其另存為JPEG文件存在“frames”文件夾中。
生成訓(xùn)練數(shù)據(jù)集后,應(yīng)該具有一個(gè)類似于以下內(nèi)容的文件夾:
- images/
- | image0.jpg
- | image1.jpg
- | image2.jpg
- | ...
如果需要的話,你還可以使用另一個(gè)文件夾,其中包含一組驗(yàn)證圖像。
現(xiàn)在是耗時(shí)的部分:標(biāo)記。Detecto支持PASCAL VOC格式,其中具有XML文件,其中包含圖像中每個(gè)對(duì)象的標(biāo)簽和位置數(shù)據(jù)。要?jiǎng)?chuàng)建這些XML文件,可以使用開源LabelImg工具,如下所示:
- pip3 install labelImg # Download LabelImg using pip
- labelImg # Launch the application
現(xiàn)在,你應(yīng)該會(huì)看到一個(gè)彈出窗口。單擊左側(cè)“打開目錄”按鈕,然后選擇想要標(biāo)記的圖像文件夾。如果一切正常,你應(yīng)該會(huì)看到類似以下內(nèi)容:
要繪制邊界框,請單擊左側(cè)菜單欄中的圖標(biāo)(或使用鍵盤快捷鍵“w”)。然后,你可以在對(duì)象周圍拖動(dòng)一個(gè)框并編寫/選擇標(biāo)簽:
標(biāo)記完圖像后,請使用CTRL+S或CMD+S保存XML文件(為簡便起見,你可以使用自動(dòng)填充的默認(rèn)文件位置和名稱)。要標(biāo)記下一張圖像,請單擊“下一張圖像”(或使用鍵盤快捷鍵“d”)。
整個(gè)數(shù)據(jù)集處理完畢之后,你的文件夾應(yīng)如下所示:
- images/
- | image0.jpg
- | image0.xml
- | image1.jpg
- | image1.xml
- | ...
我們已經(jīng)準(zhǔn)備好開始訓(xùn)練我們的對(duì)象檢測模型了!
訪問GPU
首先,檢查你的計(jì)算機(jī)是否具有啟用CUDA的GPU。由于深度學(xué)習(xí)需要大量處理能力,因此在通常的CPU上進(jìn)行訓(xùn)練可能會(huì)非常緩慢。值得慶幸的是,大多數(shù)現(xiàn)代深度學(xué)習(xí)框架(例如PyTorch和Tensorflow)都可以在GPU上運(yùn)行,從而使處理速度更快。 確保已經(jīng)下載了PyTorch(如果你安裝了Detecto,應(yīng)該已經(jīng)下載了),然后運(yùn)行以下兩行代碼:
- import torch
- print(torch.cuda.is_available())
如果打印True,那你可以跳到下一部分。如果顯示False,不要擔(dān)心。請按照以下步驟創(chuàng)建Google Colaboratory筆記本,這是一個(gè)在線編碼環(huán)境,帶有免費(fèi)可用的GPU。對(duì)于本教程,你將只在Google Drive文件夾中工作,而不是在計(jì)算機(jī)上工作。
1)登錄到Google Drive
2)創(chuàng)建一個(gè)名為“Detecto Tutorial”的文件夾并導(dǎo)航到該文件夾
3)將你的訓(xùn)練圖像(和/或驗(yàn)證圖像)上傳到此文件夾
4)右鍵單擊,轉(zhuǎn)到“更多”,然后單擊“Google Colaboratory”:
你現(xiàn)在應(yīng)該看到這樣的界面:
5)根據(jù)需要給筆記本起個(gè)名字,然后轉(zhuǎn)到“編輯”->“筆記本設(shè)置”->“硬件加速器”,然后選擇“GPU”
6)輸入以下代碼以“裝入”你的云端硬盤,將目錄更改為當(dāng)前文件夾,然后安裝Detecto:
- import os
- from google.colabimport drive
- drive.mount('/content/drive')
- os.chdir('/content/drive/My Drive/Detecto Tutorial')
- !pip install detecto
為了確保一切正常,你可以創(chuàng)建一個(gè)新的代碼單元,然后輸入 !ls 以檢查你是否處于正確的目錄中。
訓(xùn)練自定義模型
最后,我們現(xiàn)在可以在自定義數(shù)據(jù)集上訓(xùn)練模型了。如前所述,這是容易的部分。它只需要4行代碼:
- from detectoimport core, utils, visualize
- dataset = core.Dataset('images/')
- model = core.Model(['alien','bat','witch'])
- model.fit(dataset)
讓我們再次分解一下我們每行代碼所做的工作:
1、導(dǎo)入的Detecto模塊
2、從“images”文件夾(包含我們的JPEG和XML文件)創(chuàng)建了一個(gè)數(shù)據(jù)集
3、初始化模型檢測自定義對(duì)象(外星人,蝙蝠和女巫)
4、在數(shù)據(jù)集上訓(xùn)練我們的模型
根據(jù)數(shù)據(jù)集的大小,這可能需要10分鐘到1個(gè)小時(shí)以上的時(shí)間來運(yùn)行,因此請確保你的程序在完成上述語句后不會(huì)立即退出(例如:你使用的是Jupyter / Colab筆記本,它在活動(dòng)時(shí)保留狀態(tài))。
使用訓(xùn)練好的模型
現(xiàn)在你已經(jīng)有了訓(xùn)練好的模型,讓我們在一些圖像上對(duì)其進(jìn)行測試。要從文件路徑讀取圖像,可以使用 detecto.utils 模塊中的 read_image 函數(shù)(也可以使用上面創(chuàng)建的數(shù)據(jù)集中的圖像):
- # Specify the path to your image
- image = utils.read_image('images/image0.jpg')
- predictions = model.predict(image)
- # predictions format: (labels, boxes, scores)
- labels, boxes, scores = predictions
- # ['alien', 'bat', 'bat']
- print(labels)
- # xmin ymin xmax ymax
- # tensor([[ 569.2125, 203.6702, 1003.4383, 658.1044],
- # [ 276.2478, 144.0074, 579.6044, 508.7444],
- # [ 277.2929, 162.6719, 627.9399, 511.9841]])
- print(boxes)
- # tensor([0.9952, 0.9837, 0.5153])
- print(scores)
正像你看到的,模型的預(yù)測方法返回一個(gè)由3個(gè)元素組成的元組:標(biāo)簽,方框和分?jǐn)?shù)。在上面的示例中,此模型在坐標(biāo)[569、204、1003、658](框[0])處預(yù)測了一個(gè)外星人(標(biāo)簽[0]),其置信度為0.995(得分[0])。
根據(jù)這些預(yù)測,我們可以使用 detecto.visualize 模塊繪制結(jié)果。例如:
- visualize.show_labeled_image(image, boxes, labels)
將上面的代碼與收到的圖像和預(yù)測一起運(yùn)行將產(chǎn)生如下所示的內(nèi)容:
如果你有一個(gè)視頻,你可以在它上面運(yùn)行對(duì)象檢測:
- visualize.detect_video(model,'input.mp4','output.avi')
這將獲取一個(gè)名為“input.mp4”的視頻文件,并根據(jù)給定模型的預(yù)測結(jié)果生成一個(gè)“output.avi”文件。如果你使用VLC或其他視頻播放器打開此文件,應(yīng)該會(huì)看到一些希望看到的結(jié)果!
最后,你可以從文件中保存和加載模型,從而可以保存進(jìn)度并稍后返回:
- model.save('model_weights.pth')
- # ... Later ...
- model = core.Model.load('model_weights.pth', ['alien','bat','witch'])
高級(jí)用法
你會(huì)發(fā)現(xiàn)Detecto不僅限于5行代碼。舉例來說,這個(gè)模型沒有你希望的那幺好。我們可以嘗試通過使用Torchvision轉(zhuǎn)換來擴(kuò)展我們的數(shù)據(jù)集并定義一個(gè)自定義數(shù)據(jù)加載器來提高其性能:
- from torchvisionimport transforms
- augmentations = transforms.Compose([
- transforms.ToPILImage(),
- transforms.RandomHorizontalFlip(0.5),
- transforms.ColorJitter(saturation=0.5),
- transforms.ToTensor(),
- utils.normalize_transform(),
- ])
- dataset = core.Dataset('images/', transform=augmentations)
- loader = core.DataLoader(dataset, batch_size=2, shuffle=True)
此代碼對(duì)數(shù)據(jù)集中的圖像應(yīng)用了隨機(jī)的水平翻轉(zhuǎn)和飽和效果,從而增加了數(shù)據(jù)的多樣性。然后,我們使用 batch_size = 2 定義一個(gè)數(shù)據(jù)加載對(duì)象;我們將其傳遞給 model.fit 而不是Dataset,這樣來告訴我們的模型是對(duì)2張圖像進(jìn)行批量訓(xùn)練,而不是默認(rèn)的1張。
如果你之前創(chuàng)建了單獨(dú)的驗(yàn)證數(shù)據(jù)集,那幺現(xiàn)在是在訓(xùn)練期間加載它的時(shí)候了。通過提供驗(yàn)證數(shù)據(jù)集, fit 方法將返回每個(gè)時(shí)期的損失列表,如果 verbose = True ,則會(huì)在訓(xùn)練過程中將其打印出來。以下代碼塊演示了這一點(diǎn),并自定義了其他幾個(gè)訓(xùn)練參數(shù):
- import matplotlib.pyplotas plt
- val_dataset = core.Dataset('validation_images/')
- losses = model.fit(loader, val_dataset, epochs=10, learning_rate=0.001,
- lr_step_size=5, verbose=True)
- plt.plot(losses)
- plt.show()
損失的結(jié)果圖應(yīng)或多或少地減少:
為了更具有靈活性和對(duì)模型的控制,你可以完全繞過Detecto。你可以根據(jù)需要隨意調(diào)整 model.get_internal_model 方法返回使用的基礎(chǔ)模型。
結(jié)論
在本教程中,作者展示了計(jì)算機(jī)視覺和對(duì)象檢測不需要具有挑戰(zhàn)性。你所需要的是一點(diǎn)時(shí)間和耐心來處理標(biāo)記的的數(shù)集。
如果你對(duì)進(jìn)一步探索感興趣的話,請查看Detecto on GitHub或訪問文檔以獲取更多教程和用例!