五分鐘認識用 YOLO 做血液抹片物件偵測(Object Detection)

物件偵測(Object Detection)的目的,在找出物體的範圍、座標框,接著再做分類。這次,讓我們來瞧瞧如何運用物件偵測的深度學習模型,來讓 YOLO 看懂三大血球吧!

還記得在台大兒科血液腫瘤科病房時,無論病房事務多麽龐雜,每個禮拜都會有老師手把手帶我們在總院病理檢驗科或兒醫高層樓研究室看顯微鏡底下的血片,觀賞老師精湛高深的血球辨識藝術。你知道嗎?或許最精細困難的辨別還是需要專業人員做得最好,但 YOLO 竟然在稍經訓練後,也能通過初階的三大血球會面考呢!

攝影師:Artem Podrez,連結:Pexels

物件偵測(Object Detection)的目的,在找出物體的範圍、座標框,接著再做分類。針對「預測被拆成幾個步驟來做」,現在主流上分成兩種方式:One Stage 與 Two Stages,最初期多數是用 Two / Many Stages,像 R-CNN、Fast R-CNN,第一階段先試著找出各種圖中有可能有東西的部位,第二階段則一張張的內容切下來送入分類網路 Classifier 做分類 Region Classification、並修正微調原本找到的範圍 Box Regression,就能預測出圖中被分類的物體和座標大小。目前更多人用的是 One Stage,圖片 Input 後模型會一次產出所有資訊,包含物體的框框和分類結果,濃縮集合在模型裡,只要有圖片和正確結果的框框,把正確答案框框轉換成模型預測出 Tensor 可以對答案、計算 Loss 的格式,我們就能直接訓練,不用分成兩個階段,訓練起來比較快、更簡單,精確度也非常接近,成為常見的應用,像是能 Real-Time 做物件偵測的 YOLO(You Only Look Once)。

Source

物件偵測標註物體座標和分類類別的方式有很多,原則上座標須記錄 X 與 Y 的位置,像 VOC Dataset 用 X、Y 的最小及最大值,去找出長方形框框左上和右下角的座標,瞭解實際的範圍在哪裏,類別則放在 Object 的 Name 裡,標註完就能做物件偵測的訓練。YOLO v1-v3 的作者有個很有趣的示範影片,把影片拆成一張張 2D 的圖片依序通過模型做物件偵測,再將結果儲存、串連起來,不過有個把房子誤判成火車的小 Bug,個人覺得其實蠻像的 😆
https://arxiv.org/abs/1506.02640

Source

YOLO v1-v3 的核心思想沒有差異很大,我們從 v1 開始聊起。YOLO 的想法是把圖片切成 7×7 = 49 等份,每個邊 7 格(Grid / Cell),考量到物件偵測要做分類,所以針對每 1 個 Grid 的範圍預測類別(有點類似 Segmentation 是把每個 Pixel 做分類),總共有 49 個分類的結果;每個 Grid 也會以內部為基準,預測 2 個大小不同的框框、以及它們的機率值,機率值越大,代表模型覺得該處越有可能存在物體,框線也越粗,這些 Box 的中心點都是落在該 Grid 內部,不會超出格子範圍。無論圖片中有沒有物體,每一個 Grid 都還是會預測出 2 個框框座標的中心點座標 (x, y)、物體的寬度 (w) 及高度 (h) 共 4 個數值,我們就能畫出該 Box 實際的範圍邊界,若 YOLO 覺得沒有物體則會以較小的機率值輸出。因此,YOLO v1 會有 49 (Grid) x 2 (Box/Grid) = 98 Boxes 總共 98 個框框,去標出模型覺得有可能存在的物體,並用框線粗細表示機率值高低;此外,每個 Grid 也會預測它各自的分類,以不同顏色顯現。把兩者結合起來,我們就能針對每個框框根據對應區域分類的結果來上色、視覺化,也是模型的直接輸出。但 98 個框框有點太多,為了去蕪存菁,我們把機率值太低、不太可能是物體的框框過濾掉,並以 NMS 去合併預測為同類別的框框,轉換後才是模型看起來比較舒服的結果。[微註記:如果是 3D 影像,中心點座標 (x, y) 還要加上 z、物體除了寬高還要加上深度 d]

Source: https://arxiv.org/pdf/1506.02640.pdf

