機器學習的影像分析任務中,有時候不只是要辨識圖片是什麼,還會要求模型需要同時找出物件「在哪裡」的位置資訊。與此類任務相關的影像資料集,除了圖片之外,會包含圖片中重要資訊出現在哪裡的位置標註點資料。使用此類資料集其中一個需要關注的基本問題是:當我們為機器學習模型採取常用的 Data Augmentation(資料增強)技巧時,如何讓圖片與位置標註的資料增強同步?
這篇教學是我參加 2021 年 AIdea 與阿瘦皮鞋合辦的 足壓影像分析機器學習競賽 爬到 top 5% 名次的心得筆記之一,我將帶你快速認識在 Python3 進行 Data Augmentation 好用的 Albumentations 套件,並且把教學重點放在如何讓圖片與標註點同時進行 Data Augmentation。
目錄
簡短複習:Data Augmentation 是什麼?
Data Augmentation(資料增強)是基於現有資料,微調或者合成出更多新資料的資料分析技巧,最主要的目的是防止過擬合(Over-Fitting)。以影像辨識為例,圖片的資料增強可以是調整尺寸比例、旋轉、色調改變、或者加上全黑色塊當作雜訊等等。
資料增強對於資料量小的訓練任務特別有效,可以提升模型準確度。例如,此次 AIdea 足壓影像辨識競賽,主辦單位提供的圖片數量不到 2,000 張,想使用動不動就百萬參數量的 CNN 深度學習模型,很容易陷入過擬合問題,這種時候採用資料增強就會有很大的幫助!
使用 Albumentations 套件,影像資料增強超輕鬆
Albumentations 是以 OpenCV 為基礎的影像資料增強 Python 套件,由一群 Kaggle 機器學習競賽大師所開發,這群開發者非常了解影像分析任務實戰的需要,這項套件的優點包括:
- 整合 API 可以用簡潔的語法進行不同影像分析任務
- 有超過 70 種影像資料增強方法
- 快速、高效率的運算
圖片位置標註(Keypoints)的資料增強
圖片的位置標註點,英文稱為 Keypoints 或 Landmarks,標示出影像中特定資訊的位置。
進行資料增強時,如果涉及圖片的變形、旋轉、或位移,標註點沒有跟著轉換的話,標示位置就會出錯!
在 AIdea 足壓影像辨識競賽 的資料集,除了包含腳部影像、每隻腳還各有 2 個足部標註位置資料。因此,運用此資料集的要點,就是圖片與位置標註需同步進行資料增強(Keypoint Augmentation)。
好消息是:Albumentations 也提供了讓位置標註與圖片同步資料增強的簡單方法。以下範例程式碼與上方的圖片比起來,只是多一行 code 而已,三行 code 就能讓 Albumentations 函式接收位置標註資料格式、達成位置標註資料增強!
trafo = A.Compose([A.Flip(p=1.0)], keypoint_params=A.KeypointParams(format='xy'))
trafo_obj = trafo(image=img, keypoints=list(zip(*annot)))
trafo_img, trafo_keypts = trafo_obj['image'], trafo_obj['keypoints']
(如果你對上面程式碼 list(zip(*))
的用法感到疑惑,推薦你參閱好豪寫的 Python3 zip()
函式教學)
然而,也有個壞消息:如果你想做的事情更奇怪一點,Albumentations 套件也有可能不支援!
進階挑戰:Albumentations 不支援某種位置標註的資料增強怎麼辦?
筆者好豪在競賽解題過程,來回翻閱著 Albumentations 究竟支援哪些資料增強方法,其中的「ElasticTransform」不知怎麼地、一看就覺得會對足部影像辨識很有幫助 (˚∀˚) ,馬上欣喜若狂要拿來用。
再看 官方文件 才發現:ElasticTransform 不支援位置標註的資料增強!
Albumentations 套件有一些資料增強函式不支援位置標註與圖片同步變換,通常是因為:
- 位置標註不需要變換
- 例如:Dropout 是在圖片上隨機挖空格增加雜訊,位置標註點根本不會變,函式當然沒必要支援變換
- 位置標註變換無法精確
- 例如:ElasticTransform 是讓圖片不規則扭曲變形、圖片與位置標註點之間的相對位置關係在變換前後難以精確維持
可是我還是很想用 ElasticTransform 啊(你不覺得一隻腳扭曲一下就會很像是另一個人的腳嗎 (˚∀˚)? ),要怎麼辦呢?
翻翻套件的程式碼,其實是矩陣線性變換 + 各像素隨機偏移
在 Albumentations 的 ElasticTransform 程式碼 中翻找,可以發現進行這項資料增強的原理其實是做仿射變換加上每個像素的隨機偏移。
程式碼裡,仿射變換使用的是 OpenCV 的 cv2.warpAffine
,進行「線性變換 + 平移」;而各像素的隨機偏移是為 (x, y)
座標加上噪音變成 (x+dx, y+dy)
。既然看了原始碼知道可以用矩陣運算達成,那想要讓位置標註(Keypoints)也進行 ElasticTransform,就讓位置標註也用矩陣的方式呈現,這樣就能進行仿射變換 + 像素隨機偏移的矩陣運算了!
此篇文章暫且把方法先以上方圖示、以及下方圖示成果概括說明,至於位置標註表示成 Single-Entry Matrix 之後,要怎麼繼續做仿射變換,在此就不贅述了,有興趣的話,可以看看好豪的 Data Augmentation 教學 Python Notebook,有完整程式碼可以練習。
然而,這個方法並不完美,就如前面所述,ElasticTransform 無法精確維持位置標註與圖片的相對位置關係,但是在這次的 AIdea 足壓影像辨識競賽中、這些誤差是不影響結果的,最後 ElasticTransform 的資料增強確實讓我的 ResNet 模型精確度提升!
結語
這則筆記介紹了位置標註(Keypoints)的資料增強,圖片進行變形類型的資料增強之後,位置標註也必須做相同的變換才行,而這些動作用 Albumentations 套件可以很方便快速地達成。即使是 Albumentations 內不支援的位置標註資料增強,用矩陣線性變換的方法,也可以達到近似的效果。
在機器學習競賽中,對資料「動手腳」的特徵工程,常常會比使用最複雜、最先進的機器學習模型還來得有效益,這則筆記教學的資料增強就是其中一個例子。如果你對機器學習競賽有興趣,《Kaggle 競賽攻頂秘笈 – 掌握 Grandmaster 制勝的關鍵技術》這本書詳細地整理了常用且對實戰有幫助的特徵工程技巧,值得一讀。
這篇文章的 Python3 教學 Notebook、還有我參加 AIdea 足壓影像辨識競賽 所使用的 PyTorch 程式碼,我都收錄在 我的 Github,對影像辨識有興趣的讀者,歡迎參考。也希望如果有其他參賽者讀到這篇文章,可以留言交流不同的競賽技巧!
你也想學習影像辨識、正準備入門嗎?筆者好豪這次參加 AIdea 足壓影像辨識競賽,就是運用之前在 Udacity 學習的 PyTorch 深度學習 免費課程 所學,因此推薦你參考我寫過的 課程心得、或者閱讀 PyTorch 核心開發者撰寫的《PyTorch 深度學習攻略》課本,心動就馬上拿起課本、加入課程、一起學習深度學習的影像辨識吧!