hans

hans

【Tensorflow】【Python】訓練自己的數據集——數據讀取、處理、訓練、測試、可視化、Debug(單機單卡、單機多卡、多機多卡)


Github 代碼地址: https://github.com/HansRen1024/Tensorflow-preprocessing-training-testing

** 所有代碼去 Github 上拿吧,文件名對應好。 **

** TF 版本至少 1.4.0。 **

**MonitoredTrainingSession 在網上的資料十分稀少,研究了很久官方 API 和源碼 。 **

** 2018.04.13 更新 SSD 單機訓練 + 測試代碼: https://github.com/HansRen1024/Tensorflow-SSD
**

2018.03.16 更新 增加可視化代碼

2018.03.19 更新 增加 debug 調試代碼

2018.03.20 更新 增加去均值,歸一化代碼

2018.03.21 更新 增加 mobilenet 和 mobilenet v2 網絡模型

2018.03.22 更新 增加 resnet-50, **resnet-101, **resnet-152, resnet-200 **
** 網絡模型

解決了一運行就將 GPU 內存佔滿的問題(只在單機好用,分佈式環境不行)

2018.03.23 更新 選擇 GPU

** 2018.03.26 更新 添加了 validation 階段,可以在 tensorboard 上同時監控 train 和 val 階段的 loss
**

** ** 2018.03.29 更新 增加了 finetune 功能


** ** 2018.04.02 更新 優化了可視化效果,重新設置了計算 step 的方法。


** ** 2018.04.09 更新 在分佈式環境下增加了同步異步訓練開關,重寫了 MonitoredTrainingSession


** ** 2018.04.10 更新 用 global step 替換了自定義的 i 或者 step,解決了 log 輸出不匹配問題


2018.04.11 更新 解決了異步訓練記錄最後一次 event 失敗的問題

前言#

新業務要做分佈式集群,以前一直用的 caffe,現在得用 Tensorflow。

網上幾乎全是照搬官方 demo,沒有詳細介紹從數據讀取處理到訓練到測試的文章。我來寫一個。

一、準備數據集#

以前一直用的 caffe,數據集都分類放到不同目錄裡面的。我這裡放出兩個腳本,各自功能看解釋。

腳本 1(img2bin.py)不建議用這個,沒後續更新:

classes 是 images 目錄下各類數據集目錄名

img=img.resize ((227,227)) 要根據網絡結構選擇 resize 尺寸

這個腳本和 images 目錄在同一級,images 目錄下有三個目錄 “0”,“1”,“2”,分別放了三個類別的所有圖片數據集。最後生成名字為 “train.tfrecords” 的二進制文件。

腳本 2(list2bin.py):

最後會打印一組 bgr 三通道均值,記錄 訓練集 的均值,放到 arg_parsing.py 中,用於去均值操作。

一定要轉換成 RGB 三通道,否則後面數據讀取會出問題。

以前用 caffe 的時候,習慣先生成一個 txt 文檔(格式如下),然後根據文檔生成 lmdb 數據集。

腳本 2 就是根據這個 txt 文檔生成 tfrecords 二進制數據集的。

生成 txt 文檔的腳本的博客地址(就是 Github 中的 img2list.sh ):
【Caffe】快速上手訓練自己的數據 《很認真的講講 Caffe》

代碼是準備數據集裡面生成 train.txt 和 val.txt 的.sh 腳本

我寫第二個腳本就是習慣了訓練階段根據 val 的輸出判斷訓練過程是否正確。 不過後來因為一些原因,在訓練階段做不了 val。需要繼續研究 - 0-。

二、配置準備階段#

拿到上面生成的.tfrecords 二進制數據集,就可以開始佈置環境進行訓練了。

代碼比較多,解釋我都放到代碼裡面吧,這樣看起來方便點。說實話很多 tf 的 api 我也沒搞懂,現在只是跑起來了。後面還要花大量時間去學習研究。

文檔 1(arg_parsing.py):

