创建Docker容器,利用容器共享GPU资源,并完成基于GPU的计算,如Tensorflow。
* Ubuntu18.04 系统
* GeForce GTX 1060 显卡
1.安装docker
2.安装nvidia显卡驱动,(安装cuda、cudnn可选)
3.安装nvidia-docker
4.nvidia-docker pull tensorflow镜像
5.从镜像运行3个tensorflow容器,并测试GPU利用情况。(运行程序为mnist手写数字识别)
6.查看GPU资源使用情况,看看是否docker共享了资源。
#更新apt源
$ sudo apt-get update
#安装其他库文件
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
#添加Docker官方GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
添加Docker官方GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
#验证是否成功
sudo apt-key fingerprint 0EBFCD88
#将docker稳定版添加到apt仓库中
$sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
#将docker添加到apt库中后随即更新源
sudo apt-get update
#接下来就可以通过apt-get命令获取docker了
sudo apt-get install docker-ce docker-ce-cli containerd.io
此时,相信你的docker已经安装好了。下面测试一下:
sudo docker run hello-world
如果你的图是下面的结果那么你就安装成功了。(否则需要继续安装)
#创建docker用户组,并将当前用户加入组
$ sudo groupadd docker
$ sudo gpasswd -a${USER} docker
$ sudo service docker restart
我们在https://www.geforce.cn/drivers这个网址查询了Nvidia驱动输入我们的查询条件即可。经查询,为了找一个稳定的版本,我们选择了430的驱动。(其中还需要一些调整,请自行百度,主要写思路和步骤)
sudo apt-get install nvidia-driver-430
为了验证驱动安装成功,可以输入下面的指令。
nvidia-smi
若出现下面的图说明安装成功,否则请先安装驱动:
1 首先添加到apt仓库
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
sudo apt-get update
2 其次安装nvidia-docker2,并重新载入daemon.json
sudo apt-get install -y nvidia-docker2
验证安装成功方式即查看他的映像:
sudo nvidia-docker images
由于我们做的实验是创建多个容器共享GPU资源,于是我们需要pull tensorflow的GPU版本。
直接输入命令:
sudo nvidia-docker pull tensorflow/tensorflow:latest-gpu
可以通过查看 nvidi-docker images 来确定该镜像已被拉取。
*******************************************************************************************************************************
特别注意:这个文件很大,建议换国内的docker源,如可以用中国科学技术大学的docker源。
在文件 /etc/ default/ docker 中加入以下参数,表示使用中国科学技术大学镜像仓库
DOCKER_OPTS="--registry-mirror=https://docker.mirrors.ustc.edu.cn"
*******************************************************************************************************************************
输入命令: 代表创建一个用tensorflow/tensorflow:latest-gpu的镜像形成的容器,给容器的名字叫做tensorflow02,-it代表是交互模式,-v代表是映射路径,即把docker里的/usr/local/mytf2文件夹映射到宿主机里的/usr/local/mytf2文件夹下 ,-p代表docker里的8889端口映射到宿主机里的8888端口。( Note:第一次已经运行了,可以用stop+镜像名停止运行 )
sudo nvidia-docker run -it --name=tensorflow02 -v /usr/local/mytf2:/usr/local/mytf2 -p 8889:8888 tensorflow/tensorflow:latest-gpu /bin/bash
之后,现在tensorflow02已经开始运行了。我们可以用stop来停止容器运行。同时下次启动用start来启动。
#创建容器
sudo nvidia-docker run [--参数] 镜像名
#启动容器:
sudo nvidia-docker start [容器名/id] #如tensorflow02
#运行容器:(运行已经创建好的)
sudo nvidia-docker exec -it [容器名/id] /bin/bash
#查看所有容器情况
nvidia-docker ps -a
#删除容器
sudo nvidia-docker rm [容器名/id]
同样的我们再创建两个容器,一共三个容器来测试效果:
sudo nvidia-docker run -it -p 8888:8888 -v /usr/local/mytf:/usr/local/mytf --name=tensorflow01 tensorflow/tensorflow:latest-gpu /bin/bash
sudo nvidia-docker run -it -p 8890:8888 -v /usr/local/mytf2:/usr/local/mytf2 --name=tensorflow03 tensorflow/tensorflow:latest-gpu /bin/bash
记住我们的目的是打开3个终端,各运行一个tensorflow容器,测试相应的python代码,然后查看gpu利用情况。
我们首先测试一个容器:
我们先将文件复制到 /usr/local/mytf2 文件夹下。(这个目录映射到了容器tensorflow02的 /usr/local/mytf2文件夹下)
sudo cp test.py /usr/local/mytf2
进入tensorflow01容器执行该python文件
sudo nvidia-docker exec -it tensorflow02 /bin/bash
cd /usr/local/mytf2 && python ./test.py
开启tensorflow01容器
运行结果0.9178
同时再次打开一个终端运行查看nvidia-smi即,终端运行情况。
发现改程序的确调用了GPU资源。到现在为止,我已经用tensorflow容器成功运行了一个python程序,并且该python程序确实使用了该资源。(下面列出了一个我们遇到的坑)
*******************************************************************************************************************************
Note:我们在运行该程序的时候碰到了一个问题:
mnist无法运行,ModuleNotFoundError: No module named 'tensorflow.examples.tutorials'
解答:原来是因为pip install tensorflow 的时候没有获取到tutorials文件夹。
解决办法:从tensorflow的github网站下载tutorials文件夹复制到本地的
C:\Users\您的用户名\AppData\Local\Programs\Python\Python36\Lib\site-packages\tensorflow_core\examples文件夹下。(这个是windows版本。我在文末已经提供了下载链接,可以直接copy我的tutorials文件夹。)
而在Ubuntu环境中,先进入tensorflow容器,python2的文件夹路径为: /usr/local/lib/python2.7/dist-packages/tensorflow_core/examples. (将tutorials文件夹复制到该目录下即可)
输入命令:
sudo nvidia-docker exec -it tensorflow01
#然后进入有tutorials的父目录,执行下面的复制命令,将
sudo cp -r ./tutorials /usr/local/lib/python2.7/dist-packages/tensorflow_core/examples/
(注意,每个人的路径可能不同,先找到python的安装路径,然后将改文件夹复制到tensorflow_core/examples的文件夹下。)
*******************************************************************************************************************************
运行3个容器的时候我们才发现事情并不简单,第一个容器执行第一个python程序,6G的显卡内存使用了将近5G,运行第二个容器运行该容器下的python程序,发现不能执行。原来第一个python程序已经把显卡资源占满了,不能分配内存了,所以我们应该对python代码进行调整,设置程序运行的内存限额。我们设置的模式为内存动态调配。
给python代码添加下面的代码:
config = tf.ConfigProto()
config.gpu_options.allow_growth=True
sess = tf.Session(config=config)
最后我们调用nvidia-smi发现,程序运行正确,每个程序运行了使用了191MB,而不是将内存全占满。
下面是经过代码调试后的实验过程。
#打开第一个终端
sudo nvidia-docker exec -it tensorflow01 /bin/bash
python /usr/local/mytf2/test.py
#打开第二个终端
sudo nvidia-docker exec -it tensorflow02 /bin/bash
python /usr/local/mytf2/test.py
#打开第三个终端
sudo nvidia-docker exec -it tensorflow03 /bin/bash
python /usr/local/mytf2/test.py
#再次打开一个终端查看GPU使用情况
nvidia-smi
准备测试
最终,我们看到了如下图所示的结果。
测试结果最终我们的系统实现了创建容器,利用容器共享GPU资源的任务。
*******************************************************************************************************************************
附上我们的最终的测试代码:
#!/usr/bin/python
#coding=utf-8
import time
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
#import tensorflow as tf
# 2019/11/27 13:39 add
config = tf.ConfigProto()
config.gpu_options.allow_growth=True
#2019/11/27 13:39 add end
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.global_variables_initializer()
#update 2019/11/27 13:39
sess = tf.Session(config=config)
sess.run(init)
#update 2019/11/27 13:39
for i in range(1, 1000):
time.sleep(0.03)
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
batch_size = 128
test_size = 256
def init_weights(shape):
return tf.Variable(tf.random_normal(shape, stddev=0.01))
def model(X, w, w2, w3, w4, w_o, p_keep_conv, p_keep_hidden):
l1a = tf.nn.relu(tf.nn.conv2d(X, w, # l1a shape=(?, 28, 28, 32)
strides=[1, 1, 1, 1], padding='SAME'))
l1 = tf.nn.max_pool(l1a, ksize=[1, 2, 2, 1], # l1 shape=(?, 14, 14, 32)
strides=[1, 2, 2, 1], padding='SAME')
l1 = tf.nn.dropout(l1, p_keep_conv)
l2a = tf.nn.relu(tf.nn.conv2d(l1, w2, # l2a shape=(?, 14, 14, 64)
strides=[1, 1, 1, 1], padding='SAME'))
l2 = tf.nn.max_pool(l2a, ksize=[1, 2, 2, 1], # l2 shape=(?, 7, 7, 64)
strides=[1, 2, 2, 1], padding='SAME')
l2 = tf.nn.dropout(l2, p_keep_conv)
l3a = tf.nn.relu(tf.nn.conv2d(l2, w3, # l3a shape=(?, 7, 7, 128)
strides=[1, 1, 1, 1], padding='SAME'))
l3 = tf.nn.max_pool(l3a, ksize=[1, 2, 2, 1], # l3 shape=(?, 4, 4, 128)
strides=[1, 2, 2, 1], padding='SAME')
l3 = tf.reshape(l3, [-1, w4.get_shape().as_list()[0]]) # reshape to (?, 2048)
l3 = tf.nn.dropout(l3, p_keep_conv)
l4 = tf.nn.relu(tf.matmul(l3, w4))
l4 = tf.nn.dropout(l4, p_keep_hidden)
pyx = tf.matmul(l4, w_o)
return pyx
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels
trX = trX.reshape(-1, 28, 28, 1) # 28x28x1 input img
teX = teX.reshape(-1, 28, 28, 1) # 28x28x1 input img
X = tf.placeholder("float", [None, 28, 28, 1])
Y = tf.placeholder("float", [None, 10])
w = init_weights([3, 3, 1, 32]) # 3x3x1 conv, 32 outputs
w2 = init_weights([3, 3, 32, 64]) # 3x3x32 conv, 64 outputs
w3 = init_weights([3, 3, 64, 128]) # 3x3x32 conv, 128 outputs
w4 = init_weights([128 * 4 * 4, 625]) # FC 128 * 4 * 4 inputs, 625 outputs
w_o = init_weights([625, 10]) # FC 625 inputs, 10 outputs (labels)
p_keep_conv = tf.placeholder("float")
p_keep_hidden = tf.placeholder("float")
py_x = model(X, w, w2, w3, w4, w_o, p_keep_conv, p_keep_hidden)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=py_x, labels=Y))
train_op = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cost)
predict_op = tf.argmax(py_x, 1)
with tf.Session() as sess:
# you need to initialize all variables
tf.global_variables_initializer().run()
for i in range(100):
training_batch = zip(range(0, len(trX), batch_size),
range(batch_size, len(trX)+1, batch_size))
for start, end in training_batch:
sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end],
p_keep_conv: 0.8, p_keep_hidden: 0.5})
test_indices = np.arange(len(teX)) # Get A Test Batch
np.random.shuffle(test_indices)
test_indices = test_indices[0:test_size]
print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
sess.run(predict_op, feed_dict={X: teX[test_indices],
p_keep_conv: 1.0,
p_keep_hidden: 1.0})))