引言
最近初学机器学习,在搭建Pytorch等深度学习框架环境时,遇到很多问题,非常折腾。直到我发现了一个叫docker的神器后,问题得到解决。得益于Docker技术的特性,我可以轻松把我需要的环境安装上去(特定或者所有的框架),现在我可以舒服的做在自己桌子上,用自己的笔记本电脑远程到实验室的工作站上调试代码。
本文提供一个环境的搭建过程,可以避免各种因为库的版本不同而导致深度学习框架安装不成功,也可以解决系统重装等原因导致的开发环境不同导致的问题,同时可以让工作站资源让更多同学使用。
虽然是all-in-one的解决方案,本文对大多数人而言仍具有一定难度。
本文所述的Docker、deepo、ssh环境都是搭建在服务器(工作站)上面,而PyCharm在本地电脑。
名词解释:
PyCharm:PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。
Docker: Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
Deepo:Deepo是一个几乎包含所有流行深度学习框架的Docker映像,拥有一个完整的可复制的深度学习研究环境。它涵盖了当前最流行的深度学习框架: Theano, Tensorflow, Sonnet, Pytorch, Keras, Lasagne, MxNet, CNTK, Chainer, Caffe, Torch, Pytorch。
本文主要参考链接:
1、PyCharm+Docker:打造最舒适的深度学习炼丹炉
版本:v 0.1 2019.9
- Ubuntu 18.04(推荐,本文实践平台) 或者16.04(尚未测试)
- Docker
- Nvidia显卡驱动(不需要单独安装cuda和cudnn)
-
禁用第三方显示驱动
默认安装了第三方开源的驱动程序nouveau,安装Nvidia显卡驱动首先需要禁用nouveau,不然会碰到冲突的问题,导致无法安装nvidia显卡驱动。
编辑文件blacklist.conf
sudo vim /etc/modprobe.d/blacklist.conf
若未安装vim则sudo apt-get install vim
安装或使用vi
在文件最后部分插入以下两行内容
blacklist nouveau
options nouveau modeset=0
更新系统
sudo update-initramfs -u
重启系统(一定要重启)
sudo reboot
由于开源显卡驱动被禁用,所以屏幕显示分辨率会比较差,字体窗口都会显得过大,如果出现这种情况,基本可以省略下一个步骤:
- 验证nouveau是否已禁用,没有信息显示,则已禁用成功
lsmod | grep nouveau
3、完成后,打开一个终端,输入nvidia-smi
,如果能显示以下信息,则安装成功。请确保CUDA的版本大于10.0
4、如果上述方法无法正确安装显卡驱动,那么请参考网络上的解决方法,这里不再赘述。
以下内容根据 官方文档 修改而来。
如果你过去安装过 docker,先删掉,否则跳过这一步:
sudo apt-get remove docker docker-engine docker.io
首先安装依赖:
sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
信任 Docker 的 GPG 公钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
对于 amd64 架构(64位)的计算机,添加软件仓库:
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
最后安装
sudo apt-get update
sudo apt-get install docker-ce
等待完成,输入docker --version
验证是否成功,成功安装会显示版本信息。
最后,把docker添加到用户组,免除每次都需要sudo
的烦恼
我们就为当前用户添加到docker
属组即可。
-
如果还没有 docker group 就添加一个:
sudo groupadd docker
-
将用户加入该 group 内。然后退出并重新登录就生效啦。
sudo gpasswd -a ${USER} docker
-
重启 docker 服务
sudo service docker restart
-
切换当前会话到新 group 或者重启 X 会话
newgrp - docker
注意:最后一步是必须的,否则因为 groups 命令获取到的是缓存的组信息,刚添加的组信息未能生效,所以 docker images 执行时同样有错。
基本概念
image,镜像,是一个个配置好的环境。 container,容器,是image的具体实例。 image和container的关系,相当于面向对象中类与对象的关系。
如何查询命令参数: docker
可以看docker客户端有那些基本命令; 对应每一条命令,想看看具体是做什么的,可以在后面加一个--help
查看具体用法,例如对于run命令: docker run --help
docker run [-it] some-image
创建某个镜像的容器。
注意,同一个镜像可以通过这种方式创建任意多个container. 加上-it
之后,可以创建之后,马上进入交互模式。
列出当前运行的容器
docker ps
列出所有的容器,包括运行的和不运行的
docker ps -a
docker rm container-id
删除某个容器
docker start [-i] container-id
启动某个容器,必须是已经创建的。 加上-i
参数之后,可以直接进入交互模式:
除了通过-i
进入交互模式,还有一种方法,那就是通过attach
命令
docker attach container-id
进入交互模式之后,怎么退出呢: - 想退出但是保持容器运行,按CTRL+Q+P
三个键 - 退出,并关闭停止容器,按CTRL+D
或者输入exit
再回车
注:Ctrl+P+Q
按的时候有时候会不灵,多按几次!
#停止
docker stop container-id
#重启
docker restart container-id
确保docker的版本为19.03,第一次使用Docker 19.03和GPUs,参考以下过程
在Ubuntu 16.04/18.04系统里,进行如下操作
# Add the package repositories
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
$ sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
$ sudo systemctl restart docker
docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
输入以下命令,安装一个全家桶集合,具体包含了哪些包,详情请查看
sudo docker pull registry.docker-cn.com/ufoym/deepo
现在您可以尝试以下命令:
nvidia-docker run --rm ufoym/deepo nvidia-smi
如果能看到下图,则成功了
首先创建一个交互容器,如下图,进入到容器里面,当前为root身份登录
docker run -it ufoym/deepo
先升级更新一下,输入
apt-get update # apt-get 升级
接着安装openssh-server
,输入如下命令,
apt install openssh-server
修改SSH配置文件以下选项,去掉#注释,将四个选项启用:
$ vi /etc/ssh/sshd_config
RSAAuthentication yes #启用 RSA 认证
PubkeyAuthentication yes #启用公钥私钥配对认证方式
AuthorizedKeysFile .ssh/authorized_keys #公钥文件路径(和上面生成的文件同)
PermitRootLogin yes #root能使用ssh登录
重启ssh服务,并设置开机启动:
service sshd restart
chkconfig sshd on
注意!!!为了让本地电脑能访问到容器所在的服务器,我们也需要在服务器上面安装ssh,请使用exit
命令退出当前容器,或者新开一个终端,在服务器上重复上面过程,输入以下命令,更改ssh
配置文件等
apt install openssh-server
使用如下命令,设置并记住你的root密码,后面远程连接需要用到
passwd
使用exit命令或者Ctrl+C来退出当前运行的容器:
exit
当结束后,我们使用 exit 来退出,现在我们的容器已经被我们改变了,使用 docker commit 命令来提交更新后的副本。
sudo docker commit -m 'install openssh' -a 'Docker Newbee' f8513ec39154 deepo_ssh
其中,-m
来指定提交的说明信息,跟我们使用的版本控制工具一样;
-a
可以指定更新的用户信息;之后是用来创建镜像的容器的ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID 信息。
提交后docker中就会多出一个deepo_ssh的一个镜像。
安装好ssh服务后,可以尝试在远程使用jupyter notebook 和PyCharm了
本部分参考知乎,并作了一些格式调整
深度学习jupyter notebook镜像已经创建:
sudo nvidia-docker run -it -p 7777:8888 --ipc=host -v /home/shcd/Documents/gby:/gby --name gby-notebook 90be7604e476
其中:
-it
为直接进入交互式-p 7777:8888
是把主机的7777端口映射到容器的8888端口--ipc=host
可以让容器与主机共享内存--name xxxxx
可以给容器定义一个个性化名字-v /home/shcd/Documents/gby:/gby
可以将主机上的/home/shcd/Documents/gby
地址挂载到容器里,并命名为/data
文件夹,这样这个文件夹的内容可以在容器和主机之间共享了。因为容器一旦关闭,容器中的所有改动都会清除,所以这样挂载一个地址可以吧容器内的数据保存到本地。- 90be7604e476
则是你安装的jupyter
镜像的id,可以在刚刚docker images
命令后面查看,当然你也可以直接写全名ufoym/deepo:all-py36-jupyter
经过上面的操作,你应该可以直接进入容器了,这时你用ls
命令,应该可以看到一个新的文件夹gby
产生了!
使用如下命令
jupyter notebook --no-browser --ip=0.0.0.0 --allow-root --NotebookApp.token= --notebook-dir='/gby'
其中:
-
--no-browser
即不通过浏览器启动, -
--ip
指定容器的IP -
--allow-root
允许root模型运行 -
--NotebookApp.token
可以指定jupyter 登录密码,可以为空 -
--notebook-dir='/gby'
指定jupyter的根目录
开启本地与服务器的端口映射,从而远程登录jupyter:
在本地机器上,执行如下命令:
ssh username@host-ip -L 1234:127.0.0.1:7777
这样,可以将本地的1234
端口,映射到服务器的localhost
的7777
端口(即你前面创建jupyter容器时候的指定的服务器端口) 这样,你在本地电脑的浏览器里输入localhost:1234
,即可登录到服务器上的jupyter notebook
了!
当我第一次看到这个画面的时候,简直激动地要跳起来! 既能远程访问高性能服务器,又可以像在本地一样便捷地操作,你说激动不激动你说激动不激动?
之前好不容易配置好的环境,突然被学校服务器要重装!?怎么办? 你想到的一定是:能不能把配置好的环境备份一份,后面直接重新加载进来?
方法也很简单: 一般情况下,我们想备份的是容器,因为我们具体的配置都是在容器中进行的,而镜像一般都是直接在网上下载的,我们不做什么改动。
先通过docker ps
或者docker ps -a
来查看你想备份的容器的id, 然后通过:
docker commit -p [your-container-id] [your-backup-name]
来将id为your-container-id的容器创建成一个镜像快照。
接着,你通过docker images
就可以查看到刚刚创建好的镜像快照了。 然后,通过:
docker save -o [path-you-want-to-save/your-backup-name.tar]] [your-backup-name]
把那个镜像打包成tar文件,保存到服务器上。 后面就可以把服务器上打包好的tar文件,下载到本地了。
恢复:
docker load -i your-backup-name.tar
docker run -d -p 80:80 your-backup-name
Pycharm部分是在本地电脑(笔记本或台式电脑)上面实现的,请注意。
打开PyCharm*Tools > Deployment > Configuration*
, 新建一个*SFTP*
服务器,名字自己取:
输入如下图配置,注意这里的端口是你刚刚设置的映射到容器22端口的宿主机中的端口,我这里使用的是8022,账号密码是你刚刚自己设置的,这里的Root Path设置一个远程docker容器里的路径:
配置完点击Test SFTP connection,如果成功就恭喜你,可以进行下一步了。
最后在Mappings中配置路径,这里的路径是你本地存放代码的路径,与刚刚配置的Root Path相互映射(意思是Mapping里本机的路径映射到远程的Root Path)*,*方便以后在本地和远程docker中进行代码和其他文件同步。
在PyCharm里配置远程解释器
点击PyCharm的File > Setting > Project > Project Interpreter
右边的设置按钮新建一个项目的远程解释器:
配置完成以后在项目解释器界面就会出现如下图所示,可以看到此时已经完成远程解释器的本地化:
配置完成以后需要等本地和远程的环境同步一下,到这里,恭喜你,可以用最舒服的姿势。。。写代码了。
配置完成以后的日常是这样的:
左边是本地的文件,修改之后可以随时右键deployment->upload
到远程主机,或者直接在本地调试运行;最右边是远程主机的文件,假如直接在远程修改了文件刷新一下同样可以右键下载到本地,但是我不建议这样做,因为这样很容易带来冲突(毕竟没有很好的版本控制)。目前最好的实践是在局域网的服务器上,时延低,同步速度快。****确保你安装的是专业版的PyCharm**,只有专业版能进行远程调试。
一切安装完成后,你可以用一下命令打开你的远程环境,在服务器上,
sudo nvidia-docker run -p 8022:22 -p 7777:8888 --ipc=host --name="deepo_ssh" -v ~/home/gy501/remote_workspace:/workspace/gy501/remote_workspace -it 2df5
该命令的各个参数的含义可以参考本文的第六节,如何创建远程服务器的内容,以及jupyter notebook的内容。