在《機器學習》(Tom.M.Mitchell)這本書中,第四章講解人工神經網絡的時候,給了一個人臉識別的例子,實際是基於人工神經網絡反向傳播算法來識別灰度圖像中的人臉朝向等信息。
文中除理論介紹之外,還提到在官網附帶了源碼和訓練語料,為入門ANN提供了不可多得的幹貨。下麵我們就來實踐一下如何使用這些資料進行ANN的訓練和測試。(以下命令行操作都在LINUX上進行)
1、mkdir faceimages 創建工作目錄。
2、下載程序源碼[code目錄]:
wget -r -l1 -nd http://www.cs.cmu.edu/afs/cs.cmu.edu/project/theo-8/faceimages/code -P code -A Makefile,.h,.c
3、ls -al code 查看相關代碼文件如下:
[root@iZ25ttg9nypZ faceimages]# ls -al code/
total 68
drwxr-xr-x 2 root root 4096 Apr 5 11:47 .
drwxr-xr-x 3 root root 4096 Apr 5 11:47 ..
-rw-r--r-- 1 root root 10163 Oct 19 1995 backprop.c
-rw-r--r-- 1 root root 1737 Oct 19 1995 backprop.h
-rw-r--r-- 1 root root 8408 Oct 7 1997 facetrain.c
-rw-r--r-- 1 root root 1440 Oct 19 1995 hidtopgm.c
-rw-r--r-- 1 root root 2011 Oct 19 1995 imagenet.c
-rw-r--r-- 1 root root 829 Mar 15 1996 Makefile
-rw-r--r-- 1 root root 2131 Mar 15 1996 outtopgm.c
-rw-r--r-- 1 root root 5916 Oct 19 1995 pgmimage.c
-rw-r--r-- 1 root root 825 Oct 19 1995 pgmimage.h
-rw-r--r-- 1 root root 1550 Mar 19 04:08 robots.txt
- 其中backprop.c/backprop.h是反向傳播神經網絡相關的數據結構和函數。
- facetrain.c是使用backprop來訓練人臉的主函數文件
- pgmimage.c/pgmimage.h 是處理pgm格式圖片文件的相關結構和函數。
- PGM 是便攜式灰度圖像格式(portable graymap file format)
- hidtopgm.c 是將隱層權值轉化為pgm圖片的程序,方便可視化查看。
- outtopgm.c 是將輸出層權值轉化為pgm圖片的程序,方便可視化查看。
- imagenet.c 用於將圖像導入bp網絡。
4、cd到code目錄,嘗試編譯程序。make的時候,可以看到雖然輸出了一些警告,但是編譯通過。
[root@iZ25ttg9nypZ code]# make
cc -g -I. -c -o facetrain.o facetrain.c
cc -g -I. -c -o imagenet.o imagenet.c
cc -g -I. -c backprop.c
backprop.c: In function ‘alloc_1d_dbl’:
backprop.c:54: warning: incompatible implicit declaration of built-in function ‘malloc’
backprop.c: In function ‘alloc_2d_dbl’:
backprop.c:71: warning: incompatible implicit declaration of built-in function ‘malloc’
backprop.c: In function ‘bpnn_internal_create’:
backprop.c:125: warning: incompatible implicit declaration of built-in function ‘malloc’
backprop.c: In function ‘bpnn_free’:
backprop.c:160: warning: incompatible implicit declaration of built-in function ‘free’
backprop.c: In function ‘bpnn_save’:
backprop.c:374: warning: incompatible implicit declaration of built-in function ‘malloc’
backprop.c:383: warning: incompatible implicit declaration of built-in function ‘free’
backprop.c: In function ‘bpnn_read’:
backprop.c:425: warning: incompatible implicit declaration of built-in function ‘malloc’
backprop.c:433: warning: incompatible implicit declaration of built-in function ‘free’
mv backprop.o backprop_initr.o
cc -g -I. -c -o pgmimage.o pgmimage.c
pgmimage.c:13: warning: conflicting types for built-in function ‘malloc’
pgmimage.c:14: warning: conflicting types for built-in function ‘realloc’
pgmimage.c: In function ‘img_basename’:
pgmimage.c:23: warning: incompatible implicit declaration of built-in function ‘strlen’
pgmimage.c: In function ‘img_free’:
pgmimage.c:81: warning: incompatible implicit declaration of built-in function ‘free’
pgmimage.c: In function ‘imgl_free’:
pgmimage.c:277: warning: incompatible implicit declaration of built-in function ‘free’
cc facetrain.o imagenet.o backprop_initr.o pgmimage.o \
-o facetrain -lm
[root@iZ25ttg9nypZ code]#
5、 編譯成功後生成了文件facetrain,這個就是進行訓練的主程序了。
[root@iZ25ttg9nypZ code]# ./facetrain
USAGE: ./facetrain
-n <network file> //訓練之後輸出的網絡配置文件
[-e <number of epochs>] // 訓練迭代次數,默認100
[-s <random number generator seed>] //用於初始化權值的隨機函數種子,默認值102194
[-S <number of epochs between saves of network>] //S設置的每訓練多少次保存一次網絡配置文件,默認100
[-t <training set list>] //指定訓練集文件,文件內容為圖片的絕對路徑
[-1 <testing set 1 list>] //指定第一個測試集,文件內容為圖片的絕對路徑
[-2 <testing set 2 list>] //指定第二個測試集,文件內容為圖片的絕對路徑
[-T] //設置該參數後,隻測試不訓練。
6、回到faceimages工作目錄,然後下載用於訓練的圖片數據。解壓後可以看到faces目錄下是不同人的表情圖片(PGM格式)。文件命名方式為: 人名_人臉朝向_情緒_是否戴眼鏡_圖片尺寸編號.pgm
wget http://www.cs.cmu.edu/afs/cs.cmu.edu/project/theo-8/faceimages/faces.tar.gz #下載
tar xzvf faces.tar.gz #解壓
mv afs/cs/project/theo-8/faceimages/faces/ faces #簡化目錄結構
7、由於訓練程序facetrain傳入的是文件路徑列表,所以我們還需要下載train_set列表文件:
wget -r -l1 -nd http://www.cs.cmu.edu/afs/cs.cmu.edu/project/theo-8/faceimages/trainset -P trainset -A .list
//head可以看到用的是絕對路徑:
[root@iZ25ttg9nypZ trainset]# head all_train.list
/afs/cs/project/theo-8/faceimages/faces/kawamura/kawamura_straight_happy_open_4.pgm
/afs/cs/project/theo-8/faceimages/faces/phoebe/phoebe_up_sad_open_4.pgm
/afs/cs/project/theo-8/faceimages/faces/saavik/saavik_left_sad_sunglasses_4.pgm
/afs/cs/project/theo-8/faceimages/faces/sz24/sz24_right_angry_open_4.pgm
/afs/cs/project/theo-8/faceimages/faces/tammo/tammo_left_angry_sunglasses_4.pgm
//由於list文件中用的是絕對路徑, 所以還需改為本地絕對路徑
//原始圖片路徑為:/afs/cs/project/theo-8/faceimages/faces
//當前圖片路徑為:/home/working/faceimages/faces
//使用sed做個替換即可
cd trainset
find . -name "*.list" | xargs sed -i "s:/afs/cs/project/theo-8/faceimages/faces:/home/working/faceimages/faces:g"
//head看下路徑已經改為本地的了
[root@iZ25ttg9nypZ trainset]# head all_train.list
/home/working/faceimages/faces/kawamura/kawamura_straight_happy_open_4.pgm
/home/working/faceimages/faces/phoebe/phoebe_up_sad_open_4.pgm
/home/working/faceimages/faces/saavik/saavik_left_sad_sunglasses_4.pgm
/home/working/faceimages/faces/sz24/sz24_right_angry_open_4.pgm
/home/working/faceimages/faces/tammo/tammo_left_angry_sunglasses_4.pgm
8、到這裏,程序和數據準備好了,可以開始訓練了:
./facetrain -n pose.net -e 75 -t ../trainset/all_train.list -1 ../trainset/all_test1.list -2 ../trainset/all_test2.list
首先輸出傳入的圖片地址和計數等信息(紅框1);然後輸出每輪迭代的相關統計值(紅框2),依次為:
- 當前迭代的輪數編號
- 當前這輪迭代的誤差總和(包括隱層和輸出層)
- 當前這輪迭代中,訓練集正確分類的比例
- 當前這輪迭代中,平均輸出值和輸出值的誤差
- 當前這輪迭代中,測試集1正確分類的比例
- 當前這輪迭代中,測試集1的平均誤差
- 檔錢這輪迭代中,測試集2正確分類的比例
- 當前這輪迭代中,測試集2的平均誤差
9、訓練完成後,程序保存結果到facetrain -n 參數指定的pose.net文件,主要內容是:
- 輸入層、隱層、輸出層單元數量
- 輸入層到隱層所有連接的權值
- 隱層到輸出層所有連接的權值。
10. 原書附帶的例子,輸出層是單節點的,用來識別一張圖片是不是某個人。嘗試將輸出層改成了4節點,用來識別人臉的朝向(up, right, left, straight),訓練和測試結果如下圖所示,雖然隻迭代了200輪,但效果還是很不錯的:其中1是訓練集上的準確率,2是測試集上的準確率。(基於原書的例子,先用Python實現了一版,但是速度太慢,所以又改成了C++的,下圖是C++實現的結果,代碼比較長,大約有300行,這裏就不貼了。)
參考資料:
[1].http://www.cs.cmu.edu/~tom/mlbook.html
[2].http://www.cs.cmu.edu/afs/cs.cmu.edu/user/mitchell/ftp/faces.html