前面分别介绍了基本知识与环境配置,最后介绍一下具体的使用场景与使用方法。
这里分为这样几个场景进行介绍:1. 开发环境;2. 训练任务;3. Jupyter Server。
首先是我们通过nvidia-smi -L命令查看可用的GPU Device,确认其Index,然后通过以下环境变量NVIDIA_VISIBLE_DEVICES的方式将GPU挂载到Docker容器中:
docker run -d --name xxx -e NVIDIA_VISIBLE_DEVICES=x,x,x image command
NVIDIA_VISIBLE_DEVICES环境变量是目标想挂载进Docker容器的GPU的Index。
开发环境
首先是AI开发环境容器化的介绍,这种场景的目的很明确,就是将容器作为自己的远程开发环境。首先简单介绍一下利用Pycharm连接一个远程的SSH的服务器作为开发环境的流程:在Preferences > Project Interpreter > Project Interpreter后面的setting的Add,选择SSH Interpreter,配置一个新的New server configuration。一般来说我们使用远程服务器的22端口进行SSH登陆,然后在该服务器环境下进行相关的开发工作。但是在Docker环境中为了将这些区分开来,就将各个容器所代表的环境的22端口宿主机做个映射,由于大部分的AI开发环境OS为Ubuntu,这里采用基础OS为Ubuntu的tensorflow1.15的镜像为例来进行操作。
首先是在DockerHub中选择需要的Docker镜像进行拉取,国外源较慢可以使用阿里云的ACR配置一下免费的镜像加速器来加速拉取镜像。然后用Docker将其运行起来,这里模拟挂载一张GPU,并将22端口映射到宿主机上的30001端口上/
docker pull tensorflow/tensorflow:1.15.5-gpu
docker run -ti --name tensorflow-dev -p 30001:22 -e NVIDIA_VISIBLE_DEVICES=0 tensorflow/tensorflow:1.15.5-gpu /bin/bash
运行起来之后进入容器的Bash,根据Ubuntu系统的版本选择相应的源进行更换,参考阿里云官方镜像网站Ubuntu的方法进行apt源的更换,然后使用apt安装下载openssh-server来打开ssh访问的渠道,下载安装好之后启用sshd更改登录密码:
apt update
apt install openssh-server
/usr/sbin/sshd -D &
passwd
然后就可以在外部访问30001端口来进行与普通远程服务器一样的访问体验了,如果有文件持久化的需求,只需要建立hostpath的Docker数据卷将其挂载进容器即可,这样这个容器就是一个专属于个人的开发环境,除了挂载路径之外与外界全部隔离。用户可以在该容器中模拟一个远程开发环境的开发。如果需要保存的话使用docker commit命令对镜像环境进行保存,然后stop容器释放资源即可。
训练任务
如果我们调试好了一个代码,仅仅是想要让其在服务器上进行运行,这时候启动一个容器独占一个GPU,等待任务运行结束后自动释放资源是一个不错的选择,这里假设基于上面的开发环境进行开发的训练代码已经调试通过,现在需要使用4张GPU卡进行训练。
首先我们需要准备一个Dockerfile来构建训练任务的镜像,首先是将训练所需的依赖导出至requirements.txt文件:
pip freeze > ./requirements.txt
训练所需要的数据集可以提前上传至远程服务器的某个本地目录,然后作为数据卷挂载到Docker容器上(推荐),或者直接COPY打包进训练镜像中也可以(不推荐),然后编写Dockerfile,这里假设项目名叫train,运行主文件叫main.py,一个简单的Dockerfile的编写如下所示,这里pip下载使用阿里云镜像源作为index源:
FROM tensorflow/tensorflow:1.15.5-gpu
COPY ./train /opt/train
COPY ./requirements.txt /opt/requirements.txt
USER root
RUN pip install -r /opt/requirements.txt -i https://mirrors.cloud.aliyuncs.com/pypi/simple/
CMD ["sh", "-c", "python /opt/train/main.py"]
然后在一个架构为X86的机器上或者直接在该远程服务器上直接进行构建:
docker build -t xxx -f ./Dockerfile
如果不在该服务器上构建镜像则需要上传到一个Docker镜像的仓库,这里推荐阿里云ACR个人容器镜像仓库。
然后运行类似与以下的docker run命令开启该容器进行训练即可:
docker run -d --name train-01 -e NVIDIA_VISIBLE_DEVICES=1,2,3,4 xxx
如果需要随时查看训练进度的话可以通过docker logs命令查看或者将log以tf.events的形式透出至持久卷,然后启动一个tensorboard server的容器来在tensorboard上面实时观测。
Jupyter Server
最后一个场景可能不是很常用,Jupyter是在国外比较流行的一个开发+训练的环境,类似于一个远端的IDE Server,拥有Terminal可以提供一个远端服务器的远端访问体验,并且文件的传输也是很方便的。
Jupyter在容器化的部署显得就很简单与容易,其本质是一个带有相关环境的Server,现在我们一般使用的是JupyterLab,相较于Jupyter Notebook其可以提供更好的开发体验。首先当然还是构建一个合适的Docker镜像,Dockerfile类似如下所示:
FROM tensorflow/tensorflow:1.15.5-gpu
USER root
RUN pip install jupyter && \
pip install ipywidgets && \
jupyter nbextension enable --py widgetsnbextension && \
pip install jupyterlab && jupyter serverextension enable --py jupyterlab
EXPOSE 8888
USER jovyan
CMD ["sh", "-c", "jupyter-lab --notebook-dir=/home/jovyan --ip=0.0.0.0 --no-browser --allow-root --port=8888 --ServerApp.token='' --ServerApp.password='' --ServerApp.allow_origin='*' --ServerApp.authenticate_prometheus=False"]
USER root
Jupyter提供了各式各样的插件,可以通过插件的扩展让Jupyter更加强大,比如其可以使用Jupyter-Server-Proxy这个插件当作一个WebServer的开发环境去调试Web接口,当然也可引人其他的插件类似如可视化调试器、Auto代码补全、性能监控等的插件让其成为一个更强大远端IDE存在,当然Jupyter的思路可以推广到WebIDE、Remote VSCode等类似的Server上去。
然后使用docker run命令将其8888端口映射到宿主机上即可进行访问。
总结
至此,AI容器化的内容就介绍完毕了,当然目前看来其使用起来还是有一定的门槛,使用者需要了解一定的Docker操作基础、Dockerfile基础、Linux操作基础,而且最重要的是相关的事情需要服务器管理员操作的比较多。假设有这样一个工具,先将以上的整个操作Docker和Linux的操作进行封装并暴露为一个RPC或者其他类型的Server,然后使用者在本地使用一个Client的Binary进行远端操作,并且可以很好的兼顾多用户的访问与资源归属的判定,整体类似于Kubernetes中的ApiServer和Kubectl的作用,只不过是面向单机的Docker环境,并且提供远端的环境自动部署脚本。考虑如果开发实现这样一个开源的项目,整体的使用门槛会再降低一个级别,如果这几篇文章的反响不错或者AI容器化真的成为了一个趋势,笔者可能会将这个工具的开发提上日程。