YOLO Model Input 大小為 448 x 448,接上卷積層 CNN 特徵抽取、全連接層做座標與類別的預測,最後得到一疊形狀是 (7, 7, 30) 的 Tensors 輸出,7 x 7 是 YOLO 把圖切成 7 等份的 Grid Size,30 則是物體偵測和分類的資訊合併結果。為什麼是 Feature Maps Dimension 長度是 30 呢?以 v1 來說,前 5 個數值是 YOLO 在該 Grid 所預測出第 1 個框框的資訊 (x, y, w, h, c),分別是 x 座標、y 座標、預測寬度、預測高度(前 4 個數值可以繪出 Box)、物體存在的機率值(Confidence 0–1,機率越大,代表模型覺得越有可能有東西),第 6–10 個數值則是預測出第 2 個框框的數值,剩下的 20 個是 VOC Dataset 預測的 20 種物體分類機率值,總共是長度為 30 的向量,圖中 49 個 Grid 都會做一樣的事。

Source

計算預測結果和正確答案誤差的 YOLO Loss 稍微複雜,主要拆成三大塊:
1️⃣ 計算 98 個 Bounding Box 座標、尺寸大小上的誤差,如果該 Grid 有物體,就需要做計算
2️⃣ 如果該 Grid 有物體,預測出的機率值應該要越靠近 1;如果沒有東西,機率值越接近 0 越好
3️⃣ 分類的誤差

總結來說,YOLO v1 的 Output 有 7x7x30 個數值,30 代表 VOC Dataset 裡的 20 個類別,以及每個 Grid 預測出 2 個框框的 5 個數值(w, h, x, y, confidence)、1 個分類結果。

Source

就像前面說的,Model 預測出這麼多數值,勢必要有去蕪存菁的方法,這時再次用到我們聊 Segmentation 時用到的 IOU(Intersection Over Union)概念,比較預測出和實際的範圍重疊程度有多少。而最主要的方法,是用 NMS(Non-Maximum Suppression)來把許多框框合併起來,原則是「不是最大的,就把它去掉」:YOLO 除了框框和類別之外,還會預測出 c 值,數值越大代表該處越有可能有物體存在。以狗狗的 5 個框框為例,我們把這 5 個框框的 c 值列出來,從高排到低,第 1 回合先把最高的 (0.9) 取出來,計算第一名和其他 4 個框框的 IOU、看它們的重合程度,接著依照我們訂的 Threshold 門檻值 (0.5) 來決定,只要超過門檻值,代表我們認為它們是一樣的東西,所以把 c 值較小、但 IOU 超過門檻值的其他框框砍掉;第 2 回合依樣畫葫蘆,把剩下來最高的 (0.89) 取出來,計算和剩下其他 2 個框框的 IOU,發現都超過門檻值,代表是重複的預測,因此也把它們砍掉;一路做到結束,剩下來就是 NMS 合併重複預測後的結果,也是人類比較習慣的輸出。[微註記:不同類別重複預測是不會被合併的,NMS 只針對相同類別做合併]

Source

物件偵測衡量的指標,稱作 mAP(Mean Average Precision),針對單一類別做計算;譬如我們把模型預測出來的所有狗狗依照 c 值做排序,跟正確答案做比對,預測命中為 True、沒中是 False,在第一和第二名之間取個門檻值,計算門檻值以上的 Precision(預測結果正確:模型說有狗狗,結果也真的有狗)及 Recall(整張圖裡真正的狗狗,我們抓到幾隻)分別是多少,以此類推去計算第二和第三名、第三和第四名… 的 Precision 和 Recall,以 Precision 為縱軸、Recall 為橫軸畫圖,再把 Precision 在特定 Recall 範圍內的值補成階梯,代表預測結果類別的準確度,原則上 Precision 越低(精準度)、Recall 會越高(把想要的東西抓出來),兩者算是等價的交換。mAP 就是計算階梯底下的面積,面積越大、結果越好,越往右上角接近、模型越完美,代表我們說那裡有隻狗狗、那裡就真的有隻狗狗。

Source

除了 YOLO 之外,還有 SSD(Single Shot MultiBox Detector)這個模型也在做物件偵測,兩者的架構類似,差別在於 YOLO 只有 1 組輸出,v1 單次最多就是預測 98 個物件,而 SSD 會有很多組不同大小的預測輸出;且 YOLO 是預測物體座標和大小,SSD 則引入 Anchor Box 的概念,預先定義好一些大小不同的框框,預測時不需去看物體有多大,反而是要如何放大或縮小原先定義好的框框,也就是預測放大縮小的「比例」。

Source

