從學生時期開始接觸機器學習,當初以為的 Machine learning 就只要會處理資料、訓練模型、得到比較高的準確率,然後就此結束,但出社會後發現,從 Jupyter 到 Production 的路還有段距離,那該怎麼辦呢?
因此,接下來將會分幾個章節來介紹:
- 建立 GCP 機器 — VM 執行個體
- 建立機器學習環境 (GPU environment)
- Pytorch 介紹與範例 (image classification)
- Data science 的版控 → DVC 的建立與使用
- 利用 Flask 部署機器學習套件
- 利用Docker 建立機器學習容器
為什麼需要用 Docker ?
由於在每個專案、每個模型所要建立的環境都不同,有些是用 Tensorflow 框架寫的、有些是用 Pytorch 框架寫的,環境變數、 Library 的要求都不同、設備要求也都不同,這個時候如果使用 Docker 就可以很輕易的解決這些問題,因為 Docker 能夠建立獨立的的環境,能夠與外界隔絕,因此可以在 Docker 內部設立專屬的環境、不被外界影響,詳細的介紹可以參考這裡。
Dockerfile
而要在 Docker 內部安裝什麼套件、建立什麼樣的環境,都是透過 Dockerfile 來進行溝通的,他最基本的指令有幾項:
FROM pytorch/pytorch:latestRUN pip install Pillow
RUN pip install flaskWORKDIR /models
COPY ./script ./EXPOSE 5002
ENTRYPOINT ["bash","run.sh"]
From: 依據哪個 Docker image ,可以直接在 Docker hub 去搜尋已經被建立好的 Docker Image,好處是可以節省自己建立環境、安裝套件的時間。
RUN: 執行的指令,通常會在內部用 pip install
去安裝一些套件
WORKDIR: 去到該資料夾,跟 RUN cd
不同的地方在於,RUN cd
只會在剛行程式碼去到指定位置,但下一行執行時,就又會回到原本的地方。
COPY: 可以將本機端的資料,複製到 Docker 內部所指定的位置
EXPOSE: 開啟的 Port
ENTRYPOINT: Docker 建立好後,需要執行的指令
還有更多其他的指令,可以參考 Dockerfile reference
Docker 基本指令
建立好 Dockfile 後,就可以直接利用 Docker 的基本指令將它實際的建立起來,比較常用到的語法如:
- 查看目前有的 Docker image
$ docker images
2. 建置 Docker
$ docker build -t <Docker image 名稱> --build-arg <變數1=... 變數2=...>.
3. 刪除 Docker image
# 刪除 (-f 表強制)
$ docker rmi -f <id># 強制刪除正在執行的
$ docker ps -a|awk ‘{print $1}’ |xargs docker rm
4. 執行 Docker
# 進入 Docker 內部
$ docker run -it <id> /bin/bash# 若希望 docker 執行後立刻執行服務
# -d: 背景執行
$ docker run -d --runtime=<容器名稱> -p 本機端port:docker內部port <Docker image 名稱>
5. 查看現有的 Container
$ docker ps
6. 停止 Container
$ docker stop <container id>
7. 刪除 Container
$ docker rm <container id>
專案挑戰:化妝品分類
題目:是否能分辨一張圖片有出現哪一個種類的化妝品,而化妝品的種類粗類為 → 口紅、眼線筆、指甲油、粉底液、粉餅、刷具、眼影盤。
進入正題
我們這次選擇的框架是 Pytorch ,這次會延續上一篇 【機器學習從零到一】Day5: 利用 Flask 部署機器學習模型 繼續往下做,因此我們這次會用到的文件為:
./
├── dataset
│ └── classes.txt
├── script
│ └── server.py
├── model
│ └── model.pth
├── log
│ └── eval.txt
├── Dockerfile
└── run.sh
0. 事前準備
- 所需檔案:【機器學習從零到一】Day5: 利用 Flask 部署機器學習模型
- 準備
run.sh
,並且打上
python server.py --model ./model.pth --classes classes.txt --eval eval.txt --port 8891
3. 安裝 Docker ,安裝的步驟為:
Step 1 : 更新
$ sudo apt-get update
Step 2:加入 Docker 的 repository 金鑰
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
Step 3:加入 Docker 官方 repository
$ sudo apt-add-repository 'deb https://apt.dockerproject.org/repo ubuntu-xenial main'
Step 4:更新
$ sudo apt-get update
Step 5:安裝 Docker
$ sudo apt-get install -y docker-engine
Step 6:系統安裝好後會直接啟動 Docker 服務
$ sudo systemctl status docker
1. 編寫 Dockerfile
由於我們這次是用 pytorch
框架,因此我們可以先在 Docker hub 上搜尋 pytorch
,利用別人已經編制好的 Image ,可以節省大量自己建置的時間,我們這次使用的是 floydhub/pytorch:1.0.0-gpu.cuda9cudnn7-py3.40
,會選擇這個 Image 而不是用官方的 pytorch/pytorch
,是因為上面的已經順便建立好 Python 3 的環境,而不用自己重新安裝,因此整份 Dockerfile 就會顯得很簡單,如下:
FROM floydhub/pytorch:1.0.0-gpu.cuda9cudnn7-py3.40
RUN pip install Pillow
RUN pip install flask
RUN pip install requests
WORKDIR /cosmetics-classification
COPY ./script/server.py ./
COPY ./dataset/classes.txt ./
COPY ./log/eval.txt ./
COPY ./model/model.pth ./
COPY ./run.sh ./
EXPOSE 8891
ENTRYPOINT ["bash","run.sh"]
總共只安裝了 Pillow
、flask
和 requests
,其他則是在複製 Local 端的程式碼、模型到 Docker 當中去執行。
2. 建立 Docker
寫好 Dockerfile 後,只要在他所在的目錄執行,下面這段程式碼後,就會開始建立,而若建完後發現有些地方錯誤了,盡量不要去更改執行的順序,因為你會發現,第二、第三次在 Build 的時候,並不會重新安裝上次已經安裝的套件,但如果更換了順序,此時就會被認定為是不同的,因此就會等待更多的時間再重新安裝。
$ sudo docker build -t cosmetics-classification .
3. 執行 Docker
由於我們要用 GPU 來執行我們的模型,但 GPU 是在 local 端,要怎麼讓 Docker 也能用 GPU 來跑呢?這個時候只要照著這篇 NVIDIA Container Toolkit 去安裝 nvidia 的容器,再執行
$ sudo docker run --runtime=nvidia -p 8891:8891 cosmetics-classification
就可以順利的完成。
4. 測試 Docker
可以利用上一篇的方式,去發 request
錯誤訊息:
AttributeError: ‘ReLU’ object has no attribute ‘threshold’
我這邊的解決方式是照著這篇說的,存模型時的方法是存參數、而非存整個模型,實際可以參考這篇文章,我的解決方法是:
import torchvision.models as modelsdef VGG16_pretrained_model(numClasses, featureExtract=True, usePretrained=True):
model = models.vgg16(pretrained=True)
numFtrs = model.classifier[6].in_features
model.classifier[6] = nn.Linear(numFtrs,numClasses)
return modelmodel = VGG16_pretrained_model(numClasses=NUM_CLASSES, featureExtract=True, usePretrained=True).to(device)
model.load_state_dict(torch.load(path))
恭喜
恭喜各位完成了這一系列的實作練習,下一階段正在規劃中,但不外乎會講的主題有:
- 模型的加速 → 如何能同時服務更多的 request
- Data pipeline → 從資料進來到模型評估如何自動化建立
- 資料處理 → 從 Business Intelligence 到 Data Intelligence
若還有想知道的更多 Topic 歡迎在下面留言分享,也不忘按讚鼓勵!