這個文檔主要用來設置運行輸入參數的,很好理解。可以在代碼中修改大寫字符後面的默認參數,也可以在命令行指定參數。

文檔 2(dataset.py):

讀取數據,去均值,歸一化,整合成一 batch 輸入網絡

文檔 3(main.py):

在命令行要執行的文檔,內容很簡單。

if tf.gfile.Exists(FLAGS.model_dir):
#註釋的三句話是清空 models 目錄,如果沒這個目錄就創建。為了防止誤操作,我註釋了這三句話

文檔 4(net/squeezenet.py):

網絡結構文檔,單獨寫出來,以後換網絡結構就方便了。

我的是 squeezenet 網絡,官方 demo 裡只能處理 3232 數據集,我給改了,現在這個網絡可以處理正常 227227 的了。

network.py 看看就好,後續被我拋棄停止更新了。

文檔 5(test.py):

用於 test 的文檔。

文檔 6(train.py)

訓練文檔,裡面有三種訓練方法。寫的最累的文檔了,糟心~~~。

train ():# 單機單卡 + 單機多卡通用訓練方法。
train_dis_():# 可以用的分佈式多機多卡。

關於 train.py 我要多說幾句。

1. 關於 session,普遍都用 tf.Session ()。我這裡用的 tf.train.MonitoredTrainingSession (),是看的官方 api 推薦和 cifar-10
demo 裡這麼用的。這個接口中 hook

