WWDC 2019 session 222 Understanding Images in Vision Framework算法
Vision 是 Apple 2017 年和 Core ML 一塊兒推出的、基於 Core ML 封裝的圖像識別庫。根據官方文檔看,Vision 包含就有人臉識別、機器學習圖片分析、條形碼識別、文字識別等基礎功能。數組
本文主要介紹了 Vision 框架在圖像技術方面的一些酷炫功能,並必定程度上闡述了其原理。bash
Saliency 直譯成中文就是:顯著、凸起、特色。那麼在 Vision 框架之中,Saliency 究竟指的是什麼呢?先直接上圖:網絡
當咱們第一次看到左側這張圖片時,視線必定是最早被這三張鳥臉 (海雀臉) 吸引的。若是把注意力集中的地方,用高光在圖片中標註出來,那麼大概就是第二張圖這樣:高光集中於鳥的頭部。session
這些高光部分,也就是人類注意力更容易集中地部分,實際上就是一種 Saliency (即基於注意力的 Saliency),而高光事後的效果圖實際上就是 Saliency 的熱力圖 (The Heatmap)。app
這兩種 Saliency 在算法上就有着比較明顯的不一樣。基於注意力的 Saliency 實際上就是直觀的由人類注意力的集中程度來斷定,而基於物體的 Saliency 目的是識別出焦點物體,而後將焦點物體分割出來。框架
因此效果圖如上,中間的圖是基於注意力的結果,咱們一般關注的是人物、動物的面部,因此只有面部附近會高亮。而右邊的圖將整個鳥都高亮了出來,是基於物體的結果。好比下面這張圖,也是一樣的道理:機器學習
實際上,基於注意力的 Saliency 會更爲複雜。其實咱們也能直觀地感覺到,由於注意力自己就會受到太多人爲的不肯定因素的影響,好比畫面對比度、人物面部、畫面主題、視野範圍、光線強度等。有意思的是,它甚至會被持續的運動狀態所影響,好比下圖中,基於注意力的 Saliency 將人物行進路線前方的部分區域也進行了高亮:ide
具體的 Demo 能夠參見:高亮圖片中使人感興趣的部分性能
熱力圖的概念很容易理解,那麼如何獲取 Saliency 熱力圖呢?Vision API 設計的基本使用邏輯就是 handler 搭配 request。經過建立 handler (VNImageRequestHandler, Vision 圖片處理中最主要的 Handler) 以後調用 perform(_:) 方法,執行相應的 request (VNGenerateAttentionBasedSaliencyImageRequest,從名字就能夠看出,關鍵詞 AttentionBasedSaliency),具體代碼以下:
let handler = VNImageRequestHandler(url: imageURL)
let request: VNImageBasedRequest = VNGenerateAttentionBasedSaliencyImageRequest()
request.revision = VNGenerateAttentionBasedSaliencyImageRequestRevision1
try? handler.perform([request])
guard let result = request.results?.first
let observation = result as? VNSaliencyImageObservation
else { fatalError("missing result") }
let pixelBuffer = observation.pixelBuffer
複製代碼
var boundingBox: CGRect { get }
複製代碼
Bounding boxes 就是探測出來的 Saliency 的位置信息,不過須要注意的是,座標系的原點在圖片左下角。對於基於注意力的 Saliency 來講,只有惟一的 bounding box,而基於物體的 Saliency 則最多有三個 bounding box。
獲取 bounding box 代碼以下:
func addSalientObjects(in observation: VNSaliencyImageObservation,
to path: CGMutablePath,
transform: CGAffineTransform)
{
guard let objects = observation.salientObjects else { return }
for object in objects {
// 獲得 bounding box
path.addRect(object.boundingBox, transform:transform)
}
}
複製代碼
獲得圖片 Saliency 以後其實有不少做用,具體舉幾個例子:
圖片識別、分類是 Vision 的最基礎功能,Vision 框架提供了用於圖片分類的 API,使用起來很是方便,iPhone 相冊中就有大量使用。雖然 coreML 框架也能使用本身訓練圖片分類器,須要大量的數據以及計算資源等,對於普通開發者來講具備比較大的成本。並且 Vision 框架使用了多標籤分類網絡(Multi-label network)能夠在一張圖裏面識別出多個物體。
到底哪些 object 能夠被識別?這就要引出 Taxonomy 的概念了。Taxonomy 實際上指的是生物學上的分類系統,不一樣物體根據語義上的含義被分類。在這個樹狀結構中,有超過 1000 個分類,父類更加寬泛,子類更加具體。
也能夠經過下面的語句,查看整個 Taxonomy:
// List full taxonomy with
VNClassifiyImageRequest.knownClassifications(forRevision: VNClassifyImageRequestRevision1 )
複製代碼
在構造這個 Taxonomy 樹狀結構時,每一個分類都必須是能夠經過視覺定義的,必需要避免形容詞、抽象名詞、太寬泛的名詞,以及避免職業名稱。具體使用,也符合 Vision API 統一的使用方法,handler (依然是 VNImageRequestHandler, Vision 圖片處理中最主要的 Handler) 搭配 request (VNClassifyImageRequest,關鍵詞 Classify,分類識別專用):
let handler = VNImageRequestHandler(url: imageUrl)
let request = VNClassifyImageRequest()
try? handler.perform([request])
let observations = request.results as? [VNClassificationObservation]
複製代碼
最終獲得一個 Observation 數組,包含一系列物體識別結果,以及分別對應的信心值(可能性)。注意到信心值總和不爲 1,這就是由於剛纔提到的 Multi-label network 所產生的結果。
// 上圖識別以後的 observations 示例結果
// 從圖中識別出可能有:動物、貓、哺乳動物、衣服、小圓帽、帽子、人、成年人、雪...等一系列結果
[(animal, 0.848), (cat, 0.848), (mammal, 0.848), (clothing, 0.676), (beanie, 0.675), (hat, 0.675), (people, 0.616), (adult, 0.616), (snow, 0.445), (jacket, 0.214), (outdoor, 0.063), (leash, 0.057), (cord, 0.057)......]
複製代碼
獲得識別結果以後,如何 Observation 數組進行進一步分析,來斷定究竟識別結果中哪些是足夠可信的呢?很是符合常識的一個關鍵公式是:Confidence > Threshold。很容易理解,當信心值大於某個閾值時,就能夠判斷圖片中有相應物體。可是最大的問題在於,閾值應該如何肯定,而且閾值並不固定,不一樣的圖片中閾值確定是不一樣的。
接下來,咱們須要先引入兩個指標:Precision 查準率、Recall 召回率。用一張比較經典的圖來解釋一下:
Precision 和 Recall 都能反映分類算法的準確性,但卻有不一樣的傾向性。舉兩個例子,好比 AI 看病時,一般更看重 Recall 召回率,由於咱們更擔憂漏報狀況的發生。而好比在過濾垃圾郵件時,一般更看重 Precision 查準率,畢竟咱們不但願錯誤地把用戶的正常郵件也給錯誤地過濾了。
因此回到最初的問題,咱們如何斷定 Observation 數組中哪些結果是符合 Confidence > Threshold 公式,應該被留下來的呢?咱們能夠直接經過限制 Precision 或者是 Recall 的值來拿到結果。
好比使用 hasMinimumRecall(_:forPrecision:) 限制 recall,precision 爲 0.7 時,最小 recall 爲 0.5:
let searchObservations = observations?.filter { $0.hasMinimumRecall(0.5, forPrecision: 0.7)}
複製代碼
固然,使用 hasMinimumPrecision(_:forRecall:) 限制 precision 也是同理:
let searchObservations = observations?.filter { $0.hasMinimumPrecision(0.5, forRecall: 0.7)}
複製代碼
PR 曲線反映的是同一個分類器下 Precision 和 Recall 的關係,能夠用來衡量分類器性能的優劣。能夠看到 Precision 和 Recall 負相關。
對於 PR 曲線上每個點,都對應着一個 Precision 和 Recall 的值。咱們能夠經過 PR 曲線來直觀地理解上文中篩選、過濾的這個過程。好比下面咱們分別有三個分類器,分別對應識別"Cat"、"Anvil"以及"CD"時的 PR 曲線。當咱們限制了 (Recall = 0.5, Precision >= 0.4) 時,能夠看到前兩張圖都存在買組條件的點,而第三張圖並不存在,那麼很明顯的 "CD" 就應該被從結果中過濾掉。
除了識別圖片的問題以外,咱們常常會面臨的問題就是,如何判斷兩張圖片間的類似程度。那麼首先,咱們該如何描述一張圖片?傳統的方式有下面兩種:
對於一個圖片的描述,不能僅僅包含對其表面樣式的描述,還必須包含對圖片的內容的進一步敘述。用上述傳統方法咱們很難實現所謂的"進一步描述",可是巧妙的是,當咱們在用分類神經網絡對圖片進行分類時,神經網絡自己就是對圖片的進一步描述。神經網絡的上層網絡(upper layers)正好包含了圖片的關鍵信息(salient information),同時也剛好能摒棄掉了一些冗餘信息。因此,咱們能夠利用這個特色,來對圖片進行描述。
FeaturePrint 用於描述圖片內容的向量,和傳統的詞向量 (word vector) 相似。它反映的就是神經網絡在作圖片分類時,從圖片中提取出來的信息。經過特定的 Vision API,就能將圖片映射成對應的 FeaturePrint (這也是爲何說它是一種向量)。
須要注意的是,FeaturePrint 與 Taxonomy 並不相關,並非說圖片被分類爲貓,那麼對它的描述就應該是貓。
在獲得了 FeaturePrint 以後,咱們就能夠直接比較圖片間的類似程度。computeDistance(_:to:) 方法能夠直接獲得一個反映圖片類似度的浮點數。好比下圖中,數值越小,圖片在語義 (semantic sense) 上越類似。
具體 Demo 參見:Demo - 使用FeaturePrint比較圖片間類似度
接下來說一下人臉識別技術方面的進步。
人臉特徵點 (Face Landmark) 的識別一直是人臉識別技術的重要部分,Vision 框架在這方面有下面幾個進步:
Face capture quality 是一個綜合性指標,用於斷定人像效果的好壞,衡量因素包含光線、模糊程度、是否有遮擋、表現力、人物姿態等等。
好比第一張照片就比第二張照片得分高,意味着第一張照片有着更好的拍攝質量。
咱們能夠經過上面的代碼,直接獲得一張圖片的 face capture quality 的數值,進而將類似圖片進行比較,篩選出更加優質的圖片。好比這裏個 Demo:根據 face capture quality 篩選自拍照
注意,face capture quality 不能和一個固定閾值進行比較。不一樣系列的照片中 face capture quality 值分佈區域可能不一樣,若是咱們以一個固定的閾值來過濾(好比上圖中的 0.520),那麼有可能會把左邊所有的照片都過濾掉,哪怕其實左邊的圖片有一些相對拍的好的照片。換句話說,face capture quality 只是一個對同一個被攝物體的相對值,它的絕對數值大小並不能直接反映照片的拍攝效果。
除了這些傳統的識別器,還有一些新的好比人體 (Human Detector) 和貓狗 (Cat and Dog Detectors) 的識別器。
視頻追蹤技術也獲得了強化,追蹤技術的 Demo 能夠查看: 在視頻中追蹤多個物體。具體強化內容以下:
Vision 對 CoreML 的支持也獲得了提高。雖然去年就能夠經過 Vision API 運行 CoreML 的模型,可是如今使用起來更方便: