无论是第一次设置 TensorFlow 的新手数据科学爱好者,还是使用 TB 级数据的经验丰富的 AI 工程师,安装库、软件包或者框架总是一个困难又繁琐的过程。但是像 Docker 这样的容器化工具正在彻底改变着软件的可重复性,只不过它们还没有在数据科学和人工智能社区中流行起来。但随着机器学习框架和算法的不断发展,我们将很难花时间专注于学习所有相关的开发人员工具,尤其是那些与模型构建过程没有直接关联的工具。
在这篇文章中,我将展示如何使用 Docker 和 Python 工具包 Datmo 为任何流行的数据科学和 AI 框架快速配置环境。
一、Docker
1. Docker 是什么
该软件于 2013 年由 dotCloud 公司推出,发布以来一直备受关注和讨论,被认为可能会改变软件行业。
2. 为什么使用 Docker
如果让你说出软件开发最烦人的事情,那么环境配置必然是其中之一。例如开始编写 Python 应用程序,那么你的第一个步骤就是在您的计算机上安装 Python。软件运行时,你不仅需要让自己计算机上的环境需适合你的应用程序按预期运行,并且还需要与生产环境相匹配。这就是所谓的环境一致性问题。这里面大量的重复劳动不说,还经常出现系统不兼容等莫名其妙的问题,非常令人崩溃。很可能再自己机器上跑通了,但放到用户的环境里,或者服务器上就出问题了。
那么可不可以在软件安装的时候把软件需要的环境一并复制过去呢?虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,但它的缺点很多:资源占用多、冗余步骤多、启动慢等等。
Docker 是一种全新的虚拟化方式。传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。在这样的前提下,它跟传统的虚拟化方式相比具有众多优势:
- 高效的利用系统资源。
- 启动速度快。容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。
- 确保了应用运行环境一致性。
- 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。
- 容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比拟机文件要小很多。
3. 如何使用 Docker
首先要理解 Docker 的三个概念:镜像、容器、仓库。
**镜像(Image)和容器(Container)**的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。镜像是只读的,可以用来创建 Docker 容器,容器看做是一个简易版的 Linux 环境(包括 root 用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
Docker Registry 是集中存放镜像文件的场所,提供集中的存储、分发镜像的服务。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
最常使用的 Registry 公开服务是官方的 Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。
这里以 TensorFlow 机器学习框架搭建为例讲解如何利用 Docker 快速搭建环境。
首先你需要安装并启动 Docker。如果要使用 GPU 则安装 nvidia-docker。
1)直接使用别人做好的镜像
在命令行输入以下两条命令:
docker image pull tensorflow/tensorflow
docker run -it -p 8888:8888 -v /$(pwd)/notebooks:/notebooks tensorflow/tensorflow
第一行命令在 Docker Hub 上拉取 tensorflow 官方镜像的 cpu 版本。
第二行则由此镜像创建一个容器,并在容器里运行 jupyter 服务。在你的浏览器上打开 http://localhost:8888/,就可以在 jupyter 里导入 TensorFlow 包了。
-v 参数的作用是将宿主机当前目录下的 notebook 目录挂载到容器内的/notebooks 目录,不添加这个参数的话,当结束 container 的时候,jupyter notebook 里的内容也会随之消失。
我们还可以进入到容器里查看容器的环境配置信息:
docker run -it -p 8888:8888 tensorflow/tensorflow bash
解释一下参数含义:
-i: 以交互模式运行容器,通常与 -t 同时使用
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
bash: 在容器内执行 bash 命令
root@21cebb7bd6b4:/notebooks# python
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow
>>>
root@21cebb7bd6b4:/notebooks# python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'tensorflow'
2)保存修改后的容器为新的镜像
通过在容器里执行 bash 命令后我们可以看到,TensorFlow 官方提供的这个容器的环境已经安装了 Python2 和 Python3,不过只有在 python2 上安装了 TensorFlow 的环境,如果你想在 python3 运行 TensorFlow 的话,可以自己手动在容器里进行你喜欢的环境配置。
有没有办法把修改好的容器作为基础镜像,以后需要创建容器的时候都使用这个新的镜像呢?通过命令 docker commit [CONTAINER] 可以提交容器副本,制作属于你自己的镜像。命令格式如下:
docker commit -m="description" -a="authorName" 97744639b45d authorName/tensorflow-python3:latest
参数说明:
-m: 提交的描述信息
-a: 声明镜像作者
97744639b45d: 容器 ID
authorName/tensorflow-python3:latest: 指定要创建的目标镜像名
docker ps -a 这条命令可以列出所有已经创建的未删除的容器。
这里分享一个 docker hub 上的镜像 docker pull dash00/tensorflow-python3-jupyter,里面已经配置好了 python3 下 TensorFlow 的环境,大家可以直接拉取使用。
3)Dockerfile 定义全新镜像
上面的方法是在基础镜像的容器上做修改创建我们自己的镜像,我们也可以编写一个 Dockerfile 来构建全新的镜像。我们已经知道 Docker 镜像是制作 Docker 容器的模版,而 Dockerfile 则是一个定义 Docker 镜像的文件。下面我们尝试编写一个 Dockerfile。
Dockerfile 定义了容器内的环境配置。在此环境中,对网络接口和磁盘驱动器等资源的访问都是虚拟化的,该环境与系统的其他部分隔离。因此您需要将端口映射到外部的宿主机环境,并具体指定哪些文件是跟外部环境保持一致的。只要在定义好此操作之后,你就可以预期,无论什么时候你运行这个文件,由 Dockerfile 中定义的应用程序环境的构建都会执行完全相同的操作。
如何创建
这里是一个示例:创建一个空目录,创建一个名为的文件 dockerfile,再创建两个文件 requirements.txt 和 app.py 和 dockerfile 放在一起。
以下是 dockerfile 文件内容,注释里有条语句的解释:
# 使用 python:2.7-slim 作为基础镜像
FROM python:2.7-slim
# 指定工作目录(或者称为当前目录)
WORKDIR /app
# 将当前文件夹下的内容(requirements.txt 和 app.py)复制到容器里的/app目录下
ADD . /app
# 安装在 requirements.txt 文件里指定的 python 包
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 向外部环境暴露 80 端口
EXPOSE 80
# 设置环境变量
ENV NAME World
# 一旦容器开始运行,则运行 app.py 作为容器的主进程
CMD ["python", "app.py"]
FROM 指定基础镜像,是必备的指令,并且必须是第一条指令。在 Docker Store 上有非常多的高质量的官方镜像提供给我们使用。
RUN 指令是用来执行命令行命令的。
CMD 指令用于指定默认的容器主进程的启动命令。有别于传统虚拟机概念,对于容器而言,其启动程序就是容器的主要进程,容器就是为了主进程而存在的。
有了 Dockerfile 文件,我们就可以使用 docker image build 命令创建 image 文件了。运行:
Docker build -t friendlyhello
如果运行成功,使用 docker image ls 命令就可以看到新生成的 image 文件 friendlyhello 了,它位于你机器的本地 Docker 镜像注册表中。
docker image ls
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
二、Datmo
如果你觉得上面描述的关于 docker 的操作依然十分麻烦的话,我还有一个工具推荐给你,那就是 Datmo。Datmo 充分利用了 Docker,简化了流程,帮助您快速轻松地运行 AI 框架。下面是使用流程:
1. 前提条件
安装并启动 Docker(https://docs.docker.com/install/#supported-platforms)
(如果使用 GPU)安装 CUDA 9.0(https://developer.nvidia.com/cuda-90-download-archive)
(如果使用 GPU)安装 nvidia-docker(https://github.com/datmo/datmo/wiki/Datmo-GPU-support-and-setup)
2. 安装 datmo
就像任何 python 包一样,使用以下命令从终端安装 datmo:
$ pip install datmo
3. 初始化 datmo 项目
在终端中,打开项目文件夹。然后,输入以下命令:
$ datmo init
然后,你将被要求提供项目的名称和描述。
4. 启动环境设置
在输入名称和描述后,datmo 将询问是否要设置环境 - 输入 y 并按 enter。
5. 选择系统驱动程序(CPU 或 GPU)
然后,CLI 将询问希望为您的环境选择哪些系统驱动程序。如果不打算使用 GPU,请选择 cpu。
6. 选择一个环境
接下来,你将从众多预打包环境中选择一种。只需在提示中回复您要使用的环境的编号或 ID。
7. 选择编程语言版本
上述许多环境都有不同的版本,具体取决于你计划使用的语言和版本。
例如,在选择 keras-tensorflow 环境后,我将面临以下提示,询问我是否要使用 Python 2.7 或 Python 3.5。
8. 启动工作区
现在是时候启动你的工作区了。选择你要使用的工作区,然后在终端中输入相应的命令。
Jupyter Notebook - $ datmo notebook
JupyterLab - $ datmo jupyterlab
RStudio - $ datmo rstudio(在 R-base 环境中可用)
终端模式 - $ datmo terminal