這一塊很方便,可以靈活定義和使用一些功能。在官網 API 文檔中,幾乎所有 hook 都可以用在這裡。比如 debug,summary 等等,值得研究。(
2018.03.23
通過這個 MTS 管理器很難加入 validation 階段,如果是通過共享參數來 validation,問題主要是 global_step 衝突。如果通過讀取本地 ckpt 做,保存 ckpt 的頻率和 validation 頻率很難平衡。

  1. 我不了解為什麼一訓練起來所有 GPU 的內存就會馬上被佔滿,設置 batch_ size 為 1 還是 32 還是 64 結果都一樣。所以一運行 val 就會報 GPU 內存不足,過一會機器就卡死了 -0-。這個問題以後慢慢解決吧~

3. 第三個 train_dis () 方法,可以控制同步還是異步,不過有點問題,著急跑通流程就沒管了,以後有時間再看。

4. 第二個 train_dis_() 是可以使用的分佈式多機多卡方法,我判斷應該是異步的。

5. 可以通過 CUDA_VISIBLE_DEVICES=0,1 這句話來控制使用某個 GPU。或者在 main.py 中加入下面一句話設置。

三、佈置訓練階段#

第一種情況(單機單卡,單機多卡):

設置好 main.py 中調用的 train 的方法和路徑,直接運行:

python main.py

默認就是訓練模式

第二種情況(多機多卡):

只要在命令行指定了 --job_name,自動就會運行分佈式訓練。

先將所有文檔和數據集分別分發到各個伺服器當中去。

比如我現在只有兩台伺服器 10.100.1.151 和 10.100.1.120

我現在是要把 151 伺服器同時作為 ps 和 worker

把 120 伺服器作為 worker

需要先在 arg_parsing.py 中設置好 ps_hosts 和 worker_hosts,用逗號間隔開,不要有空格。

然後需要現在 151 伺服器運行:

CUDA_VISIBLE_DEVICES='' python src/main.py --job_name=ps --task_index=0

這裡說一下 CUDA_VISIBLE_DEVICES='' 表示不使用 GPU,因為作為參數伺服器,可以用 CPU 處理的。

接下來,繼續在 151 伺服器運行:

CUDA_VISIBLE_DEVICES=0 python src/main.py --job_name=worker --task_index=0

最後在 120 伺服器運行:

CUDA_VISIBLE_DEVICES=0 python src/main.py --job_name=worker --task_index=1

可以通過 CUDA_VISIBLE_DEVICES 這句話來設置需要啟用的 GPU,序列用逗號隔開。

四、測試#

特別提一下多機多卡只會在 index 為 0 的主機上保存 ckpt。

準備好測試集的.tfrecords,配置好路徑,在命令行運行:

python main.py --mode=testing

必須指定測試模式。

後記#

命令行參數可以研究一下,雖然很多,但都很簡單。

後續我會持續更新。。。

1. 同步異步(2018.04.09 搞定)

2. 去均值,歸一化(2018.03.20 搞定)

3. 可視化(2018.03.16 搞定)

4.debug(2018.03.19 搞定)

5.validation (2018.03.26 搞定)

6. 關於顯存一直被佔滿的問題(2018.03.22 搞定)

7. 準備更多網絡模型文檔 (2018.03.19 mobilenet,2018.03.22 resnet)

8. 選 GPU(2018.03.19 搞定)

9. 優化可視化的網絡結構圖(2018.04.02 搞定)

10.Finetune(2018.03.29 搞定)

11. 新問題,網上沒找到解決辦法。異步分佈式訓練完成後,最後一次記錄 event 會失敗。是因為當 index=0 主機 run_context.request_stop () 時,其他機器可能在 validation 階段導致的。(2018.04.11
搞定)

1668714987733.jpg

12. 新問題,分佈式同步訓練環境下,經過 validation 階段後 global step 和 i 出現不對應問題。具體看圖。

index=0 機器:

1668714995590.jpg

index=1 機器(990step 卡住,等待 0 機器 validation 結束。):

1668715002213.jpg

我想到的解決辦法是把 log 和 validation 寫成 hook 加到 MonitoredTrainingSession 中去,不過嘗試後發現問題並沒有得到解決。(2018.04.10
解決)

這個也和下面問題有關係:

到 validation 這一步的時候,性能不同的機器會不同步進行 validation。

順序是:當到達 validation 步驟時,性能好的機器先進行 validation,等完事後,性能差的機器才會進行 validation。

這會增加整體訓練的耗時,具體原因我觀察是:如果設置 validation 步驟為 1000 的話,當 sess run 1001 步時,1000 步的參數才會傳給 ps 機器更新後傳回 worker 機器然後繼續 1001 步
訓練。(不知道你們能讀懂不 - 0-,MonitoredTrainingSession 這種會話每次運行時其實都是分三步,begin,before run
和 after run。參數傳遞給 ps 機器,再返回給 worker 機器應該都是在 before 這一步進行的。)
(2018.04.02
重寫 MonitoredTrainingSession 後,只在 index=0 機器上進行 validation)

每次同步模式訓練完,index 0 機器會卡住一會,然後報錯:

1668715013234.jpg

Google 搜了一下,沒找到解決辦法。不過不影響我們整體訓練,無視之!

  1. 有一個疑惑,在 tensorboard 中觀察發現 val_loss 是每 100 步記錄一次。但實際我是每 1000 步才跑一次 validation。有點懵逼。

  2. 同步訓練中,性能好的機器會先一步開始訓練。如果主機沒先開始訓練的話,tensorboard 中初始步驟將不是從 1 開始的。

---------2018.03.16 更新 ----- 可視化 -------

重寫了一個網絡結構文檔(squeezenet.py),優化了參數計算過程,添加了 summary 代碼進去,可以在 tensorboard 上查看很多內容了。

相應更新了其他文檔。

如果想用回老的網絡結構文檔(network.py),需要在 train.py 文檔中,改動 inference 那一句代碼就好了。

把 index=0 伺服器上 models 目錄傳回自己的主機,在命令行運行:

tensorboard --logdir=models/

在瀏覽器地址欄輸入:

localhost:6006

就可以查看可視化內容了。也可以在伺服器上運行 tensorboard 命令,然後在自己主機瀏覽器地址欄輸入 IP:端口號,這樣查看可視化內容。

---------2018.03.19 更新 -----DEBUG-------

在 train 代碼中添加了 debug 代碼,只有一行。在 tf.train.MonitoredTrainingSession 中 hook 列表中,在 arg_parsing.py 中設置是否開啟 debug 模式

在 API 中還發現了一種在 tensorboard 上調試的接口 tfdbg.TensorBoardDebugHook (),不過我的主機 tensorflow 版本 1.2 還沒這個接口,就沒測試。看個人習慣了,喜歡在命令行調試還是在 tensorboard 上調試。

同時修改了參數代碼,每次運行必須指定訓練模式。

---------2018.03.20 更新 ----- 去均值、歸一化 -------

  1. 修改了 img2bin_list.py,最後會計算並打印 bgr 三通道均值。

  2. 修改了 arg_parsing.py,增加了均值參數。

  3. 修改了 dataset.py,在數據讀取的時候增加了去均值和歸一化操作。

---------2018.03.21 更新 ----- 增加網絡模型 -------

1. 修改了 arg_parsing.py, test.py, train.py

2. 增加 mobilenet 和 mobilenet v2 網絡模型

** --------- 2018.03.22 更新 ----- 增加網絡模型,解決 GPU 內存問題 ------- **

1. 修改了 arg_parsing.py, test.py, train.py

  1. 增加 resnet-50, resnet-101, resnet-152, resnet-200 網絡模型

  2. 解決了一運行就將 GPU 內存佔滿的問題,但是只在單機上好用,在分佈式環境不行。

---------2018.03.26 更新 ----- 在訓練階段中增加了驗證階段 ------- ****

對 train.py 改動比較大,對所有網絡結構.py 也有改動,要求 tensorflow 版本至少 1.4.0。

原因是 tf.variable_scope () 中沒有 reuse=tf.AUTO_REUSE 。

當然如果你能自己一個一個設置 reuse,理論上也可以用低版本 tensorflow 的。

比較麻煩而已,需要判斷是 train 還是 val,然後分別設置 reuse 為 False 還是 True

---------2018.03.29 更新 -----Finetune------- ****

可以進行 finetune 了

我是在自己之前訓練出的模型的基礎上 finetune 的,

還沒去找開源的訓練好的模型。 ( 2018.04.02 在 Github 上沒找到合適的預訓練模型,並且即使找到了也有可能面臨一些問題。)

在命令行指定模型保存路徑就可以自動 finetune 了

--finetune=path/

---------2018.04.02 更新 ----- 優化了可視化效果 ------- ****

  1. 把訓練階段和驗證階段 summary 分別放到了不同 namespace 中, 網絡結構圖也做了優化。

---------2018.04.09 更新 ----- 同步異步訓練 ------- ****

  1. 在分佈式環境中,添加了一個布爾開關(--issync)來控制同步還是異步更新參數訓練。

  2. worker 伺服器一定要按 index 從 0 開始的機器一個一個運行程序, 如果不按順序運行程序的話,會使各個伺服器 step 差距很大。

  3. 重寫了 MonitoredTrainingSession,將 log 和 validation 分別寫進兩個 hook 中,並且同步模式下只有 index=0 的 worker 機器上會進行 validation。

---------2018.04.10 更新 ----- 解決 log 輸出 step 不匹配問題 -------

  1. 分佈式,同步訓練環境下,通過在 hook 中 run_context.session.run (global_step) 讀取全局 step 來控制 log 和 validation,解決了不同機器之間 step 不匹配問題。

---------2018.04.11 更新 ----- 解決異步訓練記錄最後一次 event 失敗問題 -------

  1. 將異步訓練也改成通過讀取 global_step 來控制,在 ExitHook 中強制 index=0 主機在最後階段做一次 validation,保證其他機器先執行 run_context.request_stop ()。這樣解決了記錄最後一次 event 失敗的問題。我理想中解決這個問題的方法是 index=0 主機發現當前 global step 達到訓練結束次數的時候,先等待其他機器都 request stop 後,自己才 request stop。

---------2018.04.13 更新 ----- 添加了 SSD 代碼 -------

  1. 具體模型保存路徑和數據路徑要設置好

  2. 數據路徑下圖片和 xml 文件要分別保存在兩個目錄中

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。