深度學習初學者實用的 Docker 應用

甜不辣馬拉松
13 min readJul 9, 2021

--

目錄
1.Docker 的簡短背景
2.Docker 的使命實作輕量級的作業系統虛擬化解決方案
3.先從虛擬化技術
4.虛擬機器 (Virtual machine) VS 容器 (Container)
5.Docker 核心的三要素
6.實作
6.1 docker pull image from docker hub
6.2 撰寫 docker file
6.3 使用此 docker file build 專屬的docker image
6.4 使用這個 docker image啟一個docker container
6.5 開始在 docker container 訓練一個 mnist CNN 數字分類器
6.6 完成訓練後存取model h5 並且將它 commit 成新的 docker image
7. 小心得

Docker 的簡短背景

Docker 是一個開放原始碼軟體,是一個開放平台,用於開發應用、交付(shipping)應用、執行應用。(來自 Wiki)

Docker 是一個開源專案,誕生於 2013 年初,最初是 dotCloud 公司內部的一個業餘專案。它基於 Google 公司推出的 Go 語言實作。 專案後來加入了 Linux 基金會,遵從了 Apache 2.0 協議,原始碼在 GitHub 上進行維護。(詳細一點的背景可以參考這)所以docker 就這樣被誕生了!!!

Docker 的使命實作輕量級的作業系統虛擬化解決方案

這裡有兩個重點,一個是輕量級,另一個是虛擬化。

先從虛擬化技術

虛擬化想解決的一大痛點是,程式開發完成後,需要於各種不同的平台或硬體間執行,那每每遇到一個新的環境就得重新建置環境設定、重新佈署,是非常的麻煩,有時候甚至會遇到很多環境設定的問題,需要花大量的時間才得以解決,這時候虛擬化技術就十分好用。

虛擬化是一種資源管理技術,它能將一個應用程式所需的執行環境打包起來,建立一個獨立環境,方便在不同的硬體中移動。(補充個虛擬化wiki)

常見的虛擬化技術:
1. 硬體層級的虛擬化: 虛擬機器 (Virtual machine), Virtual Box.
2. 作業系統層級虛擬化: 容器(Container), Docker

更詳細的虛擬化技術可參考:

虛擬機器 (Virtual machine) VS 容器 (Container)

傳統虛擬化

透過Hypervisor使其在虛擬機器的安裝的作業系統可以和原生電腦的作業喜統進行溝通,也因此透過它可在原本的電腦上再安裝另外一套作業系統。

Docker

在Docker 架構上依靠docker engine,使其透過容器管理平台直接將應用程式所需要的環境、程式碼、函示庫等通通打包好,並且建立資源管理機制,使其可分配系統資源並獨立運行。

對比傳統虛擬機總結

容器幾乎是完勝於虛擬機,尤其最後一項,虛擬機在原生電腦能夠啟動一般大約幾十個,但容器可以啟動上千個!!!

總結 docker 確實實現輕量級作業系統虛擬化的目標

Docker 核心的三要素

  • 映像檔(Image) : 映像檔可以用來建立 Docker 容器,可以把它想像成一個靜態的腳本,執行這個腳本就可以啟動docker container,另外 docker 也提供了簡單的機制方便建立docker image 和修正docker image,以及更方便的是使用者可以從其他人製作好的image直接下載來使用。
  • 容器(Container): 容器是從映像檔建立的執行實例: 容器是通過docker image啟動而來,在容器裡面可以做新增、修改、執行、刪除等動作,可以把它想像成一個小型的linux 環境,它也包含著root 使用權限、使用者空間等,另外每個容器都是相互隔離的,也就是說在這個容器內的修改不影響到其他容器,也不會影響原本的docker image,所以換個方式想,通過一個 docker image可以啟動多個 docker container且他們是獨立的。
  • 倉庫(Repository): 倉庫是集中存放映像檔檔案的場所,那倉庫就是存放很多docker image的地方,倉庫也分成公開的倉庫和私有的倉庫,最有名的公開倉庫就是docker 官方維護的 docker hub,在docker hub 上可以很方便下載已經製作好的 docker image 並且直接使用。

實作

實作目標: 建立一個 docker image,並啟動成為 container ,在 container 裡面操作 mnist 資料集,並訓練一個CNN 的數字分類模型,最後再將此 container 輸出成一個新的 image。

流程:

  • 從 docker hub pull 一個有 python 有 tensorflow 的docker image當作base image
  • 撰寫 docker file 安裝一些需要的套件
  • 通過這個 docker file build 專屬的docker image
  • 使用這個 docker image啟一個docker container
  • 開始在 docker container 訓練一個 mnist CNN 數字分類器
  • 完成訓練後存取model h5 並且將它 commit 成新的 docker image

docker pull image from docker hub

docker hub search tensorflow docker image : https://hub.docker.com/r/tensorflow/tensorflow

可以直接使用右側指令

docker pull tensorflow/tensorflow

