创建用于AI和机器学习的Docker容器
容器技术(例如Docker)极大地简化了依赖性管理和软件的可移植性。在本系列文章中,我们将探讨Docker在机器学习(ML)场景中的用法。
本系列假定您熟悉ML,一般的容器化,尤其是Docker。欢迎您下载项目代码。
在本系列的上一篇文章中,我们讨论了Docker基础。在本文中,我们将在各种ML场景中创建和运行容器时开始应用这些知识。首先,我们将创建一个用于实验和培训的通用容器。
基本图片
考虑映像大小和安全性时,对于基本映像,AlpineLinux似乎是显而易见的选择。对于Python应用程序,它并不是那么简单。Alpine使用musl–一个不同于glib的C库,大多数标准Linux发行版都使用musl。这会使大多数已编译的Pip轮子不兼容,因此在安装过程中需要进行编译。实际上,在Alpine上设置任何非平凡的Python环境(具有多级依赖项)所花费的时间要比在Debian或Ubuntu等更流行的发行版上花费的时间要多得多。不仅如此,而且生成的图像可能更大,并且代码的运行速度可能会更慢!
有关更多详细信息,请参阅本文。为避免上述问题,我们将选择基于Debian10(Buster)构建的官方Python映像的最低版本作为基础:python:3.8.8-slim-buster。
创建Dockerfile
我们需要具有基本ML库和JupyterNotebooks的图像来处理实验。我们将所有必需的库存储在app/requirements.txt文件中:
numpy==1.19.5 pandas==1.2.2 scikit-learn==0.24.1 matplotlib==3.3.4 jupyter==1.0.0 opencv-python==4.5.1.48 tensorflow-cpu==2.4.01234567复制代码类型:[html]
现在,让我们开始创建我们的Dockerfile:
FROM python:3.8.8-slim-buster ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get -y install --no-install-recommends ffmpeg libsm6 libxext6 && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/*12345复制代码类型:[html]
首先,切换到非交互模式后,我们将安装Python库所需的所有系统依赖项,然后进行清理以限制图像大小。请注意,如果您更改requirements.txt,则这些依赖关系可能会有所不同。
接下来,我们在运行容器时使用非root用户:
ARG USERNAME=mluser ARG USERID=1000 RUN useradd --system --create-home --shell /bin/bash --uid $USERID $USERNAME123复制代码类型:[html]
对USERNAME和USERID值使用参数将使我们在需要时在构建和执行期间替换它们。
然后,让我们配置一个Python环境:
COPY app/requirements.txt /tmp/requirements.txt RUN pip3 install --no-cache-dir -r /tmp/requirements.txt && rm /tmp/requirements.txt123复制代码类型:[html]
最后,如果未指定其他命令,则默认情况下,我们切换到新用户并启动JupyterNotebook:
USER $USERNAME WORKDIR /home/$USERNAME/app EXPOSE 9000 CMD ["jupyter", "notebook", "--ip", "0.0.0.0", "--port", "9000"]1234复制代码类型:[html]
建筑形象
在Linux上,我们应该始终使用预定的用户来运行容器。这样可以确保容器的内部进程以及保存到映射的主机驱动器的文件将具有预期的所有者。在以下示例中,我们确保当前用户对构建时创建的所有文件具有适当的权限imagemld02_cpu_experiment:
$ docker build --build-arg USERID=$(id -u) -t mld02_cpu_experiment .1复制代码类型:[html]
提供的--build-argUSERID参数将用USERID提供的值替换Dockerfile的预定义参数。
实际上,仅当您在Linux上本地运行容器时才需要这样做。映像的默认值(1000)可能会在主机上引起麻烦,并且容器需要对映像中包含的用户文件夹或文件具有写权限。在任何其他情况下,您都可以跳过此步骤。
正在运行的容器
构建容器后,我们可以尝试一下。假设我们已经下载并提取了示例代码,我们将运行JupyterNotebook实例:
$ docker run -p 9000:9000 -v $(pwd)/app:/home/mluser/app -v $(pwd)/data:/home/mluser/data --rm --user $(id -u):$(id -g) mld02_cpu_experiment1复制代码类型:[html]
在Windows上:
$ docker run -p 9000:9000 -v %cd%/app:/home/mluser/app -v %cd%/data:/home/mluser/data --rm mld02_cpu_experiment1复制代码类型:[html]
这里的参数是:-p将容器端口映射到主机端口,-v将主机的应用程序和数据文件夹映射到容器文件夹(绝对路径),并--user确保我们在当前主机用户的上下文中执行容器代码(映射文件夹中文件的正确所有者)。该--rm标志确保一旦容器停止,所有容器数据将被自动删除。
如果一切顺利,我们应该会看到JupyterNotebook的日志旋转起来:
多亏了映射的端口,我们应该能够使用http://localhost:9000(或以上日志中的URL)在Web浏览器中打开笔记本。
SimpleTraining.ipynb包含使用简单的TensorFlow模型训练样本MNIST模型所需的一切。执行完所有单元格后,我们应该期望获得以下确认,证明模型的预测是正确的:
在以下文章中,我们将使用此笔记本保存的经过训练的模型进行推断。