docker配置深度學習環境
版權聲明:本文爲博主原創文章,轉載註明出處便可。 http://www.javashuo.com/article/p-vsqghqsm-mw.htmlhtml
序
閱讀本篇文章能夠幫你解決的問題是:提供一套解決方案,可以在支持Docker的任何版本Ubuntu系統下,搭建出完美運行各類深度學習框架、各類版本、各類環境依賴(NAIVID顯卡)深度學習工程的開發環境。不只如此,還要像在本機同樣方便的修改代碼運行計算。python
搭建深度學習計算平臺,通常須要咱們在本機上安裝一些必要的環境,安裝系統、顯卡驅動、cuda、cudnn等。而隨着Docker的流行,每每可以幫咱們輕鬆的進行環境搭建、複製與隔離,因此官方也利用容器技術與深度學習相結合,所以也出現瞭如下方案。linux
容器方案比傳統方案帶來更多的隨意性,裝系統前不須要考慮Ubuntu哪個版本符合不符合咱們的代碼運行要求,咱們只須要安裝一個本身喜歡的(18.04徹底能夠),再在官網下載一下顯卡驅動,或者軟件源附加驅動更新一下就好了,剩下都不須要咱們繼續考慮。這些也很是的輕鬆,由於Nvidia對Ubuntu的支持愈來愈友好,咱們只須要下載deb包,一行命令便可安裝成功。git
系統 | 顯卡驅動 | Cuda | Cudnn | |
---|---|---|---|---|
傳統方案 | 一種版本 | 必需 | 一種版本 | 必需 |
容器方案 | 各類版本 | 必需 | 非必需 | 非必需 |
安裝顯卡驅動能夠參照:https://blog.csdn.net/bskfnvjtlyzmv867/article/details/80102000github
正式進入正文以前,確保你已經安裝好趁手的系統和顯卡驅動。docker
I. 安裝Docker
關於Docker教程,詳見:Docker——入門實戰shell
安裝指定版本Docker CE
這裏的版本由第二部分的Nvidia Docker依賴決定,筆者在寫此文時須要的版本是18.03.1,若是在安裝Nvidia Docker時依賴的Docker CE版本已經變動,能夠卸載從新安裝須要的版本。json
sudo apt install curl curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu xenial edge" | sudo tee /etc/apt/sources.list.d/docker.list sudo apt-get update && sudo apt-get install -y docker-ce=18.03.1~ce-0~ubuntu1234
執行這個命令後,腳本就會自動的將一切準備工做作好,而且把Docker CE 的Edge版本安裝在系統中。ubuntu
啓動Docker CE
sudo systemctl enable docker
sudo systemctl start docker12
創建docker 用戶組
默認狀況下,docker 命令會使用Unix socket 與Docker 引擎通信。而只有root 用戶和docker 組的用戶才能夠訪問Docker 引擎的Unix socket。出於安全考慮,通常Ubuntu系統上不會直接使用root 用戶。所以,更好地作法是將須要使用docker 的用戶加入docker用戶組。vim
# 創建docker組
sudo groupadd docker
# 將當前用戶加入docker組
sudo usermod -aG docker $USER1234
註銷當前用戶,從新登陸Ubuntu,輸入docker info,此時能夠直接出現信息。
配置國內鏡像加速
在/etc/docker/daemon.json 中寫入以下內容(若是文件不存在請新建該文件)
{
"registry-mirrors": [
"https://registry.docker-cn.com"
]
}12345
從新啓動服務
sudo systemctl daemon-reload sudo systemctl restart docker12
II. 安裝Nvidia Docker2
Nvidia Docker2項目的主頁:https://github.com/NVIDIA/nvidia-docker
# If you have nvidia-docker 1.0 installed: we need to remove it and all existing GPU containers
ocker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge -y nvidia-docker
# Add the package repositories
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
# Install nvidia-docker2 and reload the Docker daemon configuration
sudo apt-get update && sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd
# Test nvidia-smi with the latest official CUDA image
docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi1234567891011121314
III. 搭建環境
拉取鏡像
Nvidia官網在DockerHub中提供了關於深度學習的各個版本環境,點我…有Ubuntu14.04-18.04,Cuda6.5-9.2,Cudnn4-7,基本含蓋了咱們所須要的各類版本的深度學習環境,咱們直接拉取鏡像,在已有的鏡像基礎上配置咱們的深度學習環境。
下載鏡像,這裏以ubuntu16.0四、cuda8.0、cudnn5.1的版本爲例,咱們找到知足版本要求的TAG爲8.0-cudnn5-devel-ubuntu16.04。
# 拉取鏡像
docker pull nvidia/cuda:8.0-cudnn5-devel-ubuntu16.04
# 查看鏡像
docker images -a1234
建立啓動容器
利用下載好的鏡像,建立一個交互式的容器。容器須要使用nvidia顯卡,須要設置額外的參數。-p 8022:22
docker run -it --name 自定義容器名 -v /home/你的用戶名/mnist/:/home/你的用戶名/mnist/ --runtime=nvidia -e NVIDIA_VISIBLE_DEVICE=0,1 nvidia/cuda:8.0-cudnn5-devel-ubuntu16.041
NVIDIA_VISIBLE_DEVICE參數指定對容器分配幾塊GPU資源;-v參數用於掛載本地目錄,冒號前爲宿主機目錄,冒號後爲容器目錄,兩個能夠設置爲同樣比較方便代碼書寫。配置目錄掛載是爲了方便本文下一部分測試Mnist服務。容器啓動完畢,此時,能夠像正常本機配置的深度學習環境同樣,測試各個軟件的版本。
nvidia-smi
nvcc -V
# 查看cudnn版本
cd /usr/lib/x86_64-linux-gnu/
ll |grep cudnn12345
IV. 構建環境
安裝環境
在上一部分咱們搭建了深度學習計算的必要環境,包括CUDA和CUDNN。然而大多數深度學習環境都是須要執行Python編寫的深度學習代碼的,甚至須要一些經常使用的深度學習框架,如TensorFlow、PyTorch等。在上一部分咱們拉取的Nvidia官方提供的鏡像中並無包含Python運行環境以及任何的深度學習框架,須要咱們本身安裝。
附上安裝環境的全部命令:
apt-get update
# 安裝Python2.7環境 3.+版本自行添加
apt-get install -y --no-install-recommends build-essential curl libfreetype6-dev libpng12-dev libzmq3-dev pkg-config python python-dev python-pip python-qt4 python-tk git vim
apt-get clean
## 安裝深度學習框架 自行添加
pip --no-cache-dir install setuptools
pip --no-cache-dir install tensorflow-gpu==1.2 opencv-python Pillow scikit-image matplotlib1234567
構建鏡像
安裝好環境後,其實已經能夠開始運行咱們的深度學習代碼了。若是你想馬上測試本身的Docker深度學習環境搭建成功與否,能夠直接開始下一部分的Mnist數據集測試。
若是此時,項目組另外一位小夥伴也想跑深度學習,剛好須要和你同樣的環境依賴,咱們徹底能夠「拷貝」一份配好的環境給他,他能夠直接上手去使用。Docker的方便之處也體如今這,咱們能夠將本身定製的容器構建成鏡像,能夠上傳到Docker Hub給別人下載,也能夠生成壓縮包拷貝給別人。
利用commit命令,生成一個名爲homography1.0的新鏡像。
# docker commit -a "做者信息" -m "提交信息" 以前啓動的容器名 自定義鏡像名
docker commit -a "wangguoping" -m "deep homography environment" tensorflow1.2 homography1.012
至於將鏡像提交Hub和拷貝就不是本文重點,也就不介紹了。
另外,這裏生成鏡像還有一個好處,就是第六部分結合PyCharm使用。PyCharm裏面配Docker選擇的是鏡像(IMAGE),而不是容器(Container),它會根據咱們選擇的鏡像本身幫咱們啓動一個容器,用來運行PyCharm裏面的代碼。我一開始沒有搞清楚這個概念,也走了很多彎路。
V. 測試Mnist
進入上一部分掛載的目錄:
cd /home/test/mnist # test是個人用戶名 vim mnist.py # 建立mnist的tensorflow代碼12
代碼內容能夠參考:Tensorflow——nn、cnn、rnn玩mnist
# coding=utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
train_img = mnist.train.images
train_lab = mnist.train.labels
test_img = mnist.test.images
test_lab = mnist.test.labels
dim_input = 784
dim_output = 10
x_data = tf.placeholder(tf.float32, [None, dim_input])
y_real = tf.placeholder(tf.float32, [None, dim_output])
stddev = 0.1
weights = {"w_conv1": tf.Variable(tf.random_normal([3, 3, 1, 64], stddev=stddev)),
"w_conv2": tf.Variable(tf.random_normal([3, 3, 64, 128], stddev=stddev)),
"w_fc1": tf.Variable(tf.random_normal([7 * 7 * 128, 1024], stddev=stddev)),
"w_fc2": tf.Variable(tf.random_normal([1024, dim_output], stddev=stddev))}
biases = {"b_conv1": tf.Variable(tf.zeros([64])),
"b_conv2": tf.Variable(tf.zeros([128])),
"b_fc1": tf.Variable(tf.zeros([1024])),
"b_fc2": tf.Variable(tf.zeros([dim_output]))}
def forward_prop(_input, _w, _b, keep_prob):
_input_r = tf.reshape(_input, shape=[-1, 28, 28, 1])
_conv1 = tf.nn.conv2d(_input_r, _w["w_conv1"], strides=[1, 1, 1, 1], padding="SAME")
_conv1 = tf.nn.relu(tf.nn.bias_add(_conv1, _b["b_conv1"]))
_pool1 = tf.nn.max_pool(_conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# dropout
_pool_dr1 = tf.nn.dropout(_pool1, keep_prob=keep_prob)
_conv2 = tf.nn.conv2d(_pool_dr1, _w["w_conv2"], strides=[1, 1, 1, 1], padding="SAME")
_conv2 = tf.nn.relu(tf.nn.bias_add(_conv2, _b["b_conv2"]))
_pool2 = tf.nn.max_pool(_conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
_pool_dr2 = tf.nn.dropout(_pool2, keep_prob=keep_prob)
flatten = tf.reshape(_pool_dr2, shape=[-1, _w["w_fc1"].get_shape().as_list()[0]])
_fc1 = tf.nn.relu(tf.add(tf.matmul(flatten, _w["w_fc1"]), _b["b_fc1"]))
_fc_dr1 = tf.nn.dropout(_fc1, keep_prob=keep_prob)
_out = tf.nn.relu(tf.add(tf.matmul(_fc_dr1, _w["w_fc2"]), _b["b_fc2"]))
return {"input_r": _input_r, "conv1": _conv1, "pool1": _pool1, "pool_dr1": _pool_dr1, "conv2": _conv2,
"pool2": _pool2, "pool_dr2": _pool_dr2, "flatten": flatten, "fc1": _fc1, "fc_dr1": _fc_dr1, "out": _out}
keep_prob = tf.placeholder(tf.float32)
y_pred = forward_prop(x_data, weights, biases, keep_prob)["out"]
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_pred, labels=y_real))
op = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)
correct = tf.equal(tf.arg_max(y_pred, 1), tf.arg_max(y_real, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))
training_epoch = 100
batch_size = 128
display_step = 2
init = tf.global_variables_initializer()
total_batch = mnist.train.num_examples // batch_size
print("have %d batchs,each batch size is:%d" % (total_batch, batch_size))
saver = tf.train.Saver(max_to_keep=2)
is_training = True
with tf.Session() as sess:
sess.run(init)
if is_training:
for epoch in range(training_epoch):
avg_loss = 0
for i_batch in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
feed_dict = {x_data: batch_xs, y_real: batch_ys, keep_prob: 0.5}
sess.run(op, feed_dict=feed_dict)
avg_loss += sess.run(loss, feed_dict=feed_dict)
avg_loss = avg_loss / total_batch
if epoch % display_step == 0:
print("Epoch:%3d/%3d, loss:%.6f" % (epoch, training_epoch, avg_loss))
feed_dict = {x_data: batch_xs, y_real: batch_ys, keep_prob: 0.5}
train_accuracy = sess.run(accuracy, feed_dict=feed_dict)
print("train accuracy:%.6f" % train_accuracy)
saver.save(sess, "MNIST_model/model.ckpt-" + str(epoch))
else:
saver.restore(sess, tf.train.latest_checkpoint(checkpoint_dir="MNIST_model/"))
feed_dict = {x_data: mnist.test.images, y_real: mnist.test.labels, keep_prob: 1.0}
test_accuracy = sess.run(accuracy, feed_dict=feed_dict)
print("test accuracy:%.6f" % test_accuracy)
print("end!")
下載Mnist數據集,保存在/home/test/mnist/MNIST_data目錄下。這裏須要咱們修改目錄權限,Docker共享目錄默認只讀。注意,這裏切換到宿主機的終端下進行操做,可能你會問爲何不直接容器內下載,由於之後咱們要跑的數據集不可能只是mnist大小,難道你要在docker裏下載幾十個G的數據集嗎。
sudo chmod -R a+rw /home/test/mnist mkdir -p /home/test/mnist/MNIST_data wget http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz wget http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz wget http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz wget http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz123456
切換至Docker的終端下,運行mnist.py腳本文件,便可發現已經能夠跑起來了。
python mnist.py1
此時會在/home/test/mnist下產生MNSIT_model文件夾,裏面保存着訓練生成的模型。
VI. PyCharm+Docker
Mnist已經測試成功,基本的Docker+Deep Learning方案演示已經完成。然而,我一直不喜歡命令行修改代碼,運行腳本,查看結果,我十分推崇PyCharm去調試Python。好比,當Mnist訓練完畢,我須要修改第80行的is_training = False來測試我訓練出的模型,沒有PyCharm,我須要經過vim修改mnist.py,而後再輸入python來運行。可能你會以爲也不是很麻煩,若是須要修改模型,更換網絡,甚至重構代碼呢?
因此能用IDE儘可能仍是讓PyCharm來開發咱們代碼,咱們只須要編碼,點擊運行,剩下的其餘操做我都不太願意去幹,一行命令都懶得敲,畢竟懶嘛!
PyCharm在2018的Profession版本以後都是提供Docker的功能的,能夠利用容器中的Python解釋器爲咱們的代碼提供運行條件。利用PyCharm,你能夠像在使用本機的深度學習環境同樣,無需考慮因容器帶來的過多的繁瑣操做。官方關於Docker的使用文檔參見:http://www.jetbrains.com/help/pycharm/run-debug-configuration-docker.html
在Settings的Build下有一個Docker選項,右側添加,PyCharm默認會給咱們設置好選擇Unix Socket的方式與Docker守護進程進行通訊。出現Connection successful便可,點擊OK。
添加成功後,PyCharm下方會出現docker的窗口,能夠可視化的查看鏡像與容器的相關信息。其中的homography1.0:latsest是咱們上一步構建的鏡像。
下面新建一個Python的解釋器,相似於本地的Python建立虛擬環境。
按照圖示新建,點擊OK,便可發現導入容器的Python解釋器已經擁有了所有的第三方Python庫以及深度學習框架。
等待PyCharm導入容器的解釋器成功,理論上咱們即可以開始點擊運行按鈕跑起咱們的代碼了。但實際還有兩個問題須要解決。
首先,PyCharm會根據咱們的鏡像來啓動一個容器運行咱們的代碼,然而PyCharm並不知道咱們是要運行深度學習程序,須要利用Nvidia Docker使用GPU資源。咱們以前是經過配置–runtime=nvidia參數來啓動一個可使用GPU的容器,那咱們只要指定PyCharm啓動一個容器的時候也帶上這個參數就好。
另外一個問題就是,咱們如今跑的程序是讀取宿主機上某個目錄下的幾十個G的數據集,好像Docker也不知道數據在哪裏,畢竟咱們沒有掛載。一樣,模型它也不會幫咱們保存,一旦程序運行結束,PyCharm啓動的容器銷燬,全部的結果都沒了,程序白跑了,因此咱們也要指定-v參數告訴PyCharm掛載什麼目錄。
解決這兩個問題,在PyCharm的Run/Debug Configuration中,能夠配置。
點擊Docker Container settings右邊的按鈕,添加上面所說的兩個參數便可。
坑的是,你發現無法加入–runtime參數。然而,仍是找到了解決方案。把default-runtime」: 「nvidia」添加到/etc/docker/daemon.json文件中。這個文件也是咱們配置國內鏡像加速的文件。
{
"registry-mirrors": [
"https://registry.docker-cn.com"
],
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}123456789101112
修改完畢,須要重啓docker服務。
sudo systemctl daemon-reload sudo systemctl restart docker12
好了,大功告成,點擊運行,跑起來~~
VII. 結語
Docker仍是有不少技巧的,短暫幾天也只學了個皮毛,用於深度學習也十分不錯。官方也有不少構建好的深度學習環境鏡像,包含了主流的深度學習框架,能夠再Docker Hub自行搜索。實驗室電腦有時候仍是很奇葩的,須要耐心解決,積極的去利用一些新的技術解決難題應該是更應該考慮的事情。
暱稱:
退出 訂閱評論
[Ctrl+Enter快捷鍵提交]
【活動】華爲雲12.12會員節 雲產品1折起 滿額送Mate20 點擊搶購
【推薦】服務器100%基準CPU性能,1核1G首年168元,限時特惠!
· 包含深度學習經常使用框架的Docker環境
· Windows10 利用 Docker 配置 TensofFlow 深度學習工具
· docker配置環境
· Ubuntu 深度煉丹環境配置
· Docker學習---ubuntu環境
· 華碩董事長施崇棠坦誠手機失敗:拼到最後已經沒辦法
· 用戶談ofo押金之殤:一個失敗的資本遊戲
· NASA自爆服務器遭入侵 過去12年員工的信息恐遭外泄
· 印度外賣創企Swiggy融資10億美圓 騰訊參投
· UP ing,做爲技術公司的聯想
» 更多新聞...