也可以點選 Tags,找尋更多相關的 images

這次使用的image是 tensorflow 2.2.3 gpu 版本且已經安裝好 jupyter,也是執行下方指令

docker pull tensorflow/tensorflow:2.2.3-gpu-jupyter

下載完成後可以使用指令檢視它

docker images

這樣 base 的 docker image 就準備好了!

撰寫 docker file

docker file 包含了幾個大的架構:

  • FROM: base image
  • MAINTAINER : 維護者的名稱,這會被寫入在image的資訊當中
  • WORKDIR: 設定起始目錄
  • RUN: 指令建置docker image 過程中需要做的事情,例如:安裝環境套件
  • CMD: 指定啟動後所要執行的指令

(詳細可參考: Docker 學習筆記)

FROM tensorflow/tensorflow:2.2.3-gpu-jupyter
MAINTAINER Sweetornotspicy marathon
# mkdir
WORKDIR /home/
# pip install matplot
RUN pip install — no-cache-dir — upgrade pip && \
pip install matplotlib && \
pip install keras
# ENTRYPOINT /bin/bash
CMD [“/bin/bash”]

使用此 docker file build 專屬的docker image

docker build -t demo/mnist:20210101

在 docker file 的路徑下,下這個指令後,就能開始build 一個 image, -t 後面帶入的參數,是給定此 image一個名稱和 tag。

build 成功後,可以再用 docker images 指令,檢查是否出現一個 name 是demo/mnist ,然後 tag 是 20210101的 image。

使用這個 docker image啟一個docker container

docker run -it — name my_mnist --gpus all -p 8888:8888 demo/mnist:20210101 bash

使用這個指令可以建立一個是 my_mnist 的 container ,另外帶入一些參數,例如:

  • — gpus all : 設定可調用的 gpu
  • -p : 指定 port

這時候就成功啟動了 container ,可以用指令 docker ps -a 查看。

開始在 docker container 訓練一個 mnist CNN 數字分類器

docker exec -it my_mnist bash

先進入這個 container ,之後開啟一個 jupyter notebook 並在上面編寫code。

jupyter notebook — ip 0.0.0.0 — allow-root — no-browser — port 8888 &

這時候會在 cmd 出現一串網址,將網址貼在瀏覽器上就可以抵達 jupyter notebook 的頁面,那我們在這上面訓練 mnist 的數字分類器。

參考: [Keras] 使用 CNN 進行 MNIST 的手寫數字辨識

import os
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D
from keras.utils import np_utils, plot_model
from keras.datasets import mnist
import matplotlib.pyplot as plt

# Mnist Dataset
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
x_train = X_train.reshape(60000, 1, 28, 28)/255
x_test = X_test.reshape(10000, 1, 28, 28)/255
y_train = np_utils.to_categorical(Y_train)
y_test = np_utils.to_categorical(Y_test)

# Model Structure
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=3, input_shape=(1, 28, 28), activation='relu', padding='same'))
model.add(MaxPool2D(pool_size=2, data_format='channels_first'))
model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dense(10, activation='softmax'))
print(model.summary())

# Train
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=10, batch_size=64, verbose=1)

# Test
loss, accuracy = model.evaluate(x_test, y_test)
print('Test:')
print('Loss: %s\nAccuracy: %s' % (loss, accuracy))

# Save model
model.save('./CNN_Mnist.h5')

# Load Model
model = load_model('./CNN_Mnist.h5')

# Display
def plot_img(n):
plt.imshow(X_test[n], cmap='gray')
plt.show()


def all_img_predict(model):
print(model.summary())
loss, accuracy = model.evaluate(x_test, y_test)
print('Loss:', loss)
print('Accuracy:', accuracy)
predict = model.predict_classes(x_test)
print(pd.crosstab(Y_test.reshape(-1), predict, rownames=['Label'], colnames=['predict']))


def one_img_predict(model, n):
predict = model.predict_classes(x_test)
print('Prediction:', predict[n])
print('Answer:', Y_test[n])
plot_img(n)

訓練完成後,會儲存 CNN_Mnist.h5 模型,之後讀取此 h5 可 predict 數字。

完成數字分類器的模型,也在這個 container 多增加code 還有h5檔。

完成訓練後存取model h5 並且將它 commit 成新的 docker image

我們可以先從 docker ps -a 查詢此 container 的 container ID,取得此 container ID 後,將它commit 成新的 image,可以給他一個新的 image name 和 tag。 (詳細可參考: docker commit)

docker commit containerID  demo/mnist:v5

小心得

這次認識 docker 的應用覺得非常的實用,後續開發就可以大大降低因為環境帶來的困擾,docker 還有一些更廣更深的應用,真的是學無不盡啊!

❤️感恩看到這裡的你,希望這篇文章有幫上你
👏歡迎拍手給我鼓勵,我是甜不辣馬拉松,我們下次見

--

--

甜不辣馬拉松

幻想自己是貝多芬,可是敲打的卻是機械鍵盤