用 10 分鐘搭建萬物識別的 Live Demo
在富奸了一週後,我尋思著有沒有只需要花很短的時間就能夠寫出很屌的文章的偷懶法。想想其實寫文章還是很難的,相對之下還是 coding 簡單多了。那不然這週就來 coding 吧。
說起標題的萬物識別,是我從剛進阿里的時候 AILabs 裡面就有的一個項目,在 2018 年的時候還上了發佈會。但時至今日 2021 年,開發一個萬物識別的 AI 功能 Demo 居然只需要 10 分鐘就能完成了,科技的變化實在太快了。
這個 Demo 是利用 OpenAI 開發的 CLIP 搭建的。廢話不多說,先上 Source Code,後面再講原理:
OpenAI CLIP 原理概述
CLIP (Contrastive Language-Image Pre-Training) 是 Iron Musk 的 AI 公司 OpenAI 推出的一個公開模型,意思是利用 Contrastive Learning (對比學習) 在 Language-Image 配對資料上的預訓練模型。以下分別簡述這些名詞是什麼意思。
Contrastive Learning 對比學習
Contrastive Learning 是 Self-Supervised Learning 的其中一個分支,特點就是跟無監督學習 (Unsupervised) 方法一樣,不需要多餘的標注數據就能訓練。但需要注意的是,對比學習不屬於無監督學習,因為它還是需要標注數據的,只是它的標注數據就是「數據自己」。
對比學習的著名方法包含MoCo、SimCLR。以 SimCLR 為例,他利用「資料擴增」的方式,將一張圖變為 N 張圖,然後讓機器學習下列問題:
這兩張圖是不是屬於同一張圖?
下圖是 SimCLR 的動畫圖,可以比較清晰地說明這個概念:
Language-Image
在前述的 SimCLR 例子中,輸入只有單純的圖片。而對於 Language-Image 的輸入來說,每個輸入是一個「圖片+文字」的配對資料,有點類似 Image Captioning 的問題定義。
雖然以往 ImageNet 那種嚴格定義的資料集也算是屬於圖片+文字,但是標注數量是有限集,而且只能給予 1 個標籤,讓模型訓練受到很大的限制。比方說上圖的左邊第一張,如果用 ImageNet 標籤的話應該定義為「吉他」還是「人」呢?
相對的,使用「圖片+文字描述」的資料集,這種文字描述的模糊性可以讓 AI 模型訓練的時候有更好的描述性。例如上圖左邊第一張,描述包含了 man, black shirt, guitar,因此預測出這三類的任何一類都可以算是正確的。
另一個好處是,這種資料很容易用爬蟲爬取。因此可以建立大規模的免費資料集,利用大數據增加模型的穩定性,也降低 overfitting (擬合過度) 的風險。
Pre-Trained Model 預訓練模型
預訓練模型,顧名思義指的是預先訓練好的模型。如果以人來描述的話,預訓練模型可以看作是「畢業生」,畢業生已經在專門的學校學習過所需要的基礎知識,所以訓練成「職員」的成本與時間都會比較低。這種從預訓練模型往特定的任務去遷移、學習的方法稱為 Transfer Learning (遷移學習)。
相反的,如果不使用預訓練模型,稱之為 Train from Scratch,也就是從零開始訓練模型。這種方法的時間與成本都比較高,因此在工業界都比較傾向利用 Transfer Learning 來減少成本。而優秀的預訓練模型能夠直接影響 Transfer Learning 的產出優劣。
目前優秀的預訓練模型有很多,例如電腦視覺領域的 ImageNet 系列模型,自然語言領域的 BERT, GPT-3,以及今天介紹的 CLIP。
CLIP 原理與應用方法
基本原理
CLIP 的架構圖如下:
- 左圖描述的是 CLIP 訓練的流程;其中 N 代表的是訓練的樣本數量。Image Encoder 負責提取視覺特徵,Text Encoder 負責提取文字特徵。右下角 NxN 的矩陣就是圖片/文字特徵匹配成的相似度矩陣,在理想情況下只有對角線(淺藍色)為 1,其他都為 0。
- 右上圖描述的是應用時的第一步,先將想要辨識的目標文本利用 Text Encoder 提取文字特徵,並且暫存下來備用。這一步因為輸入都是固定的,所以可以預先計算暫存。
- 右下圖是應用時的第二步,把輸入圖片利用 Image Encoder 提取視覺特徵,再跟文字特徵計算相似度,相似度最高的那個文字就是辨識的結果。
Demo Code 說明
完整的 Demo Code 如下:
- Line 8–10 是 CLIP 的全局設定。這裡 ViT-B/32 代表用的是 Vision Transformer 的 Base 架構,模型的圖片輸入是 32x32。
- Line 12–13 對應的是 CLIP 架構圖的右上圖。
- Line 20–24 是 OpenCV 打開 Camera 的部分。
- Line 26–35 對應的是 CLIP 架構圖的右下圖。
- Line 37–38 只對預測分數夠高的結果打字顯示出來。
- Line 41–42 是 OpenCV 的顯示部分。
下面是實際 Demo 的結果:
Demo 裡面你可能沒注意到的小細節
上面的 demo code 只要不到 50 行就可以輕鬆辨識 iPhone, coffee, papers, man 等等類別。But,如果仔細看原始碼還能發現幾個有趣的事情:
- 我把 coffee 拼錯成了 coffie。但即使如此,CLIP 的可靠性還是能正確的知道 coffie 其實就是 coffee,對結果的影響很小。
- targets 裡面包含了 man, woman 兩類。CLIP 模型很清楚的知道我是 man 而不是 woman。
- 大家可以試試看,如果在 targets 裡面加入一類 A man holding an iPhone,會發生什麼事情?對 man 跟 iPhone 的辨識率會不會有影響?