---
# System prepended metadata

title: Object Detection in Docker

---

# Object Detection in Docker

[TOC]


## 初探Dokcer
### Docker是什麼？
**Docker**是個開放原始碼的容器化平台，大致概念為：
利用Linux系統可以分離硬體資源的特性，可以供使用者創建許多**容器**(Container)並有效分配所需的資源給容器，容器裡面跑的東西多or難，分配的資源就多，反之亦然，不同於VM一開就佔了許多硬體+給你滿滿的OS。
專案開始時，使用者可以使用各家程式語言官方提供的**映象檔**(image)建立新的容器(當然也可以從0開始建立，就像拿到新電腦一樣)，並在容器內根據需求逐步加入套件、插件、檔案等等，並隨時可以**提交**(commit)成新的映象檔，不管是要部署服務或是交接給同事，都可以讓拿到映象檔的人/單位/硬體馬上從現有進度繼續開發。

現在大多數的語言都有Docker image支援：
[Java](https://hub.docker.com/_/openjdk)
[Python](https://hub.docker.com/_/python)
[C](https://hub.docker.com/_/gcc)
[Swift](https://hub.docker.com/_/swift)
甚至連windows裡讓一堆人頭大的深度學習環境[Tensorflow](https://hub.docker.com/r/tensorflow/tensorflow)都已經有人幫你準備好，連版本總是對不上的CUDA/CuDNN都一併整合進去了。

只要把Docker主程式裝起來，上Docker Hub下載需要的image版本，輸入指令`sudo docker run`，就能一秒~~從沒用過Docker的人變成會用Docker的人~~將原本在作業系統中需要裝東裝西的開發環境建立起來。

> 小雞有話要說：
> 兩年前同學叫我試試看Docker、說Docker真的很方便，我是萬分抗拒(拒絕脫離舒適圈)，這幾天用下來真的很後悔沒有早點學起來，**原本跟windows相容性很差的環境，現在用docker一樣跑在windows裡面->超順而且超好重製**。
> 

### 為什麼用Docker?
坊間已經有許多相關文件可以參考Docker的優點，這邊大至列出重點如下：
1. 在A地(可以是PC、Server,OS包括windows、linux...... etc.)能成功執行的Container，搬到B地後(或給同事使用)，只要Docker主程式裝得起來，就可以再次成功執行相同的環境、程式及服務。
-> 我可以，你也可以
2. 在PC(A地)開發某個服務，熟悉Docker的話可以直接在容器裡面部署需要的環境，如此就算換電腦、上雲端，只要將PC上容器裡面的環境打包成映像檔 (image)，上傳至Docker Hub或是輸出成檔案，就可以10秒內在別的地方建立起一樣的環境。
-> 會Docker前，換一台電腦要花一整天設定，會Docker後，新電腦來了馬上就能繼續開發
3. 將版本控制的範圍從程式碼提升為整個環境
-> 我不會用Git Hub，但反正我Docker打包後不只包了程式碼，連整個環境都一起包軌
4. Docker的容器比VM輕量化許多
-> 我沒用過VM，但聽說開一個VM很花時間也很吃資源，開一個Docker Container只需要幾秒+不佔資源
5. 達成Devops & CI/CD的重要里程碑
-> 結合自動部署框架如kubernetes(k8s)，可以快速部署開發完的Container至多台server上建立高負載服務，將開發<->維運間所需的人力/時間成本及難度大幅降低

### 使用Docker要做好什麼心理準備？
過來人的經驗：
1. 放棄圖形介面，擁抱遠離舒適圈的Terminal
2. 熟悉Docker基本操作後，其實多數東西還是滿友善，除了**網路**，但開發的時候還是在PC上為主，未來部署服務時再研究網路並不遲。
3. Docker是基於Linux開發的軟體，同第1點，需要跳脫舒適圈，熟悉沒有GUI、只有指令的開發環境(不用太擔心，環境建好後，還是可以用如同CS code、Jupyter等IDE將Docker容器裡的環境remote出來)
4. 用過就回不去了，會中毒


## 開始使用Docker
上面提到Docker是基於Linux系統開發的，那其他非Linux/大量使用GUI的作業系統該如何使用Docker呢？
Docker官方已經幫各種主流作業系統安排好了幾種方式，可以參考網路上的教學資源：
[Mac-官方說明](https://docs.docker.com/desktop/mac/install/)
[Mac](https://medium.com/%E5%AE%B8-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98/mac-%E5%AE%89%E8%A3%9D-docker-%E5%8F%8A%E6%93%8D%E4%BD%9C%E6%8C%87%E4%BB%A4-6a9cfaa55979)
[Windows-官方說明](https://docs.docker.com/desktop/windows/install/)

由於我是windows粉，故後續會使用跑在windows裡的docker做說明，
上述提到幾種Docker的安裝方式，但既然Linux對工程師來說是很重要的語言，甚至Docker是只能在Linux中運行的軟體，其他作業系統還要使用類VM的方式才能順利使用，*長痛不如短痛*，在這邊推薦一個在windows中可以有最佳原生docker體驗的方式 -> 用**WSL2運行docker**

### WSL2是什麼？
WSL全稱為Windows Subsystem for Linux，大意就是能在Windows內運行的Linux Kernel(內核)
WSL一代跟著windows 10一起上線，有滿多缺點，近幾年微軟更新了WSL2，號稱跟原生的Linux差不多，對深度學習開發人員來說最大的升級是現在可以透過CUDA抓到Nvidia的GPU(一代的wsl沒辦法使用GPU)，如此就能將全套Deep Learning開發環境避開難搞的windows、並透過Docker無痛移植到各處。

除此之外還能順便熟悉真正Linux的操作，而不是各種四不像的command

### WSL2安裝
網路上安裝資源有非常多，這邊只稍作整理：
1. 確認Windows版本 >= 19041 
點擊左下開始 -> 設定 -> 系統 -> 關於 -> windows規格
![](https://i.imgur.com/wDqX6e4.png)
建議最好要到**20H2**，若要使用GPU進行深度學習開發，則至少要**21H2**

2. 開啟Hyper-V
控制台(檢視方式切換成"大圖示"或"小圖示") -> 程式和功能 -> 左邊"開啟或關閉Windows功能" -> 找到Hyper-V並打勾
![](https://i.imgur.com/FoTMPI5.png)
按下確定後他會問你要不要關機，先不要！

3. 啟用wsl及vm功能
以系統管理員身分開啟Powershell，執行下列命令
啟用wsl
`dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart`
啟用vm
`dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart`


4. 下載並安裝Linux核心更新套件
[點這裡下載](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi)
下載並安裝，不安裝的話很容易在等等安裝Linux時報錯，反正先裝就對惹~

5. 重開機

6. 將wsl2設為wsl服務的預設版本
一樣打開Powershell輸入並執行下列指令
`wsl --set-default-version 2`

7. 安裝Linux發行版
打開Microsoft Store搜尋並下載安裝慣用的Linux發行版，我自己是用`Ubuntu 18.04 LTS`，若沒有特別喜好的話可以一樣裝這個版本
![](https://i.imgur.com/i81LaFC.png)

8. 安裝好用的終端機工具Windows Terminal
光windows就有兩種命令列 -> CMD跟Powershell，東開西開很不方便，wsl又是另一個介面，Windwos Terminal將可以用的整合各種命令列整合進來，並可以像Chrone一樣用頁籤管理不同的命令列，相當方便。
![](https://i.imgur.com/BMkbZRk.png)
可以直接在同個視窗使用不同的Terminal
![](https://i.imgur.com/zlPAR7X.png)

9. 初始化Linux並註冊Linux使用者
開啟Microsoft Store安裝發行版Linux的頁面，裝好之後有個**開啟**鈕(如上方圖)，點擊後會自動開啟CMD，第一次啟動需稍等數秒至數分鐘進行初始化，等到輸入使用者名稱的提示出現(如下圖)後，及註冊帳號密碼(僅在本機運行)並開始使用。
![](https://i.imgur.com/FPimC1Y.png)

10. 打開Windwos Terminal，確認是否安裝成功
安裝成功的話，對著Windows Terminal點右鍵，應可以看到剛剛安裝的Linux發行版，點擊即可使用wsl2進行開啟。

11. 更換Systemd
很多Linux套件都需要systemd來管理跟啟動服務，由於WSL2是Ｗindows下的一個VM，所以微軟實作了一個init (PID 1) 來做到快速啓動WSL VM以及作為與windows溝通的橋樑，使用現成的Github資源：
依序輸入下列指令(`$`記號不用輸入)

    `$ sudo apt install git`
    在wsl2安裝git (可能會想明明電腦有裝過啊怎麼還要再裝一次 -> 因為WSL2是獨立於Windows的環境(可是檔案又能共用，超方便))

    `$ git clone https://github.com/DamionGans/ubuntu-wsl2-systemd-script.git`
    將需要的資源抓下來

    `$ cd ubuntu-wsl2-systemd-script/`
    `$ bash ubuntu-wsl2-systemd-script.sh`
    照著打就對了，接著重開一個Terminal，輸入`systemctl`
    如果有跑出一堆東西就表示裝成功了

11. 開始體驗Linux

### 在WSL2裡安裝Docker
其實這一步就跟在Linux裡安裝Docker一樣，畢竟WSL2是直接使用Linux的內核，步驟如下：

1. 在WSL2環境(打開Windwos Terminal選剛剛安裝的Linux就對了)安裝需要的套件
`$ sudo apt-get update`
```
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
```
給第一次使用Linux/Command Line的人：錢字號(`$`)不用複製，`$`表示命令列已就緒可以執行下一個指令，sudo則代表"以系統管理員身分執行的意思" sudo -> super user do

2. 加入Docker官方金鑰
`$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg`
這裡因為版面所以換行了，但看錢字號`$`就知道這是同一個指令

3. 官方說要這一行
```
 $ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
這一串有兩個錢字號，但指令只有一個，第一個錢字號之後開始全部複製過去執行就對了


4. 安裝Docker引擎
`$ sudo apt-get update`
`$ sudo apt-get install docker-ce docker-ce-cli containerd.io`
安裝Docker ce版(Community Edition)

5. 安裝好了，來個Docker版的Hello world
`$ docker run hello-world`
直接執行應該會遇到Permission相關的錯誤，之後在docker指令之前都記得加上`sudo`
`$ sudo docker run hello-world`

![](https://i.imgur.com/T0ZCi7W.png)
若跑出圖中的結果就代表docker安裝成功囉！

## Docker指令

### 基本概念
Docker的指令說多不會比Linux作業系統多，但說少，其功能也涵蓋了容器、映像檔、儲存空間乃至於網路的諸多操作，本節將大致介紹Docker指令的規範及組成。

來個開啟容器很常使用的指令：
`$ sudo docker container run -it --gpus all --name Clement -v /c/Users:/Workspace -p 8888:8888 Image_01`

除了Linux常見的sudo之外，指令的其他部分分別為
| 命令開頭   | 上級指令 | 下級指令 | 選項 | 對象 |
| -------- | -------- | -------- |-------- | -------- |
| docker   | container| run  |-it --gpus all ... :8888 | Image_01 |

這行指令在`sudo`後，緊接著的是`docker`，幾乎所有的docker指令都以`docker`開頭，告訴(容器內)作業系統這個指令將對某個docker內部元件進行操作。
`docker`後則接著一個`上級指令`，直接點出此行指令運用的是docker提供的哪一項功能，如上方範例中使用的是`container`，表示這一行指令將透過docker進行一個容器方面的操作。 
`上級指令`後則為`下級指令`，**多為動詞**，直接描述了這行指令欲進行的動作，如此處為`run`，預期指令執行後會有某個container被run起來。
多數情形下，一行docker指令只會有**上、下級指令各一個**，點明要對哪個功能進行怎樣的操作，而接在指令後的`選項`及`對象`則無此限制。
`選項`為下級指令一些可調整的內容，如`-it`代表run起來的容器可以用終端機進行互動、`--gpus all`告訴容器要去抓出所有電腦中的顯示卡，`--name Clement`將run起來的容器命名為Clement、`-v`則可以掛載PC裡的儲存空間到容器裡面，最後`-p`將容器內部的port號8888與電腦本機的port號8888進行對應，如此就能直接透過網路訪問容器。
選項使用減號`-`指定，可注意到上方範例中同時存在單減號`-`與雙減號`--`，使用**縮寫**的選項(如：i、t、v、p)用**單減號**`-`指定即可，**非縮寫**的選項(如：gpus、name)則使用**雙減號**`--`進行引用。 至於範例裡面的`-it`為什麼用單減號呢？  因為那是把`-i`跟`-t`這兩個基本上會一起出現的縮寫選項寫在一起~
指令的最後則為`對象`(有時`對象`之後還可以設定`參數`，但不常見所以這裡就不做說明)，代表這行指令要操作的對象，使用docker裡容器的功能run一個映像檔進而產生一個容器，被run執行的是一個映像檔，所以範例指令中最後的`對象`為一個叫做Image_01的映像檔。

`$ sudo docker container run -it --gpus all --name Clement -v /c/Users:/Workspace -p 8888:8888 Image_01`
這行指令解釋完了，相信它的組成還算直觀，而docker也很貼心的為許多常用的指令設定了省略寫法，多為省去上級指令的部分，像是run只會用在產生新容器，所以上級指令container可以直接不用寫出來，範例指令可以直接寫做：
`$ sudo docker run -it --gpus all --name Clement -v /c/Users:/Workspace -p 8888:8888 Image_01`
docker內常用的上級指令包括：


| 上級指令 |對應功能  | 
| -------- | -------- | 
| container    | 容器     | 
| image     | 映像檔     | 
| network    | 網路設定     | 
| volume    | 儲存空間     | 

其中`container`與`image`因為最常被使用，所以省略寫法較常出現在這兩個上級指令上，`network`及`volume`指令則多半不可省略。

### 常用指令
由於坊間的教材、指令大全等一定會比我介紹得完善，要正式使用Docker於開發、部署服務等，一定要針對需要的功能查詢官方文件。 此節僅針對幾個超常用的指令組合作說明。

* 啟動Docker：`$ sudo service docker start`
理論上Docker安裝好後就會是啟動狀態，如果指令怎麼打都沒反應，可以輸入這行啟動Docker試試看
* 下載已有的官方/他人提供的映像檔：`$ sudo docker pull <image_name>`
幾乎所有容器(container)都是從映像檔(image)開始，下載官方已經設定好環境的映象檔可以省去許多部署環境的時間
* 使用映像檔開啟容器：`$ sudo docker run -it --name <set_container_name> <image_name>`
這裡使用run指令透過某個映像檔開啟映像檔作者設定好的環境，並帶了一些選項，包括：
`-it` -> 代表這個容器可以透過***終端機***進行***互動***(終端機裡的終端機，超酷)
`--name` -> 這種單字組成(非字元，如上面的-it其實是-i跟-t寫在一起，非一個單字)的選項要加上兩個減號`--`，這個選項用來命名指令生成的容器
(可以帶的選項還有很多，有遇到再介紹)
* 跳出容器(容器會繼續開著不會停擺)：`先ctrl+p再ctrl+q `
我也不知道為什麼是這個組合，反正官方是這樣教
* 查看現在有哪些容器開著：`$ sudo docker ps`
其實這是指令`$ sudo docker container ls`的縮寫，使用縮寫可以省去一些打字的時間，如果要看到"還存在但沒有在運行"的容器，可以加上選項`-a`，即可看到所有存在電腦中的容器

來個組合技：執行docker run，使用python官方釋出的映像檔開啟一個名為`clementisgood`的容器，ctrl+p再ctrl+q退出容器，並用docker ps查看現在有哪些容器正在運行(Status這一欄是容器狀態，Up代表運行中)
![](https://i.imgur.com/VexwWlT.png)

* 跳出容器後再跳進去：`$ sudo docker exec -it <container_name> /bin/bash`
我剛開始使用docker的時候不敢離開容器因為不知道怎麼回去，後來發現原來可以使用指令`exec`，並在最後加入`/bin/bash`啟用bash指令，如下圖，執行後發現命令列的長相不太一樣了(以管理員身分進到容器中了)
![](https://i.imgur.com/0SDYdAL.png)

* 覺得容器建立得不錯，可以保存成一個映像檔：`$ sudo docker commit <container_name> <set_image_name>`
一個存檔的概念，使用設定好的容器生成一個映像檔，下一次可以直接再docker run這個映像檔，即可重現這個你覺得設定得很棒的容器、也可以交接給公司內其他同事使用

* 查看電腦裡有哪些映像檔：`$ sudo docker images`
此為`$ sudo docker image ls`指令的縮寫，查看電腦裡有哪些映像檔可以隨時啟動容器，如果docker run時指定的映像檔在電腦裡找不到，docker會自動下載並保存，下一次執行`docker images`時就會看到新增了一個映像檔

以上列出的docker指令大概只佔全部指令的1/5，但已經夠用來進行docker初探及開發了

## 使用設定好的映像檔訓練一個Object Detection Model
### 故事一則
今年(2022)年後開工第一天 2月7日下班前，伯任突然來訊息，問我能不能測試一下物件偵測(Object Detection)算法，2月9日的故宮會議可能需要Demo，雖然物件偵測算法是深度學習裡面數一數二複雜的，但去年畢業前為了論文與專案也認真鑽研了一陣子物件偵測，心想拿之前留存的code出來應該設定一下就能跑。
但那時新電腦還沒收到，我手邊有Nvidia GPU的電腦只有我用一用會冒火花的筆電(目前主流的深度學習框架皆須使用Nvidia顯示卡進行加速)，經過碩士兩年摧殘，裡面更裝了一堆有的沒的軟體，環境可謂糟糕透頂，不過還是對自己滿有信心，畢竟做了兩年深度學習，環境設定等還是滿熟的。
隔天早上8點多到班後，就開始復刻記憶中各個套件的版本，沒想到兩個主要的框架(Tensorflow=2.1.0 & Keras=2.4.3)用我記憶中的版本安裝居然互斥了，既然版本對不上也沒關係，照著錯誤訊息及Stack overflow上的建議不斷微調理論上也可以順跑，但一路測試到中午12點，各種連程式都沒辦法有效反應問題的錯誤訊息(單純空白之類的)還是不斷跳出，只能放棄轉而求助以前研究室的夥伴。
夥伴建議我別再用我論文裡面使用的、2016年的算法，現在有更新而且是由Google推出的Model zoo(一堆現成的Models如動物園般供人參觀並使用)，不管算法的準度、新潮度以及嚴謹性都相當有水準，還有一堆API可以照著官方文件操作不用自己寫，唯一的缺點就是使用的框架`Tensorflow`跟windows的相容性不忍直視，我忘記早上的慘劇，心想再怎麼難，照著官方教學做不也就只是一、兩個小時的事情。 接著，等我真的設定好環境、訓練好模型(因為電腦太爛所以只訓練大概1/10的時間)、做出蝴蝶影片+物件偵測的demo，已經是晚上12點了。
![](https://i.imgur.com/5ig628S.png)
截圖為證

在中午12點到晚上12點這12小時間發生了些什麼問題呢？
* 要安裝C++ 2015 windows開發套件，官方指定要2015的版本，結果官方下載工具好像在UTM+8時區因為網路問題所以怎麼裝都裝不起來
* windows的路徑寫法如`"D:\Kaggle\1月Playgroung"`使用的\斜線在API裡面會造成程式誤判，使用python慣用的寫法(加上原始字串的標記r)`r"D:\Kaggle\1月Playgroung"`，那個r又被程式抓去搞些有的沒的，最後發現只有寫上雙斜線`"D:\\Kaggle\\1月Playgroung"`能work
* 要安裝Google推出的文件協定`Protocol Buffers`並將官方開源碼從`protoc格式`轉換為`.py檔`，結果官方提供的指令不能在windows cmd裡正常運作
* 要自己寫一個`"pbtxt"`格式的文件，結果windows一直把我副檔名弄成`XXX.pbtxt.txt`

在收到新電腦後，有了前面的經驗以為可以快一點安裝完成，沒想到模型跑出來又已經是晚上8點的事情了。


### Linux的威能
從上面提到的幾個發生的問題，就能發現深度學習框架跟windows真的八字不合，若改成Linux的話......
* Linux直接內建需要的C++套件
* Linux的路徑寫法沒有反斜線，都是正斜線像是/bin/bash/python，程式直接讀沒有問題
* 官方釋出的指令直接就是linux指令
* 使用`$ touch filename.pbtxt`指令加上`vim`文字編輯器，完全沒有被windows改檔名的問題

2022/3/15我用Tensorflow官方釋出的docker image、自己安裝需要的套件、git clone Model zoo的原始碼並照著官方文件(Linux版)在docker容器裡安裝API，僅花了1個半小時就能順利開始模型的訓練，其中還有20分鐘左右是我自己少寫一個參數導致docker沒有讀到我的顯示卡。

成功運行後，我ctrl+p、ctrl+q退出並將設定好的docker容器commit成映像檔：`billas104/od_master:emctv3`，以下將帶大家直接使用這個設定好的容器在自己電腦上訓練一個物件偵測的Model。

### 打包下載直接用
這個文件主要帶大家體驗docker的操作及方便，所以深度學習領域一些細節及資料處裡就不多敘述，已經幫大家準備好需要的訓練、地真資料**並且直接包在iamge裡面**(就是這麼方便)，大家可以透過幾行指令把資料送進程式裡面進行訓練。
首先使用指令`$ sudo docker pull billas104/od_master:emctv3`將我包好而且push上Docker Hub的映像檔抓下來，映像檔的名字docker是如此規範的：
`<帳號/使用者名稱>/<程式名稱>:<tag(版本代號)>`
所以映像檔**billas104/od_master:emctv3**，可以解讀為**使用者billas104**(就是我的docker帳號)寫的程式**od_master**(物件偵測master)，版本為**emctv3**(為了把操作流程最簡化所以包了3次)。

下載完後可以輸入指令`$ sudo docker images`檢查映像檔**billas104/od_master:emctv3**是否有出現在清單中。
確認下載成功後，使用指令`$ sudo docker run -it --name <名字自己取> --gpus all billas104/od_master:emctv3`執行映像檔並產生一個容器，選項`--name`可以自己為這個容器命名，`--gpus`則取決於你的電腦是否有**Nvidia的顯示卡**，如果沒有的話直接把`--gpus all`拿掉否則會報錯。
無顯示卡的版本：`$ sudo docker run -it --name <名字自己取> billas104/od_master:emctv3` 

接著應該就會看到命令提示字元從`$`變成`#`，代表你順利開啟容器並能以管理員身分跟他互動啦~
![](https://i.imgur.com/XvpW33v.png)
我目前正在研究怎麼編寫打開容器時彈出的訊息 -> 總有一天要換成小雞圖案

熟悉Linux系統的同仁可以自行操作指令觀察內部檔案結構，不熟的話可以使用下方的指令進入目標資料夾：
首先須要進到我存放執行檔的資料夾/Object_Detection_Master/Data/Scripts
Linux進入指定路徑的指令為`# cd /Object_Detection_Master/Data/Scripts` (一樣，提示字元`#`不用寫)

使用指令`# ls -l`可以瀏覽Scripts目錄裡面有哪些檔案，應該會看到3個.py檔及一個Readme.txt，使用指令`# vim Readme.txt`可以透過vim(Linux的文字編輯器，已經幫大家安裝好了)進行閱讀，了解三個.py檔的用途以及該如何執行。

不過大家對這個容器裡的檔案結構應該還沒有非常熟悉，可以先照著我的指令操作就好，也可以參閱[這裡](https://tensorflow-object-detection-api-tutorial.readthedocs.io/en/latest/training.html)，我的檔案結構大致上跟這篇教學差不多。

下一步將把我放在路徑/Object_Detection_Master/Data/train以及/Object_Detection_Master/Data/test裡的影像&地真檔案轉換為框架Tensorflow可以高效存取的格式`.tfrecord`，輸入下方兩個指令透過腳本generate_tfrecord.py分別轉換訓練資料(train
)跟測試資料(test)
```
# python generate_tfrecord.py -x ../Butterfly_test/train/ -l ../Butterfly_test/annotation/label_map.pbtxt -o ../Butterfly_test/annotation/train.record
```
```
# python generate_tfrecord.py -x ../Butterfly_test/test/ -l ../Butterfly_test/annotation/label_map.pbtxt -o ../Butterfly_test/annotation/test.record
```
看到終端機顯示"Successfully created the TFRecord file: ../Butterfly_test/annotation/test.record"就代表執行成功啦！
![](https://i.imgur.com/pnc7LKN.png)
**注意！** 光這個步驟在2月8號時就花了我3小時在測試


---

準備好正確格式的數據，就可以使用寫好的`model_main_tf2.py`開始訓練模型了，輸入指令：
`# python model_main_tf2.py --model_dir=../Butterfly_test/Models/Test_model_docker/ --pipeline_config_path=../Butterfly_test/Models/Test_model_docker/pipeline.config`

如果終端機跑出一堆訊息、沒有報錯，接著在等候許久後出現這個畫面：
![](https://i.imgur.com/0RMGJmz.png)
就代表順利開始訓練啦~！
從訊息中可以看到每一個訓練步驟在有GPU的電腦上為0.3秒左右(Step ___ per-step time 0.339s，頭幾個step因為包含模型初始化所以會稍久一點)，裡面可以看到幾個深度學習常見的參數：損失分數(loss)及學習率(learning rate)，具體這個模型的架構、超參數以及訓練模式等我寫在上方有調用的設定檔"pipeline.config"裡面，由於非今天主題，就不多做介紹，可以自行cd到路徑並用vim查閱config檔裡的內容。

目前在config file裡設定要訓練的step總共有25000，在無GPU的電腦上訓練，一個step可能就需要2~3秒，等到25000個steps訓練完差不多一天就過了，所以體驗完開始訓練模型後，可以直接ctrl+c(就是windows裡面的複製指令，在linex指令中這代表終止當前動作的意思)終止訓練的過程，如果使用的電腦有GPU、或是真的想導出上面訓練出來的模型看看它長什麼樣子，可以到/Object_Detection_Master/Data/Butterfly_test/Models/Test_model_docker資料夾查看"ckpt-"開頭的檔案，這是模型每訓練1000個step所記錄的checkpoint，是可以另外透過tensorflow程式碼執行的、帶有模型架構的紀錄檔，也可以使用Scripts裡面最後一個腳本`exporter_main_v2.py`將這些訓練紀錄匯出成正式的tensorflow模型格式，使用方法可參閱`Readme.txt`。


## 結語
訓練模型，包括調整模型架構、硬體平行計算的規劃、訓練超參數的微調等等全部都沒有出現在上述的指令裡面，所以訓練出來的模型長什麼樣子我甚至不確定能不能有效收斂，雖然這篇體驗docker的操作講解最後生出來的模型可能用都不能用，但回想2月8號我光讓模型能順利開跑就花了近**10小時**，這還是我接觸深度學習領域2年的所需時間。 而現在只要安裝docker、pull映像檔下來、run一個容器，再照著映像檔作者設定好的模式運作，一個從來沒用過python、沒有深度學習經驗的人在一個小時的時間內開始訓練模型絕對綽綽有餘。

就這個小型專案(雖然準備這個映像檔，從建立環境、打包到數次測試還是要一些時間)的體驗而言，相信有照著步驟執行的同仁一定能感受到docker的威能，兩年前的我就算照著網路上環境建置說明，沒給我1個月基本上連個不太準的簡單模型都做不出來。 而使用docker，直接在環境設定這邊開了捷徑，連一堆參數、路徑等等都不用擔心因為設備不同而產生變因，只要能把docker裝起來，我這裡能成功執行的容器在你的電腦上也一定可以。

最後~ 感謝所有有耐心閱讀到這裡的同仁xD 
Docker以及後續K8s的探索會持續進行，有任何問題或是想加入一起研究的話歡迎隨時跟我說！ 也希望有天能順利讓公司的服務跑在Docker中並透過K8s自動部署到各種環境，如此節省下來的時間/人力成本以及透過Docker+K8s達成的更大服務負載上限，期待能有效推進公司在業務/技術上的成長，放眼台灣、征服世界指日可待！