YOLO v2 和 v1 差距沒有很大,v1 在單個 Grid 預測 2 個 Box 和 1 個分類結果,分類是以「區塊」為基準,但 2 個框框只能是同一個分類的結果,但如果有兩個正確答案(譬如重疊的兩個物體,中心點落在同個區塊內),v1 是無法區分這兩個類別的,會帶有相同的分類結果。v2 為了解決這個問題,在每個框框預測時,都有屬於它們各自的分類,此時分類是跟著框框、而不是跟著區塊來走,除了原本的 5 個數值(w, h, x, y, confidence),還要加上 20 個類別,因此每個框框都有 25 個數值來代表。此外,v2 也把原本的區塊切得更細,從 7 x 7 換成 13 x 13,每個區塊又預測 5 個框框,故 Output = 13 * 13 * (Classes + 5 分類加上座標資訊) * 5 Bounding Boxes,更引用 Anchor Boxes 預先定義好寬度、高度的框框,預測的是從左上角往右下角要移動多少個單位、長寬放大縮小的比例,就不會直接輸出預測的寬度和高度。目前主流是 Anchor-Based,比較準確、但需要自行換算座標,比較複雜一點。

Source

YOLO v3 在 CNN Model 設計出 Darknet-53 架構,比較輕量化,用 1 x 1 和 3 x 3 的 Convolution 加上 ResNet 的 Residual 概念整合起來。基本的 Darknetconv2D 是 Convolution + Batch Normalization + Leaky Relu 構成元素,再串上 ResNet 的 res unit,重複好幾次做成 Resblock_body 成為它的骨幹,之後的其中一個分支為 13 x 13 x 255,第二和第三個分支則用到類似 UNet 把輸出前的一層放大兩倍、再和之前的 Resblock_body Concat 在一起輸出,變成 26 x 26 x 255,第三分支再放大兩倍為 52 x 52 x 255。因此和 v2 不同的是,v3 輸出了 3 組不同的結果,255 = 3 * (5 + 80),因為 v3 用的 Dataset 有 80 個類別,所以每個 Bounding Box 有 85 個數值,而每個 Grid 會預測 3 個 Box,所以深度就是 255,和預測的類別有關而變動,譬如預測 10 類的 v3 深度變成 3 * (5+10)。

Source

YOLO v2 的模型輸出只有 1 組 13 x 13,偵測小物件的準確度不高,v3 就透過不同細緻程度的 Output 來提高小物件偵測的表現,以下放 v2 和 v3 的 github 讓各位朋友參考。v4 則在 CNN 架構和訓練方法有更多的嘗試,但變革幅度沒有 v1 — v3 那麼顯著~
https://github.com/experiencor/keras-yolo2
https://github.com/qqwweee/keras-yolo3

我們今天就用 YOLO 來針對血液抹片三類最基本的血球:白血球、紅血球、血小板做辨識吧!

from utils import DataGenerator, read_annotation_lines
from models import Yolov4
from config import yolo_config
import os
from glob import glob
import numpy as np

train_lines, val_lines = read_annotation_lines('./dataset/train_txt/anno.txt', test_size=0.2)
IMG_FOLDER_PATH = './'
class_name_path = os.path.join(FOLDER_PATH, 'class_names/bccd_classes.txt') # bccd_classes or aoi_classes
data_gen_train = DataGenerator(train_lines, class_name_path, IMG_FOLDER_PATH)
data_gen_val = DataGenerator(val_lines, class_name_path, IMG_FOLDER_PATH)

model = Yolov4(weight_path=None, 
               class_name_path=class_name_path)

model.fit(data_gen_train, 
          initial_epoch=0,
          epochs=10000, 
          val_data_gen=data_gen_val)

標註的文件 xml 檔案是每張圖片記錄的座標位置,由文字可見這張血片 jpg 檔第一個 Object 是 WBC(白血球),座標位置被放在 <bndbox> 的標籤裡。

接著我們再把 xml 轉為單一座標檔案 txt 加上額外訓練參數、訓練類別的名稱來訓練。DataGenerator 是把單張血片和正確答案對應起來、座標位置的換算,再送到 Yolov4 的 Model 去訓練;由隨機的血片預測圖來看,除了 Bounding Box 之外,還會有分類、預測機率值,表格就能一目瞭然座標位置、分類、機率值、物件寬高度等。

希望各位朋友會喜歡這次對於物件偵測的介紹、和淺顯在醫療上相關的應用,下次讓我們再來瞧瞧深度學習的理論與實例吧 😍

#CC

Leave a Reply

Your email address will not be published. Required fields are marked *