第五篇:基於深度學習的人臉特徵點檢測 - 生成TFRecord檔案
在上一篇博文中,我們已經獲取到了所有樣本的面部區域,並且對面部區域的有效性進行了驗證。當使用TensorFlow進行神經網路訓練時,涉及到的大量IO操作會成為訓練速度的瓶頸。為了加快訓練的速度,方便後期利用與復現,需要將所有用到的資料打包成為TFRecord檔案,一種TensorFlow原生支援的資料格式。
提取獨立的面部影象
為了方便將來的重複利用,我決定採用保險一點的策略——將所有面部區域提取出來儲存為獨立的影象檔案。
檔名命名規則
由於影象來自於不同的資料庫,為了方便後期debug檔案需要重新命名,我推薦以下策略:
- 可追溯。只通過檔名就可以找到原始圖片。
- 不重複。即使所有檔案放置在一個資料夾下,也不會出現重名錯誤。
- 全部採用小寫字母。
這樣可以定下檔名模板dataset_name-subset_name-file_name
。
300-VW
之前已經將視訊轉換為了圖片,圖片檔名是幀編號。每一個視訊都有一個獨立的3位數編號。因此示例檔名為300vw-001-000001.jpg
。
300-W
300-W的檔名中已經包含了subset的名字,因此沿用原有檔名與dataset名字。最終結果示例300w-indoor_001.jpg
。
AFW
AFW下沒有看到明顯subset,最終檔名示例:afw-134212_1.jpg
。
HELEN
HELEN下有兩個subset,最終檔名示例:helen-trainset-232194_1.jpg
IBUG
IBUG沒有觀察到subset,最終檔名示例:ibug-image_105.jpg
。
LFPW
LFPW下有兩個subset,最終檔名示例:lfpw-trainset-image_0001.jpg
。
儲存影象為jpg格式
儲存影象並不複雜,不過由於提取到的面部區域多種多樣,因此在儲存前需要考慮以下兩點。
縮放
從原始圖片中提取到的面部區域大小是不確定的,因此需要做縮放處理。這裡縮放的目標尺寸取決於神經網路的輸入層結構。例如我將採用128×128作為神經網路的輸入層大小,因此影象縮放的目標尺寸即為128×128畫素。
壓縮品質
為了節省空間,圖片會採用壓縮格式jpg。我推薦採用OpenCV中的imwrite()
特徵點座標轉換
以上資料庫中的座標是以原始圖片座標系為基準的。當影象被裁剪後,原始座標也就失去了它的意義,需要將原始座標轉換到新的圖片座標系中。這個轉換過程並不複雜,直接用特徵點當前座標減去面部邊界框左上角的座標即可。
# Shift points first.
for point in points:
point[0] -= left_x
point[1] -= top_y
同時為了方便神經網路更好的學習,我建議將裁剪後的新影象特徵點座標歸一化。這樣所有的座標均變成了[0, 1]之間的實數。這是從Udacity的深度學習課程中學到的,算是學有所用吧。
# Then normalize the coordinates.
for point in points:
point[0] /= width
point[1] /= height
轉換完成後的座標是一個Python list,形如[[x1, y1], [x2, y2], ..., [x68, y68]]
。由於存入TFRecord檔案的資料會被序列化,所以這種二維列表的形式需要被轉換為一個一維列表。這裡我將藉助Python下的矩陣運算模組Numpy的flatten()
函式來實現[2]。轉換完成後的列表形如[x1, y1, ..., x68, y68]
。這樣做的好處是若將來想恢復原始座標的結構,只需要使用Numpy的reshape()
函式即可。
考慮到新的座標已經與原始座標相去甚遠,為方便後期使用,我將轉換完成後的歸一化的新座標儲存為單獨的json檔案,這裡我推薦使用json模組下的dump()
來實現[3]。採用json檔案的好處在於它可以方便的被其它計算機語言或者程式使用,通用性較好。
如果你感興趣,可以參考我在GitHub上的開源實現[4]。
提取結果
使用該方法提取300-VW中的人臉資料的結果如下:
All done! Total file: 218597, invalid: 1469, succeed: 217128
22萬多張圖片的資料轉換花費了3個多小時,可能是因為我在轉換過程中開啟了圖片預覽造成的。剩餘的資料集轉換原理是一樣的,具體結果如下:
- HELEN:Total file: 2330, invalid: 0, succeed: 2330
- 300W:Total file: 600, invalid: 0, succeed: 600
- AFW:Total file: 337, invalid: 0, succeed: 337
- IBUG:Total file: 135, invalid: 0, succeed: 135
- LFPW:Total file: 1035, invalid: 0, succeed: 1035
最終一共獲得221565個樣本,資料總大小約為1.9GB。
將影象與特徵點轉換為TFRecord檔案
之前的博文[5]中已經介紹了TFrecord檔案,在這裡我們需要將一些必要的資訊存入到TFRecord檔案中,具體包括:
- 影象
- 影象尺寸
- 影象檔名,以備後期DEBUG
- 影象格式
- 特徵點座標,共計68×2個數值。
在製作檔案之前,我將所有的檔案分為3大部分:train,validation與test。
Train
顧名思義,用來訓練神經網路的資料集。我隨機選擇了20萬個樣本作為訓練集。這部分資料將是神經網路主要的資訊來源。
Validation
驗證集,主要用來在訓練過程中驗證神經網路是否陷入了局部最優陷阱。典型的表現就是train集合上的準確率上升而驗證集上的準確率卻在下降。隨機選擇了11565個樣本作為驗證集的大小。
Test
測試集,神經網路在該資料集上的表現將被作為訓練是否成功的最終判定依據。所以在整個的訓練過程中這部分資料對於神經網路來說一直是不可見的絕密內容。這裡我將剩餘的1萬個樣本作為測試集。
這三部分的選擇完全是隨機的,這樣可以儘可能的使資料集均衡,消除人為因素對資料的干擾。最後生成的檔案包括:train.tfrecord,validation.tfrecord和test.tfrecord三個檔案。
最終的TFRecord檔案生成並不是非常困難,可以參考我在Github上的開源實現[6]。
小結與下一步計劃
簡單回顧一下,我們通過將視訊轉換為影象已經成功的從6個數據庫中提取出了22萬多個樣本;通過對特徵點座標進行驗證剔除掉其中的不可用樣本,提取出可用樣本221565個;採用其中的20萬個用作訓練,11565個作為驗證,1萬個作為測試;對資料進行轉換並最終生成了三個TensorFlow可以直接使用的TFRecord檔案。
到目前為止工作內容一直集中在資料的清洗與預處理,大部分的程式碼都與TensorFlow沒有太大的關係。不過TFRecord檔案的生成意味著資料相關工作已經基本完成。在下一篇文章中,我們將正式基於TensorFlow來構建一款屬於我們自己的神經網路。