2017年9月14日 星期四

Caffe 遷移學習範例: 分辨猿類相片

用 caffe 做 transfer learning 的過程及所需檔案 如果英文已經不錯了, 要學一點點西班牙文相對就不會太難; 但是英文能力對於學習彈鋼琴可能並沒有幫助。 這就是 transfer learning 學習遷移的現象。 類神經網路也是這樣: 已經訓練好、 可以辨識 1000 種類型相片的 caffe 圖像辨識模型, 如果要再拿來改訓練成 「辨識六種猿類相片」 的模型, 因為工作內容很類似, 所以對就花的運算資源相少很多, 也相對比較容易訓練得好。

請見本文插圖。 用 caffe 做 transfer learning 時, 最核心的工作, 就是要用 caffe train ... 這個指令把 bvlc_reference_caffenet.caffemodel 這個權重矩陣訓練成名為 _iter_4000.caffemodel 之類的另一個權重矩陣。

類神經網路的模型架構寫在 train.prototxt 這個設定檔裡面。 這是由 AI 研究學者所設計的; 我們只會去改相關檔案的路徑, 還有最後面輸出那一層的架構, 因為原先要辨認 1000 類圖片, 現在只要辨認 6 類圖片。 秉持著 不求甚解工程師 的精神, 前面的其他層次看不懂也沒關係 :-)

除了類神經網路的架構之外, 訓練時還需要指定一些額外的參數, 例如多久要把整個權重矩陣做一次快照 (snapshot:) 等等。 這些參數寫在 solver.prototxt 裡面。 你在 caffe train ... 的命令列上看不到模型架構的檔名 (train.prototxt), 只看得到 solver.prototxt 的檔名, 但 caffe 會從 solver.prototxt 裡面的 net: 那一句找到模型架構檔。

訓練完成後, 要用 cnclassify.py 來辨識未知圖片時, 除了要有權重檔 _iter_4000.caffemodel 之外, 當然也要餵模型架構 deploy.prototxt 給 cnclassify.py 吃。 你可以用一個比較強的文字編輯器 (例如 vimdiff) 把它拿來跟 train.prototxt 比較 -- deploy.prototxt 基本上就是簡化版 (只保留 forward phase; 丟棄 back propagation) 的 train.prototxt 。 另外, caffe 類神經網路在辨識圖片時, 輸出的結果並不是文字字串, 而是 0 到 5 之間的一個整數。 到底 0 代表哪一種猩猩、 5 代表哪一種猿類, 需要有一個標籤列表的文字檔來解讀。 等一下我們再詳細交代 wnid.txt 這個標籤列表檔的內容。 最後, 辨識時還需要把訓練過程當中所有相片的平均值 mean.npy 拿來參考 -- 這點我們在 caffe 初體驗 當中已學過。 也請下 ./cnclassify.py -h 查看更多選項。

回頭看如何準備訓練用的圖片。 訓練用的 .jpg 圖片檔並不是直接餵給 caffe, 而是要先用 pic2lmdb.py 指令把它們轉成 lmdb 的格式、 把所有圖片塞進 training/ 跟 validation/ 底下的兩個資料庫。 但別忘了這是 supervised learning, 所以你必須告訴 caffe 每一張相片究竟是黑猩猩還是大猩猩。 你的圖片檔必須按照類別命名或是按照類別放在各自的資料夾, 類似這樣:

chimp-0001.jpg
chimp-0002.jpg
...
gorilla-0225.jpg
gorilla-0226.jpg

或類似這樣:

chimp/0001.jpg
chimp/0002.jpg
...
gorilla/0225.jpg
gorilla/0226.jpg

總之代表類別的圖片類別代號 (chimp、 gorilla 等等; 姑且稱之為 pcid) 必須是一個文數字的字串 ([a-zA-Z_0-9]+) 並且必須出現在路徑當中, 而且前後不可緊鄰其他文數字。 這是因為我在 pic2lmdb.py 裡面用 regex 的 \b 去圖片檔路徑裡面比對 pcid (picture class id), 據此來決定這張圖片的類別。 至於路徑的其他部分 (0001 或 0002) 並不重要, 可以任意命名。 然後你需要建一個長得類似 wnid-apes.txt 的文字檔, 左邊是 pcid, 右邊是任意中英文字串, 列印用的。 把這個對照表跟一串圖片目錄餵給 pic2lmdb.py, 它就會產生兩個 lmdb 的目錄, 一個是 training 用, 另一個是 validation 用。 也請下 ./pic2lmdb.py.py -h 查看更多選項。

如果你跟我一樣手邊沒有很多現成的圖片, 那麼可以這樣子準備訓練用的圖片:

  1. 看你想訓練哪幾類圖片的辨識網路, 先 畫出這些名詞在 wordnet 裡面的從屬關係
  2. 用 wordnet 的 wnid 當作上述的 pcid, 手動建立上述對照表。 好幾個不同的 wnid 可以對應到同一個列印用的字串, 例如 n02481823 n02482474 n02482286 n02482060 這四個 pcid 都對應到 「黑猩猩」, 但它們在對照表當中必須連續出現列印字串 (而不是 pcid) 出現的順序, 就對應到 caffe 模型當中的類別代號 (0-5)
  3. 按照 wnid 下載 ImageNet 訓練圖片的一小部分

對了, 產生了 training 的 lmdb 之後, 還要用 $CAFFE_ROOT/build/tools/compute_image_mean 來產生訓練時要用的圖片平均值檔 mean.binaryproto, 再用 bpt2npy 把平均值檔的格式轉成 .npy 以供辨識時使用。

本文所提到的檔案跟指令, 可從 transfer-learning 這個 github repo 下載。 完整的指在 README.md 裡。 超級感謝原作者撰寫程式及教學文: A Practical Introduction to Deep Learning with Caffe and Python

訓練圖片要用工人智慧細心挑選, 因為 ImageNet 上有一些圖片標錯了 (把紅毛猩猩標成大猩猩之類的很明顯錯誤)。 我只用 CPU 訓練, 跑了兩天左右, 得到 4000 個 iterations 之後的權重矩陣, 測試結果還不錯。 也許更早就可以收工了。 除了侏儒黑猩猩判別率較低 (我自己也判別不太出來; 搞不好訓練圖片也沒餵正確), 其他判別率都還不錯。 參數/時間/正確率的分析, 就等以後再研究吧。

沒有留言:

張貼留言